W dniu 16 kwietnia 2010 17:12 użytkownik bulia byak <buliabyak@...400...> napisał:
One is that the visible screen is divided into square 16x16 tiles, but it does not mean that each such tile is painted separately. Instead, these tiles are quanta of dirtying the canvas: if you dirty a single pixel, the entire 16x16 tile it belongs to is dirtied. The goal of this is to prevent too small dirtied areas and to accumulate many small dirtying events into a few larger events (because obviously, if you request to dirty a pixel in an already dirtied tile, nothing happens).
Is there any speed advantage over just accumulating the dirty events into one Geom::Rect?
The other mechanism divides the area-to-paint into buffers, and paints each buffer completely separately, returning to the main event loop after each buffer so that redraw can be interrupted. The size of these buffers depends on mode: 256K bytes in normal mode and 1M in outline mode (these are the values I found optimal after testing; divide by 4 to get the number of pixels in a buffer). These buffers divide the area to paint into strips along the longer side of the area to paint (i.e. horizontal if the area is mode wide than tall), and the width of these strips is calculated from the size of the area and the size of the buffer; these strips are painted starting from the one in which the mouse cursor is, and spreading outwards from it. Buffer boundaries have no coordination with 16x16 tiles, but they just go until interrupted or until covering all dirtied area.
This kind of tiling will not speed up HW accelerated rendering, because in practice the speed of HW accelerated 2D drawing does not depend on the area redrawn but on the number of commands issued. Tiling the image into 16 parts and redrawing all of them will be, in the worst case (when all objects intersect all tiles), 16x slower than drawing everything in one go. For software rendering, the current aggresive tiling strategy is probably better, as the time taken is more dependent on the number of pixels rendered. So I think the best idea is to leave the tiling system intact but provide for opportunities to bypass it.
Another thing, instead of allocating 256K buffers on demand, it might be better to create one big Cairo surface, and then split it into chunks using cairo_surface_create_for_region. This could simplify multithreaded software rendering, as threads won't need to allocate any memory for the output, but I don't see this function anywhere in the public API of Cairo.
I think caching, if done properly, will give a huge interactivity gain. Right now, when you move a canvas item such as a handle or node, objects underneath it have to be redrawn (within the touched 16x16 tiles) starting from scratch - tesselating, stroking, filling, etc., even if they didn't change, which is one of the major contributors to the "feeling of slow". If these redraws can be pulled from a cache, it will feel much more responsive I think.
For dragging, the first optimization that comes to my mind is as follows 1. We determine whether all the dragged or modified objects are adjacent in the z-order 2. If they aren't we skip this optimization as it's going to be too complex 3. We render the canvas into 3 layers: below the dragged object(s), above it and a layer with the object(s) itself 4. On every drag we redraw only the portion with the affected object and composite the output from those three layers
I think this might not work when filters come into the picture though.
The problem with image surface is that it's never going to be really fast - it's just software rendering. And a problem with offscreen GL surface, as you said, is that it may not be available everywhere.
Obviously we need both. :)
One final note: please try to keep both new and old rendering functioning together for as long as possible, with an easy way to switch between them (ideally without restart), so that the new renderer can be quickly checked for correctness and speed. This is a critical point in ensuring a smooth transition! Also, this will be another reason to limit refactoring to the necessary minimum, so as to not disable the old rendering code unless absolutely unavoidable.
I am afraid this might go the way of the failed gtkmm rewrite attempt, and could limit my options. I would need to duplicate the display and libnr directories to do anything meaningful. Isn't it enough to work in a branch?
Regards, Krzysztof