[go: up one dir, main page]

MT enablement 3/4: Asynchronous Canvas

Short summary

  • Make the Canvas do all its rendering on a separate thread.

    image

  • Benefits:

    • Significantly smoother panning and zooming, since even heavy rendering cannot block the main thread.
    • Faster drawing, since the render thread no longer has to wait for slow things on the main thread to finish.
    • Render Time Limit increased to 50 ms, which mostly eliminates fragmentation while dragging.
    • No tearing on-canvas when interacting with the Fill & Stroke dialog / Pattern Editor.
    • A frame less input latency.
  • Internal benefits:

    • Eliminates the GTK4-obstructing "event bucket" introduced in !3838 (merged) as an (imperfect) tearing solution. (/cc @firox263)

Description

This continues the multi-thread enablement work from !4759 (merged). Whereas that MR was about doing rendering off main-thread, this one is about doing Canvas rendering off-main-thread. (The final one will be about doing Canvas rendering on multiple background threads.)

Changes

  1. The first commit implements snapshotting support for CanvasItem, just like !4759 (merged) did for DrawingItem. This rests upon the previous CanvasItem refactoring work !4875 (merged), so its two commits are included here and that merge request is a dependency.

  2. The second commit does the necessary refactoring of the Canvas to replace its idle-drawing mechanism with a background-thread drawing one - so prepare for !3838 (merged)-level breakage again 😅.

Outside of canvas.cpp, pixelstreamer.cpp saw a lot of modification to make the various PixelStreamers work from off-main-thread in OpenGL mode. This is tricky because they need to ask OpenGL for buffers on the main thread. The solution was to make them keep a pool of buffers, but sometimes the still need to ask for buffers, so a convoluted communication mechanism was needed to make this play well with shutdown, which eventually got split into a new file synchronizer.cpp.

I've also given the preferences a bit of a shake-up, and reinstated some legacy event-gobbling code that was removed in !3838 (merged) in tool-base.cpp. This code was superseded by event bucketisation, but now that's gone I've put it back exactly as before. I'm not actually sure it's needed, but I left it to be safe to avoid reintroducing something this this problem. In any case I don't see it working with GTK4, so it's going away soon whether it likes it or not!

Caveats

Although all the Canvas-level support for rendering on multiple background threads is already here, this MR has a line of code which forces the thread count to 1, because it would not be safe to enable that yet. The issue is that it's not quite safe to call DrawingItem::render() on more than one thread at a time, because of various caches. However, most of the work required for it has already been done, and the remaining work only needs to touch a few files in display/. Anyway, until then, we can't expect any multi-factor speedups in raw rendering speed, so only expect a modest boost from this MR.

An important remaining bottleneck is the the update function (visible in the profiling graph above). Unlike rendering, this can't be moved off-main-thread (it would need a total rework of the events system to allow asynchronous events), so if it's slow you'll still notice. Typically this is a problem for SVGs with lots of objects, especially imported text, but not for SVGs with slow-to-render objects like filters, gradients etc. This function is the final obstacle in the way of a guaranteed-fluid canvas (as mentioned in #3723 (closed)). So until then, while you can still get Inkscape to chug, it won't be rendering's fault any more, and it should hopefully chug a lot less.

Testing

The same goes as for !4759 (merged) - prolonged usage and/or stress-tests would provide reassurance that I haven't written any subtle races. (I really had to bend over backwards to avoid races in tools that call Drawing::averageColor() (e.g the dropper tool) and avoid deadlock during shutdown in OpenGL mode, so those are some things to try and break.)

On top of that, at least going by the scope of the canvas changes, there are likely to be far more mundane and easily-discoverable crashes too - so please test!

Merge request reports

Loading