A second take on HDR support with an SDR white point and HDR headroom

This better reflects how HDR content is actually used, e.g. most content is in the SDR range, with specular highlights and bright details beyond the SDR range, in the HDR headroom.

This more closely matches how HDR is handled on Apple platforms, as EDR.

This also greatly simplifies application code which no longer has to think about color scaling. SDR content is rendered at the appropriate brightness automatically, and HDR content is scaled to the correct range for the display HDR headroom.
This commit is contained in:
Sam Lantinga
2024-02-19 08:45:02 -08:00
parent 3b7533f4a2
commit 4ba6aeee9d
24 changed files with 430 additions and 546 deletions

View File

@@ -206,14 +206,15 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
* The following properties are understood by SDL:
*
* - `SDL_PROP_SURFACE_COLORSPACE_NUMBER`: an SDL_ColorSpace value describing
* the surface colorspace, defaults to SDL_COLORSPACE_SCRGB for floating
* the surface colorspace, defaults to SDL_COLORSPACE_SRGB_LINEAR for floating
* point formats, SDL_COLORSPACE_HDR10 for 10-bit formats,
* SDL_COLORSPACE_SRGB for other RGB surfaces and SDL_COLORSPACE_BT709_FULL
* for YUV textures.
* - `SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING`: the tone mapping operator
* used when converting between different colorspaces. Currently this
* supports the form "*=N", where N is a floating point scale factor applied
* in linear space.
* for YUV surfaces.
* - `SDL_PROP_SURFACE_MAXCLL_NUMBER`: MaxCLL (Maximum Content Light Level) indicates the maximum light level of any single pixel (in cd/m2 or nits) of the content. MaxCLL is usually measured off the final delivered content after mastering. If one uses the full light level of the HDR mastering display and adds a hard clip at its maximum value, MaxCLL would be equal to the peak luminance of the mastering monitor. This defaults to 400 for HDR10 surfaces.
* - `SDL_PROP_SURFACE_MAXFALL_NUMBER`: MaxFALL (Maximum Frame Average Light Level) indicates the maximum value of the frame average light level (in cd/m2 or nits) of the content. MaxFALL is calculated by averaging the decoded luminance values of all the pixels within a frame. MaxFALL is usually much lower than MaxCLL.
* - `SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT`: for HDR10 and floating point surfaces, this defines the value of 100% diffuse white, with higher values being displayed in the High Dynamic Range headroom. This defaults to 100 for surfaces using the PQ colorspace and 1.0 for other surfaces.
* - `SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT`: for HDR10 and floating point surfaces, this defines the maximum dynamic range used by the content, in terms of the SDR white point. This defaults to SDL_PROP_SURFACE_MAXCLL_NUMBER / SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT, or 4.0, for HDR10 surfaces.
* - `SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING`: the tone mapping operator used when converting between different SDR/HDR ranges. Currently this supports the form "*=N", where N is a floating point scale factor applied in linear space.
*
* \param surface the SDL_Surface structure to query
* \returns a valid property ID on success or 0 on failure; call
@@ -227,6 +228,10 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface);
#define SDL_PROP_SURFACE_COLORSPACE_NUMBER "SDL.surface.colorspace"
#define SDL_PROP_SURFACE_MAXCLL_NUMBER "SDL.surface.maxCLL"
#define SDL_PROP_SURFACE_MAXFALL_NUMBER "SDL.surface.maxFALL"
#define SDL_PROP_SURFACE_SDR_WHITE_POINT_FLOAT "SDL.surface.SDR_white_point"
#define SDL_PROP_SURFACE_HDR_HEADROOM_FLOAT "SDL.surface.HDR_headroom"
#define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
/**
@@ -247,7 +252,7 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceColorspace(SDL_Surface *surface, SDL_C
/**
* Get the colorspace used by a surface.
*
* The colorspace defaults to SDL_COLORSPACE_SCRGB for floating point formats,
* The colorspace defaults to SDL_COLORSPACE_SRGB_LINEAR for floating point formats,
* SDL_COLORSPACE_HDR10 for 10-bit formats, SDL_COLORSPACE_SRGB for other RGB
* surfaces and SDL_COLORSPACE_BT709_FULL for YUV textures.
*
@@ -723,7 +728,7 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormat(SDL_Surface *surfa
* \sa SDL_ConvertSurface
* \sa SDL_CreateSurface
*/
extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormatAndColorspace(SDL_Surface *surface, Uint32 pixel_format, SDL_Colorspace colorspace);
extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormatAndColorspace(SDL_Surface *surface, Uint32 pixel_format, SDL_Colorspace colorspace, SDL_PropertiesID props);
/**
* Copy a block of pixels of one format to another format.
@@ -764,7 +769,7 @@ extern DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height, Uint32 src_
*
* \since This function is available since SDL 3.0.0.
*/
extern DECLSPEC int SDLCALL SDL_ConvertPixelsAndColorspace(int width, int height, Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch, Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch);
extern DECLSPEC int SDLCALL SDL_ConvertPixelsAndColorspace(int width, int height, Uint32 src_format, SDL_Colorspace src_colorspace, SDL_PropertiesID src_properties, const void *src, int src_pitch, Uint32 dst_format, SDL_Colorspace dst_colorspace, SDL_PropertiesID dst_properties, void *dst, int dst_pitch);
/**
* Premultiply the alpha on a block of pixels.