1

I used the DirectXTex library to capture a screenshot of a DX11 game and save it to a file. The problem is that it works great when I save it as jpeg but if I save it as png the image would become super bright and washed out. I checked the image using TweakPNG and found out the gamma was set to 1.0 and that's what's causing the problem. TweakPNG I checked images taken by some other software including the snipping tool and they seem to use 0.45455 as gamma or they leave out the gamma value altogether.

I don't know if DirectXTex will let me specify a gamma value or not. I'm not even sure if WIC has this functionality as I can't seem to find useful information either on MSDN or other sites.

uNiverselEgacy
  • 337
  • 3
  • 14

1 Answers1

3

By default DirectXTex will add the sRGB chunk to the PNG file it writes if the format is DXGI_FORMAT_*_SRGB. Furthermore, if the format is not DXGI_FORMAT_*_SRGB I explicitly remove the sRGB chunk and set the gAMA chunk to 1.0 because otherwise WIC always adds the sRGB chunk.

You can see this behavior in the code in both DirectXTexWIC.cpp and in the DirectX Tool Kit's ScreenGrab.cpp module.

If you are not doing 'gamma-correct' rendering where your render target is an DXGI_FORMAT_*_SRGB format but have sRGB content in a DXGI_FORMAT_* format, then my recommendation is that you pass an sRGB version of the format to the function.

In DirectXTex, that's easily done with the MakeSRGB function.

Gamma correction in the PNG format is a bit of a mess. See this blog post

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
  • Thanks for your answer. I created a staging back buffer with the corresponding `*_SRGB` format and it worked. However, I was wondering if there's a reason you chose 1.0 as gamma? I commented out the whole else block where you set the gamma and it also worked just fine. I think `WIC` treated it as sRGB anyway and used the default gamma, which seems to be "more appropriate" at least in `Windows 10`. – uNiverselEgacy Jun 26 '18 at 02:41
  • The surface is likely to be sRGB (approximately the same as raising to the power of 2.2) or 'linear' (no gamma which is the same as raising a value to the power of 1.0). In the case of many textures in modern games, they are often encoding linear data. If you provide an explicitly ``_SRGB`` format, then it's clear that it's correct to write it as sRGB. If you don't provide an ``_SRGB`` format, then it is quite possibly wrong to write it as sRGB. – Chuck Walbourn Jun 26 '18 at 06:08
  • I see. There was another problem though. `Resize` now takes forever when working with `SRGB` formats. I mean orders of magnitude slower. I checked the source code and and found out that I can specify `TEX_FILTER_FORCE_WIC` and everything would be fast again. I'm not sure if this is a proper use of this option or not. – uNiverselEgacy Jun 27 '18 at 03:16
  • Are you using Debug or Release mode? The DirectXTex library avoids using WIC for various combinations of formats because it will do the 'wrong thing' in many cases, so it uses the software implementation internally instead. You can use that flag to force the use of WIC and override that logic as well. – Chuck Walbourn Jun 27 '18 at 18:16
  • I tested in both. In Debug mode it took 40x longer. In Release mode it was much better but still took 8x longer. – uNiverselEgacy Jun 27 '18 at 21:16
  • Well, WIC has integer math optimized paths for a few formats, while DirectXTex takes a generalized approach to convert everything to float. Where WIC works, it work well. There's just a *lot* of cases where for textures WIC doesn't do what you expect or need it to do... For example, it always assumes <= 8bits per channel is sRGB, so if you try to convert it to a > 8 bit UNORM or any FLOAT it will do a sRGB to linear gamma conversion even if you don't want it to. There's lots of other edge cases as well. The reason I force non-WIC paths for sRGB is to ensure you get linearly correct results. – Chuck Walbourn Jun 28 '18 at 00:09