Blending on surfaces with No Alpha (565 specifically)

I’ve found some oddities with the reference implementation when blending with RGB565 surfaces. I tried the Rasteroid implementations to cross reference against, but they, unlike the reference implementation, don’t have any non-888 configs.

My example starts with a red square (1,0,0,1) on a white background (1,1,1,1). Overtop of this, I draw a transparent green line (0,1,0, 0.5).

The spec says “the source pixels are converted into the destination color space prior to blending” (p.131).

Yet blending modes “SRC” and “SRC_OVER” look different. The SRC_OVER one looks like the alpha value is used to blend with the destination color, while SRC is just solid green. (What do you do with the alpha value anyways when converting from 8888 to 565 anyways? Just discard it?)

So, assuming they values are NOT converted to the destination format prior to blending, I tried the non-PorterDuff modes and they ALL came out weird. With the same example of the green line over the red square on the white background, these are the results from vgReadPixel in sRBA8888 format.


Mode                 With Red             With White
-----------------------------------------------------
Multiply             7B00 00FF            7BFF 7BFF
Screen               FF82 00FF            FFFF FFFF
Darken               7B00 00FF            7BFF 7BFF
Lighten              7B82 00FF            FFFF FFFF
Additive             7B82 00FF            FFFF FFFF

The way I read the spec, with Destination alpha hardcoded to 1, I see:

Multiply = (AsCs0 + 1Cd(1-As) + As1CsCd)/(As+1(1-As)) = Cd(1-As) + AsCsCd

Additive = (AsCs + 1
Cd) /(min(As+1, 1)) = AsCs + Cd

Clearly, on additive blending for example, I’m not thinking the same way as the reference implementation, as I’d expect the color FF8000FF ontop of the red square.

Anyone has any insights?

Hi Ivo,

I don’t have any official answers, but I can rant a little bit:

For render target formats that don’t have an alpha value I assume an implicit alpha of one (e.g. everything is opaque, even if I write something transparent). For SRC_OVER this boils down to the ordinary alpha blending we’ve used for years.

SRC is really an undefined case, but so are most other blend modes in the same case as well. The whole Porter-Duff blending simply does not make much sense if your render target lacks alpha.

What I do is to simply ignore the problem. If someone wants to render to a 565 bitmap I use my ordinary pipeline. That includes premultiplication of each and every color… Give me a half transparent white in SRC-mode you’ll get a opaque 50% gray (dest-alpha will never be written). Subsequent compositions will make things worse and worse.

But what should an application expect? We don’t have an alpha, so we can’t do miracles.

The only way to really get around this problem is to internally render everything into 8888_PRE and convert to the target format when done. If you have the memory resources and enough horsepower for these additional steps, go for it.

Btw, the reference implementation isn’t as reference as it should be… It’s still full of bugs, so we somehow have to use common sense and do the best we can do… If someone really wants Porter-Duff he should render into an alpha compatible format.

Hi Ivo!
As told by Nils, reference implementation is very buggy, and using Rasteroid doesn’t help (it’s even worse in terms of correctness, but of course it’s a lot faster in terms of speed).
Returning to your question: i must agree with Nils, Porter-Duff has full sense only when drawing surface has an alpha channel. To say the truth, i must admit that some blend modes have sense also without it; i’m referring to src, src_over, additive.

Thanks for the replies.

I agree with you guys that it doesn’t make the best of sense, but, alas, that’s not really an excuse not to have it implemented. sigh

What I am seeing with the destination alpha being 1, is as muratmat said, only SRC, SRC_OVER, and ADDITIVE are useful. SRC_IN is almost the same as SRC (only exception is when As == 0, in which case the resulting color is (0,0,0,0) … which uhm… is it clear or is it black when output to the screen?), DST_OVER and DST_IN mean there is no rendering is necessary (DST having the same As==0 caveat). The rest of the modes simplify ridiculously too, as the denominator cancels out (or turns to 1) in all of them.
Changing to destination color format before blending would destory the usefulness of SRC_OVER and ADDITIVE modes though, which would be a pity - I hope Khronos doesn’t decide that that is indeed what they want in the spec.

I guess I’ll do what I think makes sense, and see what happens. Thanks