Bug 99233

Summary: Nesting backgrounds with identical RGBA causes wrong or missing colours at inner levels
Product: xorg Reporter: Daniel Boles <dboles.src>
Component: Server/Acceleration/glamorAssignee: Xorg Project Team <xorg-team>
Status: RESOLVED MOVED QA Contact: Xorg Project Team <xorg-team>
Severity: normal    
Priority: medium CC: dboles.src
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments:
Description Flags
Simpler, GTK-free test case
none
Screenshot of Uli's test case none

Description Daniel Boles 2016-12-30 22:41:58 UTC
This was originally reported against GTK+ here: https://bugzilla.gnome.org/show_bug.cgi?id=774270 A primary developer for rendering on GTK+ believes this to be an issue in Cairo or the X driver. So I'm moving it here. I hope there's enough info to do something useful. Unfortunately my knowledge of the tech involved is pretty minimal at this point, but I'll try any tests you want!

Basically, by nesting GtkFrames that had identical RGBA components in their background colours and 0 < alpha < 1, I found that child widgets of the innermost frame would not properly draw its background colour as they should. Rather, they would intermittently draw the background colour of an earlier/uppermost frame... although this would flicker to/from the correct colour through such actions as hovering over the widget or resizing the window.

By noticing some inconsistencies in when this occurred, I came to realise that by ensuring each successively nested frame's background colour differs from its parent's by at least 1 point (on a 0~255 scale) in at least 1 of the RGB components, then this problem can be worked around. However, if 1 or more of the nested frames' bg colours are the same, things start glitching out.

Running the test case with GDK_RENDERING=image to achieve the following...
> Always create image surfaces. This essentially turns off all hardware acceleration inside GTK.
...also bypasses the issue.

I've tried to run this in Xvfb in an attempt to narrow down whether it's Cairo or X but haven't gotten anywhere fast yet.

Again, let me know anything I can do to help diagnose (or redirect) this. Thanks!
Comment 1 Daniel Boles 2016-12-31 01:24:45 UTC
I should also note that working around this by bumping RGB values is broken in cases where that's not possible, e.g. where (as in GTK+) you want to use a named colour (e.g. currentColor). It's not possible to extract the RGB parts of that, alter 1, and integrate them back. So we lose functionality in such cases, rather than being a pure workaround.
Comment 2 Uli Schlachter 2016-12-31 10:49:59 UTC
I can reproduce the problem:

* It DOES happen with CAIRO_DEBUG="xrender-version=0.1".
* It does NOT happen with CAIRO_DEBUG="xrender-version=0.0" in the env.
* It also does NOT occur in Xephyr.

Thus, the problem is somewhere in the X11 server / video driver.

Besides that, no idea what to do. The bug is assigned to Chris, so let's wait for his wisdom. :-)
Comment 3 Chris Wilson 2016-12-31 11:03:44 UTC
Both Cairo and X likely optimise for this case. Uli, simple reproducer for the lazy?
Comment 4 Uli Schlachter 2016-12-31 13:30:40 UTC
> Uli, simple reproducer for the lazy?

Sorry, no. Just drawing smaller-and-smaller rectangles with color (0, 0, 0, 0.2) does not reproduce this issue. GTK must be doing more than just that and I'm not prepared to dick into GTK's rendering loop.

Also, the GTK test case "flickers" here, meaning that sometimes I get the expected content and sometimes the wrong one. So why does GTK redrawing this thing when I hover over it with the mouse and what is it doing different in this case?
Comment 5 Uli Schlachter 2016-12-31 13:36:06 UTC
Created attachment 128696 [details]
Simpler, GTK-free test case

Whoops. I was wrong. I tested cairo-xcb. At least I know that cairo-xcb is not affected. ;-)

Affected program reproduces the issue here. Setting CAIRO_DEBUG="xrender-version=-1.-1" still fixes things.
Comment 6 Uli Schlachter 2016-12-31 13:42:15 UTC
I took a brief look with xtrace:

Cairo "compresses" all the rectangles into a single FillRectangles request (first one draws the white background, second one 'the rest')

000:<:001c: 24: RENDER-Request(139,4): CreatePicture pid=0x02800005 drawable=0x02800001 format=0x0000002a values={poly-mode=Imprecise(0x01)}
000:<:001d: 28: RENDER-Request(139,26): FillRectangles op=Src(0x01) dst=0x02800005 red=0xffff green=0xffff blue=0xffff alpha=0xffff rects={x=0 y=0 w=100 h=100};
000:<:001e: 52: RENDER-Request(139,26): FillRectangles op=Over(0x03) dst=0x02800005 red=0x0000 green=0x0000 blue=0x0000 alpha=0x3333 rects={x=10 y=10 w=80 h=80},{x=20 y=20 w=60 h=60},{x=30 y=30 w=40 h=40},{x=40 y=40 w=20 h=20};
000:>:001e: Event KeyPress(2) keycode=0x18 time=0x011b6157 root=0x00000117 event=0x02800001 child=None(0x00000000) root-x=967 root-y=785 event-x=966 event-y=744 state=Mod2 same-screen=true(0x01)

Since this does not happen in Xephyr, something in the X server is mis-optimising this case, I guess.

@Chris: Now is your turn. I always fail to find the broken things in Xorg.
Comment 7 Daniel Boles 2016-12-31 13:43:13 UTC
Thanks both for the thoughts! Let me know if I (and my limited knowledge) can help with anything.
Comment 8 Chris Wilson 2016-12-31 13:51:22 UTC
Concentric set of XRenderFillRectangles with over and alpha < 1 should produce a gradient of light (outside) to dark (centre). libxrender compresses multiple calls of XRenderFillRectangle with the same op + colour to a single call. X is supposed to render each rectangle in that array as a seperate draw call (though we do try to optimise the computation of the union and use the union if possible by op).

Uli, what's the bad rendering?

Daniel can you look at Uli's test and see if it has a similar misrendering on your system?
Comment 9 Daniel Boles 2016-12-31 14:04:49 UTC
(In reply to Chris Wilson from comment #8)
> Daniel can you look at Uli's test and see if it has a similar misrendering
> on your system?

Sure, I just get a single light grey rectangle when running that test.
(As Uli noted, the flickering/etc seems to be peculiar to the GTK+ case.)
Comment 10 Daniel Boles 2016-12-31 14:10:29 UTC
Created attachment 128697 [details]
Screenshot of Uli's test case
Comment 11 Chris Wilson 2016-12-31 14:11:00 UTC
The two possible incorrect optimisations:

- reducing the array of rectangles to its region

- replacing the over with a precomputed SRC (since it assumed no overlap between rectangles) and the surface is a known solid color.

Both of those are ddx issues.
Comment 12 Chris Wilson 2016-12-31 14:11:36 UTC
(Not that list is meant to be exhaustative, just personal experience :(
Comment 13 Chris Wilson 2016-12-31 14:30:12 UTC
At a guess you are using modesetting/glamor since it exhibits this bug, and the flickering may be a side-effect of another bug in that code in how it misapplies damage.
Comment 14 Daniel Boles 2016-12-31 21:28:37 UTC
Does being a DDX issue mean it needs to be reported elsewhere? If so, would you mind doing that, since I'm guessing you have experience and clearly can explain the situation better than me. :D

If you'd like me to run any commands to provide info about my graphics hardware and settings, let me know. I can't remember any useful ones at the moment!
Comment 15 Uli Schlachter 2017-01-25 11:25:59 UTC
Ah, I think I finally figured out what Chris referred to: glamor/glamor_compositerects.c function _pixman_region_init_clipped_rectangles() turns the list of rectangles into a region and is called, for example, by glamor_composite_rectangles(). This does indeed "get rid" of the overlap, which is (as evident from this bug report) incorrect.
Comment 16 GitLab Migration User 2018-12-13 18:25:23 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/xorg/xserver/issues/90.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.