Saturday, April 24, 2010

FFRell (FFRend in parallel) coming soon

There's been lots of progress on FFRell, the parallel-processing version of FFRend. I'm currently running FFRell at 1024 x 768 on a purpose-built i7 box (8 CPUs with Hyperthreading) and seeing frame rates from 30 to 60 Hz for quite complex patches. FFRend has been completely rebuilt around a multithreaded pipelined rendering engine. Each plugin runs in its own thread, and frames are routed via thread-safe zero-copy pointer queues.

I started by building a test system called ParaPET (Parallel Plugin Engine Test) which is an interesting project by itself; see the enclosed screen shot. Basically ParaPET is a tool for modeling the problem of optimal parallelism for arbitrary signal routes. The first case I had to deal with was feedback. If plugin A takes input from plugin B, and B also takes input from A, neither plugin can get started and the engine stalls. The solution is to prime one of the plugins, i.e. feed it blank frames until the feedback loop is closed and becomes self-sustaining. But first you need a general way of identifying such cases in all their permutations. ParaPET features a spider object which recursively crawls the plugins looking for feedback.

The other interesting case is when a plugin's output can arrive at a downstream mixer via multiple routes of different lengths. A simple example would be a source plugin that connects to both inputs of a mixer, one directly and the other via an effect. In such cases you'll get staggering, i.e. the plugins won't execute in parallel despite available CPUs. The solution is to add delay to the shorter route, so that the route lengths become equal again. Delay is added to a route by increasing the size of the corresponding frame queue.

This turned out to be a pretty hard problem to solve for all possible cases. Again the solution was recursion. The same crawl that detects feedback also gathers the necessary information for route balancing: for each plugin, 1) its maximum distance from the final output, and 2) for each sink mixer it's connected to, its distance from that mixer (distances are measured in hops, just as in network topology). With this information in hand, for each plugin, we can determine its longest route to a sink mixer, and compensate any shorter routes accordingly.

I came up with dozens of tough asymmetric test cases, including three- and four-input mixers, and the spider handles them all. It works so well I'm considering releasing ParaPET as a separate project. It's not tied to video processing so it would make a good general framework for pipelined parallel execution of interdependent tasks. If you're interested in playing with it let me know...

Once I got the engine working in ParaPET, I started building a new app (ParaFFEn) that used the same thread architecture but with FreeFrame plugins and actual video frames. The goal was to eventually port the engine into FFRend, but after hours of surgery the patient died: FFRend was just too single-thread oriented and couldn't adapt, so I gave up and started rebuilding FFRend from scratch, starting with ParaFFEn's engine.

After a long hard slog, FFRell can now read FFRend projects and run them in full-screen dual-monitor Exclusive mode. All of FFRend's GUI elements are included except the file browser and monitor bars. FFRell also includes the nifty dynamic graph view from ParaPET (courtesy of GraphViz), plus the scrolling execution history and queue views. What's not working includes recording, clipboard support, MIDI, and undo. Also FFRell can't create metaplugins, though it can load them. Plenty to keep me busy this summer. I hope to have a reasonably stable version by Q3.