mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-06-06 23:40:54 +00:00
Added support for other HDR color primaries
Specifically, SDL_COLOR_PRIMARIES_XYZ, SDL_COLOR_PRIMARIES_SMPTE431, and SDL_COLOR_PRIMARIES_SMPTE432
This commit is contained in:
parent
c5792cc0de
commit
8fe257b541
6 changed files with 77 additions and 25 deletions
|
@ -262,8 +262,6 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||||
*
|
*
|
||||||
* The following properties are understood by SDL:
|
* The following properties are understood by SDL:
|
||||||
*
|
*
|
||||||
* - `SDL_PROPERTY_SURFACE_HDR_BOOLEAN`: true if this surface has HDR
|
|
||||||
* properties
|
|
||||||
* - `SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER`: an SDL_ColorPrimaries
|
* - `SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER`: an SDL_ColorPrimaries
|
||||||
* value describing the surface colorspace
|
* value describing the surface colorspace
|
||||||
* - `SDL_PROPERTY_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER`: an
|
* - `SDL_PROPERTY_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER`: an
|
||||||
|
@ -291,7 +289,6 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
|
||||||
*/
|
*/
|
||||||
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface);
|
extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface);
|
||||||
|
|
||||||
#define SDL_PROPERTY_SURFACE_HDR_BOOLEAN "SDL.surface.HDR"
|
|
||||||
#define SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER "SDL.surface.color_primaries"
|
#define SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER "SDL.surface.color_primaries"
|
||||||
#define SDL_PROPERTY_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER "SDL.surface.transfer_characteristics"
|
#define SDL_PROPERTY_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER "SDL.surface.transfer_characteristics"
|
||||||
#define SDL_PROPERTY_SURFACE_MAXCLL_NUMBER "SDL.surface.maxCLL"
|
#define SDL_PROPERTY_SURFACE_MAXCLL_NUMBER "SDL.surface.maxCLL"
|
||||||
|
|
|
@ -187,7 +187,9 @@ static SDL_bool IsSurfaceHDR(SDL_Surface *surface)
|
||||||
{
|
{
|
||||||
if (surface->flags & SDL_SURFACE_USES_PROPERTIES) {
|
if (surface->flags & SDL_SURFACE_USES_PROPERTIES) {
|
||||||
SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
|
SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
|
||||||
return SDL_GetBooleanProperty(props, SDL_PROPERTY_SURFACE_HDR_BOOLEAN, SDL_FALSE);
|
if (SDL_GetNumberProperty(props, SDL_PROPERTY_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER, SDL_TRANSFER_CHARACTERISTICS_UNKNOWN) == SDL_TRANSFER_CHARACTERISTICS_SMPTE2084) {
|
||||||
|
return SDL_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -215,8 +217,10 @@ int SDL_CalculateBlit(SDL_Surface *surface)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
map->blit = SDL_SoftBlit;
|
map->blit = SDL_SoftBlit;
|
||||||
|
map->info.src_surface = surface;
|
||||||
map->info.src_fmt = surface->format;
|
map->info.src_fmt = surface->format;
|
||||||
map->info.src_pitch = surface->pitch;
|
map->info.src_pitch = surface->pitch;
|
||||||
|
map->info.dst_surface = dst;
|
||||||
map->info.dst_fmt = dst->format;
|
map->info.dst_fmt = dst->format;
|
||||||
map->info.dst_pitch = dst->pitch;
|
map->info.dst_pitch = dst->pitch;
|
||||||
|
|
||||||
|
@ -255,8 +259,8 @@ int SDL_CalculateBlit(SDL_Surface *surface)
|
||||||
} else {
|
} else {
|
||||||
/* Tone mapping from an HDR surface to SDR surface */
|
/* Tone mapping from an HDR surface to SDR surface */
|
||||||
SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
|
SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
|
||||||
if (SDL_GetNumberProperty(props, SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_BT2020) == SDL_COLOR_PRIMARIES_BT2020 &&
|
SDL_ColorPrimaries primaries = (SDL_ColorPrimaries)SDL_GetNumberProperty(props, SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_BT2020);
|
||||||
SDL_GetNumberProperty(props, SDL_PROPERTY_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER, SDL_TRANSFER_CHARACTERISTICS_SMPTE2084) == SDL_TRANSFER_CHARACTERISTICS_SMPTE2084) {
|
if (SDL_GetColorPrimariesConversionMatrix(primaries, SDL_COLOR_PRIMARIES_BT709) != NULL) {
|
||||||
if (SDL_ISPIXELFORMAT_10BIT(surface->format->format)) {
|
if (SDL_ISPIXELFORMAT_10BIT(surface->format->format)) {
|
||||||
blit = SDL_Blit_Slow_PQtoSDR;
|
blit = SDL_Blit_Slow_PQtoSDR;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -56,10 +56,12 @@ extern Uint8 *SDL_expand_byte[9];
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
SDL_Surface *src_surface;
|
||||||
Uint8 *src;
|
Uint8 *src;
|
||||||
int src_w, src_h;
|
int src_w, src_h;
|
||||||
int src_pitch;
|
int src_pitch;
|
||||||
int src_skip;
|
int src_skip;
|
||||||
|
SDL_Surface *dst_surface;
|
||||||
Uint8 *dst;
|
Uint8 *dst;
|
||||||
int dst_w, dst_h;
|
int dst_w, dst_h;
|
||||||
int dst_pitch;
|
int dst_pitch;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "SDL_blit.h"
|
#include "SDL_blit.h"
|
||||||
#include "SDL_blit_slow.h"
|
#include "SDL_blit_slow.h"
|
||||||
|
#include "SDL_pixels_c.h"
|
||||||
|
|
||||||
#define FORMAT_ALPHA 0
|
#define FORMAT_ALPHA 0
|
||||||
#define FORMAT_NO_ALPHA (-1)
|
#define FORMAT_NO_ALPHA (-1)
|
||||||
|
@ -236,6 +237,18 @@ void SDL_Blit_Slow(SDL_BlitInfo *info)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void MatrixMultiply(float v[3], const float *matrix)
|
||||||
|
{
|
||||||
|
float out[3];
|
||||||
|
|
||||||
|
out[0] = matrix[0 * 3 + 0] * v[0] + matrix[0 * 3 + 1] * v[1] + matrix[0 * 3 + 2] * v[2];
|
||||||
|
out[1] = matrix[1 * 3 + 0] * v[0] + matrix[1 * 3 + 1] * v[1] + matrix[1 * 3 + 2] * v[2];
|
||||||
|
out[2] = matrix[2 * 3 + 0] * v[0] + matrix[2 * 3 + 1] * v[1] + matrix[2 * 3 + 2] * v[2];
|
||||||
|
v[0] = out[0];
|
||||||
|
v[1] = out[1];
|
||||||
|
v[2] = out[2];
|
||||||
|
}
|
||||||
|
|
||||||
static float PQtoNits(float pq)
|
static float PQtoNits(float pq)
|
||||||
{
|
{
|
||||||
const float c1 = 0.8359375f;
|
const float c1 = 0.8359375f;
|
||||||
|
@ -251,25 +264,9 @@ static float PQtoNits(float pq)
|
||||||
return 10000.0f * SDL_powf(num / den, oo_m1);
|
return 10000.0f * SDL_powf(num / den, oo_m1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Convert2020to709(float v[3])
|
|
||||||
{
|
|
||||||
static const float matrix[3][3] = {
|
|
||||||
{ 1.660496f, -0.587656f, -0.072840f },
|
|
||||||
{ -0.124547f, 1.132895f, -0.008348f },
|
|
||||||
{ -0.018154f, -0.100597f, 1.118751f }
|
|
||||||
};
|
|
||||||
|
|
||||||
float out[3];
|
|
||||||
out[0] = matrix[0][0] * v[0] + matrix[0][1] * v[1] + matrix[0][2] * v[2];
|
|
||||||
out[1] = matrix[1][0] * v[0] + matrix[1][1] * v[1] + matrix[1][2] * v[2];
|
|
||||||
out[2] = matrix[2][0] * v[0] + matrix[2][1] * v[1] + matrix[2][2] * v[2];
|
|
||||||
v[0] = out[0];
|
|
||||||
v[1] = out[1];
|
|
||||||
v[2] = out[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This isn't really a tone mapping algorithm but it generally works well for HDR -> SDR display */
|
/* This isn't really a tone mapping algorithm but it generally works well for HDR -> SDR display */
|
||||||
static void PQtoSDR(float floatR, float floatG, float floatB, Uint32 *outR, Uint32 *outG, Uint32 *outB)
|
static void PQtoSDR(const float *color_primaries_matrix, float floatR, float floatG, float floatB, Uint32 *outR, Uint32 *outG, Uint32 *outB)
|
||||||
{
|
{
|
||||||
float v[3];
|
float v[3];
|
||||||
int i;
|
int i;
|
||||||
|
@ -278,7 +275,7 @@ static void PQtoSDR(float floatR, float floatG, float floatB, Uint32 *outR, Uint
|
||||||
v[1] = PQtoNits(floatG);
|
v[1] = PQtoNits(floatG);
|
||||||
v[2] = PQtoNits(floatB);
|
v[2] = PQtoNits(floatB);
|
||||||
|
|
||||||
Convert2020to709(v);
|
MatrixMultiply(v, color_primaries_matrix);
|
||||||
|
|
||||||
for (i = 0; i < SDL_arraysize(v); ++i) {
|
for (i = 0; i < SDL_arraysize(v); ++i) {
|
||||||
v[i] /= 400.0f;
|
v[i] /= 400.0f;
|
||||||
|
@ -313,6 +310,9 @@ void SDL_Blit_Slow_PQtoSDR(SDL_BlitInfo *info)
|
||||||
int dstfmt_val;
|
int dstfmt_val;
|
||||||
Uint32 rgbmask = ~src_fmt->Amask;
|
Uint32 rgbmask = ~src_fmt->Amask;
|
||||||
Uint32 ckey = info->colorkey & rgbmask;
|
Uint32 ckey = info->colorkey & rgbmask;
|
||||||
|
SDL_PropertiesID props = SDL_GetSurfaceProperties(info->src_surface);
|
||||||
|
SDL_ColorPrimaries src_primaries = (SDL_ColorPrimaries)SDL_GetNumberProperty(props, SDL_PROPERTY_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_BT2020);
|
||||||
|
const float *color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, SDL_COLOR_PRIMARIES_BT709);
|
||||||
|
|
||||||
dstfmt_val = detect_format(dst_fmt);
|
dstfmt_val = detect_format(dst_fmt);
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ void SDL_Blit_Slow_PQtoSDR(SDL_BlitInfo *info)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
PQtoSDR(srcFloatR, srcFloatG, srcFloatB, &srcR, &srcG, &srcB);
|
PQtoSDR(color_primaries_matrix, srcFloatR, srcFloatG, srcFloatB, &srcR, &srcG, &srcB);
|
||||||
srcA = (Uint32)(srcFloatA * 255);
|
srcA = (Uint32)(srcFloatA * 255);
|
||||||
|
|
||||||
if (flags & SDL_COPY_COLORKEY) {
|
if (flags & SDL_COPY_COLORKEY) {
|
||||||
|
|
|
@ -1173,3 +1173,51 @@ void SDL_FreeBlitMap(SDL_BlitMap *map)
|
||||||
SDL_free(map);
|
SDL_free(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float *SDL_GetColorPrimariesConversionMatrix(SDL_ColorPrimaries src, SDL_ColorPrimaries dst)
|
||||||
|
{
|
||||||
|
/* Conversion matrices generated using gamescope color helpers and the primaries definitions at:
|
||||||
|
* https://www.itu.int/rec/T-REC-H.273-201612-S/en
|
||||||
|
*/
|
||||||
|
static const float mat2020to709[] = {
|
||||||
|
1.660496f, -0.587656f, -0.072840f,
|
||||||
|
-0.124547f, 1.132895f, -0.008348f,
|
||||||
|
-0.018154f, -0.100597f, 1.118751f
|
||||||
|
};
|
||||||
|
static const float matXYZto709[] = {
|
||||||
|
3.240969f, -1.537383f, -0.498611f,
|
||||||
|
-0.969243f, 1.875967f, 0.041555f,
|
||||||
|
0.055630f, -0.203977f, 1.056971f,
|
||||||
|
};
|
||||||
|
static const float matSMPTE431to709[] = {
|
||||||
|
1.120713f, -0.234649f, 0.000000f,
|
||||||
|
-0.038478f, 1.087034f, 0.000000f,
|
||||||
|
-0.017967f, -0.082030f, 0.954576f,
|
||||||
|
};
|
||||||
|
static const float matSMPTE432to709[] = {
|
||||||
|
1.224940f, -0.224940f, -0.000000f,
|
||||||
|
-0.042057f, 1.042057f, 0.000000f,
|
||||||
|
-0.019638f, -0.078636f, 1.098273f,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (dst) {
|
||||||
|
case SDL_COLOR_PRIMARIES_BT709:
|
||||||
|
switch (src) {
|
||||||
|
case SDL_COLOR_PRIMARIES_BT2020:
|
||||||
|
return mat2020to709;
|
||||||
|
case SDL_COLOR_PRIMARIES_XYZ:
|
||||||
|
return matXYZto709;
|
||||||
|
case SDL_COLOR_PRIMARIES_SMPTE431:
|
||||||
|
return matSMPTE431to709;
|
||||||
|
case SDL_COLOR_PRIMARIES_SMPTE432:
|
||||||
|
return matSMPTE432to709;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,5 +44,6 @@ extern void SDL_InvalidateAllBlitMap(SDL_Surface *surface);
|
||||||
extern void SDL_DitherColors(SDL_Color *colors, int bpp);
|
extern void SDL_DitherColors(SDL_Color *colors, int bpp);
|
||||||
extern Uint8 SDL_FindColor(SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
extern Uint8 SDL_FindColor(SDL_Palette *pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||||
extern void SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel);
|
extern void SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel);
|
||||||
|
extern const float *SDL_GetColorPrimariesConversionMatrix(SDL_ColorPrimaries src, SDL_ColorPrimaries dst);
|
||||||
|
|
||||||
#endif /* SDL_pixels_c_h_ */
|
#endif /* SDL_pixels_c_h_ */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue