From 4082821822edd2cdffdeb130718821c5503140ea Mon Sep 17 00:00:00 2001
From: chalonverse <[EMAIL REDACTED]>
Date: Mon, 6 Jun 2022 17:42:30 -0700
Subject: [PATCH] DirectX 12 Renderer (#5761)
* DirectX 12 Renderer (27 squashed commits)
* Add missing SDL_hidapi.h of merge of SDL.vcxproj.filters
* Fixed OpenWatcom build failure
* Dynapi fix
Co-authored-by: Ryan C. Gordon <icculus@icculus.org>
---
CMakeLists.txt | 7 +-
Makefile.w32 | 3 +-
VisualC/SDL/SDL.vcxproj | 5 +-
VisualC/SDL/SDL.vcxproj.filters | 14 +-
configure.ac | 5 +
include/SDL_config.h.cmake | 1 +
include/SDL_config.h.in | 1 +
include/SDL_config_windows.h | 18 +
include/SDL_config_winrt.h | 3 +
include/SDL_hints.h | 2 +
include/SDL_system.h | 16 +
src/core/windows/SDL_windows.h | 4 +
src/dynapi/SDL2.exports | 1 +
src/dynapi/SDL_dynapi_overrides.h | 1 +
src/dynapi/SDL_dynapi_procs.h | 3 +
src/render/SDL_d3dmath.c | 4 +-
src/render/SDL_d3dmath.h | 4 +-
src/render/SDL_render.c | 3 +
src/render/SDL_sysrender.h | 1 +
src/render/direct3d12/SDL_render_d3d12.c | 3042 +++++++++
src/render/direct3d12/SDL_shaders_d3d12.c | 6967 +++++++++++++++++++++
src/render/direct3d12/SDL_shaders_d3d12.h | 57 +
22 files changed, 10154 insertions(+), 8 deletions(-)
create mode 100644 src/render/direct3d12/SDL_render_d3d12.c
create mode 100644 src/render/direct3d12/SDL_shaders_d3d12.c
create mode 100644 src/render/direct3d12/SDL_shaders_d3d12.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18cf7302b55..f5e0e344e98 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1596,6 +1596,7 @@ elseif(WINDOWS)
check_include_file(d3d9.h HAVE_D3D_H)
check_include_file(d3d11_1.h HAVE_D3D11_H)
+ check_include_file(d3d12.h HAVE_D3D12_H)
check_include_file(ddraw.h HAVE_DDRAW_H)
check_include_file(dsound.h HAVE_DSOUND_H)
check_include_file(dinput.h HAVE_DINPUT_H)
@@ -1603,7 +1604,7 @@ elseif(WINDOWS)
set(HAVE_DINPUT_H 0)
endif()
check_include_file(dxgi.h HAVE_DXGI_H)
- if(HAVE_D3D_H OR HAVE_D3D11_H OR HAVE_DDRAW_H OR HAVE_DSOUND_H OR HAVE_DINPUT_H)
+ if(HAVE_D3D_H OR HAVE_D3D11_H OR HAVE_D3D12_H OR HAVE_DDRAW_H OR HAVE_DSOUND_H OR HAVE_DINPUT_H)
set(HAVE_DIRECTX TRUE)
if(NOT MINGW AND NOT USE_WINSDK_DIRECTX)
# TODO: change $ENV{DXSDL_DIR} to get the path from the include checks
@@ -1697,6 +1698,10 @@ elseif(WINDOWS)
set(SDL_VIDEO_RENDER_D3D11 1)
set(HAVE_RENDER_D3D TRUE)
endif()
+ if(SDL_RENDER_D3D AND HAVE_D3D12_H AND NOT WINDOWS_STORE)
+ set(SDL_VIDEO_RENDER_D3D12 1)
+ set(HAVE_RENDER_D3D TRUE)
+ endif()
set(HAVE_SDL_VIDEO TRUE)
endif()
diff --git a/Makefile.w32 b/Makefile.w32
index 60775f13fef..ee5c4b10ff7 100644
--- a/Makefile.w32
+++ b/Makefile.w32
@@ -80,6 +80,7 @@ SRCS+= SDL_syspower.c
SRCS+= SDL_d3dmath.c
SRCS+= SDL_render_d3d.c SDL_shaders_d3d.c
SRCS+= SDL_render_d3d11.c SDL_shaders_d3d11.c
+SRCS+= SDL_render_d3d12.c SDL_shaders_d3d12.c
SRCS+= SDL_render_gl.c SDL_shaders_gl.c
SRCS+= SDL_render_gles2.c SDL_shaders_gles2.c
SRCS+= SDL_windowssensor.c
@@ -99,7 +100,7 @@ RCOBJS= $(RCSRCS:.rc=.res)
.c: ./src;./src/dynapi;./src/audio;./src/cpuinfo;./src/events;./src/file;./src/haptic;./src/joystick;./src/power;./src/render;./src/render/software;./src/sensor;./src/stdlib;./src/thread;./src/timer;./src/video;./src/video/yuv2rgb;./src/atomic;./src/audio/disk;
.c: ./src/haptic/dummy;./src/joystick/dummy;./src/joystick/virtual;./src/audio/dummy;./src/video/dummy;./src/sensor/dummy;
.c: ./src/core/windows;./src/audio/winmm;./src/audio/directsound;./src/audio/wasapi;./src/loadso/windows;./src/filesystem/windows;./src/haptic/windows;./src/joystick/windows;./src/sensor/windows;./src/thread/windows;./src/timer/windows;./src/video/windows;
-.c: ./src/locale/;./src/locale/windows;./src/misc;./src/misc/windows;./src/power/windows;./src/joystick/hidapi;./src/hidapi;./src/render/direct3d;./src/render/direct3d11;./src/render/opengl;./src/render/opengles2
+.c: ./src/locale/;./src/locale/windows;./src/misc;./src/misc/windows;./src/power/windows;./src/joystick/hidapi;./src/hidapi;./src/render/direct3d;./src/render/direct3d11;./src/render/direct3d12;./src/render/opengl;./src/render/opengles2
.rc: ./src/main/windows
all: $(DLLFILE) $(LIBFILE) $(TLIB) .symbolic
diff --git a/VisualC/SDL/SDL.vcxproj b/VisualC/SDL/SDL.vcxproj
index aaeda871783..04ed6b46f1e 100644
--- a/VisualC/SDL/SDL.vcxproj
+++ b/VisualC/SDL/SDL.vcxproj
@@ -348,6 +348,7 @@
<ClInclude Include="..\..\src\misc\SDL_sysurl.h" />
<ClInclude Include="..\..\src\power\SDL_syspower.h" />
<ClInclude Include="..\..\src\render\direct3d11\SDL_shaders_d3d11.h" />
+ <ClInclude Include="..\..\src\render\direct3d12\SDL_shaders_d3d12.h" />
<ClInclude Include="..\..\src\render\direct3d\SDL_shaders_d3d.h" />
<ClInclude Include="..\..\src\render\opengles2\SDL_gles2funcs.h" />
<ClInclude Include="..\..\src\render\opengles2\SDL_shaders_gles2.h" />
@@ -527,6 +528,8 @@
<ClCompile Include="..\..\src\power\SDL_power.c" />
<ClCompile Include="..\..\src\power\windows\SDL_syspower.c" />
<ClCompile Include="..\..\src\render\direct3d11\SDL_shaders_d3d11.c" />
+ <ClCompile Include="..\..\src\render\direct3d12\SDL_render_d3d12.c" />
+ <ClCompile Include="..\..\src\render\direct3d12\SDL_shaders_d3d12.c" />
<ClCompile Include="..\..\src\render\direct3d\SDL_render_d3d.c" />
<ClCompile Include="..\..\src\render\direct3d11\SDL_render_d3d11.c" />
<ClCompile Include="..\..\src\render\direct3d\SDL_shaders_d3d.c" />
@@ -617,4 +620,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/VisualC/SDL/SDL.vcxproj.filters b/VisualC/SDL/SDL.vcxproj.filters
index a3d9d5c8090..a093f4dd672 100644
--- a/VisualC/SDL/SDL.vcxproj.filters
+++ b/VisualC/SDL/SDL.vcxproj.filters
@@ -169,6 +169,9 @@
<Filter Include="video\khronos\vulkan">
<UniqueIdentifier>{4755f3a6-49ac-46d6-86be-21f5c21f2197}</UniqueIdentifier>
</Filter>
+ <Filter Include="render\direct3d12">
+ <UniqueIdentifier>{f48c2b17-1bee-4fec-a7c8-24cf619abe08}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\begin_code.h">
@@ -829,6 +832,9 @@
<ClInclude Include="..\..\src\SDL_hints_c.h" />
<ClInclude Include="..\..\src\SDL_internal.h" />
<ClInclude Include="..\..\src\SDL_log_c.h" />
+ <ClInclude Include="..\..\src\render\direct3d12\SDL_shaders_d3d12.h">
+ <Filter>render\direct3d12</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
@@ -1326,8 +1332,14 @@
<ClCompile Include="..\..\src\power\windows\SDL_syspower.c">
<Filter>power\windows</Filter>
</ClCompile>
+ <ClCompile Include="..\..\src\render\direct3d12\SDL_render_d3d12.c">
+ <Filter>render\direct3d12</Filter>
+ </ClCompile>
+ <ClCompile Include="..\..\src\render\direct3d12\SDL_shaders_d3d12.c">
+ <Filter>render\direct3d12</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\main\windows\version.rc" />
</ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/configure.ac b/configure.ac
index 421ea98ce91..dc5c4c718b5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3264,6 +3264,7 @@ CheckDIRECTX()
if test x$enable_directx = xyes; then
AC_CHECK_HEADER(d3d9.h, have_d3d=yes)
AC_CHECK_HEADER(d3d11_1.h, have_d3d11=yes)
+ AC_CHECK_HEADER(d3d12.h, have_d3d12=yes)
AC_CHECK_HEADER(ddraw.h, have_ddraw=yes)
AC_CHECK_HEADER(dsound.h, have_dsound=yes)
AC_CHECK_HEADER(dinput.h, have_dinput=yes)
@@ -3991,6 +3992,10 @@ case "$host" in
AC_DEFINE(SDL_VIDEO_RENDER_D3D11, 1, [ ])
SUMMARY_video="${SUMMARY_video} d3d11"
fi
+ if test x$enable_render_d3d = xyes -a x$have_d3d12 = xyes; then
+ AC_DEFINE(SDL_VIDEO_RENDER_D3D12, 1, [ ])
+ SUMMARY_video="${SUMMARY_video} d3d12"
+ fi
fi
# Set up files for the audio library
if test x$enable_audio = xyes; then
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 9e058218d65..b6b58399296 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -243,6 +243,7 @@
#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
#cmakedefine HAVE_D3D11_H @HAVE_D3D11_H@
+#cmakedefine HAVE_D3D12_H @HAVE_D3D12_H@
#cmakedefine HAVE_DDRAW_H @HAVE_DDRAW_H@
#cmakedefine HAVE_DSOUND_H @HAVE_DSOUND_H@
#cmakedefine HAVE_DINPUT_H @HAVE_DINPUT_H@
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index 9a80d45b7c0..c18077feac3 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -413,6 +413,7 @@
#undef SDL_VIDEO_RENDER_D3D
#undef SDL_VIDEO_RENDER_D3D11
+#undef SDL_VIDEO_RENDER_D3D12
#undef SDL_VIDEO_RENDER_OGL
#undef SDL_VIDEO_RENDER_OGL_ES
#undef SDL_VIDEO_RENDER_OGL_ES2
diff --git a/include/SDL_config_windows.h b/include/SDL_config_windows.h
index 81fde40c869..076bea4103c 100644
--- a/include/SDL_config_windows.h
+++ b/include/SDL_config_windows.h
@@ -38,6 +38,18 @@
#include <winsdkver.h>
#endif
+/* sdkddkver.h defines more specific SDK version numbers. This is needed because older versions of the
+ * Windows 10 SDK have broken declarations for the C API for DirectX 12. */
+#if !defined(HAVE_SDKDDKVER_H) && defined(__has_include)
+#if __has_include(<sdkddkver.h>)
+#define HAVE_SDKDDKVER_H 1
+#endif
+#endif
+
+#ifdef HAVE_SDKDDKVER_H
+#include <sdkddkver.h>
+#endif
+
/* This is a set of defines to configure the SDL features */
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
@@ -107,6 +119,9 @@ typedef unsigned int uintptr_t;
#define HAVE_D3D11_H 1
#define HAVE_ROAPI_H 1
#endif
+#if defined(WDK_NTDDI_VERSION) && WDK_NTDDI_VERSION > 0x0A000008 /* 10.0.19041.0 */
+#define HAVE_D3D12_H 1
+#endif
#define HAVE_MMDEVICEAPI_H 1
#define HAVE_AUDIOCLIENT_H 1
#define HAVE_TPCSHRD_H 1
@@ -295,6 +310,9 @@ typedef unsigned int uintptr_t;
#if !defined(SDL_VIDEO_RENDER_D3D11) && defined(HAVE_D3D11_H)
#define SDL_VIDEO_RENDER_D3D11 1
#endif
+#if !defined(SDL_VIDEO_RENDER_D3D12) && defined(HAVE_D3D12_H)
+#define SDL_VIDEO_RENDER_D3D12 1
+#endif
/* Enable OpenGL support */
#ifndef SDL_VIDEO_OPENGL
diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h
index 75aef4ebbdf..55694036902 100644
--- a/include/SDL_config_winrt.h
+++ b/include/SDL_config_winrt.h
@@ -250,6 +250,9 @@ typedef unsigned int uintptr_t;
/* Enable appropriate renderer(s) */
#define SDL_VIDEO_RENDER_D3D11 1
+/* Disable D3D12 as it's not implemented for WinRT */
+#define SDL_VIDEO_RENDER_D3D12 0
+
#if SDL_VIDEO_OPENGL_ES2
#define SDL_VIDEO_RENDER_OGL_ES2 1
#endif
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index 83cfe89a69a..2699b6ae911 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -1200,6 +1200,8 @@ extern "C" {
*
* This variable is case insensitive and can be set to the following values:
* "direct3d"
+ * "direct3d11"
+ * "direct3d12"
* "opengl"
* "opengles2"
* "opengles"
diff --git a/include/SDL_system.h b/include/SDL_system.h
index bbe8d45586d..60871ff9005 100644
--- a/include/SDL_system.h
+++ b/include/SDL_system.h
@@ -102,6 +102,22 @@ typedef struct ID3D11Device ID3D11Device;
*/
extern DECLSPEC ID3D11Device* SDLCALL SDL_RenderGetD3D11Device(SDL_Renderer * renderer);
+typedef struct ID3D12Device ID3D12Device;
+
+/**
+ * Get the D3D12 device associated with a renderer.
+ *
+ * Once you are done using the device, you should release it to avoid a
+ * resource leak.
+ *
+ * \param renderer the renderer from which to get the associated D3D12 device
+ * \returns the D3D12 device associated with given renderer or NULL if it is
+ * not a D3D12 renderer; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 2.0.23.
+ */
+extern DECLSPEC ID3D12Device* SDLCALL SDL_RenderGetD3D12Device(SDL_Renderer* renderer);
+
/**
* Get the DXGI Adapter and Output indices for the specified display index.
*
diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h
index 681f01b8744..9b014925318 100644
--- a/src/core/windows/SDL_windows.h
+++ b/src/core/windows/SDL_windows.h
@@ -33,7 +33,11 @@
#undef WINVER
#define WINVER 0x0501
#undef _WIN32_WINNT
+#if !defined(SDL_VIDEO_RENDER_D3D12)
#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
+#else
+#define _WIN32_WINNT 0xA00 /* For D3D12, 0xA00 is required */
+#endif
#endif
#include <windows.h>
diff --git a/src/dynapi/SDL2.exports b/src/dynapi/SDL2.exports
index 481e1db0b2f..5bc965dfd25 100644
--- a/src/dynapi/SDL2.exports
+++ b/src/dynapi/SDL2.exports
@@ -847,3 +847,4 @@
++'_SDL_GUIDFromString'.'SDL2.dll'.'SDL_GUIDFromString'
++'_SDL_HasLSX'.'SDL2.dll'.'SDL_HasLSX'
++'_SDL_HasLASX'.'SDL2.dll'.'SDL_HasLASX'
+++'_SDL_RenderGetD3D12Device'.'SDL2.dll'.'SDL_RenderGetD3D12Device'
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 97f3b800767..76c9e91998c 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -873,3 +873,4 @@
#define SDL_GUIDFromString SDL_GUIDFromString_REAL
#define SDL_HasLSX SDL_HasLSX_REAL
#define SDL_HasLASX SDL_HasLASX_REAL
+#define SDL_RenderGetD3D12Device SDL_RenderGetD3D12Device_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index a61333a3956..ddc655760bc 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -948,3 +948,6 @@ SDL_DYNAPI_PROC(void,SDL_GUIDToString,(SDL_GUID a, char *b, int c),(a,b,c),)
SDL_DYNAPI_PROC(SDL_GUID,SDL_GUIDFromString,(const char *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasLSX,(void),(),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_HasLASX,(void),(),return)
+#ifdef __WIN32__
+SDL_DYNAPI_PROC(ID3D12Device*,SDL_RenderGetD3D12Device,(SDL_Renderer *a),(a),return)
+#endif
diff --git a/src/render/SDL_d3dmath.c b/src/render/SDL_d3dmath.c
index 63048bb88ca..fb7de371fa6 100644
--- a/src/render/SDL_d3dmath.c
+++ b/src/render/SDL_d3dmath.c
@@ -20,7 +20,7 @@
*/
#include "../SDL_internal.h"
-#if (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11) && !SDL_RENDER_DISABLED
+#if (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11 || SDL_VIDEO_RENDER_D3D12) && !SDL_RENDER_DISABLED
#include "SDL_stdinc.h"
#include "SDL_d3dmath.h"
@@ -131,6 +131,6 @@ Float4X4 MatrixRotationZ(float r)
}
-#endif /* (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11) && !SDL_RENDER_DISABLED */
+#endif /* (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11 || SDL_VIDEO_RENDER_D3D12) && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/SDL_d3dmath.h b/src/render/SDL_d3dmath.h
index 7b74cfe7573..211bfdd5a67 100644
--- a/src/render/SDL_d3dmath.h
+++ b/src/render/SDL_d3dmath.h
@@ -20,7 +20,7 @@
*/
#include "../SDL_internal.h"
-#if (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11) && !SDL_RENDER_DISABLED
+#if (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11 || SDL_VIDEO_RENDER_D3D12) && !SDL_RENDER_DISABLED
/* Direct3D matrix math functions */
@@ -67,6 +67,6 @@ Float4X4 MatrixRotationX(float r);
Float4X4 MatrixRotationY(float r);
Float4X4 MatrixRotationZ(float r);
-#endif /* (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11) && !SDL_RENDER_DISABLED */
+#endif /* (SDL_VIDEO_RENDER_D3D || SDL_VIDEO_RENDER_D3D11 || SDL_VIDEO_RENDER_D3D12) && !SDL_RENDER_DISABLED */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index d94b0a988b0..4224a70f6f6 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -96,6 +96,9 @@ static const SDL_RenderDriver *render_drivers[] = {
#if SDL_VIDEO_RENDER_D3D11
&D3D11_RenderDriver,
#endif
+#if SDL_VIDEO_RENDER_D3D12
+ &D3D12_RenderDriver,
+#endif
#if SDL_VIDEO_RENDER_METAL
&METAL_RenderDriver,
#endif
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index 7aeb46710bc..481ae91bfc5 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -283,6 +283,7 @@ struct SDL_RenderDriver
/* Not all of these are available in a given build. Use #ifdefs, etc. */
extern SDL_RenderDriver D3D_RenderDriver;
extern SDL_RenderDriver D3D11_RenderDriver;
+extern SDL_RenderDriver D3D12_RenderDriver;
extern SDL_RenderDriver GL_RenderDriver;
extern SDL_RenderDriver GLES2_RenderDriver;
extern SDL_RenderDriver GLES_RenderDriver;
diff --git a/src/render/direct3d12/SDL_render_d3d12.c b/src/render/direct3d12/SDL_render_d3d12.c
new file mode 100644
index 00000000000..447e6a07b54
--- /dev/null
+++ b/src/render/direct3d12/SDL_render_d3d12.c
@@ -0,0 +1,3042 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#include "SDL_render.h"
+#include "SDL_system.h"
+
+#if SDL_VIDEO_RENDER_D3D12 && !SDL_RENDER_DISABLED
+
+#define SDL_D3D12_NUM_BUFFERS 2
+#define SDL_D3D12_NUM_VERTEX_BUFFERS 256
+#define SDL_D3D12_VERTEX_BUFFER_MAX_TRIS 2048
+#define SDL_D3D12_MAX_NUM_TEXTURES 16384
+#define SDL_D3D12_NUM_UPLOAD_BUFFERS 32
+
+#define COBJMACROS
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_hints.h"
+#include "SDL_loadso.h"
+#include "SDL_syswm.h"
+#include "../SDL_sysrender.h"
+#include "../SDL_d3dmath.h"
+
+#include <d3d12.h>
+#include <dxgi1_6.h>
+#include <dxgidebug.h>
+#include <d3d12sdklayers.h>
+
+#include "SDL_shaders_d3d12.h"
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#define SDL_COMPOSE_ERROR(str) __FUNCTION__ ", " str
+#else
+#define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str
+#endif
+
+#define SAFE_RELEASE(X) if ((X)) { IUnknown_Release(SDL_static_cast(IUnknown*, X)); X = NULL; }
+
+
+/* !!! FIXME: vertex buffer bandwidth could be lower; only use UV coords when
+ !!! FIXME: textures are needed. */
+
+/* Vertex shader, common values */
+typedef struct
+{
+ Float4X4 model;
+ Float4X4 projectionAndView;
+} VertexShaderConstants;
+
+/* Per-vertex data */
+typedef struct
+{
+ Float2 pos;
+ Float2 tex;
+ SDL_Color color;
+} VertexPositionColor;
+
+/* Per-texture data */
+typedef struct
+{
+ ID3D12Resource *mainTexture;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainTextureResourceView;
+ D3D12_RESOURCE_STATES mainResourceState;
+ SIZE_T mainSRVIndex;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainTextureRenderTargetView;
+ DXGI_FORMAT mainTextureFormat;
+ ID3D12Resource *stagingBuffer;
+ D3D12_RESOURCE_STATES stagingResourceState;
+ D3D12_FILTER scaleMode;
+#if SDL_HAVE_YUV
+ /* YV12 texture support */
+ SDL_bool yuv;
+ ID3D12Resource *mainTextureU;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainTextureResourceViewU;
+ D3D12_RESOURCE_STATES mainResourceStateU;
+ SIZE_T mainSRVIndexU;
+ ID3D12Resource *mainTextureV;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainTextureResourceViewV;
+ D3D12_RESOURCE_STATES mainResourceStateV;
+ SIZE_T mainSRVIndexV;
+
+ /* NV12 texture support */
+ SDL_bool nv12;
+ ID3D12Resource *mainTextureNV;
+ D3D12_CPU_DESCRIPTOR_HANDLE mainTextureResourceViewNV;
+ D3D12_RESOURCE_STATES mainResourceStateNV;
+ SIZE_T mainSRVIndexNV;
+
+ Uint8 *pixels;
+ int pitch;
+#endif
+ SDL_Rect lockedRect;
+} D3D12_TextureData;
+
+/* Pipeline State Object data */
+typedef struct
+{
+ D3D12_Shader shader;
+ SDL_BlendMode blendMode;
+ D3D12_PRIMITIVE_TOPOLOGY_TYPE topology;
+ DXGI_FORMAT rtvFormat;
+ ID3D12PipelineState *pipelineState;
+} D3D12_PipelineState;
+
+/* Vertex Buffer */
+typedef struct
+{
+ ID3D12Resource *resource;
+ D3D12_VERTEX_BUFFER_VIEW view;
+} D3D12_VertexBuffer;
+
+/* For SRV pool allocator */
+typedef struct
+{
+ SIZE_T index;
+ void *next;
+} D3D12_SRVPoolNode;
+
+/* Private renderer data */
+typedef struct
+{
+ void *hDXGIMod;
+ void *hD3D12Mod;
+ IDXGIFactory6 *dxgiFactory;
+ IDXGIAdapter4 *dxgiAdapter;
+ ID3D12Device5 *d3dDevice;
+ ID3D12Debug *debugInterface;
+ IDXGIDebug1 *dxgiDebug;
+ ID3D12CommandQueue *commandQueue;
+ ID3D12GraphicsCommandList2 *commandList;
+ IDXGISwapChain4 *swapChain;
+ DXGI_SWAP_EFFECT swapEffect;
+
+ /* Descriptor heaps */
+ ID3D12DescriptorHeap* rtvDescriptorHeap;
+ UINT rtvDescriptorSize;
+ ID3D12DescriptorHeap* textureRTVDescriptorHeap;
+ ID3D12DescriptorHeap* srvDescriptorHeap;
+ UINT srvDescriptorSize;
+ ID3D12DescriptorHeap* samplerDescriptorHeap;
+ UINT samplerDescriptorSize;
+
+ /* Data needed per backbuffer */
+ ID3D12CommandAllocator *commandAllocators[SDL_D3D12_NUM_BUFFERS];
+ ID3D12Resource *renderTargets[SDL_D3D12_NUM_BUFFERS];
+ UINT64 fenceValue;
+ int currentBackBufferIndex;
+
+ /* Fences */
+ ID3D12Fence *fence;
+ HANDLE fenceEvent;
+
+ /* Root signature and pipeline state data */
+ ID3D12RootSignature *rootSignatures[NUM_ROOTSIGS];
+ int pipelineStateCount;
+ D3D12_PipelineState *pipelineStates;
+ D3D12_PipelineState *currentPipelineState;
+
+ D3D12_VertexBuffer vertexBuffers[SDL_D3D12_NUM_VERTEX_BUFFERS];
+ ID3D12Heap *vertexBufferHeap;
+ D3D12_CPU_DESCRIPTOR_HANDLE nearestPixelSampler;
+ D3D12_CPU_DESCRIPTOR_HANDLE linearSampler;
+
+ /* Data for staging/allocating textures */
+ ID3D12Resource *uploadBuffers[SDL_D3D12_NUM_UPLOAD_BUFFERS];
+ int currentUploadBuffer;
+
+ /* Pool allocator to handle reusing SRV heap indices */
+ D3D12_SRVPoolNode *srvPoolHead;
+ D3D12_SRVPoolNode srvPoolNodes[SDL_D3D12_MAX_NUM_TEXTURES];
+
+ /* Vertex buffer constants */
+ VertexShaderConstants vertexShaderConstantsData;
+
+ /* Cached renderer properties */
+ DXGI_MODE_ROTATION rotation;
+ D3D12_TextureData* textureRenderTarget;
+ D3D12_CPU_DESCRIPTOR_HANDLE currentRenderTargetView;
+ D3D12_CPU_DESCRIPTOR_HANDLE currentShaderResource;
+ D3D12_CPU_DESCRIPTOR_HANDLE currentSampler;
+ SDL_bool cliprectDirty;
+ SDL_bool currentCliprectEnabled;
+ SDL_Rect currentCliprect;
+ SDL_Rect currentViewport;
+ int currentViewportRotation;
+ SDL_bool viewportDirty;
+ Float4X4 identity;
+ int currentVertexBuffer;
+ SDL_bool issueBatch;
+} D3D12_RenderData;
+
+
+/* Define D3D GUIDs here so we don't have to include uuid.lib. */
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-const-variable"
+#endif
+
+static const GUID SDL_IID_IDXGIFactory6 = { 0xc1b6694f, 0xff09, 0x44a9, { 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17 } };
+static const GUID SDL_IID_IDXGIAdapter4 = { 0x3c8d99d1, 0x4fbf, 0x4181, { 0xa8, 0x2c, 0xaf, 0x66, 0xbf, 0x7b, 0xd2, 0x4e } };
+static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } };
+static const GUID SDL_IID_ID3D12Device5 = { 0x8b4f173b, 0x2fea, 0x4b80, { 0x8f, 0x58, 0x43, 0x07, 0x19, 0x1a, 0xb9, 0x5d } };
+static const GUID SDL_IID_IDXGISwapChain4 = { 0x3D585D5A, 0xBD4A, 0x489E, { 0xB1, 0xF4, 0x3D, 0xBC, 0xB6, 0x45, 0x2F, 0xFB } };
+static const GUID SDL_IID_IDXGIDebug1 = { 0xc5a05f0c, 0x16f2, 0x4adf, { 0x9f, 0x4d, 0xa8, 0xc4, 0xd5, 0x8a, 0xc5, 0x50 } };
+static const GUID SDL_IID_IDXGIInfoQueue = { 0xD67441C7,0x672A,0x476f, { 0x9E,0x82,0xCD,0x55,0xB4,0x49,0x49,0xCE } };
+static const GUID SDL_IID_ID3D12Debug = { 0x344488b7, 0x6846, 0x474b, { 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0 } };
+static const GUID SDL_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8 } };
+static const GUID SDL_IID_ID3D12CommandQueue = { 0x0ec870a6, 0x5d7e, 0x4c22, { 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed } };
+static const GUID SDL_IID_ID3D12DescriptorHeap = { 0x8efb471d, 0x616c, 0x4f49, { 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51 } };
+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_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 } };
+static const GUID SDL_IID_ID3D12Heap = { 0x6b3b2502, 0x6e51, 0x45b3, { 0x90, 0xee, 0x98, 0x84, 0x26, 0x5e, 0x8d, 0xf3 } };
+static const GUID SDL_IID_ID3D12InfoQueue = { 0x0742a90b, 0xc387, 0x483f, { 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58 } };
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+
+
+UINT
+D3D12_Align(UINT location, UINT alignment)
+{
+ return ((location + (alignment - 1)) & ~(alignment - 1));
+}
+
+Uint32
+D3D12_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
+{
+ switch (dxgiFormat) {
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ return SDL_PIXELFORMAT_ARGB8888;
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ return SDL_PIXELFORMAT_RGB888;
+ default:
+ return SDL_PIXELFORMAT_UNKNOWN;
+ }
+}
+
+static DXGI_FORMAT
+SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
+{
+ switch (sdlFormat) {
+ case SDL_PIXELFORMAT_ARGB8888:
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case SDL_PIXELFORMAT_RGB888:
+ 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;
+ }
+}
+
+static void D3D12_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+
+static void
+D3D12_ReleaseAll(SDL_Renderer * renderer)
+{
+ D3D12_RenderData *data = (D3D12_RenderData *) renderer->driverdata;
+ SDL_Texture *texture = NULL;
+
+ /* Release all textures */
+ for (texture = renderer->textures; texture; texture = texture->next) {
+ D3D12_DestroyTexture(renderer, texture);
+ }
+
+ /* Release/reset everything else */
+ if (data) {
+ int i;
+
+ SAFE_RELEASE(data->dxgiFactory);
+ SAFE_RELEASE(data->dxgiAdapter);
+ SAFE_RELEASE(data->d3dDevice);
+ SAFE_RELEASE(data->debugInterface);
+ SAFE_RELEASE(data->commandQueue);
+ SAFE_RELEASE(data->commandList);
+ SAFE_RELEASE(data->rtvDescriptorHeap);
+ SAFE_RELEASE(data->textureRTVDescriptorHeap);
+ SAFE_RELEASE(data->srvDescriptorHeap);
+ SAFE_RELEASE(data->samplerDescriptorHeap);
+ SAFE_RELEASE(data->swapChain);
+ SAFE_RELEASE(data->fence);
+ SAFE_RELEASE(data->vertexBufferHeap);
+
+ for (i = 0; i < SDL_D3D12_NUM_BUFFERS; ++i) {
+ SAFE_RELEASE(data->commandAllocators[i]);
+ SAFE_RELEASE(data->renderTargets[i]);
+ }
+
+ if (data->pipelineStateCount > 0) {
+ for (i = 0; i < data->pipelineStateCount; ++i) {
+ SAFE_RELEASE(data->pipelineStates[i].pipelineState);
+ }
+ SDL_free(data->pipelineStates);
+ data->pipelineStateCount = 0;
+ }
+
+ for (i = 0; i < NUM_ROOTSIGS; ++i) {
+ SAFE_RELEASE(data->rootSignatures[i]);
+ }
+
+ for (i = 0; i < SDL_D3D12_NUM_VERTEX_BUFFERS; ++i) {
+ SAFE_RELEASE(data->vertexBuffers[i].resource);
+ }
+
+ data->swapEffect = (DXGI_SWAP_EFFECT) 0;
+ data->currentRenderTargetView.ptr = 0;
+ data->currentSampler.ptr = 0;
+
+ /* Check for any leaks if in debug mode */
+ if (data->dxgiDebug) {
+ IDXGIDebug1_ReportLiveObjects(data->dxgiDebug, SDL_DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL);
+ SAFE_RELEASE(data->dxgiDebug);
+ }
+
+ /* Unload the D3D libraries. This should be done last, in order
+ * to prevent IUnknown::Release() calls from crashing.
+ */
+ if (data->hD3D12Mod) {
+ SDL_UnloadObject(data->hD3D12Mod);
+ data->hD3D12Mod = NULL;
+ }
+ if (data->hDXGIMod) {
+ SDL_UnloadObject(data->hDXGIMod);
+ data->hDXGIMod = NULL;
+ }
+ }
+}
+
+static D3D12_GPU_DESCRIPTOR_HANDLE
+D3D12_CPUtoGPUHandle(ID3D12DescriptorHeap * heap, D3D12_CPU_DESCRIPTOR_HANDLE CPUHandle)
+{
+ D3D12_CPU_DESCRIPTOR_HANDLE CPUHeapStart;
+ D3D12_GPU_DESCRIPTOR_HANDLE GPUHandle;
+ SIZE_T offset;
+
+ /* Calculate the correct offset into the heap */
+ ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(heap, &CPUHeapStart);
+ offset = CPUHandle.ptr - CPUHeapStart.ptr;
+
+ ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(heap, &GPUHandle);
+ GPUHandle.ptr += offset;
+
+ return GPUHandle;
+}
+
+static void
+D3D12_WaitForGPU(D3D12_RenderData * data)
+{
+ HRESULT result;
+
+ if (data->commandQueue && data->fence && data->fenceEvent)
+ {
+ result = ID3D12CommandQueue_Signal(data->commandQueue, data->fence, data->fenceValue);
+ if (ID3D12Fence_GetCompletedValue(data->fence) < data->fenceValue) {
+ result = ID3D12Fence_SetEventOnCompletion(
+ data->fence,
+ data->fenceValue,
+ data->fenceEvent
+ );
+ WaitForSingleObjectEx(data->fenceEvent, INFINITE, FALSE);
+ }
+
+ data->fenceValue++;
+ }
+}
+
+static D3D12_CPU_DESCRIPTOR_HANDLE
+D3D12_GetCurrentRenderTargetView(SDL_Renderer * renderer)
+{
+ D3D12_RenderData* data = (D3D12_RenderData*)renderer->driverdata;
+ D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptor;
+
+ if (data->textureRenderTarget) {
+ return data->textureRenderTarget->mainTextureRenderTargetView;
+ }
+
+ SDL_zero(rtvDescriptor);
+ ID3D12Descript
(Patch may be truncated, please check the link at the top of this post.)