Atlas - SDL_gpu_d3d12.c

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