Encoding PNG on separate thread and struggling with gamma issues. Best approach?

Well, the issue here is that your gamma conversion is indeed a quite expensive operation. Unity uses Mathf.LinearToGammaSpace internally which is defined in native code. However we know that gamma conversion requires “Pow” in the calculation. See the shader implementation for reference.

In addition your conversion from Color32 to Color and back is also kinda expensive, especially in such a tight loop. So you can probably increase performance by inlining the gamma conversion in your loop.

Apart from that Unity had a bad historical record in reading and writing png files, gamma and ppi information. I’m currently no working with Unity, but I once made my PNGTools which can read and “split” a png file into its “chunks”. That makes it easy to read / modify / write specific png chunks. See this question which was also about mistreated gamma information, though it was during loading, not writing.

At least the png tools could help you identifying what chunks Unity actually outputs. Note that the PNGTools do not “interpret” any of the chunks. It’s just a scaffold framework for reading and writing png files. It can not really interpret any of the data of the individual chunks besides the “pHYs” chunk since that was the original purpose ^^. I’m not sure if your problem could be solved by removing / adding / manipulating a gAMa chunk in the output image without any manual conversion.

ps: Since we generally talk about Color32 values and each color component is “converted” individually, it might be worth it to use a LUT (look up table) instead to avoid the whole byte-float-byte conversion and Pow issues. We only have 256 distinct values so that “may” be faster. Though there’s only one way to figure that out: you have to try it ^^.

2 Likes