This is still very early, but, the idea is that when the compositor forces us to double buffer (i.e. we are swapping between two shm buffers), instead of copying the old buffer wholesome, and then applying the current frame's damage, we re-apply the old frame's damage first, then our own.
First, while applying this frame’s scroll damage, copy it to the buffer’s scroll damage list (so that we can access it via term->render.last_buf).
Also, when iterating and rendering the grid, build a pixman region of the damaged regions. This is currently done on a per-row basis. This is also stored in the buffer.
Now, when being forced to double buffer, first iterate the old buffer’s damage, and re-apply it to the current buffer. Then, composite the old buffer on top of the current buffer, using the old frame’s damage region as clip region. This effectively copies everything that was rendered to the last frame. Remember, this is on a per-row basis.
Then we go on and render the frame as usual.
Note that it would be really nice if we could subtract the current frame’s damage region from the clip region (no point in copying areas we’re going to overwrite anyway). Unfortunately, that’s harder than it looks; the current frame’s damage region is only valid after this frame’s scroll damage have been applied, while the last frame’s damage region is only valid before it’s been applied.
Translating one to the other isn’t easy, since scroll damage isn’t just about counting lines - there may be multiple scroll damage records, each with its own scrolling region. This creates very complex scenarios.
Edit: we now subtract the current frame's damage from the copy-region if the current frame has no scroll damage.
I do have some early benchmark numbers, but will wait before publishing them since they are from debug builds. It does look promising though. There is a very noticeable/measurable performance hit, but the improvement compared to the master branch is still huge.
more code cleanup
spend some more time trying to subtract current frame's damage from the old frame's damage, thereby reducing the amount of data we need to copy
check buffer age and do a full frame copy if the age is >= 2
skip old frame's damage if current frame is a full refresh
properly handle last frame being force-refreshed (urgent margins, flashing, scrollback search etc) TODO: more testing