Skip to content
Snippets Groups Projects

Add extended sRGB linear known transfer function

Closed Autumn Ashton requested to merge frog/wayland-protocols:scrgb-linear into color
4 unresolved threads

Based upon the wording in https://registry.khronos.org/EGL/extensions/EXT/EGL_EXT_gl_colorspace_scrgb_linear.txt

This can be achieved already by using linear + set luminances, however not all compositors will implement that, but probably want to support this TF as it is very commonly used in games and desktop applications.

Signed-off-by: Joshua Ashton joshua@froggi.es

Merge request reports

Merge request pipeline #1225539 passed

Merge request pipeline passed for 45d05dca

Merged by avatar (Mar 28, 2025 7:09am UTC)

Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
    • This is just linear with the black level modified to be 0 nit and trying to sidestep the feature mechanism for extended_target_volume.

    • Yes. Not every compositor wants to expose extended_target_volume or set_luminances, and they should not be required for this common tf.

    • This doesn't change anything about extended_target_volume, clients can only really rely on being able to use colors outside of the rec.709 gamut with scRGB if that's supported.

      set_luminances is not something every compositor can (if fixed function hw is involved) or wants to support though, and I think it's entirely reasonable not to require it for scRGB.

    • Ah yes, good point, as you need negatives to represent stuff outside Rec.709.

      But yes, set_luminances still stands

      Edited by Autumn Ashton
    • I just noticed that if we do !51 (merged) - clamping pixel values to the valid range - then linear + set_luminances is not actually enough to implement scRGB

    • I've been wondering if "linear" should just deviate from H.273 a bit and be defined for all real numbers. Do you know of any immediate reasons to not do that?

    • Proposed in !84 (merged) .

    • After talking to @swick, the point about extended_target_volume is as follows.

      I have heard that gamescope does not want to support set_luminances because it wants to be able to pre-generate all color transformation LUTs in advance. This means it can only support a fixed enumerated list of image descriptions. set_luminances has free parameters instead.

      Support for windows-scRGB requires the ability to handle negative color channel (optical) values. Support for negative optical values is indicated to clients with the extended_target_volume feature flag. That flag requires support for set_mastering_display_primaries as well, and the MDCV has no enumeration, it's all free parameters. The fixed list of image descriptions is insufficient to advertise extended_target_volume.

      This leads to one of two things:

      • The compositor advertises extended_target_volume but ignores MDCV, or
      • the compositor makes windows-scRGB clients rely on undefined behavior by not advertising extended_target_volume.

      Neither is good, but both are workable if you use only apps that expect gamescope specifically.

    • Please register or sign in to reply
  • Pekka Paalanen
  • Pekka Paalanen mentioned in merge request !83 (merged)

    mentioned in merge request !83 (merged)

  • Pekka Paalanen
  • 368 368 used here for HLG assume a 1000 cd/m² display.
    369 369 </description>
    370 370 </entry>
    371 <entry name="ext_srgb_linear" value="14">
    372 <description summary="linear display-referred scRGB color space">
    373 Transfer characteristics as defined by
    374 - IEC 61966-2-2:2003
    • Comment on lines +372 to +374

      Does IEC 61966-2-2:2003 also define 1.0 = 80 cd/m²? Does it allow normalized values beyond [-0.5, 7.5]?

      Maybe this should be named and explicitly defined as Windows (10? 11?) behavior of their scRGB? Maybe Microsoft even has a freely accessible spec?

      I'm getting the feeling that IEC 61966-2-2:2003 and Windows are two different scRGB specs.

      That "color space" is incorrect in the description, this is a transfer function.

    • Please register or sign in to reply
  • Pekka Paalanen mentioned in merge request !84 (merged)

    mentioned in merge request !84 (merged)

  • Pekka Paalanen
  • 376 The expected mapping is such that a color value of (1.0, 1.0, 1.0)
    377 corresponds to a luminance level of 80 nits on a standardized studio
    378 monitor.
    379 As the color value per channel goes beyond 1.0 and up to 125.0, the
    380 corresponding luminance levels also increase linearly to
    381 a maximum of 10000 nits.
    382
    383 Equivalent to EGL_EXT_gl_colorspace_scrgb_linear in OpenGL and
    384 VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT in Vulkan.
    385
    386 This TF implies these default luminances
    387 - primary color volume minimum: 0 cd/m²
    388 - primary color volume maximum: 80 cd/m²
    389 - reference white: 80 cd/m²
    390 </description>
    391 </entry>
    • Suggested change
      371 <entry name="ext_srgb_linear" value="14">
      372 <description summary="linear display-referred scRGB color space">
      373 Transfer characteristics as defined by
      374 - IEC 61966-2-2:2003
      375
      376 The expected mapping is such that a color value of (1.0, 1.0, 1.0)
      377 corresponds to a luminance level of 80 nits on a standardized studio
      378 monitor.
      379 As the color value per channel goes beyond 1.0 and up to 125.0, the
      380 corresponding luminance levels also increase linearly to
      381 a maximum of 10000 nits.
      382
      383 Equivalent to EGL_EXT_gl_colorspace_scrgb_linear in OpenGL and
      384 VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT in Vulkan.
      385
      386 This TF implies these default luminances
      387 - primary color volume minimum: 0 cd/m²
      388 - primary color volume maximum: 80 cd/m²
      389 - reference white: 80 cd/m²
      390 </description>
      391 </entry>
      371 <entry name="ext_linear_80" value="14">
      372 <description summary="extended linear TF with fixed luminance">
      373 This is the linear transfer function with extended domain,
      374 defined over all finite real values, negative included.
      375
      376 The expected mapping is such that a color value of (1.0, 1.0, 1.0)
      377 corresponds to a luminance level of 80 nits on a standardized studio
      378 monitor.
      379 As the color value per channel goes beyond 1.0 and up to 125.0, the
      380 corresponding luminance levels also increase linearly to
      381 a maximum of 10000 nits.
      382 This is intended to be equivalent to the Windows 10 definition of
      383 the linear transfer characteristic for scRGB.
      384
      385 Equivalent to EGL_EXT_gl_colorspace_scrgb_linear in OpenGL and
      386 VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT in Vulkan.
      387
      388 This TF implies these default luminances
      389 - primary color volume minimum: 0 cd/m²
      390 - primary color volume maximum: 80 cd/m²
      391 - reference white: 80 cd/m²
      392 </description>
      393 </entry>

      I propose the name ext_linear_80 to put this apart from linear and ext_linear which do not define 0.0 = 0 cd/m² and 1.0 = 80 cd/m².

      The EGL ext spec refers to IEC 61966-2-2:2003 for "details on scRGB color space". Since we are defining a transfer characteristic, the primaries and the white point do not matter. As I don't currently have access to IEC 61966-2-2:2003 I'm not sure what it defines. Wikipedia claims it uses the range [-0.5, 7.5), so it does not go up to 125.0. I also doubt it specifies 1.0 = 80 cd/m². These conventions that are in the core of a transfer characteristic are defined elsewhere, so I propose to drop the reference to IEC 61966-2-2:2003.

    • From IRC on Oct 10-11:

      @swick

      < swick[m]> pq: with ext_linear_80 would you then still want linear to have a different default luminance of 0?

      That is another discussion.

      < swick[m]> I also still don't get how I'm supposed to understand infinite contrast

      < swick[m]> you can argue that only a subset should be used via the mastering luminances but they are not required

      When MDCV luminances are not given, they are defaulted to those of the primary color volume.

      < swick[m]> Windows maps that to PQ which means you could probably use the PQ black level here to get the right semantics?

      Where is PQ black level defined? I have only seen BT.2100 saying the display black level should be less or equal to 0.005 cd/m².

      @Zamundaaa told me that some displays, when taking the minimum luminance from EDID, converting that to PQ code point and sending it to display, will result in significantly brighter pixels than the said minimum luminance. This is contrary to what I assumed how PQ with its "absoluteness" works.

      < swick[m]> but then again IIRC, the 80 from there gets mapped to 203(?) in PQ so that doesn't really make sense either

      < swick[m]> maybe it makes sense to put the black level at (PQ black level) * (203/80) so code value 0 in ext_linear_80 gets mapped to the PQ black level when 80 nits in ext_linear_80 gets mapped to 203 nits in PQ

      < swick[m]> eh, (PQ black level) * (80/203)

      < swick[m]> which is ~0.002 instead of the 0.005 from PQ

      < zamundaaa[m]> <swick[m]> "but then again IIRC, the 80 from..." <- No, nothing gets mapped on Windows

      < zamundaaa[m]> 1 nit encoded in scRGB means that it outputs 1 nit in PQ to the screen

      < swick[m]> ah well, then just define it to be PQ black level

      < swick[m]> that makes it easier

      < swick[m]> pq: and why is reference white at 80 when that maps to pq 80 on windows and there 203 is the reference white?

      Because windows maps 1.0 to 80 cd/m², hence reference white must equal primary color volume max luminance and both must equal 80 cd/m². This is the point of having ext_linear_80.

    • Because windows maps 1.0 to 80 cd/m²

      It does, but that does not mean the reference luminance is 80 cd/m², as that would require it to map 1.0 to 203cd/m² on PQ screens. The suggested ext_linear_80 would work great for Qt, but mapping Windows scRGB to it would result in games being way too bright.

    • @Zamundaaa, that brings us back to !78 (comment 2561733) .

      I guess I was mislead by the mapping of sRGB to scRGB, where sRGB reference white is at 1.0. IOW, when Windows maps sRGB to scRGB for HDR display, it will multiply the optical sRGB values by RW/80 rather than taking them as scRGB directly (RW = reference white cd/m²)?

      Do I understand correctly that ext_linear_80 needs to explicitly say that the reference white is unknown? Or set it to 203 cd/m² with a note that it is a guess that may be incorrect? Or that Windows passes these luminance values as-is to a BT.2100/PQ sink?

      linear ext_linear ext_linear_80
      domain [0, 1] real numbers real numbers
      min cd/m² 0.2 0 0
      max cd/m² 80 80 80
      ref cd/m² 80 80 unknown

      Is this what we need?

    • Curiously, EGL_EXT_gl_colorspace_scrgb_linear != Windows scRGB. But you also don't use EGL on Windows, you use WGL instead? So up to Wine to map this correctly.

      I didn't find Vulkan or Khronos Data Format Specification saying anything towards Windows scRGB, so I presume they match EGL_EXT_gl_colorspace_scrgb_linear instead. This raises the question of how does VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT work on Windows.

    • I guess I was mislead by the mapping of sRGB to scRGB, where sRGB reference white is at 1.0. IOW, when Windows maps sRGB to scRGB for HDR display, it will multiply the optical sRGB values by RW/80 rather than taking them as scRGB directly (RW = reference white cd/m²)?

      Yes.

      Do I understand correctly that ext_linear_80 needs to explicitly say that the reference white is unknown? Or set it to 203 cd/m² with a note that it is a guess that may be incorrect? Or that Windows passes these luminance values as-is to a BT.2100/PQ sink?

      Yeah, I think we should just have a ext_windows_scrgb with the reference luminance specified as unknown, and 203 cd/m² as a recommendation for how compositors can deal with it.

      Curiously, EGL_EXT_gl_colorspace_scrgb_linear != Windows scRGB. But you also don't use EGL on Windows, you use WGL instead? So up to Wine to map this correctly.

      I would be surprised if it behaved any different depending on the API, it'll all map down to the same Windows API.

      I didn't find Vulkan or Khronos Data Format Specification saying anything towards Windows scRGB, so I presume they match EGL_EXT_gl_colorspace_scrgb_linear instead. This raises the question of how does VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT work on Windows.

      It works the same way as what we've been discussing this entire time - it just ignores the reference luminance and re-encodes the whole thing with PQ for the screen.

      It does raise the question for what Mesa should do, emulate the Windows behavior or do proper scRGB... but on the protocol level we really just have to offer the choice and let Mesa and Wine deal with it.

    • Right. I'm still caught on the inconsistency. EGL_EXT_gl_colorspace_scrgb_linear says:

      For each color channel, the floating-point values of 0.0 and 1.0 still correspond to sRGB chromaticities and luminance levels. [...] The expected mapping is such that a color value of (1.0, 1.0, 1.0) corresponds to a luminance level of 80 nits on a standardized studio monitor.

      Presumably the "standardized studio monitor" is in a standardized viewing environment where that 80 cd/m² applies literally.

      If scRGB is taken to PQ as-is, but sRGB is first multiplied by RW/80, then it is impossible to "correspond to sRGB [...] luminance levels" unless RW = 80.

      Ok, I think I'm starting to understand what this is about. That's the difference we want to represent: relative vs. PQ-absolute luminance:

      • Relative luminance systems have the reference white at optical code point (1.0, 1.0, 1.0), and the reference white is monitor and environment dependent. The window system can apply the reference levels when converting to a PQ monitor signal.
      • PQ-absolute luminance (Windows) systems pass the signal as-is to a monitor. The reference levels are set in the application and never communicated to the window system, hence a translation layer like Wine cannot forward the luminance levels from the app, nor can it correctly guess or assume them.

      The application set reference levels may be non-optimal for the monitor and the environment, and the end user may or may not want to have a global adjustment to them. Separating the two cases into different TFs lets compositors handle them differently as necessary:

      • A normal contrast setting changing the reference white level of all relative luminance content.
      • In addition to above or alternatively, a PQ contrast setting for all PQ-absolute luminance content.

      Another potential difference in handling them is linear vs. logarithmic scaling (multiplier vs. gamma correction), maybe depending on how close to Windows behavior a compositor wants to be.

    • FTR, from IRC today, @swick strongly disagrees with this. He says the handling of the unknown (reference white level) should not be dumped to the compositors, and that everything a compositor might do can already be done at the client side by crafting a different image description by the help of set_luminances.

      He believes that if some use cases really cannot be implemented well without compositor support, he would very much prefer them to be contained to Wine (e.g. via the wine shell wayland protocol idea).

    • Further pondering on whether ext_linear_80 or windows-scRGB special case should exist at all...

      I would like to draw equivalence between windows-scRGB and PQ encoded contents in terms of luminance levels, but @swick pointed out that while PQ encoded content can usually be assumed to be PQ reference viewing conditions referred, windows-scRGB might be that or display-at-hand referred or neither. So another way to pose the dilemma, that also encompasses PQ, is to ask "referred to which display"?

      That question is supposed to be approximately answered by set_luminances request. It has two issues:

      • I hear that not everyone wants to implement set_luminances: gamescope generates all transformations at start-up, so cannot yet support free parameters. They want the possible values enumerated instead, and the proposal here is using the TF enum for that purpose.
      • Indicating display-at-hand referred luminances is complicated. One would need to get the luminance levels from the output or surface-preferred image description, and set them in one's own.(*) The reference white level cannot currently be set to "unknown" as a shorthand for this.

      (*) Getting the actual luminance levels would be the right thing to do, as one cannot render for it otherwise. However, as said before, Windows games tend to ignore that and offer their own settings instead. However, I do think the client (Wine, Proton, SDL, etc.) should strive to do this, even if the game ignores the value.

      Display-at-hand referred content has a fundamental problem of its own: since the content is said to be rendered for the display at hand, compositor contrast settings would have no effect on it. Yet, I hear that compositor settings should apply regardless. That's a conflict by definition. The solution is to never claim display-at-hand reference if compositor settings should apply. Claim reference to some other display instead, adjust the application settings to render for that display, and let the compositor translate the image to the display-at-hand. Which other display? BT.2100/PQ reference viewing conditions seem like a good bet. They are used with PQ encoded content, and Windows transcodes windows-scRGB to PQ signal as-is.

      Now I've circled back to setting reference white at 203 cd/m² for windows-scRGB, and trusting that any discrepancy between that and the app can be fixed in app settings, and any discrepancy between that and the display-at-hand is globally fixed in the compositor. However, it's not exactly back to square one: a compositor can still have separate contrast settings for relative and PQ-absolute luminance contents. We don't need a new TF code to differentiate between them. If someone wants PQ content to be sent to monitor as-is, they only need to adjust the PQ-absolute contrast accordingly, once.

      The new TF code would be just for an enumeration of supported set_luminances parameters. And only for gamescope?

      I think a minimum viable implementation of set_luminances would be a single multiplier in optical space. Black-point compensation would remove the need of applying an offset. OTOH, that does not help if one wants to use a pre-computed LUT for electrical-to-electrical transformation.


      Compromise proposition (again):

      Define ext_linear_80 with default reference white equal to BT.2100/PQ viewing conditions. Do not allow unknown reference levels.

      Would that be acceptable?

    • Please register or sign in to reply
  • FTR, now I do think this proposal is good to have, and is not replaced by e.g. !84 (merged) . What to do with the other linear variants are other discussions.

    • I'm starting to think that the initial phrasing "linear display-referred scRGB color space" in the TF enumeration was actually intended to convey all of

      • linear TF
      • windows-scRGB luminances
      • windows-scRGB target color volume (MDCV)

      It doesn't fit the parametric API design. The TF was meant to be just a TF. Luminance defaults kind of can be counted in, because PQ is TF with luminance defined. But MDCV has nothing to do with a TF.

      Do we want to hack windows-scRGB in the parametric API like this?

      Or should we have a third factory API: enumerated image descriptions, where windows-scRGB as a whole is defined with a single enum entry?

      Or should we introduce enumerated target color volumes in the parametric API?

    • !89 (merged) is my proposal to tackle this, and make it clearly a separate definition without complicating the parametric factory.

    • Please register or sign in to reply
  • Pekka Paalanen mentioned in merge request !89 (merged)

    mentioned in merge request !89 (merged)

  • Closing as !89 (merged) landed.

  • Please register or sign in to reply
    Loading