SDL: Fixed updating NV12 and YV12 textures on the direct3d11 renderer

From fb2287dd477769e9a86f7dd5a65cceb65d295f17 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 30 May 2024 14:19:34 -0700
Subject: [PATCH] Fixed updating NV12 and YV12 textures on the direct3d11
 renderer

Fixes https://github.com/libsdl-org/SDL/issues/9928
---
 src/render/direct3d11/SDL_render_d3d11.c | 49 +++++++++++++-----------
 1 file changed, 26 insertions(+), 23 deletions(-)

diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index 5c2ad3e786821..36d2242615708 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -1626,7 +1626,11 @@ static int D3D11_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
         const Uint8 *Uplane = Yplane + rect->h * Ypitch;
         const Uint8 *Vplane = Uplane + ((rect->h + 1) / 2) * UVpitch;
 
-        return D3D11_UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, UVpitch, Vplane, UVpitch);
+        if (texture->format == SDL_PIXELFORMAT_YV12) {
+            return D3D11_UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Vplane, UVpitch, Uplane, UVpitch);
+        } else {
+            return D3D11_UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, UVpitch, Vplane, UVpitch);
+        }
     }
 #endif
 
@@ -1653,10 +1657,10 @@ static int 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) < 0) {
         return -1;
     }
-    if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
+    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) < 0) {
         return -1;
     }
-    if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
+    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) < 0) {
         return -1;
     }
     return 0;
@@ -1693,6 +1697,11 @@ static int D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
     stagingTextureDesc.MiscFlags = 0;
     stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
     stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
+    if (stagingTextureDesc.Format == DXGI_FORMAT_NV12 ||
+        stagingTextureDesc.Format == DXGI_FORMAT_P010) {
+        stagingTextureDesc.Width = (stagingTextureDesc.Width + 1) & ~1;
+        stagingTextureDesc.Height = (stagingTextureDesc.Height + 1) & ~1;
+    }
     result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
                                           &stagingTextureDesc,
                                           NULL,
@@ -1714,11 +1723,10 @@ static int D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
     }
 
     src = Yplane;
-    dst = textureMemory.pData;
+    dst = (Uint8 *)textureMemory.pData;
     length = w;
     if (length == (UINT)Ypitch && length == textureMemory.RowPitch) {
-        SDL_memcpy(dst, src, (size_t)length * rect->h);
-        dst += length * rect->h;
+        SDL_memcpy(dst, src, (size_t)length * h);
     } else {
         if (length > (UINT)Ypitch) {
             length = Ypitch;
@@ -1733,26 +1741,21 @@ static int D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
         }
     }
 
-    /* Adjust dimensions for the UV plane */
-    w = ((w + 1) / 2) * 2;
-    h = ((h + 1) / 2);
-
     src = UVplane;
     length = w;
-    if (length == (UINT)UVpitch && length == textureMemory.RowPitch) {
-        SDL_memcpy(dst, src, (size_t)length * h);
+    h = (h + 1) / 2;
+    if (stagingTextureDesc.Format == DXGI_FORMAT_P010) {
+        length = (length + 3) & ~3;
+        UVpitch = (UVpitch + 3) & ~3;
     } else {
-        if (length > (UINT)UVpitch) {
-            length = UVpitch;
-        }
-        if (length > textureMemory.RowPitch) {
-            length = textureMemory.RowPitch;
-        }
-        for (row = 0; row < h; ++row) {
-            SDL_memcpy(dst, src, length);
-            src += UVpitch;
-            dst += textureMemory.RowPitch;
-        }
+        length = (length + 1) & ~1;
+        UVpitch = (UVpitch + 1) & ~1;
+    }
+    dst = (Uint8 *)textureMemory.pData + stagingTextureDesc.Height * textureMemory.RowPitch;
+    for (row = 0; row < h; ++row) {
+        SDL_memcpy(dst, src, length);
+        src += UVpitch;
+        dst += textureMemory.RowPitch;
     }
 
     /* Commit the pixel buffer's changes back to the staging texture: */