I thought about this again. Textures may should still use sRGB curve. Since creators won’t directly display them as pictures but render them with models, and the tools they used to create textures have higher possibility to use sRGB curve rather than 2.2 curve.
I agree.
I looked into this a bit more and it looks like the glTF spec says this:
The base color texture MUST contain 8-bit values encoded with the sRGB opto-electronic transfer function so RGB values MUST be decoded to real linear values before they are used for any computations.
Which isn’t entirely clear on what function should be used to decode to real linear values.
It does imply that they should be decoded using the inverse sRGB opto-electronic transfer function, but it is not clearly stated. The original sRGB spec CIE 61966-2-1 doesn’t use this sort of terminology for the transfer functions, but it does state that transformation from sRGB code values to CIE 1931 XYZ values should use the piecewise functions and that the resulting XYZ values “represent optimum image colorimetry when viewed on the reference display, in the reference viewing conditions, by the reference observer…”
…in spite of the fact that the reference display uses 2.2 power function for its decoding.
So “simulating” the reference display’s 2.2 power function would be incorrect because using the piecewise function to linearize, according to the sRGB spec, will produce linear values that match the 2.2 power reference display. (It actually doesn’t in practice, but this is how the spec says to do it.)
All that to say, the approach that Windows uses is correct according to the sRGB spec. The sRGB spec also goes on to acknowledge that this creates a mismatch, but states that this mismatch was worthwhile, at least back when sRGB came into existence:
One impact of this encoding specification is the creation of a mismatch between theoretical reference display tristimulus values and those generated from the encoding implementation. The advantages of optimising encoding outweigh the disadvantages of this mismatch. A linear portion of the transfer function of the dark-end signal is integrated into the encoding specification to optimise encoding implementations.
When sRGB spec was designed(1996), they never thought about the existence of modern HDR spec, so we can’t always follow what the spec says in terms of HDR.
sRGB CIE 61966-2-1: 5.1 Encoding transformations: Introduction (page 21), just before where it describes the use of a piecewise function to transform sRGB code values to linear XYZ values, in spite of this not matching the way that a reference display with 2.2 power behaves.
Please don’t map SDR content to the max reference luminance of the display. If you map a SDR application max white to 2000 nits on a 2000 nits display, you are going to burn the eyes of your users, especially for those gamers who play with the lights off. Typically, what you want to do for SDR content, like UI and stuff, is use a fixed UI luminance level like 300 nits. The peak luminance of the display can be used to configure the tone curve.
EDIT: The reason you want to use 300 nits for UI instead of a typical 200 nits is because you want UI for games to be brighter than the scene in all cases. That simple tweak will make it so that people have a higher opinion of the HDR build when they see it next to the SDR build which is what you want. Of course, good HDR is not only about luminance and I will point to Baldur’s Gate 3 on which I implemented the tone mapper and the color grading pipeline as an example of good HDR.
If we weed out the chaff from it, the colorimetric attributes that are in there are the primaries of the color space which are actually useless except for initializing another DirectX API struct, the min luminance which is generally useless too, the peak 10% luminance of the display, and the max full frame luminance. For configuring the tone curve, we want MaxLuminance from that struct.
EDIT: The reason why the display primaries are useless is because some displays, like my ASUS PA32UCX-R, have configurable color space in their OSD but will consistently report the native display primaries when queried through the Windows API. I believe this is because Windows fetches the display primaries from the EDID of the monitor. The documentation says that it can also fetch them from an installed ICC profile but since 99% of users have the default sRGB profile installed then I believe it ignores that one. In any case, that’s only a concern for non-color managed SDR mode. In color-managed HDR mode, the primaries are assumed to be either Rec. 2020 or scRGB (extended floating point sRGB with negative values) and the OS deals with all the necessary conversions.