SDL: Added support for the scRGB colorspace on D3D11 and D3D12

From 6f443e2acafd14d872c6f1c79e9c61dfe1156813 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 31 Jan 2024 17:25:25 -0800
Subject: [PATCH] Added support for the scRGB colorspace on D3D11 and D3D12

---
 include/SDL3/SDL_surface.h               | 163 +++++++++++++----------
 src/dynapi/SDL_dynapi.sym                |   4 +
 src/dynapi/SDL_dynapi_overrides.h        |   4 +
 src/dynapi/SDL_dynapi_procs.h            |   4 +
 src/render/SDL_render.c                  |  37 ++---
 src/render/direct3d/SDL_render_d3d.c     |  10 +-
 src/render/direct3d11/SDL_render_d3d11.c | 122 +++++++++++++----
 src/render/direct3d12/SDL_render_d3d12.c |  69 ++++++++--
 src/render/metal/SDL_render_metal.m      |   9 ++
 src/render/opengl/SDL_render_gl.c        |  13 +-
 src/render/opengles2/SDL_render_gles2.c  |  14 +-
 src/render/ps2/SDL_render_ps2.c          |   9 ++
 src/render/psp/SDL_render_psp.c          |   9 ++
 src/render/software/SDL_render_sw.c      |   1 +
 src/render/vitagxm/SDL_render_vita_gxm.c |   9 ++
 src/video/SDL_blit.c                     |  20 ++-
 src/video/SDL_blit.h                     |  34 +++--
 src/video/SDL_blit_slow.c                | 144 +++++++-------------
 src/video/SDL_pixels.c                   |  72 ++++++++++
 src/video/SDL_pixels_c.h                 |  10 ++
 src/video/SDL_surface.c                  | 128 +++++++++++++-----
 test/testcolorspace.c                    |  92 +++++++++----
 22 files changed, 654 insertions(+), 323 deletions(-)

diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h
index 084cf632cc54..4b8f1e4261ae 100644
--- a/include/SDL3/SDL_surface.h
+++ b/include/SDL3/SDL_surface.h
@@ -216,8 +216,7 @@ extern DECLSPEC void SDLCALL SDL_DestroySurface(SDL_Surface *surface);
  *
  * The following properties are understood by SDL:
  *
- * - `SDL_PROP_SURFACE_COLORSPACE_NUMBER`: an SDL_ColorSpace value describing
- *   the surface colorspace
+ * - `SDL_PROP_SURFACE_COLORSPACE_NUMBER`: an SDL_ColorSpace value describing the surface colorspace, defaults to SDL_COLORSPACE_SCRGB for floating point formats, SDL_COLORSPACE_HDR10 for 10-bit formats, SDL_COLORSPACE_SRGB for other RGB surfaces and SDL_COLORSPACE_BT709_FULL for YUV textures.
  * - `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
@@ -245,6 +244,34 @@ extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *s
 #define SDL_PROP_SURFACE_MAXCLL_NUMBER                      "SDL.surface.maxCLL"
 #define SDL_PROP_SURFACE_MAXFALL_NUMBER                     "SDL.surface.maxFALL"
 
+/**
+ * Set the colorspace used by a surface.
+ *
+ * Setting the colorspace doesn't change the pixels, only how they are interpreted in color operations.
+ *
+ * \param surface the SDL_Surface structure to update
+ * \param colorspace an SDL_ColorSpace value describing the surface colorspace
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC int SDLCALL SDL_SetSurfaceColorspace(SDL_Surface *surface, SDL_Colorspace colorspace);
+
+/**
+ * Get the colorspace used by a surface.
+ *
+ * The colorspace defaults to SDL_COLORSPACE_SCRGB for floating point formats, SDL_COLORSPACE_HDR10 for 10-bit formats, SDL_COLORSPACE_SRGB for other RGB surfaces and SDL_COLORSPACE_BT709_FULL for YUV textures.
+ *
+ * \param surface the SDL_Surface structure to query
+ * \param colorspace a pointer filled in with an SDL_ColorSpace value describing the surface colorspace
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC int SDLCALL SDL_GetSurfaceColorspace(SDL_Surface *surface, SDL_Colorspace *colorspace);
+
 /**
  * Set the palette used by a surface.
  *
@@ -257,8 +284,7 @@ extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSurfaceProperties(SDL_Surface *s
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC int SDLCALL SDL_SetSurfacePalette(SDL_Surface *surface,
-                                                  SDL_Palette *palette);
+extern DECLSPEC int SDLCALL SDL_SetSurfacePalette(SDL_Surface *surface, SDL_Palette *palette);
 
 /**
  * Set up a surface for directly accessing the pixels.
@@ -393,8 +419,7 @@ extern DECLSPEC int SDLCALL SDL_SaveBMP(SDL_Surface *surface, const char *file);
  * \sa SDL_LockSurface
  * \sa SDL_UnlockSurface
  */
-extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface *surface,
-                                              int flag);
+extern DECLSPEC int SDLCALL SDL_SetSurfaceRLE(SDL_Surface *surface, int flag);
 
 /**
  * Returns whether the surface is RLE enabled
@@ -434,8 +459,7 @@ extern DECLSPEC SDL_bool SDLCALL SDL_SurfaceHasRLE(SDL_Surface *surface);
  * \sa SDL_BlitSurface
  * \sa SDL_GetSurfaceColorKey
  */
-extern DECLSPEC int SDLCALL SDL_SetSurfaceColorKey(SDL_Surface *surface,
-                                            int flag, Uint32 key);
+extern DECLSPEC int SDLCALL SDL_SetSurfaceColorKey(SDL_Surface *surface, int flag, Uint32 key);
 
 /**
  * Returns whether the surface has a color key
@@ -470,8 +494,7 @@ extern DECLSPEC SDL_bool SDLCALL SDL_SurfaceHasColorKey(SDL_Surface *surface);
  * \sa SDL_BlitSurface
  * \sa SDL_SetSurfaceColorKey
  */
-extern DECLSPEC int SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface,
-                                            Uint32 *key);
+extern DECLSPEC int SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface, Uint32 *key);
 
 /**
  * Set an additional color value multiplied into blit operations.
@@ -494,8 +517,7 @@ extern DECLSPEC int SDLCALL SDL_GetSurfaceColorKey(SDL_Surface *surface,
  * \sa SDL_GetSurfaceColorMod
  * \sa SDL_SetSurfaceAlphaMod
  */
-extern DECLSPEC int SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface,
-                                                   Uint8 r, Uint8 g, Uint8 b);
+extern DECLSPEC int SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface, Uint8 r, Uint8 g, Uint8 b);
 
 
 /**
@@ -513,9 +535,7 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceColorMod(SDL_Surface *surface,
  * \sa SDL_GetSurfaceAlphaMod
  * \sa SDL_SetSurfaceColorMod
  */
-extern DECLSPEC int SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface,
-                                                   Uint8 *r, Uint8 *g,
-                                                   Uint8 *b);
+extern DECLSPEC int SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface, Uint8 *r, Uint8 *g, Uint8 *b);
 
 /**
  * Set an additional alpha value used in blit operations.
@@ -535,8 +555,7 @@ extern DECLSPEC int SDLCALL SDL_GetSurfaceColorMod(SDL_Surface *surface,
  * \sa SDL_GetSurfaceAlphaMod
  * \sa SDL_SetSurfaceColorMod
  */
-extern DECLSPEC int SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface *surface,
-                                                   Uint8 alpha);
+extern DECLSPEC int SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface *surface, Uint8 alpha);
 
 /**
  * Get the additional alpha value used in blit operations.
@@ -551,8 +570,7 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceAlphaMod(SDL_Surface *surface,
  * \sa SDL_GetSurfaceColorMod
  * \sa SDL_SetSurfaceAlphaMod
  */
-extern DECLSPEC int SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface,
-                                                   Uint8 *alpha);
+extern DECLSPEC int SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface, Uint8 *alpha);
 
 /**
  * Set the blend mode used for blit operations.
@@ -570,8 +588,7 @@ extern DECLSPEC int SDLCALL SDL_GetSurfaceAlphaMod(SDL_Surface *surface,
  *
  * \sa SDL_GetSurfaceBlendMode
  */
-extern DECLSPEC int SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface *surface,
-                                                    SDL_BlendMode blendMode);
+extern DECLSPEC int SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface *surface, SDL_BlendMode blendMode);
 
 /**
  * Get the blend mode used for blit operations.
@@ -585,8 +602,7 @@ extern DECLSPEC int SDLCALL SDL_SetSurfaceBlendMode(SDL_Surface *surface,
  *
  * \sa SDL_SetSurfaceBlendMode
  */
-extern DECLSPEC int SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface,
-                                                    SDL_BlendMode *blendMode);
+extern DECLSPEC int SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface, SDL_BlendMode *blendMode);
 
 /**
  * Set the clipping rectangle for a surface.
@@ -608,8 +624,7 @@ extern DECLSPEC int SDLCALL SDL_GetSurfaceBlendMode(SDL_Surface *surface,
  * \sa SDL_BlitSurface
  * \sa SDL_GetSurfaceClipRect
  */
-extern DECLSPEC SDL_bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface,
-                                                 const SDL_Rect *rect);
+extern DECLSPEC SDL_bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface, const SDL_Rect *rect);
 
 /**
  * Get the clipping rectangle for a surface.
@@ -629,8 +644,7 @@ extern DECLSPEC SDL_bool SDLCALL SDL_SetSurfaceClipRect(SDL_Surface *surface,
  * \sa SDL_BlitSurface
  * \sa SDL_SetSurfaceClipRect
  */
-extern DECLSPEC int SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface,
-                                             SDL_Rect *rect);
+extern DECLSPEC int SDLCALL SDL_GetSurfaceClipRect(SDL_Surface *surface, SDL_Rect *rect);
 
 /*
  * Flip a surface vertically or horizontally.
@@ -677,11 +691,10 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_DuplicateSurface(SDL_Surface *surface);
  * \sa SDL_ConvertSurfaceFormat
  * \sa SDL_CreateSurface
  */
-extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurface(SDL_Surface *surface,
-                                                        const SDL_PixelFormat *format);
+extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurface(SDL_Surface *surface, const SDL_PixelFormat *format);
 
 /**
- * Copy an existing surface to a new surface of the specified format enum.
+ * Copy an existing surface to a new surface of the specified format.
  *
  * This function operates just like SDL_ConvertSurface(), but accepts an
  * SDL_PixelFormatEnum value instead of an SDL_PixelFormat structure. As such,
@@ -689,8 +702,26 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurface(SDL_Surface *surface,
  * information for the destination surface, in case that would be important.
  *
  * \param surface the existing SDL_Surface structure to convert
- * \param pixel_format the SDL_PixelFormatEnum that the new surface is
- *                     optimized for
+ * \param pixel_format the new pixel format
+ * \returns the new SDL_Surface structure that is created or NULL if it fails;
+ *          call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_CreatePixelFormat
+ * \sa SDL_ConvertSurface
+ * \sa SDL_CreateSurface
+ */
+extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormat(SDL_Surface *surface, Uint32 pixel_format);
+
+/**
+ * Copy an existing surface to a new surface of the specified format and colorspace.
+ *
+ * This function converts an existing surface to a new format and colorspace and returns the new surface. This will perform any pixel format and colorspace conversion needed.
+ *
+ * \param surface the existing SDL_Surface structure to convert
+ * \param pixel_format the new pixel format
+ * \param colorspace the new colorspace
  * \returns the new SDL_Surface structure that is created or NULL if it fails;
  *          call SDL_GetError() for more information.
  *
@@ -700,8 +731,7 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurface(SDL_Surface *surface,
  * \sa SDL_ConvertSurface
  * \sa SDL_CreateSurface
  */
-extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormat(SDL_Surface *surface,
-                                                              Uint32 pixel_format);
+extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormatAndColorspace(SDL_Surface *surface, Uint32 pixel_format, SDL_Colorspace colorspace);
 
 /**
  * Copy a block of pixels of one format to another format.
@@ -719,11 +749,27 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_ConvertSurfaceFormat(SDL_Surface *surfa
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height,
-                                              Uint32 src_format,
-                                              const void *src, int src_pitch,
-                                              Uint32 dst_format,
-                                              void *dst, int dst_pitch);
+extern DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
+
+/**
+ * Copy a block of pixels of one format and colorspace to another format and colorspace.
+ *
+ * \param width the width of the block to copy, in pixels
+ * \param height the height of the block to copy, in pixels
+ * \param src_format an SDL_PixelFormatEnum value of the `src` pixels format
+ * \param src_colorspace an SDL_ColorSpace value describing the colorspace of the `src` pixels
+ * \param src a pointer to the source pixels
+ * \param src_pitch the pitch of the source pixels, in bytes
+ * \param dst_format an SDL_PixelFormatEnum value of the `dst` pixels format
+ * \param dst_colorspace an SDL_ColorSpace value describing the colorspace of the `dst` pixels
+ * \param dst a pointer to be filled in with new pixel data
+ * \param dst_pitch the pitch of the destination pixels, in bytes
+ * \returns 0 on success or a negative error code on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC int SDLCALL SDL_ConvertPixelsAndColorspace(int width, int height, Uint32 src_format, SDL_Colorspace src_colorspace, const void *src, int src_pitch, Uint32 dst_format, SDL_Colorspace dst_colorspace, void *dst, int dst_pitch);
 
 /**
  * Premultiply the alpha on a block of pixels.
@@ -745,11 +791,7 @@ extern DECLSPEC int SDLCALL SDL_ConvertPixels(int width, int height,
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern DECLSPEC int SDLCALL SDL_PremultiplyAlpha(int width, int height,
-                                                 Uint32 src_format,
-                                                 const void *src, int src_pitch,
-                                                 Uint32 dst_format,
-                                                 void *dst, int dst_pitch);
+extern DECLSPEC int SDLCALL SDL_PremultiplyAlpha(int width, int height, Uint32 src_format, const void *src, int src_pitch, Uint32 dst_format, void *dst, int dst_pitch);
 
 /**
  * Perform a fast fill of a rectangle with a specific color.
@@ -774,8 +816,7 @@ extern DECLSPEC int SDLCALL SDL_PremultiplyAlpha(int width, int height,
  *
  * \sa SDL_FillSurfaceRects
  */
-extern DECLSPEC int SDLCALL SDL_FillSurfaceRect
-    (SDL_Surface *dst, const SDL_Rect *rect, Uint32 color);
+extern DECLSPEC int SDLCALL SDL_FillSurfaceRect(SDL_Surface *dst, const SDL_Rect *rect, Uint32 color);
 
 /**
  * Perform a fast fill of a set of rectangles with a specific color.
@@ -800,8 +841,7 @@ extern DECLSPEC int SDLCALL SDL_FillSurfaceRect
  *
  * \sa SDL_FillSurfaceRect
  */
-extern DECLSPEC int SDLCALL SDL_FillSurfaceRects
-    (SDL_Surface *dst, const SDL_Rect *rects, int count, Uint32 color);
+extern DECLSPEC int SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SDL_Rect *rects, int count, Uint32 color);
 
 /**
  * Performs a fast blit from the source surface to the destination surface.
@@ -871,9 +911,7 @@ extern DECLSPEC int SDLCALL SDL_FillSurfaceRects
  *
  * \sa SDL_BlitSurfaceScaled
  */
-extern DECLSPEC int SDLCALL SDL_BlitSurface
-    (SDL_Surface *src, const SDL_Rect *srcrect,
-     SDL_Surface *dst, SDL_Rect *dstrect);
+extern DECLSPEC int SDLCALL SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect);
 
 /**
  * Perform low-level surface blitting only.
@@ -894,9 +932,7 @@ extern DECLSPEC int SDLCALL SDL_BlitSurface
  *
  * \sa SDL_BlitSurface
  */
-extern DECLSPEC int SDLCALL SDL_BlitSurfaceUnchecked
-    (SDL_Surface *src, const SDL_Rect *srcrect,
-     SDL_Surface *dst, const SDL_Rect *dstrect);
+extern DECLSPEC int SDLCALL SDL_BlitSurfaceUnchecked(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect);
 
 /**
  * Perform stretch blit between two surfaces of the same format.
@@ -918,11 +954,7 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceUnchecked
  *
  * \sa SDL_BlitSurfaceScaled
  */
-extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src,
-                                            const SDL_Rect *srcrect,
-                                            SDL_Surface *dst,
-                                            const SDL_Rect *dstrect,
-                                            SDL_ScaleMode scaleMode);
+extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode);
 
 /**
  * Perform a scaled surface copy to a destination surface.
@@ -942,11 +974,7 @@ extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src,
  *
  * \sa SDL_BlitSurface
  */
-extern DECLSPEC int SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src,
-                                                  const SDL_Rect *srcrect,
-                                                  SDL_Surface *dst,
-                                                  SDL_Rect *dstrect,
-                                                  SDL_ScaleMode scaleMode);
+extern DECLSPEC int SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect, SDL_ScaleMode scaleMode);
 
 /**
  * Perform low-level surface scaled blitting only.
@@ -968,11 +996,7 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceScaled(SDL_Surface *src,
  *
  * \sa SDL_BlitSurfaceScaled
  */
-extern DECLSPEC int SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src,
-                                                           const SDL_Rect *srcrect,
-                                                           SDL_Surface *dst,
-                                                           const SDL_Rect *dstrect,
-                                                           SDL_ScaleMode scaleMode);
+extern DECLSPEC int SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, const SDL_Rect *dstrect, SDL_ScaleMode scaleMode);
 
 /**
  * Retrieves a single pixel from a surface.
@@ -1001,7 +1025,6 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src,
  */
 extern DECLSPEC int SDLCALL SDL_ReadSurfacePixel(SDL_Surface *surface, int x, int y, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
 
-
 /**
  * Set the YUV conversion mode
  *
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 6e7fa2ee3e03..1dc5a5405ef2 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -965,6 +965,10 @@ SDL3_0.0.0 {
     SDL_GetTextureAlphaModFloat;
     SDL_SetRenderDrawColorFloat;
     SDL_GetRenderDrawColorFloat;
+    SDL_ConvertPixelsAndColorspace;
+    SDL_SetSurfaceColorspace;
+    SDL_GetSurfaceColorspace;
+    SDL_ConvertSurfaceFormatAndColorspace;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index cae15b798054..42a2e4846f92 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -990,3 +990,7 @@
 #define SDL_GetTextureAlphaModFloat SDL_GetTextureAlphaModFloat_REAL
 #define SDL_SetRenderDrawColorFloat SDL_SetRenderDrawColorFloat_REAL
 #define SDL_GetRenderDrawColorFloat SDL_GetRenderDrawColorFloat_REAL
+#define SDL_ConvertPixelsAndColorspace SDL_ConvertPixelsAndColorspace_REAL
+#define SDL_SetSurfaceColorspace SDL_SetSurfaceColorspace_REAL
+#define SDL_GetSurfaceColorspace SDL_GetSurfaceColorspace_REAL
+#define SDL_ConvertSurfaceFormatAndColorspace SDL_ConvertSurfaceFormatAndColorspace_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 05561268a112..b6221bb51d90 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -1015,3 +1015,7 @@ SDL_DYNAPI_PROC(int,SDL_SetTextureAlphaModFloat,(SDL_Texture *a, float b),(a,b),
 SDL_DYNAPI_PROC(int,SDL_GetTextureAlphaModFloat,(SDL_Texture *a, float *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_SetRenderDrawColorFloat,(SDL_Renderer *a, float b, float c, float d, float e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(int,SDL_GetRenderDrawColorFloat,(SDL_Renderer *a, float *b, float *c, float *d, float *e),(a,b,c,d,e),return)
+SDL_DYNAPI_PROC(int,SDL_ConvertPixelsAndColorspace,(int a, int b, Uint32 c, SDL_Colorspace d, const void *e, int f, Uint32 g, SDL_Colorspace h, void *i, int j),(a,b,c,d,e,f,g,h,i,j),return)
+SDL_DYNAPI_PROC(int,SDL_SetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace b),(a,b),return)
+SDL_DYNAPI_PROC(int,SDL_GetSurfaceColorspace,(SDL_Surface *a, SDL_Colorspace *b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_Surface*,SDL_ConvertSurfaceFormatAndColorspace,(SDL_Surface *a, Uint32 b, SDL_Colorspace c),(a,b,c),return)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 12e2d942868a..a94bf9c5b087 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -865,7 +865,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
     SDL_Renderer *renderer = NULL;
     const int n = SDL_GetNumRenderDrivers();
     const char *hint;
-    int i;
+    int i, attempted = 0;
 
     if (!window && surface) {
         return SDL_CreateSoftwareRenderer(surface);
@@ -904,6 +904,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
             const SDL_RenderDriver *driver = render_drivers[i];
             if (SDL_strcasecmp(name, driver->info.name) == 0) {
                 /* Create a new renderer instance */
+                ++attempted;
                 renderer = driver->CreateRenderer(window, props);
                 break;
             }
@@ -912,6 +913,7 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
         for (i = 0; i < n; i++) {
             const SDL_RenderDriver *driver = render_drivers[i];
             /* Create a new renderer instance */
+            ++attempted;
             renderer = driver->CreateRenderer(window, props);
             if (renderer) {
                 /* Yay, we got one! */
@@ -921,7 +923,9 @@ SDL_Renderer *SDL_CreateRendererWithProperties(SDL_PropertiesID props)
     }
 
     if (!renderer) {
-        SDL_SetError("Couldn't find matching render driver");
+        if (!name || !attempted) {
+            SDL_SetError("Couldn't find matching render driver");
+        }
         goto error;
     }
 
@@ -1175,19 +1179,6 @@ static SDL_ScaleMode SDL_GetScaleMode(void)
     }
 }
 
-static SDL_Colorspace SDL_GetDefaultTextureColorspace(Uint32 format)
-{
-    if (SDL_ISPIXELFORMAT_FOURCC(format)) {
-        return SDL_COLORSPACE_BT709_FULL;
-    } else if (SDL_ISPIXELFORMAT_FLOAT(format)) {
-        return SDL_COLORSPACE_SCRGB;
-    } else if (SDL_ISPIXELFORMAT_10BIT(format)) {
-        return SDL_COLORSPACE_HDR10;
-    } else {
-        return SDL_COLORSPACE_SRGB;
-    }
-}
-
 SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_PropertiesID props)
 {
     SDL_Texture *texture;
@@ -1195,7 +1186,7 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert
     int access = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, SDL_TEXTUREACCESS_STATIC);
     int w = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, 0);
     int h = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, 0);
-    Uint32 default_colorspace;
+    SDL_Colorspace default_colorspace;
     SDL_bool texture_is_fourcc_and_target;
 
     CHECK_RENDERER_MAGIC(renderer, NULL);
@@ -1223,14 +1214,14 @@ SDL_Texture *SDL_CreateTextureWithProperties(SDL_Renderer *renderer, SDL_Propert
         return NULL;
     }
 
-    default_colorspace = SDL_GetDefaultTextureColorspace(format);
+    default_colorspace = SDL_GetDefaultColorspaceForFormat(format);
 
     texture = (SDL_Texture *)SDL_calloc(1, sizeof(*texture));
     if (!texture) {
         return NULL;
     }
     texture->magic = &SDL_texture_magic;
-    texture->colorspace = (Uint32)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace);
+    texture->colorspace = (SDL_Colorspace)SDL_GetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, default_colorspace);
     texture->format = format;
     texture->access = access;
     texture->w = w;
@@ -1334,7 +1325,7 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s
     Uint32 format = SDL_PIXELFORMAT_UNKNOWN;
     SDL_Texture *texture;
     SDL_PropertiesID props;
-    SDL_Colorspace default_colorspace, colorspace;
+    SDL_Colorspace colorspace = SDL_COLORSPACE_UNKNOWN;
 
     CHECK_RENDERER_MAGIC(renderer, NULL);
 
@@ -1414,12 +1405,8 @@ SDL_Texture *SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *s
         direct_update = SDL_FALSE;
     }
 
-    if (direct_update) {
-        default_colorspace = SDL_GetDefaultTextureColorspace(format);
-        colorspace = (SDL_Colorspace)SDL_GetNumberProperty(SDL_GetSurfaceProperties(surface), SDL_PROP_SURFACE_COLORSPACE_NUMBER, default_colorspace);
-    } else {
-        /* We're updating through an intermediate surface, so we lose colorspace information */
-        colorspace = SDL_COLORSPACE_RGB_DEFAULT;
+    if (SDL_GetSurfaceColorspace(surface, &colorspace) < 0) {
+        return NULL;
     }
 
     props = SDL_CreateProperties();
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index 08ca0e676c65..4ba113a93b4f 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -1566,6 +1566,14 @@ SDL_Renderer *D3D_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_pro
     }
     renderer->magic = &SDL_renderer_magic;
 
+    SDL_SetupRendererColorspace(renderer, create_props);
+
+    if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
+        SDL_SetError("Unsupported output colorspace");
+        SDL_free(renderer);
+        return NULL;
+    }
+
     data = (D3D_RenderData *)SDL_calloc(1, sizeof(*data));
     if (!data) {
         SDL_free(renderer);
@@ -1573,9 +1581,9 @@ SDL_Renderer *D3D_CreateRenderer(SDL_Window *window, SDL_PropertiesID create_pro
     }
 
     if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
+        SDL_SetError("Unable to create Direct3D interface");
         SDL_free(renderer);
         SDL_free(data);
-        SDL_SetError("Unable to create Direct3D interface");
         return NULL;
     }
 
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index 8966bda40eb1..45e5fcb768c6 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -31,13 +31,14 @@
 #include "../SDL_d3dmath.h"
 
 #include <d3d11_1.h>
+#include <dxgi1_4.h>
 
 #include "SDL_shaders_d3d11.h"
 
 #ifdef SDL_PLATFORM_WINRT
 
 #if NTDDI_VERSION > NTDDI_WIN8
-#include <DXGI1_3.h>
+#include <dxgi1_3.h>
 #endif
 
 #include "SDL_render_winrt.h"
@@ -189,6 +190,7 @@ static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a
 static const GUID SDL_IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } };
 static const GUID SDL_IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } };
 /*static const GUID SDL_IID_ID3D11Debug = { 0x79cf2233, 0x7536, 0x4948, { 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60 } };*/
+static const GUID SDL_IID_IDXGISwapChain2 = { 0x94d99bdb, 0xf1f8, 0x4ab0, { 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1 } };
 
 #ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
 #pragma GCC diagnostic pop
@@ -203,6 +205,10 @@ Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
     case DXGI_FORMAT_B8G8R8X8_UNORM:
     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
         return SDL_PIXELFORMAT_XRGB8888;
+    case DXGI_FORMAT_R10G10B10A2_UNORM:
+        return SDL_PIXELFORMAT_XBGR2101010;
+    case DXGI_FORMAT_R16G16B16A16_FLOAT:
+        return SDL_PIXELFORMAT_RGBA64_FLOAT;
     default:
         return SDL_PIXELFORMAT_UNKNOWN;
     }
@@ -271,21 +277,12 @@ static void D3D11_ReleaseAll(SDL_Renderer *renderer)
     if (data) {
         int i;
 
-        SAFE_RELEASE(data->dxgiFactory);
-        SAFE_RELEASE(data->dxgiAdapter);
-        SAFE_RELEASE(data->d3dDevice);
-        SAFE_RELEASE(data->d3dContext);
-        SAFE_RELEASE(data->swapChain);
-        SAFE_RELEASE(data->mainRenderTargetView);
-        SAFE_RELEASE(data->currentOffscreenRenderTargetView);
-        SAFE_RELEASE(data->inputLayout);
-        for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
-            SAFE_RELEASE(data->vertexBuffers[i]);
-        }
-        SAFE_RELEASE(data->vertexShader);
-        for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) {
-            SAFE_RELEASE(data->pixelShaders[i]);
-        }
+        SAFE_RELEASE(data->vertexShaderConstants);
+        SAFE_RELEASE(data->clippedRasterizer);
+        SAFE_RELEASE(data->mainRasterizer);
+        SAFE_RELEASE(data->linearSampler);
+        SAFE_RELEASE(data->nearestPixelSampler);
+
         if (data->blendModesCount > 0) {
             for (i = 0; i < data->blendModesCount; ++i) {
                 SAFE_RELEASE(data->blendModes[i].blendState);
@@ -294,11 +291,26 @@ static void D3D11_ReleaseAll(SDL_Renderer *renderer)
 
             data->blendModesCount = 0;
         }
-        SAFE_RELEASE(data->nearestPixelSampler);
-        SAFE_RELEASE(data->linearSampler);
-        SAFE_RELEASE(data->mainRasterizer);
-        SAFE_RELEASE(data->clippedRasterizer);
-        SAFE_RELEASE(data->vertexShaderConstants);
+        for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) {
+            SAFE_RELEASE(data->pixelShaders[i]);
+        }
+        SAFE_RELEASE(data->vertexShader);
+        for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
+            SAFE_RELEASE(data->vertexBuffers[i]);
+        }
+        SAFE_RELEASE(data->inputLayout);
+        SAFE_RELEASE(data->currentOffscreenRenderTargetView);
+        SAFE_RELEASE(data->mainRenderTargetView);
+        SAFE_RELEASE(data->swapChain);
+
+        /* Make sure the swap chain is fully released */
+        ID3D11DeviceContext_ClearState(data->d3dContext);
+        ID3D11DeviceContext_Flush(data->d3dContext);
+
+        SAFE_RELEASE(data->d3dContext);
+        SAFE_RELEASE(data->d3dDevice);
+        SAFE_RELEASE(data->dxgiAdapter);
+        SAFE_RELEASE(data->dxgiFactory);
 
         data->swapEffect = (DXGI_SWAP_EFFECT)0;
         data->rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
@@ -779,7 +791,17 @@ static HRESULT D3D11_CreateSwapChain(SDL_Renderer *renderer, int w, int h)
     SDL_zero(swapChainDesc);
     swapChainDesc.Width = w;
     swapChainDesc.Height = h;
-    swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; /* This is the most common swap chain format. */
+    switch (renderer->output_colorspace) {
+    case SDL_COLORSPACE_SCRGB:
+        swapChainDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
+        break;

(Patch may be truncated, please check the link at the top of this post.)