Use YUV colorspaces instead of a global YUV conversion mode

Fixes https://github.com/libsdl-org/SDL/issues/8669
This commit is contained in:
Sam Lantinga
2024-02-03 07:05:32 -08:00
parent 9e76f23561
commit 50a805cdd1
22 changed files with 361 additions and 327 deletions

View File

@@ -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");
}

View File

@@ -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");
}

View File

@@ -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");
}

View File

@@ -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_Renderer *METAL_CreateRenderer(SDL_Window *window, SDL_PropertiesID c
};
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()) {

View File

@@ -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;
}
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;
if (data->yuv) {
data->shader = SHADER_YUV_JPEG;
} else if (texture->format == SDL_PIXELFORMAT_NV12) {
data->shader = SHADER_NV12_JPEG;
} else {
data->shader = SHADER_NV12_RA_BT709;
data->shader = SHADER_NV21_JPEG;
}
}
} 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_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 */

View File

@@ -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;
}

View File

@@ -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) {