SDL: Added the initial concept of colorspace to SDL

From 61b5c38e6e4be885bbd9a9086848b4f53103edf4 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sun, 28 Jan 2024 17:17:38 -0800
Subject: [PATCH] Added the initial concept of colorspace to SDL

---
 include/SDL3/SDL_pixels.h  | 194 +++++++++++++++++++++++++++++++++++++
 include/SDL3/SDL_surface.h |  54 +----------
 src/video/SDL_blit.c       |  21 ++--
 src/video/SDL_blit_slow.c  |  10 +-
 4 files changed, 216 insertions(+), 63 deletions(-)

diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h
index 04ebfee226b7..2f1cd70e97c6 100644
--- a/include/SDL3/SDL_pixels.h
+++ b/include/SDL3/SDL_pixels.h
@@ -394,6 +394,200 @@ typedef enum
         SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ')
 } SDL_PixelFormatEnum;
 
+/**
+ * Pixels are a representation of a color in a particular color space.
+ *
+ * The first characteristic of a color space is the color type. SDL understands two different color types, RGB and YCbCr, or in SDL also referred to as YUV.
+ *
+ * RGB colors consist of red, green, and blue channels of color that are added together to represent the colors we see on the screen.
+ * https://en.wikipedia.org/wiki/RGB_color_model
+ *
+ * YCbCr colors represent colors as a Y luma brightness component and red and blue chroma color offsets. This color representation takes advantage of the fact that the human eye is more sensitive to brightness than the color in an image. The Cb and Cr components are often compressed and have lower resolution than the luma component.
+ * https://en.wikipedia.org/wiki/YCbCr
+ *
+ * When the color information in YCbCr is compressed, the Y pixels are left at full resolution and each Cr and Cb pixel represents an average of the color information in a block of Y pixels. The chroma location determines where in that block of pixels the color information is coming from.
+ *
+ * The color range defines how much of the pixel to use when converting a pixel into a color on the display. When the full color range is used, the entire numeric range of the pixel bits is significant. When narrow color range is used, for historical reasons, the pixel uses only a portion of the numeric range to represent colors.
+ *
+ * The color primaries and white point are a definition of the colors in the color space relative to the standard XYZ color space.
+ * https://en.wikipedia.org/wiki/CIE_1931_color_space
+ *
+ * The transfer characteristic, or opto-electrical transfer function (OETF), is the way a color is converted from mathematically linear space into a non-linear output signals.
+ * https://en.wikipedia.org/wiki/Rec._709#Transfer_characteristics
+ *
+ * The matrix coefficients are used to convert between YCbCr and RGB colors.
+ */
+
+/**
+ * The color type
+ */
+typedef enum
+{
+    SDL_COLOR_TYPE_UNKNOWN = 0,
+    SDL_COLOR_TYPE_RGB = 1,
+    SDL_COLOR_TYPE_YCBCR = 2
+} SDL_ColorType;
+
+/**
+ * The color range, as described by https://www.itu.int/rec/R-REC-BT.2100-2-201807-I/en
+ */
+typedef enum
+{
+    SDL_COLOR_RANGE_UNKNOWN = 0,
+    SDL_COLOR_RANGE_LIMITED = 1, /**< Narrow range, e.g. 16-235 for 8-bit RGB and luma, and 16-240 for 8-bit chroma */
+    SDL_COLOR_RANGE_FULL = 2    /**< Full range, e.g. 0-255 for 8-bit RGB and luma, and 1-255 for 8-bit chroma */
+} SDL_ColorRange;
+
+/**
+ * The color primaries, as described by https://www.itu.int/rec/T-REC-H.273-201612-S/en
+ */
+typedef enum
+{
+    SDL_COLOR_PRIMARIES_UNKNOWN = 0,
+    SDL_COLOR_PRIMARIES_BT709 = 1,
+    SDL_COLOR_PRIMARIES_UNSPECIFIED = 2,
+    SDL_COLOR_PRIMARIES_BT470M = 4,
+    SDL_COLOR_PRIMARIES_BT470BG = 5,
+    SDL_COLOR_PRIMARIES_BT601 = 6,
+    SDL_COLOR_PRIMARIES_SMPTE240 = 7,
+    SDL_COLOR_PRIMARIES_GENERIC_FILM = 8,
+    SDL_COLOR_PRIMARIES_BT2020 = 9,
+    SDL_COLOR_PRIMARIES_XYZ = 10,
+    SDL_COLOR_PRIMARIES_SMPTE431 = 11,
+    SDL_COLOR_PRIMARIES_SMPTE432 = 12, /* DCI P3 */
+    SDL_COLOR_PRIMARIES_EBU3213 = 22,
+    SDL_COLOR_PRIMARIES_CUSTOM = 31
+} SDL_ColorPrimaries;
+
+/**
+ * The transfer characteristics, as described by https://www.itu.int/rec/T-REC-H.273-201612-S/en
+ */
+typedef enum
+{
+    SDL_TRANSFER_CHARACTERISTICS_UNKNOWN = 0,
+    SDL_TRANSFER_CHARACTERISTICS_BT709 = 1,         /**< ITU-R BT1361 */
+    SDL_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2,
+    SDL_TRANSFER_CHARACTERISTICS_GAMMA22 = 4,       /**< ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM */
+    SDL_TRANSFER_CHARACTERISTICS_GAMMA28 = 5,       /**< ITU-R BT470BG */
+    SDL_TRANSFER_CHARACTERISTICS_BT601 = 6,         /**< SMPTE ST 170M */
+    SDL_TRANSFER_CHARACTERISTICS_SMPTE240 = 7,      /**< SMPTE ST 240M */
+    SDL_TRANSFER_CHARACTERISTICS_LINEAR = 8,
+    SDL_TRANSFER_CHARACTERISTICS_LOG100 = 9,
+    SDL_TRANSFER_CHARACTERISTICS_LOG100_SQRT10 = 10,
+    SDL_TRANSFER_CHARACTERISTICS_IEC61966 = 11,     /**< IEC 61966-2-4 */
+    SDL_TRANSFER_CHARACTERISTICS_BT1361 = 12,       /**< ITU-R BT1361 Extended Colour Gamut */
+    SDL_TRANSFER_CHARACTERISTICS_SRGB = 13,         /**< IEC 61966-2-1 (sRGB or sYCC) */
+    SDL_TRANSFER_CHARACTERISTICS_BT2020_10BIT = 14, /**< ITU-R BT2020 for 10-bit system */
+    SDL_TRANSFER_CHARACTERISTICS_BT2020_12BIT = 15, /**< ITU-R BT2020 for 12-bit system */
+    SDL_TRANSFER_CHARACTERISTICS_PQ = 16,           /**< SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems */
+    SDL_TRANSFER_CHARACTERISTICS_SMPTE428 = 17,     /**< SMPTE ST 428-1 */
+    SDL_TRANSFER_CHARACTERISTICS_HLG = 18,          /**< ARIB STD-B67, known as "Hybrid log-gamma" */
+    SDL_TRANSFER_COEFFICIENTS_CUSTOM = 31
+} SDL_TransferCharacteristics;
+
+/**
+ * The matrix coefficients, as described by https://www.itu.int/rec/T-REC-H.273-201612-S/en
+ */
+typedef enum
+{
+    SDL_MATRIX_COEFFICIENTS_IDENTITY = 0,
+    SDL_MATRIX_COEFFICIENTS_BT709 = 1,
+    SDL_MATRIX_COEFFICIENTS_UNSPECIFIED = 2,
+    SDL_MATRIX_COEFFICIENTS_FCC = 4,
+    SDL_MATRIX_COEFFICIENTS_BT470BG = 5,
+    SDL_MATRIX_COEFFICIENTS_BT601 = 6,
+    SDL_MATRIX_COEFFICIENTS_SMPTE240 = 7,
+    SDL_MATRIX_COEFFICIENTS_YCGCO = 8,
+    SDL_MATRIX_COEFFICIENTS_BT2020_NCL = 9,
+    SDL_MATRIX_COEFFICIENTS_BT2020_CL = 10,
+    SDL_MATRIX_COEFFICIENTS_SMPTE2085 = 11,
+    SDL_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL = 12,
+    SDL_MATRIX_COEFFICIENTS_CHROMA_DERIVED_CL = 13,
+    SDL_MATRIX_COEFFICIENTS_ICTCP = 14,
+    SDL_MATRIX_COEFFICIENTS_CUSTOM = 31
+} SDL_MatrixCoefficients;
+
+/**
+ * The chroma sample location
+ */
+typedef enum
+{
+    SDL_CHROMA_LOCATION_NONE = 0,   /**< RGB, no chroma sampling */
+    SDL_CHROMA_LOCATION_LEFT = 1,   /**< In MPEG-2, MPEG-4, and AVC, Cb and Cr are taken on midpoint of the left-edge of the 2×2 square. In other words, they have the same horizontal location as the top-left pixel, but is shifted one-half pixel down vertically. */
+    SDL_CHROMA_LOCATION_CENTER = 2, /**< In JPEG/JFIF, H.261, and MPEG-1, Cb and Cr are taken at the center of 2×2 the square. In other words, they are offset one-half pixel to the right and one-half pixel down compared to the top-left pixel. */
+    SDL_CHROMA_LOCATION_TOPLEFT = 3 /**< In HEVC for BT.2020 and BT.2100 content (in particular on Blu-rays), Cb and Cr are sampled at the same location as the group's top-left Y pixel ("co-sited", "co-located"). */
+} SDL_ChromaLocation;
+
+
+/* Colorspace definition */
+#define SDL_DEFINE_COLORSPACE(type, range, primaries, transfer, matrix, chroma) \
+    (((Uint32)(type) << 28) | ((Uint32)(range) << 24) | ((Uint32)(chroma) << 20) | \
+    ((Uint32)(primaries) << 10) | ((Uint32)(transfer) << 5) | ((Uint32)(matrix) << 0))
+
+#define SDL_COLORSPACETYPE(X)       (SDL_ColorType)(((X) >> 28) & 0x0F)
+#define SDL_COLORSPACERANGE(X)      (SDL_ColorRange)(((X) >> 24) & 0x0F)
+#define SDL_COLORSPACECHROMA(X)     (SDL_ChromaLocation)(((X) >> 20) & 0x0F)
+#define SDL_COLORSPACEPRIMARIES(X)  (SDL_ColorPrimaries)(((X) >> 10) & 0x1F)
+#define SDL_COLORSPACETRANSFER(X)   (SDL_TransferCharacteristics)(((X) >> 5) & 0x1F)
+#define SDL_COLORSPACEMATRIX(X)     (SDL_MatrixCoefficients)((X) & 0x1F)
+
+typedef enum
+{
+    SDL_COLORSPACE_UNKNOWN,
+    SDL_COLORSPACE_SRGB =   /**< Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_RGB,
+                              SDL_COLOR_RANGE_FULL,
+                              SDL_COLOR_PRIMARIES_BT709,
+                              SDL_TRANSFER_CHARACTERISTICS_SRGB,
+                              SDL_MATRIX_COEFFICIENTS_UNSPECIFIED,
+                              SDL_CHROMA_LOCATION_NONE),
+    SDL_COLORSPACE_SCRGB =   /**< Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709  */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_RGB,
+                              SDL_COLOR_RANGE_FULL,
+                              SDL_COLOR_PRIMARIES_BT709,
+                              SDL_TRANSFER_CHARACTERISTICS_LINEAR,
+                              SDL_MATRIX_COEFFICIENTS_UNSPECIFIED,
+                              SDL_CHROMA_LOCATION_NONE),
+    SDL_COLORSPACE_HDR10 =   /**< Equivalent to DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020  */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_RGB,
+                              SDL_COLOR_RANGE_FULL,
+                              SDL_COLOR_PRIMARIES_BT2020,
+                              SDL_TRANSFER_CHARACTERISTICS_PQ,
+                              SDL_MATRIX_COEFFICIENTS_UNSPECIFIED,
+                              SDL_CHROMA_LOCATION_NONE),
+    SDL_COLORSPACE_BT601_LIMITED =  /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR,
+                              SDL_COLOR_RANGE_LIMITED,
+                              SDL_COLOR_PRIMARIES_BT601,
+                              SDL_TRANSFER_CHARACTERISTICS_BT601,
+                              SDL_MATRIX_COEFFICIENTS_BT601,
+                              SDL_CHROMA_LOCATION_LEFT),
+    SDL_COLORSPACE_BT601_FULL =     /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR,
+                              SDL_COLOR_RANGE_LIMITED,
+                              SDL_COLOR_PRIMARIES_BT601,
+                              SDL_TRANSFER_CHARACTERISTICS_BT601,
+                              SDL_MATRIX_COEFFICIENTS_BT601,
+                              SDL_CHROMA_LOCATION_LEFT),
+    SDL_COLORSPACE_BT709_LIMITED =  /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR,
+                              SDL_COLOR_RANGE_LIMITED,
+                              SDL_COLOR_PRIMARIES_BT709,
+                              SDL_TRANSFER_CHARACTERISTICS_BT709,
+                              SDL_MATRIX_COEFFICIENTS_BT709,
+                              SDL_CHROMA_LOCATION_LEFT),
+    SDL_COLORSPACE_BT709_FULL =     /**< Equivalent to DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 */
+        SDL_DEFINE_COLORSPACE(SDL_COLOR_TYPE_YCBCR,
+                              SDL_COLOR_RANGE_LIMITED,
+                              SDL_COLOR_PRIMARIES_BT709,
+                              SDL_TRANSFER_CHARACTERISTICS_BT709,
+                              SDL_MATRIX_COEFFICIENTS_BT709,
+                              SDL_CHROMA_LOCATION_LEFT),
+
+    /* The default colorspace for RGB surfaces if no colorspace is specified */
+    SDL_COLORSPACE_RGB_DEFAULT = SDL_COLORSPACE_SRGB,
+} SDL_Colorspace;
+
 /**
  * The bits of this structure can be directly reinterpreted as an integer-packed
  * color which uses the SDL_PIXELFORMAT_RGBA32 format (SDL_PIXELFORMAT_ABGR8888
diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h
index aeaca8d79619..ea4cbc73f403 100644
--- a/include/SDL3/SDL_surface.h
+++ b/include/SDL3/SDL_surface.h
@@ -138,52 +138,6 @@ typedef int (SDLCALL *SDL_blit) (struct SDL_Surface *src, const SDL_Rect *srcrec
                                  struct SDL_Surface *dst, const SDL_Rect *dstrect);
 
 
-/**
- * The color primaries, as described by https://www.itu.int/rec/T-REC-H.273-201612-S/en
- */
-typedef enum
-{
-    SDL_COLOR_PRIMARIES_UNKNOWN = 0,
-    SDL_COLOR_PRIMARIES_BT709 = 1,
-    SDL_COLOR_PRIMARIES_IEC61966_2_4 = 1,
-    SDL_COLOR_PRIMARIES_UNSPECIFIED = 2,
-    SDL_COLOR_PRIMARIES_BT470M = 4,
-    SDL_COLOR_PRIMARIES_BT470BG = 5,
-    SDL_COLOR_PRIMARIES_BT601 = 6,
-    SDL_COLOR_PRIMARIES_SMPTE240 = 7,
-    SDL_COLOR_PRIMARIES_GENERIC_FILM = 8,
-    SDL_COLOR_PRIMARIES_BT2020 = 9,
-    SDL_COLOR_PRIMARIES_XYZ = 10,
-    SDL_COLOR_PRIMARIES_SMPTE431 = 11,
-    SDL_COLOR_PRIMARIES_SMPTE432 = 12, /* DCI P3 */
-    SDL_COLOR_PRIMARIES_EBU3213 = 22
-} SDL_ColorPrimaries;
-
-/**
- * The transfer characteristics, as described by https://www.itu.int/rec/T-REC-H.273-201612-S/en
- */
-typedef enum
-{
-    SDL_TRANSFER_CHARACTERISTICS_UNKNOWN = 0,
-    SDL_TRANSFER_CHARACTERISTICS_BT709 = 1,
-    SDL_TRANSFER_CHARACTERISTICS_UNSPECIFIED = 2,
-    SDL_TRANSFER_CHARACTERISTICS_BT470M = 4,  /* 2.2 gamma */
-    SDL_TRANSFER_CHARACTERISTICS_BT470BG = 5, /* 2.8 gamma */
-    SDL_TRANSFER_CHARACTERISTICS_BT601 = 6,
-    SDL_TRANSFER_CHARACTERISTICS_SMPTE240 = 7,
-    SDL_TRANSFER_CHARACTERISTICS_LINEAR = 8,
-    SDL_TRANSFER_CHARACTERISTICS_LOG100 = 9,
-    SDL_TRANSFER_CHARACTERISTICS_LOG100_SQRT10 = 10,
-    SDL_TRANSFER_CHARACTERISTICS_IEC61966 = 11,
-    SDL_TRANSFER_CHARACTERISTICS_BT1361 = 12,
-    SDL_TRANSFER_CHARACTERISTICS_SRGB = 13,
-    SDL_TRANSFER_CHARACTERISTICS_BT2020_10BIT = 14,
-    SDL_TRANSFER_CHARACTERISTICS_BT2020_12BIT = 15,
-    SDL_TRANSFER_CHARACTERISTICS_SMPTE2084 = 16, /* PQ */
-    SDL_TRANSFER_CHARACTERISTICS_SMPTE428 = 17,
-    SDL_TRANSFER_CHARACTERISTICS_HLG = 18
-} SDL_TransferCharacteristics;
-
 /**
  * The formula used for converting between YUV and RGB
  */
@@ -262,10 +216,7 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
  *
  * The following properties are understood by SDL:
  *
- * - `SDL_PROP_SURFACE_COLOR_PRIMARIES_NUMBER`: an SDL_ColorPrimaries value
- *   describing the surface colorspace
- * - `SDL_PROP_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER`: an
- *   SDL_TransferCharacteristics value describing the surface colorspace
+ * - `SDL_PROP_SURFACE_COLORSPACE_NUMBER`: an SDL_ColorSpace value describing the surface colorspace
  * - `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 entire playback sequence. MaxCLL is usually measured off the final
@@ -289,8 +240,7 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
  */
 extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *surface);
 
-#define SDL_PROP_SURFACE_COLOR_PRIMARIES_NUMBER             "SDL.surface.color_primaries"
-#define SDL_PROP_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER    "SDL.surface.transfer_characteristics"
+#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"
 
diff --git a/src/video/SDL_blit.c b/src/video/SDL_blit.c
index db998d34dfbc..78820bf2dda6 100644
--- a/src/video/SDL_blit.c
+++ b/src/video/SDL_blit.c
@@ -187,7 +187,10 @@ static SDL_bool IsSurfaceHDR(SDL_Surface *surface)
 {
     if (surface->flags & SDL_SURFACE_USES_PROPERTIES) {
         SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
-        if (SDL_GetNumberProperty(props, SDL_PROP_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER, SDL_TRANSFER_CHARACTERISTICS_UNKNOWN) == SDL_TRANSFER_CHARACTERISTICS_SMPTE2084) {
+        SDL_Colorspace colorspace = SDL_GetNumberProperty(props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_RGB_DEFAULT);
+        SDL_TransferCharacteristics transfer = SDL_COLORSPACETRANSFER(colorspace);
+        if (transfer == SDL_TRANSFER_CHARACTERISTICS_PQ
+            /*|| (colorspace == SDL_COLORSPACE_SCRGB && SDL_BITSPERPIXEL(surface->format->format) > 32*/) {
             return SDL_TRUE;
         }
     }
@@ -239,10 +242,8 @@ int SDL_CalculateBlit(SDL_Surface *surface)
             /* See if they're in the same colorspace and light level */
             SDL_PropertiesID src_props = SDL_GetSurfaceProperties(surface);
             SDL_PropertiesID dst_props = SDL_GetSurfaceProperties(dst);
-            if ((SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_UNKNOWN) !=
-                 SDL_GetNumberProperty(dst_props, SDL_PROP_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_UNKNOWN)) ||
-                (SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER, SDL_TRANSFER_CHARACTERISTICS_UNKNOWN) !=
-                 SDL_GetNumberProperty(dst_props, SDL_PROP_SURFACE_TRANSFER_CHARACTERISTICS_NUMBER, SDL_TRANSFER_CHARACTERISTICS_UNKNOWN)) ||
+            if ((SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_RGB_DEFAULT) !=
+                 SDL_GetNumberProperty(dst_props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_RGB_DEFAULT)) ||
                 (SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_MAXCLL_NUMBER, 0) !=
                  SDL_GetNumberProperty(dst_props, SDL_PROP_SURFACE_MAXCLL_NUMBER, 0)) ||
                 (SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_MAXFALL_NUMBER, 0) !=
@@ -258,9 +259,13 @@ int SDL_CalculateBlit(SDL_Surface *surface)
             return SDL_SetError("Tone mapping from an SDR to an HDR surface not supported");
         } else {
             /* Tone mapping from an HDR surface to SDR surface */
-            SDL_PropertiesID props = SDL_GetSurfaceProperties(surface);
-            SDL_ColorPrimaries primaries = (SDL_ColorPrimaries)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_BT2020);
-            if (SDL_GetColorPrimariesConversionMatrix(primaries, SDL_COLOR_PRIMARIES_BT709) != NULL) {
+            SDL_PropertiesID src_props = SDL_GetSurfaceProperties(surface);
+            SDL_Colorspace src_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB);
+            SDL_ColorPrimaries src_primaries = SDL_COLORSPACEPRIMARIES(src_colorspace);
+            SDL_PropertiesID dst_props = SDL_GetSurfaceProperties(dst);
+            SDL_Colorspace dst_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(dst_props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB);
+            SDL_ColorPrimaries dst_primaries = SDL_COLORSPACEPRIMARIES(dst_colorspace);
+            if (SDL_GetColorPrimariesConversionMatrix(src_primaries, dst_primaries) != NULL) {
                 if (SDL_ISPIXELFORMAT_10BIT(surface->format->format)) {
                     blit = SDL_Blit_Slow_PQtoSDR;
                 } else {
diff --git a/src/video/SDL_blit_slow.c b/src/video/SDL_blit_slow.c
index 759dc9b6dfd9..0928c3c4135a 100644
--- a/src/video/SDL_blit_slow.c
+++ b/src/video/SDL_blit_slow.c
@@ -310,9 +310,13 @@ void SDL_Blit_Slow_PQtoSDR(SDL_BlitInfo *info)
     int dstfmt_val;
     Uint32 rgbmask = ~src_fmt->Amask;
     Uint32 ckey = info->colorkey & rgbmask;
-    SDL_PropertiesID props = SDL_GetSurfaceProperties(info->src_surface);
-    SDL_ColorPrimaries src_primaries = (SDL_ColorPrimaries)SDL_GetNumberProperty(props, SDL_PROP_SURFACE_COLOR_PRIMARIES_NUMBER, SDL_COLOR_PRIMARIES_BT2020);
-    const float *color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, SDL_COLOR_PRIMARIES_BT709);
+    SDL_PropertiesID src_props = SDL_GetSurfaceProperties(info->src_surface);
+    SDL_Colorspace src_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(src_props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB);
+    SDL_ColorPrimaries src_primaries = SDL_COLORSPACEPRIMARIES(src_colorspace);
+    SDL_PropertiesID dst_props = SDL_GetSurfaceProperties(info->dst_surface);
+    SDL_Colorspace dst_colorspace = (SDL_Colorspace)SDL_GetNumberProperty(dst_props, SDL_PROP_SURFACE_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB);
+    SDL_ColorPrimaries dst_primaries = SDL_COLORSPACEPRIMARIES(dst_colorspace);
+    const float *color_primaries_matrix = SDL_GetColorPrimariesConversionMatrix(src_primaries, dst_primaries);
 
     dstfmt_val = detect_format(dst_fmt);