Make the color primary conversion code reusable

Also added conversion from rec709 to rec2020 primaries
This commit is contained in:
Sam Lantinga 2024-02-01 07:54:31 -08:00
parent 496ed01bdb
commit c1f3c81003
3 changed files with 85 additions and 63 deletions

View File

@ -664,19 +664,6 @@ static void WriteFloatPixel(Uint8 *pixels, SlowBlitPixelAccess access, SDL_Pixel
}
}
static void ConvertColorPrimaries(float *fR, float *fG, float *fB, const float *matrix)
{
float v[3];
v[0] = *fR;
v[1] = *fG;
v[2] = *fB;
*fR = matrix[0 * 3 + 0] * v[0] + matrix[0 * 3 + 1] * v[1] + matrix[0 * 3 + 2] * v[2];
*fG = matrix[1 * 3 + 0] * v[0] + matrix[1 * 3 + 1] * v[1] + matrix[1 * 3 + 2] * v[2];
*fB = matrix[2 * 3 + 0] * v[0] + matrix[2 * 3 + 1] * v[1] + matrix[2 * 3 + 2] * v[2];
}
static float CompressPQtoSDR(float v)
{
/* This gives generally good results for PQ HDR -> SDR conversion, scaling from 400 nits to 80 nits,
@ -729,7 +716,7 @@ void SDL_Blit_Slow_Float(SDL_BlitInfo *info)
if (src_transfer == SDL_TRANSFER_CHARACTERISTICS_PQ &&
dst_transfer != SDL_TRANSFER_CHARACTERISTICS_PQ &&
dst_colorspace != SDL_COLORSPACE_SCRGB) {
compress_PQ = SDL_TRUE;
//compress_PQ = SDL_TRUE;
}
src_access = GetPixelAccessMethod(src_fmt);
@ -752,7 +739,7 @@ void SDL_Blit_Slow_Float(SDL_BlitInfo *info)
ReadFloatPixel(src, src_access, src_fmt, src_colorspace, &srcR, &srcG, &srcB, &srcA);
if (color_primaries_matrix) {
ConvertColorPrimaries(&srcR, &srcG, &srcB, color_primaries_matrix);
SDL_ConvertColorPrimaries(&srcR, &srcG, &srcB, color_primaries_matrix);
}
if (compress_PQ) {

View File

@ -764,6 +764,86 @@ float SDL_PQfromNits(float v)
return pow(num / den, m2);
}
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 mat709to2020[] = {
0.627404f, 0.329283f, 0.043313f,
0.069097f, 0.919541f, 0.011362f,
0.016391f, 0.088013f, 0.895595f,
};
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 matXYZto2020[] = {
1.716651f, -0.355671f, -0.253366f,
-0.666684f, 1.616481f, 0.015769f,
0.017640f, -0.042771f, 0.942103f,
};
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;
case SDL_COLOR_PRIMARIES_BT2020:
switch (src) {
case SDL_COLOR_PRIMARIES_BT709:
return mat709to2020;
case SDL_COLOR_PRIMARIES_XYZ:
return matXYZto2020;
default:
break;
}
break;
default:
break;
}
return NULL;
}
void SDL_ConvertColorPrimaries(float *fR, float *fG, float *fB, const float *matrix)
{
float v[3];
v[0] = *fR;
v[1] = *fG;
v[2] = *fB;
*fR = matrix[0 * 3 + 0] * v[0] + matrix[0 * 3 + 1] * v[1] + matrix[0 * 3 + 2] * v[2];
*fG = matrix[1 * 3 + 0] * v[0] + matrix[1 * 3 + 1] * v[1] + matrix[1 * 3 + 2] * v[2];
*fB = matrix[2 * 3 + 0] * v[0] + matrix[2 * 3 + 1] * v[1] + matrix[2 * 3 + 2] * v[2];
}
SDL_Palette *SDL_CreatePalette(int ncolors)
{
SDL_Palette *palette;
@ -1246,50 +1326,3 @@ void SDL_FreeBlitMap(SDL_BlitMap *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;
}

View File

@ -40,6 +40,9 @@ extern float SDL_sRGBtoNits(float v);
extern float SDL_sRGBfromNits(float v);
extern float SDL_PQtoNits(float v);
extern float SDL_PQfromNits(float v);
extern const float *SDL_GetColorPrimariesConversionMatrix(SDL_ColorPrimaries src, SDL_ColorPrimaries dst);
extern void SDL_ConvertColorPrimaries(float *fR, float *fG, float *fB, const float *matrix);
/* Blit mapping functions */
@ -54,6 +57,5 @@ extern void SDL_InvalidateAllBlitMap(SDL_Surface *surface);
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 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_ */