GNOME Bugzilla – Bug 552845
Use DamageReportRawRectangles
Last modified: 2016-01-24 06:38:05 UTC
The current integration of damage reporting and the anti-expose queue doesn't work properly with DamageReportBoundingBox because you can get: - Window modified, damage event reported - GTK+ redraws parent window and queues anti-expose - Window modified again, no damage event reported (bounding box didn't change) - Damage event received by GTK+ and discarded because of the anti-expose Simple fix is to switch to DamageeReportRawRectangles. The main downside is that if the redirected window isn't using double-buffering you could conceivably get many, many events being sent. But if the redirected window isn't using double-buffering, then you'll also get intermediate redraws and flashing, so I think this can basically be ignored.
Created attachment 118976 [details] [review] Patch to switch to DamageReportRawRectangles
I agree that this is probably the best thing to do (without making modifications to the X server). It kinda sucks, though :/ It may be worth opening a discussion with some of the Xorg guys about this. They seem to be willing to accept proposals for improvement to these sorts of things.
It's hard to imagine what the X server should do better; for clients that do proper double buffering, we want damage reported instantly and with the correct serials for when the damage occurs. All I can really imagine is something like: If more than 1000 rectangles of damage are reported for a client over a 1 second period, then the client is put (permanently?) in the "penalty box" and damage for that client is accumulated and reported in the server's block handler. Which sounds hard to implement and prone to false alarms.
On second thought, (just for discussion/ideas/brainstorming) let's look at the other side: what are we doing wrong? We're telling the X server that a damaged region has been "repaired" when actually we've done no such thing (due to anti-expose). Unfortunately, this is actually the -normal- code path, the the repair really does need to be reported. In any case, though, it's definitely wrong to call DamageSubtract() if we're not actually doing any updates. So, what if we did XDamageSubtract at the time that we're actually doing the repairs (ie: when we invalidate the parent area, or from the same context that's calling the expose event handler of the parent, just before the handler is called)? The anti-expose handler would take down the damage event that we'll get "later" (even though it's already in-flight) as a result of the child drawing. Any additional damage that was done in the mean time will be ignored as long as it happens before the expose event handler (which is fine, because then the handler would take care of it anyway). Anything that happens later causes a redraw. I think this would work and it would avoid having to use RawRectangles... Discuss? :)
Any conclusion here ?
Assume that we are implementing Ryan's idea by doing: A) Record anti-expose B) Subtract damage from subwindows C) Handle expose Then the shortest argument I can come up with with why that's correct: 1) If we draw to a pixel that's already in the damage region of a subwindow, then we haven't gotten to B) yet in processing the damage event that added that pixel, so we are still going to do C). 2) If we draw to a pixel that's not already in the damage region of a subwindow, then we'll generate a new damage event. That damage event can only be cancelled by an A) that is recorded happens after our drawing, so C) still going to draw the pixel. That's not really a fully satisfactory proof, since it doesn't get to the reason A) needs to go before B). (To avoid cancelling damage from new drawing that happens after B.) I'll attach something more cumbersome that covers all the bases. Anyways, I'm convinced of the correctness, and if Ryan wants to come up with a patch, that would be a fine fix (not that the RawRectangles approach doesn't work as well.)
Created attachment 125028 [details] Formal proof of correctness
sadly, the patch never happened