Added a simple linear scale for tonemapped HDR to SDR surface conversion
parent
fc35b7e121
commit
19dde63e7c
|
@ -232,6 +232,7 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||||
* cd/m2 or nits) of the entire playback sequence. MaxFALL is calculated by
|
* cd/m2 or nits) of the entire playback sequence. MaxFALL is calculated by
|
||||||
* averaging the decoded luminance values of all the pixels within a frame.
|
* averaging the decoded luminance values of all the pixels within a frame.
|
||||||
* MaxFALL is usually much lower than MaxCLL.
|
* MaxFALL is usually much lower than MaxCLL.
|
||||||
|
* - `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.
|
||||||
*
|
*
|
||||||
* \param surface the SDL_Surface structure to query
|
* \param surface the SDL_Surface structure to query
|
||||||
* \returns a valid property ID on success or 0 on failure; call
|
* \returns a valid property ID on success or 0 on failure; call
|
||||||
|
@ -247,6 +248,7 @@ extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *s
|
||||||
#define SDL_PROP_SURFACE_COLORSPACE_NUMBER "SDL.surface.colorspace"
|
#define SDL_PROP_SURFACE_COLORSPACE_NUMBER "SDL.surface.colorspace"
|
||||||
#define SDL_PROP_SURFACE_MAXCLL_NUMBER "SDL.surface.maxCLL"
|
#define SDL_PROP_SURFACE_MAXCLL_NUMBER "SDL.surface.maxCLL"
|
||||||
#define SDL_PROP_SURFACE_MAXFALL_NUMBER "SDL.surface.maxFALL"
|
#define SDL_PROP_SURFACE_MAXFALL_NUMBER "SDL.surface.maxFALL"
|
||||||
|
#define SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING "SDL.surface.tonemap"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the colorspace used by a surface.
|
* Set the colorspace used by a surface.
|
||||||
|
|
|
@ -664,12 +664,44 @@ static void WriteFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, SDL_Pixel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float CompressPQtoSDR(float v)
|
typedef enum
|
||||||
{
|
{
|
||||||
/* This gives generally good results for PQ HDR -> SDR conversion, scaling from 400 nits to 80 nits,
|
SDL_TONEMAP_NONE,
|
||||||
* which is scRGB 1.0
|
SDL_TONEMAP_LINEAR,
|
||||||
*/
|
} SDL_TonemapOperator;
|
||||||
return (v / 5.0f);
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SDL_TonemapOperator op;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
float scale;
|
||||||
|
} linear;
|
||||||
|
} data;
|
||||||
|
|
||||||
|
} SDL_TonemapContext;
|
||||||
|
|
||||||
|
static void ApplyTonemap(SDL_TonemapContext *ctx, float *r, float *g, float *b)
|
||||||
|
{
|
||||||
|
switch (ctx->op) {
|
||||||
|
case SDL_TONEMAP_LINEAR:
|
||||||
|
*r *= ctx->data.linear.scale;
|
||||||
|
*g *= ctx->data.linear.scale;
|
||||||
|
*b *= ctx->data.linear.scale;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_bool IsHDRColorspace(SDL_Colorspace colorspace)
|
||||||
|
{
|
||||||
|
if (colorspace == SDL_COLORSPACE_SCRGB ||
|
||||||
|
SDL_COLORSPACETRANSFER(colorspace) == SDL_TRANSFER_CHARACTERISTICS_PQ) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The SECOND TRUE BLITTER
|
/* The SECOND TRUE BLITTER
|
||||||
|
@ -694,29 +726,30 @@ void SDL_Blit_Slow_Float(SDL_BlitInfo *info)
|
||||||
SlowBlitPixelAccess src_access;
|
SlowBlitPixelAccess src_access;
|
||||||
SlowBlitPixelAccess dst_access;
|
SlowBlitPixelAccess dst_access;
|
||||||
SDL_Colorspace src_colorspace;
|
SDL_Colorspace src_colorspace;
|
||||||
SDL_ColorPrimaries src_primaries;
|
|
||||||
SDL_TransferCharacteristics src_transfer;
|
|
||||||
SDL_Colorspace dst_colorspace;
|
SDL_Colorspace dst_colorspace;
|
||||||
SDL_ColorPrimaries dst_primaries;
|
const float *color_primaries_matrix = NULL;
|
||||||
SDL_TransferCharacteristics dst_transfer;
|
SDL_TonemapContext tonemap;
|
||||||
const float *color_primaries_matrix;
|
|
||||||
SDL_bool compress_PQ = SDL_FALSE;
|
|
||||||
|
|
||||||
if (SDL_GetSurfaceColorspace(info->src_surface, &src_colorspace) < 0 ||
|
if (SDL_GetSurfaceColorspace(info->src_surface, &src_colorspace) < 0 ||
|
||||||
SDL_GetSurfaceColorspace(info->dst_surface, &dst_colorspace) < 0) {
|
SDL_GetSurfaceColorspace(info->dst_surface, &dst_colorspace) < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
src_primaries = SDL_COLORSPACEPRIMARIES(src_colorspace);
|
tonemap.op = SDL_TONEMAP_NONE;
|
||||||
src_transfer = SDL_COLORSPACETRANSFER(src_colorspace);
|
if (src_colorspace != dst_colorspace) {
|
||||||
dst_primaries = SDL_COLORSPACEPRIMARIES(dst_colorspace);
|
SDL_ColorPrimaries src_primaries = SDL_COLORSPACEPRIMARIES(src_colorspace);
|
||||||
dst_transfer = SDL_COLORSPACETRANSFER(dst_colorspace);
|
SDL_ColorPrimaries dst_primaries = SDL_COLORSPACEPRIMARIES(dst_colorspace);
|
||||||
color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, dst_primaries);
|
color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, dst_primaries);
|
||||||
|
|
||||||
if (src_transfer == SDL_TRANSFER_CHARACTERISTICS_PQ &&
|
if (IsHDRColorspace(src_colorspace) != IsHDRColorspace(dst_colorspace)) {
|
||||||
dst_transfer != SDL_TRANSFER_CHARACTERISTICS_PQ &&
|
const char *tonemap_operator = SDL_GetStringProperty(SDL_GetSurfaceProperties(info->src_surface), SDL_PROP_SURFACE_TONEMAP_OPERATOR_STRING, NULL);
|
||||||
dst_colorspace != SDL_COLORSPACE_SCRGB) {
|
if (tonemap_operator) {
|
||||||
//compress_PQ = SDL_TRUE;
|
if (SDL_strncmp(tonemap_operator, "*=", 2) == 0) {
|
||||||
|
tonemap.op = SDL_TONEMAP_LINEAR;
|
||||||
|
tonemap.data.linear.scale = SDL_atof(tonemap_operator + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
src_access = GetPixelAccessMethod(src_fmt);
|
src_access = GetPixelAccessMethod(src_fmt);
|
||||||
|
@ -742,10 +775,8 @@ void SDL_Blit_Slow_Float(SDL_BlitInfo *info)
|
||||||
SDL_ConvertColorPrimaries(&srcR, &srcG, &srcB, color_primaries_matrix);
|
SDL_ConvertColorPrimaries(&srcR, &srcG, &srcB, color_primaries_matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compress_PQ) {
|
if (tonemap.op) {
|
||||||
srcR = CompressPQtoSDR(srcR);
|
ApplyTonemap(&tonemap, &srcR, &srcG, &srcB);
|
||||||
srcG = CompressPQtoSDR(srcG);
|
|
||||||
srcB = CompressPQtoSDR(srcB);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & SDL_COPY_COLORKEY) {
|
if (flags & SDL_COPY_COLORKEY) {
|
||||||
|
|
Loading…
Reference in New Issue