So the cancel lock had to go.
Now the RequestPreDraw-method is two lines:
/** BLOCKING */
void RequestPreDraw ()
// Tell currently running PreDraw to stop.
// 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.
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.