art with code

2008-12-31

Lock-free PreDraw, less caching

The RequestPreDraw-method I was calling in the GTK event loop to tell the PreDraw-thread to queue up a new PreDraw ASAP (cancelling the current PreDraw) was doing things in a bit silly fashion. The CancelPreDraw-method was spinning for the current PreDraw to exit, and even if the PreDraw did have a pretty granular cancellation strategy, it meant that it could impose a "finish current directory listing + sorting"-delay on the draw loop. And the worst case for that is well north of half a second.

So the cancel lock had to go.

Now the RequestPreDraw-method is two lines:

/** BLOCKING */
void RequestPreDraw ()
{
// Tell currently running PreDraw to stop.
Renderer.CancelPreDraw();
// Tell PreDrawThread to start a new PreDraw after the current has stopped.
PreDrawRequested = PreDrawInProgress = true;
}

And Renderer.CancelPreDraw simply sets a "cancel when you please"-flag:

public void CancelPreDraw ()
{
PreDrawCancelled = true;
}

As the PreDraw-thread does the PreDraw-calls sequentially it doesn't need internal locking, and we can get by with a couple state bools. Result? Less code, less locking, a lock-free common drawing loop and a stable framerate.

Less caching

Made the caches throw away pretty much everything not needed on this very frame (last 10 frames for the thumbs.) And it brought memory use to ~80 megs in overview, with peaks at around 150 megs when panning the large thumbs of an image directory.

Ditching the filesystem entry cache was a bit nasty, as it causes a lot of visible relayout. A compromise between memory use and model rebuilding would be preferred. One solution might be to trace a zoom path out of the current position and keep the visible set of that cached. Implementation... genZoomLevels current_z 0 |> map preDraw. So that PreDraw doesn't determine the visible set of a single frame, but a set of frames from the current position to the root directory. Or just keep the last visited N directories cached.

No comments:

Blog Archive