Atlas - SDL_gpu_d3d12.c
Home / ext / SDL / src / gpu / d3d12 Lines: 1 | Size: 386130 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#ifdef SDL_GPU_D3D12 25 26#include "../../events/SDL_windowevents_c.h" 27#include "../../core/windows/SDL_windows.h" 28#include "../../video/directx/SDL_d3d12.h" 29 30#ifdef HAVE_GPU_OPENXR 31#define XR_USE_GRAPHICS_API_D3D12 1 32#include "../xr/SDL_openxr_internal.h" 33#include "../xr/SDL_openxrdyn.h" 34#include "../xr/SDL_gpu_openxr.h" 35#endif 36 37#include "../SDL_sysgpu.h" 38 39#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__ 40#define HAVE_IDXGIINFOQUEUE 41#endif 42 43// Built-in shaders, compiled with compile_shaders.bat 44 45#define g_FullscreenVert D3D12_FullscreenVert 46#define g_BlitFrom2D D3D12_BlitFrom2D 47#define g_BlitFrom2DArray D3D12_BlitFrom2DArray 48#define g_BlitFrom3D D3D12_BlitFrom3D 49#define g_BlitFromCube D3D12_BlitFromCube 50#define g_BlitFromCubeArray D3D12_BlitFromCubeArray 51#if defined(SDL_PLATFORM_XBOXSERIES) 52#include "D3D12_Blit_Series.h" 53#elif defined(SDL_PLATFORM_XBOXONE) 54#include "D3D12_Blit_One.h" 55#else 56#include "D3D12_Blit.h" 57#endif 58#undef g_FullscreenVert 59#undef g_BlitFrom2D 60#undef g_BlitFrom2DArray 61#undef g_BlitFrom3D 62#undef g_BlitFromCube 63#undef g_BlitFromCubeArray 64 65// Macros 66 67#define SET_ERROR(fmt, msg) \ 68 do { \ 69 if (renderer->debug_mode) { \ 70 SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ 71 } \ 72 SDL_SetError(fmt, msg); \ 73 } while (0) 74 75#define SET_ERROR_AND_RETURN(fmt, msg, ret) \ 76 do { \ 77 if (renderer->debug_mode) { \ 78 SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \ 79 } \ 80 SDL_SetError(fmt, msg); \ 81 return ret; \ 82 } while (0) 83 84#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret) 85 86#define CHECK_D3D12_ERROR_AND_RETURN(msg, ret) \ 87 do { \ 88 if (FAILED(res)) { \ 89 D3D12_INTERNAL_SetError(renderer, msg, res); \ 90 return (ret); \ 91 } \ 92 } while (0) 93 94// Defines 95#if defined(_WIN32) 96#if defined(SDL_PLATFORM_XBOXSERIES) 97#define D3D12_DLL "d3d12_xs.dll" 98#elif defined(SDL_PLATFORM_XBOXONE) 99#define D3D12_DLL "d3d12_x.dll" 100#else 101#define D3D12_DLL "d3d12.dll" 102#define USE_PIX_RUNTIME 103#define WINPIXEVENTRUNTIME_DLL "WinPixEventRuntime.dll" 104#endif 105#define DXGI_DLL "dxgi.dll" 106#define DXGIDEBUG_DLL "dxgidebug.dll" 107#elif defined(__APPLE__) 108#define D3D12_DLL "libdxvk_d3d12.dylib" 109#define DXGI_DLL "libdxvk_dxgi.dylib" 110#define DXGIDEBUG_DLL "libdxvk_dxgidebug.dylib" 111#else 112#define D3D12_DLL "libdxvk_d3d12.so" 113#define DXGI_DLL "libdxvk_dxgi.so" 114#define DXGIDEBUG_DLL "libdxvk_dxgidebug.so" 115#endif 116 117#define D3D12_CREATE_DEVICE_FUNC "D3D12CreateDevice" 118#define D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC "D3D12SerializeRootSignature" 119#define CREATE_DXGI_FACTORY1_FUNC "CreateDXGIFactory1" 120#define DXGI_GET_DEBUG_INTERFACE_FUNC "DXGIGetDebugInterface" 121#define D3D12_GET_DEBUG_INTERFACE_FUNC "D3D12GetDebugInterface" 122#define D3D12_GET_INTERFACE_FUNC "D3D12GetInterface" 123#define WINDOW_PROPERTY_DATA "SDL.internal.gpu.d3d12.data" 124#define D3D_FEATURE_LEVEL_CHOICE D3D_FEATURE_LEVEL_11_0 125#define D3D_FEATURE_LEVEL_CHOICE_STR "11_0" 126#define MAX_ROOT_SIGNATURE_PARAMETERS 64 127#define D3D12_FENCE_UNSIGNALED_VALUE 0 128#define D3D12_FENCE_SIGNAL_VALUE 1 129// TODO: do these need to be tuned? 130#define VIEW_GPU_DESCRIPTOR_COUNT 65536 131#define SAMPLER_GPU_DESCRIPTOR_COUNT 2048 132#define STAGING_HEAP_DESCRIPTOR_COUNT 1024 133 134#define SDL_GPU_SHADERSTAGE_COMPUTE (SDL_GPUShaderStage)2 135 136#ifdef _WIN32 137#define HRESULT_FMT "(0x%08lX)" 138#else 139#define HRESULT_FMT "(0x%08X)" 140#endif 141 142// Function Pointer Signatures 143typedef HRESULT (WINAPI *pfnCreateDXGIFactory1)(const GUID *riid, void **ppFactory); 144typedef HRESULT (WINAPI *pfnDXGIGetDebugInterface)(const GUID *riid, void **ppDebug); 145 146#ifdef USE_PIX_RUNTIME 147#define PIX_BEGIN_EVENT_ON_COMMAND_LIST_FUNC "PIXBeginEventOnCommandList" 148#define PIX_END_EVENT_ON_COMMAND_LIST_FUNC "PIXEndEventOnCommandList" 149#define PIX_SET_MARKER_ON_COMMAND_LIST_FUNC "PIXSetMarkerOnCommandList" 150typedef void(WINAPI* pfnBeginEventOnCommandList)(ID3D12GraphicsCommandList* commandList, UINT64 color, _In_ PCSTR formatString); 151typedef void(WINAPI* pfnEndEventOnCommandList)(ID3D12GraphicsCommandList* commandList); 152typedef void(WINAPI* pfnSetMarkerOnCommandList)(ID3D12GraphicsCommandList* commandList, UINT64 color, _In_ PCSTR formatString); 153#endif 154 155// IIDs (from https://www.magnumdb.com/) 156static const IID D3D_IID_IDXGIFactory1 = { 0x770aae78, 0xf26f, 0x4dba, { 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87 } }; 157static const IID D3D_IID_IDXGIFactory4 = { 0x1bc6ea02, 0xef36, 0x464f, { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } }; 158static const IID D3D_IID_IDXGIFactory5 = { 0x7632e1f5, 0xee65, 0x4dca, { 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d } }; 159static const IID D3D_IID_IDXGIFactory6 = { 0xc1b6694f, 0xff09, 0x44a9, { 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17 } }; 160static const IID D3D_IID_IDXGIAdapter1 = { 0x29038f61, 0x3839, 0x4626, { 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05 } }; 161#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 162static const IID D3D_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; 163#else 164static const IID D3D_IID_IDXGIDevice = { 0x54ec77fa, 0x1377, 0x44e6, { 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c } }; 165#endif 166static const IID D3D_IID_IDXGISwapChain3 = { 0x94d99bdb, 0xf1f8, 0x4ab0, { 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1 } }; 167#ifdef HAVE_IDXGIINFOQUEUE 168static const IID D3D_IID_IDXGIDebug = { 0x119e7452, 0xde9e, 0x40fe, { 0x88, 0x06, 0x88, 0xf9, 0x0c, 0x12, 0xb4, 0x41 } }; 169static const IID D3D_IID_IDXGIInfoQueue = { 0xd67441c7, 0x672a, 0x476f, { 0x9e, 0x82, 0xcd, 0x55, 0xb4, 0x49, 0x49, 0xce } }; 170#endif 171static const GUID D3D_IID_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x08 } }; 172 173static const IID D3D_IID_ID3D12Device = { 0x189819f1, 0x1db6, 0x4b57, { 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7 } }; 174static const IID D3D_IID_ID3D12CommandQueue = { 0x0ec870a6, 0x5d7e, 0x4c22, { 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed } }; 175static const IID D3D_IID_ID3D12DescriptorHeap = { 0x8efb471d, 0x616c, 0x4f49, { 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51 } }; 176static const IID D3D_IID_ID3D12Resource = { 0x696442be, 0xa72e, 0x4059, { 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad } }; 177static const IID D3D_IID_ID3D12CommandAllocator = { 0x6102dee4, 0xaf59, 0x4b09, { 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24 } }; 178static const IID D3D_IID_ID3D12CommandList = { 0x7116d91c, 0xe7e4, 0x47ce, { 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5 } }; 179static const IID D3D_IID_ID3D12GraphicsCommandList = { 0x5b160d0f, 0xac1b, 0x4185, { 0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55 } }; 180static const IID D3D_IID_ID3D12Fence = { 0x0a753dcf, 0xc4d8, 0x4b91, { 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76 } }; 181static const IID D3D_IID_ID3D12RootSignature = { 0xc54a6b66, 0x72df, 0x4ee8, { 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14 } }; 182static const IID D3D_IID_ID3D12CommandSignature = { 0xc36a797c, 0xec80, 0x4f0a, { 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1 } }; 183static const IID D3D_IID_ID3D12PipelineState = { 0x765a30f3, 0xf624, 0x4c6f, { 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45 } }; 184static const IID D3D_IID_ID3D12Debug = { 0x344488b7, 0x6846, 0x474b, { 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0 } }; 185static const IID D3D_IID_ID3D12InfoQueue = { 0x0742a90b, 0xc387, 0x483f, { 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58 } }; 186static const IID D3D_IID_ID3D12InfoQueue1 = { 0x2852dd88, 0xb484, 0x4c0c, { 0xb6, 0xb1, 0x67, 0x16, 0x85, 0x00, 0xe6, 0x00 } }; 187 188static const GUID D3D_CLSID_ID3D12SDKConfiguration = { 0x7cda6aca, 0xa03e, 0x49c8, { 0x94, 0x58, 0x03, 0x34, 0xd2, 0x0e, 0x07, 0xce } }; 189static const GUID D3D_CLSID_ID3D12Debug = { 0xf2352aeb, 0xdd84, 0x49fe, { 0xb9, 0x7b, 0xa9, 0xdc, 0xfd, 0xcc, 0x1b, 0x4f } }; 190static const IID D3D_IID_ID3D12SDKConfiguration = { 0xe9eb5314, 0x33aa, 0x42b2, { 0xa7, 0x18, 0xd7, 0x7f, 0x58, 0xb1, 0xf1, 0xc7 } }; 191static const IID D3D_IID_ID3D12SDKConfiguration1 = { 0x8aaf9303, 0xad25, 0x48b9, { 0x9a, 0x57, 0xd9, 0xc3, 0x7e, 0x00, 0x9d, 0x9f } }; 192static const IID D3D_IID_ID3D12DeviceFactory = { 0x61f307d3, 0xd34e, 0x4e7c, { 0x83, 0x74, 0x3b, 0xa4, 0xde, 0x23, 0xcc, 0xcb } }; 193 194// Enums 195 196typedef enum D3D12BufferType 197{ 198 D3D12_BUFFER_TYPE_GPU, 199 D3D12_BUFFER_TYPE_UNIFORM, 200 D3D12_BUFFER_TYPE_UPLOAD, 201 D3D12_BUFFER_TYPE_DOWNLOAD 202} D3D12BufferType; 203 204// Conversions 205 206static SDL_GPUTextureFormat SwapchainCompositionToSDLTextureFormat[] = { 207 SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, // SDR 208 SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, // SDR_LINEAR 209 SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR 210 SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM, // HDR10_ST2084 211}; 212 213static DXGI_FORMAT SwapchainCompositionToTextureFormat[] = { 214 DXGI_FORMAT_B8G8R8A8_UNORM, // SDR 215 DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format) 216 DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR 217 DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084 218}; 219 220static DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = { 221 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR 222 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR 223 DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR 224 DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084 225}; 226 227static D3D12_BLEND SDLToD3D12_BlendFactor[] = { 228 D3D12_BLEND_ZERO, // INVALID 229 D3D12_BLEND_ZERO, // ZERO 230 D3D12_BLEND_ONE, // ONE 231 D3D12_BLEND_SRC_COLOR, // SRC_COLOR 232 D3D12_BLEND_INV_SRC_COLOR, // ONE_MINUS_SRC_COLOR 233 D3D12_BLEND_DEST_COLOR, // DST_COLOR 234 D3D12_BLEND_INV_DEST_COLOR, // ONE_MINUS_DST_COLOR 235 D3D12_BLEND_SRC_ALPHA, // SRC_ALPHA 236 D3D12_BLEND_INV_SRC_ALPHA, // ONE_MINUS_SRC_ALPHA 237 D3D12_BLEND_DEST_ALPHA, // DST_ALPHA 238 D3D12_BLEND_INV_DEST_ALPHA, // ONE_MINUS_DST_ALPHA 239 D3D12_BLEND_BLEND_FACTOR, // CONSTANT_COLOR 240 D3D12_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR 241 D3D12_BLEND_SRC_ALPHA_SAT, // SRC_ALPHA_SATURATE 242}; 243SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendFactor, SDL_arraysize(SDLToD3D12_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); 244 245static D3D12_BLEND SDLToD3D12_BlendFactorAlpha[] = { 246 D3D12_BLEND_ZERO, // INVALID 247 D3D12_BLEND_ZERO, // ZERO 248 D3D12_BLEND_ONE, // ONE 249 D3D12_BLEND_SRC_ALPHA, // SRC_COLOR 250 D3D12_BLEND_INV_SRC_ALPHA, // ONE_MINUS_SRC_COLOR 251 D3D12_BLEND_DEST_ALPHA, // DST_COLOR 252 D3D12_BLEND_INV_DEST_ALPHA, // ONE_MINUS_DST_COLOR 253 D3D12_BLEND_SRC_ALPHA, // SRC_ALPHA 254 D3D12_BLEND_INV_SRC_ALPHA, // ONE_MINUS_SRC_ALPHA 255 D3D12_BLEND_DEST_ALPHA, // DST_ALPHA 256 D3D12_BLEND_INV_DEST_ALPHA, // ONE_MINUS_DST_ALPHA 257 D3D12_BLEND_BLEND_FACTOR, // CONSTANT_COLOR 258 D3D12_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR 259 D3D12_BLEND_SRC_ALPHA_SAT, // SRC_ALPHA_SATURATE 260}; 261SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendFactorAlpha, SDL_arraysize(SDLToD3D12_BlendFactorAlpha) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE); 262 263static D3D12_BLEND_OP SDLToD3D12_BlendOp[] = { 264 D3D12_BLEND_OP_ADD, // INVALID 265 D3D12_BLEND_OP_ADD, // ADD 266 D3D12_BLEND_OP_SUBTRACT, // SUBTRACT 267 D3D12_BLEND_OP_REV_SUBTRACT, // REVERSE_SUBTRACT 268 D3D12_BLEND_OP_MIN, // MIN 269 D3D12_BLEND_OP_MAX // MAX 270}; 271SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendOp, SDL_arraysize(SDLToD3D12_BlendOp) == SDL_GPU_BLENDOP_MAX_ENUM_VALUE); 272 273// These are actually color formats. 274// For some genius reason, D3D12 splits format capabilities for depth-stencil views. 275static DXGI_FORMAT SDLToD3D12_TextureFormat[] = { 276 DXGI_FORMAT_UNKNOWN, // INVALID 277 DXGI_FORMAT_A8_UNORM, // A8_UNORM 278 DXGI_FORMAT_R8_UNORM, // R8_UNORM 279 DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM 280 DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM 281 DXGI_FORMAT_R16_UNORM, // R16_UNORM 282 DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM 283 DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM 284 DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM 285 DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM 286 DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM 287 DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM 288 DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM 289 DXGI_FORMAT_BC1_UNORM, // BC1_UNORM 290 DXGI_FORMAT_BC2_UNORM, // BC2_UNORM 291 DXGI_FORMAT_BC3_UNORM, // BC3_UNORM 292 DXGI_FORMAT_BC4_UNORM, // BC4_UNORM 293 DXGI_FORMAT_BC5_UNORM, // BC5_UNORM 294 DXGI_FORMAT_BC7_UNORM, // BC7_UNORM 295 DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT 296 DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT 297 DXGI_FORMAT_R8_SNORM, // R8_SNORM 298 DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM 299 DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM 300 DXGI_FORMAT_R16_SNORM, // R16_SNORM 301 DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM 302 DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM 303 DXGI_FORMAT_R16_FLOAT, // R16_FLOAT 304 DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT 305 DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT 306 DXGI_FORMAT_R32_FLOAT, // R32_FLOAT 307 DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT 308 DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT 309 DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT 310 DXGI_FORMAT_R8_UINT, // R8_UINT 311 DXGI_FORMAT_R8G8_UINT, // R8G8_UINT 312 DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT 313 DXGI_FORMAT_R16_UINT, // R16_UINT 314 DXGI_FORMAT_R16G16_UINT, // R16G16_UINT 315 DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT 316 DXGI_FORMAT_R32_UINT, // R32_UINT 317 DXGI_FORMAT_R32G32_UINT, // R32G32_UINT 318 DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT 319 DXGI_FORMAT_R8_SINT, // R8_INT 320 DXGI_FORMAT_R8G8_SINT, // R8G8_INT 321 DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT 322 DXGI_FORMAT_R16_SINT, // R16_INT 323 DXGI_FORMAT_R16G16_SINT, // R16G16_INT 324 DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT 325 DXGI_FORMAT_R32_SINT, // R32_INT 326 DXGI_FORMAT_R32G32_SINT, // R32G32_INT 327 DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT 328 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB 329 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB 330 DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB 331 DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB 332 DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB 333 DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB 334 DXGI_FORMAT_R16_UNORM, // D16_UNORM 335 DXGI_FORMAT_R24_UNORM_X8_TYPELESS, // D24_UNORM 336 DXGI_FORMAT_R32_FLOAT, // D32_FLOAT 337 DXGI_FORMAT_R24_UNORM_X8_TYPELESS, // D24_UNORM_S8_UINT 338 DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, // D32_FLOAT_S8_UINT 339 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM 340 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM 341 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM 342 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM 343 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM 344 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM 345 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM 346 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM 347 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM 348 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM 349 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM 350 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM 351 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM 352 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM 353 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB 354 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB 355 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB 356 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB 357 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB 358 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB 359 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB 360 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB 361 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB 362 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB 363 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB 364 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB 365 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB 366 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB 367 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT 368 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT 369 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT 370 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT 371 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT 372 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT 373 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT 374 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT 375 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT 376 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT 377 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT 378 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT 379 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT 380 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT 381}; 382SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TextureFormat, SDL_arraysize(SDLToD3D12_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE); 383 384static DXGI_FORMAT SDLToD3D12_DepthFormat[] = { 385 DXGI_FORMAT_UNKNOWN, // INVALID 386 DXGI_FORMAT_UNKNOWN, // A8_UNORM 387 DXGI_FORMAT_UNKNOWN, // R8_UNORM 388 DXGI_FORMAT_UNKNOWN, // R8G8_UNORM 389 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM 390 DXGI_FORMAT_UNKNOWN, // R16_UNORM 391 DXGI_FORMAT_UNKNOWN, // R16G16_UNORM 392 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM 393 DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM 394 DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM 395 DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM 396 DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM 397 DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM 398 DXGI_FORMAT_UNKNOWN, // BC1_UNORM 399 DXGI_FORMAT_UNKNOWN, // BC2_UNORM 400 DXGI_FORMAT_UNKNOWN, // BC3_UNORM 401 DXGI_FORMAT_UNKNOWN, // BC4_UNORM 402 DXGI_FORMAT_UNKNOWN, // BC5_UNORM 403 DXGI_FORMAT_UNKNOWN, // BC7_UNORM 404 DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT 405 DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT 406 DXGI_FORMAT_UNKNOWN, // R8_SNORM 407 DXGI_FORMAT_UNKNOWN, // R8G8_SNORM 408 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM 409 DXGI_FORMAT_UNKNOWN, // R16_SNORM 410 DXGI_FORMAT_UNKNOWN, // R16G16_SNORM 411 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM 412 DXGI_FORMAT_UNKNOWN, // R16_FLOAT 413 DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT 414 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT 415 DXGI_FORMAT_UNKNOWN, // R32_FLOAT 416 DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT 417 DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT 418 DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT 419 DXGI_FORMAT_UNKNOWN, // R8_UINT 420 DXGI_FORMAT_UNKNOWN, // R8G8_UINT 421 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT 422 DXGI_FORMAT_UNKNOWN, // R16_UINT 423 DXGI_FORMAT_UNKNOWN, // R16G16_UINT 424 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT 425 DXGI_FORMAT_UNKNOWN, // R32_UINT 426 DXGI_FORMAT_UNKNOWN, // R32G32_UINT 427 DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT 428 DXGI_FORMAT_UNKNOWN, // R8_INT 429 DXGI_FORMAT_UNKNOWN, // R8G8_INT 430 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT 431 DXGI_FORMAT_UNKNOWN, // R16_INT 432 DXGI_FORMAT_UNKNOWN, // R16G16_INT 433 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT 434 DXGI_FORMAT_UNKNOWN, // R32_INT 435 DXGI_FORMAT_UNKNOWN, // R32G32_INT 436 DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT 437 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB 438 DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB 439 DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB 440 DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB 441 DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB 442 DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB 443 DXGI_FORMAT_D16_UNORM, // D16_UNORM 444 DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM 445 DXGI_FORMAT_D32_FLOAT, // D32_FLOAT 446 DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT 447 DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT 448 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM 449 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM 450 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM 451 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM 452 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM 453 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM 454 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM 455 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM 456 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM 457 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM 458 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM 459 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM 460 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM 461 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM 462 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB 463 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB 464 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB 465 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB 466 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB 467 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB 468 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB 469 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB 470 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB 471 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB 472 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB 473 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB 474 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB 475 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB 476 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT 477 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT 478 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT 479 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT 480 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT 481 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT 482 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT 483 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT 484 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT 485 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT 486 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT 487 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT 488 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT 489 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT 490}; 491SDL_COMPILE_TIME_ASSERT(SDLToD3D12_DepthFormat, SDL_arraysize(SDLToD3D12_DepthFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE); 492 493static DXGI_FORMAT SDLToD3D12_TypelessFormat[] = { 494 DXGI_FORMAT_UNKNOWN, // INVALID 495 DXGI_FORMAT_UNKNOWN, // A8_UNORM 496 DXGI_FORMAT_UNKNOWN, // R8_UNORM 497 DXGI_FORMAT_UNKNOWN, // R8G8_UNORM 498 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM 499 DXGI_FORMAT_UNKNOWN, // R16_UNORM 500 DXGI_FORMAT_UNKNOWN, // R16G16_UNORM 501 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM 502 DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM 503 DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM 504 DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM 505 DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM 506 DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM 507 DXGI_FORMAT_UNKNOWN, // BC1_UNORM 508 DXGI_FORMAT_UNKNOWN, // BC2_UNORM 509 DXGI_FORMAT_UNKNOWN, // BC3_UNORM 510 DXGI_FORMAT_UNKNOWN, // BC4_UNORM 511 DXGI_FORMAT_UNKNOWN, // BC5_UNORM 512 DXGI_FORMAT_UNKNOWN, // BC7_UNORM 513 DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT 514 DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT 515 DXGI_FORMAT_UNKNOWN, // R8_SNORM 516 DXGI_FORMAT_UNKNOWN, // R8G8_SNORM 517 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM 518 DXGI_FORMAT_UNKNOWN, // R16_SNORM 519 DXGI_FORMAT_UNKNOWN, // R16G16_SNORM 520 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM 521 DXGI_FORMAT_UNKNOWN, // R16_FLOAT 522 DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT 523 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT 524 DXGI_FORMAT_UNKNOWN, // R32_FLOAT 525 DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT 526 DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT 527 DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT 528 DXGI_FORMAT_UNKNOWN, // R8_UINT 529 DXGI_FORMAT_UNKNOWN, // R8G8_UINT 530 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT 531 DXGI_FORMAT_UNKNOWN, // R16_UINT 532 DXGI_FORMAT_UNKNOWN, // R16G16_UINT 533 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT 534 DXGI_FORMAT_UNKNOWN, // R32_UINT 535 DXGI_FORMAT_UNKNOWN, // R32G32_UINT 536 DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT 537 DXGI_FORMAT_UNKNOWN, // R8_INT 538 DXGI_FORMAT_UNKNOWN, // R8G8_INT 539 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT 540 DXGI_FORMAT_UNKNOWN, // R16_INT 541 DXGI_FORMAT_UNKNOWN, // R16G16_INT 542 DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT 543 DXGI_FORMAT_UNKNOWN, // R32_INT 544 DXGI_FORMAT_UNKNOWN, // R32G32_INT 545 DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT 546 DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB 547 DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB 548 DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB 549 DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB 550 DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB 551 DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB 552 DXGI_FORMAT_R16_TYPELESS, // D16_UNORM 553 DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM 554 DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT 555 DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT 556 DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT 557 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM 558 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM 559 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM 560 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM 561 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM 562 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM 563 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM 564 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM 565 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM 566 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM 567 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM 568 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM 569 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM 570 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM 571 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB 572 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB 573 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB 574 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB 575 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB 576 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB 577 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB 578 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB 579 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB 580 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB 581 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB 582 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB 583 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB 584 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB 585 DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT 586 DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT 587 DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT 588 DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT 589 DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT 590 DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT 591 DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT 592 DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT 593 DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT 594 DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT 595 DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT 596 DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT 597 DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT 598 DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT 599}; 600SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TypelessFormat, SDL_arraysize(SDLToD3D12_TypelessFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE); 601 602#ifdef HAVE_GPU_OPENXR 603// For XR sRGB format selection - maps DXGI sRGB formats to SDL formats 604typedef struct TextureFormatPair 605{ 606 DXGI_FORMAT dxgi; 607 SDL_GPUTextureFormat sdl; 608} TextureFormatPair; 609 610static TextureFormatPair SDLToD3D12_TextureFormat_SrgbOnly[] = { 611 { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB }, 612 { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB }, 613 { DXGI_FORMAT_BC1_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB }, 614 { DXGI_FORMAT_BC2_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB }, 615 { DXGI_FORMAT_BC3_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB }, 616 { DXGI_FORMAT_BC7_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB }, 617}; 618 619// Forward declarations for XR helper functions 620static bool D3D12_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension); 621static XrResult D3D12_INTERNAL_GetXrGraphicsRequirements(XrInstance instance, XrSystemId systemId, D3D_FEATURE_LEVEL *minimumFeatureLevel, LUID *adapter); 622static bool D3D12_INTERNAL_GetAdapterByLuid(LUID luid, IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapter); 623static bool D3D12_INTERNAL_FindXRSrgbSwapchain(int64_t *supportedFormats, Uint32 supportedFormatsCount, SDL_GPUTextureFormat *sdlFormat, DXGI_FORMAT *dxgiFormat); 624#endif /* HAVE_GPU_OPENXR */ 625 626static D3D12_COMPARISON_FUNC SDLToD3D12_CompareOp[] = { 627 D3D12_COMPARISON_FUNC_NEVER, // INVALID 628 D3D12_COMPARISON_FUNC_NEVER, // NEVER 629 D3D12_COMPARISON_FUNC_LESS, // LESS 630 D3D12_COMPARISON_FUNC_EQUAL, // EQUAL 631 D3D12_COMPARISON_FUNC_LESS_EQUAL, // LESS_OR_EQUAL 632 D3D12_COMPARISON_FUNC_GREATER, // GREATER 633 D3D12_COMPARISON_FUNC_NOT_EQUAL, // NOT_EQUAL 634 D3D12_COMPARISON_FUNC_GREATER_EQUAL, // GREATER_OR_EQUAL 635 D3D12_COMPARISON_FUNC_ALWAYS // ALWAYS 636}; 637SDL_COMPILE_TIME_ASSERT(SDLToD3D12_CompareOp, SDL_arraysize(SDLToD3D12_CompareOp) == SDL_GPU_COMPAREOP_MAX_ENUM_VALUE); 638 639static D3D12_STENCIL_OP SDLToD3D12_StencilOp[] = { 640 D3D12_STENCIL_OP_KEEP, // INVALID 641 D3D12_STENCIL_OP_KEEP, // KEEP 642 D3D12_STENCIL_OP_ZERO, // ZERO 643 D3D12_STENCIL_OP_REPLACE, // REPLACE 644 D3D12_STENCIL_OP_INCR_SAT, // INCREMENT_AND_CLAMP 645 D3D12_STENCIL_OP_DECR_SAT, // DECREMENT_AND_CLAMP 646 D3D12_STENCIL_OP_INVERT, // INVERT 647 D3D12_STENCIL_OP_INCR, // INCREMENT_AND_WRAP 648 D3D12_STENCIL_OP_DECR // DECREMENT_AND_WRAP 649}; 650SDL_COMPILE_TIME_ASSERT(SDLToD3D12_StencilOp, SDL_arraysize(SDLToD3D12_StencilOp) == SDL_GPU_STENCILOP_MAX_ENUM_VALUE); 651 652static D3D12_CULL_MODE SDLToD3D12_CullMode[] = { 653 D3D12_CULL_MODE_NONE, // NONE 654 D3D12_CULL_MODE_FRONT, // FRONT 655 D3D12_CULL_MODE_BACK // BACK 656}; 657 658static D3D12_FILL_MODE SDLToD3D12_FillMode[] = { 659 D3D12_FILL_MODE_SOLID, // FILL 660 D3D12_FILL_MODE_WIREFRAME // LINE 661}; 662 663static D3D12_INPUT_CLASSIFICATION SDLToD3D12_InputRate[] = { 664 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX 665 D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE 666}; 667 668static DXGI_FORMAT SDLToD3D12_VertexFormat[] = { 669 DXGI_FORMAT_UNKNOWN, // UNKNOWN 670 DXGI_FORMAT_R32_SINT, // INT 671 DXGI_FORMAT_R32G32_SINT, // INT2 672 DXGI_FORMAT_R32G32B32_SINT, // INT3 673 DXGI_FORMAT_R32G32B32A32_SINT, // INT4 674 DXGI_FORMAT_R32_UINT, // UINT 675 DXGI_FORMAT_R32G32_UINT, // UINT2 676 DXGI_FORMAT_R32G32B32_UINT, // UINT3 677 DXGI_FORMAT_R32G32B32A32_UINT, // UINT4 678 DXGI_FORMAT_R32_FLOAT, // FLOAT 679 DXGI_FORMAT_R32G32_FLOAT, // FLOAT2 680 DXGI_FORMAT_R32G32B32_FLOAT, // FLOAT3 681 DXGI_FORMAT_R32G32B32A32_FLOAT, // FLOAT4 682 DXGI_FORMAT_R8G8_SINT, // BYTE2 683 DXGI_FORMAT_R8G8B8A8_SINT, // BYTE4 684 DXGI_FORMAT_R8G8_UINT, // UBYTE2 685 DXGI_FORMAT_R8G8B8A8_UINT, // UBYTE4 686 DXGI_FORMAT_R8G8_SNORM, // BYTE2_NORM 687 DXGI_FORMAT_R8G8B8A8_SNORM, // BYTE4_NORM 688 DXGI_FORMAT_R8G8_UNORM, // UBYTE2_NORM 689 DXGI_FORMAT_R8G8B8A8_UNORM, // UBYTE4_NORM 690 DXGI_FORMAT_R16G16_SINT, // SHORT2 691 DXGI_FORMAT_R16G16B16A16_SINT, // SHORT4 692 DXGI_FORMAT_R16G16_UINT, // USHORT2 693 DXGI_FORMAT_R16G16B16A16_UINT, // USHORT4 694 DXGI_FORMAT_R16G16_SNORM, // SHORT2_NORM 695 DXGI_FORMAT_R16G16B16A16_SNORM, // SHORT4_NORM 696 DXGI_FORMAT_R16G16_UNORM, // USHORT2_NORM 697 DXGI_FORMAT_R16G16B16A16_UNORM, // USHORT4_NORM 698 DXGI_FORMAT_R16G16_FLOAT, // HALF2 699 DXGI_FORMAT_R16G16B16A16_FLOAT // HALF4 700}; 701SDL_COMPILE_TIME_ASSERT(SDLToD3D12_VertexFormat, SDL_arraysize(SDLToD3D12_VertexFormat) == SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE); 702 703static Uint32 SDLToD3D12_SampleCount[] = { 704 1, // SDL_GPU_SAMPLECOUNT_1 705 2, // SDL_GPU_SAMPLECOUNT_2 706 4, // SDL_GPU_SAMPLECOUNT_4 707 8, // SDL_GPU_SAMPLECOUNT_8 708}; 709 710static D3D12_PRIMITIVE_TOPOLOGY SDLToD3D12_PrimitiveType[] = { 711 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // TRIANGLELIST 712 D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, // TRIANGLESTRIP 713 D3D_PRIMITIVE_TOPOLOGY_LINELIST, // LINELIST 714 D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, // LINESTRIP 715 D3D_PRIMITIVE_TOPOLOGY_POINTLIST // POINTLIST 716}; 717 718static D3D12_PRIMITIVE_TOPOLOGY_TYPE SDLToD3D12_PrimitiveTopologyType[] = { 719 D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // TRIANGLELIST 720 D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // TRIANGLESTRIP 721 D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, // LINELIST 722 D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, // LINESTRIP 723 D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT // POINTLIST 724}; 725 726static D3D12_TEXTURE_ADDRESS_MODE SDLToD3D12_SamplerAddressMode[] = { 727 D3D12_TEXTURE_ADDRESS_MODE_WRAP, // REPEAT 728 D3D12_TEXTURE_ADDRESS_MODE_MIRROR, // MIRRORED_REPEAT 729 D3D12_TEXTURE_ADDRESS_MODE_CLAMP // CLAMP_TO_EDGE 730}; 731 732static D3D12_FILTER SDLToD3D12_Filter( 733 SDL_GPUFilter minFilter, 734 SDL_GPUFilter magFilter, 735 SDL_GPUSamplerMipmapMode mipmapMode, 736 bool comparisonEnabled, 737 bool anisotropyEnabled) 738{ 739 D3D12_FILTER result = D3D12_ENCODE_BASIC_FILTER( 740 (minFilter == SDL_GPU_FILTER_LINEAR) ? 1 : 0, 741 (magFilter == SDL_GPU_FILTER_LINEAR) ? 1 : 0, 742 (mipmapMode == SDL_GPU_SAMPLERMIPMAPMODE_LINEAR) ? 1 : 0, 743 comparisonEnabled ? 1 : 0); 744 745 if (anisotropyEnabled) { 746 result = (D3D12_FILTER)(result | D3D12_ANISOTROPIC_FILTERING_BIT); 747 } 748 749 return result; 750} 751 752// Structures 753typedef struct D3D12Renderer D3D12Renderer; 754typedef struct D3D12CommandBufferPool D3D12CommandBufferPool; 755typedef struct D3D12CommandBuffer D3D12CommandBuffer; 756typedef struct D3D12Texture D3D12Texture; 757typedef struct D3D12Shader D3D12Shader; 758typedef struct D3D12GraphicsPipeline D3D12GraphicsPipeline; 759typedef struct D3D12ComputePipeline D3D12ComputePipeline; 760typedef struct D3D12Buffer D3D12Buffer; 761typedef struct D3D12BufferContainer D3D12BufferContainer; 762typedef struct D3D12UniformBuffer D3D12UniformBuffer; 763typedef struct D3D12DescriptorHeap D3D12DescriptorHeap; 764typedef struct D3D12StagingDescriptor D3D12StagingDescriptor; 765typedef struct D3D12TextureDownload D3D12TextureDownload; 766 767typedef struct D3D12Fence 768{ 769 ID3D12Fence *handle; 770 HANDLE event; // used for blocking 771 SDL_AtomicInt referenceCount; 772} D3D12Fence; 773 774struct D3D12DescriptorHeap 775{ 776 ID3D12DescriptorHeap *handle; 777 D3D12_DESCRIPTOR_HEAP_TYPE heapType; 778 D3D12_CPU_DESCRIPTOR_HANDLE descriptorHeapCPUStart; 779 D3D12_GPU_DESCRIPTOR_HANDLE descriptorHeapGPUStart; // only used by GPU heaps 780 Uint32 maxDescriptors; 781 Uint32 descriptorSize; 782 bool staging; 783 784 Uint32 currentDescriptorIndex; // only used by GPU heaps 785}; 786 787typedef struct D3D12GPUDescriptorHeapPool 788{ 789 Uint32 capacity; 790 Uint32 count; 791 D3D12DescriptorHeap **heaps; 792 SDL_Mutex *lock; 793} D3D12GPUDescriptorHeapPool; 794 795// The only thing we care about with staging descriptors is being able to grab a free descriptor. 796typedef struct D3D12StagingDescriptorPool 797{ 798 Uint32 heapCount; 799 D3D12DescriptorHeap **heaps; 800 801 // Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap. 802 Uint32 freeDescriptorCapacity; 803 Uint32 freeDescriptorCount; 804 D3D12StagingDescriptor *freeDescriptors; 805 806 SDL_Mutex *lock; 807} D3D12StagingDescriptorPool; 808 809struct D3D12StagingDescriptor 810{ 811 D3D12StagingDescriptorPool *pool; 812 D3D12DescriptorHeap *heap; 813 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; 814 Uint32 cpuHandleIndex; 815}; 816 817typedef struct D3D12TextureContainer 818{ 819 TextureCommonHeader header; 820 821 D3D12Texture *activeTexture; 822 823 D3D12Texture **textures; 824 Uint32 textureCapacity; 825 Uint32 textureCount; 826 827 // Swapchain images cannot be cycled 828 bool canBeCycled; 829 830 char *debugName; 831 832 // XR swapchain images are managed by OpenXR runtime 833 bool externallyManaged; 834} D3D12TextureContainer; 835 836// Null views represent by heap = NULL 837typedef struct D3D12TextureSubresource 838{ 839 D3D12Texture *parent; 840 Uint32 layer; 841 Uint32 level; 842 Uint32 depth; 843 Uint32 index; 844 845 // One per depth slice 846 D3D12StagingDescriptor *rtvHandles; // NULL if not a color target 847 848 D3D12StagingDescriptor uavHandle; // NULL if not a compute storage write texture 849 D3D12StagingDescriptor dsvHandle; // NULL if not a depth stencil target 850} D3D12TextureSubresource; 851 852struct D3D12Texture 853{ 854 D3D12TextureContainer *container; 855 Uint32 containerIndex; 856 857 D3D12TextureSubresource *subresources; 858 Uint32 subresourceCount; /* layerCount * num_levels */ 859 860 ID3D12Resource *resource; 861 D3D12StagingDescriptor srvHandle; 862 863 SDL_AtomicInt referenceCount; 864 865 // XR swapchain images are managed by OpenXR runtime 866 bool externallyManaged; 867}; 868 869typedef struct D3D12Sampler 870{ 871 SDL_GPUSamplerCreateInfo createInfo; 872 D3D12StagingDescriptor handle; 873 SDL_AtomicInt referenceCount; 874} D3D12Sampler; 875 876typedef struct D3D12WindowData 877{ 878 SDL_Window *window; 879 D3D12Renderer *renderer; 880 int refcount; 881#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 882 D3D12XBOX_FRAME_PIPELINE_TOKEN frameToken; 883#else 884 IDXGISwapChain3 *swapchain; 885#endif 886 SDL_GPUPresentMode present_mode; 887 SDL_GPUSwapchainComposition swapchainComposition; 888 DXGI_COLOR_SPACE_TYPE swapchainColorSpace; 889 Uint32 frameCounter; 890 891 D3D12TextureContainer textureContainers[MAX_FRAMES_IN_FLIGHT]; 892 Uint32 swapchainTextureCount; 893 894 SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT]; 895 Uint32 width; 896 Uint32 height; 897 bool needsSwapchainRecreate; 898} D3D12WindowData; 899 900typedef struct D3D12PresentData 901{ 902 D3D12WindowData *windowData; 903 Uint32 swapchainImageIndex; 904} D3D12PresentData; 905 906#ifdef USE_PIX_RUNTIME 907typedef struct WinPixEventRuntimeFns { 908 pfnBeginEventOnCommandList pBeginEventOnCommandList; 909 pfnEndEventOnCommandList pEndEventOnCommandList; 910 pfnSetMarkerOnCommandList pSetMarkerOnCommandList; 911} WinPixEventRuntimeFns; 912#endif 913 914struct D3D12Renderer 915{ 916 // Reference to the parent device 917 SDL_GPUDevice *sdlGPUDevice; 918 919#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 920 IDXGIDebug *dxgiDebug; 921 IDXGIFactory4 *factory; 922#ifdef HAVE_IDXGIINFOQUEUE 923 IDXGIInfoQueue *dxgiInfoQueue; 924#endif 925 IDXGIAdapter1 *adapter; 926 SDL_SharedObject *dxgi_dll; 927 SDL_SharedObject *dxgidebug_dll; 928#endif 929#ifdef USE_PIX_RUNTIME 930 SDL_SharedObject *winpixeventruntime_dll; 931 WinPixEventRuntimeFns winpixeventruntimeFns; 932#endif 933 ID3D12Debug *d3d12Debug; 934 BOOL supportsTearing; 935 SDL_SharedObject *d3d12_dll; 936 ID3D12Device *device; 937 PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pD3D12SerializeRootSignature; 938 char *semantic; 939 SDL_iconv_t iconv; 940 941 ID3D12CommandQueue *commandQueue; 942 943 bool debug_mode; 944 bool GPUUploadHeapSupported; 945 bool UnrestrictedBufferTextureCopyPitchSupported; 946 // FIXME: these might not be necessary since we're not using custom heaps 947 bool UMA; 948 bool UMACacheCoherent; 949 SDL_PropertiesID props; 950 Uint32 allowedFramesInFlight; 951 952 // Indirect command signatures 953 ID3D12CommandSignature *indirectDrawCommandSignature; 954 ID3D12CommandSignature *indirectIndexedDrawCommandSignature; 955 ID3D12CommandSignature *indirectDispatchCommandSignature; 956 957 // Blit 958 SDL_GPUShader *blitVertexShader; 959 SDL_GPUShader *blitFrom2DShader; 960 SDL_GPUShader *blitFrom2DArrayShader; 961 SDL_GPUShader *blitFrom3DShader; 962 SDL_GPUShader *blitFromCubeShader; 963 SDL_GPUShader *blitFromCubeArrayShader; 964 965 SDL_GPUSampler *blitNearestSampler; 966 SDL_GPUSampler *blitLinearSampler; 967 968 BlitPipelineCacheEntry *blitPipelines; 969 Uint32 blitPipelineCount; 970 Uint32 blitPipelineCapacity; 971 972 // Resources 973 974 D3D12CommandBuffer **availableCommandBuffers; 975 Uint32 availableCommandBufferCount; 976 Uint32 availableCommandBufferCapacity; 977 978 D3D12CommandBuffer **submittedCommandBuffers; 979 Uint32 submittedCommandBufferCount; 980 Uint32 submittedCommandBufferCapacity; 981 982 D3D12UniformBuffer **uniformBufferPool; 983 Uint32 uniformBufferPoolCount; 984 Uint32 uniformBufferPoolCapacity; 985 986 D3D12WindowData **claimedWindows; 987 Uint32 claimedWindowCount; 988 Uint32 claimedWindowCapacity; 989 990 D3D12Fence **availableFences; 991 Uint32 availableFenceCount; 992 Uint32 availableFenceCapacity; 993 994 D3D12StagingDescriptorPool *stagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; 995 D3D12GPUDescriptorHeapPool gpuDescriptorHeapPools[2]; 996 997 // Deferred resource releasing 998 999 D3D12Buffer **buffersToDestroy; 1000 Uint32 buffersToDestroyCount; 1001 Uint32 buffersToDestroyCapacity; 1002 1003 D3D12Texture **texturesToDestroy; 1004 Uint32 texturesToDestroyCount; 1005 Uint32 texturesToDestroyCapacity; 1006 1007 D3D12Sampler **samplersToDestroy; 1008 Uint32 samplersToDestroyCount; 1009 Uint32 samplersToDestroyCapacity; 1010 1011 D3D12GraphicsPipeline **graphicsPipelinesToDestroy; 1012 Uint32 graphicsPipelinesToDestroyCount; 1013 Uint32 graphicsPipelinesToDestroyCapacity; 1014 1015 D3D12ComputePipeline **computePipelinesToDestroy; 1016 Uint32 computePipelinesToDestroyCount; 1017 Uint32 computePipelinesToDestroyCapacity; 1018 1019 // Locks 1020 SDL_Mutex *acquireCommandBufferLock; 1021 SDL_Mutex *acquireUniformBufferLock; 1022 SDL_Mutex *submitLock; 1023 SDL_Mutex *windowLock; 1024 SDL_Mutex *fenceLock; 1025 SDL_Mutex *disposeLock; 1026 1027#ifdef HAVE_GPU_OPENXR 1028 // OpenXR state 1029 XrInstance xrInstance; 1030 XrSystemId xrSystemId; 1031 XrInstancePfns *xr; 1032#endif 1033}; 1034 1035struct D3D12CommandBuffer 1036{ 1037 // reserved for SDL_gpu 1038 CommandBufferCommonHeader common; 1039 1040 // non owning parent reference 1041 D3D12Renderer *renderer; 1042 1043 ID3D12CommandAllocator *commandAllocator; 1044 ID3D12GraphicsCommandList *graphicsCommandList; 1045 D3D12Fence *inFlightFence; 1046 bool autoReleaseFence; 1047 1048 // Presentation data 1049 D3D12PresentData *presentDatas; 1050 Uint32 presentDataCount; 1051 Uint32 presentDataCapacity; 1052 1053 D3D12TextureSubresource *colorTargetSubresources[MAX_COLOR_TARGET_BINDINGS]; 1054 D3D12TextureSubresource *colorResolveSubresources[MAX_COLOR_TARGET_BINDINGS]; 1055 D3D12TextureSubresource *depthStencilTextureSubresource; 1056 D3D12GraphicsPipeline *currentGraphicsPipeline; 1057 D3D12ComputePipeline *currentComputePipeline; 1058 1059 // Set at acquire time 1060 D3D12DescriptorHeap *gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER + 1]; 1061 1062 D3D12DescriptorHeap **usedDescriptorHeaps; 1063 Uint32 usedDescriptorHeapCount; 1064 Uint32 usedDescriptorHeapCapacity; 1065 1066 D3D12UniformBuffer **usedUniformBuffers; 1067 Uint32 usedUniformBufferCount; 1068 Uint32 usedUniformBufferCapacity; 1069 1070 // Resource slot state 1071 bool needVertexBufferBind; 1072 bool needVertexSamplerBind; 1073 bool needVertexStorageTextureBind; 1074 bool needVertexStorageBufferBind; 1075 bool needVertexUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1076 bool needFragmentSamplerBind; 1077 bool needFragmentStorageTextureBind; 1078 bool needFragmentStorageBufferBind; 1079 bool needFragmentUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1080 1081 bool needComputeSamplerBind; 1082 bool needComputeReadOnlyStorageTextureBind; 1083 bool needComputeReadOnlyStorageBufferBind; 1084 bool needComputeUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1085 1086 D3D12Buffer *vertexBuffers[MAX_VERTEX_BUFFERS]; 1087 Uint32 vertexBufferOffsets[MAX_VERTEX_BUFFERS]; 1088 Uint32 vertexBufferCount; 1089 1090 D3D12_CPU_DESCRIPTOR_HANDLE vertexSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1091 D3D12_CPU_DESCRIPTOR_HANDLE vertexSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1092 D3D12_CPU_DESCRIPTOR_HANDLE vertexStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE]; 1093 D3D12_CPU_DESCRIPTOR_HANDLE vertexStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE]; 1094 1095 D3D12UniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1096 1097 D3D12_CPU_DESCRIPTOR_HANDLE fragmentSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1098 D3D12_CPU_DESCRIPTOR_HANDLE fragmentSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1099 D3D12_CPU_DESCRIPTOR_HANDLE fragmentStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE]; 1100 D3D12_CPU_DESCRIPTOR_HANDLE fragmentStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE]; 1101 1102 D3D12UniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1103 1104 D3D12_CPU_DESCRIPTOR_HANDLE computeSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1105 D3D12_CPU_DESCRIPTOR_HANDLE computeSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 1106 D3D12_CPU_DESCRIPTOR_HANDLE computeReadOnlyStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE]; 1107 D3D12_CPU_DESCRIPTOR_HANDLE computeReadOnlyStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE]; 1108 1109 // Track these separately because barriers can happen mid compute pass 1110 D3D12Texture *computeReadOnlyStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; 1111 D3D12Buffer *computeReadOnlyStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; 1112 1113 D3D12_CPU_DESCRIPTOR_HANDLE computeReadWriteStorageTextureDescriptorHandles[MAX_COMPUTE_WRITE_TEXTURES]; 1114 D3D12_CPU_DESCRIPTOR_HANDLE computeReadWriteStorageBufferDescriptorHandles[MAX_COMPUTE_WRITE_BUFFERS]; 1115 1116 // Track these separately because they are bound when the compute pass begins 1117 D3D12TextureSubresource *computeReadWriteStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES]; 1118 Uint32 computeReadWriteStorageTextureSubresourceCount; 1119 D3D12Buffer *computeReadWriteStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS]; 1120 Uint32 computeReadWriteStorageBufferCount; 1121 1122 D3D12UniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1123 1124 // Resource tracking 1125 D3D12Texture **usedTextures; 1126 Uint32 usedTextureCount; 1127 Uint32 usedTextureCapacity; 1128 1129 D3D12Buffer **usedBuffers; 1130 Uint32 usedBufferCount; 1131 Uint32 usedBufferCapacity; 1132 1133 D3D12Sampler **usedSamplers; 1134 Uint32 usedSamplerCount; 1135 Uint32 usedSamplerCapacity; 1136 1137 D3D12GraphicsPipeline **usedGraphicsPipelines; 1138 Uint32 usedGraphicsPipelineCount; 1139 Uint32 usedGraphicsPipelineCapacity; 1140 1141 D3D12ComputePipeline **usedComputePipelines; 1142 Uint32 usedComputePipelineCount; 1143 Uint32 usedComputePipelineCapacity; 1144 1145 // Used for texture pitch hack 1146 D3D12TextureDownload **textureDownloads; 1147 Uint32 textureDownloadCount; 1148 Uint32 textureDownloadCapacity; 1149}; 1150 1151struct D3D12Shader 1152{ 1153 // todo cleanup 1154 void *bytecode; 1155 size_t bytecodeSize; 1156 1157 SDL_GPUShaderStage stage; 1158 Uint32 num_samplers; 1159 Uint32 numUniformBuffers; 1160 Uint32 numStorageBuffers; 1161 Uint32 numStorageTextures; 1162}; 1163 1164typedef struct D3D12GraphicsRootSignature 1165{ 1166 ID3D12RootSignature *handle; 1167 1168 Sint32 vertexSamplerRootIndex; 1169 Sint32 vertexSamplerTextureRootIndex; 1170 Sint32 vertexStorageTextureRootIndex; 1171 Sint32 vertexStorageBufferRootIndex; 1172 1173 Sint32 vertexUniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1174 1175 Sint32 fragmentSamplerRootIndex; 1176 Sint32 fragmentSamplerTextureRootIndex; 1177 Sint32 fragmentStorageTextureRootIndex; 1178 Sint32 fragmentStorageBufferRootIndex; 1179 1180 Sint32 fragmentUniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1181} D3D12GraphicsRootSignature; 1182 1183struct D3D12GraphicsPipeline 1184{ 1185 GraphicsPipelineCommonHeader header; 1186 1187 ID3D12PipelineState *pipelineState; 1188 D3D12GraphicsRootSignature *rootSignature; 1189 SDL_GPUPrimitiveType primitiveType; 1190 1191 Uint32 vertexStrides[MAX_VERTEX_BUFFERS]; 1192 1193 SDL_AtomicInt referenceCount; 1194}; 1195 1196typedef struct D3D12ComputeRootSignature 1197{ 1198 ID3D12RootSignature *handle; 1199 1200 Sint32 samplerRootIndex; 1201 Sint32 samplerTextureRootIndex; 1202 Sint32 readOnlyStorageTextureRootIndex; 1203 Sint32 readOnlyStorageBufferRootIndex; 1204 Sint32 readWriteStorageTextureRootIndex; 1205 Sint32 readWriteStorageBufferRootIndex; 1206 Sint32 uniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE]; 1207} D3D12ComputeRootSignature; 1208 1209struct D3D12ComputePipeline 1210{ 1211 ComputePipelineCommonHeader header; 1212 1213 ID3D12PipelineState *pipelineState; 1214 D3D12ComputeRootSignature *rootSignature; 1215 1216 SDL_AtomicInt referenceCount; 1217}; 1218 1219struct D3D12TextureDownload 1220{ 1221 D3D12Buffer *destinationBuffer; 1222 D3D12Buffer *temporaryBuffer; 1223 Uint32 width; 1224 Uint32 height; 1225 Uint32 depth; 1226 Uint32 bufferOffset; 1227 Uint32 bytesPerRow; 1228 Uint32 bytesPerDepthSlice; 1229 Uint32 alignedBytesPerRow; 1230}; 1231 1232struct D3D12Buffer 1233{ 1234 D3D12BufferContainer *container; 1235 Uint32 containerIndex; 1236 1237 ID3D12Resource *handle; 1238 D3D12StagingDescriptor uavDescriptor; 1239 D3D12StagingDescriptor srvDescriptor; 1240 D3D12StagingDescriptor cbvDescriptor; 1241 D3D12_GPU_VIRTUAL_ADDRESS virtualAddress; 1242 Uint8 *mapPointer; // NULL except for upload buffers and fast uniform buffers 1243 SDL_AtomicInt referenceCount; 1244 bool transitioned; // used for initial resource barrier 1245}; 1246 1247struct D3D12BufferContainer 1248{ 1249 SDL_GPUBufferUsageFlags usage; 1250 Uint32 size; 1251 D3D12BufferType type; 1252 1253 D3D12Buffer *activeBuffer; 1254 1255 D3D12Buffer **buffers; 1256 Uint32 bufferCapacity; 1257 Uint32 bufferCount; 1258 1259 D3D12_RESOURCE_DESC bufferDesc; 1260 1261 char *debugName; 1262}; 1263 1264struct D3D12UniformBuffer 1265{ 1266 D3D12Buffer *buffer; 1267 Uint32 writeOffset; 1268 Uint32 drawOffset; 1269}; 1270 1271// Forward function declarations 1272 1273static void D3D12_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window); 1274static bool D3D12_Wait(SDL_GPURenderer *driverData); 1275static bool D3D12_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences); 1276static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData); 1277 1278// Helpers 1279 1280static Uint32 D3D12_INTERNAL_Align(Uint32 location, Uint32 alignment) 1281{ 1282 return (location + (alignment - 1)) & ~(alignment - 1); 1283} 1284 1285// Xbox Hack 1286 1287#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 1288// FIXME: This is purely to work around a presentation bug when recreating the device/command queue. 1289static ID3D12Device *s_Device; 1290static ID3D12CommandQueue *s_CommandQueue; 1291#endif 1292 1293#if defined(SDL_PLATFORM_XBOXONE) 1294// These are not defined in d3d12_x.h. 1295typedef HRESULT (D3DAPI* PFN_D3D12_XBOX_CREATE_DEVICE)(_In_opt_ IGraphicsUnknown *, _In_ const D3D12XBOX_CREATE_DEVICE_PARAMETERS*, _In_ REFIID, _Outptr_opt_ void **); 1296#define D3D12_STANDARD_MULTISAMPLE_PATTERN DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN 1297#endif 1298 1299// Logging 1300 1301static void D3D12_INTERNAL_SetError( 1302 D3D12Renderer *renderer, 1303 const char *msg, 1304 HRESULT res) 1305{ 1306 #define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! 1307 1308 // Buffer for text, ensure space for \0 terminator after buffer 1309 char wszMsgBuff[MAX_ERROR_LEN + 1]; 1310 DWORD dwChars; // Number of chars returned. 1311 1312 if (res == DXGI_ERROR_DEVICE_REMOVED) { 1313 if (renderer->device) { 1314 res = ID3D12Device_GetDeviceRemovedReason(renderer->device); 1315 } 1316 } 1317 1318 // Try to get the message from the system errors. 1319 dwChars = FormatMessageA( 1320 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 1321 NULL, 1322 res, 1323 0, 1324 wszMsgBuff, 1325 MAX_ERROR_LEN, 1326 NULL); 1327 1328 // No message? Screw it, just post the code. 1329 if (dwChars == 0) { 1330 if (renderer->debug_mode) { 1331 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res); 1332 } 1333 SDL_SetError("%s! Error Code: " HRESULT_FMT, msg, res); 1334 return; 1335 } 1336 1337 // Ensure valid range 1338 dwChars = SDL_min(dwChars, MAX_ERROR_LEN); 1339 1340 // Trim whitespace from tail of message 1341 while (dwChars > 0) { 1342 if (wszMsgBuff[dwChars - 1] <= ' ') { 1343 dwChars--; 1344 } else { 1345 break; 1346 } 1347 } 1348 1349 // Ensure null-terminated string 1350 wszMsgBuff[dwChars] = '\0'; 1351 1352 if (renderer->debug_mode) { 1353 SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); 1354 } 1355 SDL_SetError("%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); 1356} 1357 1358// Release / Cleanup 1359 1360static void D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1361 D3D12StagingDescriptor *cpuDescriptor) 1362{ 1363 D3D12StagingDescriptorPool *pool = cpuDescriptor->pool; 1364 1365 if (pool != NULL) { 1366 SDL_LockMutex(pool->lock); 1367 SDL_memcpy(&pool->freeDescriptors[pool->freeDescriptorCount], cpuDescriptor, sizeof(D3D12StagingDescriptor)); 1368 pool->freeDescriptorCount += 1; 1369 SDL_UnlockMutex(pool->lock); 1370 } 1371} 1372 1373static void D3D12_INTERNAL_DestroyBuffer( 1374 D3D12Buffer *buffer) 1375{ 1376 if (!buffer) { 1377 return; 1378 } 1379 1380 if (buffer->mapPointer != NULL) { 1381 ID3D12Resource_Unmap( 1382 buffer->handle, 1383 0, 1384 NULL); 1385 } 1386 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1387 &buffer->srvDescriptor); 1388 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1389 &buffer->uavDescriptor); 1390 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1391 &buffer->cbvDescriptor); 1392 1393 if (buffer->handle) { 1394 ID3D12Resource_Release(buffer->handle); 1395 } 1396 SDL_free(buffer); 1397} 1398 1399static void D3D12_INTERNAL_ReleaseBuffer( 1400 D3D12Renderer *renderer, 1401 D3D12Buffer *buffer) 1402{ 1403 SDL_LockMutex(renderer->disposeLock); 1404 1405 EXPAND_ARRAY_IF_NEEDED( 1406 renderer->buffersToDestroy, 1407 D3D12Buffer *, 1408 renderer->buffersToDestroyCount + 1, 1409 renderer->buffersToDestroyCapacity, 1410 renderer->buffersToDestroyCapacity * 2); 1411 1412 renderer->buffersToDestroy[renderer->buffersToDestroyCount] = buffer; 1413 renderer->buffersToDestroyCount += 1; 1414 1415 SDL_UnlockMutex(renderer->disposeLock); 1416} 1417 1418static void D3D12_INTERNAL_ReleaseBufferContainer( 1419 D3D12Renderer *renderer, 1420 D3D12BufferContainer *container) 1421{ 1422 SDL_LockMutex(renderer->disposeLock); 1423 1424 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 1425 D3D12_INTERNAL_ReleaseBuffer( 1426 renderer, 1427 container->buffers[i]); 1428 } 1429 1430 // Containers are just client handles, so we can free immediately 1431 SDL_free(container->debugName); 1432 SDL_free(container->buffers); 1433 SDL_free(container); 1434 1435 SDL_UnlockMutex(renderer->disposeLock); 1436} 1437 1438static void D3D12_INTERNAL_DestroyTexture( 1439 D3D12Texture *texture) 1440{ 1441 if (!texture) { 1442 return; 1443 } 1444 for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { 1445 D3D12TextureSubresource *subresource = &texture->subresources[i]; 1446 if (subresource->rtvHandles) { 1447 for (Uint32 depthIndex = 0; depthIndex < subresource->depth; depthIndex += 1) { 1448 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1449 &subresource->rtvHandles[depthIndex]); 1450 } 1451 SDL_free(subresource->rtvHandles); 1452 } 1453 1454 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1455 &subresource->uavHandle); 1456 1457 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1458 &subresource->dsvHandle); 1459 } 1460 SDL_free(texture->subresources); 1461 1462 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1463 &texture->srvHandle); 1464 1465 // XR swapchain images are owned by the OpenXR runtime 1466 if (texture->resource && !texture->externallyManaged) { 1467 ID3D12Resource_Release(texture->resource); 1468 } 1469 1470 SDL_free(texture); 1471} 1472 1473static void D3D12_INTERNAL_ReleaseTexture( 1474 D3D12Renderer *renderer, 1475 D3D12Texture *texture) 1476{ 1477 SDL_LockMutex(renderer->disposeLock); 1478 1479 EXPAND_ARRAY_IF_NEEDED( 1480 renderer->texturesToDestroy, 1481 D3D12Texture *, 1482 renderer->texturesToDestroyCount + 1, 1483 renderer->texturesToDestroyCapacity, 1484 renderer->texturesToDestroyCapacity * 2); 1485 1486 renderer->texturesToDestroy[renderer->texturesToDestroyCount] = texture; 1487 renderer->texturesToDestroyCount += 1; 1488 1489 SDL_UnlockMutex(renderer->disposeLock); 1490} 1491 1492static void D3D12_INTERNAL_ReleaseTextureContainer( 1493 D3D12Renderer *renderer, 1494 D3D12TextureContainer *container) 1495{ 1496 SDL_LockMutex(renderer->disposeLock); 1497 1498 for (Uint32 i = 0; i < container->textureCount; i += 1) { 1499 D3D12_INTERNAL_ReleaseTexture( 1500 renderer, 1501 container->textures[i]); 1502 } 1503 1504 SDL_DestroyProperties(container->header.info.props); 1505 1506 // Containers are just client handles, so we can destroy immediately 1507 SDL_free(container->debugName); 1508 SDL_free(container->textures); 1509 SDL_free(container); 1510 1511 SDL_UnlockMutex(renderer->disposeLock); 1512} 1513 1514static void D3D12_INTERNAL_DestroySampler( 1515 D3D12Sampler *sampler) 1516{ 1517 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 1518 &sampler->handle); 1519 1520 SDL_free(sampler); 1521} 1522 1523static void D3D12_INTERNAL_DestroyGraphicsRootSignature( 1524 D3D12GraphicsRootSignature *rootSignature) 1525{ 1526 if (!rootSignature) { 1527 return; 1528 } 1529 if (rootSignature->handle) { 1530 ID3D12RootSignature_Release(rootSignature->handle); 1531 } 1532 SDL_free(rootSignature); 1533} 1534 1535static void D3D12_INTERNAL_DestroyGraphicsPipeline( 1536 D3D12GraphicsPipeline *graphicsPipeline) 1537{ 1538 if (graphicsPipeline->pipelineState) { 1539 ID3D12PipelineState_Release(graphicsPipeline->pipelineState); 1540 } 1541 D3D12_INTERNAL_DestroyGraphicsRootSignature(graphicsPipeline->rootSignature); 1542 SDL_free(graphicsPipeline); 1543} 1544 1545static void D3D12_INTERNAL_DestroyComputeRootSignature( 1546 D3D12ComputeRootSignature *rootSignature) 1547{ 1548 if (!rootSignature) { 1549 return; 1550 } 1551 if (rootSignature->handle) { 1552 ID3D12RootSignature_Release(rootSignature->handle); 1553 } 1554 SDL_free(rootSignature); 1555} 1556 1557static void D3D12_INTERNAL_DestroyComputePipeline( 1558 D3D12ComputePipeline *computePipeline) 1559{ 1560 if (computePipeline->pipelineState) { 1561 ID3D12PipelineState_Release(computePipeline->pipelineState); 1562 } 1563 D3D12_INTERNAL_DestroyComputeRootSignature(computePipeline->rootSignature); 1564 SDL_free(computePipeline); 1565} 1566 1567static void D3D12_INTERNAL_ReleaseFenceToPool( 1568 D3D12Renderer *renderer, 1569 D3D12Fence *fence) 1570{ 1571 SDL_LockMutex(renderer->fenceLock); 1572 1573 EXPAND_ARRAY_IF_NEEDED( 1574 renderer->availableFences, 1575 D3D12Fence *, 1576 renderer->availableFenceCount + 1, 1577 renderer->availableFenceCapacity, 1578 renderer->availableFenceCapacity * 2); 1579 1580 renderer->availableFences[renderer->availableFenceCount] = fence; 1581 renderer->availableFenceCount += 1; 1582 1583 SDL_UnlockMutex(renderer->fenceLock); 1584} 1585 1586static void D3D12_ReleaseFence( 1587 SDL_GPURenderer *driverData, 1588 SDL_GPUFence *fence) 1589{ 1590 D3D12Fence *d3d12Fence = (D3D12Fence *)fence; 1591 1592 if (SDL_AtomicDecRef(&d3d12Fence->referenceCount)) { 1593 D3D12_INTERNAL_ReleaseFenceToPool( 1594 (D3D12Renderer *)driverData, 1595 d3d12Fence); 1596 } 1597} 1598 1599static bool D3D12_QueryFence( 1600 SDL_GPURenderer *driverData, 1601 SDL_GPUFence *fence) 1602{ 1603 D3D12Fence *d3d12Fence = (D3D12Fence *)fence; 1604 return ID3D12Fence_GetCompletedValue(d3d12Fence->handle) == D3D12_FENCE_SIGNAL_VALUE; 1605} 1606 1607static void D3D12_INTERNAL_DestroyDescriptorHeap(D3D12DescriptorHeap *descriptorHeap) 1608{ 1609 if (!descriptorHeap) { 1610 return; 1611 } 1612 if (descriptorHeap->handle) { 1613 ID3D12DescriptorHeap_Release(descriptorHeap->handle); 1614 } 1615 SDL_free(descriptorHeap); 1616} 1617 1618static void D3D12_INTERNAL_DestroyStagingDescriptorPool( 1619 D3D12StagingDescriptorPool *pool) 1620{ 1621 for (Uint32 i = 0; i < pool->heapCount; i += 1) { 1622 D3D12_INTERNAL_DestroyDescriptorHeap(pool->heaps[i]); 1623 } 1624 SDL_free(pool->heaps); 1625 SDL_free(pool->freeDescriptors); 1626 SDL_DestroyMutex(pool->lock); 1627 1628 SDL_free(pool); 1629} 1630 1631static void D3D12_INTERNAL_DestroyCommandBuffer(D3D12CommandBuffer *commandBuffer) 1632{ 1633 if (!commandBuffer) { 1634 return; 1635 } 1636 if (commandBuffer->graphicsCommandList) { 1637 ID3D12GraphicsCommandList_Release(commandBuffer->graphicsCommandList); 1638 } 1639 if (commandBuffer->commandAllocator) { 1640 ID3D12CommandAllocator_Release(commandBuffer->commandAllocator); 1641 } 1642 SDL_free(commandBuffer->presentDatas); 1643 SDL_free(commandBuffer->usedTextures); 1644 SDL_free(commandBuffer->usedBuffers); 1645 SDL_free(commandBuffer->usedSamplers); 1646 SDL_free(commandBuffer->usedGraphicsPipelines); 1647 SDL_free(commandBuffer->usedComputePipelines); 1648 SDL_free(commandBuffer->usedDescriptorHeaps); 1649 SDL_free(commandBuffer->usedUniformBuffers); 1650 SDL_free(commandBuffer->textureDownloads); 1651 SDL_free(commandBuffer); 1652} 1653 1654static void D3D12_INTERNAL_DestroyFence(D3D12Fence *fence) 1655{ 1656 if (!fence) { 1657 return; 1658 } 1659 if (fence->handle) { 1660 ID3D12Fence_Release(fence->handle); 1661 } 1662 if (fence->event) { 1663 CloseHandle(fence->event); 1664 } 1665 SDL_free(fence); 1666} 1667 1668static void D3D12_INTERNAL_DestroyRenderer(D3D12Renderer *renderer) 1669{ 1670 // Release uniform buffers 1671 for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) { 1672 D3D12_INTERNAL_DestroyBuffer( 1673 renderer->uniformBufferPool[i]->buffer); 1674 SDL_free(renderer->uniformBufferPool[i]); 1675 } 1676 1677 // Clean up descriptor heaps 1678 for (Uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { 1679 if (renderer->stagingDescriptorPools[i]) { 1680 D3D12_INTERNAL_DestroyStagingDescriptorPool(renderer->stagingDescriptorPools[i]); 1681 renderer->stagingDescriptorPools[i] = NULL; 1682 } 1683 } 1684 1685 for (Uint32 i = 0; i < 2; i += 1) { 1686 if (renderer->gpuDescriptorHeapPools[i].heaps) { 1687 for (Uint32 j = 0; j < renderer->gpuDescriptorHeapPools[i].count; j += 1) { 1688 if (renderer->gpuDescriptorHeapPools[i].heaps[j]) { 1689 D3D12_INTERNAL_DestroyDescriptorHeap(renderer->gpuDescriptorHeapPools[i].heaps[j]); 1690 renderer->gpuDescriptorHeapPools[i].heaps[j] = NULL; 1691 } 1692 } 1693 SDL_free(renderer->gpuDescriptorHeapPools[i].heaps); 1694 } 1695 if (renderer->gpuDescriptorHeapPools[i].lock) { 1696 SDL_DestroyMutex(renderer->gpuDescriptorHeapPools[i].lock); 1697 renderer->gpuDescriptorHeapPools[i].lock = NULL; 1698 } 1699 } 1700 1701 // Release command buffers 1702 for (Uint32 i = 0; i < renderer->availableCommandBufferCount; i += 1) { 1703 if (renderer->availableCommandBuffers[i]) { 1704 D3D12_INTERNAL_DestroyCommandBuffer(renderer->availableCommandBuffers[i]); 1705 renderer->availableCommandBuffers[i] = NULL; 1706 } 1707 } 1708 1709 // Release fences 1710 for (Uint32 i = 0; i < renderer->availableFenceCount; i += 1) { 1711 if (renderer->availableFences[i]) { 1712 D3D12_INTERNAL_DestroyFence(renderer->availableFences[i]); 1713 renderer->availableFences[i] = NULL; 1714 } 1715 } 1716 1717 // Clean up allocations 1718 SDL_free(renderer->availableCommandBuffers); 1719 SDL_free(renderer->submittedCommandBuffers); 1720 SDL_free(renderer->uniformBufferPool); 1721 SDL_free(renderer->claimedWindows); 1722 SDL_free(renderer->availableFences); 1723 SDL_free(renderer->buffersToDestroy); 1724 SDL_free(renderer->texturesToDestroy); 1725 SDL_free(renderer->samplersToDestroy); 1726 SDL_free(renderer->graphicsPipelinesToDestroy); 1727 SDL_free(renderer->computePipelinesToDestroy); 1728 1729 SDL_DestroyProperties(renderer->props); 1730 1731 // Tear down D3D12 objects 1732 if (renderer->indirectDrawCommandSignature) { 1733 ID3D12CommandSignature_Release(renderer->indirectDrawCommandSignature); 1734 renderer->indirectDrawCommandSignature = NULL; 1735 } 1736 if (renderer->indirectIndexedDrawCommandSignature) { 1737 ID3D12CommandSignature_Release(renderer->indirectIndexedDrawCommandSignature); 1738 renderer->indirectIndexedDrawCommandSignature = NULL; 1739 } 1740 if (renderer->indirectDispatchCommandSignature) { 1741 ID3D12CommandSignature_Release(renderer->indirectDispatchCommandSignature); 1742 renderer->indirectDispatchCommandSignature = NULL; 1743 } 1744#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 1745 if (renderer->commandQueue) { 1746 ID3D12CommandQueue_Release(renderer->commandQueue); 1747 renderer->commandQueue = NULL; 1748 } 1749 if (renderer->device) { 1750 ID3D12Device_Release(renderer->device); 1751 renderer->device = NULL; 1752 } 1753 if (renderer->adapter) { 1754 IDXGIAdapter1_Release(renderer->adapter); 1755 renderer->adapter = NULL; 1756 } 1757 if (renderer->factory) { 1758 IDXGIFactory4_Release(renderer->factory); 1759 renderer->factory = NULL; 1760 } 1761 if (renderer->dxgiDebug) { 1762 IDXGIDebug_ReportLiveObjects( 1763 renderer->dxgiDebug, 1764 D3D_IID_DXGI_DEBUG_ALL, 1765 (DXGI_DEBUG_RLO_FLAGS)(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_DETAIL)); 1766 IDXGIDebug_Release(renderer->dxgiDebug); 1767 renderer->dxgiDebug = NULL; 1768 } 1769#endif 1770 if (renderer->d3d12_dll) { 1771 SDL_UnloadObject(renderer->d3d12_dll); 1772 renderer->d3d12_dll = NULL; 1773 } 1774#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 1775 if (renderer->dxgi_dll) { 1776 SDL_UnloadObject(renderer->dxgi_dll); 1777 renderer->dxgi_dll = NULL; 1778 } 1779 if (renderer->dxgidebug_dll) { 1780 SDL_UnloadObject(renderer->dxgidebug_dll); 1781 renderer->dxgidebug_dll = NULL; 1782 } 1783#endif 1784#ifdef USE_PIX_RUNTIME 1785 if (renderer->winpixeventruntime_dll) { 1786 SDL_UnloadObject(renderer->winpixeventruntime_dll); 1787 renderer->winpixeventruntime_dll = NULL; 1788 } 1789#endif 1790 renderer->pD3D12SerializeRootSignature = NULL; 1791 1792 if (renderer->iconv) { 1793 SDL_iconv_close(renderer->iconv); 1794 } 1795 1796 SDL_DestroyMutex(renderer->acquireCommandBufferLock); 1797 SDL_DestroyMutex(renderer->acquireUniformBufferLock); 1798 SDL_DestroyMutex(renderer->submitLock); 1799 SDL_DestroyMutex(renderer->windowLock); 1800 SDL_DestroyMutex(renderer->fenceLock); 1801 SDL_DestroyMutex(renderer->disposeLock); 1802 SDL_free(renderer->semantic); 1803 SDL_free(renderer); 1804} 1805 1806static void D3D12_DestroyDevice(SDL_GPUDevice *device) 1807{ 1808 D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; 1809 1810 // Release blit pipeline structures 1811 D3D12_INTERNAL_ReleaseBlitPipelines((SDL_GPURenderer *)renderer); 1812 1813 // Flush any remaining GPU work... 1814 D3D12_Wait((SDL_GPURenderer *)renderer); 1815 1816 // Release window data 1817 for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) { 1818 D3D12_ReleaseWindow((SDL_GPURenderer *)renderer, renderer->claimedWindows[i]->window); 1819 } 1820 1821 D3D12_INTERNAL_DestroyRenderer(renderer); 1822 SDL_free(device); 1823} 1824 1825static SDL_PropertiesID D3D12_GetDeviceProperties(SDL_GPUDevice *device) 1826{ 1827 D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; 1828 return renderer->props; 1829} 1830 1831// Barriers 1832 1833static inline Uint32 D3D12_INTERNAL_CalcSubresource( 1834 Uint32 mipLevel, 1835 Uint32 layer, 1836 Uint32 numLevels) 1837{ 1838 return mipLevel + (layer * numLevels); 1839} 1840 1841static void D3D12_INTERNAL_ResourceBarrier( 1842 D3D12CommandBuffer *commandBuffer, 1843 D3D12_RESOURCE_STATES sourceState, 1844 D3D12_RESOURCE_STATES destinationState, 1845 ID3D12Resource *resource, 1846 Uint32 subresourceIndex, 1847 bool needsUavBarrier) 1848{ 1849 D3D12_RESOURCE_BARRIER barrierDesc[2]; 1850 Uint32 numBarriers = 0; 1851 1852 // No transition barrier is needed if the state is not changing. 1853 if (sourceState != destinationState) { 1854 barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 1855 barrierDesc[numBarriers].Flags = (D3D12_RESOURCE_BARRIER_FLAGS)0; 1856 barrierDesc[numBarriers].Transition.StateBefore = sourceState; 1857 barrierDesc[numBarriers].Transition.StateAfter = destinationState; 1858 barrierDesc[numBarriers].Transition.pResource = resource; 1859 barrierDesc[numBarriers].Transition.Subresource = subresourceIndex; 1860 1861 numBarriers += 1; 1862 } 1863 1864 if (needsUavBarrier) { 1865 barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; 1866 barrierDesc[numBarriers].Flags = (D3D12_RESOURCE_BARRIER_FLAGS)0; 1867 barrierDesc[numBarriers].UAV.pResource = resource; 1868 1869 numBarriers += 1; 1870 } 1871 1872 if (numBarriers > 0) { 1873 ID3D12GraphicsCommandList_ResourceBarrier( 1874 commandBuffer->graphicsCommandList, 1875 numBarriers, 1876 barrierDesc); 1877 } 1878} 1879 1880static void D3D12_INTERNAL_TextureSubresourceBarrier( 1881 D3D12CommandBuffer *commandBuffer, 1882 D3D12_RESOURCE_STATES sourceState, 1883 D3D12_RESOURCE_STATES destinationState, 1884 D3D12TextureSubresource *textureSubresource) 1885{ 1886 bool needsUAVBarrier = 1887 (textureSubresource->parent->container->header.info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) || 1888 (textureSubresource->parent->container->header.info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE); 1889 1890 D3D12_INTERNAL_ResourceBarrier( 1891 commandBuffer, 1892 sourceState, 1893 destinationState, 1894 textureSubresource->parent->resource, 1895 textureSubresource->index, 1896 needsUAVBarrier); 1897} 1898 1899static D3D12_RESOURCE_STATES D3D12_INTERNAL_DefaultTextureResourceState( 1900 SDL_GPUTextureUsageFlags usageFlags) 1901{ 1902 // NOTE: order matters here! 1903 1904 if (usageFlags & SDL_GPU_TEXTUREUSAGE_SAMPLER) { 1905 return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; 1906 } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) { 1907 return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; 1908 } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 1909 return D3D12_RESOURCE_STATE_RENDER_TARGET; 1910 } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 1911 return D3D12_RESOURCE_STATE_DEPTH_WRITE; 1912 } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ) { 1913 return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; 1914 } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) { 1915 return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; 1916 } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) { 1917 return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; 1918 } else { 1919 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Texture has no default usage mode!"); 1920 return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; 1921 } 1922} 1923 1924static void D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 1925 D3D12CommandBuffer *commandBuffer, 1926 D3D12_RESOURCE_STATES destinationUsageMode, 1927 D3D12TextureSubresource *textureSubresource) 1928{ 1929 D3D12_INTERNAL_TextureSubresourceBarrier( 1930 commandBuffer, 1931 D3D12_INTERNAL_DefaultTextureResourceState(textureSubresource->parent->container->header.info.usage), 1932 destinationUsageMode, 1933 textureSubresource); 1934} 1935 1936static void D3D12_INTERNAL_TextureTransitionFromDefaultUsage( 1937 D3D12CommandBuffer *commandBuffer, 1938 D3D12_RESOURCE_STATES destinationUsageMode, 1939 D3D12Texture *texture) 1940{ 1941 for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { 1942 D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 1943 commandBuffer, 1944 destinationUsageMode, 1945 &texture->subresources[i]); 1946 } 1947} 1948 1949static void D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 1950 D3D12CommandBuffer *commandBuffer, 1951 D3D12_RESOURCE_STATES sourceUsageMode, 1952 D3D12TextureSubresource *textureSubresource) 1953{ 1954 D3D12_INTERNAL_TextureSubresourceBarrier( 1955 commandBuffer, 1956 sourceUsageMode, 1957 D3D12_INTERNAL_DefaultTextureResourceState(textureSubresource->parent->container->header.info.usage), 1958 textureSubresource); 1959} 1960 1961static void D3D12_INTERNAL_TextureTransitionToDefaultUsage( 1962 D3D12CommandBuffer *commandBuffer, 1963 D3D12_RESOURCE_STATES sourceUsageMode, 1964 D3D12Texture *texture) 1965{ 1966 for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { 1967 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 1968 commandBuffer, 1969 sourceUsageMode, 1970 &texture->subresources[i]); 1971 } 1972} 1973 1974static D3D12_RESOURCE_STATES D3D12_INTERNAL_DefaultBufferResourceState( 1975 D3D12Buffer *buffer) 1976{ 1977 if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_VERTEX) { 1978 return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; 1979 } else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_INDEX) { 1980 return D3D12_RESOURCE_STATE_INDEX_BUFFER; 1981 } else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) { 1982 return D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; 1983 } else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) { 1984 return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; 1985 } else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) { 1986 return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; 1987 } else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) { 1988 return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; 1989 } else { 1990 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Buffer has no default usage mode!"); 1991 return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; 1992 } 1993} 1994 1995static void D3D12_INTERNAL_BufferBarrier( 1996 D3D12CommandBuffer *commandBuffer, 1997 D3D12_RESOURCE_STATES sourceState, 1998 D3D12_RESOURCE_STATES destinationState, 1999 D3D12Buffer *buffer) 2000{ 2001 D3D12_INTERNAL_ResourceBarrier( 2002 commandBuffer, 2003 buffer->transitioned ? sourceState : D3D12_RESOURCE_STATE_COMMON, 2004 destinationState, 2005 buffer->handle, 2006 0, 2007 buffer->container->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE); 2008 2009 buffer->transitioned = true; 2010} 2011 2012static void D3D12_INTERNAL_BufferTransitionFromDefaultUsage( 2013 D3D12CommandBuffer *commandBuffer, 2014 D3D12_RESOURCE_STATES destinationState, 2015 D3D12Buffer *buffer) 2016{ 2017 D3D12_INTERNAL_BufferBarrier( 2018 commandBuffer, 2019 D3D12_INTERNAL_DefaultBufferResourceState(buffer), 2020 destinationState, 2021 buffer); 2022} 2023 2024static void D3D12_INTERNAL_BufferTransitionToDefaultUsage( 2025 D3D12CommandBuffer *commandBuffer, 2026 D3D12_RESOURCE_STATES sourceState, 2027 D3D12Buffer *buffer) 2028{ 2029 D3D12_INTERNAL_BufferBarrier( 2030 commandBuffer, 2031 sourceState, 2032 D3D12_INTERNAL_DefaultBufferResourceState(buffer), 2033 buffer); 2034} 2035 2036// Resource tracking 2037 2038#define TRACK_RESOURCE(resource, type, array, count, capacity) \ 2039 Uint32 i; \ 2040 \ 2041 for (i = 0; i < commandBuffer->count; i += 1) { \ 2042 if (commandBuffer->array[i] == resource) { \ 2043 return; \ 2044 } \ 2045 } \ 2046 \ 2047 if (commandBuffer->count == commandBuffer->capacity) { \ 2048 commandBuffer->capacity += 1; \ 2049 commandBuffer->array = (type *)SDL_realloc( \ 2050 commandBuffer->array, \ 2051 commandBuffer->capacity * sizeof(type)); \ 2052 } \ 2053 commandBuffer->array[commandBuffer->count] = resource; \ 2054 commandBuffer->count += 1; \ 2055 SDL_AtomicIncRef(&resource->referenceCount); 2056 2057static void D3D12_INTERNAL_TrackTexture( 2058 D3D12CommandBuffer *commandBuffer, 2059 D3D12Texture *texture) 2060{ 2061 TRACK_RESOURCE( 2062 texture, 2063 D3D12Texture *, 2064 usedTextures, 2065 usedTextureCount, 2066 usedTextureCapacity) 2067} 2068 2069static void D3D12_INTERNAL_TrackBuffer( 2070 D3D12CommandBuffer *commandBuffer, 2071 D3D12Buffer *buffer) 2072{ 2073 TRACK_RESOURCE( 2074 buffer, 2075 D3D12Buffer *, 2076 usedBuffers, 2077 usedBufferCount, 2078 usedBufferCapacity) 2079} 2080 2081static void D3D12_INTERNAL_TrackSampler( 2082 D3D12CommandBuffer *commandBuffer, 2083 D3D12Sampler *sampler) 2084{ 2085 TRACK_RESOURCE( 2086 sampler, 2087 D3D12Sampler *, 2088 usedSamplers, 2089 usedSamplerCount, 2090 usedSamplerCapacity) 2091} 2092 2093static void D3D12_INTERNAL_TrackGraphicsPipeline( 2094 D3D12CommandBuffer *commandBuffer, 2095 D3D12GraphicsPipeline *graphicsPipeline) 2096{ 2097 TRACK_RESOURCE( 2098 graphicsPipeline, 2099 D3D12GraphicsPipeline *, 2100 usedGraphicsPipelines, 2101 usedGraphicsPipelineCount, 2102 usedGraphicsPipelineCapacity) 2103} 2104 2105static void D3D12_INTERNAL_TrackComputePipeline( 2106 D3D12CommandBuffer *commandBuffer, 2107 D3D12ComputePipeline *computePipeline) 2108{ 2109 TRACK_RESOURCE( 2110 computePipeline, 2111 D3D12ComputePipeline *, 2112 usedComputePipelines, 2113 usedComputePipelineCount, 2114 usedComputePipelineCapacity) 2115} 2116 2117#undef TRACK_RESOURCE 2118 2119// Debug Naming 2120 2121static void D3D12_INTERNAL_SetPipelineStateName( 2122 D3D12Renderer *renderer, 2123 ID3D12PipelineState *pipelineState, 2124 const char *text 2125) { 2126 if (renderer->debug_mode && text != NULL) { 2127 WCHAR *wchar_text = WIN_UTF8ToStringW(text); 2128 ID3D12PipelineState_SetName( 2129 pipelineState, 2130 wchar_text); 2131 SDL_free(wchar_text); 2132 } 2133} 2134 2135static void D3D12_INTERNAL_SetResourceName( 2136 D3D12Renderer *renderer, 2137 ID3D12Resource *resource, 2138 const char *text 2139) { 2140 if (renderer->debug_mode && text != NULL) { 2141 WCHAR *wchar_text = WIN_UTF8ToStringW(text); 2142 ID3D12Resource_SetName( 2143 resource, 2144 wchar_text); 2145 SDL_free(wchar_text); 2146 } 2147} 2148 2149static void D3D12_SetBufferName( 2150 SDL_GPURenderer *driverData, 2151 SDL_GPUBuffer *buffer, 2152 const char *text) 2153{ 2154 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 2155 D3D12BufferContainer *container = (D3D12BufferContainer *)buffer; 2156 2157 if (renderer->debug_mode && text != NULL) { 2158 SDL_free(container->debugName); 2159 2160 container->debugName = SDL_strdup(text); 2161 2162 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 2163 D3D12_INTERNAL_SetResourceName( 2164 renderer, 2165 container->buffers[i]->handle, 2166 text); 2167 } 2168 } 2169} 2170 2171static void D3D12_SetTextureName( 2172 SDL_GPURenderer *driverData, 2173 SDL_GPUTexture *texture, 2174 const char *text) 2175{ 2176 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 2177 D3D12TextureContainer *container = (D3D12TextureContainer *)texture; 2178 2179 if (renderer->debug_mode && text != NULL) { 2180 SDL_free(container->debugName); 2181 2182 container->debugName = SDL_strdup(text); 2183 2184 for (Uint32 i = 0; i < container->textureCount; i += 1) { 2185 D3D12_INTERNAL_SetResourceName( 2186 renderer, 2187 container->textures[i]->resource, 2188 text); 2189 } 2190 } 2191} 2192 2193/* These debug functions now require the PIX runtime under Windows to avoid validation 2194 * layer errors. Calling them without the PIX runtime in your path is a no-op. 2195 */ 2196 2197static void D3D12_InsertDebugLabel( 2198 SDL_GPUCommandBuffer *commandBuffer, 2199 const char *text) 2200{ 2201 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 2202#ifdef USE_PIX_RUNTIME 2203 // Requires PIX runtime under Windows, no-op if DLL unavailable. 2204 WinPixEventRuntimeFns *fns = &d3d12CommandBuffer->renderer->winpixeventruntimeFns; 2205 if (fns->pSetMarkerOnCommandList) { 2206 fns->pSetMarkerOnCommandList(d3d12CommandBuffer->graphicsCommandList, 0 /*default color*/, text); 2207 } 2208#else 2209 WCHAR *wchar_text = WIN_UTF8ToStringW(text); 2210 2211 ID3D12GraphicsCommandList_SetMarker( 2212 d3d12CommandBuffer->graphicsCommandList, 2213 0, 2214 wchar_text, 2215 (UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR)); 2216 2217 SDL_free(wchar_text); 2218#endif 2219} 2220 2221static void D3D12_PushDebugGroup( 2222 SDL_GPUCommandBuffer *commandBuffer, 2223 const char *name) 2224{ 2225 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 2226#ifdef USE_PIX_RUNTIME 2227 // Requires PIX runtime under Windows, no-op if DLL unavailable. 2228 WinPixEventRuntimeFns *fns = &d3d12CommandBuffer->renderer->winpixeventruntimeFns; 2229 if (fns->pBeginEventOnCommandList) { 2230 fns->pBeginEventOnCommandList(d3d12CommandBuffer->graphicsCommandList, 0 /*default color*/, name); 2231 } 2232#else 2233 WCHAR *wchar_text = WIN_UTF8ToStringW(name); 2234 2235 ID3D12GraphicsCommandList_BeginEvent( 2236 d3d12CommandBuffer->graphicsCommandList, 2237 0, 2238 wchar_text, 2239 (UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR)); 2240 2241 SDL_free(wchar_text); 2242#endif 2243} 2244 2245static void D3D12_PopDebugGroup( 2246 SDL_GPUCommandBuffer *commandBuffer) 2247{ 2248 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 2249#ifdef USE_PIX_RUNTIME 2250 // Requires PIX runtime under Windows, no-op if DLL unavailable. 2251 WinPixEventRuntimeFns *fns = &d3d12CommandBuffer->renderer->winpixeventruntimeFns; 2252 if (fns->pEndEventOnCommandList) { 2253 fns->pEndEventOnCommandList(d3d12CommandBuffer->graphicsCommandList); 2254 } 2255#else 2256 ID3D12GraphicsCommandList_EndEvent(d3d12CommandBuffer->graphicsCommandList); 2257#endif 2258} 2259 2260// State Creation 2261 2262static D3D12DescriptorHeap *D3D12_INTERNAL_CreateDescriptorHeap( 2263 D3D12Renderer *renderer, 2264 D3D12_DESCRIPTOR_HEAP_TYPE type, 2265 Uint32 descriptorCount, 2266 bool staging) 2267{ 2268 D3D12DescriptorHeap *heap; 2269 ID3D12DescriptorHeap *handle; 2270 D3D12_DESCRIPTOR_HEAP_DESC heapDesc; 2271 HRESULT res; 2272 2273 heap = (D3D12DescriptorHeap *)SDL_calloc(1, sizeof(D3D12DescriptorHeap)); 2274 if (!heap) { 2275 return NULL; 2276 } 2277 2278 heap->currentDescriptorIndex = 0; 2279 2280 heapDesc.NumDescriptors = descriptorCount; 2281 heapDesc.Type = type; 2282 heapDesc.Flags = staging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; 2283 heapDesc.NodeMask = 0; 2284 2285 res = ID3D12Device_CreateDescriptorHeap( 2286 renderer->device, 2287 &heapDesc, 2288 D3D_GUID(D3D_IID_ID3D12DescriptorHeap), 2289 (void **)&handle); 2290 2291 if (FAILED(res)) { 2292 D3D12_INTERNAL_SetError(renderer, "Failed to create descriptor heap!", res); 2293 D3D12_INTERNAL_DestroyDescriptorHeap(heap); 2294 return NULL; 2295 } 2296 2297 heap->handle = handle; 2298 heap->heapType = type; 2299 heap->maxDescriptors = descriptorCount; 2300 heap->staging = staging; 2301 heap->descriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(renderer->device, type); 2302 D3D_CALL_RET(handle, GetCPUDescriptorHandleForHeapStart, &heap->descriptorHeapCPUStart); 2303 if (!staging) { 2304 D3D_CALL_RET(handle, GetGPUDescriptorHandleForHeapStart, &heap->descriptorHeapGPUStart); 2305 } 2306 2307 return heap; 2308} 2309 2310static D3D12StagingDescriptorPool *D3D12_INTERNAL_CreateStagingDescriptorPool( 2311 D3D12Renderer *renderer, 2312 D3D12_DESCRIPTOR_HEAP_TYPE heapType 2313) { 2314 D3D12DescriptorHeap *heap = D3D12_INTERNAL_CreateDescriptorHeap( 2315 renderer, 2316 heapType, 2317 STAGING_HEAP_DESCRIPTOR_COUNT, 2318 true); 2319 2320 if (!heap) { 2321 return NULL; 2322 } 2323 2324 D3D12StagingDescriptorPool *pool = (D3D12StagingDescriptorPool *)SDL_calloc(1, sizeof(D3D12StagingDescriptorPool)); 2325 2326 pool->heapCount = 1; 2327 pool->heaps = (D3D12DescriptorHeap **)SDL_malloc(sizeof(D3D12DescriptorHeap *)); 2328 pool->heaps[0] = heap; 2329 2330 pool->freeDescriptorCapacity = STAGING_HEAP_DESCRIPTOR_COUNT; 2331 pool->freeDescriptorCount = STAGING_HEAP_DESCRIPTOR_COUNT; 2332 pool->freeDescriptors = (D3D12StagingDescriptor *)SDL_malloc(STAGING_HEAP_DESCRIPTOR_COUNT * sizeof(D3D12StagingDescriptor)); 2333 2334 for (Uint32 i = 0; i < STAGING_HEAP_DESCRIPTOR_COUNT; i += 1) { 2335 pool->freeDescriptors[i].pool = pool; 2336 pool->freeDescriptors[i].heap = heap; 2337 pool->freeDescriptors[i].cpuHandleIndex = i; 2338 pool->freeDescriptors[i].cpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (i * heap->descriptorSize); 2339 } 2340 2341 pool->lock = SDL_CreateMutex(); 2342 2343 return pool; 2344} 2345 2346/* If the pool is empty, we need to refill it! */ 2347static bool D3D12_INTERNAL_ExpandStagingDescriptorPool( 2348 D3D12Renderer *renderer, 2349 D3D12StagingDescriptorPool *pool 2350) { 2351 D3D12DescriptorHeap *heap = D3D12_INTERNAL_CreateDescriptorHeap( 2352 renderer, 2353 pool->heaps[0]->heapType, 2354 STAGING_HEAP_DESCRIPTOR_COUNT, 2355 true); 2356 2357 if (!heap) { 2358 return false; 2359 } 2360 2361 pool->heapCount += 1; 2362 pool->heaps = (D3D12DescriptorHeap **)SDL_realloc(pool->heaps, pool->heapCount * sizeof(D3D12DescriptorHeap *)); 2363 pool->heaps[pool->heapCount - 1] = heap; 2364 2365 pool->freeDescriptorCapacity += STAGING_HEAP_DESCRIPTOR_COUNT; 2366 pool->freeDescriptorCount += STAGING_HEAP_DESCRIPTOR_COUNT; 2367 pool->freeDescriptors = (D3D12StagingDescriptor *)SDL_realloc(pool->freeDescriptors, pool->freeDescriptorCapacity * sizeof(D3D12StagingDescriptor)); 2368 2369 for (Uint32 i = 0; i < STAGING_HEAP_DESCRIPTOR_COUNT; i += 1) { 2370 pool->freeDescriptors[i].pool = pool; 2371 pool->freeDescriptors[i].heap = heap; 2372 pool->freeDescriptors[i].cpuHandleIndex = i; 2373 pool->freeDescriptors[i].cpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (i * heap->descriptorSize); 2374 } 2375 2376 return true; 2377} 2378 2379static void D3D12_INTERNAL_TrackGPUDescriptorHeap( 2380 D3D12CommandBuffer *commandBuffer, 2381 D3D12DescriptorHeap *descriptorHeap) 2382{ 2383 Uint32 i; 2384 for (i = 0; i < commandBuffer->usedDescriptorHeapCount; i += 1) { 2385 if (commandBuffer->usedDescriptorHeaps[i] == descriptorHeap) { 2386 return; 2387 } 2388 } 2389 2390 if (commandBuffer->usedDescriptorHeapCount == commandBuffer->usedDescriptorHeapCapacity) { 2391 commandBuffer->usedDescriptorHeapCapacity += 1; 2392 commandBuffer->usedDescriptorHeaps = (D3D12DescriptorHeap **)SDL_realloc( 2393 commandBuffer->usedDescriptorHeaps, 2394 commandBuffer->usedDescriptorHeapCapacity * sizeof(D3D12DescriptorHeap *)); 2395 } 2396 2397 commandBuffer->usedDescriptorHeaps[commandBuffer->usedDescriptorHeapCount] = descriptorHeap; 2398 commandBuffer->usedDescriptorHeapCount += 1; 2399} 2400 2401static D3D12DescriptorHeap *D3D12_INTERNAL_AcquireGPUDescriptorHeapFromPool( 2402 D3D12CommandBuffer *commandBuffer, 2403 D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType) 2404{ 2405 D3D12DescriptorHeap *result; 2406 D3D12Renderer *renderer = commandBuffer->renderer; 2407 D3D12GPUDescriptorHeapPool *pool = &renderer->gpuDescriptorHeapPools[descriptorHeapType]; 2408 2409 SDL_LockMutex(pool->lock); 2410 if (pool->count > 0) { 2411 result = pool->heaps[pool->count - 1]; 2412 pool->count -= 1; 2413 } else { 2414 result = D3D12_INTERNAL_CreateDescriptorHeap( 2415 renderer, 2416 descriptorHeapType, 2417 descriptorHeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ? VIEW_GPU_DESCRIPTOR_COUNT : SAMPLER_GPU_DESCRIPTOR_COUNT, 2418 false); 2419 } 2420 SDL_UnlockMutex(pool->lock); 2421 2422 D3D12_INTERNAL_TrackGPUDescriptorHeap(commandBuffer, result); 2423 return result; 2424} 2425 2426static void D3D12_INTERNAL_ReturnGPUDescriptorHeapToPool( 2427 D3D12Renderer *renderer, 2428 D3D12DescriptorHeap *heap) 2429{ 2430 if (heap == NULL) { 2431 return; 2432 } 2433 2434 D3D12GPUDescriptorHeapPool *pool = &renderer->gpuDescriptorHeapPools[heap->heapType]; 2435 2436 heap->currentDescriptorIndex = 0; 2437 2438 SDL_LockMutex(pool->lock); 2439 if (pool->count >= pool->capacity) { 2440 pool->capacity *= 2; 2441 pool->heaps = (D3D12DescriptorHeap **)SDL_realloc( 2442 pool->heaps, 2443 pool->capacity * sizeof(D3D12DescriptorHeap *)); 2444 } 2445 2446 pool->heaps[pool->count] = heap; 2447 pool->count += 1; 2448 SDL_UnlockMutex(pool->lock); 2449} 2450 2451/* 2452 * The root signature lets us define "root parameters" which are essentially bind points for resources. 2453 * These let us define the register ranges as well as the register "space". 2454 * The register space is akin to the descriptor set index in Vulkan, which allows us to group resources 2455 * by stage so that the registers from the vertex and fragment shaders don't clobber each other. 2456 * 2457 * Most of our root parameters are implemented as "descriptor tables" so we can 2458 * copy and then point to contiguous descriptor regions. 2459 * Uniform buffers are the exception - these have to be implemented as raw "root descriptors" so 2460 * that we can dynamically update the address that the constant buffer view points to. 2461 * 2462 * The root signature has a maximum size of 64 DWORDs. 2463 * A descriptor table uses 1 DWORD. 2464 * A root descriptor uses 2 DWORDS. 2465 * This means our biggest root signature uses 24 DWORDs total, well under the limit. 2466 * 2467 * The root parameter indices are created dynamically and stored in the D3D12GraphicsRootSignature struct. 2468 */ 2469static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature( 2470 D3D12Renderer *renderer, 2471 D3D12Shader *vertexShader, 2472 D3D12Shader *fragmentShader) 2473{ 2474 // FIXME: I think the max can be smaller... 2475 D3D12_ROOT_PARAMETER rootParameters[MAX_ROOT_SIGNATURE_PARAMETERS]; 2476 D3D12_DESCRIPTOR_RANGE descriptorRanges[MAX_ROOT_SIGNATURE_PARAMETERS]; 2477 Uint32 parameterCount = 0; 2478 Uint32 rangeCount = 0; 2479 D3D12_DESCRIPTOR_RANGE descriptorRange; 2480 D3D12_ROOT_PARAMETER rootParameter; 2481 D3D12GraphicsRootSignature *d3d12GraphicsRootSignature = 2482 (D3D12GraphicsRootSignature *)SDL_calloc(1, sizeof(D3D12GraphicsRootSignature)); 2483 if (!d3d12GraphicsRootSignature) { 2484 return NULL; 2485 } 2486 2487 SDL_zeroa(rootParameters); 2488 SDL_zeroa(descriptorRanges); 2489 SDL_zero(rootParameter); 2490 2491 d3d12GraphicsRootSignature->vertexSamplerRootIndex = -1; 2492 d3d12GraphicsRootSignature->vertexSamplerTextureRootIndex = -1; 2493 d3d12GraphicsRootSignature->vertexStorageTextureRootIndex = -1; 2494 d3d12GraphicsRootSignature->vertexStorageBufferRootIndex = -1; 2495 2496 d3d12GraphicsRootSignature->fragmentSamplerRootIndex = -1; 2497 d3d12GraphicsRootSignature->fragmentSamplerTextureRootIndex = -1; 2498 d3d12GraphicsRootSignature->fragmentStorageTextureRootIndex = -1; 2499 d3d12GraphicsRootSignature->fragmentStorageBufferRootIndex = -1; 2500 2501 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 2502 d3d12GraphicsRootSignature->vertexUniformBufferRootIndex[i] = -1; 2503 d3d12GraphicsRootSignature->fragmentUniformBufferRootIndex[i] = -1; 2504 } 2505 2506 if (vertexShader->num_samplers > 0) { 2507 // Vertex Samplers 2508 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; 2509 descriptorRange.NumDescriptors = vertexShader->num_samplers; 2510 descriptorRange.BaseShaderRegister = 0; 2511 descriptorRange.RegisterSpace = 0; 2512 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2513 descriptorRanges[rangeCount] = descriptorRange; 2514 2515 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2516 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2517 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2518 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; 2519 rootParameters[parameterCount] = rootParameter; 2520 d3d12GraphicsRootSignature->vertexSamplerRootIndex = parameterCount; 2521 rangeCount += 1; 2522 parameterCount += 1; 2523 2524 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2525 descriptorRange.NumDescriptors = vertexShader->num_samplers; 2526 descriptorRange.BaseShaderRegister = 0; 2527 descriptorRange.RegisterSpace = 0; 2528 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2529 descriptorRanges[rangeCount] = descriptorRange; 2530 2531 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2532 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2533 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2534 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; 2535 rootParameters[parameterCount] = rootParameter; 2536 d3d12GraphicsRootSignature->vertexSamplerTextureRootIndex = parameterCount; 2537 rangeCount += 1; 2538 parameterCount += 1; 2539 } 2540 2541 if (vertexShader->numStorageTextures) { 2542 // Vertex storage textures 2543 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2544 descriptorRange.NumDescriptors = vertexShader->numStorageTextures; 2545 descriptorRange.BaseShaderRegister = vertexShader->num_samplers; 2546 descriptorRange.RegisterSpace = 0; 2547 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2548 descriptorRanges[rangeCount] = descriptorRange; 2549 2550 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2551 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2552 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2553 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; 2554 rootParameters[parameterCount] = rootParameter; 2555 d3d12GraphicsRootSignature->vertexStorageTextureRootIndex = parameterCount; 2556 rangeCount += 1; 2557 parameterCount += 1; 2558 } 2559 2560 if (vertexShader->numStorageBuffers) { 2561 2562 // Vertex storage buffers 2563 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2564 descriptorRange.NumDescriptors = vertexShader->numStorageBuffers; 2565 descriptorRange.BaseShaderRegister = vertexShader->num_samplers + vertexShader->numStorageTextures; 2566 descriptorRange.RegisterSpace = 0; 2567 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2568 descriptorRanges[rangeCount] = descriptorRange; 2569 2570 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2571 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2572 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2573 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; 2574 rootParameters[parameterCount] = rootParameter; 2575 d3d12GraphicsRootSignature->vertexStorageBufferRootIndex = parameterCount; 2576 rangeCount += 1; 2577 parameterCount += 1; 2578 } 2579 2580 // Vertex Uniforms 2581 for (Uint32 i = 0; i < vertexShader->numUniformBuffers; i += 1) { 2582 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; 2583 rootParameter.Descriptor.ShaderRegister = i; 2584 rootParameter.Descriptor.RegisterSpace = 1; 2585 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; 2586 rootParameters[parameterCount] = rootParameter; 2587 d3d12GraphicsRootSignature->vertexUniformBufferRootIndex[i] = parameterCount; 2588 parameterCount += 1; 2589 } 2590 2591 if (fragmentShader->num_samplers) { 2592 // Fragment Samplers 2593 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; 2594 descriptorRange.NumDescriptors = fragmentShader->num_samplers; 2595 descriptorRange.BaseShaderRegister = 0; 2596 descriptorRange.RegisterSpace = 2; 2597 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2598 descriptorRanges[rangeCount] = descriptorRange; 2599 2600 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2601 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2602 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2603 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; 2604 rootParameters[parameterCount] = rootParameter; 2605 d3d12GraphicsRootSignature->fragmentSamplerRootIndex = parameterCount; 2606 rangeCount += 1; 2607 parameterCount += 1; 2608 2609 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2610 descriptorRange.NumDescriptors = fragmentShader->num_samplers; 2611 descriptorRange.BaseShaderRegister = 0; 2612 descriptorRange.RegisterSpace = 2; 2613 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2614 descriptorRanges[rangeCount] = descriptorRange; 2615 2616 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2617 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2618 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2619 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; 2620 rootParameters[parameterCount] = rootParameter; 2621 d3d12GraphicsRootSignature->fragmentSamplerTextureRootIndex = parameterCount; 2622 rangeCount += 1; 2623 parameterCount += 1; 2624 } 2625 2626 if (fragmentShader->numStorageTextures) { 2627 // Fragment Storage Textures 2628 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2629 descriptorRange.NumDescriptors = fragmentShader->numStorageTextures; 2630 descriptorRange.BaseShaderRegister = fragmentShader->num_samplers; 2631 descriptorRange.RegisterSpace = 2; 2632 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2633 descriptorRanges[rangeCount] = descriptorRange; 2634 2635 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2636 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2637 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2638 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; 2639 rootParameters[parameterCount] = rootParameter; 2640 d3d12GraphicsRootSignature->fragmentStorageTextureRootIndex = parameterCount; 2641 rangeCount += 1; 2642 parameterCount += 1; 2643 } 2644 2645 if (fragmentShader->numStorageBuffers) { 2646 // Fragment Storage Buffers 2647 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2648 descriptorRange.NumDescriptors = fragmentShader->numStorageBuffers; 2649 descriptorRange.BaseShaderRegister = fragmentShader->num_samplers + fragmentShader->numStorageTextures; 2650 descriptorRange.RegisterSpace = 2; 2651 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2652 descriptorRanges[rangeCount] = descriptorRange; 2653 2654 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2655 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2656 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2657 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; 2658 rootParameters[parameterCount] = rootParameter; 2659 d3d12GraphicsRootSignature->fragmentStorageBufferRootIndex = parameterCount; 2660 rangeCount += 1; 2661 parameterCount += 1; 2662 } 2663 2664 // Fragment Uniforms 2665 for (Uint32 i = 0; i < fragmentShader->numUniformBuffers; i += 1) { 2666 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; 2667 rootParameter.Descriptor.ShaderRegister = i; 2668 rootParameter.Descriptor.RegisterSpace = 3; 2669 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; 2670 rootParameters[parameterCount] = rootParameter; 2671 d3d12GraphicsRootSignature->fragmentUniformBufferRootIndex[i] = parameterCount; 2672 parameterCount += 1; 2673 } 2674 2675 // FIXME: shouldn't have to assert here 2676 SDL_assert(parameterCount <= MAX_ROOT_SIGNATURE_PARAMETERS); 2677 SDL_assert(rangeCount <= MAX_ROOT_SIGNATURE_PARAMETERS); 2678 2679 // Create the root signature description 2680 D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; 2681 rootSignatureDesc.NumParameters = parameterCount; 2682 rootSignatureDesc.pParameters = rootParameters; 2683 rootSignatureDesc.NumStaticSamplers = 0; 2684 rootSignatureDesc.pStaticSamplers = NULL; 2685 rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; 2686 2687 // Serialize the root signature 2688 ID3DBlob *serializedRootSignature; 2689 ID3DBlob *errorBlob; 2690 HRESULT res = renderer->pD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSignature, &errorBlob); 2691 2692 if (FAILED(res)) { 2693 if (errorBlob) { 2694 SET_ERROR("Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); 2695 ID3D10Blob_Release(errorBlob); 2696 } 2697 D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); 2698 return NULL; 2699 } 2700 2701 // Create the root signature 2702 ID3D12RootSignature *rootSignature; 2703 2704 res = ID3D12Device_CreateRootSignature( 2705 renderer->device, 2706 0, 2707 ID3D10Blob_GetBufferPointer(serializedRootSignature), 2708 ID3D10Blob_GetBufferSize(serializedRootSignature), 2709 D3D_GUID(D3D_IID_ID3D12RootSignature), 2710 (void **)&rootSignature); 2711 2712 if (FAILED(res)) { 2713 if (errorBlob) { 2714 SET_ERROR("Failed to create RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); 2715 ID3D10Blob_Release(errorBlob); 2716 } 2717 D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); 2718 return NULL; 2719 } 2720 2721 d3d12GraphicsRootSignature->handle = rootSignature; 2722 return d3d12GraphicsRootSignature; 2723} 2724 2725static bool D3D12_INTERNAL_IsValidShaderBytecode( 2726 const Uint8 *code, 2727 size_t codeSize) 2728{ 2729 // Both DXIL and DXBC bytecode have a 4 byte header containing `DXBC`. 2730 if (codeSize < 4 || code == NULL) { 2731 return false; 2732 } 2733 return SDL_memcmp(code, "DXBC", 4) == 0; 2734} 2735 2736static bool D3D12_INTERNAL_CreateShaderBytecode( 2737 D3D12Renderer *renderer, 2738 const Uint8 *code, 2739 size_t codeSize, 2740 SDL_GPUShaderFormat format, 2741 void **pBytecode, 2742 size_t *pBytecodeSize) 2743{ 2744 if (!D3D12_INTERNAL_IsValidShaderBytecode(code, codeSize)) { 2745 if (format == SDL_GPU_SHADERFORMAT_DXBC) { 2746 SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid DXBC!", false); 2747 } 2748 SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid DXIL!", false); 2749 } 2750 2751 if (pBytecode != NULL) { 2752 *pBytecode = SDL_malloc(codeSize); 2753 if (!*pBytecode) { 2754 return false; 2755 } 2756 SDL_memcpy(*pBytecode, code, codeSize); 2757 *pBytecodeSize = codeSize; 2758 } 2759 2760 return true; 2761} 2762 2763static D3D12ComputeRootSignature *D3D12_INTERNAL_CreateComputeRootSignature( 2764 D3D12Renderer *renderer, 2765 const SDL_GPUComputePipelineCreateInfo *createInfo) 2766{ 2767 // FIXME: I think the max can be smaller... 2768 D3D12_ROOT_PARAMETER rootParameters[MAX_ROOT_SIGNATURE_PARAMETERS]; 2769 D3D12_DESCRIPTOR_RANGE descriptorRanges[MAX_ROOT_SIGNATURE_PARAMETERS]; 2770 Uint32 parameterCount = 0; 2771 Uint32 rangeCount = 0; 2772 D3D12_DESCRIPTOR_RANGE descriptorRange; 2773 D3D12_ROOT_PARAMETER rootParameter; 2774 D3D12ComputeRootSignature *d3d12ComputeRootSignature = 2775 (D3D12ComputeRootSignature *)SDL_calloc(1, sizeof(D3D12ComputeRootSignature)); 2776 if (!d3d12ComputeRootSignature) { 2777 return NULL; 2778 } 2779 2780 SDL_zeroa(rootParameters); 2781 SDL_zeroa(descriptorRanges); 2782 SDL_zero(rootParameter); 2783 2784 d3d12ComputeRootSignature->samplerRootIndex = -1; 2785 d3d12ComputeRootSignature->samplerTextureRootIndex = -1; 2786 d3d12ComputeRootSignature->readOnlyStorageTextureRootIndex = -1; 2787 d3d12ComputeRootSignature->readOnlyStorageBufferRootIndex = -1; 2788 d3d12ComputeRootSignature->readWriteStorageTextureRootIndex = -1; 2789 d3d12ComputeRootSignature->readWriteStorageBufferRootIndex = -1; 2790 2791 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 2792 d3d12ComputeRootSignature->uniformBufferRootIndex[i] = -1; 2793 } 2794 2795 if (createInfo->num_samplers) { 2796 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; 2797 descriptorRange.NumDescriptors = createInfo->num_samplers; 2798 descriptorRange.BaseShaderRegister = 0; 2799 descriptorRange.RegisterSpace = 0; 2800 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2801 descriptorRanges[rangeCount] = descriptorRange; 2802 2803 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2804 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2805 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2806 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2807 rootParameters[parameterCount] = rootParameter; 2808 d3d12ComputeRootSignature->samplerRootIndex = parameterCount; 2809 rangeCount += 1; 2810 parameterCount += 1; 2811 2812 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2813 descriptorRange.NumDescriptors = createInfo->num_samplers; 2814 descriptorRange.BaseShaderRegister = 0; 2815 descriptorRange.RegisterSpace = 0; 2816 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2817 descriptorRanges[rangeCount] = descriptorRange; 2818 2819 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2820 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2821 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2822 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2823 rootParameters[parameterCount] = rootParameter; 2824 d3d12ComputeRootSignature->samplerTextureRootIndex = parameterCount; 2825 rangeCount += 1; 2826 parameterCount += 1; 2827 } 2828 2829 if (createInfo->num_readonly_storage_textures) { 2830 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2831 descriptorRange.NumDescriptors = createInfo->num_readonly_storage_textures; 2832 descriptorRange.BaseShaderRegister = createInfo->num_samplers; 2833 descriptorRange.RegisterSpace = 0; 2834 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2835 descriptorRanges[rangeCount] = descriptorRange; 2836 2837 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2838 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2839 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2840 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2841 rootParameters[parameterCount] = rootParameter; 2842 d3d12ComputeRootSignature->readOnlyStorageTextureRootIndex = parameterCount; 2843 rangeCount += 1; 2844 parameterCount += 1; 2845 } 2846 2847 if (createInfo->num_readonly_storage_buffers) { 2848 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; 2849 descriptorRange.NumDescriptors = createInfo->num_readonly_storage_buffers; 2850 descriptorRange.BaseShaderRegister = createInfo->num_samplers + createInfo->num_readonly_storage_textures; 2851 descriptorRange.RegisterSpace = 0; 2852 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2853 descriptorRanges[rangeCount] = descriptorRange; 2854 2855 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2856 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2857 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2858 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2859 rootParameters[parameterCount] = rootParameter; 2860 d3d12ComputeRootSignature->readOnlyStorageBufferRootIndex = parameterCount; 2861 rangeCount += 1; 2862 parameterCount += 1; 2863 } 2864 2865 if (createInfo->num_readwrite_storage_textures) { 2866 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; 2867 descriptorRange.NumDescriptors = createInfo->num_readwrite_storage_textures; 2868 descriptorRange.BaseShaderRegister = 0; 2869 descriptorRange.RegisterSpace = 1; 2870 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2871 descriptorRanges[rangeCount] = descriptorRange; 2872 2873 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2874 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2875 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2876 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2877 rootParameters[parameterCount] = rootParameter; 2878 d3d12ComputeRootSignature->readWriteStorageTextureRootIndex = parameterCount; 2879 rangeCount += 1; 2880 parameterCount += 1; 2881 } 2882 2883 if (createInfo->num_readwrite_storage_buffers) { 2884 descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; 2885 descriptorRange.NumDescriptors = createInfo->num_readwrite_storage_buffers; 2886 descriptorRange.BaseShaderRegister = createInfo->num_readwrite_storage_textures; 2887 descriptorRange.RegisterSpace = 1; 2888 descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 2889 descriptorRanges[rangeCount] = descriptorRange; 2890 2891 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 2892 rootParameter.DescriptorTable.NumDescriptorRanges = 1; 2893 rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; 2894 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2895 rootParameters[parameterCount] = rootParameter; 2896 d3d12ComputeRootSignature->readWriteStorageBufferRootIndex = parameterCount; 2897 rangeCount += 1; 2898 parameterCount += 1; 2899 } 2900 2901 for (Uint32 i = 0; i < createInfo->num_uniform_buffers; i += 1) { 2902 rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; 2903 rootParameter.Descriptor.ShaderRegister = i; 2904 rootParameter.Descriptor.RegisterSpace = 2; 2905 rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute 2906 rootParameters[parameterCount] = rootParameter; 2907 d3d12ComputeRootSignature->uniformBufferRootIndex[i] = parameterCount; 2908 parameterCount += 1; 2909 } 2910 2911 D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; 2912 rootSignatureDesc.NumParameters = parameterCount; 2913 rootSignatureDesc.pParameters = rootParameters; 2914 rootSignatureDesc.NumStaticSamplers = 0; 2915 rootSignatureDesc.pStaticSamplers = NULL; 2916 rootSignatureDesc.Flags = (D3D12_ROOT_SIGNATURE_FLAGS)0; 2917 2918 ID3DBlob *serializedRootSignature; 2919 ID3DBlob *errorBlob; 2920 HRESULT res = renderer->pD3D12SerializeRootSignature( 2921 &rootSignatureDesc, 2922 D3D_ROOT_SIGNATURE_VERSION_1, 2923 &serializedRootSignature, 2924 &errorBlob); 2925 2926 if (FAILED(res)) { 2927 if (errorBlob) { 2928 SET_ERROR("Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); 2929 ID3D10Blob_Release(errorBlob); 2930 } 2931 D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature); 2932 return NULL; 2933 } 2934 2935 ID3D12RootSignature *rootSignature; 2936 2937 res = ID3D12Device_CreateRootSignature( 2938 renderer->device, 2939 0, 2940 ID3D10Blob_GetBufferPointer(serializedRootSignature), 2941 ID3D10Blob_GetBufferSize(serializedRootSignature), 2942 D3D_GUID(D3D_IID_ID3D12RootSignature), 2943 (void **)&rootSignature); 2944 2945 if (FAILED(res)) { 2946 if (errorBlob) { 2947 SET_ERROR("Failed to create RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); 2948 ID3D10Blob_Release(errorBlob); 2949 } 2950 D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature); 2951 return NULL; 2952 } 2953 2954 d3d12ComputeRootSignature->handle = rootSignature; 2955 return d3d12ComputeRootSignature; 2956} 2957 2958static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( 2959 SDL_GPURenderer *driverData, 2960 const SDL_GPUComputePipelineCreateInfo *createinfo) 2961{ 2962 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 2963 ID3D12PipelineState *pipelineState; 2964 2965 if (!D3D12_INTERNAL_CreateShaderBytecode( 2966 renderer, 2967 createinfo->code, 2968 createinfo->code_size, 2969 createinfo->format, 2970 NULL, 2971 NULL)) { 2972 return NULL; 2973 } 2974 2975 D3D12ComputeRootSignature *rootSignature = D3D12_INTERNAL_CreateComputeRootSignature( 2976 renderer, 2977 createinfo); 2978 2979 if (rootSignature == NULL) { 2980 SET_STRING_ERROR_AND_RETURN("Could not create root signature!", NULL); 2981 } 2982 2983 D3D12_COMPUTE_PIPELINE_STATE_DESC pipelineDesc; 2984 pipelineDesc.CS.pShaderBytecode = createinfo->code; 2985 pipelineDesc.CS.BytecodeLength = createinfo->code_size; 2986 pipelineDesc.pRootSignature = rootSignature->handle; 2987 pipelineDesc.CachedPSO.CachedBlobSizeInBytes = 0; 2988 pipelineDesc.CachedPSO.pCachedBlob = NULL; 2989 pipelineDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; 2990 pipelineDesc.NodeMask = 0; 2991 2992 HRESULT res = ID3D12Device_CreateComputePipelineState( 2993 renderer->device, 2994 &pipelineDesc, 2995 D3D_GUID(D3D_IID_ID3D12PipelineState), 2996 (void **)&pipelineState); 2997 2998 if (FAILED(res)) { 2999 D3D12_INTERNAL_SetError(renderer, "Could not create compute pipeline state", res); 3000 return NULL; 3001 } 3002 3003 D3D12ComputePipeline *computePipeline = 3004 (D3D12ComputePipeline *)SDL_calloc(1, sizeof(D3D12ComputePipeline)); 3005 3006 if (!computePipeline) { 3007 ID3D12PipelineState_Release(pipelineState); 3008 return NULL; 3009 } 3010 3011 computePipeline->pipelineState = pipelineState; 3012 computePipeline->rootSignature = rootSignature; 3013 computePipeline->header.numSamplers = createinfo->num_samplers; 3014 computePipeline->header.numReadonlyStorageTextures = createinfo->num_readonly_storage_textures; 3015 computePipeline->header.numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers; 3016 computePipeline->header.numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures; 3017 computePipeline->header.numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers; 3018 computePipeline->header.numUniformBuffers = createinfo->num_uniform_buffers; 3019 SDL_SetAtomicInt(&computePipeline->referenceCount, 0); 3020 3021 if (renderer->debug_mode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) { 3022 D3D12_INTERNAL_SetPipelineStateName( 3023 renderer, 3024 computePipeline->pipelineState, 3025 SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING, NULL)); 3026 } 3027 3028 return (SDL_GPUComputePipeline *)computePipeline; 3029} 3030 3031static bool D3D12_INTERNAL_ConvertRasterizerState(SDL_GPURasterizerState rasterizerState, D3D12_RASTERIZER_DESC *desc) 3032{ 3033 if (!desc) { 3034 return false; 3035 } 3036 3037 desc->FillMode = SDLToD3D12_FillMode[rasterizerState.fill_mode]; 3038 desc->CullMode = SDLToD3D12_CullMode[rasterizerState.cull_mode]; 3039 3040 switch (rasterizerState.front_face) { 3041 case SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE: 3042 desc->FrontCounterClockwise = TRUE; 3043 break; 3044 case SDL_GPU_FRONTFACE_CLOCKWISE: 3045 desc->FrontCounterClockwise = FALSE; 3046 break; 3047 default: 3048 return false; 3049 } 3050 3051 if (rasterizerState.enable_depth_bias) { 3052 desc->DepthBias = SDL_lroundf(rasterizerState.depth_bias_constant_factor); 3053 desc->DepthBiasClamp = rasterizerState.depth_bias_clamp; 3054 desc->SlopeScaledDepthBias = rasterizerState.depth_bias_slope_factor; 3055 } else { 3056 desc->DepthBias = 0; 3057 desc->DepthBiasClamp = 0.0f; 3058 desc->SlopeScaledDepthBias = 0.0f; 3059 } 3060 3061 desc->DepthClipEnable = rasterizerState.enable_depth_clip; 3062 desc->MultisampleEnable = FALSE; 3063 desc->AntialiasedLineEnable = FALSE; 3064 desc->ForcedSampleCount = 0; 3065 desc->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; 3066 3067 return true; 3068} 3069 3070static bool D3D12_INTERNAL_ConvertBlendState( 3071 const SDL_GPUGraphicsPipelineCreateInfo *pipelineInfo, 3072 D3D12_BLEND_DESC *blendDesc) 3073{ 3074 if (!blendDesc) { 3075 return false; 3076 } 3077 3078 SDL_zerop(blendDesc); 3079 blendDesc->AlphaToCoverageEnable = pipelineInfo->multisample_state.enable_alpha_to_coverage; 3080 blendDesc->IndependentBlendEnable = FALSE; 3081 3082 for (UINT i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) { 3083 D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc; 3084 rtBlendDesc.BlendEnable = FALSE; 3085 rtBlendDesc.LogicOpEnable = FALSE; 3086 rtBlendDesc.SrcBlend = D3D12_BLEND_ONE; 3087 rtBlendDesc.DestBlend = D3D12_BLEND_ZERO; 3088 rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD; 3089 rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE; 3090 rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO; 3091 rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD; 3092 rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP; 3093 rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; 3094 3095 // If target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot 3096 if (i < pipelineInfo->target_info.num_color_targets) { 3097 SDL_GPUColorTargetBlendState sdlBlendState = pipelineInfo->target_info.color_target_descriptions[i].blend_state; 3098 SDL_GPUColorComponentFlags colorWriteMask = sdlBlendState.enable_color_write_mask ? 3099 sdlBlendState.color_write_mask : 3100 0xF; 3101 3102 rtBlendDesc.BlendEnable = sdlBlendState.enable_blend; 3103 rtBlendDesc.SrcBlend = SDLToD3D12_BlendFactor[sdlBlendState.src_color_blendfactor]; 3104 rtBlendDesc.DestBlend = SDLToD3D12_BlendFactor[sdlBlendState.dst_color_blendfactor]; 3105 rtBlendDesc.BlendOp = SDLToD3D12_BlendOp[sdlBlendState.color_blend_op]; 3106 rtBlendDesc.SrcBlendAlpha = SDLToD3D12_BlendFactorAlpha[sdlBlendState.src_alpha_blendfactor]; 3107 rtBlendDesc.DestBlendAlpha = SDLToD3D12_BlendFactorAlpha[sdlBlendState.dst_alpha_blendfactor]; 3108 rtBlendDesc.BlendOpAlpha = SDLToD3D12_BlendOp[sdlBlendState.alpha_blend_op]; 3109 rtBlendDesc.RenderTargetWriteMask = colorWriteMask; 3110 3111 if (i > 0) { 3112 blendDesc->IndependentBlendEnable = TRUE; 3113 } 3114 } 3115 3116 blendDesc->RenderTarget[i] = rtBlendDesc; 3117 } 3118 3119 return true; 3120} 3121 3122static bool D3D12_INTERNAL_ConvertDepthStencilState(SDL_GPUDepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC *desc) 3123{ 3124 if (desc == NULL) { 3125 return false; 3126 } 3127 3128 desc->DepthEnable = depthStencilState.enable_depth_test == true ? TRUE : FALSE; 3129 desc->DepthWriteMask = depthStencilState.enable_depth_write == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; 3130 desc->DepthFunc = SDLToD3D12_CompareOp[depthStencilState.compare_op]; 3131 desc->StencilEnable = depthStencilState.enable_stencil_test == true ? TRUE : FALSE; 3132 desc->StencilReadMask = depthStencilState.compare_mask; 3133 desc->StencilWriteMask = depthStencilState.write_mask; 3134 3135 desc->FrontFace.StencilFailOp = SDLToD3D12_StencilOp[depthStencilState.front_stencil_state.fail_op]; 3136 desc->FrontFace.StencilDepthFailOp = SDLToD3D12_StencilOp[depthStencilState.front_stencil_state.depth_fail_op]; 3137 desc->FrontFace.StencilPassOp = SDLToD3D12_StencilOp[depthStencilState.front_stencil_state.pass_op]; 3138 desc->FrontFace.StencilFunc = SDLToD3D12_CompareOp[depthStencilState.front_stencil_state.compare_op]; 3139 3140 desc->BackFace.StencilFailOp = SDLToD3D12_StencilOp[depthStencilState.back_stencil_state.fail_op]; 3141 desc->BackFace.StencilDepthFailOp = SDLToD3D12_StencilOp[depthStencilState.back_stencil_state.depth_fail_op]; 3142 desc->BackFace.StencilPassOp = SDLToD3D12_StencilOp[depthStencilState.back_stencil_state.pass_op]; 3143 desc->BackFace.StencilFunc = SDLToD3D12_CompareOp[depthStencilState.back_stencil_state.compare_op]; 3144 3145 return true; 3146} 3147 3148static bool D3D12_INTERNAL_ConvertVertexInputState(SDL_GPUVertexInputState vertexInputState, D3D12_INPUT_ELEMENT_DESC *desc, const char *semantic) 3149{ 3150 if (desc == NULL || vertexInputState.num_vertex_attributes == 0) { 3151 return false; 3152 } 3153 3154 for (Uint32 i = 0; i < vertexInputState.num_vertex_attributes; i += 1) { 3155 SDL_GPUVertexAttribute attribute = vertexInputState.vertex_attributes[i]; 3156 3157 desc[i].SemanticName = semantic; 3158 desc[i].SemanticIndex = attribute.location; 3159 desc[i].Format = SDLToD3D12_VertexFormat[attribute.format]; 3160 desc[i].InputSlot = attribute.buffer_slot; 3161 desc[i].AlignedByteOffset = attribute.offset; 3162 desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate]; 3163 desc[i].InstanceDataStepRate = (vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) 3164 ? 1 3165 : 0; 3166 } 3167 3168 return true; 3169} 3170 3171static bool D3D12_INTERNAL_AssignStagingDescriptorHandle( 3172 D3D12Renderer *renderer, 3173 D3D12_DESCRIPTOR_HEAP_TYPE heapType, 3174 D3D12StagingDescriptor *cpuDescriptor) 3175{ 3176 D3D12StagingDescriptor *descriptor; 3177 D3D12StagingDescriptorPool *pool = renderer->stagingDescriptorPools[heapType]; 3178 3179 SDL_LockMutex(pool->lock); 3180 3181 if (pool->freeDescriptorCount == 0) { 3182 if (!D3D12_INTERNAL_ExpandStagingDescriptorPool(renderer, pool)) 3183 { 3184 SDL_UnlockMutex(pool->lock); 3185 return false; 3186 } 3187 } 3188 3189 descriptor = &pool->freeDescriptors[pool->freeDescriptorCount - 1]; 3190 SDL_memcpy(cpuDescriptor, descriptor, sizeof(D3D12StagingDescriptor)); 3191 pool->freeDescriptorCount -= 1; 3192 3193 SDL_UnlockMutex(pool->lock); 3194 3195 return true; 3196} 3197 3198static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( 3199 SDL_GPURenderer *driverData, 3200 const SDL_GPUGraphicsPipelineCreateInfo *createinfo) 3201{ 3202 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 3203 D3D12Shader *vertShader = (D3D12Shader *)createinfo->vertex_shader; 3204 D3D12Shader *fragShader = (D3D12Shader *)createinfo->fragment_shader; 3205 3206 if (renderer->debug_mode) { 3207 if (vertShader->stage != SDL_GPU_SHADERSTAGE_VERTEX) { 3208 SDL_assert_release(!"CreateGraphicsPipeline was passed a fragment shader for the vertex stage"); 3209 } 3210 if (fragShader->stage != SDL_GPU_SHADERSTAGE_FRAGMENT) { 3211 SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage"); 3212 } 3213 } 3214 3215 D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc; 3216 SDL_zero(psoDesc); 3217 psoDesc.VS.pShaderBytecode = vertShader->bytecode; 3218 psoDesc.VS.BytecodeLength = vertShader->bytecodeSize; 3219 psoDesc.PS.pShaderBytecode = fragShader->bytecode; 3220 psoDesc.PS.BytecodeLength = fragShader->bytecodeSize; 3221 3222 D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; 3223 if (createinfo->vertex_input_state.num_vertex_attributes > 0) { 3224 psoDesc.InputLayout.pInputElementDescs = inputElementDescs; 3225 psoDesc.InputLayout.NumElements = createinfo->vertex_input_state.num_vertex_attributes; 3226 D3D12_INTERNAL_ConvertVertexInputState(createinfo->vertex_input_state, inputElementDescs, renderer->semantic); 3227 } 3228 3229 psoDesc.PrimitiveTopologyType = SDLToD3D12_PrimitiveTopologyType[createinfo->primitive_type]; 3230 3231 if (!D3D12_INTERNAL_ConvertRasterizerState(createinfo->rasterizer_state, &psoDesc.RasterizerState)) { 3232 return NULL; 3233 } 3234 if (!D3D12_INTERNAL_ConvertBlendState(createinfo, &psoDesc.BlendState)) { 3235 return NULL; 3236 } 3237 if (!D3D12_INTERNAL_ConvertDepthStencilState(createinfo->depth_stencil_state, &psoDesc.DepthStencilState)) { 3238 return NULL; 3239 } 3240 3241 D3D12GraphicsPipeline *pipeline = (D3D12GraphicsPipeline *)SDL_calloc(1, sizeof(D3D12GraphicsPipeline)); 3242 if (!pipeline) { 3243 return NULL; 3244 } 3245 3246 psoDesc.SampleMask = 0xFFFFFFFF; 3247 psoDesc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->multisample_state.sample_count]; 3248 psoDesc.SampleDesc.Quality = (createinfo->multisample_state.sample_count > SDL_GPU_SAMPLECOUNT_1) ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0; 3249 3250 if (createinfo->target_info.has_depth_stencil_target) { 3251 psoDesc.DSVFormat = SDLToD3D12_DepthFormat[createinfo->target_info.depth_stencil_format]; 3252 } 3253 psoDesc.NumRenderTargets = createinfo->target_info.num_color_targets; 3254 for (uint32_t i = 0; i < createinfo->target_info.num_color_targets; i += 1) { 3255 psoDesc.RTVFormats[i] = SDLToD3D12_TextureFormat[createinfo->target_info.color_target_descriptions[i].format]; 3256 } 3257 3258 // Assuming some default values or further initialization 3259 psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; 3260 psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; 3261 psoDesc.CachedPSO.pCachedBlob = NULL; 3262 3263 psoDesc.NodeMask = 0; 3264 3265 D3D12GraphicsRootSignature *rootSignature = D3D12_INTERNAL_CreateGraphicsRootSignature( 3266 renderer, 3267 vertShader, 3268 fragShader); 3269 3270 if (rootSignature == NULL) { 3271 D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline); 3272 return NULL; 3273 } 3274 pipeline->rootSignature = rootSignature; 3275 3276 psoDesc.pRootSignature = rootSignature->handle; 3277 ID3D12PipelineState *pipelineState; 3278 3279 HRESULT res = ID3D12Device_CreateGraphicsPipelineState( 3280 renderer->device, 3281 &psoDesc, 3282 D3D_GUID(D3D_IID_ID3D12PipelineState), 3283 (void **)&pipelineState); 3284 if (FAILED(res)) { 3285 D3D12_INTERNAL_SetError(renderer, "Could not create graphics pipeline state", res); 3286 D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline); 3287 return NULL; 3288 } 3289 3290 pipeline->pipelineState = pipelineState; 3291 3292 for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) { 3293 pipeline->vertexStrides[createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot] = 3294 createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch; 3295 } 3296 3297 pipeline->primitiveType = createinfo->primitive_type; 3298 3299 pipeline->header.num_vertex_samplers = vertShader->num_samplers; 3300 pipeline->header.num_vertex_storage_textures = vertShader->numStorageTextures; 3301 pipeline->header.num_vertex_storage_buffers = vertShader->numStorageBuffers; 3302 pipeline->header.num_vertex_uniform_buffers = vertShader->numUniformBuffers; 3303 3304 pipeline->header.num_fragment_samplers = fragShader->num_samplers; 3305 pipeline->header.num_fragment_storage_textures = fragShader->numStorageTextures; 3306 pipeline->header.num_fragment_storage_buffers = fragShader->numStorageBuffers; 3307 pipeline->header.num_fragment_uniform_buffers = fragShader->numUniformBuffers; 3308 3309 SDL_SetAtomicInt(&pipeline->referenceCount, 0); 3310 3311 if (renderer->debug_mode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING)) { 3312 D3D12_INTERNAL_SetPipelineStateName( 3313 renderer, 3314 pipeline->pipelineState, 3315 SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING, NULL)); 3316 } 3317 3318 return (SDL_GPUGraphicsPipeline *)pipeline; 3319} 3320 3321static SDL_GPUSampler *D3D12_CreateSampler( 3322 SDL_GPURenderer *driverData, 3323 const SDL_GPUSamplerCreateInfo *createinfo) 3324{ 3325 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 3326 D3D12Sampler *sampler = (D3D12Sampler *)SDL_calloc(1, sizeof(D3D12Sampler)); 3327 if (!sampler) { 3328 return NULL; 3329 } 3330 D3D12_SAMPLER_DESC samplerDesc; 3331 3332 samplerDesc.Filter = SDLToD3D12_Filter( 3333 createinfo->min_filter, 3334 createinfo->mag_filter, 3335 createinfo->mipmap_mode, 3336 createinfo->enable_compare, 3337 createinfo->enable_anisotropy); 3338 samplerDesc.AddressU = SDLToD3D12_SamplerAddressMode[createinfo->address_mode_u]; 3339 samplerDesc.AddressV = SDLToD3D12_SamplerAddressMode[createinfo->address_mode_v]; 3340 samplerDesc.AddressW = SDLToD3D12_SamplerAddressMode[createinfo->address_mode_w]; 3341 samplerDesc.MaxAnisotropy = (Uint32)createinfo->max_anisotropy; 3342 samplerDesc.ComparisonFunc = SDLToD3D12_CompareOp[createinfo->compare_op]; 3343 samplerDesc.MinLOD = createinfo->min_lod; 3344 samplerDesc.MaxLOD = createinfo->max_lod; 3345 samplerDesc.MipLODBias = createinfo->mip_lod_bias; 3346 samplerDesc.BorderColor[0] = 0; 3347 samplerDesc.BorderColor[1] = 0; 3348 samplerDesc.BorderColor[2] = 0; 3349 samplerDesc.BorderColor[3] = 0; 3350 3351 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3352 renderer, 3353 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 3354 &sampler->handle); 3355 3356 ID3D12Device_CreateSampler( 3357 renderer->device, 3358 &samplerDesc, 3359 sampler->handle.cpuHandle); 3360 3361 sampler->createInfo = *createinfo; 3362 SDL_SetAtomicInt(&sampler->referenceCount, 0); 3363 3364 // Ignore name property because it is not applicable to D3D12. 3365 3366 return (SDL_GPUSampler *)sampler; 3367} 3368 3369static SDL_GPUShader *D3D12_CreateShader( 3370 SDL_GPURenderer *driverData, 3371 const SDL_GPUShaderCreateInfo *createinfo) 3372{ 3373 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 3374 void *bytecode; 3375 size_t bytecodeSize; 3376 D3D12Shader *shader; 3377 3378 if (!D3D12_INTERNAL_CreateShaderBytecode( 3379 renderer, 3380 createinfo->code, 3381 createinfo->code_size, 3382 createinfo->format, 3383 &bytecode, 3384 &bytecodeSize)) { 3385 return NULL; 3386 } 3387 shader = (D3D12Shader *)SDL_calloc(1, sizeof(D3D12Shader)); 3388 if (!shader) { 3389 SDL_free(bytecode); 3390 return NULL; 3391 } 3392 shader->stage = createinfo->stage; 3393 shader->num_samplers = createinfo->num_samplers; 3394 shader->numStorageBuffers = createinfo->num_storage_buffers; 3395 shader->numStorageTextures = createinfo->num_storage_textures; 3396 shader->numUniformBuffers = createinfo->num_uniform_buffers; 3397 3398 shader->bytecode = bytecode; 3399 shader->bytecodeSize = bytecodeSize; 3400 3401 // Ignore name property because it is not applicable to D3D12. 3402 3403 return (SDL_GPUShader *)shader; 3404} 3405 3406static D3D12Texture *D3D12_INTERNAL_CreateTexture( 3407 D3D12Renderer *renderer, 3408 const SDL_GPUTextureCreateInfo *createinfo, 3409 bool isSwapchainTexture, 3410 const char *debugName) 3411{ 3412 D3D12Texture *texture; 3413 ID3D12Resource *handle; 3414 D3D12_HEAP_PROPERTIES heapProperties; 3415 D3D12_HEAP_FLAGS heapFlags = (D3D12_HEAP_FLAGS)0; 3416 D3D12_RESOURCE_DESC desc; 3417 D3D12_RESOURCE_FLAGS resourceFlags = (D3D12_RESOURCE_FLAGS)0; 3418 D3D12_RESOURCE_STATES initialState = (D3D12_RESOURCE_STATES)0; 3419 D3D12_CLEAR_VALUE clearValue; 3420 DXGI_FORMAT format; 3421 bool useClearValue = false; 3422 bool needsSRV = 3423 (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) || 3424 (createinfo->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) || 3425 (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ); 3426 bool needsUAV = 3427 (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) || 3428 (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE); 3429 HRESULT res; 3430 3431 texture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture)); 3432 if (!texture) { 3433 return NULL; 3434 } 3435 3436 Uint32 layerCount = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? 1 : createinfo->layer_count_or_depth; 3437 Uint32 depth = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? createinfo->layer_count_or_depth : 1; 3438 bool isMultisample = createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1; 3439 3440 format = SDLToD3D12_TextureFormat[createinfo->format]; 3441 3442 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 3443 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; 3444 useClearValue = true; 3445 clearValue.Format = format; 3446 clearValue.Color[0] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT, 0); 3447 clearValue.Color[1] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT, 0); 3448 clearValue.Color[2] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT, 0); 3449 clearValue.Color[3] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT, 0); 3450 } 3451 3452 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 3453 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; 3454 useClearValue = true; 3455 clearValue.Format = SDLToD3D12_DepthFormat[createinfo->format]; 3456 clearValue.DepthStencil.Depth = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT, 0); 3457 clearValue.DepthStencil.Stencil = (UINT8)SDL_GetNumberProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER, 0); 3458 format = needsSRV ? SDLToD3D12_TypelessFormat[createinfo->format] : SDLToD3D12_DepthFormat[createinfo->format]; 3459 } 3460 3461 if (needsUAV) { 3462 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 3463 } 3464 3465 heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; 3466 heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 3467 heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 3468 heapProperties.CreationNodeMask = 0; // We don't do multi-adapter operation 3469 heapProperties.VisibleNodeMask = 0; // We don't do multi-adapter operation 3470 3471 heapFlags = isSwapchainTexture ? D3D12_HEAP_FLAG_ALLOW_DISPLAY : D3D12_HEAP_FLAG_NONE; 3472 3473 if (createinfo->type != SDL_GPU_TEXTURETYPE_3D) { 3474 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; 3475 desc.Alignment = isSwapchainTexture ? 0 : isMultisample ? D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; 3476 desc.Width = createinfo->width; 3477 desc.Height = createinfo->height; 3478 desc.DepthOrArraySize = (UINT16)createinfo->layer_count_or_depth; 3479 desc.MipLevels = (UINT16)createinfo->num_levels; 3480 desc.Format = format; 3481 desc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->sample_count]; 3482 desc.SampleDesc.Quality = isMultisample ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0; 3483 desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // Apparently this is the most efficient choice 3484 desc.Flags = resourceFlags; 3485 } else { 3486 desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; 3487 desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; 3488 desc.Width = createinfo->width; 3489 desc.Height = createinfo->height; 3490 desc.DepthOrArraySize = (UINT16)createinfo->layer_count_or_depth; 3491 desc.MipLevels = (UINT16)createinfo->num_levels; 3492 desc.Format = format; 3493 desc.SampleDesc.Count = 1; 3494 desc.SampleDesc.Quality = 0; 3495 desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; 3496 desc.Flags = resourceFlags; 3497 } 3498 3499 initialState = isSwapchainTexture ? D3D12_RESOURCE_STATE_PRESENT : D3D12_INTERNAL_DefaultTextureResourceState(createinfo->usage); 3500 3501 res = ID3D12Device_CreateCommittedResource( 3502 renderer->device, 3503 &heapProperties, 3504 heapFlags, 3505 &desc, 3506 initialState, 3507 useClearValue ? &clearValue : NULL, 3508 D3D_GUID(D3D_IID_ID3D12Resource), 3509 (void **)&handle); 3510 if (FAILED(res)) { 3511 D3D12_INTERNAL_SetError(renderer, "Failed to create texture!", res); 3512 D3D12_INTERNAL_DestroyTexture(texture); 3513 return NULL; 3514 } 3515 3516 texture->resource = handle; 3517 3518 // Create the SRV if applicable 3519 if (needsSRV) { 3520 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; 3521 3522 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3523 renderer, 3524 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3525 &texture->srvHandle); 3526 3527 srvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format]; 3528 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 3529 3530 if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) { 3531 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; 3532 srvDesc.TextureCube.MipLevels = createinfo->num_levels; 3533 srvDesc.TextureCube.MostDetailedMip = 0; 3534 srvDesc.TextureCube.ResourceMinLODClamp = 0; 3535 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 3536 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; 3537 srvDesc.TextureCubeArray.MipLevels = createinfo->num_levels; 3538 srvDesc.TextureCubeArray.MostDetailedMip = 0; 3539 srvDesc.TextureCubeArray.First2DArrayFace = 0; 3540 srvDesc.TextureCubeArray.NumCubes = createinfo->layer_count_or_depth / 6; 3541 srvDesc.TextureCubeArray.ResourceMinLODClamp = 0; 3542 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { 3543 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; 3544 srvDesc.Texture2DArray.MipLevels = createinfo->num_levels; 3545 srvDesc.Texture2DArray.MostDetailedMip = 0; 3546 srvDesc.Texture2DArray.FirstArraySlice = 0; 3547 srvDesc.Texture2DArray.ArraySize = layerCount; 3548 srvDesc.Texture2DArray.ResourceMinLODClamp = 0; 3549 srvDesc.Texture2DArray.PlaneSlice = 0; 3550 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 3551 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; 3552 srvDesc.Texture3D.MipLevels = createinfo->num_levels; 3553 srvDesc.Texture3D.MostDetailedMip = 0; 3554 srvDesc.Texture3D.ResourceMinLODClamp = 0; // default behavior 3555 } else { 3556 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; 3557 srvDesc.Texture2D.MipLevels = createinfo->num_levels; 3558 srvDesc.Texture2D.MostDetailedMip = 0; 3559 srvDesc.Texture2D.PlaneSlice = 0; 3560 srvDesc.Texture2D.ResourceMinLODClamp = 0; // default behavior 3561 } 3562 3563 ID3D12Device_CreateShaderResourceView( 3564 renderer->device, 3565 handle, 3566 &srvDesc, 3567 texture->srvHandle.cpuHandle); 3568 } 3569 3570 SDL_SetAtomicInt(&texture->referenceCount, 0); 3571 3572 texture->subresourceCount = createinfo->num_levels * layerCount; 3573 texture->subresources = (D3D12TextureSubresource *)SDL_calloc( 3574 texture->subresourceCount, sizeof(D3D12TextureSubresource)); 3575 if (!texture->subresources) { 3576 D3D12_INTERNAL_DestroyTexture(texture); 3577 return NULL; 3578 } 3579 for (Uint32 layerIndex = 0; layerIndex < layerCount; layerIndex += 1) { 3580 for (Uint32 levelIndex = 0; levelIndex < createinfo->num_levels; levelIndex += 1) { 3581 Uint32 subresourceIndex = D3D12_INTERNAL_CalcSubresource( 3582 levelIndex, 3583 layerIndex, 3584 createinfo->num_levels); 3585 3586 texture->subresources[subresourceIndex].parent = texture; 3587 texture->subresources[subresourceIndex].layer = layerIndex; 3588 texture->subresources[subresourceIndex].level = levelIndex; 3589 texture->subresources[subresourceIndex].depth = depth; 3590 texture->subresources[subresourceIndex].index = subresourceIndex; 3591 3592 texture->subresources[subresourceIndex].rtvHandles = NULL; 3593 texture->subresources[subresourceIndex].uavHandle.heap = NULL; 3594 texture->subresources[subresourceIndex].dsvHandle.heap = NULL; 3595 3596 // Create RTV if needed 3597 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) { 3598 texture->subresources[subresourceIndex].rtvHandles = (D3D12StagingDescriptor *)SDL_calloc(depth, sizeof(D3D12StagingDescriptor)); 3599 3600 for (Uint32 depthIndex = 0; depthIndex < depth; depthIndex += 1) { 3601 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; 3602 3603 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3604 renderer, 3605 D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 3606 &texture->subresources[subresourceIndex].rtvHandles[depthIndex]); 3607 3608 rtvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format]; 3609 3610 if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 3611 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; 3612 rtvDesc.Texture2DArray.MipSlice = levelIndex; 3613 rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; 3614 rtvDesc.Texture2DArray.ArraySize = 1; 3615 rtvDesc.Texture2DArray.PlaneSlice = 0; 3616 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 3617 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; 3618 rtvDesc.Texture3D.MipSlice = levelIndex; 3619 rtvDesc.Texture3D.FirstWSlice = depthIndex; 3620 rtvDesc.Texture3D.WSize = 1; 3621 } else if (isMultisample) { 3622 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS; 3623 } else { 3624 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; 3625 rtvDesc.Texture2D.MipSlice = levelIndex; 3626 rtvDesc.Texture2D.PlaneSlice = 0; 3627 } 3628 3629 ID3D12Device_CreateRenderTargetView( 3630 renderer->device, 3631 texture->resource, 3632 &rtvDesc, 3633 texture->subresources[subresourceIndex].rtvHandles[depthIndex].cpuHandle); 3634 } 3635 } 3636 3637 // Create DSV if needed 3638 if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) { 3639 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; 3640 3641 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3642 renderer, 3643 D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 3644 &texture->subresources[subresourceIndex].dsvHandle); 3645 3646 dsvDesc.Format = SDLToD3D12_DepthFormat[createinfo->format]; 3647 dsvDesc.Flags = (D3D12_DSV_FLAGS)0; 3648 3649 if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 3650 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY; 3651 dsvDesc.Texture2DArray.MipSlice = levelIndex; 3652 dsvDesc.Texture2DArray.FirstArraySlice = layerIndex; 3653 dsvDesc.Texture2DArray.ArraySize = 1; 3654 } else if (isMultisample) { 3655 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS; 3656 } else { 3657 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; 3658 dsvDesc.Texture2D.MipSlice = levelIndex; 3659 } 3660 3661 ID3D12Device_CreateDepthStencilView( 3662 renderer->device, 3663 texture->resource, 3664 &dsvDesc, 3665 texture->subresources[subresourceIndex].dsvHandle.cpuHandle); 3666 } 3667 3668 // Create subresource UAV if necessary 3669 if (needsUAV) { 3670 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; 3671 3672 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3673 renderer, 3674 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3675 &texture->subresources[subresourceIndex].uavHandle); 3676 3677 uavDesc.Format = SDLToD3D12_TextureFormat[createinfo->format]; 3678 3679 if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) { 3680 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; 3681 uavDesc.Texture2DArray.MipSlice = levelIndex; 3682 uavDesc.Texture2DArray.FirstArraySlice = layerIndex; 3683 uavDesc.Texture2DArray.ArraySize = 1; 3684 uavDesc.Texture2DArray.PlaneSlice = 0; 3685 } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) { 3686 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; 3687 uavDesc.Texture3D.MipSlice = levelIndex; 3688 uavDesc.Texture3D.FirstWSlice = 0; 3689 uavDesc.Texture3D.WSize = depth; 3690 } else { 3691 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; 3692 uavDesc.Texture2D.MipSlice = levelIndex; 3693 uavDesc.Texture2D.PlaneSlice = 0; 3694 } 3695 3696 ID3D12Device_CreateUnorderedAccessView( 3697 renderer->device, 3698 texture->resource, 3699 NULL, 3700 &uavDesc, 3701 texture->subresources[subresourceIndex].uavHandle.cpuHandle); 3702 } 3703 } 3704 } 3705 3706 D3D12_INTERNAL_SetResourceName( 3707 renderer, 3708 texture->resource, 3709 debugName); 3710 3711 return texture; 3712} 3713 3714static SDL_GPUTexture *D3D12_CreateTexture( 3715 SDL_GPURenderer *driverData, 3716 const SDL_GPUTextureCreateInfo *createinfo) 3717{ 3718 D3D12TextureContainer *container = (D3D12TextureContainer *)SDL_calloc(1, sizeof(D3D12TextureContainer)); 3719 if (!container) { 3720 return NULL; 3721 } 3722 3723 // Copy properties so we don't lose information when the client destroys them 3724 container->header.info = *createinfo; 3725 container->header.info.props = SDL_CreateProperties(); 3726 if (createinfo->props) { 3727 SDL_CopyProperties(createinfo->props, container->header.info.props); 3728 } 3729 3730 container->textureCapacity = 1; 3731 container->textureCount = 1; 3732 container->textures = (D3D12Texture **)SDL_calloc( 3733 container->textureCapacity, sizeof(D3D12Texture *)); 3734 3735 if (!container->textures) { 3736 SDL_free(container); 3737 return NULL; 3738 } 3739 3740 container->debugName = NULL; 3741 if (SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) { 3742 container->debugName = SDL_strdup(SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL)); 3743 } 3744 3745 container->canBeCycled = true; 3746 3747 D3D12Texture *texture = D3D12_INTERNAL_CreateTexture( 3748 (D3D12Renderer *)driverData, 3749 createinfo, 3750 false, 3751 container->debugName); 3752 3753 if (!texture) { 3754 SDL_free(container->textures); 3755 SDL_free(container); 3756 return NULL; 3757 } 3758 3759 container->textures[0] = texture; 3760 container->activeTexture = texture; 3761 3762 texture->container = container; 3763 texture->containerIndex = 0; 3764 3765 return (SDL_GPUTexture *)container; 3766} 3767 3768static D3D12Buffer *D3D12_INTERNAL_CreateBuffer( 3769 D3D12Renderer *renderer, 3770 SDL_GPUBufferUsageFlags usageFlags, 3771 Uint32 size, 3772 D3D12BufferType type, 3773 const char *debugName) 3774{ 3775 D3D12Buffer *buffer; 3776 ID3D12Resource *handle; 3777 D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; 3778 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; 3779 D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc; 3780 D3D12_HEAP_PROPERTIES heapProperties; 3781 D3D12_RESOURCE_DESC desc; 3782 D3D12_HEAP_FLAGS heapFlags = (D3D12_HEAP_FLAGS)0; 3783 D3D12_RESOURCE_FLAGS resourceFlags = (D3D12_RESOURCE_FLAGS)0; 3784 D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON; 3785 HRESULT res; 3786 3787 buffer = (D3D12Buffer *)SDL_calloc(1, sizeof(D3D12Buffer)); 3788 3789 if (!buffer) { 3790 return NULL; 3791 } 3792 3793 if (usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) { 3794 resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; 3795 } 3796#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 3797 if (usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT) { 3798 resourceFlags |= D3D12XBOX_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER; 3799 } 3800#endif 3801 3802 heapProperties.CreationNodeMask = 0; // We don't do multi-adapter operation 3803 heapProperties.VisibleNodeMask = 0; // We don't do multi-adapter operation 3804 3805 if (type == D3D12_BUFFER_TYPE_GPU) { 3806 heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; 3807 heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 3808 heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 3809 heapFlags = D3D12_HEAP_FLAG_NONE; 3810 } else if (type == D3D12_BUFFER_TYPE_UPLOAD) { 3811 heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; 3812 heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 3813 heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 3814 heapFlags = D3D12_HEAP_FLAG_NONE; 3815 initialState = D3D12_RESOURCE_STATE_GENERIC_READ; 3816 } else if (type == D3D12_BUFFER_TYPE_DOWNLOAD) { 3817 heapProperties.Type = D3D12_HEAP_TYPE_READBACK; 3818 heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 3819 heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 3820 heapFlags = D3D12_HEAP_FLAG_NONE; 3821 initialState = D3D12_RESOURCE_STATE_COPY_DEST; 3822 } else if (type == D3D12_BUFFER_TYPE_UNIFORM) { 3823 // D3D12 is badly designed, so we have to check if the fast path for uniform buffers is enabled 3824 if (renderer->GPUUploadHeapSupported) { 3825 heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD; 3826 heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 3827 heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 3828 } else { 3829 heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; 3830 heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; 3831 heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; 3832 initialState = D3D12_RESOURCE_STATE_GENERIC_READ; 3833 } 3834 heapFlags = D3D12_HEAP_FLAG_NONE; 3835 } else { 3836 SET_STRING_ERROR_AND_RETURN("Unrecognized buffer type!", NULL); 3837 } 3838 3839 desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; 3840 desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; 3841 desc.Width = size; 3842 desc.Height = 1; 3843 desc.DepthOrArraySize = 1; 3844 desc.MipLevels = 1; 3845 desc.Format = DXGI_FORMAT_UNKNOWN; 3846 desc.SampleDesc.Count = 1; 3847 desc.SampleDesc.Quality = 0; 3848 desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; 3849 desc.Flags = resourceFlags; 3850 3851 res = ID3D12Device_CreateCommittedResource( 3852 renderer->device, 3853 &heapProperties, 3854 heapFlags, 3855 &desc, 3856 initialState, 3857 NULL, 3858 D3D_GUID(D3D_IID_ID3D12Resource), 3859 (void **)&handle); 3860 if (FAILED(res)) { 3861 D3D12_INTERNAL_SetError(renderer, "Could not create buffer!", res); 3862 D3D12_INTERNAL_DestroyBuffer(buffer); 3863 return NULL; 3864 } 3865 3866 buffer->handle = handle; 3867 SDL_SetAtomicInt(&buffer->referenceCount, 0); 3868 3869 buffer->uavDescriptor.heap = NULL; 3870 buffer->srvDescriptor.heap = NULL; 3871 buffer->cbvDescriptor.heap = NULL; 3872 3873 if (usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) { 3874 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3875 renderer, 3876 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3877 &buffer->uavDescriptor); 3878 3879 uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; 3880 uavDesc.Format = DXGI_FORMAT_R32_TYPELESS; 3881 uavDesc.Buffer.FirstElement = 0; 3882 uavDesc.Buffer.NumElements = size / sizeof(Uint32); 3883 uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW; 3884 uavDesc.Buffer.CounterOffsetInBytes = 0; // TODO: support counters? 3885 uavDesc.Buffer.StructureByteStride = 0; 3886 3887 // Create UAV 3888 ID3D12Device_CreateUnorderedAccessView( 3889 renderer->device, 3890 handle, 3891 NULL, // TODO: support counters? 3892 &uavDesc, 3893 buffer->uavDescriptor.cpuHandle); 3894 } 3895 3896 if ( 3897 (usageFlags & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) || 3898 (usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ)) { 3899 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3900 renderer, 3901 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3902 &buffer->srvDescriptor); 3903 3904 srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; 3905 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 3906 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; 3907 srvDesc.Buffer.FirstElement = 0; 3908 srvDesc.Buffer.NumElements = size / sizeof(Uint32); 3909 srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; 3910 srvDesc.Buffer.StructureByteStride = 0; 3911 3912 // Create SRV 3913 ID3D12Device_CreateShaderResourceView( 3914 renderer->device, 3915 handle, 3916 &srvDesc, 3917 buffer->srvDescriptor.cpuHandle); 3918 } 3919 3920 // FIXME: we may not need a CBV since we use root descriptors 3921 if (type == D3D12_BUFFER_TYPE_UNIFORM) { 3922 D3D12_INTERNAL_AssignStagingDescriptorHandle( 3923 renderer, 3924 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 3925 &buffer->cbvDescriptor); 3926 3927 cbvDesc.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(handle); 3928 cbvDesc.SizeInBytes = size; 3929 3930 // Create CBV 3931 ID3D12Device_CreateConstantBufferView( 3932 renderer->device, 3933 &cbvDesc, 3934 buffer->cbvDescriptor.cpuHandle); 3935 } 3936 3937 buffer->virtualAddress = 0; 3938 if (type == D3D12_BUFFER_TYPE_GPU || type == D3D12_BUFFER_TYPE_UNIFORM) { 3939 buffer->virtualAddress = ID3D12Resource_GetGPUVirtualAddress(buffer->handle); 3940 } 3941 3942 buffer->mapPointer = NULL; 3943 // Persistently map upload buffers 3944 if (type == D3D12_BUFFER_TYPE_UPLOAD) { 3945 res = ID3D12Resource_Map( 3946 buffer->handle, 3947 0, 3948 NULL, 3949 (void **)&buffer->mapPointer); 3950 if (FAILED(res)) { 3951 D3D12_INTERNAL_SetError(renderer, "Failed to map upload buffer!", res); 3952 D3D12_INTERNAL_DestroyBuffer(buffer); 3953 return NULL; 3954 } 3955 } 3956 3957 buffer->container = NULL; 3958 buffer->containerIndex = 0; 3959 3960 buffer->transitioned = initialState != D3D12_RESOURCE_STATE_COMMON; 3961 SDL_SetAtomicInt(&buffer->referenceCount, 0); 3962 3963 D3D12_INTERNAL_SetResourceName( 3964 renderer, 3965 buffer->handle, 3966 debugName); 3967 3968 return buffer; 3969} 3970 3971static D3D12BufferContainer *D3D12_INTERNAL_CreateBufferContainer( 3972 D3D12Renderer *renderer, 3973 SDL_GPUBufferUsageFlags usageFlags, 3974 Uint32 size, 3975 D3D12BufferType type, 3976 const char *debugName) 3977{ 3978 D3D12BufferContainer *container; 3979 D3D12Buffer *buffer; 3980 3981 container = (D3D12BufferContainer *)SDL_calloc(1, sizeof(D3D12BufferContainer)); 3982 if (!container) { 3983 return NULL; 3984 } 3985 3986 container->usage = usageFlags; 3987 container->size = size; 3988 container->type = type; 3989 3990 container->bufferCapacity = 1; 3991 container->bufferCount = 1; 3992 container->buffers = (D3D12Buffer **)SDL_calloc( 3993 container->bufferCapacity, sizeof(D3D12Buffer *)); 3994 if (!container->buffers) { 3995 SDL_free(container); 3996 return NULL; 3997 } 3998 container->debugName = NULL; 3999 4000 buffer = D3D12_INTERNAL_CreateBuffer( 4001 renderer, 4002 usageFlags, 4003 size, 4004 type, 4005 debugName); 4006 4007 if (buffer == NULL) { 4008 SDL_free(container->buffers); 4009 SDL_free(container); 4010 return NULL; 4011 } 4012 4013 container->activeBuffer = buffer; 4014 container->buffers[0] = buffer; 4015 buffer->container = container; 4016 buffer->containerIndex = 0; 4017 4018 if (debugName != NULL) { 4019 container->debugName = SDL_strdup(debugName); 4020 } 4021 4022 return container; 4023} 4024 4025static SDL_GPUBuffer *D3D12_CreateBuffer( 4026 SDL_GPURenderer *driverData, 4027 SDL_GPUBufferUsageFlags usageFlags, 4028 Uint32 size, 4029 const char *debugName) 4030{ 4031 return (SDL_GPUBuffer *)D3D12_INTERNAL_CreateBufferContainer( 4032 (D3D12Renderer *)driverData, 4033 usageFlags, 4034 size, 4035 D3D12_BUFFER_TYPE_GPU, 4036 debugName); 4037} 4038 4039static SDL_GPUTransferBuffer *D3D12_CreateTransferBuffer( 4040 SDL_GPURenderer *driverData, 4041 SDL_GPUTransferBufferUsage usage, 4042 Uint32 size, 4043 const char *debugName) 4044{ 4045 return (SDL_GPUTransferBuffer *)D3D12_INTERNAL_CreateBufferContainer( 4046 (D3D12Renderer *)driverData, 4047 0, 4048 size, 4049 usage == SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD ? D3D12_BUFFER_TYPE_UPLOAD : D3D12_BUFFER_TYPE_DOWNLOAD, 4050 debugName); 4051} 4052 4053// Disposal 4054 4055static void D3D12_ReleaseTexture( 4056 SDL_GPURenderer *driverData, 4057 SDL_GPUTexture *texture) 4058{ 4059 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4060 D3D12TextureContainer *container = (D3D12TextureContainer *)texture; 4061 4062 D3D12_INTERNAL_ReleaseTextureContainer( 4063 renderer, 4064 container); 4065} 4066 4067static void D3D12_ReleaseSampler( 4068 SDL_GPURenderer *driverData, 4069 SDL_GPUSampler *sampler) 4070{ 4071 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4072 D3D12Sampler *d3d12Sampler = (D3D12Sampler *)sampler; 4073 4074 SDL_LockMutex(renderer->disposeLock); 4075 4076 EXPAND_ARRAY_IF_NEEDED( 4077 renderer->samplersToDestroy, 4078 D3D12Sampler *, 4079 renderer->samplersToDestroyCount + 1, 4080 renderer->samplersToDestroyCapacity, 4081 renderer->samplersToDestroyCapacity * 2); 4082 4083 renderer->samplersToDestroy[renderer->samplersToDestroyCount] = d3d12Sampler; 4084 renderer->samplersToDestroyCount += 1; 4085 4086 SDL_UnlockMutex(renderer->disposeLock); 4087} 4088 4089static void D3D12_ReleaseBuffer( 4090 SDL_GPURenderer *driverData, 4091 SDL_GPUBuffer *buffer) 4092{ 4093 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4094 D3D12BufferContainer *bufferContainer = (D3D12BufferContainer *)buffer; 4095 4096 D3D12_INTERNAL_ReleaseBufferContainer( 4097 renderer, 4098 bufferContainer); 4099} 4100 4101static void D3D12_ReleaseTransferBuffer( 4102 SDL_GPURenderer *driverData, 4103 SDL_GPUTransferBuffer *transferBuffer) 4104{ 4105 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4106 D3D12BufferContainer *transferBufferContainer = (D3D12BufferContainer *)transferBuffer; 4107 4108 D3D12_INTERNAL_ReleaseBufferContainer( 4109 renderer, 4110 transferBufferContainer); 4111} 4112 4113static void D3D12_ReleaseShader( 4114 SDL_GPURenderer *driverData, 4115 SDL_GPUShader *shader) 4116{ 4117 /* D3D12Renderer *renderer = (D3D12Renderer *)driverData; */ 4118 D3D12Shader *d3d12shader = (D3D12Shader *)shader; 4119 4120 if (d3d12shader->bytecode) { 4121 SDL_free(d3d12shader->bytecode); 4122 d3d12shader->bytecode = NULL; 4123 } 4124 SDL_free(d3d12shader); 4125} 4126 4127static void D3D12_ReleaseComputePipeline( 4128 SDL_GPURenderer *driverData, 4129 SDL_GPUComputePipeline *computePipeline) 4130{ 4131 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4132 D3D12ComputePipeline *d3d12ComputePipeline = (D3D12ComputePipeline *)computePipeline; 4133 4134 SDL_LockMutex(renderer->disposeLock); 4135 4136 EXPAND_ARRAY_IF_NEEDED( 4137 renderer->computePipelinesToDestroy, 4138 D3D12ComputePipeline *, 4139 renderer->computePipelinesToDestroyCount + 1, 4140 renderer->computePipelinesToDestroyCapacity, 4141 renderer->computePipelinesToDestroyCapacity * 2); 4142 4143 renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount] = d3d12ComputePipeline; 4144 renderer->computePipelinesToDestroyCount += 1; 4145 4146 SDL_UnlockMutex(renderer->disposeLock); 4147} 4148 4149static void D3D12_ReleaseGraphicsPipeline( 4150 SDL_GPURenderer *driverData, 4151 SDL_GPUGraphicsPipeline *graphicsPipeline) 4152{ 4153 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4154 D3D12GraphicsPipeline *d3d12GraphicsPipeline = (D3D12GraphicsPipeline *)graphicsPipeline; 4155 4156 SDL_LockMutex(renderer->disposeLock); 4157 4158 EXPAND_ARRAY_IF_NEEDED( 4159 renderer->graphicsPipelinesToDestroy, 4160 D3D12GraphicsPipeline *, 4161 renderer->graphicsPipelinesToDestroyCount + 1, 4162 renderer->graphicsPipelinesToDestroyCapacity, 4163 renderer->graphicsPipelinesToDestroyCapacity * 2); 4164 4165 renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount] = d3d12GraphicsPipeline; 4166 renderer->graphicsPipelinesToDestroyCount += 1; 4167 4168 SDL_UnlockMutex(renderer->disposeLock); 4169} 4170 4171static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData) 4172{ 4173 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 4174 D3D12_ReleaseSampler(driverData, renderer->blitLinearSampler); 4175 D3D12_ReleaseSampler(driverData, renderer->blitNearestSampler); 4176 D3D12_ReleaseShader(driverData, renderer->blitVertexShader); 4177 D3D12_ReleaseShader(driverData, renderer->blitFrom2DShader); 4178 D3D12_ReleaseShader(driverData, renderer->blitFrom2DArrayShader); 4179 D3D12_ReleaseShader(driverData, renderer->blitFrom3DShader); 4180 D3D12_ReleaseShader(driverData, renderer->blitFromCubeShader); 4181 D3D12_ReleaseShader(driverData, renderer->blitFromCubeArrayShader); 4182 4183 for (Uint32 i = 0; i < renderer->blitPipelineCount; i += 1) { 4184 D3D12_ReleaseGraphicsPipeline(driverData, renderer->blitPipelines[i].pipeline); 4185 } 4186 SDL_free(renderer->blitPipelines); 4187} 4188 4189// Render Pass 4190 4191static void D3D12_SetViewport( 4192 SDL_GPUCommandBuffer *commandBuffer, 4193 const SDL_GPUViewport *viewport) 4194{ 4195 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4196 D3D12_VIEWPORT d3d12Viewport; 4197 d3d12Viewport.TopLeftX = viewport->x; 4198 d3d12Viewport.TopLeftY = viewport->y; 4199 d3d12Viewport.Width = viewport->w; 4200 d3d12Viewport.Height = viewport->h; 4201 d3d12Viewport.MinDepth = viewport->min_depth; 4202 d3d12Viewport.MaxDepth = viewport->max_depth; 4203 ID3D12GraphicsCommandList_RSSetViewports(d3d12CommandBuffer->graphicsCommandList, 1, &d3d12Viewport); 4204} 4205 4206static void D3D12_SetScissor( 4207 SDL_GPUCommandBuffer *commandBuffer, 4208 const SDL_Rect *scissor) 4209{ 4210 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4211 D3D12_RECT scissorRect; 4212 scissorRect.left = scissor->x; 4213 scissorRect.top = scissor->y; 4214 scissorRect.right = scissor->x + scissor->w; 4215 scissorRect.bottom = scissor->y + scissor->h; 4216 ID3D12GraphicsCommandList_RSSetScissorRects(d3d12CommandBuffer->graphicsCommandList, 1, &scissorRect); 4217} 4218 4219static void D3D12_SetBlendConstants( 4220 SDL_GPUCommandBuffer *commandBuffer, 4221 SDL_FColor blendConstants) 4222{ 4223 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4224 FLOAT blendFactor[4] = { blendConstants.r, blendConstants.g, blendConstants.b, blendConstants.a }; 4225 ID3D12GraphicsCommandList_OMSetBlendFactor(d3d12CommandBuffer->graphicsCommandList, blendFactor); 4226} 4227 4228static void D3D12_SetStencilReference( 4229 SDL_GPUCommandBuffer *commandBuffer, 4230 Uint8 reference 4231) { 4232 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4233 ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandBuffer->graphicsCommandList, reference); 4234} 4235 4236static D3D12TextureSubresource *D3D12_INTERNAL_FetchTextureSubresource( 4237 D3D12TextureContainer *container, 4238 Uint32 layer, 4239 Uint32 level) 4240{ 4241 Uint32 index = D3D12_INTERNAL_CalcSubresource( 4242 level, 4243 layer, 4244 container->header.info.num_levels); 4245 return &container->activeTexture->subresources[index]; 4246} 4247 4248static void D3D12_INTERNAL_CycleActiveTexture( 4249 D3D12Renderer *renderer, 4250 D3D12TextureContainer *container) 4251{ 4252 D3D12Texture *texture; 4253 4254 // If a previously-cycled texture is available, we can use that. 4255 for (Uint32 i = 0; i < container->textureCount; i += 1) { 4256 texture = container->textures[i]; 4257 4258 if (SDL_GetAtomicInt(&texture->referenceCount) == 0) { 4259 container->activeTexture = texture; 4260 return; 4261 } 4262 } 4263 4264 // No texture is available, generate a new one. 4265 texture = D3D12_INTERNAL_CreateTexture( 4266 renderer, 4267 &container->header.info, 4268 false, 4269 container->debugName); 4270 4271 if (!texture) { 4272 return; 4273 } 4274 4275 EXPAND_ARRAY_IF_NEEDED( 4276 container->textures, 4277 D3D12Texture *, 4278 container->textureCount + 1, 4279 container->textureCapacity, 4280 container->textureCapacity * 2); 4281 4282 container->textures[container->textureCount] = texture; 4283 texture->container = container; 4284 texture->containerIndex = container->textureCount; 4285 container->textureCount += 1; 4286 4287 container->activeTexture = texture; 4288} 4289 4290static D3D12TextureSubresource *D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 4291 D3D12CommandBuffer *commandBuffer, 4292 D3D12TextureContainer *container, 4293 Uint32 layer, 4294 Uint32 level, 4295 bool cycle, 4296 D3D12_RESOURCE_STATES destinationUsageMode) 4297{ 4298 D3D12TextureSubresource *subresource = D3D12_INTERNAL_FetchTextureSubresource( 4299 container, 4300 layer, 4301 level); 4302 4303 if ( 4304 container->canBeCycled && 4305 cycle && 4306 SDL_GetAtomicInt(&subresource->parent->referenceCount) > 0) { 4307 D3D12_INTERNAL_CycleActiveTexture( 4308 commandBuffer->renderer, 4309 container); 4310 4311 subresource = D3D12_INTERNAL_FetchTextureSubresource( 4312 container, 4313 layer, 4314 level); 4315 } 4316 4317 D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 4318 commandBuffer, 4319 destinationUsageMode, 4320 subresource); 4321 4322 return subresource; 4323} 4324 4325static void D3D12_INTERNAL_CycleActiveBuffer( 4326 D3D12Renderer *renderer, 4327 D3D12BufferContainer *container) 4328{ 4329 // If a previously-cycled buffer is available, we can use that. 4330 for (Uint32 i = 0; i < container->bufferCount; i += 1) { 4331 D3D12Buffer *buffer = container->buffers[i]; 4332 if (SDL_GetAtomicInt(&buffer->referenceCount) == 0) { 4333 container->activeBuffer = buffer; 4334 return; 4335 } 4336 } 4337 4338 // No buffer handle is available, create a new one. 4339 D3D12Buffer *buffer = D3D12_INTERNAL_CreateBuffer( 4340 renderer, 4341 container->usage, 4342 container->size, 4343 container->type, 4344 container->debugName); 4345 4346 if (!buffer) { 4347 return; 4348 } 4349 4350 EXPAND_ARRAY_IF_NEEDED( 4351 container->buffers, 4352 D3D12Buffer *, 4353 container->bufferCount + 1, 4354 container->bufferCapacity, 4355 container->bufferCapacity * 2); 4356 4357 container->buffers[container->bufferCount] = buffer; 4358 buffer->container = container; 4359 buffer->containerIndex = container->bufferCount; 4360 container->bufferCount += 1; 4361 4362 container->activeBuffer = buffer; 4363 4364 if (renderer->debug_mode && container->debugName != NULL) { 4365 D3D12_INTERNAL_SetResourceName( 4366 renderer, 4367 container->activeBuffer->handle, 4368 container->debugName); 4369 } 4370} 4371 4372static D3D12Buffer *D3D12_INTERNAL_PrepareBufferForWrite( 4373 D3D12CommandBuffer *commandBuffer, 4374 D3D12BufferContainer *container, 4375 bool cycle, 4376 D3D12_RESOURCE_STATES destinationState) 4377{ 4378 if ( 4379 cycle && 4380 SDL_GetAtomicInt(&container->activeBuffer->referenceCount) > 0) { 4381 D3D12_INTERNAL_CycleActiveBuffer( 4382 commandBuffer->renderer, 4383 container); 4384 } 4385 4386 D3D12_INTERNAL_BufferTransitionFromDefaultUsage( 4387 commandBuffer, 4388 destinationState, 4389 container->activeBuffer); 4390 4391 return container->activeBuffer; 4392} 4393 4394static void D3D12_BeginRenderPass( 4395 SDL_GPUCommandBuffer *commandBuffer, 4396 const SDL_GPUColorTargetInfo *colorTargetInfos, 4397 Uint32 numColorTargets, 4398 const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo) 4399{ 4400 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4401 4402 Uint32 framebufferWidth = SDL_MAX_UINT32; 4403 Uint32 framebufferHeight = SDL_MAX_UINT32; 4404 4405 for (Uint32 i = 0; i < numColorTargets; i += 1) { 4406 D3D12TextureContainer *container = (D3D12TextureContainer *)colorTargetInfos[i].texture; 4407 Uint32 h = container->header.info.height >> colorTargetInfos[i].mip_level; 4408 Uint32 w = container->header.info.width >> colorTargetInfos[i].mip_level; 4409 4410 // The framebuffer cannot be larger than the smallest target. 4411 4412 if (w < framebufferWidth) { 4413 framebufferWidth = w; 4414 } 4415 4416 if (h < framebufferHeight) { 4417 framebufferHeight = h; 4418 } 4419 } 4420 4421 if (depthStencilTargetInfo != NULL) { 4422 D3D12TextureContainer *container = (D3D12TextureContainer *)depthStencilTargetInfo->texture; 4423 4424 Uint32 h = container->header.info.height >> depthStencilTargetInfo->mip_level; 4425 Uint32 w = container->header.info.width >> depthStencilTargetInfo->mip_level; 4426 4427 // The framebuffer cannot be larger than the smallest target. 4428 4429 if (w < framebufferWidth) { 4430 framebufferWidth = w; 4431 } 4432 4433 if (h < framebufferHeight) { 4434 framebufferHeight = h; 4435 } 4436 } 4437 4438 D3D12_CPU_DESCRIPTOR_HANDLE rtvs[MAX_COLOR_TARGET_BINDINGS]; 4439 4440 for (Uint32 i = 0; i < numColorTargets; i += 1) { 4441 D3D12TextureContainer *container = (D3D12TextureContainer *)colorTargetInfos[i].texture; 4442 D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 4443 d3d12CommandBuffer, 4444 container, 4445 container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane, 4446 colorTargetInfos[i].mip_level, 4447 colorTargetInfos[i].cycle, 4448 D3D12_RESOURCE_STATE_RENDER_TARGET); 4449 4450 Uint32 rtvIndex = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0; 4451 D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->rtvHandles[rtvIndex].cpuHandle; 4452 4453 if (colorTargetInfos[i].load_op == SDL_GPU_LOADOP_CLEAR) { 4454 float clearColor[4]; 4455 clearColor[0] = colorTargetInfos[i].clear_color.r; 4456 clearColor[1] = colorTargetInfos[i].clear_color.g; 4457 clearColor[2] = colorTargetInfos[i].clear_color.b; 4458 clearColor[3] = colorTargetInfos[i].clear_color.a; 4459 4460 ID3D12GraphicsCommandList_ClearRenderTargetView( 4461 d3d12CommandBuffer->graphicsCommandList, 4462 rtv, 4463 clearColor, 4464 0, 4465 NULL); 4466 } 4467 4468 rtvs[i] = rtv; 4469 d3d12CommandBuffer->colorTargetSubresources[i] = subresource; 4470 4471 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, subresource->parent); 4472 4473 if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) { 4474 D3D12TextureContainer *resolveContainer = (D3D12TextureContainer *)colorTargetInfos[i].resolve_texture; 4475 D3D12TextureSubresource *resolveSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 4476 d3d12CommandBuffer, 4477 resolveContainer, 4478 colorTargetInfos[i].resolve_layer, 4479 colorTargetInfos[i].resolve_mip_level, 4480 colorTargetInfos[i].cycle_resolve_texture, 4481 D3D12_RESOURCE_STATE_RESOLVE_DEST); 4482 4483 d3d12CommandBuffer->colorResolveSubresources[i] = resolveSubresource; 4484 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, resolveSubresource->parent); 4485 } 4486 } 4487 4488 D3D12_CPU_DESCRIPTOR_HANDLE dsv; 4489 if (depthStencilTargetInfo != NULL) { 4490 D3D12TextureContainer *container = (D3D12TextureContainer *)depthStencilTargetInfo->texture; 4491 D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 4492 d3d12CommandBuffer, 4493 container, 4494 depthStencilTargetInfo->layer, 4495 depthStencilTargetInfo->mip_level, 4496 depthStencilTargetInfo->cycle, 4497 D3D12_RESOURCE_STATE_DEPTH_WRITE); 4498 4499 if ( 4500 depthStencilTargetInfo->load_op == SDL_GPU_LOADOP_CLEAR || 4501 depthStencilTargetInfo->stencil_load_op == SDL_GPU_LOADOP_CLEAR) { 4502 D3D12_CLEAR_FLAGS clearFlags = (D3D12_CLEAR_FLAGS)0; 4503 if (depthStencilTargetInfo->load_op == SDL_GPU_LOADOP_CLEAR) { 4504 clearFlags |= D3D12_CLEAR_FLAG_DEPTH; 4505 } 4506 if (depthStencilTargetInfo->stencil_load_op == SDL_GPU_LOADOP_CLEAR) { 4507 clearFlags |= D3D12_CLEAR_FLAG_STENCIL; 4508 } 4509 4510 ID3D12GraphicsCommandList_ClearDepthStencilView( 4511 d3d12CommandBuffer->graphicsCommandList, 4512 subresource->dsvHandle.cpuHandle, 4513 clearFlags, 4514 depthStencilTargetInfo->clear_depth, 4515 depthStencilTargetInfo->clear_stencil, 4516 0, 4517 NULL); 4518 } 4519 4520 dsv = subresource->dsvHandle.cpuHandle; 4521 d3d12CommandBuffer->depthStencilTextureSubresource = subresource; 4522 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, subresource->parent); 4523 } 4524 4525 ID3D12GraphicsCommandList_OMSetRenderTargets( 4526 d3d12CommandBuffer->graphicsCommandList, 4527 numColorTargets, 4528 rtvs, 4529 false, 4530 (depthStencilTargetInfo == NULL) ? NULL : &dsv); 4531 4532 // Set sensible default states 4533 SDL_GPUViewport defaultViewport; 4534 defaultViewport.x = 0; 4535 defaultViewport.y = 0; 4536 defaultViewport.w = (float)framebufferWidth; 4537 defaultViewport.h = (float)framebufferHeight; 4538 defaultViewport.min_depth = 0; 4539 defaultViewport.max_depth = 1; 4540 4541 D3D12_SetViewport( 4542 commandBuffer, 4543 &defaultViewport); 4544 4545 SDL_Rect defaultScissor; 4546 defaultScissor.x = 0; 4547 defaultScissor.y = 0; 4548 defaultScissor.w = (Sint32)framebufferWidth; 4549 defaultScissor.h = (Sint32)framebufferHeight; 4550 4551 D3D12_SetScissor( 4552 commandBuffer, 4553 &defaultScissor); 4554 4555 D3D12_SetStencilReference( 4556 commandBuffer, 4557 0); 4558 4559 SDL_FColor blendConstants; 4560 blendConstants.r = 1.0f; 4561 blendConstants.g = 1.0f; 4562 blendConstants.b = 1.0f; 4563 blendConstants.a = 1.0f; 4564 4565 D3D12_SetBlendConstants( 4566 commandBuffer, 4567 blendConstants); 4568} 4569 4570static void D3D12_INTERNAL_TrackUniformBuffer( 4571 D3D12CommandBuffer *commandBuffer, 4572 D3D12UniformBuffer *uniformBuffer) 4573{ 4574 Uint32 i; 4575 for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { 4576 if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) { 4577 return; 4578 } 4579 } 4580 4581 if (commandBuffer->usedUniformBufferCount == commandBuffer->usedUniformBufferCapacity) { 4582 commandBuffer->usedUniformBufferCapacity += 1; 4583 commandBuffer->usedUniformBuffers = (D3D12UniformBuffer **)SDL_realloc( 4584 commandBuffer->usedUniformBuffers, 4585 commandBuffer->usedUniformBufferCapacity * sizeof(D3D12UniformBuffer *)); 4586 } 4587 4588 commandBuffer->usedUniformBuffers[commandBuffer->usedUniformBufferCount] = uniformBuffer; 4589 commandBuffer->usedUniformBufferCount += 1; 4590 4591 D3D12_INTERNAL_TrackBuffer( 4592 commandBuffer, 4593 uniformBuffer->buffer); 4594} 4595 4596static D3D12UniformBuffer *D3D12_INTERNAL_AcquireUniformBufferFromPool( 4597 D3D12CommandBuffer *commandBuffer) 4598{ 4599 D3D12Renderer *renderer = commandBuffer->renderer; 4600 D3D12UniformBuffer *uniformBuffer; 4601 4602 SDL_LockMutex(renderer->acquireUniformBufferLock); 4603 4604 if (renderer->uniformBufferPoolCount > 0) { 4605 uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1]; 4606 renderer->uniformBufferPoolCount -= 1; 4607 } else { 4608 uniformBuffer = (D3D12UniformBuffer *)SDL_calloc(1, sizeof(D3D12UniformBuffer)); 4609 if (!uniformBuffer) { 4610 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 4611 return NULL; 4612 } 4613 4614 uniformBuffer->buffer = D3D12_INTERNAL_CreateBuffer( 4615 renderer, 4616 0, 4617 UNIFORM_BUFFER_SIZE, 4618 D3D12_BUFFER_TYPE_UNIFORM, 4619 NULL); 4620 if (!uniformBuffer->buffer) { 4621 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 4622 return NULL; 4623 } 4624 } 4625 4626 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 4627 4628 uniformBuffer->drawOffset = 0; 4629 uniformBuffer->writeOffset = 0; 4630 4631 HRESULT res = ID3D12Resource_Map( 4632 uniformBuffer->buffer->handle, 4633 0, 4634 NULL, 4635 (void **)&uniformBuffer->buffer->mapPointer); 4636 CHECK_D3D12_ERROR_AND_RETURN("Failed to map buffer pool!", NULL); 4637 4638 D3D12_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer); 4639 4640 return uniformBuffer; 4641} 4642 4643static void D3D12_INTERNAL_ReturnUniformBufferToPool( 4644 D3D12Renderer *renderer, 4645 D3D12UniformBuffer *uniformBuffer) 4646{ 4647 if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) { 4648 renderer->uniformBufferPoolCapacity *= 2; 4649 renderer->uniformBufferPool = (D3D12UniformBuffer **)SDL_realloc( 4650 renderer->uniformBufferPool, 4651 renderer->uniformBufferPoolCapacity * sizeof(D3D12UniformBuffer *)); 4652 } 4653 4654 renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer; 4655 renderer->uniformBufferPoolCount += 1; 4656} 4657 4658static void D3D12_INTERNAL_PushUniformData( 4659 D3D12CommandBuffer *commandBuffer, 4660 SDL_GPUShaderStage shaderStage, 4661 Uint32 slotIndex, 4662 const void *data, 4663 Uint32 length) 4664{ 4665 D3D12UniformBuffer *uniformBuffer; 4666 Uint32 blockSize; 4667 4668 if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) { 4669 if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) { 4670 commandBuffer->vertexUniformBuffers[slotIndex] = D3D12_INTERNAL_AcquireUniformBufferFromPool( 4671 commandBuffer); 4672 } 4673 uniformBuffer = commandBuffer->vertexUniformBuffers[slotIndex]; 4674 } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) { 4675 if (commandBuffer->fragmentUniformBuffers[slotIndex] == NULL) { 4676 commandBuffer->fragmentUniformBuffers[slotIndex] = D3D12_INTERNAL_AcquireUniformBufferFromPool( 4677 commandBuffer); 4678 } 4679 uniformBuffer = commandBuffer->fragmentUniformBuffers[slotIndex]; 4680 } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) { 4681 if (commandBuffer->computeUniformBuffers[slotIndex] == NULL) { 4682 commandBuffer->computeUniformBuffers[slotIndex] = D3D12_INTERNAL_AcquireUniformBufferFromPool( 4683 commandBuffer); 4684 } 4685 uniformBuffer = commandBuffer->computeUniformBuffers[slotIndex]; 4686 } else { 4687 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 4688 return; 4689 } 4690 4691 blockSize = 4692 D3D12_INTERNAL_Align( 4693 length, 4694 256); 4695 4696 // If there is no more room, acquire a new uniform buffer 4697 if (uniformBuffer->writeOffset + blockSize >= UNIFORM_BUFFER_SIZE) { 4698 ID3D12Resource_Unmap( 4699 uniformBuffer->buffer->handle, 4700 0, 4701 NULL); 4702 uniformBuffer->buffer->mapPointer = NULL; 4703 4704 uniformBuffer = D3D12_INTERNAL_AcquireUniformBufferFromPool(commandBuffer); 4705 4706 uniformBuffer->drawOffset = 0; 4707 uniformBuffer->writeOffset = 0; 4708 4709 if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) { 4710 commandBuffer->vertexUniformBuffers[slotIndex] = uniformBuffer; 4711 } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) { 4712 commandBuffer->fragmentUniformBuffers[slotIndex] = uniformBuffer; 4713 } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) { 4714 commandBuffer->computeUniformBuffers[slotIndex] = uniformBuffer; 4715 } else { 4716 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 4717 } 4718 } 4719 4720 uniformBuffer->drawOffset = uniformBuffer->writeOffset; 4721 4722 SDL_memcpy( 4723 (Uint8 *)uniformBuffer->buffer->mapPointer + uniformBuffer->writeOffset, 4724 data, 4725 length); 4726 4727 uniformBuffer->writeOffset += blockSize; 4728 4729 if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) { 4730 commandBuffer->needVertexUniformBufferBind[slotIndex] = true; 4731 } else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) { 4732 commandBuffer->needFragmentUniformBufferBind[slotIndex] = true; 4733 } else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) { 4734 commandBuffer->needComputeUniformBufferBind[slotIndex] = true; 4735 } else { 4736 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!"); 4737 } 4738} 4739 4740static void D3D12_BindGraphicsPipeline( 4741 SDL_GPUCommandBuffer *commandBuffer, 4742 SDL_GPUGraphicsPipeline *graphicsPipeline) 4743{ 4744 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4745 D3D12GraphicsPipeline *pipeline = (D3D12GraphicsPipeline *)graphicsPipeline; 4746 Uint32 i; 4747 4748 d3d12CommandBuffer->currentGraphicsPipeline = pipeline; 4749 4750 // Set the pipeline state 4751 ID3D12GraphicsCommandList_SetPipelineState(d3d12CommandBuffer->graphicsCommandList, pipeline->pipelineState); 4752 ID3D12GraphicsCommandList_SetGraphicsRootSignature(d3d12CommandBuffer->graphicsCommandList, pipeline->rootSignature->handle); 4753 ID3D12GraphicsCommandList_IASetPrimitiveTopology(d3d12CommandBuffer->graphicsCommandList, SDLToD3D12_PrimitiveType[pipeline->primitiveType]); 4754 4755 // Mark that bindings are needed 4756 d3d12CommandBuffer->needVertexSamplerBind = true; 4757 d3d12CommandBuffer->needVertexStorageTextureBind = true; 4758 d3d12CommandBuffer->needVertexStorageBufferBind = true; 4759 d3d12CommandBuffer->needFragmentSamplerBind = true; 4760 d3d12CommandBuffer->needFragmentStorageTextureBind = true; 4761 d3d12CommandBuffer->needFragmentStorageBufferBind = true; 4762 4763 for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 4764 d3d12CommandBuffer->needVertexUniformBufferBind[i] = true; 4765 d3d12CommandBuffer->needFragmentUniformBufferBind[i] = true; 4766 } 4767 4768 for (i = 0; i < pipeline->header.num_vertex_uniform_buffers; i += 1) { 4769 if (d3d12CommandBuffer->vertexUniformBuffers[i] == NULL) { 4770 d3d12CommandBuffer->vertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool( 4771 d3d12CommandBuffer); 4772 } 4773 } 4774 4775 for (i = 0; i < pipeline->header.num_fragment_uniform_buffers; i += 1) { 4776 if (d3d12CommandBuffer->fragmentUniformBuffers[i] == NULL) { 4777 d3d12CommandBuffer->fragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool( 4778 d3d12CommandBuffer); 4779 } 4780 } 4781 4782 D3D12_INTERNAL_TrackGraphicsPipeline(d3d12CommandBuffer, pipeline); 4783} 4784 4785static void D3D12_BindVertexBuffers( 4786 SDL_GPUCommandBuffer *commandBuffer, 4787 Uint32 firstSlot, 4788 const SDL_GPUBufferBinding *bindings, 4789 Uint32 numBindings) 4790{ 4791 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4792 4793 for (Uint32 i = 0; i < numBindings; i += 1) { 4794 D3D12Buffer *currentBuffer = ((D3D12BufferContainer *)bindings[i].buffer)->activeBuffer; 4795 4796 if (d3d12CommandBuffer->vertexBuffers[firstSlot + i] != currentBuffer || d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) { 4797 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, currentBuffer); 4798 4799 d3d12CommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer; 4800 d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset; 4801 d3d12CommandBuffer->needVertexBufferBind = true; 4802 } 4803 } 4804 4805 d3d12CommandBuffer->vertexBufferCount = 4806 SDL_max(d3d12CommandBuffer->vertexBufferCount, firstSlot + numBindings); 4807} 4808 4809static void D3D12_BindIndexBuffer( 4810 SDL_GPUCommandBuffer *commandBuffer, 4811 const SDL_GPUBufferBinding *binding, 4812 SDL_GPUIndexElementSize indexElementSize) 4813{ 4814 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4815 D3D12Buffer *buffer = ((D3D12BufferContainer *)binding->buffer)->activeBuffer; 4816 D3D12_INDEX_BUFFER_VIEW view; 4817 4818 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, buffer); 4819 4820 view.BufferLocation = buffer->virtualAddress + binding->offset; 4821 view.SizeInBytes = buffer->container->size - binding->offset; 4822 view.Format = 4823 indexElementSize == SDL_GPU_INDEXELEMENTSIZE_16BIT ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT; 4824 4825 ID3D12GraphicsCommandList_IASetIndexBuffer( 4826 d3d12CommandBuffer->graphicsCommandList, 4827 &view); 4828} 4829 4830static void D3D12_BindVertexSamplers( 4831 SDL_GPUCommandBuffer *commandBuffer, 4832 Uint32 firstSlot, 4833 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 4834 Uint32 numBindings) 4835{ 4836 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4837 4838 for (Uint32 i = 0; i < numBindings; i += 1) { 4839 D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture; 4840 D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler; 4841 4842 if (d3d12CommandBuffer->vertexSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) { 4843 D3D12_INTERNAL_TrackSampler( 4844 d3d12CommandBuffer, 4845 sampler); 4846 4847 d3d12CommandBuffer->vertexSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle; 4848 d3d12CommandBuffer->needVertexSamplerBind = true; 4849 } 4850 4851 if (d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) { 4852 D3D12_INTERNAL_TrackTexture( 4853 d3d12CommandBuffer, 4854 container->activeTexture); 4855 4856 d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle; 4857 d3d12CommandBuffer->needVertexSamplerBind = true; 4858 } 4859 } 4860} 4861 4862static void D3D12_BindVertexStorageTextures( 4863 SDL_GPUCommandBuffer *commandBuffer, 4864 Uint32 firstSlot, 4865 SDL_GPUTexture *const *storageTextures, 4866 Uint32 numBindings) 4867{ 4868 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4869 4870 for (Uint32 i = 0; i < numBindings; i += 1) { 4871 D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; 4872 D3D12Texture *texture = container->activeTexture; 4873 4874 if (d3d12CommandBuffer->vertexStorageTextureDescriptorHandles[firstSlot + i].ptr != texture->srvHandle.cpuHandle.ptr) { 4875 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture); 4876 4877 d3d12CommandBuffer->vertexStorageTextureDescriptorHandles[firstSlot + i] = texture->srvHandle.cpuHandle; 4878 d3d12CommandBuffer->needVertexStorageTextureBind = true; 4879 } 4880 } 4881} 4882 4883static void D3D12_BindVertexStorageBuffers( 4884 SDL_GPUCommandBuffer *commandBuffer, 4885 Uint32 firstSlot, 4886 SDL_GPUBuffer *const *storageBuffers, 4887 Uint32 numBindings) 4888{ 4889 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4890 4891 for (Uint32 i = 0; i < numBindings; i += 1) { 4892 D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i]; 4893 if (d3d12CommandBuffer->vertexStorageBufferDescriptorHandles[firstSlot + i].ptr != container->activeBuffer->srvDescriptor.cpuHandle.ptr) { 4894 D3D12_INTERNAL_TrackBuffer( 4895 d3d12CommandBuffer, 4896 container->activeBuffer); 4897 4898 d3d12CommandBuffer->vertexStorageBufferDescriptorHandles[firstSlot + i] = container->activeBuffer->srvDescriptor.cpuHandle; 4899 d3d12CommandBuffer->needVertexStorageBufferBind = true; 4900 } 4901 } 4902} 4903 4904static void D3D12_BindFragmentSamplers( 4905 SDL_GPUCommandBuffer *commandBuffer, 4906 Uint32 firstSlot, 4907 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 4908 Uint32 numBindings) 4909{ 4910 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4911 4912 for (Uint32 i = 0; i < numBindings; i += 1) { 4913 D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture; 4914 D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler; 4915 4916 if (d3d12CommandBuffer->fragmentSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) { 4917 D3D12_INTERNAL_TrackSampler( 4918 d3d12CommandBuffer, 4919 sampler); 4920 4921 d3d12CommandBuffer->fragmentSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle; 4922 d3d12CommandBuffer->needFragmentSamplerBind = true; 4923 } 4924 4925 if (d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) { 4926 D3D12_INTERNAL_TrackTexture( 4927 d3d12CommandBuffer, 4928 container->activeTexture); 4929 4930 d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle; 4931 d3d12CommandBuffer->needFragmentSamplerBind = true; 4932 } 4933 } 4934} 4935 4936static void D3D12_BindFragmentStorageTextures( 4937 SDL_GPUCommandBuffer *commandBuffer, 4938 Uint32 firstSlot, 4939 SDL_GPUTexture *const *storageTextures, 4940 Uint32 numBindings) 4941{ 4942 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4943 4944 for (Uint32 i = 0; i < numBindings; i += 1) { 4945 D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; 4946 D3D12Texture *texture = container->activeTexture; 4947 4948 if (d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles[firstSlot + i].ptr != texture->srvHandle.cpuHandle.ptr) { 4949 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture); 4950 4951 d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles[firstSlot + i] = texture->srvHandle.cpuHandle; 4952 d3d12CommandBuffer->needFragmentStorageTextureBind = true; 4953 } 4954 } 4955} 4956 4957static void D3D12_BindFragmentStorageBuffers( 4958 SDL_GPUCommandBuffer *commandBuffer, 4959 Uint32 firstSlot, 4960 SDL_GPUBuffer *const *storageBuffers, 4961 Uint32 numBindings) 4962{ 4963 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4964 4965 for (Uint32 i = 0; i < numBindings; i += 1) { 4966 D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i]; 4967 4968 if (d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles[firstSlot + i].ptr != container->activeBuffer->srvDescriptor.cpuHandle.ptr) { 4969 D3D12_INTERNAL_TrackBuffer( 4970 d3d12CommandBuffer, 4971 container->activeBuffer); 4972 4973 d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles[firstSlot + i] = container->activeBuffer->srvDescriptor.cpuHandle; 4974 d3d12CommandBuffer->needFragmentStorageBufferBind = true; 4975 } 4976 } 4977} 4978 4979static void D3D12_PushVertexUniformData( 4980 SDL_GPUCommandBuffer *commandBuffer, 4981 Uint32 slotIndex, 4982 const void *data, 4983 Uint32 length) 4984{ 4985 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 4986 4987 D3D12_INTERNAL_PushUniformData( 4988 d3d12CommandBuffer, 4989 SDL_GPU_SHADERSTAGE_VERTEX, 4990 slotIndex, 4991 data, 4992 length); 4993} 4994 4995static void D3D12_PushFragmentUniformData( 4996 SDL_GPUCommandBuffer *commandBuffer, 4997 Uint32 slotIndex, 4998 const void *data, 4999 Uint32 length) 5000{ 5001 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5002 5003 D3D12_INTERNAL_PushUniformData( 5004 d3d12CommandBuffer, 5005 SDL_GPU_SHADERSTAGE_FRAGMENT, 5006 slotIndex, 5007 data, 5008 length); 5009} 5010 5011static void D3D12_INTERNAL_SetGPUDescriptorHeaps(D3D12CommandBuffer *commandBuffer) 5012{ 5013 ID3D12DescriptorHeap *heaps[2]; 5014 D3D12DescriptorHeap *viewHeap; 5015 D3D12DescriptorHeap *samplerHeap; 5016 5017 viewHeap = D3D12_INTERNAL_AcquireGPUDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); 5018 samplerHeap = D3D12_INTERNAL_AcquireGPUDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); 5019 5020 commandBuffer->gpuDescriptorHeaps[0] = viewHeap; 5021 commandBuffer->gpuDescriptorHeaps[1] = samplerHeap; 5022 5023 heaps[0] = viewHeap->handle; 5024 heaps[1] = samplerHeap->handle; 5025 5026 ID3D12GraphicsCommandList_SetDescriptorHeaps( 5027 commandBuffer->graphicsCommandList, 5028 2, 5029 heaps); 5030} 5031 5032static void D3D12_INTERNAL_WriteGPUDescriptors( 5033 D3D12CommandBuffer *commandBuffer, 5034 D3D12_DESCRIPTOR_HEAP_TYPE heapType, 5035 D3D12_CPU_DESCRIPTOR_HANDLE *resourceDescriptorHandles, 5036 Uint32 resourceHandleCount, 5037 D3D12_GPU_DESCRIPTOR_HANDLE *gpuBaseDescriptor) 5038{ 5039 D3D12DescriptorHeap *heap; 5040 D3D12_CPU_DESCRIPTOR_HANDLE gpuHeapCpuHandle; 5041 5042 /* Descriptor overflow, acquire new heaps */ 5043 if (commandBuffer->gpuDescriptorHeaps[heapType]->currentDescriptorIndex >= commandBuffer->gpuDescriptorHeaps[heapType]->maxDescriptors) { 5044 D3D12_INTERNAL_SetGPUDescriptorHeaps(commandBuffer); 5045 } 5046 5047 heap = commandBuffer->gpuDescriptorHeaps[heapType]; 5048 5049 // FIXME: need to error on overflow 5050 gpuHeapCpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (heap->currentDescriptorIndex * heap->descriptorSize); 5051 gpuBaseDescriptor->ptr = heap->descriptorHeapGPUStart.ptr + (heap->currentDescriptorIndex * heap->descriptorSize); 5052 5053 for (Uint32 i = 0; i < resourceHandleCount; i += 1) { 5054 // This will crash the driver if it gets a null handle! Cool! 5055 if (resourceDescriptorHandles[i].ptr != 0) 5056 { 5057 ID3D12Device_CopyDescriptorsSimple( 5058 commandBuffer->renderer->device, 5059 1, 5060 gpuHeapCpuHandle, 5061 resourceDescriptorHandles[i], 5062 heapType); 5063 5064 heap->currentDescriptorIndex += 1; 5065 gpuHeapCpuHandle.ptr += heap->descriptorSize; 5066 } 5067 } 5068} 5069 5070static void D3D12_INTERNAL_BindGraphicsResources( 5071 D3D12CommandBuffer *commandBuffer) 5072{ 5073 D3D12GraphicsPipeline *graphicsPipeline = commandBuffer->currentGraphicsPipeline; 5074 5075 /* Acquire GPU descriptor heaps if we haven't yet */ 5076 if (commandBuffer->gpuDescriptorHeaps[0] == NULL) { 5077 D3D12_INTERNAL_SetGPUDescriptorHeaps(commandBuffer); 5078 } 5079 5080 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 5081 D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle; 5082 D3D12_VERTEX_BUFFER_VIEW vertexBufferViews[MAX_VERTEX_BUFFERS]; 5083 5084 if (commandBuffer->needVertexBufferBind) { 5085 for (Uint32 i = 0; i < commandBuffer->vertexBufferCount; i += 1) { 5086 vertexBufferViews[i].BufferLocation = commandBuffer->vertexBuffers[i]->virtualAddress + commandBuffer->vertexBufferOffsets[i]; 5087 vertexBufferViews[i].SizeInBytes = commandBuffer->vertexBuffers[i]->container->size - commandBuffer->vertexBufferOffsets[i]; 5088 vertexBufferViews[i].StrideInBytes = graphicsPipeline->vertexStrides[i]; 5089 } 5090 5091 ID3D12GraphicsCommandList_IASetVertexBuffers( 5092 commandBuffer->graphicsCommandList, 5093 0, 5094 commandBuffer->vertexBufferCount, 5095 vertexBufferViews); 5096 5097 commandBuffer->needVertexBufferBind = false; 5098 } 5099 5100 if (commandBuffer->needVertexSamplerBind) { 5101 if (graphicsPipeline->header.num_vertex_samplers > 0) { 5102 for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_samplers; i += 1) { 5103 cpuHandles[i] = commandBuffer->vertexSamplerDescriptorHandles[i]; 5104 } 5105 5106 D3D12_INTERNAL_WriteGPUDescriptors( 5107 commandBuffer, 5108 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 5109 cpuHandles, 5110 graphicsPipeline->header.num_vertex_samplers, 5111 &gpuDescriptorHandle); 5112 5113 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5114 commandBuffer->graphicsCommandList, 5115 graphicsPipeline->rootSignature->vertexSamplerRootIndex, 5116 gpuDescriptorHandle); 5117 5118 for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_samplers; i += 1) { 5119 cpuHandles[i] = commandBuffer->vertexSamplerTextureDescriptorHandles[i]; 5120 } 5121 5122 D3D12_INTERNAL_WriteGPUDescriptors( 5123 commandBuffer, 5124 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5125 cpuHandles, 5126 graphicsPipeline->header.num_vertex_samplers, 5127 &gpuDescriptorHandle); 5128 5129 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5130 commandBuffer->graphicsCommandList, 5131 graphicsPipeline->rootSignature->vertexSamplerTextureRootIndex, 5132 gpuDescriptorHandle); 5133 } 5134 commandBuffer->needVertexSamplerBind = false; 5135 } 5136 5137 if (commandBuffer->needVertexStorageTextureBind) { 5138 if (graphicsPipeline->header.num_vertex_storage_textures > 0) { 5139 for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_storage_textures; i += 1) { 5140 cpuHandles[i] = commandBuffer->vertexStorageTextureDescriptorHandles[i]; 5141 } 5142 5143 D3D12_INTERNAL_WriteGPUDescriptors( 5144 commandBuffer, 5145 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5146 cpuHandles, 5147 graphicsPipeline->header.num_vertex_storage_textures, 5148 &gpuDescriptorHandle); 5149 5150 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5151 commandBuffer->graphicsCommandList, 5152 graphicsPipeline->rootSignature->vertexStorageTextureRootIndex, 5153 gpuDescriptorHandle); 5154 } 5155 commandBuffer->needVertexStorageTextureBind = false; 5156 } 5157 5158 if (commandBuffer->needVertexStorageBufferBind) { 5159 if (graphicsPipeline->header.num_vertex_storage_buffers > 0) { 5160 for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_storage_buffers; i += 1) { 5161 cpuHandles[i] = commandBuffer->vertexStorageBufferDescriptorHandles[i]; 5162 } 5163 5164 D3D12_INTERNAL_WriteGPUDescriptors( 5165 commandBuffer, 5166 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5167 cpuHandles, 5168 graphicsPipeline->header.num_vertex_storage_buffers, 5169 &gpuDescriptorHandle); 5170 5171 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5172 commandBuffer->graphicsCommandList, 5173 graphicsPipeline->rootSignature->vertexStorageBufferRootIndex, 5174 gpuDescriptorHandle); 5175 } 5176 commandBuffer->needVertexStorageBufferBind = false; 5177 } 5178 5179 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 5180 if (commandBuffer->needVertexUniformBufferBind[i]) { 5181 if (graphicsPipeline->header.num_vertex_uniform_buffers > i) { 5182 ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView( 5183 commandBuffer->graphicsCommandList, 5184 graphicsPipeline->rootSignature->vertexUniformBufferRootIndex[i], 5185 commandBuffer->vertexUniformBuffers[i]->buffer->virtualAddress + commandBuffer->vertexUniformBuffers[i]->drawOffset); 5186 } 5187 commandBuffer->needVertexUniformBufferBind[i] = false; 5188 } 5189 } 5190 5191 if (commandBuffer->needFragmentSamplerBind) { 5192 if (graphicsPipeline->header.num_fragment_samplers > 0) { 5193 for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_samplers; i += 1) { 5194 cpuHandles[i] = commandBuffer->fragmentSamplerDescriptorHandles[i]; 5195 } 5196 5197 D3D12_INTERNAL_WriteGPUDescriptors( 5198 commandBuffer, 5199 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 5200 cpuHandles, 5201 graphicsPipeline->header.num_fragment_samplers, 5202 &gpuDescriptorHandle); 5203 5204 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5205 commandBuffer->graphicsCommandList, 5206 graphicsPipeline->rootSignature->fragmentSamplerRootIndex, 5207 gpuDescriptorHandle); 5208 5209 for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_samplers; i += 1) { 5210 cpuHandles[i] = commandBuffer->fragmentSamplerTextureDescriptorHandles[i]; 5211 } 5212 5213 D3D12_INTERNAL_WriteGPUDescriptors( 5214 commandBuffer, 5215 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5216 cpuHandles, 5217 graphicsPipeline->header.num_fragment_samplers, 5218 &gpuDescriptorHandle); 5219 5220 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5221 commandBuffer->graphicsCommandList, 5222 graphicsPipeline->rootSignature->fragmentSamplerTextureRootIndex, 5223 gpuDescriptorHandle); 5224 } 5225 commandBuffer->needFragmentSamplerBind = false; 5226 } 5227 5228 if (commandBuffer->needFragmentStorageTextureBind) { 5229 if (graphicsPipeline->header.num_fragment_storage_textures > 0) { 5230 for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_storage_textures; i += 1) { 5231 cpuHandles[i] = commandBuffer->fragmentStorageTextureDescriptorHandles[i]; 5232 } 5233 5234 D3D12_INTERNAL_WriteGPUDescriptors( 5235 commandBuffer, 5236 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5237 cpuHandles, 5238 graphicsPipeline->header.num_fragment_storage_textures, 5239 &gpuDescriptorHandle); 5240 5241 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5242 commandBuffer->graphicsCommandList, 5243 graphicsPipeline->rootSignature->fragmentStorageTextureRootIndex, 5244 gpuDescriptorHandle); 5245 } 5246 commandBuffer->needFragmentStorageTextureBind = false; 5247 } 5248 5249 if (commandBuffer->needFragmentStorageBufferBind) { 5250 if (graphicsPipeline->header.num_fragment_storage_buffers > 0) { 5251 for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_storage_buffers; i += 1) { 5252 cpuHandles[i] = commandBuffer->fragmentStorageBufferDescriptorHandles[i]; 5253 } 5254 5255 D3D12_INTERNAL_WriteGPUDescriptors( 5256 commandBuffer, 5257 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5258 cpuHandles, 5259 graphicsPipeline->header.num_fragment_storage_buffers, 5260 &gpuDescriptorHandle); 5261 5262 ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable( 5263 commandBuffer->graphicsCommandList, 5264 graphicsPipeline->rootSignature->fragmentStorageBufferRootIndex, 5265 gpuDescriptorHandle); 5266 } 5267 commandBuffer->needFragmentStorageBufferBind = false; 5268 } 5269 5270 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 5271 if (commandBuffer->needFragmentUniformBufferBind[i]) { 5272 if (graphicsPipeline->header.num_fragment_uniform_buffers > i) { 5273 ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView( 5274 commandBuffer->graphicsCommandList, 5275 graphicsPipeline->rootSignature->fragmentUniformBufferRootIndex[i], 5276 commandBuffer->fragmentUniformBuffers[i]->buffer->virtualAddress + commandBuffer->fragmentUniformBuffers[i]->drawOffset); 5277 } 5278 commandBuffer->needFragmentUniformBufferBind[i] = false; 5279 } 5280 } 5281} 5282 5283static void D3D12_DrawIndexedPrimitives( 5284 SDL_GPUCommandBuffer *commandBuffer, 5285 Uint32 numIndices, 5286 Uint32 numInstances, 5287 Uint32 firstIndex, 5288 Sint32 vertexOffset, 5289 Uint32 firstInstance) 5290{ 5291 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5292 D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); 5293 5294 ID3D12GraphicsCommandList_DrawIndexedInstanced( 5295 d3d12CommandBuffer->graphicsCommandList, 5296 numIndices, 5297 numInstances, 5298 firstIndex, 5299 vertexOffset, 5300 firstInstance); 5301} 5302 5303static void D3D12_DrawPrimitives( 5304 SDL_GPUCommandBuffer *commandBuffer, 5305 Uint32 numVertices, 5306 Uint32 numInstances, 5307 Uint32 firstVertex, 5308 Uint32 firstInstance) 5309{ 5310 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5311 D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); 5312 5313 ID3D12GraphicsCommandList_DrawInstanced( 5314 d3d12CommandBuffer->graphicsCommandList, 5315 numVertices, 5316 numInstances, 5317 firstVertex, 5318 firstInstance); 5319} 5320 5321static void D3D12_DrawPrimitivesIndirect( 5322 SDL_GPUCommandBuffer *commandBuffer, 5323 SDL_GPUBuffer *buffer, 5324 Uint32 offset, 5325 Uint32 drawCount) 5326{ 5327 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5328 D3D12Buffer *d3d12Buffer = ((D3D12BufferContainer *)buffer)->activeBuffer; 5329 5330 D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); 5331 5332 ID3D12GraphicsCommandList_ExecuteIndirect( 5333 d3d12CommandBuffer->graphicsCommandList, 5334 d3d12CommandBuffer->renderer->indirectDrawCommandSignature, 5335 drawCount, 5336 d3d12Buffer->handle, 5337 offset, 5338 NULL, 5339 0); 5340 5341 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, d3d12Buffer); 5342} 5343 5344static void D3D12_DrawIndexedPrimitivesIndirect( 5345 SDL_GPUCommandBuffer *commandBuffer, 5346 SDL_GPUBuffer *buffer, 5347 Uint32 offset, 5348 Uint32 drawCount) 5349{ 5350 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5351 D3D12Buffer *d3d12Buffer = ((D3D12BufferContainer *)buffer)->activeBuffer; 5352 5353 D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); 5354 5355 ID3D12GraphicsCommandList_ExecuteIndirect( 5356 d3d12CommandBuffer->graphicsCommandList, 5357 d3d12CommandBuffer->renderer->indirectIndexedDrawCommandSignature, 5358 drawCount, 5359 d3d12Buffer->handle, 5360 offset, 5361 NULL, 5362 0); 5363 5364 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, d3d12Buffer); 5365} 5366 5367static void D3D12_EndRenderPass( 5368 SDL_GPUCommandBuffer *commandBuffer) 5369{ 5370 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5371 Uint32 i; 5372 5373 for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) { 5374 if (d3d12CommandBuffer->colorTargetSubresources[i] != NULL) { 5375 if (d3d12CommandBuffer->colorResolveSubresources[i] != NULL) { 5376 // Resolving requires some extra barriers 5377 D3D12_INTERNAL_TextureSubresourceBarrier( 5378 d3d12CommandBuffer, 5379 D3D12_RESOURCE_STATE_RENDER_TARGET, 5380 D3D12_RESOURCE_STATE_RESOLVE_SOURCE, 5381 d3d12CommandBuffer->colorTargetSubresources[i] 5382 ); 5383 5384 ID3D12GraphicsCommandList_ResolveSubresource( 5385 d3d12CommandBuffer->graphicsCommandList, 5386 d3d12CommandBuffer->colorResolveSubresources[i]->parent->resource, 5387 d3d12CommandBuffer->colorResolveSubresources[i]->index, 5388 d3d12CommandBuffer->colorTargetSubresources[i]->parent->resource, 5389 d3d12CommandBuffer->colorTargetSubresources[i]->index, 5390 SDLToD3D12_TextureFormat[d3d12CommandBuffer->colorTargetSubresources[i]->parent->container->header.info.format]); 5391 5392 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 5393 d3d12CommandBuffer, 5394 D3D12_RESOURCE_STATE_RESOLVE_SOURCE, 5395 d3d12CommandBuffer->colorTargetSubresources[i]); 5396 5397 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 5398 d3d12CommandBuffer, 5399 D3D12_RESOURCE_STATE_RESOLVE_DEST, 5400 d3d12CommandBuffer->colorResolveSubresources[i]); 5401 } else { 5402 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 5403 d3d12CommandBuffer, 5404 D3D12_RESOURCE_STATE_RENDER_TARGET, 5405 d3d12CommandBuffer->colorTargetSubresources[i]); 5406 } 5407 } 5408 } 5409 5410 if (d3d12CommandBuffer->depthStencilTextureSubresource != NULL) { 5411 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 5412 d3d12CommandBuffer, 5413 D3D12_RESOURCE_STATE_DEPTH_WRITE, 5414 d3d12CommandBuffer->depthStencilTextureSubresource); 5415 5416 d3d12CommandBuffer->depthStencilTextureSubresource = NULL; 5417 } 5418 5419 d3d12CommandBuffer->currentGraphicsPipeline = NULL; 5420 5421 ID3D12GraphicsCommandList_OMSetRenderTargets( 5422 d3d12CommandBuffer->graphicsCommandList, 5423 0, 5424 NULL, 5425 false, 5426 NULL); 5427 5428 // Reset bind state 5429 SDL_zeroa(d3d12CommandBuffer->colorTargetSubresources); 5430 SDL_zeroa(d3d12CommandBuffer->colorResolveSubresources); 5431 d3d12CommandBuffer->depthStencilTextureSubresource = NULL; 5432 5433 SDL_zeroa(d3d12CommandBuffer->vertexBuffers); 5434 SDL_zeroa(d3d12CommandBuffer->vertexBufferOffsets); 5435 d3d12CommandBuffer->vertexBufferCount = 0; 5436 5437 SDL_zeroa(d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles); 5438 SDL_zeroa(d3d12CommandBuffer->vertexSamplerDescriptorHandles); 5439 SDL_zeroa(d3d12CommandBuffer->vertexStorageTextureDescriptorHandles); 5440 SDL_zeroa(d3d12CommandBuffer->vertexStorageBufferDescriptorHandles); 5441 5442 SDL_zeroa(d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles); 5443 SDL_zeroa(d3d12CommandBuffer->fragmentSamplerDescriptorHandles); 5444 SDL_zeroa(d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles); 5445 SDL_zeroa(d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles); 5446} 5447 5448// Compute Pass 5449 5450static void D3D12_BeginComputePass( 5451 SDL_GPUCommandBuffer *commandBuffer, 5452 const SDL_GPUStorageTextureReadWriteBinding *storageTextureBindings, 5453 Uint32 numStorageTextureBindings, 5454 const SDL_GPUStorageBufferReadWriteBinding *storageBufferBindings, 5455 Uint32 numStorageBufferBindings) 5456{ 5457 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5458 5459 d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount = numStorageTextureBindings; 5460 d3d12CommandBuffer->computeReadWriteStorageBufferCount = numStorageBufferBindings; 5461 5462 /* Read-write resources will be actually bound in BindComputePipeline 5463 * after the root signature is set. 5464 * We also have to scan to see which barriers we actually need because depth slices aren't separate subresources 5465 */ 5466 if (numStorageTextureBindings > 0) { 5467 for (Uint32 i = 0; i < numStorageTextureBindings; i += 1) { 5468 D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextureBindings[i].texture; 5469 5470 D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 5471 d3d12CommandBuffer, 5472 container, 5473 storageTextureBindings[i].layer, 5474 storageTextureBindings[i].mip_level, 5475 storageTextureBindings[i].cycle, 5476 D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 5477 5478 d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i] = subresource; 5479 d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles[i] = subresource->uavHandle.cpuHandle; 5480 5481 D3D12_INTERNAL_TrackTexture( 5482 d3d12CommandBuffer, 5483 subresource->parent); 5484 } 5485 } 5486 5487 if (numStorageBufferBindings > 0) { 5488 for (Uint32 i = 0; i < numStorageBufferBindings; i += 1) { 5489 D3D12BufferContainer *container = (D3D12BufferContainer *)storageBufferBindings[i].buffer; 5490 5491 D3D12Buffer *buffer = D3D12_INTERNAL_PrepareBufferForWrite( 5492 d3d12CommandBuffer, 5493 container, 5494 storageBufferBindings[i].cycle, 5495 D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 5496 5497 d3d12CommandBuffer->computeReadWriteStorageBuffers[i] = buffer; 5498 d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles[i] = buffer->uavDescriptor.cpuHandle; 5499 5500 D3D12_INTERNAL_TrackBuffer( 5501 d3d12CommandBuffer, 5502 buffer); 5503 } 5504 } 5505} 5506 5507static void D3D12_BindComputePipeline( 5508 SDL_GPUCommandBuffer *commandBuffer, 5509 SDL_GPUComputePipeline *computePipeline) 5510{ 5511 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5512 5513 /* Acquire GPU descriptor heaps if we haven't yet */ 5514 if (d3d12CommandBuffer->gpuDescriptorHeaps[0] == NULL) { 5515 D3D12_INTERNAL_SetGPUDescriptorHeaps(d3d12CommandBuffer); 5516 } 5517 5518 D3D12ComputePipeline *pipeline = (D3D12ComputePipeline *)computePipeline; 5519 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 5520 D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle; 5521 5522 ID3D12GraphicsCommandList_SetPipelineState( 5523 d3d12CommandBuffer->graphicsCommandList, 5524 pipeline->pipelineState); 5525 5526 ID3D12GraphicsCommandList_SetComputeRootSignature( 5527 d3d12CommandBuffer->graphicsCommandList, 5528 pipeline->rootSignature->handle); 5529 5530 d3d12CommandBuffer->currentComputePipeline = pipeline; 5531 5532 d3d12CommandBuffer->needComputeSamplerBind = true; 5533 d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true; 5534 d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true; 5535 5536 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 5537 d3d12CommandBuffer->needComputeUniformBufferBind[i] = true; 5538 } 5539 5540 for (Uint32 i = 0; i < pipeline->header.numUniformBuffers; i += 1) { 5541 if (d3d12CommandBuffer->computeUniformBuffers[i] == NULL) { 5542 d3d12CommandBuffer->computeUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool( 5543 d3d12CommandBuffer); 5544 } 5545 } 5546 5547 D3D12_INTERNAL_TrackComputePipeline(d3d12CommandBuffer, pipeline); 5548 5549 // Bind write-only resources after setting root signature 5550 if (pipeline->header.numReadWriteStorageTextures > 0) { 5551 for (Uint32 i = 0; i < pipeline->header.numReadWriteStorageTextures; i += 1) { 5552 cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles[i]; 5553 } 5554 5555 D3D12_INTERNAL_WriteGPUDescriptors( 5556 d3d12CommandBuffer, 5557 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5558 cpuHandles, 5559 d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount, 5560 &gpuDescriptorHandle); 5561 5562 ID3D12GraphicsCommandList_SetComputeRootDescriptorTable( 5563 d3d12CommandBuffer->graphicsCommandList, 5564 d3d12CommandBuffer->currentComputePipeline->rootSignature->readWriteStorageTextureRootIndex, 5565 gpuDescriptorHandle); 5566 } 5567 5568 if (pipeline->header.numReadWriteStorageBuffers > 0) { 5569 for (Uint32 i = 0; i < pipeline->header.numReadWriteStorageBuffers; i += 1) { 5570 cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles[i]; 5571 } 5572 5573 D3D12_INTERNAL_WriteGPUDescriptors( 5574 d3d12CommandBuffer, 5575 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5576 cpuHandles, 5577 d3d12CommandBuffer->computeReadWriteStorageBufferCount, 5578 &gpuDescriptorHandle); 5579 5580 ID3D12GraphicsCommandList_SetComputeRootDescriptorTable( 5581 d3d12CommandBuffer->graphicsCommandList, 5582 d3d12CommandBuffer->currentComputePipeline->rootSignature->readWriteStorageBufferRootIndex, 5583 gpuDescriptorHandle); 5584 } 5585} 5586 5587static void D3D12_BindComputeSamplers( 5588 SDL_GPUCommandBuffer *commandBuffer, 5589 Uint32 firstSlot, 5590 const SDL_GPUTextureSamplerBinding *textureSamplerBindings, 5591 Uint32 numBindings) 5592{ 5593 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5594 5595 for (Uint32 i = 0; i < numBindings; i += 1) { 5596 D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture; 5597 D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler; 5598 5599 if (d3d12CommandBuffer->computeSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) { 5600 D3D12_INTERNAL_TrackSampler( 5601 d3d12CommandBuffer, 5602 (D3D12Sampler *)textureSamplerBindings[i].sampler); 5603 5604 d3d12CommandBuffer->computeSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle; 5605 d3d12CommandBuffer->needComputeSamplerBind = true; 5606 } 5607 5608 if (d3d12CommandBuffer->computeSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) { 5609 D3D12_INTERNAL_TrackTexture( 5610 d3d12CommandBuffer, 5611 container->activeTexture); 5612 5613 d3d12CommandBuffer->computeSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle; 5614 d3d12CommandBuffer->needComputeSamplerBind = true; 5615 } 5616 } 5617} 5618 5619static void D3D12_BindComputeStorageTextures( 5620 SDL_GPUCommandBuffer *commandBuffer, 5621 Uint32 firstSlot, 5622 SDL_GPUTexture *const *storageTextures, 5623 Uint32 numBindings) 5624{ 5625 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5626 5627 for (Uint32 i = 0; i < numBindings; i += 1) { 5628 D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i]; 5629 5630 if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != container->activeTexture) { 5631 /* If a different texture was in this slot, transition it back to its default usage */ 5632 if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != NULL) { 5633 D3D12_INTERNAL_TextureTransitionToDefaultUsage( 5634 d3d12CommandBuffer, 5635 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, 5636 d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i]); 5637 } 5638 5639 /* Then transition the new texture and prepare it for binding */ 5640 D3D12_INTERNAL_TextureTransitionFromDefaultUsage( 5641 d3d12CommandBuffer, 5642 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, 5643 container->activeTexture); 5644 5645 D3D12_INTERNAL_TrackTexture( 5646 d3d12CommandBuffer, 5647 container->activeTexture); 5648 5649 d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] = container->activeTexture; 5650 d3d12CommandBuffer->computeReadOnlyStorageTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle; 5651 d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true; 5652 } 5653 } 5654} 5655 5656static void D3D12_BindComputeStorageBuffers( 5657 SDL_GPUCommandBuffer *commandBuffer, 5658 Uint32 firstSlot, 5659 SDL_GPUBuffer *const *storageBuffers, 5660 Uint32 numBindings) 5661{ 5662 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5663 5664 for (Uint32 i = 0; i < numBindings; i += 1) { 5665 D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i]; 5666 D3D12Buffer *buffer = container->activeBuffer; 5667 5668 if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != buffer) { 5669 /* If a different buffer was in this slot, transition it back to its default usage */ 5670 if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != NULL) { 5671 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 5672 d3d12CommandBuffer, 5673 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, 5674 d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i]); 5675 } 5676 5677 /* Then transition the new buffer and prepare it for binding */ 5678 D3D12_INTERNAL_BufferTransitionFromDefaultUsage( 5679 d3d12CommandBuffer, 5680 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, 5681 buffer); 5682 5683 D3D12_INTERNAL_TrackBuffer( 5684 d3d12CommandBuffer, 5685 buffer); 5686 5687 d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] = buffer; 5688 d3d12CommandBuffer->computeReadOnlyStorageBufferDescriptorHandles[firstSlot + i] = buffer->srvDescriptor.cpuHandle; 5689 d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true; 5690 } 5691 } 5692} 5693 5694static void D3D12_PushComputeUniformData( 5695 SDL_GPUCommandBuffer *commandBuffer, 5696 Uint32 slotIndex, 5697 const void *data, 5698 Uint32 length) 5699{ 5700 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5701 5702 D3D12_INTERNAL_PushUniformData( 5703 d3d12CommandBuffer, 5704 SDL_GPU_SHADERSTAGE_COMPUTE, 5705 slotIndex, 5706 data, 5707 length); 5708} 5709 5710static void D3D12_INTERNAL_BindComputeResources( 5711 D3D12CommandBuffer *commandBuffer) 5712{ 5713 D3D12ComputePipeline *computePipeline = commandBuffer->currentComputePipeline; 5714 5715 /* Acquire GPU descriptor heaps if we haven't yet */ 5716 if (commandBuffer->gpuDescriptorHeaps[0] == NULL) { 5717 D3D12_INTERNAL_SetGPUDescriptorHeaps(commandBuffer); 5718 } 5719 5720 D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE]; 5721 D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle; 5722 5723 if (commandBuffer->needComputeSamplerBind) { 5724 if (computePipeline->header.numSamplers > 0) { 5725 for (Uint32 i = 0; i < computePipeline->header.numSamplers; i += 1) { 5726 cpuHandles[i] = commandBuffer->computeSamplerDescriptorHandles[i]; 5727 } 5728 5729 D3D12_INTERNAL_WriteGPUDescriptors( 5730 commandBuffer, 5731 D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, 5732 cpuHandles, 5733 computePipeline->header.numSamplers, 5734 &gpuDescriptorHandle); 5735 5736 ID3D12GraphicsCommandList_SetComputeRootDescriptorTable( 5737 commandBuffer->graphicsCommandList, 5738 computePipeline->rootSignature->samplerRootIndex, 5739 gpuDescriptorHandle); 5740 5741 for (Uint32 i = 0; i < computePipeline->header.numSamplers; i += 1) { 5742 cpuHandles[i] = commandBuffer->computeSamplerTextureDescriptorHandles[i]; 5743 } 5744 5745 D3D12_INTERNAL_WriteGPUDescriptors( 5746 commandBuffer, 5747 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5748 cpuHandles, 5749 computePipeline->header.numSamplers, 5750 &gpuDescriptorHandle); 5751 5752 ID3D12GraphicsCommandList_SetComputeRootDescriptorTable( 5753 commandBuffer->graphicsCommandList, 5754 computePipeline->rootSignature->samplerTextureRootIndex, 5755 gpuDescriptorHandle); 5756 } 5757 commandBuffer->needComputeSamplerBind = false; 5758 } 5759 5760 if (commandBuffer->needComputeReadOnlyStorageTextureBind) { 5761 if (computePipeline->header.numReadonlyStorageTextures > 0) { 5762 for (Uint32 i = 0; i < computePipeline->header.numReadonlyStorageTextures; i += 1) { 5763 cpuHandles[i] = commandBuffer->computeReadOnlyStorageTextureDescriptorHandles[i]; 5764 } 5765 5766 D3D12_INTERNAL_WriteGPUDescriptors( 5767 commandBuffer, 5768 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5769 cpuHandles, 5770 computePipeline->header.numReadonlyStorageTextures, 5771 &gpuDescriptorHandle); 5772 5773 ID3D12GraphicsCommandList_SetComputeRootDescriptorTable( 5774 commandBuffer->graphicsCommandList, 5775 computePipeline->rootSignature->readOnlyStorageTextureRootIndex, 5776 gpuDescriptorHandle); 5777 } 5778 commandBuffer->needComputeReadOnlyStorageTextureBind = false; 5779 } 5780 5781 if (commandBuffer->needComputeReadOnlyStorageBufferBind) { 5782 if (computePipeline->header.numReadonlyStorageBuffers > 0) { 5783 for (Uint32 i = 0; i < computePipeline->header.numReadonlyStorageBuffers; i += 1) { 5784 cpuHandles[i] = commandBuffer->computeReadOnlyStorageBufferDescriptorHandles[i]; 5785 } 5786 5787 D3D12_INTERNAL_WriteGPUDescriptors( 5788 commandBuffer, 5789 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 5790 cpuHandles, 5791 computePipeline->header.numReadonlyStorageBuffers, 5792 &gpuDescriptorHandle); 5793 5794 ID3D12GraphicsCommandList_SetComputeRootDescriptorTable( 5795 commandBuffer->graphicsCommandList, 5796 computePipeline->rootSignature->readOnlyStorageBufferRootIndex, 5797 gpuDescriptorHandle); 5798 } 5799 commandBuffer->needComputeReadOnlyStorageBufferBind = false; 5800 } 5801 5802 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 5803 if (commandBuffer->needComputeUniformBufferBind[i]) { 5804 if (computePipeline->header.numUniformBuffers > i) { 5805 ID3D12GraphicsCommandList_SetComputeRootConstantBufferView( 5806 commandBuffer->graphicsCommandList, 5807 computePipeline->rootSignature->uniformBufferRootIndex[i], 5808 commandBuffer->computeUniformBuffers[i]->buffer->virtualAddress + commandBuffer->computeUniformBuffers[i]->drawOffset); 5809 } 5810 } 5811 commandBuffer->needComputeUniformBufferBind[i] = false; 5812 } 5813} 5814 5815static void D3D12_DispatchCompute( 5816 SDL_GPUCommandBuffer *commandBuffer, 5817 Uint32 groupcountX, 5818 Uint32 groupcountY, 5819 Uint32 groupcountZ) 5820{ 5821 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5822 5823 D3D12_INTERNAL_BindComputeResources(d3d12CommandBuffer); 5824 ID3D12GraphicsCommandList_Dispatch( 5825 d3d12CommandBuffer->graphicsCommandList, 5826 groupcountX, 5827 groupcountY, 5828 groupcountZ); 5829} 5830 5831static void D3D12_DispatchComputeIndirect( 5832 SDL_GPUCommandBuffer *commandBuffer, 5833 SDL_GPUBuffer *buffer, 5834 Uint32 offset) 5835{ 5836 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5837 D3D12Buffer *d3d12Buffer = ((D3D12BufferContainer *)buffer)->activeBuffer; 5838 5839 D3D12_INTERNAL_BindComputeResources(d3d12CommandBuffer); 5840 ID3D12GraphicsCommandList_ExecuteIndirect( 5841 d3d12CommandBuffer->graphicsCommandList, 5842 d3d12CommandBuffer->renderer->indirectDispatchCommandSignature, 5843 1, 5844 d3d12Buffer->handle, 5845 offset, 5846 NULL, 5847 0); 5848 5849 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, d3d12Buffer); 5850} 5851 5852static void D3D12_EndComputePass( 5853 SDL_GPUCommandBuffer *commandBuffer) 5854{ 5855 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5856 5857 for (Uint32 i = 0; i < d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount; i += 1) { 5858 if (d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i]) { 5859 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 5860 d3d12CommandBuffer, 5861 D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 5862 d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i]); 5863 5864 d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i] = NULL; 5865 } 5866 } 5867 d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount = 0; 5868 5869 for (Uint32 i = 0; i < d3d12CommandBuffer->computeReadWriteStorageBufferCount; i += 1) { 5870 if (d3d12CommandBuffer->computeReadWriteStorageBuffers[i]) { 5871 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 5872 d3d12CommandBuffer, 5873 D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 5874 d3d12CommandBuffer->computeReadWriteStorageBuffers[i]); 5875 5876 d3d12CommandBuffer->computeReadWriteStorageBuffers[i] = NULL; 5877 } 5878 } 5879 d3d12CommandBuffer->computeReadWriteStorageBufferCount = 0; 5880 5881 for (Uint32 i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) { 5882 if (d3d12CommandBuffer->computeReadOnlyStorageTextures[i]) { 5883 D3D12_INTERNAL_TextureTransitionToDefaultUsage( 5884 d3d12CommandBuffer, 5885 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, 5886 d3d12CommandBuffer->computeReadOnlyStorageTextures[i]); 5887 5888 d3d12CommandBuffer->computeReadOnlyStorageTextures[i] = NULL; 5889 } 5890 } 5891 5892 for (Uint32 i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) { 5893 if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[i]) { 5894 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 5895 d3d12CommandBuffer, 5896 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE, 5897 d3d12CommandBuffer->computeReadOnlyStorageBuffers[i]); 5898 5899 d3d12CommandBuffer->computeReadOnlyStorageBuffers[i] = NULL; 5900 } 5901 } 5902 5903 SDL_zeroa(d3d12CommandBuffer->computeSamplerTextureDescriptorHandles); 5904 SDL_zeroa(d3d12CommandBuffer->computeSamplerDescriptorHandles); 5905 5906 SDL_zeroa(d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles); 5907 SDL_zeroa(d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles); 5908 5909 d3d12CommandBuffer->currentComputePipeline = NULL; 5910} 5911 5912// TransferBuffer Data 5913 5914static void *D3D12_MapTransferBuffer( 5915 SDL_GPURenderer *driverData, 5916 SDL_GPUTransferBuffer *transferBuffer, 5917 bool cycle) 5918{ 5919 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 5920 D3D12BufferContainer *container = (D3D12BufferContainer *)transferBuffer; 5921 void *dataPointer; 5922 5923 if ( 5924 cycle && 5925 SDL_GetAtomicInt(&container->activeBuffer->referenceCount) > 0) { 5926 D3D12_INTERNAL_CycleActiveBuffer( 5927 renderer, 5928 container); 5929 } 5930 5931 // Upload buffers are persistently mapped, download buffers are not 5932 if (container->type == D3D12_BUFFER_TYPE_UPLOAD) { 5933 dataPointer = container->activeBuffer->mapPointer; 5934 } else { 5935 ID3D12Resource_Map( 5936 container->activeBuffer->handle, 5937 0, 5938 NULL, 5939 (void **)&dataPointer); 5940 } 5941 5942 return dataPointer; 5943} 5944 5945static void D3D12_UnmapTransferBuffer( 5946 SDL_GPURenderer *driverData, 5947 SDL_GPUTransferBuffer *transferBuffer) 5948{ 5949 (void)driverData; 5950 D3D12BufferContainer *container = (D3D12BufferContainer *)transferBuffer; 5951 5952 // Upload buffers are persistently mapped, download buffers are not 5953 if (container->type == D3D12_BUFFER_TYPE_DOWNLOAD) { 5954 ID3D12Resource_Unmap( 5955 container->activeBuffer->handle, 5956 0, 5957 NULL); 5958 } 5959} 5960 5961// Copy Pass 5962 5963static void D3D12_BeginCopyPass( 5964 SDL_GPUCommandBuffer *commandBuffer) 5965{ 5966 // no-op 5967 (void)commandBuffer; 5968} 5969 5970static void D3D12_UploadToTexture( 5971 SDL_GPUCommandBuffer *commandBuffer, 5972 const SDL_GPUTextureTransferInfo *source, 5973 const SDL_GPUTextureRegion *destination, 5974 bool cycle) 5975{ 5976 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 5977 D3D12Renderer *renderer = (D3D12Renderer *)d3d12CommandBuffer->renderer; 5978 D3D12BufferContainer *transferBufferContainer = (D3D12BufferContainer *)source->transfer_buffer; 5979 D3D12Buffer *temporaryBuffer = NULL; 5980 D3D12_TEXTURE_COPY_LOCATION sourceLocation; 5981 D3D12_TEXTURE_COPY_LOCATION destinationLocation; 5982 Uint32 pixelsPerRow = source->pixels_per_row; 5983 Uint32 blockWidth; 5984 Uint32 blockSize; 5985 Uint32 rowPitch; 5986 Uint32 blockHeight; 5987 Uint32 alignedRowPitch; 5988 Uint32 rowsPerSlice = source->rows_per_layer; 5989 Uint32 bytesPerSlice; 5990 Uint32 alignedBytesPerSlice; 5991 bool needsRealignment; 5992 bool needsPlacementCopy; 5993 5994 // Note that the transfer buffer does not need a barrier, as it is synced by the client. 5995 5996 D3D12TextureContainer *textureContainer = (D3D12TextureContainer *)destination->texture; 5997 D3D12TextureSubresource *textureSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 5998 d3d12CommandBuffer, 5999 textureContainer, 6000 destination->layer, 6001 destination->mip_level, 6002 cycle, 6003 D3D12_RESOURCE_STATE_COPY_DEST); 6004 6005 /* Unless the UnrestrictedBufferTextureCopyPitchSupported feature is supported, D3D12 requires 6006 * texture data row pitch to be 256 byte aligned, which is obviously insane. Instead of exposing 6007 * that restriction to the client, which is a huge rake to step on, and a restriction that no 6008 * other backend requires, we're going to copy data to a temporary buffer, copy THAT data to the 6009 * texture, and then get rid of the temporary buffer ASAP. If we're lucky and the row pitch and 6010 * depth pitch are already aligned, we can skip all of that. 6011 * 6012 * D3D12 also requires offsets to be 512 byte aligned. We'll fix that for the client and warn them as well. 6013 * 6014 * And just for some extra fun, D3D12 doesn't actually support depth pitch, so we have to realign that too! 6015 */ 6016 6017 if (pixelsPerRow == 0) { 6018 pixelsPerRow = destination->w; 6019 } 6020 6021 if (rowsPerSlice == 0) { 6022 rowsPerSlice = destination->h; 6023 } 6024 6025 blockWidth = Texture_GetBlockWidth(textureContainer->header.info.format); 6026 blockSize = SDL_GPUTextureFormatTexelBlockSize(textureContainer->header.info.format); 6027 rowPitch = (pixelsPerRow + (blockWidth - 1)) / blockWidth * blockSize; 6028 blockHeight = (rowsPerSlice + (blockWidth - 1)) / blockWidth; 6029 6030 bytesPerSlice = rowsPerSlice * rowPitch; 6031 6032 if (renderer->UnrestrictedBufferTextureCopyPitchSupported) { 6033 alignedRowPitch = rowPitch; 6034 needsRealignment = false; 6035 needsPlacementCopy = false; 6036 } else { 6037 alignedRowPitch = (destination->w + (blockWidth - 1)) / blockWidth * blockSize; 6038 alignedRowPitch = D3D12_INTERNAL_Align(alignedRowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 6039 needsRealignment = rowsPerSlice != destination->h || rowPitch != alignedRowPitch; 6040 needsPlacementCopy = source->offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT != 0; 6041 } 6042 6043 alignedBytesPerSlice = alignedRowPitch * destination->h; 6044 6045 sourceLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; 6046 sourceLocation.PlacedFootprint.Footprint.Format = SDLToD3D12_TextureFormat[textureContainer->header.info.format]; 6047 sourceLocation.PlacedFootprint.Footprint.RowPitch = alignedRowPitch; 6048 6049 destinationLocation.pResource = textureContainer->activeTexture->resource; 6050 destinationLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 6051 destinationLocation.SubresourceIndex = textureSubresource->index; 6052 6053 if (needsRealignment) { 6054 temporaryBuffer = D3D12_INTERNAL_CreateBuffer( 6055 d3d12CommandBuffer->renderer, 6056 0, 6057 alignedRowPitch * blockHeight * destination->d, 6058 D3D12_BUFFER_TYPE_UPLOAD, 6059 NULL); 6060 6061 if (!temporaryBuffer) { 6062 return; 6063 } 6064 6065 sourceLocation.pResource = temporaryBuffer->handle; 6066 6067 for (Uint32 sliceIndex = 0; sliceIndex < destination->d; sliceIndex += 1) { 6068 for (Uint32 rowIndex = 0; rowIndex < blockHeight; rowIndex += 1) { 6069 SDL_memcpy( 6070 temporaryBuffer->mapPointer + (sliceIndex * alignedBytesPerSlice) + (rowIndex * alignedRowPitch), 6071 transferBufferContainer->activeBuffer->mapPointer + source->offset + (sliceIndex * bytesPerSlice) + (rowIndex * rowPitch), 6072 rowPitch); 6073 6074 } 6075 6076 sourceLocation.PlacedFootprint.Footprint.Width = destination->w; 6077 sourceLocation.PlacedFootprint.Footprint.Height = destination->h; 6078 sourceLocation.PlacedFootprint.Footprint.Depth = 1; 6079 sourceLocation.PlacedFootprint.Offset = (sliceIndex * alignedBytesPerSlice); 6080 6081 ID3D12GraphicsCommandList_CopyTextureRegion( 6082 d3d12CommandBuffer->graphicsCommandList, 6083 &destinationLocation, 6084 destination->x, 6085 destination->y, 6086 destination->z + sliceIndex, 6087 &sourceLocation, 6088 NULL); 6089 } 6090 6091 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, temporaryBuffer); 6092 D3D12_INTERNAL_ReleaseBuffer( 6093 d3d12CommandBuffer->renderer, 6094 temporaryBuffer); 6095 6096 if (d3d12CommandBuffer->renderer->debug_mode) { 6097 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Texture upload row pitch not aligned to 256 bytes! This is suboptimal on D3D12!"); 6098 } 6099 } else if (needsPlacementCopy) { 6100 temporaryBuffer = D3D12_INTERNAL_CreateBuffer( 6101 d3d12CommandBuffer->renderer, 6102 0, 6103 alignedRowPitch * blockHeight * destination->d, 6104 D3D12_BUFFER_TYPE_UPLOAD, 6105 NULL); 6106 6107 if (!temporaryBuffer) { 6108 return; 6109 } 6110 6111 SDL_memcpy( 6112 temporaryBuffer->mapPointer, 6113 transferBufferContainer->activeBuffer->mapPointer + source->offset, 6114 alignedRowPitch * blockHeight * destination->d); 6115 6116 sourceLocation.pResource = temporaryBuffer->handle; 6117 sourceLocation.PlacedFootprint.Offset = 0; 6118 sourceLocation.PlacedFootprint.Footprint.Width = destination->w; 6119 sourceLocation.PlacedFootprint.Footprint.Height = destination->h; 6120 sourceLocation.PlacedFootprint.Footprint.Depth = destination->d; 6121 6122 ID3D12GraphicsCommandList_CopyTextureRegion( 6123 d3d12CommandBuffer->graphicsCommandList, 6124 &destinationLocation, 6125 destination->x, 6126 destination->y, 6127 destination->z, 6128 &sourceLocation, 6129 NULL); 6130 6131 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, temporaryBuffer); 6132 D3D12_INTERNAL_ReleaseBuffer( 6133 d3d12CommandBuffer->renderer, 6134 temporaryBuffer); 6135 6136 if (d3d12CommandBuffer->renderer->debug_mode) { 6137 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Texture upload offset not aligned to 512 bytes! This is suboptimal on D3D12!"); 6138 } 6139 } else { 6140 sourceLocation.pResource = transferBufferContainer->activeBuffer->handle; 6141 sourceLocation.PlacedFootprint.Offset = source->offset; 6142 sourceLocation.PlacedFootprint.Footprint.Width = destination->w; 6143 sourceLocation.PlacedFootprint.Footprint.Height = destination->h; 6144 sourceLocation.PlacedFootprint.Footprint.Depth = destination->d; 6145 6146 ID3D12GraphicsCommandList_CopyTextureRegion( 6147 d3d12CommandBuffer->graphicsCommandList, 6148 &destinationLocation, 6149 destination->x, 6150 destination->y, 6151 destination->z, 6152 &sourceLocation, 6153 NULL); 6154 } 6155 6156 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 6157 d3d12CommandBuffer, 6158 D3D12_RESOURCE_STATE_COPY_DEST, 6159 textureSubresource); 6160 6161 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, transferBufferContainer->activeBuffer); 6162 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, textureSubresource->parent); 6163} 6164 6165static void D3D12_UploadToBuffer( 6166 SDL_GPUCommandBuffer *commandBuffer, 6167 const SDL_GPUTransferBufferLocation *source, 6168 const SDL_GPUBufferRegion *destination, 6169 bool cycle) 6170{ 6171 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6172 D3D12BufferContainer *transferBufferContainer = (D3D12BufferContainer *)source->transfer_buffer; 6173 D3D12BufferContainer *bufferContainer = (D3D12BufferContainer *)destination->buffer; 6174 6175 // The transfer buffer does not need a barrier, it is synced by the client. 6176 6177 D3D12Buffer *buffer = D3D12_INTERNAL_PrepareBufferForWrite( 6178 d3d12CommandBuffer, 6179 bufferContainer, 6180 cycle, 6181 D3D12_RESOURCE_STATE_COPY_DEST); 6182 6183 ID3D12GraphicsCommandList_CopyBufferRegion( 6184 d3d12CommandBuffer->graphicsCommandList, 6185 buffer->handle, 6186 destination->offset, 6187 transferBufferContainer->activeBuffer->handle, 6188 source->offset, 6189 destination->size); 6190 6191 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 6192 d3d12CommandBuffer, 6193 D3D12_RESOURCE_STATE_COPY_DEST, 6194 buffer); 6195 6196 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, transferBufferContainer->activeBuffer); 6197 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, buffer); 6198} 6199 6200static void D3D12_CopyTextureToTexture( 6201 SDL_GPUCommandBuffer *commandBuffer, 6202 const SDL_GPUTextureLocation *source, 6203 const SDL_GPUTextureLocation *destination, 6204 Uint32 w, 6205 Uint32 h, 6206 Uint32 d, 6207 bool cycle) 6208{ 6209 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6210 D3D12_TEXTURE_COPY_LOCATION sourceLocation; 6211 D3D12_TEXTURE_COPY_LOCATION destinationLocation; 6212 6213 D3D12TextureSubresource *sourceSubresource = D3D12_INTERNAL_FetchTextureSubresource( 6214 (D3D12TextureContainer *)source->texture, 6215 source->layer, 6216 source->mip_level); 6217 6218 D3D12TextureSubresource *destinationSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite( 6219 d3d12CommandBuffer, 6220 (D3D12TextureContainer *)destination->texture, 6221 destination->layer, 6222 destination->mip_level, 6223 cycle, 6224 D3D12_RESOURCE_STATE_COPY_DEST); 6225 6226 D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 6227 d3d12CommandBuffer, 6228 D3D12_RESOURCE_STATE_COPY_SOURCE, 6229 sourceSubresource); 6230 6231 sourceLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 6232 sourceLocation.SubresourceIndex = sourceSubresource->index; 6233 sourceLocation.pResource = sourceSubresource->parent->resource; 6234 6235 destinationLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 6236 destinationLocation.SubresourceIndex = destinationSubresource->index; 6237 destinationLocation.pResource = destinationSubresource->parent->resource; 6238 6239 D3D12_BOX sourceBox = { source->x, source->y, source->z, source->x + w, source->y + h, source->z + d }; 6240 6241 ID3D12GraphicsCommandList_CopyTextureRegion( 6242 d3d12CommandBuffer->graphicsCommandList, 6243 &destinationLocation, 6244 destination->x, 6245 destination->y, 6246 destination->z, 6247 &sourceLocation, 6248 &sourceBox); 6249 6250 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 6251 d3d12CommandBuffer, 6252 D3D12_RESOURCE_STATE_COPY_SOURCE, 6253 sourceSubresource); 6254 6255 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 6256 d3d12CommandBuffer, 6257 D3D12_RESOURCE_STATE_COPY_DEST, 6258 destinationSubresource); 6259 6260 D3D12_INTERNAL_TrackTexture( 6261 d3d12CommandBuffer, 6262 sourceSubresource->parent); 6263 6264 D3D12_INTERNAL_TrackTexture( 6265 d3d12CommandBuffer, 6266 destinationSubresource->parent); 6267} 6268 6269static void D3D12_CopyBufferToBuffer( 6270 SDL_GPUCommandBuffer *commandBuffer, 6271 const SDL_GPUBufferLocation *source, 6272 const SDL_GPUBufferLocation *destination, 6273 Uint32 size, 6274 bool cycle) 6275{ 6276 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6277 D3D12BufferContainer *sourceContainer = (D3D12BufferContainer *)source->buffer; 6278 D3D12BufferContainer *destinationContainer = (D3D12BufferContainer *)destination->buffer; 6279 6280 D3D12Buffer *sourceBuffer = sourceContainer->activeBuffer; 6281 D3D12Buffer *destinationBuffer = D3D12_INTERNAL_PrepareBufferForWrite( 6282 d3d12CommandBuffer, 6283 destinationContainer, 6284 cycle, 6285 D3D12_RESOURCE_STATE_COPY_DEST); 6286 6287 D3D12_INTERNAL_BufferTransitionFromDefaultUsage( 6288 d3d12CommandBuffer, 6289 D3D12_RESOURCE_STATE_COPY_SOURCE, 6290 sourceBuffer); 6291 6292 ID3D12GraphicsCommandList_CopyBufferRegion( 6293 d3d12CommandBuffer->graphicsCommandList, 6294 destinationBuffer->handle, 6295 destination->offset, 6296 sourceBuffer->handle, 6297 source->offset, 6298 size); 6299 6300 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 6301 d3d12CommandBuffer, 6302 D3D12_RESOURCE_STATE_COPY_SOURCE, 6303 sourceBuffer); 6304 6305 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 6306 d3d12CommandBuffer, 6307 D3D12_RESOURCE_STATE_COPY_DEST, 6308 destinationBuffer); 6309 6310 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, sourceBuffer); 6311 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, destinationBuffer); 6312} 6313 6314static void D3D12_DownloadFromTexture( 6315 SDL_GPUCommandBuffer *commandBuffer, 6316 const SDL_GPUTextureRegion *source, 6317 const SDL_GPUTextureTransferInfo *destination) 6318{ 6319 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6320 D3D12Renderer *renderer = d3d12CommandBuffer->renderer; 6321 D3D12_TEXTURE_COPY_LOCATION sourceLocation; 6322 D3D12_TEXTURE_COPY_LOCATION destinationLocation; 6323 Uint32 pixelsPerRow = destination->pixels_per_row; 6324 Uint32 rowPitch; 6325 Uint32 alignedRowPitch; 6326 Uint32 rowsPerSlice = destination->rows_per_layer; 6327 bool needsRealignment; 6328 bool needsPlacementCopy; 6329 D3D12TextureDownload *textureDownload = NULL; 6330 D3D12TextureContainer *sourceContainer = (D3D12TextureContainer *)source->texture; 6331 D3D12TextureSubresource *sourceSubresource = D3D12_INTERNAL_FetchTextureSubresource( 6332 sourceContainer, 6333 source->layer, 6334 source->mip_level); 6335 D3D12BufferContainer *destinationContainer = (D3D12BufferContainer *)destination->transfer_buffer; 6336 D3D12Buffer *destinationBuffer = destinationContainer->activeBuffer; 6337 6338 /* Unless the UnrestrictedBufferTextureCopyPitchSupported feature is supported, D3D12 requires 6339 * texture data row pitch to be 256 byte aligned, which is obviously insane. Instead of exposing 6340 * that restriction to the client, which is a huge rake to step on, and a restriction that no 6341 * other backend requires, we're going to copy data to a temporary buffer, copy THAT data to the 6342 * texture, and then get rid of the temporary buffer ASAP. If we're lucky and the row pitch and 6343 * depth pitch are already aligned, we can skip all of that. 6344 * 6345 * D3D12 also requires offsets to be 512 byte aligned. We'll fix that for the client and warn them as well. 6346 * 6347 * And just for some extra fun, D3D12 doesn't actually support depth pitch, so we have to realign that too! 6348 * 6349 * Since this is an async download we have to do all these fixups after the command is finished, 6350 * so we'll cache the metadata and map and copy it when the command buffer is cleaned. 6351 */ 6352 6353 if (pixelsPerRow == 0) { 6354 pixelsPerRow = source->w; 6355 } 6356 6357 rowPitch = BytesPerRow(pixelsPerRow, sourceContainer->header.info.format); 6358 6359 if (rowsPerSlice == 0) { 6360 rowsPerSlice = source->h; 6361 } 6362 6363 if (renderer->UnrestrictedBufferTextureCopyPitchSupported) { 6364 alignedRowPitch = rowPitch; 6365 needsRealignment = false; 6366 needsPlacementCopy = false; 6367 } else { 6368 alignedRowPitch = D3D12_INTERNAL_Align(rowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); 6369 needsRealignment = rowsPerSlice != source->h || rowPitch != alignedRowPitch; 6370 needsPlacementCopy = destination->offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT != 0; 6371 } 6372 6373 sourceLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; 6374 sourceLocation.SubresourceIndex = sourceSubresource->index; 6375 sourceLocation.pResource = sourceSubresource->parent->resource; 6376 6377 D3D12_BOX sourceBox = { source->x, source->y, source->z, source->x + source->w, source->y + rowsPerSlice, source->z + source->d }; 6378 6379 destinationLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; 6380 destinationLocation.PlacedFootprint.Footprint.Format = SDLToD3D12_TextureFormat[sourceContainer->header.info.format]; 6381 destinationLocation.PlacedFootprint.Footprint.Width = source->w; 6382 destinationLocation.PlacedFootprint.Footprint.Height = rowsPerSlice; 6383 destinationLocation.PlacedFootprint.Footprint.Depth = source->d; 6384 destinationLocation.PlacedFootprint.Footprint.RowPitch = alignedRowPitch; 6385 6386 if (needsRealignment || needsPlacementCopy) { 6387 textureDownload = (D3D12TextureDownload *)SDL_malloc(sizeof(D3D12TextureDownload)); 6388 6389 if (!textureDownload) { 6390 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture download structure!"); 6391 return; 6392 } 6393 6394 textureDownload->temporaryBuffer = D3D12_INTERNAL_CreateBuffer( 6395 d3d12CommandBuffer->renderer, 6396 0, 6397 alignedRowPitch * rowsPerSlice * source->d, 6398 D3D12_BUFFER_TYPE_DOWNLOAD, 6399 NULL); 6400 6401 if (!textureDownload->temporaryBuffer) { 6402 SDL_free(textureDownload); 6403 return; 6404 } 6405 6406 textureDownload->destinationBuffer = destinationBuffer; 6407 textureDownload->bufferOffset = destination->offset; 6408 textureDownload->width = source->w; 6409 textureDownload->height = rowsPerSlice; 6410 textureDownload->depth = source->d; 6411 textureDownload->bytesPerRow = rowPitch; 6412 textureDownload->bytesPerDepthSlice = rowPitch * rowsPerSlice; 6413 textureDownload->alignedBytesPerRow = alignedRowPitch; 6414 6415 destinationLocation.pResource = textureDownload->temporaryBuffer->handle; 6416 destinationLocation.PlacedFootprint.Offset = 0; 6417 if (d3d12CommandBuffer->renderer->debug_mode) { 6418 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Texture pitch or offset not aligned properly! This is suboptimal on D3D12!"); 6419 } 6420 } else { 6421 destinationLocation.pResource = destinationBuffer->handle; 6422 destinationLocation.PlacedFootprint.Offset = destination->offset; 6423 } 6424 6425 D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( 6426 d3d12CommandBuffer, 6427 D3D12_RESOURCE_STATE_COPY_SOURCE, 6428 sourceSubresource); 6429 6430 ID3D12GraphicsCommandList_CopyTextureRegion( 6431 d3d12CommandBuffer->graphicsCommandList, 6432 &destinationLocation, 6433 0, 6434 0, 6435 0, 6436 &sourceLocation, 6437 &sourceBox); 6438 6439 D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( 6440 d3d12CommandBuffer, 6441 D3D12_RESOURCE_STATE_COPY_SOURCE, 6442 sourceSubresource); 6443 6444 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, destinationBuffer); 6445 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, sourceSubresource->parent); 6446 6447 if (textureDownload != NULL) { 6448 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, textureDownload->temporaryBuffer); 6449 6450 if (d3d12CommandBuffer->textureDownloadCount >= d3d12CommandBuffer->textureDownloadCapacity) { 6451 d3d12CommandBuffer->textureDownloadCapacity *= 2; 6452 d3d12CommandBuffer->textureDownloads = (D3D12TextureDownload **)SDL_realloc( 6453 d3d12CommandBuffer->textureDownloads, 6454 d3d12CommandBuffer->textureDownloadCapacity * sizeof(D3D12TextureDownload *)); 6455 } 6456 6457 d3d12CommandBuffer->textureDownloads[d3d12CommandBuffer->textureDownloadCount] = textureDownload; 6458 d3d12CommandBuffer->textureDownloadCount += 1; 6459 6460 D3D12_INTERNAL_ReleaseBuffer(d3d12CommandBuffer->renderer, textureDownload->temporaryBuffer); 6461 } 6462} 6463 6464static void D3D12_DownloadFromBuffer( 6465 SDL_GPUCommandBuffer *commandBuffer, 6466 const SDL_GPUBufferRegion *source, 6467 const SDL_GPUTransferBufferLocation *destination) 6468{ 6469 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6470 D3D12BufferContainer *sourceContainer = (D3D12BufferContainer *)source->buffer; 6471 D3D12BufferContainer *destinationContainer = (D3D12BufferContainer *)destination->transfer_buffer; 6472 6473 D3D12Buffer *sourceBuffer = sourceContainer->activeBuffer; 6474 D3D12_INTERNAL_BufferTransitionFromDefaultUsage( 6475 d3d12CommandBuffer, 6476 D3D12_RESOURCE_STATE_COPY_SOURCE, 6477 sourceBuffer); 6478 6479 D3D12Buffer *destinationBuffer = destinationContainer->activeBuffer; 6480 6481 ID3D12GraphicsCommandList_CopyBufferRegion( 6482 d3d12CommandBuffer->graphicsCommandList, 6483 destinationBuffer->handle, 6484 destination->offset, 6485 sourceBuffer->handle, 6486 source->offset, 6487 source->size); 6488 6489 D3D12_INTERNAL_BufferTransitionToDefaultUsage( 6490 d3d12CommandBuffer, 6491 D3D12_RESOURCE_STATE_COPY_SOURCE, 6492 sourceBuffer); 6493 6494 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, sourceBuffer); 6495 D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, destinationBuffer); 6496} 6497 6498static void D3D12_EndCopyPass( 6499 SDL_GPUCommandBuffer *commandBuffer) 6500{ 6501 // no-op 6502 (void)commandBuffer; 6503} 6504 6505static void D3D12_GenerateMipmaps( 6506 SDL_GPUCommandBuffer *commandBuffer, 6507 SDL_GPUTexture *texture) 6508{ 6509 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6510 D3D12Renderer *renderer = d3d12CommandBuffer->renderer; 6511 D3D12TextureContainer *container = (D3D12TextureContainer *)texture; 6512 SDL_GPUGraphicsPipeline *blitPipeline; 6513 6514 blitPipeline = SDL_GPU_FetchBlitPipeline( 6515 renderer->sdlGPUDevice, 6516 container->header.info.type, 6517 container->header.info.format, 6518 renderer->blitVertexShader, 6519 renderer->blitFrom2DShader, 6520 renderer->blitFrom2DArrayShader, 6521 renderer->blitFrom3DShader, 6522 renderer->blitFromCubeShader, 6523 renderer->blitFromCubeArrayShader, 6524 &renderer->blitPipelines, 6525 &renderer->blitPipelineCount, 6526 &renderer->blitPipelineCapacity); 6527 6528 if (blitPipeline == NULL) { 6529 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Could not fetch blit pipeline"); 6530 return; 6531 } 6532 6533 // We have to do this one subresource at a time 6534 for (Uint32 layerOrDepthIndex = 0; layerOrDepthIndex < container->header.info.layer_count_or_depth; layerOrDepthIndex += 1) { 6535 for (Uint32 levelIndex = 1; levelIndex < container->header.info.num_levels; levelIndex += 1) { 6536 SDL_GPUBlitInfo blitInfo; 6537 SDL_zero(blitInfo); 6538 6539 blitInfo.source.texture = texture; 6540 blitInfo.source.mip_level = levelIndex - 1; 6541 blitInfo.source.layer_or_depth_plane = layerOrDepthIndex; 6542 blitInfo.source.x = 0; 6543 blitInfo.source.y = 0; 6544 blitInfo.source.w = SDL_max(container->header.info.width >> (levelIndex - 1), 1); 6545 blitInfo.source.h = SDL_max(container->header.info.height >> (levelIndex - 1), 1); 6546 6547 blitInfo.destination.texture = texture; 6548 blitInfo.destination.mip_level = levelIndex; 6549 blitInfo.destination.layer_or_depth_plane = layerOrDepthIndex; 6550 blitInfo.destination.x = 0; 6551 blitInfo.destination.y = 0; 6552 blitInfo.destination.w = SDL_max(container->header.info.width >> levelIndex, 1); 6553 blitInfo.destination.h = SDL_max(container->header.info.height >> levelIndex, 1); 6554 6555 blitInfo.load_op = SDL_GPU_LOADOP_DONT_CARE; 6556 blitInfo.filter = SDL_GPU_FILTER_LINEAR; 6557 6558 SDL_BlitGPUTexture( 6559 commandBuffer, 6560 &blitInfo); 6561 } 6562 } 6563 6564 D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, container->activeTexture); 6565} 6566 6567static void D3D12_Blit( 6568 SDL_GPUCommandBuffer *commandBuffer, 6569 const SDL_GPUBlitInfo *info) 6570{ 6571 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 6572 D3D12Renderer *renderer = (D3D12Renderer *)d3d12CommandBuffer->renderer; 6573 6574 SDL_GPU_BlitCommon( 6575 commandBuffer, 6576 info, 6577 renderer->blitLinearSampler, 6578 renderer->blitNearestSampler, 6579 renderer->blitVertexShader, 6580 renderer->blitFrom2DShader, 6581 renderer->blitFrom2DArrayShader, 6582 renderer->blitFrom3DShader, 6583 renderer->blitFromCubeShader, 6584 renderer->blitFromCubeArrayShader, 6585 &renderer->blitPipelines, 6586 &renderer->blitPipelineCount, 6587 &renderer->blitPipelineCapacity); 6588} 6589 6590// Submission/Presentation 6591 6592static D3D12WindowData *D3D12_INTERNAL_FetchWindowData( 6593 SDL_Window *window) 6594{ 6595 SDL_PropertiesID properties = SDL_GetWindowProperties(window); 6596 return (D3D12WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL); 6597} 6598 6599static bool D3D12_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e) 6600{ 6601 SDL_Window *w = (SDL_Window *)userdata; 6602 D3D12WindowData *data; 6603 if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) { 6604 data = D3D12_INTERNAL_FetchWindowData(w); 6605 data->needsSwapchainRecreate = true; 6606 } 6607 6608 return true; 6609} 6610 6611static bool D3D12_SupportsSwapchainComposition( 6612 SDL_GPURenderer *driverData, 6613 SDL_Window *window, 6614 SDL_GPUSwapchainComposition swapchainComposition) 6615{ 6616#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 6617 // FIXME: HDR support would be nice to add, but it seems complicated... 6618 return swapchainComposition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR || 6619 swapchainComposition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR; 6620#else 6621 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 6622 DXGI_FORMAT format; 6623 D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport; 6624 Uint32 colorSpaceSupport; 6625 HRESULT res; 6626 6627 format = SwapchainCompositionToTextureFormat[swapchainComposition]; 6628 6629 formatSupport.Format = format; 6630 res = ID3D12Device_CheckFeatureSupport( 6631 renderer->device, 6632 D3D12_FEATURE_FORMAT_SUPPORT, 6633 &formatSupport, 6634 sizeof(formatSupport)); 6635 if (FAILED(res)) { 6636 // Format is apparently unknown 6637 return false; 6638 } 6639 6640 if (!(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_DISPLAY)) { 6641 return false; 6642 } 6643 6644 D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); 6645 if (windowData == NULL) { 6646 SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false); 6647 } 6648 6649 // Check the color space support if necessary 6650 if (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR) { 6651 IDXGISwapChain3_CheckColorSpaceSupport( 6652 windowData->swapchain, 6653 SwapchainCompositionToColorSpace[swapchainComposition], 6654 &colorSpaceSupport); 6655 6656 if (!(colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) { 6657 return false; 6658 } 6659 } 6660#endif 6661 6662 return true; 6663} 6664 6665static bool D3D12_SupportsPresentMode( 6666 SDL_GPURenderer *driverData, 6667 SDL_Window *window, 6668 SDL_GPUPresentMode presentMode) 6669{ 6670 (void)driverData; 6671 (void)window; 6672 6673 switch (presentMode) { 6674 case SDL_GPU_PRESENTMODE_IMMEDIATE: 6675 case SDL_GPU_PRESENTMODE_VSYNC: 6676 return true; 6677 case SDL_GPU_PRESENTMODE_MAILBOX: 6678#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 6679 return false; 6680#else 6681 return true; 6682#endif 6683 default: 6684 SDL_assert(!"Unrecognized present mode"); 6685 return false; 6686 } 6687} 6688 6689#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 6690static bool D3D12_INTERNAL_CreateSwapchain( 6691 D3D12Renderer *renderer, 6692 D3D12WindowData *windowData, 6693 SDL_GPUSwapchainComposition swapchain_composition, 6694 SDL_GPUPresentMode present_mode) 6695{ 6696 int width, height; 6697 SDL_GPUTextureCreateInfo createInfo; 6698 D3D12Texture *texture; 6699 6700 // Get the swapchain size 6701 SDL_SyncWindow(windowData->window); 6702 SDL_GetWindowSizeInPixels(windowData->window, &width, &height); 6703 6704 // Min swapchain image count is 2 6705 windowData->swapchainTextureCount = SDL_clamp(renderer->allowedFramesInFlight, 2, 3); 6706 6707 // Create the swapchain textures 6708 SDL_zero(createInfo); 6709 createInfo.type = SDL_GPU_TEXTURETYPE_2D; 6710 createInfo.width = width; 6711 createInfo.height = height; 6712 createInfo.format = SwapchainCompositionToSDLTextureFormat[swapchain_composition]; 6713 createInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 6714 createInfo.layer_count_or_depth = 1; 6715 createInfo.num_levels = 1; 6716 6717 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 6718 texture = D3D12_INTERNAL_CreateTexture(renderer, &createInfo, true, "Swapchain"); 6719 texture->container = &windowData->textureContainers[i]; 6720 windowData->textureContainers[i].activeTexture = texture; 6721 windowData->textureContainers[i].canBeCycled = false; 6722 windowData->textureContainers[i].header.info = createInfo; 6723 windowData->textureContainers[i].textureCapacity = 1; 6724 windowData->textureContainers[i].textureCount = 1; 6725 windowData->textureContainers[i].textures = &windowData->textureContainers[i].activeTexture; 6726 } 6727 6728 // Initialize the swapchain data 6729 windowData->present_mode = present_mode; 6730 windowData->swapchainComposition = swapchain_composition; 6731 windowData->swapchainColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; 6732 windowData->frameCounter = 0; 6733 windowData->width = width; 6734 windowData->height = height; 6735 6736 // Precache blit pipelines for the swapchain format 6737 for (Uint32 i = 0; i < 5; i += 1) { 6738 SDL_GPU_FetchBlitPipeline( 6739 renderer->sdlGPUDevice, 6740 (SDL_GPUTextureType)i, 6741 createInfo.format, 6742 renderer->blitVertexShader, 6743 renderer->blitFrom2DShader, 6744 renderer->blitFrom2DArrayShader, 6745 renderer->blitFrom3DShader, 6746 renderer->blitFromCubeShader, 6747 renderer->blitFromCubeArrayShader, 6748 &renderer->blitPipelines, 6749 &renderer->blitPipelineCount, 6750 &renderer->blitPipelineCapacity); 6751 } 6752 6753 return true; 6754} 6755 6756static void D3D12_INTERNAL_DestroySwapchain( 6757 D3D12Renderer *renderer, 6758 D3D12WindowData *windowData) 6759{ 6760 renderer->commandQueue->PresentX(0, NULL, NULL); 6761 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 6762 D3D12_INTERNAL_DestroyTexture(windowData->textureContainers[i].activeTexture); 6763 } 6764} 6765 6766static bool D3D12_INTERNAL_ResizeSwapchain( 6767 D3D12Renderer *renderer, 6768 D3D12WindowData *windowData) 6769{ 6770 // Wait so we don't release in-flight views 6771 D3D12_Wait((SDL_GPURenderer *)renderer); 6772 6773 // Present a black screen 6774 renderer->commandQueue->PresentX(0, NULL, NULL); 6775 6776 // Clean up the previous swapchain textures 6777 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 6778 D3D12_INTERNAL_DestroyTexture(windowData->textureContainers[i].activeTexture); 6779 } 6780 6781 // Create a new swapchain 6782 D3D12_INTERNAL_CreateSwapchain( 6783 renderer, 6784 windowData, 6785 windowData->swapchainComposition, 6786 windowData->present_mode); 6787 6788 windowData->needsSwapchainRecreate = false; 6789 return true; 6790} 6791#else 6792static bool D3D12_INTERNAL_InitializeSwapchainTexture( 6793 D3D12Renderer *renderer, 6794 IDXGISwapChain3 *swapchain, 6795 SDL_GPUSwapchainComposition composition, 6796 Uint32 index, 6797 D3D12TextureContainer *pTextureContainer) 6798{ 6799 D3D12Texture *pTexture; 6800 ID3D12Resource *swapchainTexture; 6801 D3D12_RESOURCE_DESC textureDesc; 6802 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; 6803 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; 6804 DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[composition]; 6805 HRESULT res; 6806 6807 res = IDXGISwapChain_GetBuffer( 6808 swapchain, 6809 index, 6810 D3D_GUID(D3D_IID_ID3D12Resource), 6811 (void **)&swapchainTexture); 6812 CHECK_D3D12_ERROR_AND_RETURN("Could not get buffer from swapchain!", false); 6813 6814 pTexture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture)); 6815 if (!pTexture) { 6816 ID3D12Resource_Release(swapchainTexture); 6817 return false; 6818 } 6819 pTexture->resource = NULL; // This will be set in AcquireSwapchainTexture 6820 SDL_SetAtomicInt(&pTexture->referenceCount, 0); 6821 pTexture->subresourceCount = 1; 6822 pTexture->subresources = (D3D12TextureSubresource *)SDL_calloc(1, sizeof(D3D12TextureSubresource)); 6823 if (!pTexture->subresources) { 6824 SDL_free(pTexture); 6825 ID3D12Resource_Release(swapchainTexture); 6826 return false; 6827 } 6828 pTexture->subresources[0].rtvHandles = SDL_calloc(1, sizeof(D3D12StagingDescriptor)); 6829 pTexture->subresources[0].uavHandle.heap = NULL; 6830 pTexture->subresources[0].dsvHandle.heap = NULL; 6831 pTexture->subresources[0].parent = pTexture; 6832 pTexture->subresources[0].index = 0; 6833 pTexture->subresources[0].layer = 0; 6834 pTexture->subresources[0].depth = 1; 6835 pTexture->subresources[0].level = 0; 6836 6837 ID3D12Resource_GetDesc(swapchainTexture, &textureDesc); 6838 pTextureContainer->header.info.width = (Uint32)textureDesc.Width; 6839 pTextureContainer->header.info.height = (Uint32)textureDesc.Height; 6840 pTextureContainer->header.info.layer_count_or_depth = 1; 6841 pTextureContainer->header.info.num_levels = 1; 6842 pTextureContainer->header.info.type = SDL_GPU_TEXTURETYPE_2D; 6843 pTextureContainer->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 6844 pTextureContainer->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; 6845 pTextureContainer->header.info.format = SwapchainCompositionToSDLTextureFormat[composition]; 6846 6847 pTextureContainer->debugName = NULL; 6848 pTextureContainer->textures = (D3D12Texture **)SDL_calloc(1, sizeof(D3D12Texture *)); 6849 if (!pTextureContainer->textures) { 6850 SDL_free(pTexture->subresources); 6851 SDL_free(pTexture); 6852 ID3D12Resource_Release(swapchainTexture); 6853 return false; 6854 } 6855 6856 pTextureContainer->textureCapacity = 1; 6857 pTextureContainer->textureCount = 1; 6858 pTextureContainer->textures[0] = pTexture; 6859 pTextureContainer->activeTexture = pTexture; 6860 pTextureContainer->canBeCycled = false; 6861 6862 pTexture->container = pTextureContainer; 6863 pTexture->containerIndex = 0; 6864 6865 // Create the SRV for the swapchain 6866 D3D12_INTERNAL_AssignStagingDescriptorHandle( 6867 renderer, 6868 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, 6869 &pTexture->srvHandle); 6870 6871 srvDesc.Format = SwapchainCompositionToTextureFormat[composition]; 6872 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; 6873 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; 6874 srvDesc.Texture2D.MipLevels = 1; 6875 srvDesc.Texture2D.MostDetailedMip = 0; 6876 srvDesc.Texture2D.ResourceMinLODClamp = 0; 6877 srvDesc.Texture2D.PlaneSlice = 0; 6878 6879 ID3D12Device_CreateShaderResourceView( 6880 renderer->device, 6881 swapchainTexture, 6882 &srvDesc, 6883 pTexture->srvHandle.cpuHandle); 6884 6885 // Create the RTV for the swapchain 6886 D3D12_INTERNAL_AssignStagingDescriptorHandle( 6887 renderer, 6888 D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 6889 &pTexture->subresources[0].rtvHandles[0]); 6890 6891 rtvDesc.Format = (composition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat; 6892 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; 6893 rtvDesc.Texture2D.MipSlice = 0; 6894 rtvDesc.Texture2D.PlaneSlice = 0; 6895 6896 ID3D12Device_CreateRenderTargetView( 6897 renderer->device, 6898 swapchainTexture, 6899 &rtvDesc, 6900 pTexture->subresources[0].rtvHandles[0].cpuHandle); 6901 6902 ID3D12Resource_Release(swapchainTexture); 6903 6904 return true; 6905} 6906 6907static bool D3D12_INTERNAL_ResizeSwapchain( 6908 D3D12Renderer *renderer, 6909 D3D12WindowData *windowData) 6910{ 6911 // Wait so we don't release in-flight views 6912 D3D12_Wait((SDL_GPURenderer *)renderer); 6913 6914 // Release views and clean up 6915 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 6916 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 6917 &windowData->textureContainers[i].activeTexture->srvHandle); 6918 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 6919 &windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles[0]); 6920 6921 SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles); 6922 SDL_free(windowData->textureContainers[i].activeTexture->subresources); 6923 SDL_free(windowData->textureContainers[i].activeTexture); 6924 SDL_free(windowData->textureContainers[i].textures); 6925 } 6926 6927 // Resize the swapchain 6928 HRESULT res = IDXGISwapChain_ResizeBuffers( 6929 windowData->swapchain, 6930 0, // Keep buffer count the same 6931 0, // use client window width 6932 0, // use client window height 6933 DXGI_FORMAT_UNKNOWN, // Keep the old format 6934 renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0); 6935 CHECK_D3D12_ERROR_AND_RETURN("Could not resize swapchain buffers", false); 6936 6937 // Create texture object for the swapchain 6938 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 6939 if (!D3D12_INTERNAL_InitializeSwapchainTexture( 6940 renderer, 6941 windowData->swapchain, 6942 windowData->swapchainComposition, 6943 i, 6944 &windowData->textureContainers[i])) { 6945 return false; 6946 } 6947 } 6948 6949 DXGI_SWAP_CHAIN_DESC1 swapchainDesc; 6950 IDXGISwapChain3_GetDesc1(windowData->swapchain, &swapchainDesc); 6951 CHECK_D3D12_ERROR_AND_RETURN("Failed to retrieve swapchain descriptor!", false); 6952 6953 windowData->width = swapchainDesc.Width; 6954 windowData->height = swapchainDesc.Height; 6955 windowData->needsSwapchainRecreate = false; 6956 return true; 6957} 6958 6959static void D3D12_INTERNAL_DestroySwapchain( 6960 D3D12Renderer *renderer, 6961 D3D12WindowData *windowData) 6962{ 6963 // Release views and clean up 6964 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 6965 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 6966 &windowData->textureContainers[i].activeTexture->srvHandle); 6967 D3D12_INTERNAL_ReleaseStagingDescriptorHandle( 6968 &windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles[0]); 6969 6970 SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles); 6971 SDL_free(windowData->textureContainers[i].activeTexture->subresources); 6972 SDL_free(windowData->textureContainers[i].activeTexture); 6973 SDL_free(windowData->textureContainers[i].textures); 6974 } 6975 6976 IDXGISwapChain_Release(windowData->swapchain); 6977 windowData->swapchain = NULL; 6978} 6979 6980static bool D3D12_INTERNAL_CreateSwapchain( 6981 D3D12Renderer *renderer, 6982 D3D12WindowData *windowData, 6983 SDL_GPUSwapchainComposition swapchainComposition, 6984 SDL_GPUPresentMode presentMode) 6985{ 6986 HWND dxgiHandle; 6987 DXGI_SWAP_CHAIN_DESC1 swapchainDesc; 6988 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreenDesc; 6989 DXGI_FORMAT swapchainFormat; 6990 IDXGIFactory1 *pParent; 6991 IDXGISwapChain1 *swapchain; 6992 IDXGISwapChain3 *swapchain3; 6993 HRESULT res; 6994 6995 // Get the DXGI handle 6996#ifdef _WIN32 6997 dxgiHandle = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(windowData->window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); 6998#else 6999 dxgiHandle = (HWND)windowData->window; 7000#endif 7001 7002 swapchainFormat = SwapchainCompositionToTextureFormat[swapchainComposition]; 7003 7004 // Min swapchain image count is 2 7005 windowData->swapchainTextureCount = SDL_clamp(renderer->allowedFramesInFlight, 2, 3); 7006 7007 // Initialize the swapchain buffer descriptor 7008 swapchainDesc.Width = 0; // use client window width 7009 swapchainDesc.Height = 0; // use client window height 7010 swapchainDesc.Format = swapchainFormat; 7011 swapchainDesc.SampleDesc.Count = 1; 7012 swapchainDesc.SampleDesc.Quality = 0; 7013 swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 7014 swapchainDesc.BufferCount = windowData->swapchainTextureCount; 7015 swapchainDesc.Scaling = DXGI_SCALING_NONE; 7016 swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 7017 swapchainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; 7018 swapchainDesc.Flags = 0; 7019 swapchainDesc.Stereo = 0; 7020 7021 // Initialize the fullscreen descriptor (if needed) 7022 fullscreenDesc.RefreshRate.Numerator = 0; 7023 fullscreenDesc.RefreshRate.Denominator = 0; 7024 fullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; 7025 fullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; 7026 fullscreenDesc.Windowed = true; 7027 7028 if (renderer->supportsTearing) { 7029 swapchainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; 7030 } else { 7031 swapchainDesc.Flags = 0; 7032 } 7033 7034 if (!IsWindow(dxgiHandle)) { 7035 return false; 7036 } 7037 7038 // Create the swapchain! 7039 res = IDXGIFactory4_CreateSwapChainForHwnd( 7040 renderer->factory, 7041 (IUnknown *)renderer->commandQueue, 7042 dxgiHandle, 7043 &swapchainDesc, 7044 &fullscreenDesc, 7045 NULL, 7046 &swapchain); 7047 CHECK_D3D12_ERROR_AND_RETURN("Could not create swapchain", false); 7048 7049 res = IDXGISwapChain1_QueryInterface( 7050 swapchain, 7051 D3D_GUID(D3D_IID_IDXGISwapChain3), 7052 (void **)&swapchain3); 7053 IDXGISwapChain1_Release(swapchain); 7054 CHECK_D3D12_ERROR_AND_RETURN("Could not create IDXGISwapChain3", false); 7055 7056 if (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR) { 7057 // Support already verified if we hit this block 7058 IDXGISwapChain3_SetColorSpace1( 7059 swapchain3, 7060 SwapchainCompositionToColorSpace[swapchainComposition]); 7061 } 7062 7063 /* 7064 * The swapchain's parent is a separate factory from the factory that 7065 * we used to create the swapchain, and only that parent can be used to 7066 * set the window association. Trying to set an association on our factory 7067 * will silently fail and doesn't even verify arguments or return errors. 7068 * See https://gamedev.net/forums/topic/634235-dxgidisabling-altenter/4999955/ 7069 */ 7070 res = IDXGISwapChain3_GetParent( 7071 swapchain3, 7072 D3D_GUID(D3D_IID_IDXGIFactory1), 7073 (void **)&pParent); 7074 if (FAILED(res)) { 7075 SDL_LogWarn( 7076 SDL_LOG_CATEGORY_GPU, 7077 "Could not get swapchain parent! Error Code: " HRESULT_FMT, 7078 res); 7079 } else { 7080 // Disable DXGI window crap 7081 res = IDXGIFactory1_MakeWindowAssociation( 7082 pParent, 7083 dxgiHandle, 7084 DXGI_MWA_NO_WINDOW_CHANGES); 7085 if (FAILED(res)) { 7086 SDL_LogWarn( 7087 SDL_LOG_CATEGORY_GPU, 7088 "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, 7089 res); 7090 } 7091 7092 // We're done with the parent now 7093 IDXGIFactory1_Release(pParent); 7094 } 7095 7096 IDXGISwapChain3_GetDesc1(swapchain3, &swapchainDesc); 7097 CHECK_D3D12_ERROR_AND_RETURN("Failed to retrieve swapchain descriptor!", false); 7098 7099 // Initialize the swapchain data 7100 windowData->swapchain = swapchain3; 7101 windowData->present_mode = presentMode; 7102 windowData->swapchainComposition = swapchainComposition; 7103 windowData->swapchainColorSpace = SwapchainCompositionToColorSpace[swapchainComposition]; 7104 windowData->frameCounter = 0; 7105 windowData->width = swapchainDesc.Width; 7106 windowData->height = swapchainDesc.Height; 7107 7108 // Precache blit pipelines for the swapchain format 7109 for (Uint32 i = 0; i < 5; i += 1) { 7110 SDL_GPU_FetchBlitPipeline( 7111 renderer->sdlGPUDevice, 7112 (SDL_GPUTextureType)i, 7113 SwapchainCompositionToSDLTextureFormat[swapchainComposition], 7114 renderer->blitVertexShader, 7115 renderer->blitFrom2DShader, 7116 renderer->blitFrom2DArrayShader, 7117 renderer->blitFrom3DShader, 7118 renderer->blitFromCubeShader, 7119 renderer->blitFromCubeArrayShader, 7120 &renderer->blitPipelines, 7121 &renderer->blitPipelineCount, 7122 &renderer->blitPipelineCapacity); 7123 } 7124 7125 /* If a you are using a FLIP model format you can't create the swapchain as DXGI_FORMAT_B8G8R8A8_UNORM_SRGB. 7126 * You have to create the swapchain as DXGI_FORMAT_B8G8R8A8_UNORM and then set the render target view's format to DXGI_FORMAT_B8G8R8A8_UNORM_SRGB 7127 */ 7128 for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) { 7129 if (!D3D12_INTERNAL_InitializeSwapchainTexture( 7130 renderer, 7131 swapchain3, 7132 swapchainComposition, 7133 i, 7134 &windowData->textureContainers[i])) { 7135 IDXGISwapChain3_Release(swapchain3); 7136 return false; 7137 } 7138 } 7139 7140 return true; 7141} 7142#endif 7143 7144static bool D3D12_ClaimWindow( 7145 SDL_GPURenderer *driverData, 7146 SDL_Window *window) 7147{ 7148 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7149 D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); 7150 7151 if (windowData == NULL) { 7152 windowData = (D3D12WindowData *)SDL_calloc(1, sizeof(D3D12WindowData)); 7153 if (!windowData) { 7154 return false; 7155 } 7156 windowData->window = window; 7157 windowData->renderer = renderer; 7158 windowData->refcount = 1; 7159 7160 if (D3D12_INTERNAL_CreateSwapchain(renderer, windowData, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC)) { 7161 SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData); 7162 7163 SDL_LockMutex(renderer->windowLock); 7164 if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) { 7165 renderer->claimedWindowCapacity *= 2; 7166 renderer->claimedWindows = (D3D12WindowData **)SDL_realloc( 7167 renderer->claimedWindows, 7168 renderer->claimedWindowCapacity * sizeof(D3D12WindowData *)); 7169 } 7170 renderer->claimedWindows[renderer->claimedWindowCount] = windowData; 7171 renderer->claimedWindowCount += 1; 7172 SDL_UnlockMutex(renderer->windowLock); 7173 7174 SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, D3D12_INTERNAL_OnWindowResize, window); 7175 7176 return true; 7177 } else { 7178 SDL_free(windowData); 7179 return false; 7180 } 7181 } else if (windowData->renderer == renderer) { 7182 ++windowData->refcount; 7183 return true; 7184 } else { 7185 SET_STRING_ERROR_AND_RETURN("Window already claimed", false); 7186 } 7187} 7188 7189static void D3D12_ReleaseWindow( 7190 SDL_GPURenderer *driverData, 7191 SDL_Window *window) 7192{ 7193 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7194 D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); 7195 7196 if (windowData == NULL) { 7197 return; 7198 } 7199 if (windowData->renderer != renderer) { 7200 SDL_SetError("Window not claimed by this device"); 7201 return; 7202 } 7203 if (windowData->refcount > 1) { 7204 --windowData->refcount; 7205 return; 7206 } 7207 7208 D3D12_Wait(driverData); 7209 7210 for (Uint32 i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) { 7211 if (windowData->inFlightFences[i] != NULL) { 7212 D3D12_ReleaseFence( 7213 driverData, 7214 windowData->inFlightFences[i]); 7215 windowData->inFlightFences[i] = NULL; 7216 } 7217 } 7218 7219 D3D12_INTERNAL_DestroySwapchain(renderer, windowData); 7220 7221 SDL_LockMutex(renderer->windowLock); 7222 for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) { 7223 if (renderer->claimedWindows[i]->window == window) { 7224 renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1]; 7225 renderer->claimedWindowCount -= 1; 7226 break; 7227 } 7228 } 7229 SDL_UnlockMutex(renderer->windowLock); 7230 7231 SDL_free(windowData); 7232 SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA); 7233 SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, D3D12_INTERNAL_OnWindowResize, window); 7234} 7235 7236static bool D3D12_SetSwapchainParameters( 7237 SDL_GPURenderer *driverData, 7238 SDL_Window *window, 7239 SDL_GPUSwapchainComposition swapchainComposition, 7240 SDL_GPUPresentMode presentMode) 7241{ 7242 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7243 D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); 7244 7245 if (windowData == NULL) { 7246 SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false); 7247 } 7248 7249 if (!D3D12_SupportsSwapchainComposition(driverData, window, swapchainComposition)) { 7250 SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false); 7251 } 7252 7253 if (!D3D12_SupportsPresentMode(driverData, window, presentMode)) { 7254 SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false); 7255 } 7256 7257 if ( 7258 swapchainComposition != windowData->swapchainComposition || 7259 presentMode != windowData->present_mode) { 7260 D3D12_Wait(driverData); 7261 7262 // Recreate the swapchain 7263 D3D12_INTERNAL_DestroySwapchain( 7264 renderer, 7265 windowData); 7266 7267 return D3D12_INTERNAL_CreateSwapchain( 7268 renderer, 7269 windowData, 7270 swapchainComposition, 7271 presentMode); 7272 } 7273 7274 return true; 7275} 7276 7277static bool D3D12_SetAllowedFramesInFlight( 7278 SDL_GPURenderer *driverData, 7279 Uint32 allowedFramesInFlight) 7280{ 7281 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7282 7283 if (!D3D12_Wait(driverData)) { 7284 return false; 7285 } 7286 7287 // Destroy all swapchains 7288 for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) { 7289 D3D12WindowData *windowData = renderer->claimedWindows[i]; 7290 7291 D3D12_INTERNAL_DestroySwapchain(renderer, windowData); 7292 } 7293 7294 // Set the frames in flight value 7295 renderer->allowedFramesInFlight = allowedFramesInFlight; 7296 7297 // Recreate all swapchains 7298 for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) { 7299 D3D12WindowData *windowData = renderer->claimedWindows[i]; 7300 7301 if (!D3D12_INTERNAL_CreateSwapchain( 7302 renderer, 7303 windowData, 7304 windowData->swapchainComposition, 7305 windowData->present_mode)) { 7306 return false; 7307 } 7308 } 7309 7310 return true; 7311} 7312 7313static SDL_GPUTextureFormat D3D12_GetSwapchainTextureFormat( 7314 SDL_GPURenderer *driverData, 7315 SDL_Window *window) 7316{ 7317 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7318 D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); 7319 7320 if (windowData == NULL) { 7321 SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID); 7322 } 7323 7324 return windowData->textureContainers[windowData->frameCounter].header.info.format; 7325} 7326 7327static D3D12Fence *D3D12_INTERNAL_AcquireFence( 7328 D3D12Renderer *renderer) 7329{ 7330 D3D12Fence *fence; 7331 ID3D12Fence *handle; 7332 HRESULT res; 7333 7334 SDL_LockMutex(renderer->fenceLock); 7335 7336 if (renderer->availableFenceCount == 0) { 7337 res = ID3D12Device_CreateFence( 7338 renderer->device, 7339 D3D12_FENCE_UNSIGNALED_VALUE, 7340 D3D12_FENCE_FLAG_NONE, 7341 D3D_GUID(D3D_IID_ID3D12Fence), 7342 (void **)&handle); 7343 if (FAILED(res)) { 7344 D3D12_INTERNAL_SetError(renderer, "Failed to create fence!", res); 7345 SDL_UnlockMutex(renderer->fenceLock); 7346 return NULL; 7347 } 7348 7349 fence = (D3D12Fence *)SDL_calloc(1, sizeof(D3D12Fence)); 7350 if (!fence) { 7351 ID3D12Fence_Release(handle); 7352 SDL_UnlockMutex(renderer->fenceLock); 7353 return NULL; 7354 } 7355 fence->handle = handle; 7356 fence->event = CreateEvent(NULL, FALSE, FALSE, NULL); 7357 SDL_SetAtomicInt(&fence->referenceCount, 0); 7358 } else { 7359 fence = renderer->availableFences[renderer->availableFenceCount - 1]; 7360 renderer->availableFenceCount -= 1; 7361 ID3D12Fence_Signal(fence->handle, D3D12_FENCE_UNSIGNALED_VALUE); 7362 } 7363 7364 SDL_UnlockMutex(renderer->fenceLock); 7365 7366 (void)SDL_AtomicIncRef(&fence->referenceCount); 7367 return fence; 7368} 7369 7370static bool D3D12_INTERNAL_AllocateCommandBuffer( 7371 D3D12Renderer *renderer) 7372{ 7373 D3D12CommandBuffer *commandBuffer; 7374 HRESULT res; 7375 ID3D12CommandAllocator *commandAllocator; 7376 ID3D12GraphicsCommandList *commandList; 7377 7378 commandBuffer = (D3D12CommandBuffer *)SDL_calloc(1, sizeof(D3D12CommandBuffer)); 7379 if (!commandBuffer) { 7380 SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false); 7381 } 7382 7383 res = ID3D12Device_CreateCommandAllocator( 7384 renderer->device, 7385 D3D12_COMMAND_LIST_TYPE_DIRECT, 7386 D3D_GUID(D3D_IID_ID3D12CommandAllocator), 7387 (void **)&commandAllocator); 7388 if (FAILED(res)) { 7389 D3D12_INTERNAL_SetError(renderer, "Failed to create ID3D12CommandAllocator", res); 7390 D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); 7391 return false; 7392 } 7393 commandBuffer->commandAllocator = commandAllocator; 7394 7395 res = ID3D12Device_CreateCommandList( 7396 renderer->device, 7397 0, 7398 D3D12_COMMAND_LIST_TYPE_DIRECT, 7399 commandAllocator, 7400 NULL, 7401 D3D_GUID(D3D_IID_ID3D12GraphicsCommandList), 7402 (void **)&commandList); 7403 7404 if (FAILED(res)) { 7405 D3D12_INTERNAL_SetError(renderer, "Failed to create ID3D12CommandList", res); 7406 D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); 7407 return false; 7408 } 7409 commandBuffer->graphicsCommandList = commandList; 7410 7411 commandBuffer->renderer = renderer; 7412 commandBuffer->inFlightFence = NULL; 7413 7414 // Window handling 7415 commandBuffer->presentDataCapacity = 1; 7416 commandBuffer->presentDataCount = 0; 7417 commandBuffer->presentDatas = (D3D12PresentData *)SDL_calloc( 7418 commandBuffer->presentDataCapacity, sizeof(D3D12PresentData)); 7419 7420 // Resource tracking 7421 commandBuffer->usedTextureCapacity = 4; 7422 commandBuffer->usedTextureCount = 0; 7423 commandBuffer->usedTextures = (D3D12Texture **)SDL_calloc( 7424 commandBuffer->usedTextureCapacity, sizeof(D3D12Texture *)); 7425 7426 commandBuffer->usedBufferCapacity = 4; 7427 commandBuffer->usedBufferCount = 0; 7428 commandBuffer->usedBuffers = (D3D12Buffer **)SDL_calloc( 7429 commandBuffer->usedBufferCapacity, sizeof(D3D12Buffer *)); 7430 7431 commandBuffer->usedSamplerCapacity = 4; 7432 commandBuffer->usedSamplerCount = 0; 7433 commandBuffer->usedSamplers = (D3D12Sampler **)SDL_calloc( 7434 commandBuffer->usedSamplerCapacity, sizeof(D3D12Sampler *)); 7435 7436 commandBuffer->usedGraphicsPipelineCapacity = 4; 7437 commandBuffer->usedGraphicsPipelineCount = 0; 7438 commandBuffer->usedGraphicsPipelines = (D3D12GraphicsPipeline **)SDL_calloc( 7439 commandBuffer->usedGraphicsPipelineCapacity, sizeof(D3D12GraphicsPipeline *)); 7440 7441 commandBuffer->usedComputePipelineCapacity = 4; 7442 commandBuffer->usedComputePipelineCount = 0; 7443 commandBuffer->usedComputePipelines = (D3D12ComputePipeline **)SDL_calloc( 7444 commandBuffer->usedComputePipelineCapacity, sizeof(D3D12ComputePipeline *)); 7445 7446 commandBuffer->usedDescriptorHeapCapacity = 4; 7447 commandBuffer->usedDescriptorHeapCount = 0; 7448 commandBuffer->usedDescriptorHeaps = (D3D12DescriptorHeap **)SDL_calloc( 7449 commandBuffer->usedDescriptorHeapCapacity, sizeof(D3D12DescriptorHeap *)); 7450 7451 commandBuffer->usedUniformBufferCapacity = 4; 7452 commandBuffer->usedUniformBufferCount = 0; 7453 commandBuffer->usedUniformBuffers = (D3D12UniformBuffer **)SDL_calloc( 7454 commandBuffer->usedUniformBufferCapacity, sizeof(D3D12UniformBuffer *)); 7455 7456 commandBuffer->textureDownloadCapacity = 4; 7457 commandBuffer->textureDownloadCount = 0; 7458 commandBuffer->textureDownloads = (D3D12TextureDownload **)SDL_calloc( 7459 commandBuffer->textureDownloadCapacity, sizeof(D3D12TextureDownload *)); 7460 7461 if ( 7462 (!commandBuffer->presentDatas) || 7463 (!commandBuffer->usedTextures) || 7464 (!commandBuffer->usedBuffers) || 7465 (!commandBuffer->usedSamplers) || 7466 (!commandBuffer->usedGraphicsPipelines) || 7467 (!commandBuffer->usedComputePipelines) || 7468 (!commandBuffer->usedUniformBuffers) || 7469 (!commandBuffer->textureDownloads)) { 7470 D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); 7471 SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false); 7472 } 7473 7474 D3D12CommandBuffer **resizedAvailableCommandBuffers = (D3D12CommandBuffer **)SDL_realloc( 7475 renderer->availableCommandBuffers, 7476 sizeof(D3D12CommandBuffer *) * (renderer->availableCommandBufferCapacity + 1)); 7477 7478 if (!resizedAvailableCommandBuffers) { 7479 D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer); 7480 SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false); 7481 } 7482 // Add to inactive command buffer array 7483 renderer->availableCommandBufferCapacity += 1; 7484 renderer->availableCommandBuffers = resizedAvailableCommandBuffers; 7485 7486 renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer; 7487 renderer->availableCommandBufferCount += 1; 7488 7489 return true; 7490} 7491 7492static D3D12CommandBuffer *D3D12_INTERNAL_AcquireCommandBufferFromPool( 7493 D3D12Renderer *renderer) 7494{ 7495 D3D12CommandBuffer *commandBuffer; 7496 7497 if (renderer->availableCommandBufferCount == 0) { 7498 if (!D3D12_INTERNAL_AllocateCommandBuffer(renderer)) { 7499 return NULL; 7500 } 7501 } 7502 7503 commandBuffer = renderer->availableCommandBuffers[renderer->availableCommandBufferCount - 1]; 7504 renderer->availableCommandBufferCount -= 1; 7505 7506 return commandBuffer; 7507} 7508 7509static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer( 7510 SDL_GPURenderer *driverData) 7511{ 7512 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7513 D3D12CommandBuffer *commandBuffer; 7514 ID3D12DescriptorHeap *heaps[2]; 7515 SDL_zeroa(heaps); 7516 7517 SDL_LockMutex(renderer->acquireCommandBufferLock); 7518 commandBuffer = D3D12_INTERNAL_AcquireCommandBufferFromPool(renderer); 7519 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 7520 7521 if (commandBuffer == NULL) { 7522 return NULL; 7523 } 7524 7525 // Set the bind state 7526 commandBuffer->currentGraphicsPipeline = NULL; 7527 7528 SDL_zeroa(commandBuffer->colorTargetSubresources); 7529 SDL_zeroa(commandBuffer->colorResolveSubresources); 7530 commandBuffer->depthStencilTextureSubresource = NULL; 7531 7532 SDL_zeroa(commandBuffer->vertexBuffers); 7533 SDL_zeroa(commandBuffer->vertexBufferOffsets); 7534 commandBuffer->vertexBufferCount = 0; 7535 7536 SDL_zeroa(commandBuffer->vertexSamplerTextureDescriptorHandles); 7537 SDL_zeroa(commandBuffer->vertexSamplerDescriptorHandles); 7538 SDL_zeroa(commandBuffer->vertexStorageTextureDescriptorHandles); 7539 SDL_zeroa(commandBuffer->vertexStorageBufferDescriptorHandles); 7540 SDL_zeroa(commandBuffer->vertexUniformBuffers); 7541 7542 SDL_zeroa(commandBuffer->fragmentSamplerTextureDescriptorHandles); 7543 SDL_zeroa(commandBuffer->fragmentSamplerDescriptorHandles); 7544 SDL_zeroa(commandBuffer->fragmentStorageTextureDescriptorHandles); 7545 SDL_zeroa(commandBuffer->fragmentStorageBufferDescriptorHandles); 7546 SDL_zeroa(commandBuffer->fragmentUniformBuffers); 7547 7548 SDL_zeroa(commandBuffer->computeSamplerTextureDescriptorHandles); 7549 SDL_zeroa(commandBuffer->computeSamplerDescriptorHandles); 7550 SDL_zeroa(commandBuffer->computeReadOnlyStorageTextureDescriptorHandles); 7551 SDL_zeroa(commandBuffer->computeReadOnlyStorageBufferDescriptorHandles); 7552 SDL_zeroa(commandBuffer->computeReadOnlyStorageTextures); 7553 SDL_zeroa(commandBuffer->computeReadOnlyStorageBuffers); 7554 SDL_zeroa(commandBuffer->computeReadWriteStorageTextureSubresources); 7555 SDL_zeroa(commandBuffer->computeReadWriteStorageBuffers); 7556 SDL_zeroa(commandBuffer->computeUniformBuffers); 7557 7558 commandBuffer->autoReleaseFence = true; 7559 7560 return (SDL_GPUCommandBuffer *)commandBuffer; 7561} 7562 7563static bool D3D12_WaitForSwapchain( 7564 SDL_GPURenderer *driverData, 7565 SDL_Window *window) 7566{ 7567 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 7568 D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window); 7569 7570 if (windowData == NULL) { 7571 SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false); 7572 } 7573 7574 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 7575 if (!D3D12_WaitForFences( 7576 driverData, 7577 true, 7578 &windowData->inFlightFences[windowData->frameCounter], 7579 1)) { 7580 return false; 7581 } 7582 } 7583 7584 return true; 7585} 7586 7587static bool D3D12_INTERNAL_AcquireSwapchainTexture( 7588 bool block, 7589 SDL_GPUCommandBuffer *commandBuffer, 7590 SDL_Window *window, 7591 SDL_GPUTexture **swapchainTexture, 7592 Uint32 *swapchainTextureWidth, 7593 Uint32 *swapchainTextureHeight) 7594{ 7595 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 7596 D3D12Renderer *renderer = d3d12CommandBuffer->renderer; 7597 D3D12WindowData *windowData; 7598 Uint32 swapchainIndex; 7599 HRESULT res; 7600 7601 *swapchainTexture = NULL; 7602 if (swapchainTextureWidth) { 7603 *swapchainTextureWidth = 0; 7604 } 7605 if (swapchainTextureHeight) { 7606 *swapchainTextureHeight = 0; 7607 } 7608 7609 windowData = D3D12_INTERNAL_FetchWindowData(window); 7610 if (windowData == NULL) { 7611 SET_STRING_ERROR_AND_RETURN("Cannot acquire swapchain texture from an unclaimed window!", false); 7612 } 7613 7614 if (windowData->needsSwapchainRecreate) { 7615 if (!D3D12_INTERNAL_ResizeSwapchain(renderer, windowData)) { 7616 return false; 7617 } 7618 } 7619 7620 if (swapchainTextureWidth) { 7621 *swapchainTextureWidth = windowData->width; 7622 } 7623 if (swapchainTextureHeight) { 7624 *swapchainTextureHeight = windowData->height; 7625 } 7626 7627 if (windowData->inFlightFences[windowData->frameCounter] != NULL) { 7628 if (block) { 7629 // In VSYNC mode, block until the least recent presented frame is done 7630 if (!D3D12_WaitForFences( 7631 (SDL_GPURenderer *)renderer, 7632 true, 7633 &windowData->inFlightFences[windowData->frameCounter], 7634 1)) { 7635 return false; 7636 } 7637 } else { 7638 // If we are not blocking and the least recent fence is not signaled, 7639 // return true to indicate that there is no error but rendering should be skipped. 7640 if (!D3D12_QueryFence( 7641 (SDL_GPURenderer *)renderer, 7642 windowData->inFlightFences[windowData->frameCounter])) { 7643 return true; 7644 } 7645 } 7646 7647 D3D12_ReleaseFence( 7648 (SDL_GPURenderer *)renderer, 7649 windowData->inFlightFences[windowData->frameCounter]); 7650 7651 windowData->inFlightFences[windowData->frameCounter] = NULL; 7652 } 7653 7654#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 7655 // FIXME: Should this happen before the inFlightFences stuff above? 7656 windowData->frameToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL; 7657 renderer->device->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, INFINITE, NULL, D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &windowData->frameToken); 7658 swapchainIndex = windowData->frameCounter; 7659#else 7660 swapchainIndex = IDXGISwapChain3_GetCurrentBackBufferIndex(windowData->swapchain); 7661 7662 // Set the handle on the windowData texture data. 7663 res = IDXGISwapChain_GetBuffer( 7664 windowData->swapchain, 7665 swapchainIndex, 7666 D3D_GUID(D3D_IID_ID3D12Resource), 7667 (void **)&windowData->textureContainers[swapchainIndex].activeTexture->resource); 7668 CHECK_D3D12_ERROR_AND_RETURN("Could not acquire swapchain!", false); 7669#endif 7670 7671 // Set up presentation 7672 if (d3d12CommandBuffer->presentDataCount == d3d12CommandBuffer->presentDataCapacity) { 7673 d3d12CommandBuffer->presentDataCapacity += 1; 7674 d3d12CommandBuffer->presentDatas = (D3D12PresentData *)SDL_realloc( 7675 d3d12CommandBuffer->presentDatas, 7676 d3d12CommandBuffer->presentDataCapacity * sizeof(D3D12PresentData)); 7677 } 7678 d3d12CommandBuffer->presentDatas[d3d12CommandBuffer->presentDataCount].windowData = windowData; 7679 d3d12CommandBuffer->presentDatas[d3d12CommandBuffer->presentDataCount].swapchainImageIndex = swapchainIndex; 7680 d3d12CommandBuffer->presentDataCount += 1; 7681 7682 // Set up resource barrier 7683 D3D12_RESOURCE_BARRIER barrierDesc; 7684 barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 7685 barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 7686 barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; 7687 barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; 7688 barrierDesc.Transition.pResource = windowData->textureContainers[swapchainIndex].activeTexture->resource; 7689 barrierDesc.Transition.Subresource = 0; 7690 7691 ID3D12GraphicsCommandList_ResourceBarrier( 7692 d3d12CommandBuffer->graphicsCommandList, 7693 1, 7694 &barrierDesc); 7695 7696 *swapchainTexture = (SDL_GPUTexture *)&windowData->textureContainers[swapchainIndex]; 7697 return true; 7698} 7699 7700static bool D3D12_AcquireSwapchainTexture( 7701 SDL_GPUCommandBuffer *command_buffer, 7702 SDL_Window *window, 7703 SDL_GPUTexture **swapchain_texture, 7704 Uint32 *swapchain_texture_width, 7705 Uint32 *swapchain_texture_height 7706) { 7707 return D3D12_INTERNAL_AcquireSwapchainTexture( 7708 false, 7709 command_buffer, 7710 window, 7711 swapchain_texture, 7712 swapchain_texture_width, 7713 swapchain_texture_height); 7714} 7715 7716static bool D3D12_WaitAndAcquireSwapchainTexture( 7717 SDL_GPUCommandBuffer *command_buffer, 7718 SDL_Window *window, 7719 SDL_GPUTexture **swapchain_texture, 7720 Uint32 *swapchain_texture_width, 7721 Uint32 *swapchain_texture_height 7722) { 7723 return D3D12_INTERNAL_AcquireSwapchainTexture( 7724 true, 7725 command_buffer, 7726 window, 7727 swapchain_texture, 7728 swapchain_texture_width, 7729 swapchain_texture_height); 7730} 7731 7732static void D3D12_INTERNAL_PerformPendingDestroys(D3D12Renderer *renderer) 7733{ 7734 SDL_LockMutex(renderer->disposeLock); 7735 7736 for (Sint32 i = renderer->buffersToDestroyCount - 1; i >= 0; i -= 1) { 7737 if (SDL_GetAtomicInt(&renderer->buffersToDestroy[i]->referenceCount) == 0) { 7738 D3D12_INTERNAL_DestroyBuffer( 7739 renderer->buffersToDestroy[i]); 7740 7741 renderer->buffersToDestroy[i] = renderer->buffersToDestroy[renderer->buffersToDestroyCount - 1]; 7742 renderer->buffersToDestroyCount -= 1; 7743 } 7744 } 7745 7746 for (Sint32 i = renderer->texturesToDestroyCount - 1; i >= 0; i -= 1) { 7747 if (SDL_GetAtomicInt(&renderer->texturesToDestroy[i]->referenceCount) == 0) { 7748 D3D12_INTERNAL_DestroyTexture( 7749 renderer->texturesToDestroy[i]); 7750 7751 renderer->texturesToDestroy[i] = renderer->texturesToDestroy[renderer->texturesToDestroyCount - 1]; 7752 renderer->texturesToDestroyCount -= 1; 7753 } 7754 } 7755 7756 for (Sint32 i = renderer->samplersToDestroyCount - 1; i >= 0; i -= 1) { 7757 if (SDL_GetAtomicInt(&renderer->samplersToDestroy[i]->referenceCount) == 0) { 7758 D3D12_INTERNAL_DestroySampler( 7759 renderer->samplersToDestroy[i]); 7760 7761 renderer->samplersToDestroy[i] = renderer->samplersToDestroy[renderer->samplersToDestroyCount - 1]; 7762 renderer->samplersToDestroyCount -= 1; 7763 } 7764 } 7765 7766 for (Sint32 i = renderer->graphicsPipelinesToDestroyCount - 1; i >= 0; i -= 1) { 7767 if (SDL_GetAtomicInt(&renderer->graphicsPipelinesToDestroy[i]->referenceCount) == 0) { 7768 D3D12_INTERNAL_DestroyGraphicsPipeline( 7769 renderer->graphicsPipelinesToDestroy[i]); 7770 7771 renderer->graphicsPipelinesToDestroy[i] = renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount - 1]; 7772 renderer->graphicsPipelinesToDestroyCount -= 1; 7773 } 7774 } 7775 7776 for (Sint32 i = renderer->computePipelinesToDestroyCount - 1; i >= 0; i -= 1) { 7777 if (SDL_GetAtomicInt(&renderer->computePipelinesToDestroy[i]->referenceCount) == 0) { 7778 D3D12_INTERNAL_DestroyComputePipeline( 7779 renderer->computePipelinesToDestroy[i]); 7780 7781 renderer->computePipelinesToDestroy[i] = renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount - 1]; 7782 renderer->computePipelinesToDestroyCount -= 1; 7783 } 7784 } 7785 7786 SDL_UnlockMutex(renderer->disposeLock); 7787} 7788 7789static bool D3D12_INTERNAL_CopyTextureDownload( 7790 D3D12CommandBuffer *commandBuffer, 7791 D3D12TextureDownload *download) 7792{ 7793 D3D12Renderer *renderer = commandBuffer->renderer; 7794 Uint8 *sourcePtr; 7795 Uint8 *destPtr; 7796 HRESULT res; 7797 7798 res = ID3D12Resource_Map( 7799 download->temporaryBuffer->handle, 7800 0, 7801 NULL, 7802 (void **)&sourcePtr); 7803 7804 CHECK_D3D12_ERROR_AND_RETURN("Failed to map temporary buffer", false); 7805 7806 res = ID3D12Resource_Map( 7807 download->destinationBuffer->handle, 7808 0, 7809 NULL, 7810 (void **)&destPtr); 7811 7812 CHECK_D3D12_ERROR_AND_RETURN("Failed to map destination buffer", false); 7813 7814 for (Uint32 sliceIndex = 0; sliceIndex < download->depth; sliceIndex += 1) { 7815 for (Uint32 rowIndex = 0; rowIndex < download->height; rowIndex += 1) { 7816 SDL_memcpy( 7817 destPtr + download->bufferOffset + (sliceIndex * download->bytesPerDepthSlice) + (rowIndex * download->bytesPerRow), 7818 sourcePtr + (sliceIndex * download->height) + (rowIndex * download->alignedBytesPerRow), 7819 download->bytesPerRow); 7820 } 7821 } 7822 7823 ID3D12Resource_Unmap( 7824 download->temporaryBuffer->handle, 7825 0, 7826 NULL); 7827 7828 ID3D12Resource_Unmap( 7829 download->destinationBuffer->handle, 7830 0, 7831 NULL); 7832 7833 return true; 7834} 7835 7836static bool D3D12_INTERNAL_CleanCommandBuffer( 7837 D3D12Renderer *renderer, 7838 D3D12CommandBuffer *commandBuffer, 7839 bool cancel) 7840{ 7841 Uint32 i; 7842 HRESULT res; 7843 bool result = true; 7844 7845 // Perform deferred texture data copies 7846 for (i = 0; i < commandBuffer->textureDownloadCount; i += 1) { 7847 if (!cancel) { 7848 result &= D3D12_INTERNAL_CopyTextureDownload( 7849 commandBuffer, 7850 commandBuffer->textureDownloads[i]); 7851 } 7852 SDL_free(commandBuffer->textureDownloads[i]); 7853 } 7854 commandBuffer->textureDownloadCount = 0; 7855 7856 if (!result) { 7857 return false; 7858 } 7859 7860 res = ID3D12CommandAllocator_Reset(commandBuffer->commandAllocator); 7861 CHECK_D3D12_ERROR_AND_RETURN("Could not reset command allocator", false); 7862 7863 res = ID3D12GraphicsCommandList_Reset( 7864 commandBuffer->graphicsCommandList, 7865 commandBuffer->commandAllocator, 7866 NULL); 7867 CHECK_D3D12_ERROR_AND_RETURN("Could not reset command list", false); 7868 7869 // Return descriptor heaps to pool, pools own their own locks 7870 for (i = 0; i < commandBuffer->usedDescriptorHeapCount; i += 1) { 7871 D3D12_INTERNAL_ReturnGPUDescriptorHeapToPool( 7872 renderer, 7873 commandBuffer->usedDescriptorHeaps[i]); 7874 } 7875 commandBuffer->usedDescriptorHeapCount = 0; 7876 7877 commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] = NULL; 7878 commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER] = NULL; 7879 7880 // Uniform buffers are now available 7881 SDL_LockMutex(renderer->acquireUniformBufferLock); 7882 7883 for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) { 7884 D3D12_INTERNAL_ReturnUniformBufferToPool( 7885 renderer, 7886 commandBuffer->usedUniformBuffers[i]); 7887 } 7888 commandBuffer->usedUniformBufferCount = 0; 7889 7890 SDL_UnlockMutex(renderer->acquireUniformBufferLock); 7891 7892 // TODO: More reference counting 7893 7894 for (i = 0; i < commandBuffer->usedTextureCount; i += 1) { 7895 (void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount); 7896 } 7897 commandBuffer->usedTextureCount = 0; 7898 7899 for (i = 0; i < commandBuffer->usedBufferCount; i += 1) { 7900 (void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount); 7901 } 7902 commandBuffer->usedBufferCount = 0; 7903 7904 for (i = 0; i < commandBuffer->usedSamplerCount; i += 1) { 7905 (void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount); 7906 } 7907 commandBuffer->usedSamplerCount = 0; 7908 7909 for (i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) { 7910 (void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount); 7911 } 7912 commandBuffer->usedGraphicsPipelineCount = 0; 7913 7914 for (i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) { 7915 (void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount); 7916 } 7917 commandBuffer->usedComputePipelineCount = 0; 7918 7919 // Reset presentation 7920 commandBuffer->presentDataCount = 0; 7921 7922 // The fence is now available (unless SubmitAndAcquireFence was called) 7923 if (commandBuffer->autoReleaseFence) { 7924 D3D12_ReleaseFence( 7925 (SDL_GPURenderer *)renderer, 7926 (SDL_GPUFence *)commandBuffer->inFlightFence); 7927 7928 commandBuffer->inFlightFence = NULL; 7929 } 7930 7931 // Return command buffer to pool 7932 SDL_LockMutex(renderer->acquireCommandBufferLock); 7933 7934 if (renderer->availableCommandBufferCount == renderer->availableCommandBufferCapacity) { 7935 renderer->availableCommandBufferCapacity += 1; 7936 renderer->availableCommandBuffers = (D3D12CommandBuffer **)SDL_realloc( 7937 renderer->availableCommandBuffers, 7938 renderer->availableCommandBufferCapacity * sizeof(D3D12CommandBuffer *)); 7939 } 7940 7941 renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer; 7942 renderer->availableCommandBufferCount += 1; 7943 7944 SDL_UnlockMutex(renderer->acquireCommandBufferLock); 7945 7946 // Remove this command buffer from the submitted list 7947 if (!cancel) { 7948 for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) { 7949 if (renderer->submittedCommandBuffers[i] == commandBuffer) { 7950 renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1]; 7951 renderer->submittedCommandBufferCount -= 1; 7952 } 7953 } 7954 } 7955 7956 return true; 7957} 7958 7959static bool D3D12_Submit( 7960 SDL_GPUCommandBuffer *commandBuffer) 7961{ 7962 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 7963 D3D12Renderer *renderer = d3d12CommandBuffer->renderer; 7964 ID3D12CommandList *commandLists[1]; 7965 HRESULT res; 7966 7967 SDL_LockMutex(renderer->submitLock); 7968 7969 // Unmap uniform buffers 7970 for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { 7971 if (d3d12CommandBuffer->vertexUniformBuffers[i] != NULL) { 7972 ID3D12Resource_Unmap( 7973 d3d12CommandBuffer->vertexUniformBuffers[i]->buffer->handle, 7974 0, 7975 NULL); 7976 d3d12CommandBuffer->vertexUniformBuffers[i]->buffer->mapPointer = NULL; 7977 } 7978 7979 if (d3d12CommandBuffer->fragmentUniformBuffers[i] != NULL) { 7980 ID3D12Resource_Unmap( 7981 d3d12CommandBuffer->fragmentUniformBuffers[i]->buffer->handle, 7982 0, 7983 NULL); 7984 d3d12CommandBuffer->fragmentUniformBuffers[i]->buffer->mapPointer = NULL; 7985 } 7986 7987 // TODO: compute uniforms 7988 } 7989 7990 // Transition present textures to present mode 7991 for (Uint32 i = 0; i < d3d12CommandBuffer->presentDataCount; i += 1) { 7992 Uint32 swapchainIndex = d3d12CommandBuffer->presentDatas[i].swapchainImageIndex; 7993 D3D12TextureContainer *container = &d3d12CommandBuffer->presentDatas[i].windowData->textureContainers[swapchainIndex]; 7994 D3D12TextureSubresource *subresource = D3D12_INTERNAL_FetchTextureSubresource(container, 0, 0); 7995 7996 D3D12_RESOURCE_BARRIER barrierDesc; 7997 barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; 7998 barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; 7999 barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; 8000 barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; 8001 barrierDesc.Transition.pResource = subresource->parent->resource; 8002 barrierDesc.Transition.Subresource = subresource->index; 8003 8004 ID3D12GraphicsCommandList_ResourceBarrier( 8005 d3d12CommandBuffer->graphicsCommandList, 8006 1, 8007 &barrierDesc); 8008 } 8009 8010 // Notify the command buffer that we have completed recording 8011 res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList); 8012 CHECK_D3D12_ERROR_AND_RETURN("Failed to close command list!", false); 8013 8014 res = ID3D12GraphicsCommandList_QueryInterface( 8015 d3d12CommandBuffer->graphicsCommandList, 8016 D3D_GUID(D3D_IID_ID3D12CommandList), 8017 (void **)&commandLists[0]); 8018 if (FAILED(res)) { 8019 SDL_UnlockMutex(renderer->submitLock); 8020 CHECK_D3D12_ERROR_AND_RETURN("Failed to convert command list!", false); 8021 } 8022 8023 // Submit the command list to the queue 8024 ID3D12CommandQueue_ExecuteCommandLists( 8025 renderer->commandQueue, 8026 1, 8027 commandLists); 8028 8029 ID3D12CommandList_Release(commandLists[0]); 8030 8031 // Acquire a fence and set it to the in-flight fence 8032 d3d12CommandBuffer->inFlightFence = D3D12_INTERNAL_AcquireFence(renderer); 8033 if (!d3d12CommandBuffer->inFlightFence) { 8034 SDL_UnlockMutex(renderer->submitLock); 8035 return false; 8036 } 8037 8038 // Mark that a fence should be signaled after command list execution 8039 res = ID3D12CommandQueue_Signal( 8040 renderer->commandQueue, 8041 d3d12CommandBuffer->inFlightFence->handle, 8042 D3D12_FENCE_SIGNAL_VALUE); 8043 if (FAILED(res)) { 8044 SDL_UnlockMutex(renderer->submitLock); 8045 CHECK_D3D12_ERROR_AND_RETURN("Failed to enqueue fence signal!", false); 8046 } 8047 8048 // Mark the command buffer as submitted 8049 if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) { 8050 renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1; 8051 8052 renderer->submittedCommandBuffers = (D3D12CommandBuffer **)SDL_realloc( 8053 renderer->submittedCommandBuffers, 8054 sizeof(D3D12CommandBuffer *) * renderer->submittedCommandBufferCapacity); 8055 } 8056 8057 renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = d3d12CommandBuffer; 8058 renderer->submittedCommandBufferCount += 1; 8059 8060 bool result = true; 8061 8062 // Present, if applicable 8063 for (Uint32 i = 0; i < d3d12CommandBuffer->presentDataCount; i += 1) { 8064 D3D12PresentData *presentData = &d3d12CommandBuffer->presentDatas[i]; 8065 D3D12WindowData *windowData = presentData->windowData; 8066 8067#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 8068 D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParams; 8069 SDL_zero(planeParams); 8070 planeParams.Token = windowData->frameToken; 8071 planeParams.ResourceCount = 1; 8072 planeParams.ppResources = &windowData->textureContainers[windowData->frameCounter].activeTexture->resource; 8073 planeParams.ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; // FIXME 8074 8075 D3D12XBOX_PRESENT_PARAMETERS presentParams; 8076 SDL_zero(presentParams); 8077 presentParams.Flags = (windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE) ? D3D12XBOX_PRESENT_FLAG_IMMEDIATE : D3D12XBOX_PRESENT_FLAG_NONE; 8078 8079 renderer->commandQueue->PresentX(1, &planeParams, &presentParams); 8080 if (FAILED(res)) { 8081 result = false; 8082 } 8083#else 8084 // NOTE: flip discard always supported since DXGI 1.4 is required 8085 Uint32 syncInterval = 1; 8086 if (windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE || 8087 windowData->present_mode == SDL_GPU_PRESENTMODE_MAILBOX) { 8088 syncInterval = 0; 8089 } 8090 8091 Uint32 presentFlags = 0; 8092 if (renderer->supportsTearing && 8093 windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE) { 8094 presentFlags = DXGI_PRESENT_ALLOW_TEARING; 8095 } 8096 8097 res = IDXGISwapChain_Present( 8098 windowData->swapchain, 8099 syncInterval, 8100 presentFlags); 8101 if (FAILED(res)) { 8102 result = false; 8103 } 8104 8105 ID3D12Resource_Release(windowData->textureContainers[presentData->swapchainImageIndex].activeTexture->resource); 8106#endif 8107 8108 windowData->inFlightFences[windowData->frameCounter] = (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence; 8109 (void)SDL_AtomicIncRef(&d3d12CommandBuffer->inFlightFence->referenceCount); 8110 8111 // Normally this is '% allowedFramesInFlight', but the value gets clamped 8112 // at swapchain creation time, so use swapchainTextureCount instead 8113 windowData->frameCounter = (windowData->frameCounter + 1) % windowData->swapchainTextureCount; 8114 } 8115 8116 // Check for cleanups 8117 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 8118 Uint64 fenceValue = ID3D12Fence_GetCompletedValue( 8119 renderer->submittedCommandBuffers[i]->inFlightFence->handle); 8120 8121 if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { 8122 result &= D3D12_INTERNAL_CleanCommandBuffer( 8123 renderer, 8124 renderer->submittedCommandBuffers[i], 8125 false); 8126 } 8127 } 8128 8129 D3D12_INTERNAL_PerformPendingDestroys(renderer); 8130 8131 SDL_UnlockMutex(renderer->submitLock); 8132 8133 return result; 8134} 8135 8136static SDL_GPUFence *D3D12_SubmitAndAcquireFence( 8137 SDL_GPUCommandBuffer *commandBuffer) 8138{ 8139 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 8140 d3d12CommandBuffer->autoReleaseFence = false; 8141 if (!D3D12_Submit(commandBuffer)) { 8142 return NULL; 8143 } 8144 return (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence; 8145} 8146 8147static bool D3D12_Cancel( 8148 SDL_GPUCommandBuffer *commandBuffer) 8149{ 8150 D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer; 8151 D3D12Renderer *renderer = d3d12CommandBuffer->renderer; 8152 bool result; 8153 HRESULT res; 8154 8155 // Notify the command buffer that we have completed recording 8156 res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList); 8157 CHECK_D3D12_ERROR_AND_RETURN("Failed to close command list!", false); 8158 8159 d3d12CommandBuffer->autoReleaseFence = false; 8160 SDL_LockMutex(renderer->submitLock); 8161 result = D3D12_INTERNAL_CleanCommandBuffer(renderer, d3d12CommandBuffer, true); 8162 SDL_UnlockMutex(renderer->submitLock); 8163 8164 return result; 8165} 8166 8167static bool D3D12_Wait( 8168 SDL_GPURenderer *driverData) 8169{ 8170 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 8171 D3D12Fence *fence = D3D12_INTERNAL_AcquireFence(renderer); 8172 if (!fence) { 8173 return false; 8174 } 8175 HRESULT res; 8176 8177 SDL_LockMutex(renderer->submitLock); 8178 8179 if (renderer->commandQueue) { 8180 // Insert a signal into the end of the command queue... 8181 ID3D12CommandQueue_Signal( 8182 renderer->commandQueue, 8183 fence->handle, 8184 D3D12_FENCE_SIGNAL_VALUE); 8185 8186 // ...and then block on it. 8187 if (ID3D12Fence_GetCompletedValue(fence->handle) != D3D12_FENCE_SIGNAL_VALUE) { 8188 res = ID3D12Fence_SetEventOnCompletion( 8189 fence->handle, 8190 D3D12_FENCE_SIGNAL_VALUE, 8191 fence->event); 8192 CHECK_D3D12_ERROR_AND_RETURN("Setting fence event failed", false); 8193 8194 DWORD waitResult = WaitForSingleObject(fence->event, INFINITE); 8195 if (waitResult == WAIT_FAILED) { 8196 SDL_UnlockMutex(renderer->submitLock); 8197 SET_STRING_ERROR_AND_RETURN("Wait failed", false); // TODO: is there a better way to report this? 8198 } 8199 } 8200 } 8201 8202 D3D12_ReleaseFence( 8203 (SDL_GPURenderer *)renderer, 8204 (SDL_GPUFence *)fence); 8205 8206 bool result = true; 8207 8208 // Clean up 8209 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 8210 result &= D3D12_INTERNAL_CleanCommandBuffer(renderer, renderer->submittedCommandBuffers[i], false); 8211 } 8212 8213 D3D12_INTERNAL_PerformPendingDestroys(renderer); 8214 8215 SDL_UnlockMutex(renderer->submitLock); 8216 8217 return result; 8218} 8219 8220static bool D3D12_WaitForFences( 8221 SDL_GPURenderer *driverData, 8222 bool waitAll, 8223 SDL_GPUFence *const *fences, 8224 Uint32 numFences) 8225{ 8226 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 8227 D3D12Fence *fence; 8228 HANDLE *events = SDL_stack_alloc(HANDLE, numFences); 8229 HRESULT res; 8230 8231 SDL_LockMutex(renderer->submitLock); 8232 8233 for (Uint32 i = 0; i < numFences; i += 1) { 8234 fence = (D3D12Fence *)fences[i]; 8235 8236 res = ID3D12Fence_SetEventOnCompletion( 8237 fence->handle, 8238 D3D12_FENCE_SIGNAL_VALUE, 8239 fence->event); 8240 CHECK_D3D12_ERROR_AND_RETURN("Setting fence event failed", false); 8241 8242 events[i] = fence->event; 8243 } 8244 8245 DWORD waitResult = WaitForMultipleObjects( 8246 numFences, 8247 events, 8248 waitAll, 8249 INFINITE); 8250 8251 if (waitResult == WAIT_FAILED) { 8252 SDL_UnlockMutex(renderer->submitLock); 8253 SET_STRING_ERROR_AND_RETURN("Wait failed", false); // TODO: is there a better way to report this? 8254 } 8255 8256 bool result = true; 8257 8258 // Check for cleanups 8259 for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { 8260 Uint64 fenceValue = ID3D12Fence_GetCompletedValue( 8261 renderer->submittedCommandBuffers[i]->inFlightFence->handle); 8262 8263 if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { 8264 result &= D3D12_INTERNAL_CleanCommandBuffer( 8265 renderer, 8266 renderer->submittedCommandBuffers[i], 8267 false); 8268 } 8269 } 8270 8271 D3D12_INTERNAL_PerformPendingDestroys(renderer); 8272 8273 SDL_stack_free(events); 8274 8275 SDL_UnlockMutex(renderer->submitLock); 8276 8277 return result; 8278} 8279 8280// Feature Queries 8281 8282static bool D3D12_SupportsTextureFormat( 8283 SDL_GPURenderer *driverData, 8284 SDL_GPUTextureFormat format, 8285 SDL_GPUTextureType type, 8286 SDL_GPUTextureUsageFlags usage) 8287{ 8288 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 8289 DXGI_FORMAT dxgiFormat = SDLToD3D12_TextureFormat[format]; 8290 D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = { dxgiFormat, D3D12_FORMAT_SUPPORT1_NONE, D3D12_FORMAT_SUPPORT2_NONE }; 8291 HRESULT res; 8292 8293 res = ID3D12Device_CheckFeatureSupport( 8294 renderer->device, 8295 D3D12_FEATURE_FORMAT_SUPPORT, 8296 &formatSupport, 8297 sizeof(formatSupport)); 8298 if (FAILED(res)) { 8299 // Format is apparently unknown 8300 return false; 8301 } 8302 8303 // Is the texture type supported? 8304 if (type == SDL_GPU_TEXTURETYPE_2D && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) { 8305 return false; 8306 } 8307 if (type == SDL_GPU_TEXTURETYPE_2D_ARRAY && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) { 8308 return false; 8309 } 8310 if (type == SDL_GPU_TEXTURETYPE_3D && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE3D)) { 8311 return false; 8312 } 8313 if (type == SDL_GPU_TEXTURETYPE_CUBE && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)) { 8314 return false; 8315 } 8316 if (type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)) { 8317 return false; 8318 } 8319 8320 // Are the usage flags supported? 8321 if ((usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)) { 8322 return false; 8323 } 8324 if ((usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD)) { 8325 return false; 8326 } 8327 if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) && !(formatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) { 8328 return false; 8329 } 8330 if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) && !(formatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD)) { 8331 return false; 8332 } 8333 if ((usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) { 8334 return false; 8335 } 8336 8337 // Special case check for depth, because D3D12 is great. 8338 formatSupport.Format = SDLToD3D12_DepthFormat[format]; 8339 formatSupport.Support1 = D3D12_FORMAT_SUPPORT1_NONE; 8340 formatSupport.Support2 = D3D12_FORMAT_SUPPORT2_NONE; 8341 8342 res = ID3D12Device_CheckFeatureSupport( 8343 renderer->device, 8344 D3D12_FEATURE_FORMAT_SUPPORT, 8345 &formatSupport, 8346 sizeof(formatSupport)); 8347 if (FAILED(res)) { 8348 // Format is apparently unknown 8349 return false; 8350 } 8351 8352 if ((usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) { 8353 return false; 8354 } 8355 8356 return true; 8357} 8358 8359static bool D3D12_SupportsSampleCount( 8360 SDL_GPURenderer *driverData, 8361 SDL_GPUTextureFormat format, 8362 SDL_GPUSampleCount sampleCount) 8363{ 8364 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 8365 D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS featureData; 8366 HRESULT res; 8367 8368#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 8369 featureData.Flags = (D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG)0; 8370#else 8371 featureData.Flags = (D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS)0; 8372#endif 8373 featureData.Format = SDLToD3D12_TextureFormat[format]; 8374 featureData.SampleCount = SDLToD3D12_SampleCount[sampleCount]; 8375 res = ID3D12Device_CheckFeatureSupport( 8376 renderer->device, 8377 D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, 8378 &featureData, 8379 sizeof(featureData)); 8380 8381 return SUCCEEDED(res) && featureData.NumQualityLevels > 0; 8382} 8383 8384static void D3D12_INTERNAL_InitBlitResources( 8385 D3D12Renderer *renderer) 8386{ 8387 SDL_GPUShaderCreateInfo shaderCreateInfo; 8388 SDL_GPUSamplerCreateInfo samplerCreateInfo; 8389 8390 renderer->blitPipelineCapacity = 2; 8391 renderer->blitPipelineCount = 0; 8392 renderer->blitPipelines = (BlitPipelineCacheEntry *)SDL_malloc( 8393 renderer->blitPipelineCapacity * sizeof(BlitPipelineCacheEntry)); 8394 8395 // Fullscreen vertex shader 8396 SDL_zero(shaderCreateInfo); 8397 shaderCreateInfo.code = (Uint8 *)D3D12_FullscreenVert; 8398 shaderCreateInfo.code_size = sizeof(D3D12_FullscreenVert); 8399 shaderCreateInfo.stage = SDL_GPU_SHADERSTAGE_VERTEX; 8400 shaderCreateInfo.format = SDL_GPU_SHADERFORMAT_DXIL; 8401 8402 renderer->blitVertexShader = D3D12_CreateShader( 8403 (SDL_GPURenderer *)renderer, 8404 &shaderCreateInfo); 8405 8406 if (renderer->blitVertexShader == NULL) { 8407 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile vertex shader for blit!"); 8408 } 8409 8410 // BlitFrom2D pixel shader 8411 shaderCreateInfo.code = (Uint8 *)D3D12_BlitFrom2D; 8412 shaderCreateInfo.code_size = sizeof(D3D12_BlitFrom2D); 8413 shaderCreateInfo.stage = SDL_GPU_SHADERSTAGE_FRAGMENT; 8414 shaderCreateInfo.num_samplers = 1; 8415 shaderCreateInfo.num_uniform_buffers = 1; 8416 8417 renderer->blitFrom2DShader = D3D12_CreateShader( 8418 (SDL_GPURenderer *)renderer, 8419 &shaderCreateInfo); 8420 8421 if (renderer->blitFrom2DShader == NULL) { 8422 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom2D pixel shader!"); 8423 } 8424 8425 // BlitFrom2DArray pixel shader 8426 shaderCreateInfo.code = (Uint8 *)D3D12_BlitFrom2DArray; 8427 shaderCreateInfo.code_size = sizeof(D3D12_BlitFrom2DArray); 8428 8429 renderer->blitFrom2DArrayShader = D3D12_CreateShader( 8430 (SDL_GPURenderer *)renderer, 8431 &shaderCreateInfo); 8432 8433 if (renderer->blitFrom2DArrayShader == NULL) { 8434 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom2DArray pixel shader!"); 8435 } 8436 8437 // BlitFrom3D pixel shader 8438 shaderCreateInfo.code = (Uint8 *)D3D12_BlitFrom3D; 8439 shaderCreateInfo.code_size = sizeof(D3D12_BlitFrom3D); 8440 8441 renderer->blitFrom3DShader = D3D12_CreateShader( 8442 (SDL_GPURenderer *)renderer, 8443 &shaderCreateInfo); 8444 8445 if (renderer->blitFrom3DShader == NULL) { 8446 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom3D pixel shader!"); 8447 } 8448 8449 // BlitFromCube pixel shader 8450 shaderCreateInfo.code = (Uint8 *)D3D12_BlitFromCube; 8451 shaderCreateInfo.code_size = sizeof(D3D12_BlitFromCube); 8452 8453 renderer->blitFromCubeShader = D3D12_CreateShader( 8454 (SDL_GPURenderer *)renderer, 8455 &shaderCreateInfo); 8456 8457 if (renderer->blitFromCubeShader == NULL) { 8458 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFromCube pixel shader!"); 8459 } 8460 8461 // BlitFromCubeArray pixel shader 8462 shaderCreateInfo.code = (Uint8 *)D3D12_BlitFromCubeArray; 8463 shaderCreateInfo.code_size = sizeof(D3D12_BlitFromCubeArray); 8464 8465 renderer->blitFromCubeArrayShader = D3D12_CreateShader( 8466 (SDL_GPURenderer *)renderer, 8467 &shaderCreateInfo); 8468 8469 if (renderer->blitFromCubeArrayShader == NULL) { 8470 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFromCubeArray pixel shader!"); 8471 } 8472 8473 // Create samplers 8474 samplerCreateInfo.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; 8475 samplerCreateInfo.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; 8476 samplerCreateInfo.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; 8477 samplerCreateInfo.enable_anisotropy = 0; 8478 samplerCreateInfo.enable_compare = 0; 8479 samplerCreateInfo.mag_filter = SDL_GPU_FILTER_NEAREST; 8480 samplerCreateInfo.min_filter = SDL_GPU_FILTER_NEAREST; 8481 samplerCreateInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST; 8482 samplerCreateInfo.mip_lod_bias = 0.0f; 8483 samplerCreateInfo.min_lod = 0; 8484 samplerCreateInfo.max_lod = 1000; 8485 samplerCreateInfo.max_anisotropy = 1.0f; 8486 samplerCreateInfo.compare_op = SDL_GPU_COMPAREOP_NEVER; 8487 8488 renderer->blitNearestSampler = D3D12_CreateSampler( 8489 (SDL_GPURenderer *)renderer, 8490 &samplerCreateInfo); 8491 8492 if (renderer->blitNearestSampler == NULL) { 8493 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create blit nearest sampler!"); 8494 } 8495 8496 samplerCreateInfo.mag_filter = SDL_GPU_FILTER_LINEAR; 8497 samplerCreateInfo.min_filter = SDL_GPU_FILTER_LINEAR; 8498 samplerCreateInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; 8499 8500 renderer->blitLinearSampler = D3D12_CreateSampler( 8501 (SDL_GPURenderer *)renderer, 8502 &samplerCreateInfo); 8503 8504 if (renderer->blitLinearSampler == NULL) { 8505 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create blit linear sampler!"); 8506 } 8507} 8508 8509static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props) 8510{ 8511#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 8512 return true; 8513#else 8514 SDL_SharedObject *d3d12Dll; 8515 SDL_SharedObject *dxgiDll; 8516 PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice; 8517 pfnCreateDXGIFactory1 pCreateDXGIFactory1; 8518 HRESULT res; 8519 ID3D12Device *device; 8520 IDXGIFactory1 *factory; 8521 IDXGIFactory4 *factory4; 8522 IDXGIFactory6 *factory6; 8523 IDXGIAdapter1 *adapter; 8524 bool supports_64UAVs = false; 8525 bool needs_64UAVs = !SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN, false); 8526 8527 // Early check to see if the app has _any_ D3D12 formats, if not we don't 8528 // have to fuss with loading D3D in the first place. 8529 bool has_dxbc = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, false); 8530 bool has_dxil = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, false); 8531 bool supports_dxil = false; 8532 // TODO SM7: bool has_spirv = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN, false); 8533 // TODO SM7: bool supports_spirv = false; 8534 if (!has_dxbc && !has_dxil) { 8535 return false; 8536 } 8537 8538 // Can we load D3D12? 8539 8540 d3d12Dll = SDL_LoadObject(D3D12_DLL); 8541 if (d3d12Dll == NULL) { 8542 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find " D3D12_DLL); 8543 return false; 8544 } 8545 8546 pD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( 8547 d3d12Dll, 8548 D3D12_CREATE_DEVICE_FUNC); 8549 if (pD3D12CreateDevice == NULL) { 8550 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find function " D3D12_CREATE_DEVICE_FUNC " in " D3D12_DLL); 8551 SDL_UnloadObject(d3d12Dll); 8552 return false; 8553 } 8554 8555 // Can we load DXGI? 8556 8557 dxgiDll = SDL_LoadObject(DXGI_DLL); 8558 if (dxgiDll == NULL) { 8559 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find " DXGI_DLL); 8560 return false; 8561 } 8562 8563 pCreateDXGIFactory1 = (pfnCreateDXGIFactory1)SDL_LoadFunction( 8564 dxgiDll, 8565 CREATE_DXGI_FACTORY1_FUNC); 8566 if (pCreateDXGIFactory1 == NULL) { 8567 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find function " CREATE_DXGI_FACTORY1_FUNC " in " DXGI_DLL); 8568 SDL_UnloadObject(dxgiDll); 8569 return false; 8570 } 8571 8572 // Can we create a device? 8573 8574 // Create the DXGI factory 8575 res = pCreateDXGIFactory1( 8576 &D3D_IID_IDXGIFactory1, 8577 (void **)&factory); 8578 if (FAILED(res)) { 8579 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not create DXGIFactory"); 8580 SDL_UnloadObject(d3d12Dll); 8581 SDL_UnloadObject(dxgiDll); 8582 return false; 8583 } 8584 8585 // Check for DXGI 1.4 support 8586 res = IDXGIFactory1_QueryInterface( 8587 factory, 8588 D3D_GUID(D3D_IID_IDXGIFactory4), 8589 (void **)&factory4); 8590 if (FAILED(res)) { 8591 IDXGIFactory1_Release(factory); 8592 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to find DXGI1.4 support, required for DX12"); 8593 SDL_UnloadObject(d3d12Dll); 8594 SDL_UnloadObject(dxgiDll); 8595 return false; 8596 } 8597 IDXGIFactory4_Release(factory4); 8598 8599 res = IDXGIFactory1_QueryInterface( 8600 factory, 8601 D3D_GUID(D3D_IID_IDXGIFactory6), 8602 (void **)&factory6); 8603 if (SUCCEEDED(res)) { 8604 res = IDXGIFactory6_EnumAdapterByGpuPreference( 8605 factory6, 8606 0, 8607 DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, 8608 D3D_GUID(D3D_IID_IDXGIAdapter1), 8609 (void **)&adapter); 8610 IDXGIFactory6_Release(factory6); 8611 } else { 8612 res = IDXGIFactory1_EnumAdapters1( 8613 factory, 8614 0, 8615 &adapter); 8616 } 8617 if (FAILED(res)) { 8618 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to find adapter for D3D12Device"); 8619 IDXGIFactory1_Release(factory); 8620 SDL_UnloadObject(d3d12Dll); 8621 SDL_UnloadObject(dxgiDll); 8622 return false; 8623 } 8624 8625 SDL_COMPILE_TIME_ASSERT(featurelevel, D3D_FEATURE_LEVEL_CHOICE < D3D_FEATURE_LEVEL_11_1); 8626 8627 /* If Windows 11 is running and the app has neither DXIL nor TIER2 8628 * requirements, we can skip doing any device checks entirely 8629 */ 8630 if (!needs_64UAVs && !has_dxil && WIN_IsWindows11OrGreater()) { 8631 IDXGIAdapter1_Release(adapter); 8632 IDXGIFactory1_Release(factory); 8633 8634 SDL_UnloadObject(d3d12Dll); 8635 SDL_UnloadObject(dxgiDll); 8636 8637 return true; 8638 } 8639 8640 res = pD3D12CreateDevice( 8641 (IUnknown *)adapter, 8642 D3D_FEATURE_LEVEL_CHOICE, 8643 D3D_GUID(D3D_IID_ID3D12Device), 8644 (void **)&device); 8645 if (SUCCEEDED(res)) { 8646 // Only check for Tier 2 resource binding if the app needs it 8647 if (needs_64UAVs) { 8648 D3D12_FEATURE_DATA_D3D12_OPTIONS featureOptions; 8649 SDL_zero(featureOptions); 8650 8651 res = ID3D12Device_CheckFeatureSupport( 8652 device, 8653 D3D12_FEATURE_D3D12_OPTIONS, 8654 &featureOptions, 8655 sizeof(featureOptions)); 8656 if (SUCCEEDED(res) && featureOptions.ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_2) { 8657 supports_64UAVs = true; 8658 } 8659 } 8660 8661 // Only check for SM6 support if DXIL is provided 8662 if (has_dxil) { 8663 D3D12_FEATURE_DATA_SHADER_MODEL shaderModel; 8664 shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; 8665 8666 res = ID3D12Device_CheckFeatureSupport( 8667 device, 8668 D3D12_FEATURE_SHADER_MODEL, 8669 &shaderModel, 8670 sizeof(shaderModel)); 8671 if (SUCCEEDED(res) && shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0) { 8672 supports_dxil = true; 8673 } 8674 } 8675 8676 ID3D12Device_Release(device); 8677 } 8678 8679 IDXGIAdapter1_Release(adapter); 8680 IDXGIFactory1_Release(factory); 8681 8682 SDL_UnloadObject(d3d12Dll); 8683 SDL_UnloadObject(dxgiDll); 8684 8685 if (!supports_64UAVs && needs_64UAVs) { 8686 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Tier 2 Resource Binding is not supported"); 8687 return false; 8688 } 8689 8690 if (!supports_dxil && !has_dxbc) { 8691 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: DXIL is not supported and DXBC is not being provided"); 8692 return false; 8693 } 8694 8695 if (FAILED(res)) { 8696 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not create D3D12Device with feature level " D3D_FEATURE_LEVEL_CHOICE_STR); 8697 return false; 8698 } 8699 8700#ifdef HAVE_GPU_OPENXR 8701 // Check for OpenXR support if requested 8702 bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false); 8703 if (xr) { 8704 if (!SDL_OpenXR_LoadLibrary()) { 8705 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to load OpenXR: %s", SDL_GetError()); 8706 return false; 8707 } 8708 8709 XrExtensionProperties gpuExtension; 8710 if (!D3D12_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) { 8711 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to find " XR_KHR_D3D12_ENABLE_EXTENSION_NAME " extension"); 8712 SDL_OpenXR_UnloadLibrary(); 8713 return false; 8714 } 8715 SDL_OpenXR_UnloadLibrary(); 8716 } 8717#endif 8718 8719 return true; 8720#endif 8721} 8722 8723#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) && defined(HAVE_IDXGIINFOQUEUE) 8724static bool D3D12_INTERNAL_TryInitializeDXGIDebug(D3D12Renderer *renderer) 8725{ 8726 pfnDXGIGetDebugInterface pDXGIGetDebugInterface; 8727 HRESULT res; 8728 8729 renderer->dxgidebug_dll = SDL_LoadObject(DXGIDEBUG_DLL); 8730 if (renderer->dxgidebug_dll == NULL) { 8731 return false; 8732 } 8733 8734 pDXGIGetDebugInterface = (pfnDXGIGetDebugInterface)SDL_LoadFunction( 8735 renderer->dxgidebug_dll, 8736 DXGI_GET_DEBUG_INTERFACE_FUNC); 8737 if (pDXGIGetDebugInterface == NULL) { 8738 return false; 8739 } 8740 8741 res = pDXGIGetDebugInterface(&D3D_IID_IDXGIDebug, (void **)&renderer->dxgiDebug); 8742 if (FAILED(res)) { 8743 return false; 8744 } 8745 8746 res = pDXGIGetDebugInterface(&D3D_IID_IDXGIInfoQueue, (void **)&renderer->dxgiInfoQueue); 8747 if (FAILED(res)) { 8748 return false; 8749 } 8750 8751 return true; 8752} 8753#endif 8754 8755static bool D3D12_INTERNAL_TryInitializeD3D12Debug(D3D12Renderer *renderer 8756#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 8757 , ID3D12DeviceFactory * factory 8758#endif 8759) { 8760 PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface; 8761 HRESULT res; 8762 8763#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 8764 if (factory) { 8765 res = ID3D12DeviceFactory_GetConfigurationInterface(factory, &D3D_CLSID_ID3D12Debug, &D3D_IID_ID3D12Debug, (void **)&renderer->d3d12Debug); 8766 8767 if (FAILED(res)) { 8768 return false; 8769 } 8770 8771 ID3D12Debug_EnableDebugLayer(renderer->d3d12Debug); 8772 return true; 8773 } 8774#endif 8775 8776 pD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)SDL_LoadFunction( 8777 renderer->d3d12_dll, 8778 D3D12_GET_DEBUG_INTERFACE_FUNC); 8779 if (pD3D12GetDebugInterface == NULL) { 8780 return false; 8781 } 8782 8783 res = pD3D12GetDebugInterface(D3D_GUID(D3D_IID_ID3D12Debug), (void **)&renderer->d3d12Debug); 8784 if (FAILED(res)) { 8785 return false; 8786 } 8787 8788 ID3D12Debug_EnableDebugLayer(renderer->d3d12Debug); 8789 return true; 8790} 8791 8792#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 8793static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *renderer) 8794{ 8795 ID3D12InfoQueue *infoQueue = NULL; 8796 D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; 8797 D3D12_INFO_QUEUE_FILTER filter; 8798 HRESULT res; 8799 8800 res = ID3D12Device_QueryInterface( 8801 renderer->device, 8802 D3D_GUID(D3D_IID_ID3D12InfoQueue), 8803 (void **)&infoQueue); 8804 if (FAILED(res)) { 8805 return; 8806 } 8807 8808 SDL_zero(filter); 8809 filter.DenyList.NumSeverities = 1; 8810 filter.DenyList.pSeverityList = severities; 8811 ID3D12InfoQueue_PushStorageFilter( 8812 infoQueue, 8813 &filter); 8814 8815 ID3D12InfoQueue_SetBreakOnSeverity( 8816 infoQueue, 8817 D3D12_MESSAGE_SEVERITY_CORRUPTION, 8818 true); 8819 8820 ID3D12InfoQueue_Release(infoQueue); 8821} 8822 8823static void WINAPI D3D12_INTERNAL_OnD3D12DebugInfoMsg( 8824 D3D12_MESSAGE_CATEGORY category, 8825 D3D12_MESSAGE_SEVERITY severity, 8826 D3D12_MESSAGE_ID id, 8827 LPCSTR description, 8828 void *context) 8829{ 8830 char *catStr; 8831 char *sevStr; 8832 8833 switch (category) { 8834 case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: 8835 catStr = "APPLICATION_DEFINED"; 8836 break; 8837 case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: 8838 catStr = "MISCELLANEOUS"; 8839 break; 8840 case D3D12_MESSAGE_CATEGORY_INITIALIZATION: 8841 catStr = "INITIALIZATION"; 8842 break; 8843 case D3D12_MESSAGE_CATEGORY_CLEANUP: 8844 catStr = "CLEANUP"; 8845 break; 8846 case D3D12_MESSAGE_CATEGORY_COMPILATION: 8847 catStr = "COMPILATION"; 8848 break; 8849 case D3D12_MESSAGE_CATEGORY_STATE_CREATION: 8850 catStr = "STATE_CREATION"; 8851 break; 8852 case D3D12_MESSAGE_CATEGORY_STATE_SETTING: 8853 catStr = "STATE_SETTING"; 8854 break; 8855 case D3D12_MESSAGE_CATEGORY_STATE_GETTING: 8856 catStr = "STATE_GETTING"; 8857 break; 8858 case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: 8859 catStr = "RESOURCE_MANIPULATION"; 8860 break; 8861 case D3D12_MESSAGE_CATEGORY_EXECUTION: 8862 catStr = "EXECUTION"; 8863 break; 8864 case D3D12_MESSAGE_CATEGORY_SHADER: 8865 catStr = "SHADER"; 8866 break; 8867 default: 8868 catStr = "UNKNOWN"; 8869 break; 8870 } 8871 8872 switch (severity) { 8873 case D3D12_MESSAGE_SEVERITY_CORRUPTION: 8874 sevStr = "CORRUPTION"; 8875 break; 8876 case D3D12_MESSAGE_SEVERITY_ERROR: 8877 sevStr = "ERROR"; 8878 break; 8879 case D3D12_MESSAGE_SEVERITY_WARNING: 8880 sevStr = "WARNING"; 8881 break; 8882 case D3D12_MESSAGE_SEVERITY_INFO: 8883 sevStr = "INFO"; 8884 break; 8885 case D3D12_MESSAGE_SEVERITY_MESSAGE: 8886 sevStr = "MESSAGE"; 8887 break; 8888 default: 8889 sevStr = "UNKNOWN"; 8890 break; 8891 } 8892 8893 if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) { 8894 SDL_LogError( 8895 SDL_LOG_CATEGORY_GPU, 8896 "D3D12 ERROR: %s [%s %s #%d]", 8897 description, 8898 catStr, 8899 sevStr, 8900 id); 8901 } else { 8902 SDL_LogWarn( 8903 SDL_LOG_CATEGORY_GPU, 8904 "D3D12 WARNING: %s [%s %s #%d]", 8905 description, 8906 catStr, 8907 sevStr, 8908 id); 8909 } 8910} 8911 8912static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoLogger(D3D12Renderer *renderer) 8913{ 8914 ID3D12InfoQueue1 *infoQueue = NULL; 8915 HRESULT res; 8916 8917 res = ID3D12Device_QueryInterface( 8918 renderer->device, 8919 D3D_GUID(D3D_IID_ID3D12InfoQueue1), 8920 (void **)&infoQueue); 8921 if (FAILED(res)) { 8922 return; 8923 } 8924 8925 ID3D12InfoQueue1_RegisterMessageCallback( 8926 infoQueue, 8927 D3D12_INTERNAL_OnD3D12DebugInfoMsg, 8928 D3D12_MESSAGE_CALLBACK_FLAG_NONE, 8929 NULL, 8930 NULL); 8931 8932 ID3D12InfoQueue1_Release(infoQueue); 8933} 8934#endif 8935 8936// OpenXR D3D12 Support 8937#ifdef HAVE_GPU_OPENXR 8938static bool D3D12_INTERNAL_SearchForOpenXrGpuExtension(XrExtensionProperties *found_extension) 8939{ 8940 XrResult result; 8941 Uint32 extension_count; 8942 Uint32 i; 8943 8944 result = xrEnumerateInstanceExtensionProperties(NULL, 0, &extension_count, NULL); 8945 if (result != XR_SUCCESS) { 8946 return false; 8947 } 8948 8949 XrExtensionProperties *extension_properties = (XrExtensionProperties *)SDL_calloc(extension_count, sizeof(XrExtensionProperties)); 8950 for (i = 0; i < extension_count; i++) { 8951 extension_properties[i] = (XrExtensionProperties){ XR_TYPE_EXTENSION_PROPERTIES }; 8952 } 8953 8954 result = xrEnumerateInstanceExtensionProperties(NULL, extension_count, &extension_count, extension_properties); 8955 if (result != XR_SUCCESS) { 8956 SDL_free(extension_properties); 8957 return false; 8958 } 8959 8960 for (i = 0; i < extension_count; i++) { 8961 XrExtensionProperties extension = extension_properties[i]; 8962 8963 if (SDL_strcmp(extension.extensionName, XR_KHR_D3D12_ENABLE_EXTENSION_NAME) == 0) { 8964 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Found " XR_KHR_D3D12_ENABLE_EXTENSION_NAME " extension"); 8965 8966 *found_extension = extension; 8967 8968 SDL_free(extension_properties); 8969 return true; 8970 } 8971 } 8972 8973 SDL_free(extension_properties); 8974 return false; 8975} 8976 8977static XrResult D3D12_INTERNAL_GetXrGraphicsRequirements(XrInstance instance, XrSystemId systemId, D3D_FEATURE_LEVEL *minimumFeatureLevel, LUID *adapter) 8978{ 8979 XrResult xrResult; 8980 8981 PFN_xrGetD3D12GraphicsRequirementsKHR xrGetD3D12GraphicsRequirementsKHR; 8982 if ((xrResult = xrGetInstanceProcAddr(instance, "xrGetD3D12GraphicsRequirementsKHR", (PFN_xrVoidFunction *)&xrGetD3D12GraphicsRequirementsKHR)) != XR_SUCCESS) { 8983 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get xrGetD3D12GraphicsRequirementsKHR"); 8984 return xrResult; 8985 } 8986 8987 XrGraphicsRequirementsD3D12KHR graphicsRequirementsD3D12 = { XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR }; 8988 if ((xrResult = xrGetD3D12GraphicsRequirementsKHR(instance, systemId, &graphicsRequirementsD3D12)) != XR_SUCCESS) { 8989 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to get D3D12 graphics requirements, got OpenXR error %d", xrResult); 8990 return xrResult; 8991 } 8992 8993 *adapter = graphicsRequirementsD3D12.adapterLuid; 8994 *minimumFeatureLevel = graphicsRequirementsD3D12.minFeatureLevel; 8995 return XR_SUCCESS; 8996} 8997 8998static bool D3D12_INTERNAL_GetAdapterByLuid(LUID luid, IDXGIFactory1 *factory, IDXGIAdapter1 **outAdapter) 8999{ 9000 HRESULT res; 9001 9002 // We need to iterate over all the adapters in the system to find the one with the matching LUID 9003 for (Uint32 adapterIndex = 0;; adapterIndex++) { 9004 // EnumAdapters1 will fail with DXGI_ERROR_NOT_FOUND when there are no more adapters to enumerate. 9005 IDXGIAdapter1 *adapter; 9006 res = IDXGIFactory1_EnumAdapters1(factory, adapterIndex, &adapter); 9007 if (FAILED(res)) { 9008 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get an adapter when iterating, i: %d, res: %ld", adapterIndex, res); 9009 return false; 9010 } 9011 9012 DXGI_ADAPTER_DESC1 adapterDesc; 9013 res = IDXGIAdapter1_GetDesc1(adapter, &adapterDesc); 9014 if (FAILED(res)) { 9015 IDXGIAdapter1_Release(adapter); 9016 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get description of adapter, i: %d, res %ld", adapterIndex, res); 9017 return false; 9018 } 9019 if (SDL_memcmp(&adapterDesc.AdapterLuid, &luid, sizeof(luid)) == 0) { 9020 *outAdapter = adapter; 9021 return true; 9022 } 9023 IDXGIAdapter1_Release(adapter); 9024 } 9025} 9026 9027static bool D3D12_INTERNAL_FindXRSrgbSwapchain( 9028 int64_t *supportedFormats, 9029 Uint32 supportedFormatsCount, 9030 SDL_GPUTextureFormat *sdlFormat, 9031 DXGI_FORMAT *dxgiFormat) 9032{ 9033 for (Uint32 i = 0; i < SDL_arraysize(SDLToD3D12_TextureFormat_SrgbOnly); i++) { 9034 for (Uint32 j = 0; j < supportedFormatsCount; j++) { 9035 if (SDLToD3D12_TextureFormat_SrgbOnly[i].dxgi == supportedFormats[j]) { 9036 *sdlFormat = SDLToD3D12_TextureFormat_SrgbOnly[i].sdl; 9037 *dxgiFormat = SDLToD3D12_TextureFormat_SrgbOnly[i].dxgi; 9038 return true; 9039 } 9040 } 9041 } 9042 return false; 9043} 9044#endif /* HAVE_GPU_OPENXR */ 9045 9046static XrResult D3D12_DestroyXRSwapchain( 9047 SDL_GPURenderer *driverData, 9048 XrSwapchain swapchain, 9049 SDL_GPUTexture **swapchainImages) 9050{ 9051#ifdef HAVE_GPU_OPENXR 9052 XrResult result; 9053 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 9054 9055 D3D12_Wait(driverData); 9056 9057 Uint32 swapchainCount; 9058 result = renderer->xr->xrEnumerateSwapchainImages(swapchain, 0, &swapchainCount, NULL); 9059 if (result != XR_SUCCESS) { 9060 return result; 9061 } 9062 9063 // We always want to destroy the swapchain images, so don't early return if xrDestroySwapchain fails for some reason 9064 for (Uint32 i = 0; i < swapchainCount; i++) { 9065 D3D12Texture *container = (D3D12Texture *)swapchainImages[i]; 9066 9067 if (!container->externallyManaged) { 9068 SDL_SetError("Invalid GPU Texture handle."); 9069 return XR_ERROR_HANDLE_INVALID; 9070 } 9071 9072 D3D12_INTERNAL_DestroyTexture(container); 9073 9074 // Free the container now that it's unused 9075 SDL_free(container); 9076 } 9077 9078 SDL_free(swapchainImages); 9079 9080 return renderer->xr->xrDestroySwapchain(swapchain); 9081#else 9082 (void)driverData; 9083 (void)swapchain; 9084 (void)swapchainImages; 9085 SDL_SetError("SDL not built with OpenXR support"); 9086 return XR_ERROR_FUNCTION_UNSUPPORTED; 9087#endif 9088} 9089 9090static SDL_GPUTextureFormat* D3D12_GetXRSwapchainFormats( 9091 SDL_GPURenderer *driverData, 9092 XrSession session, 9093 int *num_formats) 9094{ 9095#ifdef HAVE_GPU_OPENXR 9096 XrResult result; 9097 Uint32 i, j, num_supported_formats; 9098 int64_t *supported_formats; 9099 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 9100 9101 result = renderer->xr->xrEnumerateSwapchainFormats(session, 0, &num_supported_formats, NULL); 9102 if (result != XR_SUCCESS) { 9103 return NULL; 9104 } 9105 9106 supported_formats = SDL_stack_alloc(int64_t, num_supported_formats); 9107 result = renderer->xr->xrEnumerateSwapchainFormats(session, num_supported_formats, &num_supported_formats, supported_formats); 9108 if (result != XR_SUCCESS) { 9109 SDL_stack_free(supported_formats); 9110 return NULL; 9111 } 9112 9113 // FIXME: For now we're just searching for the optimal format, not all supported formats. 9114 // FIXME: Expand this search for all SDL_GPU formats! 9115 9116 SDL_GPUTextureFormat sdlFormat = SDL_GPU_TEXTUREFORMAT_INVALID; 9117 DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN; 9118 // The OpenXR spec recommends applications not submit linear data, so let's try to explicitly find an sRGB swapchain before we search the whole list 9119 if (!D3D12_INTERNAL_FindXRSrgbSwapchain(supported_formats, num_supported_formats, &sdlFormat, &dxgiFormat)) { 9120 // Iterate over all formats the runtime supports 9121 for (i = 0; i < num_supported_formats && dxgiFormat == DXGI_FORMAT_UNKNOWN; i++) { 9122 // Iterate over all formats we support 9123 for (j = 0; j < SDL_arraysize(SDLToD3D12_TextureFormat); j++) { 9124 // Pick the first format the runtime wants that we also support, the runtime should return these in order of preference 9125 if (SDLToD3D12_TextureFormat[j] == supported_formats[i]) { 9126 dxgiFormat = (DXGI_FORMAT)supported_formats[i]; 9127 sdlFormat = j; 9128 break; 9129 } 9130 } 9131 } 9132 } 9133 9134 SDL_stack_free(supported_formats); 9135 9136 if (dxgiFormat == DXGI_FORMAT_UNKNOWN) { 9137 SDL_SetError("Failed to find a swapchain format supported by both OpenXR and SDL"); 9138 return NULL; 9139 } 9140 9141 SDL_GPUTextureFormat *retval = (SDL_GPUTextureFormat*) SDL_malloc(sizeof(SDL_GPUTextureFormat) * 2); 9142 retval[0] = sdlFormat; 9143 retval[1] = SDL_GPU_TEXTUREFORMAT_INVALID; 9144 *num_formats = 1; 9145 return retval; 9146#else 9147 SDL_SetError("SDL not built with OpenXR support"); 9148 return NULL; 9149#endif 9150} 9151 9152static XrResult D3D12_CreateXRSwapchain( 9153 SDL_GPURenderer *driverData, 9154 XrSession session, 9155 const XrSwapchainCreateInfo *oldCreateInfo, 9156 SDL_GPUTextureFormat format, 9157 XrSwapchain *swapchain, 9158 SDL_GPUTexture ***textures) 9159{ 9160#ifdef HAVE_GPU_OPENXR 9161 XrResult result; 9162 Uint32 layerIndex, levelIndex; 9163 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 9164 9165 XrSwapchainCreateInfo createInfo = *oldCreateInfo; 9166 createInfo.format = SDLToD3D12_TextureFormat[format]; 9167 9168 result = renderer->xr->xrCreateSwapchain(session, &createInfo, swapchain); 9169 if (result != XR_SUCCESS) { 9170 return result; 9171 } 9172 9173 Uint32 swapchainImageCount; 9174 result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, 0, &swapchainImageCount, NULL); 9175 if (result != XR_SUCCESS) { 9176 return result; 9177 } 9178 9179 XrSwapchainImageD3D12KHR *swapchainImages = (XrSwapchainImageD3D12KHR *)SDL_calloc(swapchainImageCount, sizeof(XrSwapchainImageD3D12KHR)); 9180 for (layerIndex = 0; layerIndex < swapchainImageCount; layerIndex++) { 9181 swapchainImages[layerIndex].type = XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR; 9182 } 9183 9184 result = renderer->xr->xrEnumerateSwapchainImages(*swapchain, swapchainImageCount, &swapchainImageCount, (XrSwapchainImageBaseHeader *)swapchainImages); 9185 if (result != XR_SUCCESS) { 9186 SDL_free(swapchainImages); 9187 return result; 9188 } 9189 9190 D3D12TextureContainer **textureContainers = (D3D12TextureContainer **)SDL_calloc(swapchainImageCount, sizeof(D3D12TextureContainer *)); 9191 9192 Uint32 depth = 1; 9193 9194 for (Uint32 idx = 0; idx < swapchainImageCount; idx++) { 9195 ID3D12Resource *d3d12Texture = swapchainImages[idx].texture; 9196 9197 D3D12Texture *texture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture)); 9198 9199 texture->resource = d3d12Texture; 9200 texture->externallyManaged = true; 9201 SDL_SetAtomicInt(&texture->referenceCount, 0); 9202 9203 texture->subresourceCount = createInfo.arraySize * createInfo.mipCount; 9204 texture->subresources = (D3D12TextureSubresource *)SDL_calloc( 9205 texture->subresourceCount, 9206 sizeof(D3D12TextureSubresource)); 9207 9208 for (layerIndex = 0; layerIndex < createInfo.arraySize; layerIndex += 1) { 9209 for (levelIndex = 0; levelIndex < createInfo.mipCount; levelIndex += 1) { 9210 Uint32 subresourceIndex = D3D12_INTERNAL_CalcSubresource( 9211 levelIndex, 9212 layerIndex, 9213 createInfo.mipCount); 9214 9215 texture->subresources[subresourceIndex].parent = texture; 9216 texture->subresources[subresourceIndex].layer = layerIndex; 9217 texture->subresources[subresourceIndex].level = levelIndex; 9218 texture->subresources[subresourceIndex].depth = depth; 9219 texture->subresources[subresourceIndex].index = subresourceIndex; 9220 9221 texture->subresources[subresourceIndex].rtvHandles = NULL; 9222 texture->subresources[subresourceIndex].uavHandle.heap = NULL; 9223 texture->subresources[subresourceIndex].dsvHandle.heap = NULL; 9224 9225 if (createInfo.usageFlags & XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT) { 9226 texture->subresources[subresourceIndex].rtvHandles = (D3D12StagingDescriptor *)SDL_calloc(depth, sizeof(D3D12StagingDescriptor)); 9227 9228 for (Uint32 depthIndex = 0; depthIndex < depth; depthIndex += 1) { 9229 D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; 9230 9231 D3D12_INTERNAL_AssignStagingDescriptorHandle( 9232 renderer, 9233 D3D12_DESCRIPTOR_HEAP_TYPE_RTV, 9234 &texture->subresources[subresourceIndex].rtvHandles[depthIndex]); 9235 9236 rtvDesc.Format = SDLToD3D12_TextureFormat[format]; 9237 9238 // For XR we typically use 2D array textures for stereo rendering 9239 if (createInfo.arraySize > 1) { 9240 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; 9241 rtvDesc.Texture2DArray.MipSlice = levelIndex; 9242 rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; 9243 rtvDesc.Texture2DArray.ArraySize = 1; 9244 rtvDesc.Texture2DArray.PlaneSlice = 0; 9245 } else { 9246 rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; 9247 rtvDesc.Texture2D.MipSlice = levelIndex; 9248 rtvDesc.Texture2D.PlaneSlice = 0; 9249 } 9250 9251 ID3D12Device_CreateRenderTargetView( 9252 renderer->device, 9253 texture->resource, 9254 &rtvDesc, 9255 texture->subresources[subresourceIndex].rtvHandles[depthIndex].cpuHandle); 9256 } 9257 } 9258 } 9259 } 9260 9261 textureContainers[idx] = (D3D12TextureContainer *)SDL_malloc(sizeof(D3D12TextureContainer)); 9262 D3D12TextureContainer *container = textureContainers[idx]; 9263 SDL_zero(container->header.info); 9264 container->header.info.width = createInfo.width; 9265 container->header.info.height = createInfo.height; 9266 container->header.info.format = format; 9267 container->header.info.layer_count_or_depth = createInfo.arraySize; 9268 container->header.info.num_levels = createInfo.mipCount; 9269 container->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1; 9270 container->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; 9271 9272 container->externallyManaged = true; 9273 container->canBeCycled = false; 9274 container->activeTexture = texture; 9275 container->textureCapacity = 1; 9276 container->textureCount = 1; 9277 container->textures = (D3D12Texture **)SDL_malloc( 9278 container->textureCapacity * sizeof(D3D12Texture *)); 9279 container->textures[0] = container->activeTexture; 9280 container->debugName = NULL; 9281 9282 texture->container = container; 9283 texture->containerIndex = 0; 9284 } 9285 9286 *textures = (SDL_GPUTexture **)textureContainers; 9287 9288 SDL_free(swapchainImages); 9289 9290 return XR_SUCCESS; 9291#else 9292 (void)driverData; 9293 (void)session; 9294 (void)oldCreateInfo; 9295 (void)format; 9296 (void)swapchain; 9297 (void)textures; 9298 SDL_SetError("SDL not built with OpenXR support"); 9299 return XR_ERROR_FUNCTION_UNSUPPORTED; 9300#endif 9301} 9302 9303static XrResult D3D12_CreateXRSession( 9304 SDL_GPURenderer *driverData, 9305 const XrSessionCreateInfo *createinfo, 9306 XrSession *session) 9307{ 9308#ifdef HAVE_GPU_OPENXR 9309 D3D12Renderer *renderer = (D3D12Renderer *)driverData; 9310 9311 // Copy out the existing next ptr so that we can append it to the end of the chain we create 9312 const void *XR_MAY_ALIAS currentNextPtr = createinfo->next; 9313 9314 XrGraphicsBindingD3D12KHR graphicsBinding = { XR_TYPE_GRAPHICS_BINDING_D3D12_KHR }; 9315 graphicsBinding.device = renderer->device; 9316 graphicsBinding.queue = renderer->commandQueue; 9317 graphicsBinding.next = currentNextPtr; 9318 9319 XrSessionCreateInfo sessionCreateInfo = *createinfo; 9320 sessionCreateInfo.systemId = renderer->xrSystemId; 9321 sessionCreateInfo.next = &graphicsBinding; 9322 9323 return renderer->xr->xrCreateSession(renderer->xrInstance, &sessionCreateInfo, session); 9324#else 9325 (void)driverData; 9326 (void)createinfo; 9327 (void)session; 9328 SDL_SetError("SDL not built with OpenXR support"); 9329 return XR_ERROR_FUNCTION_UNSUPPORTED; 9330#endif 9331} 9332 9333static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props) 9334{ 9335 SDL_GPUDevice *result; 9336 D3D12Renderer *renderer; 9337 HRESULT res; 9338 9339#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9340 PFN_D3D12_XBOX_CREATE_DEVICE D3D12XboxCreateDeviceFunc; 9341 D3D12XBOX_CREATE_DEVICE_PARAMETERS createDeviceParams; 9342#else 9343 pfnCreateDXGIFactory1 pCreateDXGIFactory1; 9344 IDXGIFactory1 *factory1; 9345 IDXGIFactory5 *factory5; 9346 IDXGIFactory6 *factory6; 9347 DXGI_ADAPTER_DESC1 adapterDesc; 9348 LARGE_INTEGER umdVersion; 9349 PFN_D3D12_GET_INTERFACE pD3D12GetInterface; 9350 PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice; 9351#endif 9352 D3D12_FEATURE_DATA_ARCHITECTURE architecture; 9353 D3D12_COMMAND_QUEUE_DESC queueDesc; 9354 9355 bool verboseLogs = SDL_GetBooleanProperty( 9356 props, 9357 SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN, 9358 true); 9359 9360 renderer = (D3D12Renderer *)SDL_calloc(1, sizeof(D3D12Renderer)); 9361 9362 bool hasDxgiDebug = false; 9363#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9364 // Load the DXGI library 9365 renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL); 9366 if (renderer->dxgi_dll == NULL) { 9367 D3D12_INTERNAL_DestroyRenderer(renderer); 9368 SET_STRING_ERROR_AND_RETURN("Could not find " DXGI_DLL, NULL); 9369 } 9370 9371#ifdef HAVE_IDXGIINFOQUEUE 9372 // Initialize the DXGI debug layer, if applicable 9373 if (debugMode) { 9374 hasDxgiDebug = D3D12_INTERNAL_TryInitializeDXGIDebug(renderer); 9375 } 9376#else 9377 hasDxgiDebug = true; 9378#endif 9379 9380#ifdef USE_PIX_RUNTIME 9381 // Load the PIX runtime DLL so that we can set D3D12 debug events on command lists 9382 renderer->winpixeventruntime_dll = SDL_LoadObject(WINPIXEVENTRUNTIME_DLL); 9383 WinPixEventRuntimeFns *fns = &renderer->winpixeventruntimeFns; 9384 if (renderer->winpixeventruntime_dll) { 9385 // Load the specific functions we need from the PIX runtime 9386 fns->pBeginEventOnCommandList = (pfnBeginEventOnCommandList)SDL_LoadFunction( 9387 renderer->winpixeventruntime_dll, 9388 PIX_BEGIN_EVENT_ON_COMMAND_LIST_FUNC); 9389 fns->pEndEventOnCommandList = (pfnEndEventOnCommandList)SDL_LoadFunction( 9390 renderer->winpixeventruntime_dll, 9391 PIX_END_EVENT_ON_COMMAND_LIST_FUNC); 9392 fns->pSetMarkerOnCommandList = (pfnSetMarkerOnCommandList)SDL_LoadFunction( 9393 renderer->winpixeventruntime_dll, 9394 PIX_SET_MARKER_ON_COMMAND_LIST_FUNC); 9395 } else { 9396 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, 9397 "WinPixEventRuntime.dll is not available. " 9398 "It is required for SDL_Push/PopGPUDebugGroup and SDL_InsertGPUDebugLabel to function correctly. " 9399 "See here for instructions on how to obtain it: https://devblogs.microsoft.com/pix/winpixeventruntime/"); 9400 fns->pBeginEventOnCommandList = NULL; 9401 fns->pEndEventOnCommandList = NULL; 9402 fns->pSetMarkerOnCommandList = NULL; 9403 } 9404#endif 9405 9406 // Load the CreateDXGIFactory1 function 9407 pCreateDXGIFactory1 = (pfnCreateDXGIFactory1)SDL_LoadFunction( 9408 renderer->dxgi_dll, 9409 CREATE_DXGI_FACTORY1_FUNC); 9410 if (pCreateDXGIFactory1 == NULL) { 9411 D3D12_INTERNAL_DestroyRenderer(renderer); 9412 SET_STRING_ERROR_AND_RETURN("Could not load function: " CREATE_DXGI_FACTORY1_FUNC, NULL); 9413 } 9414 9415 // Create the DXGI factory 9416 res = pCreateDXGIFactory1( 9417 &D3D_IID_IDXGIFactory1, 9418 (void **)&factory1); 9419 if (FAILED(res)) { 9420 D3D12_INTERNAL_DestroyRenderer(renderer); 9421 CHECK_D3D12_ERROR_AND_RETURN("Could not create DXGIFactory", NULL); 9422 } 9423 9424 // Check for DXGI 1.4 support 9425 res = IDXGIFactory1_QueryInterface( 9426 factory1, 9427 D3D_GUID(D3D_IID_IDXGIFactory4), 9428 (void **)&renderer->factory); 9429 if (FAILED(res)) { 9430 D3D12_INTERNAL_DestroyRenderer(renderer); 9431 CHECK_D3D12_ERROR_AND_RETURN("DXGI1.4 support not found, required for DX12", NULL); 9432 } 9433 IDXGIFactory1_Release(factory1); 9434 9435 // Check for explicit tearing support 9436 res = IDXGIFactory4_QueryInterface( 9437 renderer->factory, 9438 D3D_GUID(D3D_IID_IDXGIFactory5), 9439 (void **)&factory5); 9440 if (SUCCEEDED(res)) { 9441 res = IDXGIFactory5_CheckFeatureSupport( 9442 factory5, 9443 DXGI_FEATURE_PRESENT_ALLOW_TEARING, 9444 &renderer->supportsTearing, 9445 sizeof(renderer->supportsTearing)); 9446 if (FAILED(res)) { 9447 renderer->supportsTearing = false; 9448 } 9449 IDXGIFactory5_Release(factory5); 9450 } 9451 9452#ifdef HAVE_GPU_OPENXR 9453 bool xr = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_ENABLE_BOOLEAN, false); 9454 XrInstance *xrInstance = (XrInstance *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_INSTANCE_POINTER, NULL); 9455 XrSystemId *xrSystemId = (XrSystemId *)SDL_GetPointerProperty(props, SDL_PROP_GPU_DEVICE_CREATE_XR_SYSTEM_ID_POINTER, NULL); 9456 D3D_FEATURE_LEVEL featureLevel = D3D_FEATURE_LEVEL_11_0; 9457 9458 if (xr) { 9459 XrExtensionProperties gpuExtension; 9460 9461 if (!xrInstance) { 9462 D3D12_INTERNAL_DestroyRenderer(renderer); 9463 SET_STRING_ERROR_AND_RETURN("You must specify an out pointer for the OpenXR instance", NULL); 9464 } 9465 9466 if (!xrSystemId) { 9467 D3D12_INTERNAL_DestroyRenderer(renderer); 9468 SET_STRING_ERROR_AND_RETURN("You must specify an out pointer for the OpenXR system ID", NULL); 9469 } 9470 9471 if (!SDL_OpenXR_LoadLibrary()) { 9472 D3D12_INTERNAL_DestroyRenderer(renderer); 9473 SET_STRING_ERROR_AND_RETURN("This should have failed in PrepareDevice first!", NULL); 9474 } 9475 9476 if (!D3D12_INTERNAL_SearchForOpenXrGpuExtension(&gpuExtension)) { 9477 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to find a compatible OpenXR D3D12 extension"); 9478 SDL_OpenXR_UnloadLibrary(); 9479 D3D12_INTERNAL_DestroyRenderer(renderer); 9480 SET_STRING_ERROR_AND_RETURN("Failed to find XR_KHR_D3D12_enable extension", NULL); 9481 } 9482 9483 if (!SDL_OPENXR_INTERNAL_GPUInitOpenXR(debugMode, gpuExtension, props, xrInstance, xrSystemId, &renderer->xr)) { 9484 SDL_LogDebug(SDL_LOG_CATEGORY_GPU, "Failed to init OpenXR"); 9485 SDL_OpenXR_UnloadLibrary(); 9486 D3D12_INTERNAL_DestroyRenderer(renderer); 9487 SET_STRING_ERROR_AND_RETURN("Failed to initialize OpenXR", NULL); 9488 } 9489 9490 renderer->xrInstance = *xrInstance; 9491 renderer->xrSystemId = *xrSystemId; 9492 9493 LUID xrAdapter; 9494 9495 if (D3D12_INTERNAL_GetXrGraphicsRequirements(*xrInstance, *xrSystemId, &featureLevel, &xrAdapter) != XR_SUCCESS) { 9496 SDL_OpenXR_UnloadLibrary(); 9497 D3D12_INTERNAL_DestroyRenderer(renderer); 9498 SET_STRING_ERROR_AND_RETURN("Failed to get XR graphics requirements", NULL); 9499 } 9500 9501 // Need factory1 again for adapter enumeration 9502 IDXGIFactory1 *factory1ForXr; 9503 res = pCreateDXGIFactory1( 9504 &D3D_IID_IDXGIFactory1, 9505 (void **)&factory1ForXr); 9506 if (FAILED(res)) { 9507 SDL_OpenXR_UnloadLibrary(); 9508 D3D12_INTERNAL_DestroyRenderer(renderer); 9509 CHECK_D3D12_ERROR_AND_RETURN("Could not create DXGIFactory for XR adapter lookup", NULL); 9510 } 9511 9512 if (!D3D12_INTERNAL_GetAdapterByLuid(xrAdapter, factory1ForXr, &renderer->adapter)) { 9513 IDXGIFactory1_Release(factory1ForXr); 9514 SDL_OpenXR_UnloadLibrary(); 9515 D3D12_INTERNAL_DestroyRenderer(renderer); 9516 SET_STRING_ERROR_AND_RETURN("Failed to find adapter matching XR LUID", NULL); 9517 } 9518 IDXGIFactory1_Release(factory1ForXr); 9519 } else 9520#endif /* HAVE_GPU_OPENXR */ 9521 { 9522 // Select the appropriate device for rendering 9523 res = IDXGIFactory4_QueryInterface( 9524 renderer->factory, 9525 D3D_GUID(D3D_IID_IDXGIFactory6), 9526 (void **)&factory6); 9527 if (SUCCEEDED(res)) { 9528 res = IDXGIFactory6_EnumAdapterByGpuPreference( 9529 factory6, 9530 0, 9531 preferLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, 9532 D3D_GUID(D3D_IID_IDXGIAdapter1), 9533 (void **)&renderer->adapter); 9534 IDXGIFactory6_Release(factory6); 9535 } else { 9536 res = IDXGIFactory4_EnumAdapters1( 9537 renderer->factory, 9538 0, 9539 &renderer->adapter); 9540 } 9541 9542 if (FAILED(res)) { 9543 D3D12_INTERNAL_DestroyRenderer(renderer); 9544 CHECK_D3D12_ERROR_AND_RETURN("Could not find adapter for D3D12Device", NULL); 9545 } 9546 } 9547 9548 // Get information about the selected adapter. Used for logging info. 9549 res = IDXGIAdapter1_GetDesc1(renderer->adapter, &adapterDesc); 9550 if (FAILED(res)) { 9551 D3D12_INTERNAL_DestroyRenderer(renderer); 9552 CHECK_D3D12_ERROR_AND_RETURN("Could not get adapter description", NULL); 9553 } 9554 res = IDXGIAdapter1_CheckInterfaceSupport(renderer->adapter, D3D_GUID(D3D_IID_IDXGIDevice), &umdVersion); 9555 if (FAILED(res)) { 9556 D3D12_INTERNAL_DestroyRenderer(renderer); 9557 CHECK_D3D12_ERROR_AND_RETURN("Could not get adapter driver version", NULL); 9558 } 9559 9560 renderer->props = SDL_CreateProperties(); 9561 if (verboseLogs) { 9562 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: D3D12"); 9563 } 9564 9565 // Record device name 9566 char *deviceName = SDL_iconv_wchar_utf8(&adapterDesc.Description[0]); 9567 SDL_SetStringProperty( 9568 renderer->props, 9569 SDL_PROP_GPU_DEVICE_NAME_STRING, 9570 deviceName); 9571 if (verboseLogs) { 9572 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Adapter: %s", deviceName); 9573 } 9574 SDL_free(deviceName); 9575 9576 // Record driver version 9577 char driverVer[64]; 9578 (void)SDL_snprintf( 9579 driverVer, 9580 SDL_arraysize(driverVer), 9581 "%d.%d.%d.%d", 9582 HIWORD(umdVersion.HighPart), 9583 LOWORD(umdVersion.HighPart), 9584 HIWORD(umdVersion.LowPart), 9585 LOWORD(umdVersion.LowPart)); 9586 SDL_SetStringProperty( 9587 renderer->props, 9588 SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING, 9589 driverVer); 9590 if (verboseLogs) { 9591 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Driver: %s", driverVer); 9592 } 9593#endif 9594 9595 // Load the D3D library 9596 renderer->d3d12_dll = SDL_LoadObject(D3D12_DLL); 9597 if (renderer->d3d12_dll == NULL) { 9598 D3D12_INTERNAL_DestroyRenderer(renderer); 9599 SET_STRING_ERROR_AND_RETURN("Could not find " D3D12_DLL, NULL); 9600 } 9601 9602 // Load the CreateDevice function 9603#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9604 D3D12XboxCreateDeviceFunc = (PFN_D3D12_XBOX_CREATE_DEVICE)SDL_LoadFunction( 9605 renderer->d3d12_dll, 9606 "D3D12XboxCreateDevice"); 9607 if (D3D12XboxCreateDeviceFunc == NULL) { 9608 D3D12_INTERNAL_DestroyRenderer(renderer); 9609 SET_STRING_ERROR_AND_RETURN("Could not load function: D3D12XboxCreateDevice", NULL); 9610 } 9611#else 9612 pD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction( 9613 renderer->d3d12_dll, 9614 D3D12_CREATE_DEVICE_FUNC); 9615 if (pD3D12CreateDevice == NULL) { 9616 D3D12_INTERNAL_DestroyRenderer(renderer); 9617 SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_CREATE_DEVICE_FUNC, NULL); 9618 } 9619#endif 9620 9621 renderer->pD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)SDL_LoadFunction( 9622 renderer->d3d12_dll, 9623 D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC); 9624 if (renderer->pD3D12SerializeRootSignature == NULL) { 9625 D3D12_INTERNAL_DestroyRenderer(renderer); 9626 SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC, NULL); 9627 } 9628 9629#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9630 // A device factory allows a D3D12 redistributable provided by the client to be loaded. 9631 ID3D12DeviceFactory *factory = NULL; 9632 9633 if (SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING) && SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER)) { 9634 int d3d12SDKVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER, 0); 9635 const char *d3d12SDKPath = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING, ".\\D3D12\\"); 9636 9637 pD3D12GetInterface = (PFN_D3D12_GET_INTERFACE)SDL_LoadFunction( 9638 renderer->d3d12_dll, 9639 D3D12_GET_INTERFACE_FUNC); 9640 if (pD3D12GetInterface == NULL) { 9641 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Could not load D3D12GetInterface, custom D3D12 SDK will not load."); 9642 } 9643 9644 ID3D12SDKConfiguration *sdk_config = NULL; 9645 9646 if (SUCCEEDED(pD3D12GetInterface(D3D_GUID(D3D_CLSID_ID3D12SDKConfiguration), D3D_GUID(D3D_IID_ID3D12SDKConfiguration), (void**) &sdk_config))) { 9647 ID3D12SDKConfiguration1 *sdk_config1 = NULL; 9648 if (SUCCEEDED(IUnknown_QueryInterface(sdk_config, &D3D_IID_ID3D12SDKConfiguration1, (void**) &sdk_config1))) { 9649 if (SUCCEEDED(ID3D12SDKConfiguration1_CreateDeviceFactory(sdk_config1, d3d12SDKVersion, d3d12SDKPath, &D3D_IID_ID3D12DeviceFactory, (void**) &factory))) { 9650 SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Loaded vendored D3D12Core.dll"); 9651 } else { 9652 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to load vendored D3D12Core.dll"); 9653 } 9654 9655 ID3D12SDKConfiguration1_Release(sdk_config1); 9656 } 9657 9658 ID3D12SDKConfiguration_Release(sdk_config); 9659 } else { 9660 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to load vendored D3D12 SDK Configuration"); 9661 } 9662 } 9663#endif 9664 9665 // Initialize the D3D12 debug layer, if applicable 9666 if (debugMode) { 9667 bool hasD3d12Debug = D3D12_INTERNAL_TryInitializeD3D12Debug(renderer 9668#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9669 , factory 9670#endif 9671 ); 9672#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9673 if (hasD3d12Debug) { 9674 SDL_LogInfo( 9675 SDL_LOG_CATEGORY_GPU, 9676 "Validation layers enabled, expect debug level performance!"); 9677#else 9678 if (hasDxgiDebug && hasD3d12Debug) { 9679 SDL_LogInfo( 9680 SDL_LOG_CATEGORY_GPU, 9681 "Validation layers enabled, expect debug level performance!"); 9682 } else if (hasDxgiDebug || hasD3d12Debug) { 9683 SDL_LogWarn( 9684 SDL_LOG_CATEGORY_GPU, 9685 "Validation layers partially enabled, some warnings may not be available"); 9686#endif 9687 } else { 9688 SDL_LogWarn( 9689 SDL_LOG_CATEGORY_GPU, 9690 "Validation layers not found, continuing without validation"); 9691 } 9692 } 9693 9694 // Create the D3D12Device 9695#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9696 if (s_Device != NULL) { 9697 renderer->device = s_Device; 9698 } else { 9699 SDL_zero(createDeviceParams); 9700 createDeviceParams.Version = D3D12_SDK_VERSION; 9701 createDeviceParams.GraphicsCommandQueueRingSizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES; 9702 createDeviceParams.GraphicsScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES; 9703 createDeviceParams.ComputeScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES; 9704 createDeviceParams.DisableGeometryShaderAllocations = TRUE; 9705 createDeviceParams.DisableTessellationShaderAllocations = TRUE; 9706#if defined(SDL_PLATFORM_XBOXSERIES) 9707 createDeviceParams.DisableDXR = TRUE; 9708#endif 9709 if (debugMode) { 9710 createDeviceParams.ProcessDebugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_DEBUG; 9711 } 9712 9713 res = D3D12XboxCreateDeviceFunc( 9714 NULL, 9715 &createDeviceParams, 9716 IID_GRAPHICS_PPV_ARGS(&renderer->device)); 9717 if (FAILED(res)) { 9718 D3D12_INTERNAL_DestroyRenderer(renderer); 9719 CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL); 9720 } 9721 9722 s_Device = renderer->device; 9723 } 9724#else 9725 9726 if (factory) { 9727 ID3D12DeviceFactory_SetFlags(factory, D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_EXISTING_DEVICE); 9728 res = ID3D12DeviceFactory_CreateDevice( 9729 factory, 9730 (IUnknown *)renderer->adapter, 9731 D3D_FEATURE_LEVEL_CHOICE, 9732 D3D_GUID(D3D_IID_ID3D12Device), 9733 (void**)&renderer->device); 9734 9735 ID3D12DeviceFactory_Release(factory); 9736 9737 if (FAILED(res)) { 9738 D3D12_INTERNAL_DestroyRenderer(renderer); 9739 CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL); 9740 } 9741 } else { 9742 res = pD3D12CreateDevice( 9743 (IUnknown *)renderer->adapter, 9744 D3D_FEATURE_LEVEL_CHOICE, 9745 D3D_GUID(D3D_IID_ID3D12Device), 9746 (void **)&renderer->device); 9747 9748 if (FAILED(res)) { 9749 D3D12_INTERNAL_DestroyRenderer(renderer); 9750 CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL); 9751 } 9752 } 9753 9754 // Initialize the D3D12 debug info queue, if applicable 9755 if (debugMode) { 9756 D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(renderer); 9757 D3D12_INTERNAL_TryInitializeD3D12DebugInfoLogger(renderer); 9758 } 9759#endif 9760 9761 // Check UMA 9762 architecture.NodeIndex = 0; 9763 res = ID3D12Device_CheckFeatureSupport( 9764 renderer->device, 9765 D3D12_FEATURE_ARCHITECTURE, 9766 &architecture, 9767 sizeof(D3D12_FEATURE_DATA_ARCHITECTURE)); 9768 if (FAILED(res)) { 9769 D3D12_INTERNAL_DestroyRenderer(renderer); 9770 CHECK_D3D12_ERROR_AND_RETURN("Could not get device architecture", NULL); 9771 } 9772 9773 renderer->UMA = (bool)architecture.UMA; 9774 renderer->UMACacheCoherent = (bool)architecture.CacheCoherentUMA; 9775 9776#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9777 renderer->GPUUploadHeapSupported = false; 9778#else 9779 // Check "GPU Upload Heap" support (for fast uniform buffers) 9780 D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16; // 15 wasn't enough, huh? 9781 renderer->GPUUploadHeapSupported = false; 9782 res = ID3D12Device_CheckFeatureSupport( 9783 renderer->device, 9784 D3D12_FEATURE_D3D12_OPTIONS16, 9785 &options16, 9786 sizeof(options16)); 9787 9788 if (SUCCEEDED(res)) { 9789 renderer->GPUUploadHeapSupported = options16.GPUUploadHeapSupported; 9790 } 9791#endif 9792 9793 // Check for unrestricted texture-buffer copy pitch support 9794 D3D12_FEATURE_DATA_D3D12_OPTIONS13 options13; 9795 res = ID3D12Device_CheckFeatureSupport( 9796 renderer->device, 9797 D3D12_FEATURE_D3D12_OPTIONS13, 9798 &options13, 9799 sizeof(options13)); 9800 9801 if (SUCCEEDED(res)) { 9802 renderer->UnrestrictedBufferTextureCopyPitchSupported = options13.UnrestrictedBufferTextureCopyPitchSupported; 9803 } 9804 else 9805 { 9806 SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "CheckFeatureSupport for UnrestrictedBufferTextureCopyPitchSupported failed. You may need to provide a vendored D3D12Core.dll through the Agility SDK on older platforms."); 9807 } 9808 9809 // Create command queue 9810#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9811 if (s_CommandQueue != NULL) { 9812 renderer->commandQueue = s_CommandQueue; 9813 } else { 9814#endif 9815 queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; 9816 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 9817 queueDesc.NodeMask = 0; 9818 queueDesc.Priority = 0; 9819 9820 res = ID3D12Device_CreateCommandQueue( 9821 renderer->device, 9822 &queueDesc, 9823 D3D_GUID(D3D_IID_ID3D12CommandQueue), 9824 (void **)&renderer->commandQueue); 9825 9826 if (FAILED(res)) { 9827 D3D12_INTERNAL_DestroyRenderer(renderer); 9828 CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12CommandQueue", NULL); 9829 } 9830#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 9831 s_CommandQueue = renderer->commandQueue; 9832 } 9833#endif 9834 9835 // Create indirect command signatures 9836 9837 D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc; 9838 D3D12_INDIRECT_ARGUMENT_DESC indirectArgumentDesc; 9839 SDL_zero(indirectArgumentDesc); 9840 9841 indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; 9842 commandSignatureDesc.NodeMask = 0; 9843 commandSignatureDesc.ByteStride = sizeof(SDL_GPUIndirectDrawCommand); 9844 commandSignatureDesc.NumArgumentDescs = 1; 9845 commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; 9846 9847 res = ID3D12Device_CreateCommandSignature( 9848 renderer->device, 9849 &commandSignatureDesc, 9850 NULL, 9851 D3D_GUID(D3D_IID_ID3D12CommandSignature), 9852 (void **)&renderer->indirectDrawCommandSignature); 9853 if (FAILED(res)) { 9854 D3D12_INTERNAL_DestroyRenderer(renderer); 9855 CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect draw command signature", NULL); 9856 } 9857 9858 indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; 9859 commandSignatureDesc.ByteStride = sizeof(SDL_GPUIndexedIndirectDrawCommand); 9860 commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; 9861 9862 res = ID3D12Device_CreateCommandSignature( 9863 renderer->device, 9864 &commandSignatureDesc, 9865 NULL, 9866 D3D_GUID(D3D_IID_ID3D12CommandSignature), 9867 (void **)&renderer->indirectIndexedDrawCommandSignature); 9868 if (FAILED(res)) { 9869 D3D12_INTERNAL_DestroyRenderer(renderer); 9870 CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect indexed draw command signature", NULL); 9871 } 9872 9873 indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; 9874 commandSignatureDesc.ByteStride = sizeof(SDL_GPUIndirectDispatchCommand); 9875 commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; 9876 9877 res = ID3D12Device_CreateCommandSignature( 9878 renderer->device, 9879 &commandSignatureDesc, 9880 NULL, 9881 D3D_GUID(D3D_IID_ID3D12CommandSignature), 9882 (void **)&renderer->indirectDispatchCommandSignature); 9883 if (FAILED(res)) { 9884 D3D12_INTERNAL_DestroyRenderer(renderer); 9885 CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect dispatch command signature", NULL); 9886 } 9887 9888 // Initialize pools 9889 9890 renderer->submittedCommandBufferCapacity = 4; 9891 renderer->submittedCommandBufferCount = 0; 9892 renderer->submittedCommandBuffers = (D3D12CommandBuffer **)SDL_calloc( 9893 renderer->submittedCommandBufferCapacity, sizeof(D3D12CommandBuffer *)); 9894 if (!renderer->submittedCommandBuffers) { 9895 D3D12_INTERNAL_DestroyRenderer(renderer); 9896 return NULL; 9897 } 9898 9899 renderer->uniformBufferPoolCapacity = 4; 9900 renderer->uniformBufferPoolCount = 0; 9901 renderer->uniformBufferPool = (D3D12UniformBuffer **)SDL_calloc( 9902 renderer->uniformBufferPoolCapacity, sizeof(D3D12UniformBuffer *)); 9903 if (!renderer->uniformBufferPool) { 9904 D3D12_INTERNAL_DestroyRenderer(renderer); 9905 return NULL; 9906 } 9907 9908 renderer->claimedWindowCapacity = 4; 9909 renderer->claimedWindowCount = 0; 9910 renderer->claimedWindows = (D3D12WindowData **)SDL_calloc( 9911 renderer->claimedWindowCapacity, sizeof(D3D12WindowData *)); 9912 if (!renderer->claimedWindows) { 9913 D3D12_INTERNAL_DestroyRenderer(renderer); 9914 return NULL; 9915 } 9916 9917 renderer->availableFenceCapacity = 4; 9918 renderer->availableFenceCount = 0; 9919 renderer->availableFences = (D3D12Fence **)SDL_calloc( 9920 renderer->availableFenceCapacity, sizeof(D3D12Fence *)); 9921 if (!renderer->availableFences) { 9922 D3D12_INTERNAL_DestroyRenderer(renderer); 9923 return NULL; 9924 } 9925 9926 // Initialize staging descriptor pools 9927 for (Uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { 9928 renderer->stagingDescriptorPools[i] = D3D12_INTERNAL_CreateStagingDescriptorPool( 9929 renderer, 9930 (D3D12_DESCRIPTOR_HEAP_TYPE)i); 9931 9932 if (renderer->stagingDescriptorPools[i] == NULL) { 9933 D3D12_INTERNAL_DestroyRenderer(renderer); 9934 return NULL; 9935 } 9936 } 9937 9938 // Initialize GPU descriptor heaps 9939 for (Uint32 i = 0; i < 2; i += 1) { 9940 renderer->gpuDescriptorHeapPools[i].lock = SDL_CreateMutex(); 9941 renderer->gpuDescriptorHeapPools[i].capacity = 4; 9942 renderer->gpuDescriptorHeapPools[i].count = 4; 9943 renderer->gpuDescriptorHeapPools[i].heaps = (D3D12DescriptorHeap **)SDL_calloc( 9944 renderer->gpuDescriptorHeapPools[i].capacity, sizeof(D3D12DescriptorHeap *)); 9945 9946 for (Uint32 j = 0; j < renderer->gpuDescriptorHeapPools[i].capacity; j += 1) { 9947 renderer->gpuDescriptorHeapPools[i].heaps[j] = D3D12_INTERNAL_CreateDescriptorHeap( 9948 renderer, 9949 (D3D12_DESCRIPTOR_HEAP_TYPE)i, 9950 i == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ? VIEW_GPU_DESCRIPTOR_COUNT : SAMPLER_GPU_DESCRIPTOR_COUNT, 9951 false); 9952 9953 if (renderer->gpuDescriptorHeapPools[i].heaps[j] == NULL) { 9954 D3D12_INTERNAL_DestroyRenderer(renderer); 9955 return NULL; 9956 } 9957 } 9958 } 9959 9960 // Deferred resource releasing 9961 9962 renderer->buffersToDestroyCapacity = 4; 9963 renderer->buffersToDestroyCount = 0; 9964 renderer->buffersToDestroy = (D3D12Buffer **)SDL_calloc( 9965 renderer->buffersToDestroyCapacity, sizeof(D3D12Buffer *)); 9966 if (!renderer->buffersToDestroy) { 9967 D3D12_INTERNAL_DestroyRenderer(renderer); 9968 return NULL; 9969 } 9970 9971 renderer->texturesToDestroyCapacity = 4; 9972 renderer->texturesToDestroyCount = 0; 9973 renderer->texturesToDestroy = (D3D12Texture **)SDL_calloc( 9974 renderer->texturesToDestroyCapacity, sizeof(D3D12Texture *)); 9975 if (!renderer->texturesToDestroy) { 9976 D3D12_INTERNAL_DestroyRenderer(renderer); 9977 return NULL; 9978 } 9979 9980 renderer->samplersToDestroyCapacity = 4; 9981 renderer->samplersToDestroyCount = 0; 9982 renderer->samplersToDestroy = (D3D12Sampler **)SDL_calloc( 9983 renderer->samplersToDestroyCapacity, sizeof(D3D12Sampler *)); 9984 if (!renderer->samplersToDestroy) { 9985 D3D12_INTERNAL_DestroyRenderer(renderer); 9986 return NULL; 9987 } 9988 9989 renderer->graphicsPipelinesToDestroyCapacity = 4; 9990 renderer->graphicsPipelinesToDestroyCount = 0; 9991 renderer->graphicsPipelinesToDestroy = (D3D12GraphicsPipeline **)SDL_calloc( 9992 renderer->graphicsPipelinesToDestroyCapacity, sizeof(D3D12GraphicsPipeline *)); 9993 if (!renderer->graphicsPipelinesToDestroy) { 9994 D3D12_INTERNAL_DestroyRenderer(renderer); 9995 return NULL; 9996 } 9997 9998 renderer->computePipelinesToDestroyCapacity = 4; 9999 renderer->computePipelinesToDestroyCount = 0; 10000 renderer->computePipelinesToDestroy = (D3D12ComputePipeline **)SDL_calloc( 10001 renderer->computePipelinesToDestroyCapacity, sizeof(D3D12ComputePipeline *)); 10002 if (!renderer->computePipelinesToDestroy) { 10003 D3D12_INTERNAL_DestroyRenderer(renderer); 10004 return NULL; 10005 } 10006 10007 // Locks 10008 renderer->acquireCommandBufferLock = SDL_CreateMutex(); 10009 renderer->acquireUniformBufferLock = SDL_CreateMutex(); 10010 renderer->submitLock = SDL_CreateMutex(); 10011 renderer->windowLock = SDL_CreateMutex(); 10012 renderer->fenceLock = SDL_CreateMutex(); 10013 renderer->disposeLock = SDL_CreateMutex(); 10014 10015 renderer->debug_mode = debugMode; 10016 renderer->allowedFramesInFlight = 2; 10017 10018 renderer->semantic = SDL_strdup(SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING, "TEXCOORD")); 10019 10020 // Blit resources 10021 D3D12_INTERNAL_InitBlitResources(renderer); 10022 10023#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 10024 res = renderer->device->SetFrameIntervalX( 10025 NULL, 10026 D3D12XBOX_FRAME_INTERVAL_60_HZ, 10027 renderer->allowedFramesInFlight - 1, 10028 D3D12XBOX_FRAME_INTERVAL_FLAG_NONE); 10029 if (FAILED(res)) { 10030 D3D12_INTERNAL_DestroyRenderer(renderer); 10031 CHECK_D3D12_ERROR_AND_RETURN("Could not get set frame interval", NULL); 10032 } 10033 10034 res = renderer->device->ScheduleFrameEventX( 10035 D3D12XBOX_FRAME_EVENT_ORIGIN, 10036 0, 10037 NULL, 10038 D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE); 10039 if (FAILED(res)) { 10040 D3D12_INTERNAL_DestroyRenderer(renderer); 10041 CHECK_D3D12_ERROR_AND_RETURN("Could not schedule frame events", NULL); 10042 } 10043#endif 10044 10045 // Create the SDL_GPU Device 10046 result = (SDL_GPUDevice *)SDL_calloc(1, sizeof(SDL_GPUDevice)); 10047 10048 if (!result) { 10049 D3D12_INTERNAL_DestroyRenderer(renderer); 10050 return NULL; 10051 } 10052 10053 SDL_GPUShaderFormat shaderFormats = SDL_GPU_SHADERFORMAT_DXBC; 10054 10055 D3D12_FEATURE_DATA_SHADER_MODEL shaderModel; 10056 shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0; 10057 10058 res = ID3D12Device_CheckFeatureSupport( 10059 renderer->device, 10060 D3D12_FEATURE_SHADER_MODEL, 10061 &shaderModel, 10062 sizeof(shaderModel)); 10063 if (SUCCEEDED(res) && shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0) { 10064 shaderFormats |= SDL_GPU_SHADERFORMAT_DXIL; 10065 } 10066 10067 ASSIGN_DRIVER(D3D12) 10068 result->driverData = (SDL_GPURenderer *)renderer; 10069 result->shader_formats = shaderFormats; 10070 result->debug_mode = debugMode; 10071 renderer->sdlGPUDevice = result; 10072 10073 return result; 10074} 10075 10076SDL_GPUBootstrap D3D12Driver = { 10077 "direct3d12", 10078 D3D12_PrepareDriver, 10079 D3D12_CreateDevice 10080}; 10081 10082#endif // SDL_GPU_D3D12 10083 10084// GDK-specific APIs 10085 10086#ifdef SDL_PLATFORM_GDK 10087 10088void SDL_GDKSuspendGPU(SDL_GPUDevice *device) 10089{ 10090#if defined(SDL_GPU_D3D12) && (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 10091 D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; 10092 HRESULT res; 10093 if (device == NULL) { 10094 SET_STRING_ERROR_AND_RETURN("Invalid GPU device", ); 10095 } 10096 10097 SDL_LockMutex(renderer->submitLock); 10098 res = renderer->commandQueue->SuspendX(0); 10099 if (FAILED(res)) { 10100 SDL_LogError(SDL_LOG_CATEGORY_GPU, "SuspendX failed: %X", res); 10101 } 10102 SDL_UnlockMutex(renderer->submitLock); 10103#endif 10104} 10105 10106void SDL_GDKResumeGPU(SDL_GPUDevice *device) 10107{ 10108#if defined(SDL_GPU_D3D12) && (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 10109 D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; 10110 HRESULT res; 10111 if (device == NULL) { 10112 SET_STRING_ERROR_AND_RETURN("Invalid GPU device", ); 10113 } 10114 10115 SDL_LockMutex(renderer->submitLock); 10116 res = renderer->commandQueue->ResumeX(); 10117 if (FAILED(res)) { 10118 SDL_LogError(SDL_LOG_CATEGORY_GPU, "ResumeX failed: %X", res); 10119 } 10120 SDL_UnlockMutex(renderer->submitLock); 10121 10122 res = renderer->device->SetFrameIntervalX( 10123 NULL, 10124 D3D12XBOX_FRAME_INTERVAL_60_HZ, 10125 renderer->allowedFramesInFlight - 1, 10126 D3D12XBOX_FRAME_INTERVAL_FLAG_NONE); 10127 if (FAILED(res)) { 10128 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not set frame interval: %X", res); 10129 } 10130 10131 res = renderer->device->ScheduleFrameEventX( 10132 D3D12XBOX_FRAME_EVENT_ORIGIN, 10133 0, 10134 NULL, 10135 D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE); 10136 if (FAILED(res)) { 10137 SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not schedule frame events: %X", res); 10138 } 10139#endif 10140} 10141 10142#endif // SDL_PLATFORM_GDK 10143[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.