From 07ecc125cf34cc0f1787c13c50176b0730aecbc5 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 22 Jun 2026 12:42:45 -0700
Subject: [PATCH] Added SDL_PIXELFORMAT_P408 and SDL_PIXELFORMAT_P416
---
include/SDL3/SDL_pixels.h | 23 ++--
src/render/SDL_render.c | 6 +-
src/render/SDL_yuv_sw.c | 134 +++++++++++++++----
src/render/direct3d/SDL_render_d3d.c | 69 ++++++++--
src/render/direct3d11/SDL_render_d3d11.c | 99 +++++++++++---
src/render/direct3d12/SDL_render_d3d12.c | 112 +++++++++++++---
src/render/gpu/SDL_render_gpu.c | 84 ++++++++++--
src/render/metal/SDL_render_metal.m | 43 ++++++-
src/render/opengl/SDL_render_gl.c | 117 +++++++++++++----
src/render/opengles2/SDL_render_gles2.c | 157 +++++++++++++++--------
src/render/vulkan/SDL_render_vulkan.c | 59 +++++++--
src/video/SDL_pixels.c | 4 +-
src/video/SDL_yuv.c | 138 ++++++++++++++++++--
src/video/yuv2rgb/yuv_rgb_internal.h | 8 +-
src/video/yuv2rgb/yuv_rgb_std.c | 40 ++++++
src/video/yuv2rgb/yuv_rgb_std.h | 30 +++++
src/video/yuv2rgb/yuv_rgb_std_func.h | 26 ++++
test/testautomation_pixels.c | 22 +++-
test/testyuv.c | 93 ++++++++++++--
test/testyuv_cvt.c | 53 ++++++++
20 files changed, 1091 insertions(+), 226 deletions(-)
diff --git a/include/SDL3/SDL_pixels.h b/include/SDL3/SDL_pixels.h
index fd1ed31a4a266..1ac325b9aed7c 100644
--- a/include/SDL3/SDL_pixels.h
+++ b/include/SDL3/SDL_pixels.h
@@ -363,7 +363,8 @@ typedef enum SDL_PackedLayout
((((format) == SDL_PIXELFORMAT_YUY2) || \
((format) == SDL_PIXELFORMAT_UYVY) || \
((format) == SDL_PIXELFORMAT_YVYU) || \
- ((format) == SDL_PIXELFORMAT_P010)) ? 2 : 1) : (((format) >> 0) & 0xFF))
+ ((format) == SDL_PIXELFORMAT_P010) || \
+ ((format) == SDL_PIXELFORMAT_P416)) ? 2 : 1) : (((format) >> 0) & 0xFF))
/**
@@ -657,22 +658,26 @@ typedef enum SDL_PixelFormat
SDL_PIXELFORMAT_ABGR128_FLOAT = 0x1b608010u,
/* SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_ARRAYF32, SDL_ARRAYORDER_ABGR, 0, 128, 16), */
- SDL_PIXELFORMAT_YV12 = 0x32315659u, /**< Planar mode: Y + V + U (3 planes) */
+ SDL_PIXELFORMAT_YV12 = 0x32315659u, /**< YUV 4:2:0 8-bit planar mode: Y + V + U (3 planes) */
/* SDL_DEFINE_PIXELFOURCC('Y', 'V', '1', '2'), */
- SDL_PIXELFORMAT_IYUV = 0x56555949u, /**< Planar mode: Y + U + V (3 planes) */
+ SDL_PIXELFORMAT_IYUV = 0x56555949u, /**< YUV 4:2:0 8-bit planar mode: Y + U + V (3 planes) */
/* SDL_DEFINE_PIXELFOURCC('I', 'Y', 'U', 'V'), */
- SDL_PIXELFORMAT_YUY2 = 0x32595559u, /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */
+ SDL_PIXELFORMAT_YUY2 = 0x32595559u, /**< YUV 4:2:0 8-bit packed mode: Y0+U0+Y1+V0 (1 plane) */
/* SDL_DEFINE_PIXELFOURCC('Y', 'U', 'Y', '2'), */
- SDL_PIXELFORMAT_UYVY = 0x59565955u, /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
+ SDL_PIXELFORMAT_UYVY = 0x59565955u, /**< YUV 4:2:0 8-bit packed mode: U0+Y0+V0+Y1 (1 plane) */
/* SDL_DEFINE_PIXELFOURCC('U', 'Y', 'V', 'Y'), */
- SDL_PIXELFORMAT_YVYU = 0x55595659u, /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
+ SDL_PIXELFORMAT_YVYU = 0x55595659u, /**< YUV 4:2:0 8-bit packed mode: Y0+V0+Y1+U0 (1 plane) */
/* SDL_DEFINE_PIXELFOURCC('Y', 'V', 'Y', 'U'), */
- SDL_PIXELFORMAT_NV12 = 0x3231564eu, /**< Planar mode: Y + U/V interleaved (2 planes) */
+ SDL_PIXELFORMAT_NV12 = 0x3231564eu, /**< YUV 4:2:0 8-bit planar mode: Y + U/V interleaved (2 planes) */
/* SDL_DEFINE_PIXELFOURCC('N', 'V', '1', '2'), */
- SDL_PIXELFORMAT_NV21 = 0x3132564eu, /**< Planar mode: Y + V/U interleaved (2 planes) */
+ SDL_PIXELFORMAT_NV21 = 0x3132564eu, /**< YUV 4:2:0 8-bit planar mode: Y + V/U interleaved (2 planes) */
/* SDL_DEFINE_PIXELFOURCC('N', 'V', '2', '1'), */
- SDL_PIXELFORMAT_P010 = 0x30313050u, /**< Planar mode: Y + U/V interleaved (2 planes) */
+ SDL_PIXELFORMAT_P010 = 0x30313050u, /**< YUV 4:2:0 16-bit planar mode: Y + U/V interleaved (2 planes) */
/* SDL_DEFINE_PIXELFOURCC('P', '0', '1', '0'), */
+ SDL_PIXELFORMAT_P408 = 0x38303450u, /**< YUV 4:4:4 8-bit planar mode: Y + U + V (3 planes) */
+ /* SDL_DEFINE_PIXELFOURCC('P', '4', '0', '8'), */
+ SDL_PIXELFORMAT_P416 = 0x36313450u, /**< YUV 4:4:4 16-bit planar mode: Y + U + V (3 planes) */
+ /* SDL_DEFINE_PIXELFOURCC('P', '4', '0', '8'), */
SDL_PIXELFORMAT_EXTERNAL_OES = 0x2053454fu, /**< Android video texture format */
/* SDL_DEFINE_PIXELFOURCC('O', 'E', 'S', ' ') */
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index c11c29e71d306..e9645aca93d94 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -2518,8 +2518,10 @@ bool SDL_UpdateYUVTexture(SDL_Texture *texture, const SDL_Rect *rect,
}
CHECK_PARAM(texture->format != SDL_PIXELFORMAT_YV12 &&
- texture->format != SDL_PIXELFORMAT_IYUV) {
- return SDL_SetError("Texture format must be YV12 or IYUV");
+ texture->format != SDL_PIXELFORMAT_IYUV &&
+ texture->format != SDL_PIXELFORMAT_P408 &&
+ texture->format != SDL_PIXELFORMAT_P416) {
+ return SDL_SetError("Texture format must be YV12, IYUV, P408, or P416");
}
real_rect.x = 0;
diff --git a/src/render/SDL_yuv_sw.c b/src/render/SDL_yuv_sw.c
index 4c4b7dc987345..97d8b0b59fd6b 100644
--- a/src/render/SDL_yuv_sw.c
+++ b/src/render/SDL_yuv_sw.c
@@ -35,6 +35,8 @@ SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspac
switch (format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_P408:
+ case SDL_PIXELFORMAT_P416:
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
@@ -80,13 +82,21 @@ SDL_SW_YUVTexture *SDL_SW_CreateYUVTexture(SDL_PixelFormat format, SDL_Colorspac
swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * ((h + 1) / 2);
break;
+ case SDL_PIXELFORMAT_P408:
+ case SDL_PIXELFORMAT_P416:
+ swdata->pitches[0] = w * SDL_BYTESPERPIXEL(format);
+ swdata->pitches[1] = swdata->pitches[0];
+ swdata->pitches[2] = swdata->pitches[1];
+ swdata->planes[0] = swdata->pixels;
+ swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
+ swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * h;
+ break;
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
swdata->pitches[0] = ((w + 1) / 2) * 4;
swdata->planes[0] = swdata->pixels;
break;
-
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
swdata->pitches[0] = w;
@@ -119,7 +129,7 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
if (rect->x == 0 && rect->y == 0 &&
- rect->w == swdata->w && rect->h == swdata->h) {
+ rect->w == swdata->w && rect->h == swdata->h && pitch == swdata->pitches[0]) {
SDL_memcpy(swdata->pixels, pixels,
(size_t)(swdata->h * swdata->w) + 2 * ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2));
} else {
@@ -161,6 +171,47 @@ bool SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
}
}
break;
+ case SDL_PIXELFORMAT_P408:
+ case SDL_PIXELFORMAT_P416:
+ if (rect->x == 0 && rect->y == 0 &&
+ rect->w == swdata->w && rect->h == swdata->h && pitch == swdata->pitches[0]) {
+ SDL_memcpy(swdata->pixels, pixels, (size_t)(swdata->h * pitch * 3));
+ } else {
+ Uint8 *src, *dst;
+ int row;
+ size_t length;
+ const int bpp = SDL_BYTESPERPIXEL(swdata->format);
+
+ // Copy the Y plane
+ src = (Uint8 *)pixels;
+ dst = swdata->pixels;
+ dst += rect->y * swdata->pitches[0] + rect->x *bpp;
+ length = rect->w * bpp;
+ for (row = 0; row < rect->h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += pitch;
+ dst += swdata->pitches[0];
+ }
+
+ // Copy the next plane
+ dst = swdata->pixels + swdata->h * swdata->pitches[0];
+ dst += rect->y * swdata->pitches[1] + rect->x * bpp;
+ for (row = 0; row < rect->h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += pitch;
+ dst += swdata->pitches[1];
+ }
+
+ // Copy the next plane
+ dst = swdata->pixels + swdata->h * swdata->pitches[0] + swdata->h * swdata->pitches[1];
+ dst += rect->y * swdata->pitches[2] + rect->x * bpp;
+ for (row = 0; row < rect->h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += pitch;
+ dst += swdata->pitches[2];
+ }
+ }
+ break;
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
@@ -229,47 +280,72 @@ bool SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture *swdata, const SDL_Rect *re
Uint8 *dst;
int row;
size_t length;
+ const int bpp = SDL_BYTESPERPIXEL(swdata->format);
// Copy the Y plane
src = Yplane;
- dst = swdata->pixels + rect->y * swdata->w + rect->x;
+ dst = swdata->pixels + rect->y * swdata->pitches[0] + rect->x * bpp;
length = rect->w;
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += Ypitch;
- dst += swdata->w;
+ dst += swdata->pitches[0];
}
// Copy the U plane
src = Uplane;
- if (swdata->format == SDL_PIXELFORMAT_IYUV) {
- dst = swdata->pixels + swdata->h * swdata->w;
+ if (swdata->format == SDL_PIXELFORMAT_P408 ||
+ swdata->format == SDL_PIXELFORMAT_P416) {
+ dst = swdata->pixels + swdata->h * swdata->pitches[0];
+ dst += rect->y * swdata->pitches[1] + rect->x * bpp;
+ length = rect->w * bpp;
+ for (row = 0; row < rect->h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += Upitch;
+ dst += swdata->pitches[1];
+ }
} else {
- dst = swdata->pixels + swdata->h * swdata->w +
- ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
- }
- dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2;
- length = (rect->w + 1) / 2;
- for (row = 0; row < (rect->h + 1) / 2; ++row) {
- SDL_memcpy(dst, src, length);
- src += Upitch;
- dst += (swdata->w + 1) / 2;
+ if (swdata->format == SDL_PIXELFORMAT_IYUV) {
+ dst = swdata->pixels + swdata->h * swdata->w;
+ } else {
+ dst = swdata->pixels + swdata->h * swdata->w +
+ ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
+ }
+ dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2;
+ length = (rect->w + 1) / 2;
+ for (row = 0; row < (rect->h + 1) / 2; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += Upitch;
+ dst += (swdata->w + 1) / 2;
+ }
}
// Copy the V plane
src = Vplane;
- if (swdata->format == SDL_PIXELFORMAT_YV12) {
- dst = swdata->pixels + swdata->h * swdata->w;
+ if (swdata->format == SDL_PIXELFORMAT_P408 ||
+ swdata->format == SDL_PIXELFORMAT_P416) {
+ dst = swdata->pixels + swdata->h * swdata->pitches[0] + swdata->h * swdata->pitches[1];
+ dst += rect->y * swdata->pitches[2] + rect->x * bpp;
+ length = rect->w * bpp;
+ for (row = 0; row < rect->h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += Vpitch;
+ dst += swdata->pitches[2];
+ }
} else {
- dst = swdata->pixels + swdata->h * swdata->w +
- ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
- }
- dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2;
- length = (rect->w + 1) / 2;
- for (row = 0; row < (rect->h + 1) / 2; ++row) {
- SDL_memcpy(dst, src, length);
- src += Vpitch;
- dst += (swdata->w + 1) / 2;
+ if (swdata->format == SDL_PIXELFORMAT_YV12) {
+ dst = swdata->pixels + swdata->h * swdata->w;
+ } else {
+ dst = swdata->pixels + swdata->h * swdata->w +
+ ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
+ }
+ dst += rect->y / 2 * ((swdata->w + 1) / 2) + rect->x / 2;
+ length = (rect->w + 1) / 2;
+ for (row = 0; row < (rect->h + 1) / 2; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += Vpitch;
+ dst += (swdata->w + 1) / 2;
+ }
}
return true;
}
@@ -314,10 +390,12 @@ bool SDL_SW_LockYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
switch (swdata->format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_P408:
+ case SDL_PIXELFORMAT_P416:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
if (rect && (rect->x != 0 || rect->y != 0 || rect->w != swdata->w || rect->h != swdata->h)) {
- return SDL_SetError("YV12, IYUV, NV12, NV21 textures only support full surface locks");
+ return SDL_SetError("YV12, IYUV, P408, P416, NV12, NV21 textures only support full surface locks");
}
break;
default:
@@ -325,7 +403,7 @@ bool SDL_SW_LockYUVTexture(SDL_SW_YUVTexture *swdata, const SDL_Rect *rect,
}
if (rect) {
- *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * 2;
+ *pixels = swdata->planes[0] + rect->y * swdata->pitches[0] + rect->x * SDL_BYTESPERPIXEL(swdata->format);
} else {
*pixels = swdata->planes[0];
}
diff --git a/src/render/direct3d/SDL_render_d3d.c b/src/render/direct3d/SDL_render_d3d.c
index ed17e6c8b1d3c..c06ec7998a1da 100644
--- a/src/render/direct3d/SDL_render_d3d.c
+++ b/src/render/direct3d/SDL_render_d3d.c
@@ -223,6 +223,7 @@ static D3DFORMAT PixelFormatToD3DFMT(Uint32 format)
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
+ case SDL_PIXELFORMAT_P408:
return D3DFMT_L8;
default:
for (int i = 0; i < SDL_arraysize(d3d_format_map); i++) {
@@ -628,17 +629,30 @@ static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
}
#ifdef SDL_HAVE_YUV
if (texturedata->yuv) {
- // Skip to the correct offset into the next texture
- pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
+ if (texture->format == SDL_PIXELFORMAT_P408) {
+ // Skip to the correct offset into the next texture
+ pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
+ if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
+ return false;
+ }
- if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
- return false;
- }
+ // Skip to the correct offset into the next texture
+ pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
+ if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
+ return false;
+ }
+ } else {
+ // Skip to the correct offset into the next texture
+ pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
+ if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
+ return false;
+ }
- // Skip to the correct offset into the next texture
- pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
- if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
- return false;
+ // Skip to the correct offset into the next texture
+ pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
+ if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
+ return false;
+ }
}
}
#endif
@@ -688,6 +702,23 @@ static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_
return false;
}
+ texturedata->shader_params_length = 4; // The YUV shader takes 4 float4 parameters
+ texturedata->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
+ if (texturedata->shader_params == NULL) {
+ return SDL_SetError("Unsupported YUV colorspace");
+ }
+ }
+ if (texture->format == SDL_PIXELFORMAT_P408) {
+ texturedata->yuv = true;
+
+ if (!D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) {
+ return false;
+ }
+
+ if (!D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) {
+ return false;
+ }
+
texturedata->shader_params_length = 4; // The YUV shader takes 4 float4 parameters
texturedata->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
if (texturedata->shader_params == NULL) {
@@ -741,11 +772,20 @@ static bool D3D_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch)) {
return false;
}
- if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) {
- return false;
- }
- if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) {
- return false;
+ if (texture->format == SDL_PIXELFORMAT_P408) {
+ if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x, rect->y, rect->w, rect->h, Uplane, Upitch)) {
+ return false;
+ }
+ if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x, rect->y, rect->w, rect->h, Vplane, Vpitch)) {
+ return false;
+ }
+ } else {
+ if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) {
+ return false;
+ }
+ if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) {
+ return false;
+ }
}
return true;
}
@@ -2005,6 +2045,7 @@ static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_P
if (caps.MaxSimultaneousTextures >= 3 && data->shaders[SHADER_YUV]) {
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV);
+ SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P408);
}
#endif
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index edb0be613ae93..607242c51efce 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -266,12 +266,15 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 outpu
case SDL_PIXELFORMAT_INDEX8:
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_P408:
return DXGI_FORMAT_R8_UNORM;
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
return DXGI_FORMAT_NV12;
case SDL_PIXELFORMAT_P010:
return DXGI_FORMAT_P010;
+ case SDL_PIXELFORMAT_P416:
+ return DXGI_FORMAT_R16_UNORM;
default:
for (int i = 0; i < SDL_arraysize(dxgi_format_map); i++) {
if (dxgi_format_map[i].sdl == format) {
@@ -289,8 +292,6 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 format, Uint32 outpu
static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 format, Uint32 colorspace)
{
switch (format) {
- case SDL_PIXELFORMAT_YV12:
- case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12: // For the Y texture
case SDL_PIXELFORMAT_NV21: // For the Y texture
return DXGI_FORMAT_R8_UNORM;
@@ -1309,6 +1310,45 @@ static bool D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
return SDL_SetError("Unsupported YUV colorspace");
}
}
+ if (texture->format == SDL_PIXELFORMAT_P408 ||
+ texture->format == SDL_PIXELFORMAT_P416) {
+
+ textureData->yuv = true;
+
+ if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_U_POINTER, &textureData->mainTextureU)) {
+ return false;
+ }
+ if (!textureData->mainTextureU) {
+ result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
+ &textureDesc,
+ NULL,
+ &textureData->mainTextureU);
+ if (FAILED(result)) {
+ return WIN_SetErrorFromHRESULT("ID3D11Device1::CreateTexture2D", result);
+ }
+ }
+ SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_U_POINTER, textureData->mainTextureU);
+
+ if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D11_TEXTURE_V_POINTER, &textureData->mainTextureV)) {
+ return false;
+ }
+ if (!textureData->mainTextureV) {
+ result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
+ &textureDesc,
+ NULL,
+ &textureData->mainTextureV);
+ if (FAILED(result)) {
+ return WIN_SetErrorFromHRESULT("ID3D11Device1::CreateTexture2D", result);
+ }
+ }
+ SDL_SetPointerProperty(SDL_GetTextureProperties(texture), SDL_PROP_TEXTURE_D3D11_TEXTURE_V_POINTER, textureData->mainTextureV);
+
+ const int bits_per_pixel = (texture->format == SDL_PIXELFORMAT_P408) ? 8 : 16;
+ textureData->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel);
+ if (!textureData->YCbCr_matrix) {
+ return SDL_SetError("Unsupported YUV colorspace");
+ }
+ }
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21 ||
texture->format == SDL_PIXELFORMAT_P010) {
@@ -1562,16 +1602,29 @@ static bool D3D11_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
return D3D11_UpdateTextureNV(renderer, texture, rect, plane0, Ypitch, plane1, UVpitch);
} else if (textureData->yuv) {
- int Ypitch = srcPitch;
- int UVpitch = ((Ypitch + 1) / 2);
- const Uint8 *plane0 = (const Uint8 *)srcPixels;
- const Uint8 *plane1 = plane0 + rect->h * Ypitch;
- const Uint8 *plane2 = plane1 + ((rect->h + 1) / 2) * UVpitch;
+ if (texture->format == SDL_PIXELFORMAT_P408 || texture->format == SDL_PIXELFORMAT_P416) {
+ const Uint8 *plane0 = (const Uint8 *)srcPixels;
+ const Uint8 *plane1 = plane0 + rect->h * srcPitch;
+ const Uint8 *plane2 = plane1 + rect->h * srcPitch;
- if (texture->format == SDL_PIXELFORMAT_YV12) {
- return D3D11_UpdateTextureYUV(renderer, texture, rect, plane0, Ypitch, plane2, UVpitch, plane1, UVpitch);
+ if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, plane1, srcPitch)) {
+ return false;
+ }
+ if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, plane2, srcPitch)) {
+ return false;
+ }
} else {
- return D3D11_UpdateTextureYUV(renderer, texture, rect, plane0, Ypitch, plane1, UVpitch, plane2, UVpitch);
+ int Ypitch = srcPitch;
+ int UVpitch = ((Ypitch + 1) / 2);
+ const Uint8 *plane0 = (const Uint8 *)srcPixels;
+ const Uint8 *plane1 = plane0 + rect->h * Ypitch;
+ const Uint8 *plane2 = plane1 + ((rect->h + 1) / 2) * UVpitch;
+
+ if (texture->format == SDL_PIXELFORMAT_YV12) {
+ return D3D11_UpdateTextureYUV(renderer, texture, rect, plane0, Ypitch, plane2, UVpitch, plane1, UVpitch);
+ } else {
+ return D3D11_UpdateTextureYUV(renderer, texture, rect, plane0, Ypitch, plane1, UVpitch, plane2, UVpitch);
+ }
}
}
#endif
@@ -1599,11 +1652,20 @@ static bool D3D11_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch)) {
return false;
}
- if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) {
- return false;
- }
- if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) {
- return false;
+ if (texture->format == SDL_PIXELFORMAT_P408 || texture->format == SDL_PIXELFORMAT_P416) {
+ if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Uplane, Upitch)) {
+ return false;
+ }
+ if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Vplane, Vpitch)) {
+ return false;
+ }
+ } else {
+ if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) {
+ return false;
+ }
+ if (!D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) {
+ return false;
+ }
}
return true;
}
@@ -2153,6 +2215,7 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC
break;
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_P408:
constants->texture_type = TEXTURETYPE_YUV;
constants->input_type = INPUTTYPE_SRGB;
break;
@@ -2168,6 +2231,10 @@ static void D3D11_SetupShaderConstants(SDL_Renderer *renderer, const SDL_RenderC
constants->texture_type = TEXTURETYPE_NV12;
constants->input_type = INPUTTYPE_HDR10;
break;
+ case SDL_PIXELFORMAT_P416:
+ constants->texture_type = TEXTURETYPE_YUV;
+ constants->input_type = INPUTTYPE_HDR10;
+ break;
default:
if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) {
constants->texture_type = TEXTURETYPE_RGB_PIXELART;
@@ -2971,9 +3038,11 @@ static bool D3D11_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV);
+ SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P408);
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12);
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21);
SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010);
+ SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P416);
return true;
}
diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c
index d88903c6f6266..c2671988b8a19 100644
--- a/src/render/direct3d12/SDL_render_d3d12.c
+++ b/src/render/direct3d12/SDL_render_d3d12.c
@@ -328,12 +328,15 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(SDL_PixelFormat format, Uin
case SDL_PIXELFORMAT_INDEX8:
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_P408:
return DXGI_FORMAT_R8_UNORM;
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
return DXGI_FORMAT_NV12;
case SDL_PIXELFORMAT_P010:
return DXGI_FORMAT_P010;
+ case SDL_PIXELFORMAT_P416:
+ return DXGI_FORMAT_R16_UNORM;
default:
for (int i = 0; i < SDL_arraysize(dxgi_format_map); i++) {
if (dxgi_format_map[i].sdl == format) {
@@ -351,9 +354,6 @@ static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(SDL_PixelFormat format, Uin
static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(SDL_PixelFormat format, Uint32 colorspace)
{
switch (format) {
- case SDL_PIXELFORMAT_INDEX8:
- case SDL_PIXELFORMAT_YV12:
- case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12: // For the Y texture
case SDL_PIXELFORMAT_NV21: // For the Y texture
return DXGI_FORMAT_R8_UNORM;
@@ -1740,6 +1740,55 @@ static bool D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SD
}
}
+ if (texture->format == SDL_PIXELFORMAT_P408 ||
+ texture->format == SDL_PIXELFORMAT_P416) {
+ textureData->yuv = true;
+
+ if (!GetTextureProperty(create_props, SDL_PROP_TEXTURE_CREATE_D3D12_TEXTURE_U_POINTER, &textureData->mainTextureU)) {
+ return false;
+ }
+ if (!textureData->mainTextureU) {
+ result = ID3D12Device1_CreateCommittedResource(rendererData->d3dDevice,
+ &heapProps,
+ D3
(Patch may be truncated, please check the link at the top of this post.)