PremultiplyAlpha with sRGB Source Data

Sep 29, 2013 at 2:15 AM
I have a PNG file that has srgb data. The data is not premultiplied, but I need it to be.

Looking at the premultiply code, it handles srgb and linear data the same.

Is the code correct or should the premultiplying be happening in linear space? I thought the premultiplying was a linear operation, but honestly my head spins in circles when thinking about the srgb vs linear stuff.

If the premultiply should be in linear, is there a recommended approach to handling that? Should I load the data as srgb, do a conversion to a linear format (I see the conversion functions handle srgb->linear), run the premultiply, convert it back to srgb and store it? If I do that am I looking at any precision loss with the conversions? Should I convert it to a floating point linear format if I do that?

Looking for guidance on how to get the best/correct result. This is an asset conversion process so I'm not particularly concerned about speed here.
Sep 29, 2013 at 5:54 AM
Edited Sep 29, 2013 at 5:55 AM
In sRGB format data, only RGB are in the sRGB color space. Alpha remains in the linear space. If you just load the data as sRGB and then apply Premultiply, it will still be in sRGB.

In other words, the pmalpha step of RA, GA, B*A won't change the colorspace of R, G, and B at all. The choice of RGB vs. sRGB colorspace for the R, G, and B channels is independent of the choice of straight-alpha or pmalpha.
Sep 29, 2013 at 6:50 AM
Still having some trouble wrapping my head around that concept. If I have a non-linear RGB how can a linear multiplier give me even results?

For me, my confusion (or perhaps misunderstanding), is coming from the values I get once converted to linear.

If I start out with with linear data that is not premultiplied:
RGB=0.5, Alpha=0.5
Premultiply -> RGB=0.25, Alpha=0.5

For what I think is equivalent using 2.2 gamma (I know isn't exact with srgb):
RGB=0.73, Alpha=0.5
Premultiply -> RGB=0.365, Alpha=0.5
Convert to Linear -> pow(0.365, 2.2) = RGB=0.1, Alpha=0.5

The results when converted to linear space are quite different from the all-linear path. It doesn't come out to half the linear value. If the alpha is linear, shouldn't the linear results be the same?

If instead I took the gamma space value, converted to linear, applied the premultiply, then converted back:
RGB=0.73, Alpha=0.5
Linear -> pow(0.73, 2.2) = RGB=0.5, Alpha=0.5
Premultiply -> RGB=0.25, Alpha=0.5
Gamma -> pow(0.25, 1/2.2) = RGB=0.53, Alpha=0.5
Back to linear in shader (via srgb surface) -> pow(0.53, 2.2) = RGB=.247, Alpha=0.5 which is the same value I would have if working in linear space the whole way (I trimmed a lot of decimals off for brevity)

So I have equal relative start values (linear=.5, gamma=.73) and come out with different linear when shading if I apply the alpha against the source values the same way. That doesn't seem right? Quite possible I'm missing some concept here still, but I am not seeing it.
Sep 29, 2013 at 7:41 AM
Edited Sep 29, 2013 at 7:44 AM
This website seems to explain it pretty well, as does this one.

If you are happy with the blending taking place in sRGB, then it works out ok. If you actually want to blend in linear RGB colorspace it's more complicated.
Sep 29, 2013 at 8:14 AM
Edited Sep 29, 2013 at 8:16 AM
Thanks for the link Chuck.

Makes sense and it confirms what I was thinking I needed to do.

It definitely agrees with you in that if you want to blend in srgb space you can do alpha * srgb. For my shaders I need to be able to blend in linear.

For linear blending it suggests the values are stored as:
(red * alpha) ^ (1/2.2)
where before it was:
alpha * (red^(1/2.2))

Since in this case I am starting with a PNG, and it is non-premultiplied, but does have srgb data, I would have to convert it to linear, multiply the alpha then convert it back for linear blending.

I don't have to use PNG, I don't really have a preference actually. Is there a "most people use this format" answer to the problem? For sRGB+Alpha? I am converting to DDS by the way, but I haven't found an easy to use workflow that lets me spit out DDS directly.
Sep 29, 2013 at 6:23 PM
Sounds like an option I should add to DirectXTex's Premultiply function then... Should be a simple matter of using _LoadScanlineLinear and _StoreScanlineLinear in the _PremultiplyAlpha function when this mode is requested, and of course yet another command-line switch for texconv...
Sep 29, 2013 at 6:26 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Sep 29, 2013 at 9:33 PM
Much appreciated, thanks.