SDL: Make the color primary conversion code reusable

From c1f3c810033e22d0ecbebff4050523164ceea59d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 1 Feb 2024 07:54:31 -0800
Subject: [PATCH] Make the color primary conversion code reusable

Also added conversion from rec709 to rec2020 primaries
---
 src/video/SDL_blit_slow.c |  17 +----
 src/video/SDL_pixels.c    | 127 ++++++++++++++++++++++++--------------
 src/video/SDL_pixels_c.h  |   4 +-
 3 files changed, 85 insertions(+), 63 deletions(-)

diff --git a/src/video/SDL_blit_slow.c b/src/video/SDL_blit_slow.c
index da4f9b9550a6..424e09c17a28 100644
--- a/src/video/SDL_blit_slow.c
+++ b/src/video/SDL_blit_slow.c
@@ -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) {
diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index d9082d3ddfb1..2b6ece7fa71d 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -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;
-}
-
diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h
index e7c66ff71d05..dd4cd09b6ed7 100644
--- a/src/video/SDL_pixels_c.h
+++ b/src/video/SDL_pixels_c.h
@@ -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_ */