PBS: honour non-sRGB colour targets in the pass hash - #584
PBS: honour non-sRGB colour targets in the pass hash#584steffen-roemer wants to merge 2 commits into
Conversation
preparePassHash hardcodes hw_gamma_write=1, assuming every colour target is sRGB. On a UNORM swapchain the linear lighting result then lands raw in the target and displays gamma-crushed (a mid-albedo surface under a zenith sun reads ~0.03 instead of ~0.5). Derive the property from the current pass descriptor's first colour target instead: sRGB targets keep hardware conversion exactly as before, and non-sRGB targets engage the existing !hw_gamma_write template path, whose shader-side encode was already written for this case but unreachable.
|
Thanks for the PR but there is a blocking issue which is why it wasn't fixed before and I just pretended it doesn't exist: Your solution assumes that if the target is not sRGB, then it should manually output as sRGB to preserve precision. It is simple to detect the case for RenderTargets like But there are targets like When we analyze the problem, we can inspect that there are two distinct problems (lol I sound like ChatGPT, but I swear LLMs copied me and not the reverse):
Ideally, that's what But sometimes reality can be disappointing because the swapchain may not have been created by you (e.g. Qt) and you don't know or it is impossible to request Technically you can workaround this by rendering everything to an internal RenderTexture in But if you want to avoid such workaround, then something more advanced is needed to indicate "I want it in sRGB regardless of what the pixel format says", because simply assuming everything should be output in sRGB is the wrong approach. |
What
HlmsPbs::preparePassHashhardcodeshw_gamma_write=1, assuming the colour target is always sRGB. When an app renders to a UNORM (non-sRGB) swapchain, PBS writes its linear lighting result raw into the target, and the image displays gamma-crushed — a mid-albedo surface under the zenith sun reads ~0.03 instead of ~0.5, and night/indoor scenes collapse to black.This PR derives the property from the live pass descriptor instead: if the first colour target's format is sRGB, hardware conversion is used exactly as today; otherwise
hw_gamma_writeis 0 and the existing!hw_gamma_writetemplate path gamma-encodes in the shader — that path was already written for this case but was unreachable with the hardcoded property.Why not just use an sRGB swapchain?
Engines mixing PBS 3D with byte-exact 2D/UI pipelines (or matching a legacy renderer pixel-for-pixel) legitimately run UNORM swapchains. The template code says this configuration was meant to work; only the pass-hash property disagreed.
How tested
macOS 15 / Apple Silicon, Metal RS, static build via vcpkg at master ef2e8f3: measured readback of a mid-grey PBS reference under a known directional light on a UNORM swapchain — ~0.19 before, ~0.43 after (the sqrt-encode expectation); sRGB-target rendering byte-identical before/after (property still 1 there). Soaked through an engine's full desktop suite (789 green) including an Hlms-Unlit 2D parity pixel test that stays byte-identical.