[cairo] Problem in cairo + xcb where alpha blending is cumulative (becoming more opaque with each render)

Ryan Flannery ryan.flannery at gmail.com
Thu Sep 27 04:28:08 UTC 2018

>From what I can see, my issue boils down to CAIRO_OPERATOR_SOURCE not
behaving as I would expect, with the use of an xcb backed surface.
Namely, after doing a cairo_pop_group_to_source(), if I
CAIRO_OPERATOR_SOURCE), based on the docs I would expect the alpha channel
to be copied from the intermediate pattern/surface as-is to the
destination, with no blending. I actually observe this when the destination
is *not* an xcb derived surface (I'm playing with a png one now, using the
sample program I included).

With an xcb backed surface like in my original program, setting the
operator to CAIRO_OPERATOR_SOURCE results in a solid black background.

Specifically, my case is this:

   // BEGIN render loop
   cairo_set_source_rgba(cairo, 0.8, 0, 0, 0.1);

   // draw (lots of) stuff

   // END render loop
   cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
   // reset operator to CAIRO_OPERATOR_OVER

I've been looking into cairo-xcb / xcb specifics regarding this, but any
cluesticks that could be provided would be appreciated.


> I've recently been using cairo + xcb to build a new application. I've hit
> a problem supporting transparency / alpha-blending, where I want to allow
> users to set the background window with an alpha value and have the root
> x11 window show through that. The raw transparency piece works fine and is
> easy in cairo + xcb, but I'm struggling with my main render loop -- it
> seems to add / accumulate the alpha values with each render, and doesn't
> remove previously drawn content with alpha values. I have more details
> below including a fully functioning prototype with my layout setup (also
> below and in a gist), but here's what I've been trying after much
> google'ing and searching the archives:
> My main render loop looks roughly like this (and I understand why this
> would accumulate opaqueness over time):
>    // BEGIN render loop
>    cairo_push_group(cairo);
>    clear_background();
>    // draw (lots of) stuff
>    // END render loop
>    cairo_pop_group_to_source(cairo);
>    cairo_paint(cairo);
>    xcb_flush(xcon);
>    sleep(1);
> where clear_background() is:
>    cairo_set_source_rgba(cairo, 0.8, 0, 0, 0.1);
>    cairo_paint(cairo);
> With that loop, as-is, I can see why the alpha values are accumulating
> with each render.
> To compensate, I've tried the following based on the cairo site's
> documentation, and browsing the archives, but with no success:
>    1. cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); (and subsequent
> resets to *_OVER)
>       I've tried this before the cairo_paint() at the END of the loop, as
> well as in the BEGIN loop (both before and after the cairo_push_group()).
>       My understanding is that this copies the alpha from SOURCE as-is,
> with no blending, but I'm not observing that in the results, regardless of
> where I place it (and tweak the timing to confirm each step).
>       Use of it *always* results in a black background, which makes me
> think I have something larger out-of-whack.
>    2. I've looked at other operators, but none seem applicable (and I've
> tested most in various setups like the above).
>    3. Using cairo_mask() / cairo_mask_surface() when using
> cairo_pop_group() (the raw one, returning a cairo_pattern_t) to render
> after the pop, but that also fails.
> My ultimate goals are basically these:
>    1. Have the window always reset to a consistent background of rgba =
> 0.8/0/0/0.1
>    2. Don't 'accumulate' alpha artifacts from the widgets drawn in the
> loop each time
> My sample code below illustrates what I'm trying and my setup.
> It draws a 200 x 200 pixel window (at x,y = 200,200).
> It has an initial background of rgba = 0.8/0/0/0.1,
> and a 50x50 pixel green square in the top left (rgba=0/1/0/0.5).
> Every second it redraws, and moves the square towards the bottom right.
>    1. The background is *always* rgba = 0.8/0/0/0.1
>    2. Only one square (the most recent) is shown with rgba = 0/1/0/0.5
> BUT what I observe (trying lots of variants):
>    1. The background gets more opaque with each render, eventually
> becoming solid
>    2. The previous renders of the green square persist and aren't cleared
> The code is below, along with build instructions, and available at:
>    https://gist.github.com/ryanflannery/1649ce3dd45cb6e16088931262283386
> Note the example includes a great deal of XCB setup, including logic to
> handle tiling window managers (my use case). I doubt that's of interest
> here, but I'm including it for completeness (but below the main cairo
> logic).
> Any feedback appreciated (on this or other conventions I have!)
> Cheers,
> -Ryan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.cairographics.org/archives/cairo/attachments/20180927/29cb9ad4/attachment.html>

More information about the cairo mailing list