From 50a805cdd1bffc43c0eaebbcd8eef818b943f9e9 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 3 Feb 2024 07:05:32 -0800
Subject: [PATCH] Use YUV colorspaces instead of a global YUV conversion mode
Fixes https://github.com/libsdl-org/SDL/issues/8669
---
docs/README-migration.md | 3 +
include/SDL3/SDL_pixels.h | 9 +++
include/SDL3/SDL_render.h | 2 +-
include/SDL3/SDL_surface.h | 41 ----------
src/dynapi/SDL_dynapi.sym | 3 -
src/dynapi/SDL_dynapi_overrides.h | 3 -
src/dynapi/SDL_dynapi_procs.h | 3 -
src/render/direct3d/SDL_render_d3d.c | 24 +++---
src/render/direct3d11/SDL_render_d3d11.c | 48 ++++++------
src/render/direct3d12/SDL_render_d3d12.c | 48 ++++++------
src/render/metal/SDL_render_metal.m | 36 ++++-----
src/render/opengl/SDL_render_gl.c | 63 +++++++--------
src/render/opengles2/SDL_render_gles2.c | 93 ++++++++++++----------
src/render/vitagxm/SDL_render_vita_gxm.c | 25 +++---
src/video/SDL_pixels.c | 2 +-
src/video/SDL_surface.c | 21 ++---
src/video/SDL_yuv.c | 98 ++++++++++--------------
src/video/SDL_yuv_c.h | 6 +-
test/testffmpeg.c | 56 +++++++++-----
test/testyuv.c | 53 ++++++++-----
test/testyuv_cvt.c | 39 ++++++++--
test/testyuv_cvt.h | 12 ++-
22 files changed, 361 insertions(+), 327 deletions(-)
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 5f135c38d2d0..4d3768bfa678 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -1382,6 +1382,9 @@ The following functions have been renamed:
* SDL_UpperBlitScaled() => SDL_BlitSurfaceScaled()
The following functions have been removed:
+* SDL_GetYUVConversionMode()
+* SDL_GetYUVConversionModeForResolution()
+* SDL_SetYUVConversionMode() - use SDL_SetSurfaceColorspace() to set the surface colorspace and SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER with SDL_CreateTextureWithProperties() to set the texture colorspace. The default colorspace for YUV pixel formats is SDL_COLORSPACE_BT601_LIMITED.
* SDL_SoftStretchLinear() - use SDL_SoftStretch() with SDL_SCALEMODE_LINEAR
## SDL_system.h
diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h
index f53cd7f644e7..112c6534f503 100644
--- a/include/SDL3/SDL_pixels.h
+++ b/include/SDL3/SDL_pixels.h
@@ -555,6 +555,11 @@ typedef enum
#define SDL_COLORSPACETRANSFER(X) (SDL_TransferCharacteristics)(((X) >> 5) & 0x1F)
#define SDL_COLORSPACEMATRIX(X) (SDL_MatrixCoefficients)((X) & 0x1F)
+#define SDL_ISCOLORSPACE_YUV_BT601(X) (SDL_COLORSPACEMATRIX(X) == SDL_MATRIX_COEFFICIENTS_BT601 || SDL_COLORSPACEMATRIX(X) == SDL_MATRIX_COEFFICIENTS_BT470BG)
+#define SDL_ISCOLORSPACE_YUV_BT709(X) (SDL_COLORSPACEMATRIX(X) == SDL_MATRIX_COEFFICIENTS_BT709)
+#define SDL_ISCOLORSPACE_LIMITED_RANGE(X) (SDL_COLORSPACERANGE(X) == SDL_COLOR_RANGE_LIMITED)
+#define SDL_ISCOLORSPACE_FULL_RANGE(X) (SDL_COLORSPACERANGE(X) == SDL_COLOR_RANGE_LIMITED)
+
typedef enum
{
SDL_COLORSPACE_UNKNOWN,
@@ -620,6 +625,10 @@ typedef enum
/* The default colorspace for RGB surfaces if no colorspace is specified */
SDL_COLORSPACE_RGB_DEFAULT = SDL_COLORSPACE_SRGB,
+
+ /* The default colorspace for YUV surfaces if no colorspace is specified */
+ SDL_COLORSPACE_YUV_DEFAULT = SDL_COLORSPACE_BT601_LIMITED,
+
} SDL_Colorspace;
/**
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index b1aba7adcefb..1764e02a623a 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -458,7 +458,7 @@ extern DECLSPEC SDL_Texture *SDLCALL SDL_CreateTextureFromSurface(SDL_Renderer *
* - `SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER`: an SDL_ColorSpace value
* describing the texture colorspace, defaults to SDL_COLORSPACE_SCRGB for
* floating point textures, SDL_COLORSPACE_HDR10 for 10-bit textures,
- * SDL_COLORSPACE_SRGB for other RGB textures and SDL_COLORSPACE_BT709_FULL
+ * SDL_COLORSPACE_SRGB for other RGB textures and SDL_COLORSPACE_BT601_LIMITED
* for YUV textures.
* - `SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER`: one of the enumerated values in
* SDL_PixelFormatEnum, defaults to the best RGBA format for the renderer
diff --git a/include/SDL3/SDL_surface.h b/include/SDL3/SDL_surface.h
index f4c647395d60..8e064109a9b1 100644
--- a/include/SDL3/SDL_surface.h
+++ b/include/SDL3/SDL_surface.h
@@ -138,17 +138,6 @@ typedef int (SDLCALL *SDL_blit) (struct SDL_Surface *src, const SDL_Rect *srcrec
struct SDL_Surface *dst, const SDL_Rect *dstrect);
-/**
- * The formula used for converting between YUV and RGB
- */
-typedef enum
-{
- SDL_YUV_CONVERSION_JPEG, /**< Full range JPEG */
- SDL_YUV_CONVERSION_BT601, /**< BT.601 (the default) */
- SDL_YUV_CONVERSION_BT709, /**< BT.709 */
- SDL_YUV_CONVERSION_AUTOMATIC /**< BT.601 for SD content, BT.709 for HD content */
-} SDL_YUV_CONVERSION_MODE;
-
/**
* Allocate a new RGB surface with a specific pixel format.
*
@@ -1031,36 +1020,6 @@ extern DECLSPEC int SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src, con
*/
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
- *
- * \param mode YUV conversion mode
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern DECLSPEC void SDLCALL SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode);
-
-/**
- * Get the YUV conversion mode
- *
- * \returns YUV conversion mode
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionMode(void);
-
-/**
- * Get the YUV conversion mode, returning the correct mode for the resolution
- * when the current conversion mode is SDL_YUV_CONVERSION_AUTOMATIC
- *
- * \param width width
- * \param height height
- * \returns YUV conversion mode
- *
- * \since This function is available since SDL 3.0.0.
- */
-extern DECLSPEC SDL_YUV_CONVERSION_MODE SDLCALL SDL_GetYUVConversionModeForResolution(int width, int height);
-
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 631fe95d66e6..07f36e853532 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -347,8 +347,6 @@ SDL3_0.0.0 {
SDL_GetWindowSizeInPixels;
SDL_GetWindowSurface;
SDL_GetWindowTitle;
- SDL_GetYUVConversionMode;
- SDL_GetYUVConversionModeForResolution;
SDL_CloseHaptic;
SDL_DestroyHapticEffect;
SDL_HapticEffectSupported;
@@ -594,7 +592,6 @@ SDL3_0.0.0 {
SDL_SetWindowSize;
SDL_SetWindowTitle;
SDL_SetWindowsMessageHook;
- SDL_SetYUVConversionMode;
SDL_ShowCursor;
SDL_ShowMessageBox;
SDL_ShowSimpleMessageBox;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 4f479e8c15c7..208eb12382a3 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -371,8 +371,6 @@
#define SDL_GetWindowSizeInPixels SDL_GetWindowSizeInPixels_REAL
#define SDL_GetWindowSurface SDL_GetWindowSurface_REAL
#define SDL_GetWindowTitle SDL_GetWindowTitle_REAL
-#define SDL_GetYUVConversionMode SDL_GetYUVConversionMode_REAL
-#define SDL_GetYUVConversionModeForResolution SDL_GetYUVConversionModeForResolution_REAL
#define SDL_CloseHaptic SDL_CloseHaptic_REAL
#define SDL_DestroyHapticEffect SDL_DestroyHapticEffect_REAL
#define SDL_HapticEffectSupported SDL_HapticEffectSupported_REAL
@@ -617,7 +615,6 @@
#define SDL_SetWindowSize SDL_SetWindowSize_REAL
#define SDL_SetWindowTitle SDL_SetWindowTitle_REAL
#define SDL_SetWindowsMessageHook SDL_SetWindowsMessageHook_REAL
-#define SDL_SetYUVConversionMode SDL_SetYUVConversionMode_REAL
#define SDL_ShowCursor SDL_ShowCursor_REAL
#define SDL_ShowMessageBox SDL_ShowMessageBox_REAL
#define SDL_ShowSimpleMessageBox SDL_ShowSimpleMessageBox_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 2fac10f7fa52..62b4e6c4fe82 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -430,8 +430,6 @@ SDL_DYNAPI_PROC(int,SDL_GetWindowSize,(SDL_Window *a, int *b, int *c),(a,b,c),re
SDL_DYNAPI_PROC(int,SDL_GetWindowSizeInPixels,(SDL_Window *a, int *b, int *c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_Surface*,SDL_GetWindowSurface,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetWindowTitle,(SDL_Window *a),(a),return)
-SDL_DYNAPI_PROC(SDL_YUV_CONVERSION_MODE,SDL_GetYUVConversionMode,(void),(),return)
-SDL_DYNAPI_PROC(SDL_YUV_CONVERSION_MODE,SDL_GetYUVConversionModeForResolution,(int a, int b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_CloseHaptic,(SDL_Haptic *a),(a),)
SDL_DYNAPI_PROC(void,SDL_DestroyHapticEffect,(SDL_Haptic *a, int b),(a,b),)
SDL_DYNAPI_PROC(SDL_bool,SDL_HapticEffectSupported,(SDL_Haptic *a, const SDL_HapticEffect *b),(a,b),return)
@@ -659,7 +657,6 @@ SDL_DYNAPI_PROC(int,SDL_SetWindowPosition,(SDL_Window *a, int b, int c),(a,b,c),
SDL_DYNAPI_PROC(int,SDL_SetWindowResizable,(SDL_Window *a, SDL_bool b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowSize,(SDL_Window *a, int b, int c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_SetWindowTitle,(SDL_Window *a, const char *b),(a,b),return)
-SDL_DYNAPI_PROC(void,SDL_SetYUVConversionMode,(SDL_YUV_CONVERSION_MODE a),(a),)
SDL_DYNAPI_PROC(int,SDL_ShowCursor,(void),(),return)
SDL_DYNAPI_PROC(int,SDL_ShowMessageBox,(const SDL_MessageBoxData *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_ShowSimpleMessageBox,(Uint32 a, const char *b, const char *c, SDL_Window *d),(a,b,c,d),return)
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index 4ba113a93b4f..c8d2e7b46b4f 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -944,17 +944,19 @@ static int SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, LPDIREC
}
#if SDL_HAVE_YUV
if (texturedata->yuv) {
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- *shader = data->shaders[SHADER_YUV_JPEG];
- break;
- case SDL_YUV_CONVERSION_BT601:
- *shader = data->shaders[SHADER_YUV_BT601];
- break;
- case SDL_YUV_CONVERSION_BT709:
- *shader = data->shaders[SHADER_YUV_BT709];
- break;
- default:
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ *shader = data->shaders[SHADER_YUV_BT601];
+ } else {
+ *shader = data->shaders[SHADER_YUV_JPEG];
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ *shader = data->shaders[SHADER_YUV_BT709];
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
+ }
+ } else {
return SDL_SetError("Unsupported YUV conversion mode");
}
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index 3c61a192e3cf..f1bbcea57f86 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -2151,17 +2151,19 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D11_Shader shader;
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- shader = SHADER_YUV_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- shader = SHADER_YUV_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- shader = SHADER_YUV_BT709;
- break;
- default:
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = SHADER_YUV_BT601;
+ } else {
+ shader = SHADER_YUV_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = SHADER_YUV_BT709;
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
+ }
+ } else {
return SDL_SetError("Unsupported YUV conversion mode");
}
@@ -2175,17 +2177,19 @@ static int D3D11_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D11_Shader shader;
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
- break;
- default:
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
+ } else {
+ shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
+ }
+ } else {
return SDL_SetError("Unsupported YUV conversion mode");
}
diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c
index 0d6c40590166..484d0e27270f 100644
--- a/src/render/direct3d12/SDL_render_d3d12.c
+++ b/src/render/direct3d12/SDL_render_d3d12.c
@@ -2589,17 +2589,19 @@ static int D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D12_Shader shader;
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- shader = SHADER_YUV_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- shader = SHADER_YUV_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- shader = SHADER_YUV_BT709;
- break;
- default:
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = SHADER_YUV_BT601;
+ } else {
+ shader = SHADER_YUV_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = SHADER_YUV_BT709;
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
+ }
+ } else {
return SDL_SetError("Unsupported YUV conversion mode");
}
@@ -2620,17 +2622,19 @@ static int D3D12_SetCopyState(SDL_Renderer *renderer, const SDL_RenderCommand *c
};
D3D12_Shader shader;
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
- break;
- default:
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
+ } else {
+ shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
+ }
+ } else {
return SDL_SetError("Unsupported YUV conversion mode");
}
diff --git a/src/render/metal/SDL_render_metal.m b/src/render/metal/SDL_render_metal.m
index 09f39fbf20b1..fb545336577e 100644
--- a/src/render/metal/SDL_render_metal.m
+++ b/src/render/metal/SDL_render_metal.m
@@ -638,20 +638,20 @@ static int METAL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL
#if SDL_HAVE_YUV
if (yuv || nv12) {
size_t offset = 0;
- SDL_YUV_CONVERSION_MODE mode = SDL_GetYUVConversionModeForResolution(texture->w, texture->h);
- switch (mode) {
- case SDL_YUV_CONVERSION_JPEG:
- offset = CONSTANTS_OFFSET_DECODE_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- offset = CONSTANTS_OFFSET_DECODE_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- offset = CONSTANTS_OFFSET_DECODE_BT709;
- break;
- default:
- offset = 0;
- break;
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ offset = CONSTANTS_OFFSET_DECODE_BT601;
+ } else {
+ offset = CONSTANTS_OFFSET_DECODE_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ offset = CONSTANTS_OFFSET_DECODE_BT709;
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
+ }
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
}
texturedata.conversionBufferOffset = offset;
}
@@ -1723,10 +1723,10 @@ static SDL_MetalView GetWindowView(SDL_Window *window)
};
float decodetransformBT709[4 * 4] = {
- 0.0, -0.501960814, -0.501960814, 0.0, /* offset */
- 1.0000, 0.0000, 1.4020, 0.0, /* Rcoeff */
- 1.0000, -0.3441, -0.7141, 0.0, /* Gcoeff */
- 1.0000, 1.7720, 0.0000, 0.0, /* Bcoeff */
+ -0.0627451017, -0.501960814, -0.501960814, 0.0, /* offset */
+ 1.1644, 0.0000, 1.7927, 0.0, /* Rcoeff */
+ 1.1644, -0.2132, -0.5329, 0.0, /* Gcoeff */
+ 1.1644, 2.1124, 0.0000, 0.0, /* Bcoeff */
};
if (!IsMetalAvailable()) {
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index e758e0de045a..5749e496affc 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -662,45 +662,46 @@ static int GL_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Pr
#if SDL_HAVE_YUV
if (data->yuv || data->nv12) {
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_JPEG:
- if (data->yuv) {
- data->shader = SHADER_YUV_JPEG;
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
- data->shader = SHADER_NV12_JPEG;
- } else {
- data->shader = SHADER_NV21_JPEG;
- }
- break;
- case SDL_YUV_CONVERSION_BT601:
- if (data->yuv) {
- data->shader = SHADER_YUV_BT601;
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
- if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
- data->shader = SHADER_NV12_RG_BT601;
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ if (data->yuv) {
+ data->shader = SHADER_YUV_BT601;
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
+ if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
+ data->shader = SHADER_NV12_RG_BT601;
+ } else {
+ data->shader = SHADER_NV12_RA_BT601;
+ }
} else {
- data->shader = SHADER_NV12_RA_BT601;
+ data->shader = SHADER_NV21_BT601;
}
} else {
- data->shader = SHADER_NV21_BT601;
+ if (data->yuv) {
+ data->shader = SHADER_YUV_JPEG;
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
+ data->shader = SHADER_NV12_JPEG;
+ } else {
+ data->shader = SHADER_NV21_JPEG;
+ }
}
- break;
- case SDL_YUV_CONVERSION_BT709:
- if (data->yuv) {
- data->shader = SHADER_YUV_BT709;
- } else if (texture->format == SDL_PIXELFORMAT_NV12) {
- if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
- data->shader = SHADER_NV12_RG_BT709;
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ if (data->yuv) {
+ data->shader = SHADER_YUV_BT709;
+ } else if (texture->format == SDL_PIXELFORMAT_NV12) {
+ if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
+ data->shader = SHADER_NV12_RG_BT709;
+ } else {
+ data->shader = SHADER_NV12_RA_BT709;
+ }
} else {
- data->shader = SHADER_NV12_RA_BT709;
+ data->shader = SHADER_NV21_BT709;
}
} else {
- data->shader = SHADER_NV21_BT709;
+ return SDL_SetError("Unsupported YUV conversion mode");
}
- break;
- default:
- SDL_assert(!"unsupported YUV conversion mode");
- break;
+ } else {
+ return SDL_SetError("Unsupported YUV conversion mode");
}
}
#endif /* SDL_HAVE_YUV */
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index a3ea1eee046e..2ac81959902b 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -588,7 +588,7 @@ static int GLES2_CacheShaders(GLES2_RenderData *data)
return 0;
}
-static int GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, int w, int h)
+static int GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source, SDL_Colorspace colorspace)
{
GLuint vertex;
GLuint fragment;
@@ -615,58 +615,67 @@ static int GLES2_SelectProgram(GLES2_RenderData *data, GLES2_ImageSource source,
break;
#if SDL_HAVE_YUV
case GLES2_IMAGESOURCE_TEXTURE_YUV:
- switch (SDL_GetYUVConversionModeForResolution(w, h)) {
- case SDL_YUV_CONVERSION_JPEG:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709;
- break;
- default:
- SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
+ if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT601;
+ } else {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_YUV_BT709;
+ } else {
+ SDL_SetError("Unsupported YUV conversion mode");
+ goto fault;
+ }
+ } else {
+ SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
case GLES2_IMAGESOURCE_TEXTURE_NV12:
- switch (SDL_GetYUVConversionModeForResolution(w, h)) {
- case SDL_YUV_CONVERSION_JPEG:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT601;
+ if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
+ if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT601;
+ } else {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT601;
+ }
} else {
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT601;
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_JPEG;
}
- break;
- case SDL_YUV_CONVERSION_BT709:
- if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT709;
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
+ if (SDL_GetHintBoolean("SDL_RENDER_OPENGL_NV12_RG_SHADER", SDL_FALSE)) {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RG_BT709;
+ } else {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT709;
+ }
} else {
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV12_RA_BT709;
+ SDL_SetError("Unsupported YUV conversion mode");
+ goto fault;
}
- break;
- default:
- SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
+ } else {
+ SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
case GLES2_IMAGESOURCE_TEXTURE_NV21:
- switch (SDL_GetYUVConversionModeForResolution(w, h)) {
- case SDL_YUV_CONVERSION_JPEG:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG;
- break;
- case SDL_YUV_CONVERSION_BT601:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601;
- break;
- case SDL_YUV_CONVERSION_BT709:
- ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709;
- break;
- default:
- SDL_SetError("Unsupported YUV conversion mode: %d\n", SDL_GetYUVConversionModeForResolution(w, h));
+ if (SDL_ISCOLORSPACE_YUV_BT601(colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT601;
+ } else {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_JPEG;
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(colorspace)) {
+ ftype = GLES2_SHADER_FRAGMENT_TEXTURE_NV21_BT709;
+ } else {
+ SDL_SetError("Unsupported YUV conversion mode");
+ goto fault;
+ }
+ } else {
+ SDL_SetError("Unsupported YUV conversion mode");
goto fault;
}
break;
@@ -961,7 +970,7 @@ static int SetDrawState(GLES2_RenderData *data, const SDL_RenderCommand *cmd, co
data->glVertexAttribPointer(GLES2_ATTRIBUTE_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, (const GLvoid *)&verts->tex_coord);
}
- if (GLES2_SelectProgram(data, imgsrc, texture ? texture->w : 0, texture ? texture->h : 0) < 0) {
+ if (GLES2_SelectProgram(data, imgsrc, texture ? texture->colorspace : SDL_COLORSPACE_SRGB) < 0) {
return -1;
}
diff --git a/src/render/vitagxm/SDL_render_vita_gxm.c b/src/render/vitagxm/SDL_render_vita_gxm.c
index 5bd09e4a18d2..c82219c42a9b 100644
--- a/src/render/vitagxm/SDL_render_vita_gxm.c
+++ b/src/render/vitagxm/SDL_render_vita_gxm.c
@@ -341,17 +341,20 @@ static void VITA_GXM_SetYUVProfile(SDL_Renderer *renderer, SDL_Texture *texture)
{
VITA_GXM_RenderData *data = (VITA_GXM_RenderData *)renderer->driverdata;
int ret = 0;
- switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
- case SDL_YUV_CONVERSION_BT601:
- ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD);
- break;
- case SDL_YUV_CONVERSION_BT709:
- ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD);
- break;
- case SDL_YUV_CONVERSION_JPEG:
- default:
- SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV profile: %d\n", SDL_GetYUVConversionModeForResolution(texture->w, texture->h));
- break;
+ if (SDL_ISCOLORSPACE_YUV_BT601(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_STANDARD);
+ } else {
+ ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT601_FULL_RANGE);
+ }
+ } else if (SDL_ISCOLORSPACE_YUV_BT709(texture->colorspace)) {
+ if (SDL_ISCOLORSPACE_LIMITED_RANGE(texture->colorspace)) {
+ ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_STANDARD);
+ } else {
+ ret = sceGxmSetYuvProfile(data->gxm_context, 0, SCE_GXM_YUV_PROFILE_BT709_FULL_RANGE);
+ }
+ } else {
+ SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Unsupported YUV conversion mode\n");
}
if (ret < 0) {
diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index 2b6ece7fa71d..c76805151969 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -695,7 +695
(Patch may be truncated, please check the link at the top of this post.)