Transparent behaviour

  • Hi,

    I've read that a 50% transparent grey square, say, takes Qt longer to draw than an opaque grey square. Makes sense, because for transparent, for every pixel, Qt has to read the pixel underneath, mix in some grey, then write back the pixel. Whereas for opaque, it's just a write of a grey pixel.

    50% transparent: rgba( 128, 128, 128, 50% );
    Opaque: rgb( 128, 128, 128 ); -or- rgba( 128, 128, 128, 0% );

    But what about 100% transparent? Is Qt smart, and actually does no drawing at all ?

    100% transparent: rgba( 128, 128, 128, 100% ) -or- transparent;

    You might ask why would I want to bother drawing a grey square that I can't see ?
    It's a fair question - but it was an example.

    What I'm actually interested in, is drawing a conical gradient, where 180 degrees of it have dynamically varying 'stops'.
    But the other 180 degrees of it, are omitted, courtesy stops that make it 100% transparent.

    Then as a test, I thought I'd try black instead, for the latter.
    But that made no difference, to my frames-per-second - I've got some measurement code.

    Which made me think, maybe Qt is not so smart, and for my 180% transparent part, Qt is reading the pixel underneath,
    mixing in nothing, then writing the pixel back.

    Tell me otherwise !

    Maybe it's smart only where the whole of the element, is 100% transparent. Like my example square.

    Or maybe it's supersmart, and knows my background colour is black, and so draws nothing for my black 180 degrees or 100% transparent 180 degrees, as they amount to the same thing.

    And that's why my frames-per-second, is the same :-)

    Best regards,


  • Moderators

    I think you're trying to draw simple conclusions from oversimplified observations.

    The process of rasterization is not a simple loop over each pixel and applying some logic to it. The way it actually occurs depends on many factors - for example software (CPU) and hardware (GPU) raserization of QPainter looks completely different. Another differentiation is the underlying platform specific drawing surface. Yet another factor is the composition mode you use (or is chosen automatically). The optimization of alpha is just one of the factors.

    I won't go over details of how it works in each of the branches the code may take, but a common scenario is that Qt caches the gradient to a buffer using CompositionMode_Source i.e. filling the buffer with correct values, even the fully transparent ones. Then, when the gradient is actually painted with a brush a decision about composition mode is made based on whether the gradient has any transparent stops.
    Rasterization usually takes place line by line (or "span" by "span" in Qt's nomenclature). If the gradient has no transparent stops a CompositionMode_Source can be used so each line can be set using a simple memcpy of the cached gradient. If the gradient does have transparency a CompositionMode_SourceOver needs to be used, which, again, can branch into several techniques, including SSE2 optimized one on the CPU. In this case the SSE registers are 128bit so they can "process" four 32bit pixels at a time. Splitting them into single pixels and adding that branching "if" to see if the pixel is fully transparent wouldn't improve the performance here. It would actually degrade it. The data is accessed in a fashion that makes it "hot" in the cpu cache so there's little penalty for actually storing a value that didn't need storing. The SSE optimization is worth it.
    On GPUs the situation gets even more interesting, because a pixel shader could be involved and those, depending on the gpu architecture, work in step-lock on blocks of pixels (usually 2x2 or 4x4), not lines.

    So, all in all, in this particular case Qt does some optimization when the gradient is fully opaque. It doesn't optimize further when the entire gradient is fully transparent (i.e. alpha 0 on every stop). I guess it could, but that's just a rare corner case you can optimize (i.e. just don't draw) on your side.
    In grander scale of things optimization on per pixel level is not very beneficial, and though in specific cases a small boost could be gained there's just no point in general case IMO.

  • Hi Chris, thanks for the really informative reply. I can see now there's a lot more subtlety to the topic than I imagined. And explains I think why I saw no difference in my frames-per-second figure. Best regards, David

Log in to reply