From 2bd478ae65a3a7e073d4d6df2364ce970bc6ed4d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 10 Oct 2023 00:04:45 -0700
Subject: [PATCH] Added SDL_GetTextureDXGIResource() to get the DXGI resource
associated with a render texture.
Also switched the D3D11 and D3D12 renderers to use real NV12 textures for NV12 data.
The combination of these two changes allows us to implement 0-copy video decode and playback for D3D11 in testffmpeg without any access to the renderer internals.
---
include/SDL3/SDL_render.h | 17 +++
src/dynapi/SDL_dynapi.sym | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 1 +
src/render/SDL_render.c | 13 ++
src/render/SDL_sysrender.h | 2 +
src/render/direct3d11/SDL_render_d3d11.c | 187 ++++++++++++++++++-----
src/render/direct3d12/SDL_render_d3d12.c | 138 +++++++++--------
test/testffmpeg.c | 166 ++++----------------
test/testoverlay.c | 77 +++++++---
10 files changed, 337 insertions(+), 266 deletions(-)
diff --git a/include/SDL3/SDL_render.h b/include/SDL3/SDL_render.h
index d38484a1c232..bbd4516b782b 100644
--- a/include/SDL3/SDL_render.h
+++ b/include/SDL3/SDL_render.h
@@ -404,6 +404,23 @@ extern DECLSPEC SDL_Texture *SDLCALL SDL_CreateTexture(SDL_Renderer *renderer, U
*/
extern DECLSPEC SDL_Texture *SDLCALL SDL_CreateTextureFromSurface(SDL_Renderer *renderer, SDL_Surface *surface);
+typedef struct IDXGIResource IDXGIResource;
+/**
+ * Get the DXGI resource associated with a texture.
+ *
+ * This is available when using the direct3d11 and direct3d12 renderers.
+ *
+ * Once you are done using the resource, you should release it to avoid a
+ * resource leak.
+ *
+ * \param texture the texture from which to get the associated resource
+ * \returns the DXGI resource associated with given texture or NULL if it is
+ * not available; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC IDXGIResource* SDLCALL SDL_GetTextureDXGIResource(SDL_Texture *texture);
+
/**
* Query the attributes of a texture.
*
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 54467c5f5161..89bf3aff6e5f 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -907,6 +907,7 @@ SDL3_0.0.0 {
SDL_SetAudioStreamFrequencyRatio;
SDL_SetAudioPostmixCallback;
SDL_GetAudioStreamQueued;
+ SDL_GetTextureDXGIResource;
# 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 da300e291329..e7b16789b90d 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -932,3 +932,4 @@
#define SDL_SetAudioStreamFrequencyRatio SDL_SetAudioStreamFrequencyRatio_REAL
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
#define SDL_GetAudioStreamQueued SDL_GetAudioStreamQueued_REAL
+#define SDL_GetTextureDXGIResource SDL_GetTextureDXGIResource_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index a4ffe8d12c67..6bb5f63da287 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -978,3 +978,4 @@ SDL_DYNAPI_PROC(float,SDL_GetAudioStreamFrequencyRatio,(SDL_AudioStream *a),(a),
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFrequencyRatio,(SDL_AudioStream *a, float b),(a,b),return)
SDL_DYNAPI_PROC(int,SDL_SetAudioPostmixCallback,(SDL_AudioDeviceID a, SDL_AudioPostmixCallback b, void *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return)
+SDL_DYNAPI_PROC(IDXGIResource*,SDL_GetTextureDXGIResource,(SDL_Texture *a),(a),return)
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 1df0349806d3..9e9fc1629bdf 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -4186,6 +4186,19 @@ void *SDL_GetRenderMetalCommandEncoder(SDL_Renderer *renderer)
return NULL;
}
+IDXGIResource *SDL_GetTextureDXGIResource(SDL_Texture *texture)
+{
+ SDL_Renderer *renderer;
+
+ CHECK_TEXTURE_MAGIC(texture, NULL);
+ renderer = texture->renderer;
+ if (renderer && renderer->GetTextureDXGIResource) {
+ return renderer->GetTextureDXGIResource(texture);
+ }
+ SDL_Unsupported();
+ return NULL;
+}
+
static SDL_BlendMode SDL_GetShortBlendMode(SDL_BlendMode blendMode)
{
if (blendMode == SDL_BLENDMODE_NONE_FULL) {
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index c7033f8f26cf..b1cb2e8e29e1 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -212,6 +212,8 @@ struct SDL_Renderer
void *(*GetMetalLayer)(SDL_Renderer *renderer);
void *(*GetMetalCommandEncoder)(SDL_Renderer *renderer);
+ IDXGIResource *(*GetTextureDXGIResource)(SDL_Texture *texture);
+
/* The current renderer info */
SDL_RendererInfo info;
diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c
index 5e1b825b9eb6..5df9049e065a 100644
--- a/src/render/direct3d11/SDL_render_d3d11.c
+++ b/src/render/direct3d11/SDL_render_d3d11.c
@@ -102,7 +102,6 @@ typedef struct
/* NV12 texture support */
SDL_bool nv12;
- ID3D11Texture2D *mainTextureNV;
ID3D11ShaderResourceView *mainTextureResourceViewNV;
Uint8 *pixels;
@@ -187,6 +186,7 @@ static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0
#if defined(__WINRT__) && NTDDI_VERSION > NTDDI_WIN8
static const GUID SDL_IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } };
#endif
+static const GUID SDL_IID_IDXGIResource = { 0x035f3ab4, 0x482e, 0x4e50, { 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96, 0x0b } };
static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } };
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 } };
@@ -208,7 +208,7 @@ Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
}
}
-static DXGI_FORMAT SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
+static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 sdlFormat)
{
switch (sdlFormat) {
case SDL_PIXELFORMAT_ARGB8888:
@@ -217,8 +217,26 @@ static DXGI_FORMAT SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
return DXGI_FORMAT_B8G8R8X8_UNORM;
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;
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ return DXGI_FORMAT_NV12;
+ default:
+ return DXGI_FORMAT_UNKNOWN;
+ }
+}
+
+static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 sdlFormat)
+{
+ switch (sdlFormat) {
+ case SDL_PIXELFORMAT_ARGB8888:
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case SDL_PIXELFORMAT_XRGB8888:
+ return DXGI_FORMAT_B8G8R8X8_UNORM;
+ 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;
default:
return DXGI_FORMAT_UNKNOWN;
@@ -850,8 +868,7 @@ static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer *renderer)
static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer *renderer);
-HRESULT
-D3D11_HandleDeviceLost(SDL_Renderer *renderer)
+static HRESULT D3D11_HandleDeviceLost(SDL_Renderer *renderer)
{
HRESULT result = S_OK;
@@ -1055,7 +1072,7 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
D3D11_TextureData *textureData;
HRESULT result;
- DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format);
+ DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format);
D3D11_TEXTURE2D_DESC textureDesc;
D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
@@ -1131,29 +1148,13 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
}
}
-
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21) {
- D3D11_TEXTURE2D_DESC nvTextureDesc = textureDesc;
-
textureData->nv12 = SDL_TRUE;
-
- nvTextureDesc.Format = DXGI_FORMAT_R8G8_UNORM;
- nvTextureDesc.Width = (textureDesc.Width + 1) / 2;
- nvTextureDesc.Height = (textureDesc.Height + 1) / 2;
-
- result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
- &nvTextureDesc,
- NULL,
- &textureData->mainTextureNV);
- if (FAILED(result)) {
- D3D11_DestroyTexture(renderer, texture);
- return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
- }
}
#endif /* SDL_HAVE_YUV */
SDL_zero(resourceViewDesc);
- resourceViewDesc.Format = textureDesc.Format;
+ resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format);
resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
resourceViewDesc.Texture2D.MostDetailedMip = 0;
resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
@@ -1191,7 +1192,7 @@ static int D3D11_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
nvResourceViewDesc.Format = DXGI_FORMAT_R8G8_UNORM;
result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
- (ID3D11Resource *)textureData->mainTextureNV,
+ (ID3D11Resource *)textureData->mainTexture,
&nvResourceViewDesc,
&textureData->mainTextureResourceViewNV);
if (FAILED(result)) {
@@ -1239,7 +1240,6 @@ static void D3D11_DestroyTexture(SDL_Renderer *renderer,
SAFE_RELEASE(data->mainTextureResourceViewU);
SAFE_RELEASE(data->mainTextureV);
SAFE_RELEASE(data->mainTextureResourceViewV);
- SAFE_RELEASE(data->mainTextureNV);
SAFE_RELEASE(data->mainTextureResourceViewNV);
SDL_free(data->pixels);
#endif
@@ -1286,6 +1286,11 @@ static int D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Tex
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result);
}
+ if (stagingTextureDesc.Format == DXGI_FORMAT_NV12) {
+ /* Copy the UV plane as well */
+ h += (h + 1) / 2;
+ }
+
src = (const Uint8 *)pixels;
dst = textureMemory.pData;
length = w * bpp;
@@ -1355,15 +1360,6 @@ static int D3D11_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
return -1;
}
}
-
- if (textureData->nv12) {
- /* Skip to the correct offset into the next texture */
- srcPixels = (const void *)((const Uint8 *)srcPixels + rect->h * srcPitch);
-
- if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureNV, 2, rect->x / 2, rect->y / 2, ((rect->w + 1) / 2), (rect->h + 1) / 2, srcPixels, 2 * ((srcPitch + 1) / 2)) < 0) {
- return -1;
- }
- }
#endif /* SDL_HAVE_YUV */
return 0;
}
@@ -1401,18 +1397,110 @@ static int D3D11_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
{
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata;
+ ID3D11Texture2D *stagingTexture;
+ const Uint8 *src;
+ Uint8 *dst;
+ int w, h, row;
+ UINT length;
+ HRESULT result;
+ D3D11_TEXTURE2D_DESC stagingTextureDesc;
+ D3D11_MAPPED_SUBRESOURCE textureMemory;
if (textureData == NULL) {
return SDL_SetError("Texture is not currently available");
}
- if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
- return -1;
+ w = rect->w;
+ h = rect->h;
+
+ /* Create a 'staging' texture, which will be used to write to a portion of the main texture. */
+ ID3D11Texture2D_GetDesc(textureData->mainTexture, &stagingTextureDesc);
+ stagingTextureDesc.Width = w;
+ stagingTextureDesc.Height = h;
+ stagingTextureDesc.BindFlags = 0;
+ stagingTextureDesc.MiscFlags = 0;
+ stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
+ result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
+ &stagingTextureDesc,
+ NULL,
+ &stagingTexture);
+ if (FAILED(result)) {
+ return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result);
}
- if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureNV, 2, rect->x / 2, rect->y / 2, ((rect->w + 1) / 2), (rect->h + 1) / 2, UVplane, UVpitch) < 0) {
- return -1;
+ /* Get a write-only pointer to data in the staging texture: */
+ result = ID3D11DeviceContext_Map(rendererData->d3dContext,
+ (ID3D11Resource *)stagingTexture,
+ 0,
+ D3D11_MAP_WRITE,
+ 0,
+ &textureMemory);
+ if (FAILED(result)) {
+ SAFE_RELEASE(stagingTexture);
+ return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result);
+ }
+
+ src = Yplane;
+ dst = textureMemory.pData;
+ length = w;
+ if (length == (UINT)Ypitch && length == textureMemory.RowPitch) {
+ SDL_memcpy(dst, src, (size_t)length * rect->h);
+ dst += length * rect->h;
+ } else {
+ if (length > (UINT)Ypitch) {
+ length = Ypitch;
+ }
+ if (length > textureMemory.RowPitch) {
+ length = textureMemory.RowPitch;
+ }
+ for (row = 0; row < h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += Ypitch;
+ dst += textureMemory.RowPitch;
+ }
+ }
+
+ /* 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);
+ } 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;
+ }
}
+
+ /* Commit the pixel buffer's changes back to the staging texture: */
+ ID3D11DeviceContext_Unmap(rendererData->d3dContext,
+ (ID3D11Resource *)stagingTexture,
+ 0);
+
+ /* Copy the staging texture's contents back to the texture: */
+ ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext,
+ (ID3D11Resource *)textureData->mainTexture,
+ 0,
+ rect->x,
+ rect->y,
+ 0,
+ (ID3D11Resource *)stagingTexture,
+ 0,
+ NULL);
+
+ SAFE_RELEASE(stagingTexture);
+
return 0;
}
#endif
@@ -1548,6 +1636,26 @@ static void D3D11_SetTextureScaleMode(SDL_Renderer *renderer, SDL_Texture *textu
textureData->scaleMode = (scaleMode == SDL_SCALEMODE_NEAREST) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
}
+static IDXGIResource *D3D11_GetTextureDXGIResource(SDL_Texture *texture)
+{
+ D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata;
+ IDXGIResource *resource = NULL;
+ HRESULT result;
+
+ if (textureData == NULL || textureData->mainTexture == NULL) {
+ SDL_SetError("Texture is not currently available");
+ return NULL;
+ }
+
+
+ result = ID3D11Texture2D_QueryInterface(textureData->mainTexture, &SDL_IID_IDXGIResource, (void **)&resource);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("GetTextureDXGIResource"), result);
+ return NULL;
+ }
+ return resource;
+}
+
static int D3D11_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
{
D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
@@ -2324,6 +2432,7 @@ SDL_Renderer *D3D11_CreateRenderer(SDL_Window *window, Uint32 flags)
renderer->LockTexture = D3D11_LockTexture;
renderer->UnlockTexture = D3D11_UnlockTexture;
renderer->SetTextureScaleMode = D3D11_SetTextureScaleMode;
+ renderer->GetTextureDXGIResource = D3D11_GetTextureDXGIResource;
renderer->SetRenderTarget = D3D11_SetRenderTarget;
renderer->QueueSetViewport = D3D11_QueueSetViewport;
renderer->QueueSetDrawColor = D3D11_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c
index 43ce78b4c2e0..161bc700bd21 100644
--- a/src/render/direct3d12/SDL_render_d3d12.c
+++ b/src/render/direct3d12/SDL_render_d3d12.c
@@ -123,9 +123,7 @@ typedef struct
/* NV12 texture support */
SDL_bool nv12;
- ID3D12Resource *mainTextureNV;
D3D12_CPU_DESCRIPTOR_HANDLE mainTextureResourceViewNV;
- D3D12_RESOURCE_STATES mainResourceStateNV;
SIZE_T mainSRVIndexNV;
Uint8 *pixels;
@@ -257,6 +255,7 @@ static const GUID SDL_IID_ID3D12DescriptorHeap = { 0x8efb471d, 0x616c, 0x4f49, {
static const GUID SDL_IID_ID3D12CommandAllocator = { 0x6102dee4, 0xaf59, 0x4b09, { 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24 } };
static const GUID SDL_IID_ID3D12GraphicsCommandList2 = { 0x38C3E585, 0xFF17, 0x412C, { 0x91, 0x50, 0x4F, 0xC6, 0xF9, 0xD7, 0x2A, 0x28 } };
static const GUID SDL_IID_ID3D12Fence = { 0x0a753dcf, 0xc4d8, 0x4b91, { 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76 } };
+static const GUID SDL_IID_IDXGIResource = { 0x035f3ab4, 0x482e, 0x4e50, { 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96, 0x0b } };
static const GUID SDL_IID_ID3D12Resource = { 0x696442be, 0xa72e, 0x4059, { 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad } };
static const GUID SDL_IID_ID3D12RootSignature = { 0xc54a6b66, 0x72df, 0x4ee8, { 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14 } };
static const GUID SDL_IID_ID3D12PipelineState = { 0x765a30f3, 0xf624, 0x4c6f, { 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45 } };
@@ -284,7 +283,25 @@ Uint32 D3D12_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
}
}
-static DXGI_FORMAT SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
+static DXGI_FORMAT SDLPixelFormatToDXGITextureFormat(Uint32 sdlFormat)
+{
+ switch (sdlFormat) {
+ case SDL_PIXELFORMAT_ARGB8888:
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case SDL_PIXELFORMAT_XRGB8888:
+ return DXGI_FORMAT_B8G8R8X8_UNORM;
+ case SDL_PIXELFORMAT_YV12:
+ case SDL_PIXELFORMAT_IYUV:
+ return DXGI_FORMAT_R8_UNORM;
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ return DXGI_FORMAT_NV12;
+ default:
+ return DXGI_FORMAT_UNKNOWN;
+ }
+}
+
+static DXGI_FORMAT SDLPixelFormatToDXGIMainResourceViewFormat(Uint32 sdlFormat)
{
switch (sdlFormat) {
case SDL_PIXELFORMAT_ARGB8888:
@@ -703,7 +720,7 @@ static HRESULT D3D12_CreateDeviceResources(SDL_Renderer *renderer)
HRESULT result = S_OK;
UINT creationFlags = 0;
int i, j, k, l;
- SDL_bool createDebug = SDL_FALSE;
+ SDL_bool createDebug;
D3D12_COMMAND_QUEUE_DESC queueDesc;
D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc;
@@ -1417,7 +1434,7 @@ static int D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
D3D12_RenderData *rendererData = (D3D12_RenderData *)renderer->driverdata;
D3D12_TextureData *textureData;
HRESULT result;
- DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format);
+ DXGI_FORMAT textureFormat = SDLPixelFormatToDXGITextureFormat(texture->format);
D3D12_RESOURCE_DESC textureDesc;
D3D12_HEAP_PROPERTIES heapProps;
D3D12_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
@@ -1508,34 +1525,13 @@ static int D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21) {
- D3D12_RESOURCE_DESC nvTextureDesc = textureDesc;
-
textureData->nv12 = SDL_TRUE;
-
- nvTextureDesc.Format = DXGI_FORMAT_R8G8_UNORM;
- nvTextureDesc.Width = (textureDesc.Width + 1) / 2;
- nvTextureDesc.Height = (textureDesc.Height + 1) / 2;
-
- result = D3D_CALL(rendererData->d3dDevice, CreateCommittedResource,
- &heapProps,
- D3D12_HEAP_FLAG_NONE,
- &nvTextureDesc,
- D3D12_RESOURCE_STATE_COPY_DEST,
- NULL,
- D3D_GUID(SDL_IID_ID3D12Resource),
- (void **)&textureData->mainTextureNV);
- textureData->mainResourceStateNV = D3D12_RESOURCE_STATE_COPY_DEST;
- if (FAILED(result)) {
- D3D12_DestroyTexture(renderer, texture);
- return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D12Device::CreateTexture2D"), result);
- }
}
#endif /* SDL_HAVE_YUV */
SDL_zero(resourceViewDesc);
resourceViewDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
- resourceViewDesc.Format = textureDesc.Format;
+ resourceViewDesc.Format = SDLPixelFormatToDXGIMainResourceViewFormat(texture->format);
resourceViewDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
- resourceViewDesc.Texture2D.MostDetailedMip = 0;
resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
textureData->mainSRVIndex = D3D12_GetAvailableSRVIndex(renderer);
@@ -1569,12 +1565,13 @@ static int D3D12_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
D3D12_SHADER_RESOURCE_VIEW_DESC nvResourceViewDesc = resourceViewDesc;
nvResourceViewDesc.Format = DXGI_FORMAT_R8G8_UNORM;
+ nvResourceViewDesc.Texture2D.PlaneSlice = 1;
D3D_CALL_RET(rendererData->srvDescriptorHeap, GetCPUDescriptorHandleForHeapStart, &textureData->mainTextureResourceViewNV);
textureData->mainSRVIndexNV = D3D12_GetAvailableSRVIndex(renderer);
textureData->mainTextureResourceViewNV.ptr += textureData->mainSRVIndexNV * rendererData->srvDescriptorSize;
D3D_CALL(rendererData->d3dDevice, CreateShaderResourceView,
- textureData->mainTextureNV,
+ textureData->mainTexture,
&nvResourceViewDesc,
textureData->mainTextureResourceViewNV);
}
@@ -1623,8 +1620,7 @@ static void D3D12_DestroyTexture(SDL_Renderer *renderer,
D3D12_FreeSRVIndex(renderer, textureData->mainSRVIndexU);
D3D12_FreeSRVIndex(renderer, textureData->mainSRVIndexV);
}
- SAFE_RELEASE(textureData->mainTextureNV);
- if (textureData->yuv) {
+ if (textureData->nv12) {
D3D12_FreeSRVIndex(renderer, textureData->mainSRVIndexNV);
}
SDL_free(textureData->pixels);
@@ -1633,22 +1629,22 @@ static void D3D12_DestroyTexture(SDL_Renderer *renderer,
texture->driverdata = NULL;
}
-static int D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Resource *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch, D3D12_RESOURCE_STATES *resourceState)
+static int D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Resource *texture, int plane, int x, int y, int w, int h, const void *pixels, int pitch, D3D12_RESOURCE_STATES *resourceState)
{
const Uint8 *src;
Uint8 *dst;
- int row;
UINT length;
HRESULT result;
D3D12_RESOURCE_DESC textureDesc;
D3D12_RESOURCE_DESC uploadDesc;
D3D12_HEAP_PROPERTIES heapProps;
- D3D12_SUBRESOURCE_FOOTPRINT pitchedDesc;
D3D12_PLACED_SUBRESOURCE_FOOTPRINT placedTextureDesc;
D3D12_TEXTURE_COPY_LOCATION srcLocation;
D3D12_TEXTURE_COPY_LOCATION dstLocation;
BYTE *textureMemory;
ID3D12Resource *uploadBuffer;
+ UINT row, NumRows, RowPitch;
+ UINT64 RowLength;
/* Create an upload buffer, which will be used to write to the main texture. */
SDL_zero(textureDesc);
@@ -1671,13 +1667,14 @@ static int D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Res
/* Figure out how much we need to allocate for the upload buffer */
D3D_CALL(rendererData->d3dDevice, GetCopyableFootprints,
&textureDesc,
- 0,
+ plane,
1,
0,
- NULL,
- NULL,
- NULL,
+ &placedTextureDesc,
+ &NumRows,
+ &RowLength,
&uploadDesc.Width);
+ RowPitch = placedTextureDesc.Footprint.RowPitch;
SDL_zero(heapProps);
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
@@ -1708,33 +1705,22 @@ static int D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Res
return WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D12Resource::Map [map staging texture]"), result);
}
- SDL_zero(pitchedDesc);
- pitchedDesc.Format = textureDesc.Format;
- pitchedDesc.Width = w;
- pitchedDesc.Height = h;
- pitchedDesc.Depth = 1;
- pitchedDesc.RowPitch = D3D12_Align(w * bpp, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
-
- SDL_zero(placedTextureDesc);
- placedTextureDesc.Offset = 0;
- placedTextureDesc.Footprint = pitchedDesc;
-
src = (const Uint8 *)pixels;
dst = textureMemory;
- length = w * bpp;
- if (length == (UINT)pitch && length == pitchedDesc.RowPitch) {
- SDL_memcpy(dst, src, (size_t)length * h);
+ length = RowLength;
+ if (length == (UINT)pitch && length == RowPitch) {
+ SDL_memcpy(dst, src, (size_t)length * NumRows);
} else {
if (length > (UINT)pitch) {
length = pitch;
}
- if (length > pitchedDesc.RowPitch) {
- length = pitchedDesc.RowPitch;
+ if (length > RowPitch) {
+ length = RowPitch;
}
- for (row = 0; row < h; ++row) {
+ for (row = NumRows; row--; ) {
SDL_memcpy(dst, src, length);
src += pitch;
- dst += pitchedDesc.RowPitch;
+ dst += RowPitch;
}
}
@@ -1748,7 +1734,7 @@ static int D3D12_UpdateTextureInternal(D3D12_RenderData *rendererData, ID3D12Res
SDL_zero(dstLocation);
dstLocation.pResource = texture;
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
- dstLocation.SubresourceIndex = 0;
+ dstLocation.SubresourceIndex = plane;
SDL_zero(srcLocation);
srcLocation.pResource = rendererData->uploadBuffers[rendererData->currentUploadBuffer];
@@ -1787,7 +1773,7 @@ static int D3D12_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
return SDL_SetError("Texture is not currently available");
}
- if (D3D12_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch, &textureData->mainResourceState) < 0) {
+ if (D3D12_UpdateTextureInternal(rendererData, textureData->mainTexture, 0, rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch, &textureData->mainResourceState) < 0) {
return -1;
}
#if SDL_HAVE_YUV
@@ -1795,13 +1781,13 @@ static int D3D12_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
/* Skip to the correct offset into the next texture */
srcPixels = (const void *)((const Uint8 *)srcPixels + rect->h * srcPitch);
- if (D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureV : textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateV : &textureData->mainResourceStateU) < 0) {
+ if (D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureV : textureData->mainTextureU, 0, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateV : &textureData->mainResourceStateU) < 0) {
return -1;
}
/* Skip to the correct offset into the next texture */
srcPixels = (const void *)((const Uint8 *)srcPixels + ((rect->h + 1) / 2) * ((srcPitch + 1) / 2));
- if (D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureU : textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateU : &textureData->mainResourceStateV) < 0) {
+ if (D3D12_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureU : textureData->mainTextureV, 0, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2, texture->format == SDL_PIXELFORMAT_YV12 ? &textureData->mainResourceStateU : &textureData->mainResourceStateV) < 0) {
return -1;
}
}
@@ -1810,7 +1796,7 @@ static int D3D12_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
/* Skip to the correct offset into the next texture */
srcPixels = (const void *)((const Uint8 *)srcPixels + rect->h * srcPitch);
- if (D3D12_UpdateTextureInternal(rendererData, textureData->mainTextureNV, 2, rect->x / 2, rect->y / 2, ((rect->w + 1) / 2), (rect->h + 1) / 2, srcPixels, 2 * ((srcPitch + 1) / 2), &textureData->mainResourceStateNV) < 0) {
+ if (D3D12_UpdateTextureInternal(rendererData, textureData->mainTexture, 1, rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch, &textureData->mainResourceState) < 0) {
return -1;
}
}
@@ -1832,13 +1818,13 @@ static int D3D12_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
return SDL_SetError("Texture is no
(Patch may be truncated, please check the link at the top of this post.)