| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org> |
| |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the authors be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| |
| #include "SDL_internal.h" |
| |
| #if SDL_GPU_D3D12 |
| |
| #include "../../video/directx/SDL_d3d12.h" |
| #include "../SDL_sysgpu.h" |
| #include "SDL_hashtable.h" |
| |
| // Built-in shaders, compiled with compile_shaders.bat |
| |
| #define g_FullscreenVert D3D12_FullscreenVert |
| #define g_BlitFrom2D D3D12_BlitFrom2D |
| #define g_BlitFrom2DArray D3D12_BlitFrom2DArray |
| #define g_BlitFrom3D D3D12_BlitFrom3D |
| #define g_BlitFromCube D3D12_BlitFromCube |
| #if defined(SDL_PLATFORM_XBOXSERIES) |
| #include "D3D12_Blit_Series.h" |
| #elif defined(SDL_PLATFORM_XBOXONE) |
| #include "D3D12_Blit_One.h" |
| #else |
| #include "D3D12_Blit.h" |
| #endif |
| #undef g_FullscreenVert |
| #undef g_BlitFrom2D |
| #undef g_BlitFrom2DArray |
| #undef g_BlitFrom3D |
| #undef g_BlitFromCube |
| |
| // Macros |
| |
| #define ERROR_CHECK(msg) \ |
| if (FAILED(res)) { \ |
| D3D12_INTERNAL_LogError(renderer->device, msg, res); \ |
| } |
| |
| #define ERROR_CHECK_RETURN(msg, ret) \ |
| if (FAILED(res)) { \ |
| D3D12_INTERNAL_LogError(renderer->device, msg, res); \ |
| return ret; \ |
| } |
| |
| // Defines |
| #if defined(_WIN32) |
| #if defined(SDL_PLATFORM_XBOXSERIES) |
| #define D3D12_DLL "d3d12_xs.dll" |
| #elif defined(SDL_PLATFORM_XBOXONE) |
| #define D3D12_DLL "d3d12_x.dll" |
| #else |
| #define D3D12_DLL "d3d12.dll" |
| #endif |
| #define DXGI_DLL "dxgi.dll" |
| #define DXGIDEBUG_DLL "dxgidebug.dll" |
| #elif defined(__APPLE__) |
| #define D3D12_DLL "libdxvk_d3d12.dylib" |
| #define DXGI_DLL "libdxvk_dxgi.dylib" |
| #define DXGIDEBUG_DLL "libdxvk_dxgidebug.dylib" |
| #else |
| #define D3D12_DLL "libdxvk_d3d12.so" |
| #define DXGI_DLL "libdxvk_dxgi.so" |
| #define DXGIDEBUG_DLL "libdxvk_dxgidebug.so" |
| #endif |
| |
| #define D3D12_CREATE_DEVICE_FUNC "D3D12CreateDevice" |
| #define D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC "D3D12SerializeRootSignature" |
| #define CREATE_DXGI_FACTORY1_FUNC "CreateDXGIFactory1" |
| #define DXGI_GET_DEBUG_INTERFACE_FUNC "DXGIGetDebugInterface" |
| #define D3D12_GET_DEBUG_INTERFACE_FUNC "D3D12GetDebugInterface" |
| #define WINDOW_PROPERTY_DATA "SDL_GPUD3D12WindowPropertyData" |
| #define D3D_FEATURE_LEVEL_CHOICE D3D_FEATURE_LEVEL_11_1 |
| #define D3D_FEATURE_LEVEL_CHOICE_STR "11_1" |
| // FIXME: just use sysgpu.h defines |
| #define MAX_ROOT_SIGNATURE_PARAMETERS 64 |
| #define VIEW_GPU_DESCRIPTOR_COUNT 65536 |
| #define SAMPLER_GPU_DESCRIPTOR_COUNT 2048 |
| #define VIEW_SAMPLER_STAGING_DESCRIPTOR_COUNT 1000000 |
| #define TARGET_STAGING_DESCRIPTOR_COUNT 1000000 |
| #define D3D12_FENCE_UNSIGNALED_VALUE 0 |
| #define D3D12_FENCE_SIGNAL_VALUE 1 |
| |
| #define SDL_GPU_SHADERSTAGE_COMPUTE (SDL_GPUShaderStage)2 |
| |
| #define EXPAND_ELEMENTS_IF_NEEDED(arr, initialValue, type) \ |
| if (arr->count == arr->capacity) { \ |
| if (arr->capacity == 0) { \ |
| arr->capacity = initialValue; \ |
| } else { \ |
| arr->capacity *= 2; \ |
| } \ |
| arr->elements = (type *)SDL_realloc( \ |
| arr->elements, \ |
| arr->capacity * sizeof(type)); \ |
| } |
| |
| #ifdef _WIN32 |
| #define HRESULT_FMT "(0x%08lX)" |
| #else |
| #define HRESULT_FMT "(0x%08X)" |
| #endif |
| |
| // Function Pointer Signatures |
| typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY1)(const GUID *riid, void **ppFactory); |
| typedef HRESULT(WINAPI *PFN_DXGI_GET_DEBUG_INTERFACE)(const GUID *riid, void **ppDebug); |
| |
| // IIDs (from https://www.magnumdb.com/) |
| static const IID D3D_IID_IDXGIFactory1 = { 0x770aae78, 0xf26f, 0x4dba, { 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3, 0x87 } }; |
| static const IID D3D_IID_IDXGIFactory4 = { 0x1bc6ea02, 0xef36, 0x464f, { 0xbf, 0x0c, 0x21, 0xca, 0x39, 0xe5, 0x16, 0x8a } }; |
| static const IID D3D_IID_IDXGIFactory5 = { 0x7632e1f5, 0xee65, 0x4dca, { 0x87, 0xfd, 0x84, 0xcd, 0x75, 0xf8, 0x83, 0x8d } }; |
| static const IID D3D_IID_IDXGIFactory6 = { 0xc1b6694f, 0xff09, 0x44a9, { 0xb0, 0x3c, 0x77, 0x90, 0x0a, 0x0a, 0x1d, 0x17 } }; |
| static const IID D3D_IID_IDXGIAdapter1 = { 0x29038f61, 0x3839, 0x4626, { 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a, 0x05 } }; |
| #if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) |
| static const IID D3D_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; |
| #endif |
| static const IID D3D_IID_IDXGISwapChain3 = { 0x94d99bdb, 0xf1f8, 0x4ab0, { 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1 } }; |
| static const IID D3D_IID_IDXGIDebug = { 0x119e7452, 0xde9e, 0x40fe, { 0x88, 0x06, 0x88, 0xf9, 0x0c, 0x12, 0xb4, 0x41 } }; |
| static const IID D3D_IID_IDXGIInfoQueue = { 0xd67441c7, 0x672a, 0x476f, { 0x9e, 0x82, 0xcd, 0x55, 0xb4, 0x49, 0x49, 0xce } }; |
| static const GUID D3D_IID_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x08 } }; |
| static const GUID D3D_IID_D3DDebugObjectName = { 0x429b8c22, 0x9188, 0x4b0c, { 0x87, 0x42, 0xac, 0xb0, 0xbf, 0x85, 0xc2, 0x00 } }; |
| |
| static const IID D3D_IID_ID3D12Device = { 0x189819f1, 0x1db6, 0x4b57, { 0xbe, 0x54, 0x18, 0x21, 0x33, 0x9b, 0x85, 0xf7 } }; |
| static const IID D3D_IID_ID3D12CommandQueue = { 0x0ec870a6, 0x5d7e, 0x4c22, { 0x8c, 0xfc, 0x5b, 0xaa, 0xe0, 0x76, 0x16, 0xed } }; |
| static const IID D3D_IID_ID3D12DescriptorHeap = { 0x8efb471d, 0x616c, 0x4f49, { 0x90, 0xf7, 0x12, 0x7b, 0xb7, 0x63, 0xfa, 0x51 } }; |
| static const IID D3D_IID_ID3D12Resource = { 0x696442be, 0xa72e, 0x4059, { 0xbc, 0x79, 0x5b, 0x5c, 0x98, 0x04, 0x0f, 0xad } }; |
| static const IID D3D_IID_ID3D12CommandAllocator = { 0x6102dee4, 0xaf59, 0x4b09, { 0xb9, 0x99, 0xb4, 0x4d, 0x73, 0xf0, 0x9b, 0x24 } }; |
| static const IID D3D_IID_ID3D12CommandList = { 0x7116d91c, 0xe7e4, 0x47ce, { 0xb8, 0xc6, 0xec, 0x81, 0x68, 0xf4, 0x37, 0xe5 } }; |
| static const IID D3D_IID_ID3D12GraphicsCommandList = { 0x5b160d0f, 0xac1b, 0x4185, { 0x8b, 0xa8, 0xb3, 0xae, 0x42, 0xa5, 0xa4, 0x55 } }; |
| static const IID D3D_IID_ID3D12Fence = { 0x0a753dcf, 0xc4d8, 0x4b91, { 0xad, 0xf6, 0xbe, 0x5a, 0x60, 0xd9, 0x5a, 0x76 } }; |
| static const IID D3D_IID_ID3D12RootSignature = { 0xc54a6b66, 0x72df, 0x4ee8, { 0x8b, 0xe5, 0xa9, 0x46, 0xa1, 0x42, 0x92, 0x14 } }; |
| static const IID D3D_IID_ID3D12CommandSignature = { 0xc36a797c, 0xec80, 0x4f0a, { 0x89, 0x85, 0xa7, 0xb2, 0x47, 0x50, 0x82, 0xd1 } }; |
| static const IID D3D_IID_ID3D12PipelineState = { 0x765a30f3, 0xf624, 0x4c6f, { 0xa8, 0x28, 0xac, 0xe9, 0x48, 0x62, 0x24, 0x45 } }; |
| static const IID D3D_IID_ID3D12Debug = { 0x344488b7, 0x6846, 0x474b, { 0xb9, 0x89, 0xf0, 0x27, 0x44, 0x82, 0x45, 0xe0 } }; |
| static const IID D3D_IID_ID3D12InfoQueue = { 0x0742a90b, 0xc387, 0x483f, { 0xb9, 0x46, 0x30, 0xa7, 0xe4, 0xe6, 0x14, 0x58 } }; |
| |
| // Enums |
| |
| typedef enum D3D12BufferType |
| { |
| D3D12_BUFFER_TYPE_GPU, |
| D3D12_BUFFER_TYPE_UNIFORM, |
| D3D12_BUFFER_TYPE_UPLOAD, |
| D3D12_BUFFER_TYPE_DOWNLOAD |
| } D3D12BufferType; |
| |
| // Conversions |
| |
| static SDL_GPUTextureFormat SwapchainCompositionToSDLTextureFormat[] = { |
| SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, // SDR |
| SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, // SDR_SRGB |
| SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT, // HDR |
| SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM, // HDR_ADVANCED |
| }; |
| |
| static DXGI_FORMAT SwapchainCompositionToTextureFormat[] = { |
| DXGI_FORMAT_B8G8R8A8_UNORM, // SDR |
| DXGI_FORMAT_B8G8R8A8_UNORM, /* SDR_SRGB */ // NOTE: The RTV uses the sRGB format |
| DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR |
| DXGI_FORMAT_R10G10B10A2_UNORM, // HDR_ADVANCED |
| }; |
| |
| static DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = { |
| DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR |
| DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_SRGB |
| DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR |
| DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR_ADVANCED |
| }; |
| |
| static D3D12_BLEND SDLToD3D12_BlendFactor[] = { |
| D3D12_BLEND_ZERO, // ZERO |
| D3D12_BLEND_ONE, // ONE |
| D3D12_BLEND_SRC_COLOR, // SRC_COLOR |
| D3D12_BLEND_INV_SRC_COLOR, // ONE_MINUS_SRC_COLOR |
| D3D12_BLEND_DEST_COLOR, // DST_COLOR |
| D3D12_BLEND_INV_DEST_COLOR, // ONE_MINUS_DST_COLOR |
| D3D12_BLEND_SRC_ALPHA, // SRC_ALPHA |
| D3D12_BLEND_INV_SRC_ALPHA, // ONE_MINUS_SRC_ALPHA |
| D3D12_BLEND_DEST_ALPHA, // DST_ALPHA |
| D3D12_BLEND_INV_DEST_ALPHA, // ONE_MINUS_DST_ALPHA |
| D3D12_BLEND_BLEND_FACTOR, // CONSTANT_COLOR |
| D3D12_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR |
| D3D12_BLEND_SRC_ALPHA_SAT, // SRC_ALPHA_SATURATE |
| }; |
| |
| static D3D12_BLEND SDLToD3D12_BlendFactorAlpha[] = { |
| D3D12_BLEND_ZERO, // ZERO |
| D3D12_BLEND_ONE, // ONE |
| D3D12_BLEND_SRC_ALPHA, // SRC_COLOR |
| D3D12_BLEND_INV_SRC_ALPHA, // ONE_MINUS_SRC_COLOR |
| D3D12_BLEND_DEST_ALPHA, // DST_COLOR |
| D3D12_BLEND_INV_DEST_ALPHA, // ONE_MINUS_DST_COLOR |
| D3D12_BLEND_SRC_ALPHA, // SRC_ALPHA |
| D3D12_BLEND_INV_SRC_ALPHA, // ONE_MINUS_SRC_ALPHA |
| D3D12_BLEND_DEST_ALPHA, // DST_ALPHA |
| D3D12_BLEND_INV_DEST_ALPHA, // ONE_MINUS_DST_ALPHA |
| D3D12_BLEND_BLEND_FACTOR, // CONSTANT_COLOR |
| D3D12_BLEND_INV_BLEND_FACTOR, // ONE_MINUS_CONSTANT_COLOR |
| D3D12_BLEND_SRC_ALPHA_SAT, // SRC_ALPHA_SATURATE |
| }; |
| |
| static D3D12_BLEND_OP SDLToD3D12_BlendOp[] = { |
| D3D12_BLEND_OP_ADD, // ADD |
| D3D12_BLEND_OP_SUBTRACT, // SUBTRACT |
| D3D12_BLEND_OP_REV_SUBTRACT, // REVERSE_SUBTRACT |
| D3D12_BLEND_OP_MIN, // MIN |
| D3D12_BLEND_OP_MAX // MAX |
| }; |
| |
| static DXGI_FORMAT SDLToD3D12_TextureFormat[] = { |
| DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM |
| DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM |
| DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM |
| DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM |
| DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM |
| DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM |
| DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM |
| DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM |
| DXGI_FORMAT_R8_UNORM, // R8_UNORM |
| DXGI_FORMAT_A8_UNORM, // A8_UNORM |
| DXGI_FORMAT_BC1_UNORM, // BC1_UNORM |
| DXGI_FORMAT_BC2_UNORM, // BC2_UNORM |
| DXGI_FORMAT_BC3_UNORM, // BC3_UNORM |
| DXGI_FORMAT_BC7_UNORM, // BC7_UNORM |
| DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM |
| DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM |
| DXGI_FORMAT_R16_FLOAT, // R16_FLOAT |
| DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT |
| DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT |
| DXGI_FORMAT_R32_FLOAT, // R32_FLOAT |
| DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT |
| DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT |
| DXGI_FORMAT_R8_UINT, // R8_UINT |
| DXGI_FORMAT_R8G8_UINT, // R8G8_UINT |
| DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT |
| DXGI_FORMAT_R16_UINT, // R16_UINT |
| DXGI_FORMAT_R16G16_UINT, // R16G16_UINT |
| DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT |
| DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB |
| DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB |
| DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB |
| DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB |
| DXGI_FORMAT_D16_UNORM, // D16_UNORM |
| DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM |
| DXGI_FORMAT_D32_FLOAT, // D32_FLOAT |
| DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT |
| DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT |
| }; |
| SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TextureFormat, SDL_arraysize(SDLToD3D12_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX); |
| |
| static D3D12_COMPARISON_FUNC SDLToD3D12_CompareOp[] = { |
| D3D12_COMPARISON_FUNC_NEVER, // NEVER |
| D3D12_COMPARISON_FUNC_LESS, // LESS |
| D3D12_COMPARISON_FUNC_EQUAL, // EQUAL |
| D3D12_COMPARISON_FUNC_LESS_EQUAL, // LESS_OR_EQUAL |
| D3D12_COMPARISON_FUNC_GREATER, // GREATER |
| D3D12_COMPARISON_FUNC_NOT_EQUAL, // NOT_EQUAL |
| D3D12_COMPARISON_FUNC_GREATER_EQUAL, // GREATER_OR_EQUAL |
| D3D12_COMPARISON_FUNC_ALWAYS // ALWAYS |
| }; |
| |
| static D3D12_STENCIL_OP SDLToD3D12_StencilOp[] = { |
| D3D12_STENCIL_OP_KEEP, // KEEP |
| D3D12_STENCIL_OP_ZERO, // ZERO |
| D3D12_STENCIL_OP_REPLACE, // REPLACE |
| D3D12_STENCIL_OP_INCR_SAT, // INCREMENT_AND_CLAMP |
| D3D12_STENCIL_OP_DECR_SAT, // DECREMENT_AND_CLAMP |
| D3D12_STENCIL_OP_INVERT, // INVERT |
| D3D12_STENCIL_OP_INCR, // INCREMENT_AND_WRAP |
| D3D12_STENCIL_OP_DECR // DECREMENT_AND_WRAP |
| }; |
| |
| static D3D12_CULL_MODE SDLToD3D12_CullMode[] = { |
| D3D12_CULL_MODE_NONE, // NONE |
| D3D12_CULL_MODE_FRONT, // FRONT |
| D3D12_CULL_MODE_BACK // BACK |
| }; |
| |
| static D3D12_FILL_MODE SDLToD3D12_FillMode[] = { |
| D3D12_FILL_MODE_SOLID, // FILL |
| D3D12_FILL_MODE_WIREFRAME // LINE |
| }; |
| |
| static D3D12_INPUT_CLASSIFICATION SDLToD3D12_InputRate[] = { |
| D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX |
| D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE |
| }; |
| |
| static DXGI_FORMAT SDLToD3D12_VertexFormat[] = { |
| DXGI_FORMAT_R32_SINT, // INT |
| DXGI_FORMAT_R32G32_SINT, // INT2 |
| DXGI_FORMAT_R32G32B32_SINT, // INT3 |
| DXGI_FORMAT_R32G32B32A32_SINT, // INT4 |
| DXGI_FORMAT_R32_UINT, // UINT |
| DXGI_FORMAT_R32G32_UINT, // UINT2 |
| DXGI_FORMAT_R32G32B32_UINT, // UINT3 |
| DXGI_FORMAT_R32G32B32A32_UINT, // UINT4 |
| DXGI_FORMAT_R32_FLOAT, // FLOAT |
| DXGI_FORMAT_R32G32_FLOAT, // FLOAT2 |
| DXGI_FORMAT_R32G32B32_FLOAT, // FLOAT3 |
| DXGI_FORMAT_R32G32B32A32_FLOAT, // FLOAT4 |
| DXGI_FORMAT_R8G8_SINT, // BYTE2 |
| DXGI_FORMAT_R8G8B8A8_SINT, // BYTE4 |
| DXGI_FORMAT_R8G8_UINT, // UBYTE2 |
| DXGI_FORMAT_R8G8B8A8_UINT, // UBYTE4 |
| DXGI_FORMAT_R8G8_SNORM, // BYTE2_NORM |
| DXGI_FORMAT_R8G8B8A8_SNORM, // BYTE4_NORM |
| DXGI_FORMAT_R8G8_UNORM, // UBYTE2_NORM |
| DXGI_FORMAT_R8G8B8A8_UNORM, // UBYTE4_NORM |
| DXGI_FORMAT_R16G16_SINT, // SHORT2 |
| DXGI_FORMAT_R16G16B16A16_SINT, // SHORT4 |
| DXGI_FORMAT_R16G16_UINT, // USHORT2 |
| DXGI_FORMAT_R16G16B16A16_UINT, // USHORT4 |
| DXGI_FORMAT_R16G16_SNORM, // SHORT2_NORM |
| DXGI_FORMAT_R16G16B16A16_SNORM, // SHORT4_NORM |
| DXGI_FORMAT_R16G16_UNORM, // USHORT2_NORM |
| DXGI_FORMAT_R16G16B16A16_UNORM, // USHORT4_NORM |
| DXGI_FORMAT_R16G16_FLOAT, // HALF2 |
| DXGI_FORMAT_R16G16B16A16_FLOAT // HALF4 |
| }; |
| |
| static Uint32 SDLToD3D12_SampleCount[] = { |
| 1, // SDL_GPU_SAMPLECOUNT_1 |
| 2, // SDL_GPU_SAMPLECOUNT_2 |
| 4, // SDL_GPU_SAMPLECOUNT_4 |
| 8, // SDL_GPU_SAMPLECOUNT_8 |
| }; |
| |
| static D3D12_PRIMITIVE_TOPOLOGY SDLToD3D12_PrimitiveType[] = { |
| D3D_PRIMITIVE_TOPOLOGY_POINTLIST, // POINTLIST |
| D3D_PRIMITIVE_TOPOLOGY_LINELIST, // LINELIST |
| D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, // LINESTRIP |
| D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // TRIANGLELIST |
| D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP // TRIANGLESTRIP |
| }; |
| |
| static D3D12_TEXTURE_ADDRESS_MODE SDLToD3D12_SamplerAddressMode[] = { |
| D3D12_TEXTURE_ADDRESS_MODE_WRAP, // REPEAT |
| D3D12_TEXTURE_ADDRESS_MODE_MIRROR, // MIRRORED_REPEAT |
| D3D12_TEXTURE_ADDRESS_MODE_CLAMP // CLAMP_TO_EDGE |
| }; |
| |
| static D3D12_FILTER SDLToD3D12_Filter( |
| SDL_GPUFilter minFilter, |
| SDL_GPUFilter magFilter, |
| SDL_GPUSamplerMipmapMode mipmapMode, |
| bool comparisonEnabled, |
| bool anisotropyEnabled) |
| { |
| D3D12_FILTER result = D3D12_ENCODE_BASIC_FILTER( |
| (minFilter == SDL_GPU_FILTER_LINEAR) ? 1 : 0, |
| (magFilter == SDL_GPU_FILTER_LINEAR) ? 1 : 0, |
| (mipmapMode == SDL_GPU_SAMPLERMIPMAPMODE_LINEAR) ? 1 : 0, |
| comparisonEnabled ? 1 : 0); |
| |
| if (anisotropyEnabled) { |
| result = (D3D12_FILTER)(result | D3D12_ANISOTROPIC_FILTERING_BIT); |
| } |
| |
| return result; |
| } |
| |
| // Structures |
| typedef struct D3D12Renderer D3D12Renderer; |
| typedef struct D3D12CommandBufferPool D3D12CommandBufferPool; |
| typedef struct D3D12CommandBuffer D3D12CommandBuffer; |
| typedef struct D3D12Texture D3D12Texture; |
| typedef struct D3D12Shader D3D12Shader; |
| typedef struct D3D12GraphicsPipeline D3D12GraphicsPipeline; |
| typedef struct D3D12ComputePipeline D3D12ComputePipeline; |
| typedef struct D3D12Buffer D3D12Buffer; |
| typedef struct D3D12BufferContainer D3D12BufferContainer; |
| typedef struct D3D12UniformBuffer D3D12UniformBuffer; |
| typedef struct D3D12DescriptorHeap D3D12DescriptorHeap; |
| typedef struct D3D12TextureDownload D3D12TextureDownload; |
| |
| typedef struct D3D12Fence |
| { |
| ID3D12Fence *handle; |
| HANDLE event; // used for blocking |
| SDL_AtomicInt referenceCount; |
| } D3D12Fence; |
| |
| struct D3D12DescriptorHeap |
| { |
| ID3D12DescriptorHeap *handle; |
| D3D12_DESCRIPTOR_HEAP_TYPE heapType; |
| D3D12_CPU_DESCRIPTOR_HANDLE descriptorHeapCPUStart; |
| D3D12_GPU_DESCRIPTOR_HANDLE descriptorHeapGPUStart; // only exists if staging is true |
| Uint32 maxDescriptors; |
| Uint32 descriptorSize; |
| bool staging; |
| |
| Uint32 currentDescriptorIndex; |
| |
| Uint32 *inactiveDescriptorIndices; // only exists if staging is true |
| Uint32 inactiveDescriptorCount; |
| }; |
| |
| typedef struct D3D12DescriptorHeapPool |
| { |
| Uint32 capacity; |
| Uint32 count; |
| D3D12DescriptorHeap **heaps; |
| SDL_Mutex *lock; |
| } D3D12DescriptorHeapPool; |
| |
| typedef struct D3D12CPUDescriptor |
| { |
| D3D12DescriptorHeap *heap; |
| D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle; |
| Uint32 cpuHandleIndex; |
| } D3D12CPUDescriptor; |
| |
| typedef struct D3D12TextureContainer |
| { |
| TextureCommonHeader header; |
| |
| D3D12Texture *activeTexture; |
| |
| D3D12Texture **textures; |
| Uint32 textureCapacity; |
| Uint32 textureCount; |
| |
| // Swapchain images cannot be cycled |
| bool canBeCycled; |
| |
| char *debugName; |
| } D3D12TextureContainer; |
| |
| // Null views represent by heap = NULL |
| typedef struct D3D12TextureSubresource |
| { |
| D3D12Texture *parent; |
| Uint32 layer; |
| Uint32 level; |
| Uint32 depth; |
| Uint32 index; |
| |
| // One per depth slice |
| D3D12CPUDescriptor *rtvHandles; // NULL if not a color target |
| |
| D3D12CPUDescriptor uavHandle; // NULL if not a compute storage write texture |
| D3D12CPUDescriptor dsvHandle; // NULL if not a depth stencil target |
| } D3D12TextureSubresource; |
| |
| struct D3D12Texture |
| { |
| D3D12TextureContainer *container; |
| Uint32 containerIndex; |
| |
| D3D12TextureSubresource *subresources; |
| Uint32 subresourceCount; /* layerCount * levelCount */ |
| |
| ID3D12Resource *resource; |
| D3D12CPUDescriptor srvHandle; |
| |
| SDL_AtomicInt referenceCount; |
| }; |
| |
| typedef struct D3D12Sampler |
| { |
| SDL_GPUSamplerCreateInfo createInfo; |
| D3D12CPUDescriptor handle; |
| SDL_AtomicInt referenceCount; |
| } D3D12Sampler; |
| |
| typedef struct D3D12WindowData |
| { |
| SDL_Window *window; |
| #if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) |
| D3D12XBOX_FRAME_PIPELINE_TOKEN frameToken; |
| Uint32 swapchainWidth, swapchainHeight; |
| #else |
| IDXGISwapChain3 *swapchain; |
| #endif |
| SDL_GPUPresentMode presentMode; |
| SDL_GPUSwapchainComposition swapchainComposition; |
| DXGI_COLOR_SPACE_TYPE swapchainColorSpace; |
| Uint32 frameCounter; |
| |
| D3D12TextureContainer textureContainers[MAX_FRAMES_IN_FLIGHT]; |
| D3D12Fence *inFlightFences[MAX_FRAMES_IN_FLIGHT]; |
| } D3D12WindowData; |
| |
| typedef struct D3D12PresentData |
| { |
| D3D12WindowData *windowData; |
| Uint32 swapchainImageIndex; |
| } D3D12PresentData; |
| |
| struct D3D12Renderer |
| { |
| // Reference to the parent device |
| SDL_GPUDevice *sdlGPUDevice; |
| |
| #if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) |
| IDXGIDebug *dxgiDebug; |
| IDXGIFactory4 *factory; |
| IDXGIInfoQueue *dxgiInfoQueue; |
| IDXGIAdapter1 *adapter; |
| void *dxgi_dll; |
| void *dxgidebug_dll; |
| #endif |
| ID3D12Debug *d3d12Debug; |
| bool supportsTearing; |
| void *d3d12_dll; |
| ID3D12Device *device; |
| PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignature_func; |
| const char *semantic; |
| SDL_iconv_t iconv; |
| |
| ID3D12CommandQueue *commandQueue; |
| |
| bool debugMode; |
| bool GPUUploadHeapSupported; |
| // FIXME: these might not be necessary since we're not using custom heaps |
| bool UMA; |
| bool UMACacheCoherent; |
| |
| // Indirect command signatures |
| ID3D12CommandSignature *indirectDrawCommandSignature; |
| ID3D12CommandSignature *indirectIndexedDrawCommandSignature; |
| ID3D12CommandSignature *indirectDispatchCommandSignature; |
| |
| // Blit |
| SDL_GPUShader *blitVertexShader; |
| SDL_GPUShader *blitFrom2DShader; |
| SDL_GPUShader *blitFrom2DArrayShader; |
| SDL_GPUShader *blitFrom3DShader; |
| SDL_GPUShader *blitFromCubeShader; |
| |
| SDL_GPUSampler *blitNearestSampler; |
| SDL_GPUSampler *blitLinearSampler; |
| |
| BlitPipelineCacheEntry *blitPipelines; |
| Uint32 blitPipelineCount; |
| Uint32 blitPipelineCapacity; |
| |
| // Resources |
| |
| D3D12CommandBuffer **availableCommandBuffers; |
| Uint32 availableCommandBufferCount; |
| Uint32 availableCommandBufferCapacity; |
| |
| D3D12CommandBuffer **submittedCommandBuffers; |
| Uint32 submittedCommandBufferCount; |
| Uint32 submittedCommandBufferCapacity; |
| |
| D3D12UniformBuffer **uniformBufferPool; |
| Uint32 uniformBufferPoolCount; |
| Uint32 uniformBufferPoolCapacity; |
| |
| D3D12WindowData **claimedWindows; |
| Uint32 claimedWindowCount; |
| Uint32 claimedWindowCapacity; |
| |
| D3D12Fence **availableFences; |
| Uint32 availableFenceCount; |
| Uint32 availableFenceCapacity; |
| |
| D3D12DescriptorHeap *stagingDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; |
| D3D12DescriptorHeapPool descriptorHeapPools[2]; |
| |
| // Deferred resource releasing |
| |
| D3D12Buffer **buffersToDestroy; |
| Uint32 buffersToDestroyCount; |
| Uint32 buffersToDestroyCapacity; |
| |
| D3D12Texture **texturesToDestroy; |
| Uint32 texturesToDestroyCount; |
| Uint32 texturesToDestroyCapacity; |
| |
| D3D12Sampler **samplersToDestroy; |
| Uint32 samplersToDestroyCount; |
| Uint32 samplersToDestroyCapacity; |
| |
| D3D12GraphicsPipeline **graphicsPipelinesToDestroy; |
| Uint32 graphicsPipelinesToDestroyCount; |
| Uint32 graphicsPipelinesToDestroyCapacity; |
| |
| D3D12ComputePipeline **computePipelinesToDestroy; |
| Uint32 computePipelinesToDestroyCount; |
| Uint32 computePipelinesToDestroyCapacity; |
| |
| // Locks |
| SDL_Mutex *stagingDescriptorHeapLock; |
| SDL_Mutex *acquireCommandBufferLock; |
| SDL_Mutex *acquireUniformBufferLock; |
| SDL_Mutex *submitLock; |
| SDL_Mutex *windowLock; |
| SDL_Mutex *fenceLock; |
| SDL_Mutex *disposeLock; |
| }; |
| |
| struct D3D12CommandBuffer |
| { |
| // reserved for SDL_gpu |
| CommandBufferCommonHeader common; |
| |
| // non owning parent reference |
| D3D12Renderer *renderer; |
| |
| ID3D12CommandAllocator *commandAllocator; |
| ID3D12GraphicsCommandList *graphicsCommandList; |
| D3D12Fence *inFlightFence; |
| bool autoReleaseFence; |
| |
| // Presentation data |
| D3D12PresentData *presentDatas; |
| Uint32 presentDataCount; |
| Uint32 presentDataCapacity; |
| |
| Uint32 colorAttachmentTextureSubresourceCount; |
| D3D12TextureSubresource *colorAttachmentTextureSubresources[MAX_COLOR_TARGET_BINDINGS]; |
| D3D12TextureSubresource *depthStencilTextureSubresource; |
| D3D12GraphicsPipeline *currentGraphicsPipeline; |
| D3D12ComputePipeline *currentComputePipeline; |
| |
| // Set at acquire time |
| D3D12DescriptorHeap *gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER + 1]; |
| |
| D3D12UniformBuffer **usedUniformBuffers; |
| Uint32 usedUniformBufferCount; |
| Uint32 usedUniformBufferCapacity; |
| |
| // Resource slot state |
| bool needVertexBufferBind; |
| bool needVertexSamplerBind; |
| bool needVertexStorageTextureBind; |
| bool needVertexStorageBufferBind; |
| bool needVertexUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| bool needFragmentSamplerBind; |
| bool needFragmentStorageTextureBind; |
| bool needFragmentStorageBufferBind; |
| bool needFragmentUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| |
| bool needComputeReadOnlyStorageTextureBind; |
| bool needComputeReadOnlyStorageBufferBind; |
| bool needComputeUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| |
| D3D12Buffer *vertexBuffers[MAX_BUFFER_BINDINGS]; |
| Uint32 vertexBufferOffsets[MAX_BUFFER_BINDINGS]; |
| Uint32 vertexBufferCount; |
| |
| D3D12Texture *vertexSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; |
| D3D12Sampler *vertexSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; |
| D3D12Texture *vertexStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; |
| D3D12Buffer *vertexStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; |
| D3D12UniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| |
| D3D12Texture *fragmentSamplerTextures[MAX_TEXTURE_SAMPLERS_PER_STAGE]; |
| D3D12Sampler *fragmentSamplers[MAX_TEXTURE_SAMPLERS_PER_STAGE]; |
| D3D12Texture *fragmentStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; |
| D3D12Buffer *fragmentStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; |
| D3D12UniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| |
| D3D12Texture *computeReadOnlyStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE]; |
| D3D12Buffer *computeReadOnlyStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE]; |
| D3D12TextureSubresource *computeWriteOnlyStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES]; |
| Uint32 computeWriteOnlyStorageTextureSubresourceCount; |
| D3D12Buffer *computeWriteOnlyStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS]; |
| Uint32 computeWriteOnlyStorageBufferCount; |
| D3D12UniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| |
| // Resource tracking |
| D3D12Texture **usedTextures; |
| Uint32 usedTextureCount; |
| Uint32 usedTextureCapacity; |
| |
| D3D12Buffer **usedBuffers; |
| Uint32 usedBufferCount; |
| Uint32 usedBufferCapacity; |
| |
| D3D12Sampler **usedSamplers; |
| Uint32 usedSamplerCount; |
| Uint32 usedSamplerCapacity; |
| |
| D3D12GraphicsPipeline **usedGraphicsPipelines; |
| Uint32 usedGraphicsPipelineCount; |
| Uint32 usedGraphicsPipelineCapacity; |
| |
| D3D12ComputePipeline **usedComputePipelines; |
| Uint32 usedComputePipelineCount; |
| Uint32 usedComputePipelineCapacity; |
| |
| // Used for texture pitch hack |
| D3D12TextureDownload **textureDownloads; |
| Uint32 textureDownloadCount; |
| Uint32 textureDownloadCapacity; |
| }; |
| |
| struct D3D12Shader |
| { |
| // todo cleanup |
| void *bytecode; |
| size_t bytecodeSize; |
| |
| Uint32 samplerCount; |
| Uint32 uniformBufferCount; |
| Uint32 storageBufferCount; |
| Uint32 storageTextureCount; |
| }; |
| |
| typedef struct D3D12GraphicsRootSignature |
| { |
| ID3D12RootSignature *handle; |
| |
| Sint32 vertexSamplerRootIndex; |
| Sint32 vertexSamplerTextureRootIndex; |
| Sint32 vertexStorageTextureRootIndex; |
| Sint32 vertexStorageBufferRootIndex; |
| |
| Sint32 vertexUniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| |
| Sint32 fragmentSamplerRootIndex; |
| Sint32 fragmentSamplerTextureRootIndex; |
| Sint32 fragmentStorageTextureRootIndex; |
| Sint32 fragmentStorageBufferRootIndex; |
| |
| Sint32 fragmentUniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| } D3D12GraphicsRootSignature; |
| |
| struct D3D12GraphicsPipeline |
| { |
| ID3D12PipelineState *pipelineState; |
| D3D12GraphicsRootSignature *rootSignature; |
| SDL_GPUPrimitiveType primitiveType; |
| |
| Uint32 vertexStrides[MAX_BUFFER_BINDINGS]; |
| |
| float blendConstants[4]; |
| Uint8 stencilRef; |
| |
| Uint32 vertexSamplerCount; |
| Uint32 vertexUniformBufferCount; |
| Uint32 vertexStorageBufferCount; |
| Uint32 vertexStorageTextureCount; |
| |
| Uint32 fragmentSamplerCount; |
| Uint32 fragmentUniformBufferCount; |
| Uint32 fragmentStorageBufferCount; |
| Uint32 fragmentStorageTextureCount; |
| |
| SDL_AtomicInt referenceCount; |
| }; |
| |
| typedef struct D3D12ComputeRootSignature |
| { |
| ID3D12RootSignature *handle; |
| |
| Uint32 readOnlyStorageTextureRootIndex; |
| Uint32 readOnlyStorageBufferRootIndex; |
| Uint32 writeOnlyStorageTextureRootIndex; |
| Uint32 writeOnlyStorageBufferRootIndex; |
| Uint32 uniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE]; |
| } D3D12ComputeRootSignature; |
| |
| struct D3D12ComputePipeline |
| { |
| ID3D12PipelineState *pipelineState; |
| D3D12ComputeRootSignature *rootSignature; |
| |
| Uint32 readOnlyStorageTextureCount; |
| Uint32 readOnlyStorageBufferCount; |
| Uint32 writeOnlyStorageTextureCount; |
| Uint32 writeOnlyStorageBufferCount; |
| Uint32 uniformBufferCount; |
| |
| SDL_AtomicInt referenceCount; |
| }; |
| |
| struct D3D12TextureDownload |
| { |
| D3D12Buffer *destinationBuffer; |
| D3D12Buffer *temporaryBuffer; |
| Uint32 width; |
| Uint32 height; |
| Uint32 depth; |
| Uint32 bufferOffset; |
| Uint32 bytesPerRow; |
| Uint32 bytesPerDepthSlice; |
| Uint32 alignedBytesPerRow; |
| }; |
| |
| struct D3D12Buffer |
| { |
| D3D12BufferContainer *container; |
| Uint32 containerIndex; |
| |
| ID3D12Resource *handle; |
| D3D12CPUDescriptor uavDescriptor; |
| D3D12CPUDescriptor srvDescriptor; |
| D3D12CPUDescriptor cbvDescriptor; |
| D3D12_GPU_VIRTUAL_ADDRESS virtualAddress; |
| Uint8 *mapPointer; // NULL except for upload buffers and fast uniform buffers |
| SDL_AtomicInt referenceCount; |
| bool transitioned; // used for initial resource barrier |
| }; |
| |
| struct D3D12BufferContainer |
| { |
| SDL_GPUBufferUsageFlags usageFlags; |
| Uint32 size; |
| D3D12BufferType type; |
| |
| D3D12Buffer *activeBuffer; |
| |
| D3D12Buffer **buffers; |
| Uint32 bufferCapacity; |
| Uint32 bufferCount; |
| |
| D3D12_RESOURCE_DESC bufferDesc; |
| |
| char *debugName; |
| }; |
| |
| struct D3D12UniformBuffer |
| { |
| D3D12Buffer *buffer; |
| Uint32 writeOffset; |
| Uint32 drawOffset; |
| Uint32 currentBlockSize; |
| }; |
| |
| // Foward function declarations |
| |
| static void D3D12_UnclaimWindow(SDL_GPURenderer *driverData, SDL_Window *window); |
| static void D3D12_Wait(SDL_GPURenderer *driverData); |
| static void D3D12_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence **pFences, Uint32 fenceCount); |
| static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData); |
| |
| // Helpers |
| |
| static Uint32 D3D12_INTERNAL_Align(Uint32 location, Uint32 alignment) |
| { |
| return (location + (alignment - 1)) & ~(alignment - 1); |
| } |
| |
| // Xbox Hack |
| |
| #if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) |
| // FIXME: This is purely to work around a presentation bug when recreating the device/command queue. |
| static ID3D12Device *s_Device; |
| static ID3D12CommandQueue *s_CommandQueue; |
| #endif |
| |
| // Logging |
| |
| static void |
| D3D12_INTERNAL_LogError( |
| ID3D12Device *device, |
| const char *msg, |
| HRESULT res) |
| { |
| #define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! |
| |
| // Buffer for text, ensure space for \0 terminator after buffer |
| char wszMsgBuff[MAX_ERROR_LEN + 1]; |
| DWORD dwChars; // Number of chars returned. |
| |
| if (res == DXGI_ERROR_DEVICE_REMOVED) { |
| if (device) { |
| res = ID3D12Device_GetDeviceRemovedReason(device); |
| } |
| } |
| |
| // Try to get the message from the system errors. |
| dwChars = FormatMessageA( |
| FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
| NULL, |
| res, |
| 0, |
| wszMsgBuff, |
| MAX_ERROR_LEN, |
| NULL); |
| |
| // No message? Screw it, just post the code. |
| if (dwChars == 0) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res); |
| return; |
| } |
| |
| // Ensure valid range |
| dwChars = SDL_min(dwChars, MAX_ERROR_LEN); |
| |
| // Trim whitespace from tail of message |
| while (dwChars > 0) { |
| if (wszMsgBuff[dwChars - 1] <= ' ') { |
| dwChars--; |
| } else { |
| break; |
| } |
| } |
| |
| // Ensure null-terminated string |
| wszMsgBuff[dwChars] = '\0'; |
| |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res); |
| } |
| |
| // Debug Naming |
| |
| static void D3D12_INTERNAL_SetResourceName( |
| D3D12Renderer *renderer, |
| ID3D12Resource *resource, |
| const char *text) |
| { |
| if (renderer->debugMode) { |
| ID3D12DeviceChild_SetPrivateData( |
| resource, |
| D3D_GUID(D3D_IID_D3DDebugObjectName), |
| (UINT)SDL_strlen(text), |
| text); |
| } |
| } |
| |
| // Release / Cleanup |
| |
| // TODO: call this when releasing resources |
| static void D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| D3D12Renderer *renderer, |
| D3D12CPUDescriptor *cpuDescriptor) |
| { |
| D3D12DescriptorHeap *heap = cpuDescriptor->heap; |
| |
| if (heap != NULL) { |
| SDL_LockMutex(renderer->stagingDescriptorHeapLock); |
| heap->inactiveDescriptorIndices[heap->inactiveDescriptorCount] = cpuDescriptor->cpuHandleIndex; |
| heap->inactiveDescriptorCount += 1; |
| SDL_UnlockMutex(renderer->stagingDescriptorHeapLock); |
| } |
| |
| cpuDescriptor->heap = NULL; |
| cpuDescriptor->cpuHandle.ptr = 0; |
| cpuDescriptor->cpuHandleIndex = SDL_MAX_UINT32; |
| } |
| |
| static void D3D12_INTERNAL_DestroyBuffer( |
| D3D12Renderer *renderer, |
| D3D12Buffer *buffer) |
| { |
| if (!buffer) { |
| return; |
| } |
| |
| if (buffer->mapPointer != NULL) { |
| ID3D12Resource_Unmap( |
| buffer->handle, |
| 0, |
| NULL); |
| } |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &buffer->srvDescriptor); |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &buffer->uavDescriptor); |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &buffer->cbvDescriptor); |
| |
| if (buffer->handle) { |
| ID3D12Resource_Release(buffer->handle); |
| } |
| SDL_free(buffer); |
| } |
| |
| static void D3D12_INTERNAL_ReleaseBuffer( |
| D3D12Renderer *renderer, |
| D3D12Buffer *buffer) |
| { |
| SDL_LockMutex(renderer->disposeLock); |
| |
| EXPAND_ARRAY_IF_NEEDED( |
| renderer->buffersToDestroy, |
| D3D12Buffer *, |
| renderer->buffersToDestroyCount + 1, |
| renderer->buffersToDestroyCapacity, |
| renderer->buffersToDestroyCapacity * 2) |
| |
| renderer->buffersToDestroy[renderer->buffersToDestroyCount] = buffer; |
| renderer->buffersToDestroyCount += 1; |
| |
| SDL_UnlockMutex(renderer->disposeLock); |
| } |
| |
| static void D3D12_INTERNAL_ReleaseBufferContainer( |
| D3D12Renderer *renderer, |
| D3D12BufferContainer *container) |
| { |
| SDL_LockMutex(renderer->disposeLock); |
| |
| for (Uint32 i = 0; i < container->bufferCount; i += 1) { |
| D3D12_INTERNAL_ReleaseBuffer( |
| renderer, |
| container->buffers[i]); |
| } |
| |
| // Containers are just client handles, so we can free immediately |
| if (container->debugName) { |
| SDL_free(container->debugName); |
| } |
| SDL_free(container->buffers); |
| SDL_free(container); |
| |
| SDL_UnlockMutex(renderer->disposeLock); |
| } |
| |
| static void D3D12_INTERNAL_DestroyTexture( |
| D3D12Renderer *renderer, |
| D3D12Texture *texture) |
| { |
| if (!texture) { |
| return; |
| } |
| for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { |
| D3D12TextureSubresource *subresource = &texture->subresources[i]; |
| if (subresource->rtvHandles) { |
| for (Uint32 depthIndex = 0; depthIndex < subresource->depth; depthIndex += 1) { |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &subresource->rtvHandles[depthIndex]); |
| } |
| SDL_free(subresource->rtvHandles); |
| } |
| |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &subresource->uavHandle); |
| |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &subresource->dsvHandle); |
| } |
| SDL_free(texture->subresources); |
| |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &texture->srvHandle); |
| |
| if (texture->resource) { |
| ID3D12Resource_Release(texture->resource); |
| } |
| |
| SDL_free(texture); |
| } |
| |
| static void D3D12_INTERNAL_ReleaseTexture( |
| D3D12Renderer *renderer, |
| D3D12Texture *texture) |
| { |
| SDL_LockMutex(renderer->disposeLock); |
| |
| EXPAND_ARRAY_IF_NEEDED( |
| renderer->texturesToDestroy, |
| D3D12Texture *, |
| renderer->texturesToDestroyCount + 1, |
| renderer->texturesToDestroyCapacity, |
| renderer->texturesToDestroyCapacity * 2) |
| |
| renderer->texturesToDestroy[renderer->texturesToDestroyCount] = texture; |
| renderer->texturesToDestroyCount += 1; |
| |
| SDL_UnlockMutex(renderer->disposeLock); |
| } |
| |
| static void D3D12_INTERNAL_ReleaseTextureContainer( |
| D3D12Renderer *renderer, |
| D3D12TextureContainer *container) |
| { |
| SDL_LockMutex(renderer->disposeLock); |
| |
| for (Uint32 i = 0; i < container->textureCount; i += 1) { |
| D3D12_INTERNAL_ReleaseTexture( |
| renderer, |
| container->textures[i]); |
| } |
| |
| // Containers are just client handles, so we can destroy immediately |
| if (container->debugName) { |
| SDL_free(container->debugName); |
| } |
| SDL_free(container->textures); |
| SDL_free(container); |
| |
| SDL_UnlockMutex(renderer->disposeLock); |
| } |
| |
| static void D3D12_INTERNAL_DestroySampler( |
| D3D12Renderer *renderer, |
| D3D12Sampler *sampler) |
| { |
| D3D12_INTERNAL_ReleaseCpuDescriptorHandle( |
| renderer, |
| &sampler->handle); |
| |
| SDL_free(sampler); |
| } |
| |
| static void D3D12_INTERNAL_DestroyGraphicsRootSignature( |
| D3D12GraphicsRootSignature *rootSignature) |
| { |
| if (!rootSignature) { |
| return; |
| } |
| if (rootSignature->handle) { |
| ID3D12RootSignature_Release(rootSignature->handle); |
| } |
| SDL_free(rootSignature); |
| } |
| |
| static void D3D12_INTERNAL_DestroyGraphicsPipeline( |
| D3D12GraphicsPipeline *graphicsPipeline) |
| { |
| if (graphicsPipeline->pipelineState) { |
| ID3D12PipelineState_Release(graphicsPipeline->pipelineState); |
| } |
| D3D12_INTERNAL_DestroyGraphicsRootSignature(graphicsPipeline->rootSignature); |
| SDL_free(graphicsPipeline); |
| } |
| |
| static void D3D12_INTERNAL_DestroyComputeRootSignature( |
| D3D12ComputeRootSignature *rootSignature) |
| { |
| if (!rootSignature) { |
| return; |
| } |
| if (rootSignature->handle) { |
| ID3D12RootSignature_Release(rootSignature->handle); |
| } |
| SDL_free(rootSignature); |
| } |
| |
| static void D3D12_INTERNAL_DestroyComputePipeline( |
| D3D12ComputePipeline *computePipeline) |
| { |
| if (computePipeline->pipelineState) { |
| ID3D12PipelineState_Release(computePipeline->pipelineState); |
| } |
| D3D12_INTERNAL_DestroyComputeRootSignature(computePipeline->rootSignature); |
| SDL_free(computePipeline); |
| } |
| |
| static void D3D12_INTERNAL_ReleaseFenceToPool( |
| D3D12Renderer *renderer, |
| D3D12Fence *fence) |
| { |
| SDL_LockMutex(renderer->fenceLock); |
| |
| EXPAND_ARRAY_IF_NEEDED( |
| renderer->availableFences, |
| D3D12Fence *, |
| renderer->availableFenceCount + 1, |
| renderer->availableFenceCapacity, |
| renderer->availableFenceCapacity * 2); |
| |
| renderer->availableFences[renderer->availableFenceCount] = fence; |
| renderer->availableFenceCount += 1; |
| |
| SDL_UnlockMutex(renderer->fenceLock); |
| } |
| |
| static void D3D12_ReleaseFence( |
| SDL_GPURenderer *driverData, |
| SDL_GPUFence *fence) |
| { |
| D3D12Fence *d3d12Fence = (D3D12Fence *)fence; |
| |
| if (SDL_AtomicDecRef(&d3d12Fence->referenceCount)) { |
| D3D12_INTERNAL_ReleaseFenceToPool( |
| (D3D12Renderer *)driverData, |
| d3d12Fence); |
| } |
| } |
| |
| static bool D3D12_QueryFence( |
| SDL_GPURenderer *driverData, |
| SDL_GPUFence *fence) |
| { |
| D3D12Fence *d3d12Fence = (D3D12Fence *)fence; |
| return ID3D12Fence_GetCompletedValue(d3d12Fence->handle) == D3D12_FENCE_SIGNAL_VALUE; |
| } |
| |
| static void D3D12_INTERNAL_DestroyDescriptorHeap(D3D12DescriptorHeap *descriptorHeap) |
| { |
| if (!descriptorHeap) { |
| return; |
| } |
| SDL_free(descriptorHeap->inactiveDescriptorIndices); |
| if (descriptorHeap->handle) { |
| ID3D12DescriptorHeap_Release(descriptorHeap->handle); |
| } |
| SDL_free(descriptorHeap); |
| } |
| |
| static void D3D12_INTERNAL_DestroyCommandBuffer(D3D12CommandBuffer *commandBuffer) |
| { |
| if (!commandBuffer) { |
| return; |
| } |
| if (commandBuffer->graphicsCommandList) { |
| ID3D12GraphicsCommandList_Release(commandBuffer->graphicsCommandList); |
| } |
| if (commandBuffer->commandAllocator) { |
| ID3D12CommandAllocator_Release(commandBuffer->commandAllocator); |
| } |
| SDL_free(commandBuffer->presentDatas); |
| SDL_free(commandBuffer->usedTextures); |
| SDL_free(commandBuffer->usedBuffers); |
| SDL_free(commandBuffer->usedSamplers); |
| SDL_free(commandBuffer->usedGraphicsPipelines); |
| SDL_free(commandBuffer->usedComputePipelines); |
| SDL_free(commandBuffer->usedUniformBuffers); |
| SDL_free(commandBuffer); |
| } |
| |
| static void D3D12_INTERNAL_DestroyFence(D3D12Fence *fence) |
| { |
| if (!fence) { |
| return; |
| } |
| if (fence->handle) { |
| ID3D12Fence_Release(fence->handle); |
| } |
| if (fence->event) { |
| CloseHandle(fence->event); |
| } |
| SDL_free(fence); |
| } |
| |
| static void D3D12_INTERNAL_DestroyRenderer(D3D12Renderer *renderer) |
| { |
| // Release uniform buffers |
| for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) { |
| D3D12_INTERNAL_DestroyBuffer( |
| renderer, |
| renderer->uniformBufferPool[i]->buffer); |
| SDL_free(renderer->uniformBufferPool[i]); |
| } |
| |
| // Clean up descriptor heaps |
| for (Uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { |
| if (renderer->stagingDescriptorHeaps[i]) { |
| D3D12_INTERNAL_DestroyDescriptorHeap(renderer->stagingDescriptorHeaps[i]); |
| renderer->stagingDescriptorHeaps[i] = NULL; |
| } |
| } |
| |
| for (Uint32 i = 0; i < 2; i += 1) { |
| if (renderer->descriptorHeapPools[i].heaps) { |
| for (Uint32 j = 0; j < renderer->descriptorHeapPools[i].count; j += 1) { |
| if (renderer->descriptorHeapPools[i].heaps[j]) { |
| D3D12_INTERNAL_DestroyDescriptorHeap(renderer->descriptorHeapPools[i].heaps[j]); |
| renderer->descriptorHeapPools[i].heaps[j] = NULL; |
| } |
| } |
| SDL_free(renderer->descriptorHeapPools[i].heaps); |
| } |
| if (renderer->descriptorHeapPools[i].lock) { |
| SDL_DestroyMutex(renderer->descriptorHeapPools[i].lock); |
| renderer->descriptorHeapPools[i].lock = NULL; |
| } |
| } |
| |
| // Release command buffers |
| for (Uint32 i = 0; i < renderer->availableCommandBufferCount; i += 1) { |
| if (renderer->availableCommandBuffers[i]) { |
| D3D12_INTERNAL_DestroyCommandBuffer(renderer->availableCommandBuffers[i]); |
| renderer->availableCommandBuffers[i] = NULL; |
| } |
| } |
| |
| // Release fences |
| for (Uint32 i = 0; i < renderer->availableFenceCount; i += 1) { |
| if (renderer->availableFences[i]) { |
| D3D12_INTERNAL_DestroyFence(renderer->availableFences[i]); |
| renderer->availableFences[i] = NULL; |
| } |
| } |
| |
| // Clean up allocations |
| SDL_free(renderer->availableCommandBuffers); |
| SDL_free(renderer->submittedCommandBuffers); |
| SDL_free(renderer->uniformBufferPool); |
| SDL_free(renderer->claimedWindows); |
| SDL_free(renderer->availableFences); |
| SDL_free(renderer->buffersToDestroy); |
| SDL_free(renderer->texturesToDestroy); |
| SDL_free(renderer->samplersToDestroy); |
| SDL_free(renderer->graphicsPipelinesToDestroy); |
| SDL_free(renderer->computePipelinesToDestroy); |
| |
| // Tear down D3D12 objects |
| if (renderer->indirectDrawCommandSignature) { |
| ID3D12CommandSignature_Release(renderer->indirectDrawCommandSignature); |
| renderer->indirectDrawCommandSignature = NULL; |
| } |
| if (renderer->indirectIndexedDrawCommandSignature) { |
| ID3D12CommandSignature_Release(renderer->indirectIndexedDrawCommandSignature); |
| renderer->indirectIndexedDrawCommandSignature = NULL; |
| } |
| if (renderer->indirectDispatchCommandSignature) { |
| ID3D12CommandSignature_Release(renderer->indirectDispatchCommandSignature); |
| renderer->indirectDispatchCommandSignature = NULL; |
| } |
| #if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) |
| if (renderer->commandQueue) { |
| ID3D12CommandQueue_Release(renderer->commandQueue); |
| renderer->commandQueue = NULL; |
| } |
| if (renderer->device) { |
| ID3D12Device_Release(renderer->device); |
| renderer->device = NULL; |
| } |
| if (renderer->adapter) { |
| IDXGIAdapter1_Release(renderer->adapter); |
| renderer->adapter = NULL; |
| } |
| if (renderer->factory) { |
| IDXGIFactory4_Release(renderer->factory); |
| renderer->factory = NULL; |
| } |
| if (renderer->dxgiDebug) { |
| IDXGIDebug_ReportLiveObjects( |
| renderer->dxgiDebug, |
| D3D_IID_DXGI_DEBUG_ALL, |
| (DXGI_DEBUG_RLO_FLAGS)(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_DETAIL)); |
| IDXGIDebug_Release(renderer->dxgiDebug); |
| renderer->dxgiDebug = NULL; |
| } |
| #endif |
| if (renderer->d3d12_dll) { |
| SDL_UnloadObject(renderer->d3d12_dll); |
| renderer->d3d12_dll = NULL; |
| } |
| #if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) |
| if (renderer->dxgi_dll) { |
| SDL_UnloadObject(renderer->dxgi_dll); |
| renderer->dxgi_dll = NULL; |
| } |
| if (renderer->dxgidebug_dll) { |
| SDL_UnloadObject(renderer->dxgidebug_dll); |
| renderer->dxgidebug_dll = NULL; |
| } |
| #endif |
| renderer->D3D12SerializeRootSignature_func = NULL; |
| |
| if (renderer->iconv) { |
| SDL_iconv_close(renderer->iconv); |
| } |
| |
| SDL_DestroyMutex(renderer->stagingDescriptorHeapLock); |
| SDL_DestroyMutex(renderer->acquireCommandBufferLock); |
| SDL_DestroyMutex(renderer->acquireUniformBufferLock); |
| SDL_DestroyMutex(renderer->submitLock); |
| SDL_DestroyMutex(renderer->windowLock); |
| SDL_DestroyMutex(renderer->fenceLock); |
| SDL_DestroyMutex(renderer->disposeLock); |
| SDL_free(renderer); |
| } |
| |
| static void D3D12_DestroyDevice(SDL_GPUDevice *device) |
| { |
| D3D12Renderer *renderer = (D3D12Renderer *)device->driverData; |
| |
| // Release blit pipeline structures |
| D3D12_INTERNAL_ReleaseBlitPipelines((SDL_GPURenderer *)renderer); |
| |
| // Flush any remaining GPU work... |
| D3D12_Wait((SDL_GPURenderer *)renderer); |
| |
| // Release window data |
| for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) { |
| D3D12_UnclaimWindow((SDL_GPURenderer *)renderer, renderer->claimedWindows[i]->window); |
| } |
| |
| D3D12_INTERNAL_DestroyRenderer(renderer); |
| SDL_free(device); |
| } |
| |
| // Barriers |
| |
| static inline Uint32 D3D12_INTERNAL_CalcSubresource( |
| Uint32 mipLevel, |
| Uint32 layer, |
| Uint32 numLevels) |
| { |
| return mipLevel + (layer * numLevels); |
| } |
| |
| static void D3D12_INTERNAL_ResourceBarrier( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES sourceState, |
| D3D12_RESOURCE_STATES destinationState, |
| ID3D12Resource *resource, |
| Uint32 subresourceIndex, |
| bool needsUavBarrier) |
| { |
| D3D12_RESOURCE_BARRIER barrierDesc[2]; |
| Uint32 numBarriers = 0; |
| |
| // No transition barrier is needed if the state is not changing. |
| if (sourceState != destinationState) { |
| barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; |
| barrierDesc[numBarriers].Flags = (D3D12_RESOURCE_BARRIER_FLAGS)0; |
| barrierDesc[numBarriers].Transition.StateBefore = sourceState; |
| barrierDesc[numBarriers].Transition.StateAfter = destinationState; |
| barrierDesc[numBarriers].Transition.pResource = resource; |
| barrierDesc[numBarriers].Transition.Subresource = subresourceIndex; |
| |
| numBarriers += 1; |
| } |
| |
| if (needsUavBarrier) { |
| barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; |
| barrierDesc[numBarriers].Flags = (D3D12_RESOURCE_BARRIER_FLAGS)0; |
| barrierDesc[numBarriers].UAV.pResource = resource; |
| |
| numBarriers += 1; |
| } |
| |
| if (numBarriers > 0) { |
| ID3D12GraphicsCommandList_ResourceBarrier( |
| commandBuffer->graphicsCommandList, |
| numBarriers, |
| barrierDesc); |
| } |
| } |
| |
| static void D3D12_INTERNAL_TextureSubresourceBarrier( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES sourceState, |
| D3D12_RESOURCE_STATES destinationState, |
| D3D12TextureSubresource *textureSubresource) |
| { |
| D3D12_INTERNAL_ResourceBarrier( |
| commandBuffer, |
| sourceState, |
| destinationState, |
| textureSubresource->parent->resource, |
| textureSubresource->index, |
| textureSubresource->parent->container->header.info.usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT); |
| } |
| |
| static D3D12_RESOURCE_STATES D3D12_INTERNAL_DefaultTextureResourceState( |
| SDL_GPUTextureUsageFlags usageFlags) |
| { |
| // NOTE: order matters here! |
| |
| if (usageFlags & SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT) { |
| return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; |
| } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ_BIT) { |
| return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; |
| } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT) { |
| return D3D12_RESOURCE_STATE_RENDER_TARGET; |
| } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT) { |
| return D3D12_RESOURCE_STATE_DEPTH_WRITE; |
| } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ_BIT) { |
| return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; |
| } else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT) { |
| return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; |
| } else { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Texture has no default usage mode!"); |
| return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; |
| } |
| } |
| |
| static void D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES destinationUsageMode, |
| D3D12TextureSubresource *textureSubresource) |
| { |
| D3D12_INTERNAL_TextureSubresourceBarrier( |
| commandBuffer, |
| D3D12_INTERNAL_DefaultTextureResourceState(textureSubresource->parent->container->header.info.usageFlags), |
| destinationUsageMode, |
| textureSubresource); |
| } |
| |
| static void D3D12_INTERNAL_TextureTransitionFromDefaultUsage( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES destinationUsageMode, |
| D3D12Texture *texture) |
| { |
| for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { |
| D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage( |
| commandBuffer, |
| destinationUsageMode, |
| &texture->subresources[i]); |
| } |
| } |
| |
| static void D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES sourceUsageMode, |
| D3D12TextureSubresource *textureSubresource) |
| { |
| D3D12_INTERNAL_TextureSubresourceBarrier( |
| commandBuffer, |
| sourceUsageMode, |
| D3D12_INTERNAL_DefaultTextureResourceState(textureSubresource->parent->container->header.info.usageFlags), |
| textureSubresource); |
| } |
| |
| static void D3D12_INTERNAL_TextureTransitionToDefaultUsage( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES sourceUsageMode, |
| D3D12Texture *texture) |
| { |
| for (Uint32 i = 0; i < texture->subresourceCount; i += 1) { |
| D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage( |
| commandBuffer, |
| sourceUsageMode, |
| &texture->subresources[i]); |
| } |
| } |
| |
| static D3D12_RESOURCE_STATES D3D12_INTERNAL_DefaultBufferResourceState( |
| D3D12Buffer *buffer) |
| { |
| if (buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_VERTEX_BIT) { |
| return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; |
| } else if (buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_INDEX_BIT) { |
| return D3D12_RESOURCE_STATE_INDEX_BUFFER; |
| } else if (buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT_BIT) { |
| return D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT; |
| } else if (buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ_BIT) { |
| return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; |
| } else if (buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ_BIT) { |
| return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; |
| } else if (buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE_BIT) { |
| return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; |
| } else { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Buffer has no default usage mode!"); |
| return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER; |
| } |
| } |
| |
| static void D3D12_INTERNAL_BufferBarrier( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES sourceState, |
| D3D12_RESOURCE_STATES destinationState, |
| D3D12Buffer *buffer) |
| { |
| D3D12_INTERNAL_ResourceBarrier( |
| commandBuffer, |
| buffer->transitioned ? sourceState : D3D12_RESOURCE_STATE_COMMON, |
| destinationState, |
| buffer->handle, |
| 0, |
| buffer->container->usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE_BIT); |
| |
| buffer->transitioned = true; |
| } |
| |
| static void D3D12_INTERNAL_BufferTransitionFromDefaultUsage( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES destinationState, |
| D3D12Buffer *buffer) |
| { |
| D3D12_INTERNAL_BufferBarrier( |
| commandBuffer, |
| D3D12_INTERNAL_DefaultBufferResourceState(buffer), |
| destinationState, |
| buffer); |
| } |
| |
| static void D3D12_INTERNAL_BufferTransitionToDefaultUsage( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_RESOURCE_STATES sourceState, |
| D3D12Buffer *buffer) |
| { |
| D3D12_INTERNAL_BufferBarrier( |
| commandBuffer, |
| sourceState, |
| D3D12_INTERNAL_DefaultBufferResourceState(buffer), |
| buffer); |
| } |
| |
| // Resource tracking |
| |
| #define TRACK_RESOURCE(resource, type, array, count, capacity) \ |
| Uint32 i; \ |
| \ |
| for (i = 0; i < commandBuffer->count; i += 1) { \ |
| if (commandBuffer->array[i] == resource) { \ |
| return; \ |
| } \ |
| } \ |
| \ |
| if (commandBuffer->count == commandBuffer->capacity) { \ |
| commandBuffer->capacity += 1; \ |
| commandBuffer->array = (type *)SDL_realloc( \ |
| commandBuffer->array, \ |
| commandBuffer->capacity * sizeof(type)); \ |
| } \ |
| commandBuffer->array[commandBuffer->count] = resource; \ |
| commandBuffer->count += 1; \ |
| SDL_AtomicIncRef(&resource->referenceCount); |
| |
| static void D3D12_INTERNAL_TrackTexture( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12Texture *texture) |
| { |
| TRACK_RESOURCE( |
| texture, |
| D3D12Texture *, |
| usedTextures, |
| usedTextureCount, |
| usedTextureCapacity) |
| } |
| |
| static void D3D12_INTERNAL_TrackBuffer( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12Buffer *buffer) |
| { |
| TRACK_RESOURCE( |
| buffer, |
| D3D12Buffer *, |
| usedBuffers, |
| usedBufferCount, |
| usedBufferCapacity) |
| } |
| |
| static void D3D12_INTERNAL_TrackSampler( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12Sampler *sampler) |
| { |
| TRACK_RESOURCE( |
| sampler, |
| D3D12Sampler *, |
| usedSamplers, |
| usedSamplerCount, |
| usedSamplerCapacity) |
| } |
| |
| static void D3D12_INTERNAL_TrackGraphicsPipeline( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12GraphicsPipeline *graphicsPipeline) |
| { |
| TRACK_RESOURCE( |
| graphicsPipeline, |
| D3D12GraphicsPipeline *, |
| usedGraphicsPipelines, |
| usedGraphicsPipelineCount, |
| usedGraphicsPipelineCapacity) |
| } |
| |
| static void D3D12_INTERNAL_TrackComputePipeline( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12ComputePipeline *computePipeline) |
| { |
| TRACK_RESOURCE( |
| computePipeline, |
| D3D12ComputePipeline *, |
| usedComputePipelines, |
| usedComputePipelineCount, |
| usedComputePipelineCapacity) |
| } |
| |
| #undef TRACK_RESOURCE |
| |
| // State Creation |
| |
| static D3D12DescriptorHeap *D3D12_INTERNAL_CreateDescriptorHeap( |
| D3D12Renderer *renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE type, |
| Uint32 descriptorCount, |
| bool staging) |
| { |
| D3D12DescriptorHeap *heap; |
| ID3D12DescriptorHeap *handle; |
| D3D12_DESCRIPTOR_HEAP_DESC heapDesc; |
| HRESULT res; |
| |
| heap = (D3D12DescriptorHeap *)SDL_calloc(1, sizeof(D3D12DescriptorHeap)); |
| if (!heap) { |
| return NULL; |
| } |
| |
| heap->currentDescriptorIndex = 0; |
| heap->inactiveDescriptorCount = 0; |
| heap->inactiveDescriptorIndices = NULL; |
| |
| if (staging) { |
| heap->inactiveDescriptorIndices = (Uint32 *)SDL_calloc(descriptorCount, sizeof(Uint32)); |
| if (!heap->inactiveDescriptorIndices) { |
| D3D12_INTERNAL_DestroyDescriptorHeap(heap); |
| return NULL; |
| } |
| } |
| |
| heapDesc.NumDescriptors = descriptorCount; |
| heapDesc.Type = type; |
| heapDesc.Flags = staging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; |
| heapDesc.NodeMask = 0; |
| |
| res = ID3D12Device_CreateDescriptorHeap( |
| renderer->device, |
| &heapDesc, |
| D3D_GUID(D3D_IID_ID3D12DescriptorHeap), |
| (void **)&handle); |
| |
| if (FAILED(res)) { |
| D3D12_INTERNAL_LogError(renderer->device, "Failed to create descriptor heap!", res); |
| D3D12_INTERNAL_DestroyDescriptorHeap(heap); |
| return NULL; |
| } |
| |
| heap->handle = handle; |
| heap->heapType = type; |
| heap->maxDescriptors = descriptorCount; |
| heap->staging = staging; |
| heap->descriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(renderer->device, type); |
| D3D_CALL_RET(handle, GetCPUDescriptorHandleForHeapStart, &heap->descriptorHeapCPUStart); |
| if (!staging) { |
| D3D_CALL_RET(handle, GetGPUDescriptorHandleForHeapStart, &heap->descriptorHeapGPUStart); |
| } |
| |
| return heap; |
| } |
| |
| static D3D12DescriptorHeap *D3D12_INTERNAL_AcquireDescriptorHeapFromPool( |
| D3D12CommandBuffer *commandBuffer, |
| D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType) |
| { |
| D3D12DescriptorHeap *result; |
| D3D12Renderer *renderer = commandBuffer->renderer; |
| D3D12DescriptorHeapPool *pool = &renderer->descriptorHeapPools[descriptorHeapType]; |
| |
| SDL_LockMutex(pool->lock); |
| if (pool->count > 0) { |
| result = pool->heaps[pool->count - 1]; |
| pool->count -= 1; |
| } else { |
| result = D3D12_INTERNAL_CreateDescriptorHeap( |
| renderer, |
| descriptorHeapType, |
| descriptorHeapType == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ? VIEW_GPU_DESCRIPTOR_COUNT : SAMPLER_GPU_DESCRIPTOR_COUNT, |
| false); |
| } |
| SDL_UnlockMutex(pool->lock); |
| |
| return result; |
| } |
| |
| static void D3D12_INTERNAL_ReturnDescriptorHeapToPool( |
| D3D12Renderer *renderer, |
| D3D12DescriptorHeap *heap) |
| { |
| D3D12DescriptorHeapPool *pool = &renderer->descriptorHeapPools[heap->heapType]; |
| |
| heap->currentDescriptorIndex = 0; |
| |
| SDL_LockMutex(pool->lock); |
| if (pool->count >= pool->capacity) { |
| pool->capacity *= 2; |
| pool->heaps = (D3D12DescriptorHeap **)SDL_realloc( |
| pool->heaps, |
| pool->capacity * sizeof(D3D12DescriptorHeap *)); |
| } |
| |
| pool->heaps[pool->count] = heap; |
| pool->count += 1; |
| SDL_UnlockMutex(pool->lock); |
| } |
| |
| /* |
| * The root signature lets us define "root parameters" which are essentially bind points for resources. |
| * These let us define the register ranges as well as the register "space". |
| * The register space is akin to the descriptor set index in Vulkan, which allows us to group resources |
| * by stage so that the registers from the vertex and fragment shaders don't clobber each other. |
| * |
| * Most of our root parameters are implemented as "descriptor tables" so we can |
| * copy and then point to contiguous descriptor regions. |
| * Uniform buffers are the exception - these have to be implemented as raw "root descriptors" so |
| * that we can dynamically update the address that the constant buffer view points to. |
| * |
| * The root signature has a maximum size of 64 DWORDs. |
| * A descriptor table uses 1 DWORD. |
| * A root descriptor uses 2 DWORDS. |
| * This means our biggest root signature uses 24 DWORDs total, well under the limit. |
| * |
| * The root parameter indices are created dynamically and stored in the D3D12GraphicsRootSignature struct. |
| */ |
| static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature( |
| D3D12Renderer *renderer, |
| D3D12Shader *vertexShader, |
| D3D12Shader *fragmentShader) |
| { |
| // FIXME: I think the max can be smaller... |
| D3D12_ROOT_PARAMETER rootParameters[MAX_ROOT_SIGNATURE_PARAMETERS]; |
| D3D12_DESCRIPTOR_RANGE descriptorRanges[MAX_ROOT_SIGNATURE_PARAMETERS]; |
| Uint32 parameterCount = 0; |
| Uint32 rangeCount = 0; |
| D3D12_DESCRIPTOR_RANGE descriptorRange; |
| D3D12_ROOT_PARAMETER rootParameter; |
| D3D12GraphicsRootSignature *d3d12GraphicsRootSignature = |
| (D3D12GraphicsRootSignature *)SDL_calloc(1, sizeof(D3D12GraphicsRootSignature)); |
| if (!d3d12GraphicsRootSignature) { |
| return NULL; |
| } |
| |
| SDL_zeroa(rootParameters); |
| SDL_zeroa(descriptorRanges); |
| SDL_zero(rootParameter); |
| |
| d3d12GraphicsRootSignature->vertexSamplerRootIndex = -1; |
| d3d12GraphicsRootSignature->vertexSamplerTextureRootIndex = -1; |
| d3d12GraphicsRootSignature->vertexStorageTextureRootIndex = -1; |
| d3d12GraphicsRootSignature->vertexStorageBufferRootIndex = -1; |
| |
| d3d12GraphicsRootSignature->fragmentSamplerRootIndex = -1; |
| d3d12GraphicsRootSignature->fragmentSamplerTextureRootIndex = -1; |
| d3d12GraphicsRootSignature->fragmentStorageTextureRootIndex = -1; |
| d3d12GraphicsRootSignature->fragmentStorageBufferRootIndex = -1; |
| |
| for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { |
| d3d12GraphicsRootSignature->vertexUniformBufferRootIndex[i] = -1; |
| d3d12GraphicsRootSignature->fragmentUniformBufferRootIndex[i] = -1; |
| } |
| |
| if (vertexShader->samplerCount > 0) { |
| // Vertex Samplers |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; |
| descriptorRange.NumDescriptors = vertexShader->samplerCount; |
| descriptorRange.BaseShaderRegister = 0; |
| descriptorRange.RegisterSpace = 0; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->vertexSamplerRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = vertexShader->samplerCount; |
| descriptorRange.BaseShaderRegister = 0; |
| descriptorRange.RegisterSpace = 0; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->vertexSamplerTextureRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (vertexShader->storageTextureCount) { |
| // Vertex storage textures |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = vertexShader->storageTextureCount; |
| descriptorRange.BaseShaderRegister = vertexShader->samplerCount; |
| descriptorRange.RegisterSpace = 0; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->vertexStorageTextureRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (vertexShader->storageBufferCount) { |
| |
| // Vertex storage buffers |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = vertexShader->storageBufferCount; |
| descriptorRange.BaseShaderRegister = vertexShader->samplerCount + vertexShader->storageTextureCount; |
| descriptorRange.RegisterSpace = 0; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->vertexStorageBufferRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| // Vertex Uniforms |
| for (Uint32 i = 0; i < vertexShader->uniformBufferCount; i += 1) { |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; |
| rootParameter.Descriptor.ShaderRegister = i; |
| rootParameter.Descriptor.RegisterSpace = 1; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->vertexUniformBufferRootIndex[i] = parameterCount; |
| parameterCount += 1; |
| } |
| |
| if (fragmentShader->samplerCount) { |
| // Fragment Samplers |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; |
| descriptorRange.NumDescriptors = fragmentShader->samplerCount; |
| descriptorRange.BaseShaderRegister = 0; |
| descriptorRange.RegisterSpace = 2; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->fragmentSamplerRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = fragmentShader->samplerCount; |
| descriptorRange.BaseShaderRegister = 0; |
| descriptorRange.RegisterSpace = 2; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->fragmentSamplerTextureRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (fragmentShader->storageTextureCount) { |
| // Fragment Storage Textures |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = fragmentShader->storageTextureCount; |
| descriptorRange.BaseShaderRegister = fragmentShader->samplerCount; |
| descriptorRange.RegisterSpace = 2; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->fragmentStorageTextureRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (fragmentShader->storageBufferCount) { |
| // Fragment Storage Buffers |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = fragmentShader->storageBufferCount; |
| descriptorRange.BaseShaderRegister = fragmentShader->samplerCount + fragmentShader->storageTextureCount; |
| descriptorRange.RegisterSpace = 2; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->fragmentStorageBufferRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| // Fragment Uniforms |
| for (Uint32 i = 0; i < fragmentShader->uniformBufferCount; i += 1) { |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; |
| rootParameter.Descriptor.ShaderRegister = i; |
| rootParameter.Descriptor.RegisterSpace = 3; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; |
| rootParameters[parameterCount] = rootParameter; |
| d3d12GraphicsRootSignature->fragmentUniformBufferRootIndex[i] = parameterCount; |
| parameterCount += 1; |
| } |
| |
| // FIXME: shouldn't have to assert here |
| SDL_assert(parameterCount <= MAX_ROOT_SIGNATURE_PARAMETERS); |
| SDL_assert(rangeCount <= MAX_ROOT_SIGNATURE_PARAMETERS); |
| |
| // Create the root signature description |
| D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; |
| rootSignatureDesc.NumParameters = parameterCount; |
| rootSignatureDesc.pParameters = rootParameters; |
| rootSignatureDesc.NumStaticSamplers = 0; |
| rootSignatureDesc.pStaticSamplers = NULL; |
| rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; |
| |
| // Serialize the root signature |
| ID3DBlob *serializedRootSignature; |
| ID3DBlob *errorBlob; |
| HRESULT res = renderer->D3D12SerializeRootSignature_func(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSignature, &errorBlob); |
| |
| if (FAILED(res)) { |
| if (errorBlob) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); |
| ID3D10Blob_Release(errorBlob); |
| } |
| D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); |
| return NULL; |
| } |
| |
| // Create the root signature |
| ID3D12RootSignature *rootSignature; |
| |
| res = ID3D12Device_CreateRootSignature( |
| renderer->device, |
| 0, |
| ID3D10Blob_GetBufferPointer(serializedRootSignature), |
| ID3D10Blob_GetBufferSize(serializedRootSignature), |
| D3D_GUID(D3D_IID_ID3D12RootSignature), |
| (void **)&rootSignature); |
| |
| if (FAILED(res)) { |
| if (errorBlob) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create RootSignature"); |
| ID3D10Blob_Release(errorBlob); |
| } |
| D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); |
| return NULL; |
| } |
| |
| d3d12GraphicsRootSignature->handle = rootSignature; |
| return d3d12GraphicsRootSignature; |
| } |
| |
| static bool D3D12_INTERNAL_CreateShaderBytecode( |
| D3D12Renderer *renderer, |
| Uint32 stage, |
| SDL_GPUShaderFormat format, |
| const Uint8 *code, |
| size_t codeSize, |
| const char *entryPointName, |
| void **pBytecode, |
| size_t *pBytecodeSize) |
| { |
| if (pBytecode != NULL) { |
| *pBytecode = SDL_malloc(codeSize); |
| if (!*pBytecode) { |
| return false; |
| } |
| SDL_memcpy(*pBytecode, code, codeSize); |
| *pBytecodeSize = codeSize; |
| } |
| |
| return true; |
| } |
| |
| static D3D12ComputeRootSignature *D3D12_INTERNAL_CreateComputeRootSignature( |
| D3D12Renderer *renderer, |
| SDL_GPUComputePipelineCreateInfo *createInfo) |
| { |
| // FIXME: I think the max can be smaller... |
| D3D12_ROOT_PARAMETER rootParameters[MAX_ROOT_SIGNATURE_PARAMETERS]; |
| D3D12_DESCRIPTOR_RANGE descriptorRanges[MAX_ROOT_SIGNATURE_PARAMETERS]; |
| Uint32 parameterCount = 0; |
| Uint32 rangeCount = 0; |
| D3D12_DESCRIPTOR_RANGE descriptorRange; |
| D3D12_ROOT_PARAMETER rootParameter; |
| D3D12ComputeRootSignature *d3d12ComputeRootSignature = |
| (D3D12ComputeRootSignature *)SDL_calloc(1, sizeof(D3D12ComputeRootSignature)); |
| if (!d3d12ComputeRootSignature) { |
| return NULL; |
| } |
| |
| SDL_zeroa(rootParameters); |
| SDL_zeroa(descriptorRanges); |
| SDL_zero(rootParameter); |
| |
| d3d12ComputeRootSignature->readOnlyStorageTextureRootIndex = -1; |
| d3d12ComputeRootSignature->readOnlyStorageBufferRootIndex = -1; |
| d3d12ComputeRootSignature->writeOnlyStorageTextureRootIndex = -1; |
| d3d12ComputeRootSignature->writeOnlyStorageBufferRootIndex = -1; |
| |
| for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) { |
| d3d12ComputeRootSignature->uniformBufferRootIndex[i] = -1; |
| } |
| |
| if (createInfo->readOnlyStorageTextureCount) { |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = createInfo->readOnlyStorageTextureCount; |
| descriptorRange.BaseShaderRegister = 0; |
| descriptorRange.RegisterSpace = 0; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute |
| rootParameters[parameterCount] = rootParameter; |
| d3d12ComputeRootSignature->readOnlyStorageTextureRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (createInfo->readOnlyStorageBufferCount) { |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; |
| descriptorRange.NumDescriptors = createInfo->readOnlyStorageBufferCount; |
| descriptorRange.BaseShaderRegister = createInfo->readOnlyStorageTextureCount; |
| descriptorRange.RegisterSpace = 0; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute |
| rootParameters[parameterCount] = rootParameter; |
| d3d12ComputeRootSignature->readOnlyStorageBufferRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (createInfo->writeOnlyStorageTextureCount) { |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; |
| descriptorRange.NumDescriptors = createInfo->writeOnlyStorageTextureCount; |
| descriptorRange.BaseShaderRegister = 0; |
| descriptorRange.RegisterSpace = 1; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute |
| rootParameters[parameterCount] = rootParameter; |
| d3d12ComputeRootSignature->writeOnlyStorageTextureRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| if (createInfo->writeOnlyStorageBufferCount) { |
| descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; |
| descriptorRange.NumDescriptors = createInfo->writeOnlyStorageBufferCount; |
| descriptorRange.BaseShaderRegister = createInfo->writeOnlyStorageTextureCount; |
| descriptorRange.RegisterSpace = 1; |
| descriptorRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; |
| descriptorRanges[rangeCount] = descriptorRange; |
| |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; |
| rootParameter.DescriptorTable.NumDescriptorRanges = 1; |
| rootParameter.DescriptorTable.pDescriptorRanges = &descriptorRanges[rangeCount]; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute |
| rootParameters[parameterCount] = rootParameter; |
| d3d12ComputeRootSignature->writeOnlyStorageBufferRootIndex = parameterCount; |
| rangeCount += 1; |
| parameterCount += 1; |
| } |
| |
| for (Uint32 i = 0; i < createInfo->uniformBufferCount; i += 1) { |
| rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; |
| rootParameter.Descriptor.ShaderRegister = i; |
| rootParameter.Descriptor.RegisterSpace = 2; |
| rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; // ALL is used for compute |
| rootParameters[parameterCount] = rootParameter; |
| d3d12ComputeRootSignature->uniformBufferRootIndex[i] = parameterCount; |
| parameterCount += 1; |
| } |
| |
| D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc; |
| rootSignatureDesc.NumParameters = parameterCount; |
| rootSignatureDesc.pParameters = rootParameters; |
| rootSignatureDesc.NumStaticSamplers = 0; |
| rootSignatureDesc.pStaticSamplers = NULL; |
| rootSignatureDesc.Flags = (D3D12_ROOT_SIGNATURE_FLAGS)0; |
| |
| ID3DBlob *serializedRootSignature; |
| ID3DBlob *errorBlob; |
| HRESULT res = renderer->D3D12SerializeRootSignature_func( |
| &rootSignatureDesc, |
| D3D_ROOT_SIGNATURE_VERSION_1, |
| &serializedRootSignature, |
| &errorBlob); |
| |
| if (FAILED(res)) { |
| if (errorBlob) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob)); |
| ID3D10Blob_Release(errorBlob); |
| } |
| D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature); |
| return NULL; |
| } |
| |
| ID3D12RootSignature *rootSignature; |
| |
| res = ID3D12Device_CreateRootSignature( |
| renderer->device, |
| 0, |
| ID3D10Blob_GetBufferPointer(serializedRootSignature), |
| ID3D10Blob_GetBufferSize(serializedRootSignature), |
| D3D_GUID(D3D_IID_ID3D12RootSignature), |
| (void **)&rootSignature); |
| |
| if (FAILED(res)) { |
| if (errorBlob) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create RootSignature"); |
| ID3D10Blob_Release(errorBlob); |
| } |
| D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature); |
| return NULL; |
| } |
| |
| d3d12ComputeRootSignature->handle = rootSignature; |
| return d3d12ComputeRootSignature; |
| } |
| |
| static SDL_GPUComputePipeline *D3D12_CreateComputePipeline( |
| SDL_GPURenderer *driverData, |
| SDL_GPUComputePipelineCreateInfo *pipelineCreateInfo) |
| { |
| D3D12Renderer *renderer = (D3D12Renderer *)driverData; |
| void *bytecode; |
| size_t bytecodeSize; |
| ID3D12PipelineState *pipelineState; |
| |
| if (!D3D12_INTERNAL_CreateShaderBytecode( |
| renderer, |
| SDL_GPU_SHADERSTAGE_COMPUTE, |
| pipelineCreateInfo->format, |
| pipelineCreateInfo->code, |
| pipelineCreateInfo->codeSize, |
| pipelineCreateInfo->entryPointName, |
| &bytecode, |
| &bytecodeSize)) { |
| return NULL; |
| } |
| |
| D3D12ComputeRootSignature *rootSignature = D3D12_INTERNAL_CreateComputeRootSignature( |
| renderer, |
| pipelineCreateInfo); |
| |
| if (rootSignature == NULL) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create root signature!"); |
| SDL_free(bytecode); |
| return NULL; |
| } |
| |
| D3D12_COMPUTE_PIPELINE_STATE_DESC pipelineDesc; |
| pipelineDesc.CS.pShaderBytecode = bytecode; |
| pipelineDesc.CS.BytecodeLength = bytecodeSize; |
| pipelineDesc.pRootSignature = rootSignature->handle; |
| pipelineDesc.CachedPSO.CachedBlobSizeInBytes = 0; |
| pipelineDesc.CachedPSO.pCachedBlob = NULL; |
| pipelineDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; |
| pipelineDesc.NodeMask = 0; |
| |
| HRESULT res = ID3D12Device_CreateComputePipelineState( |
| renderer->device, |
| &pipelineDesc, |
| D3D_GUID(D3D_IID_ID3D12PipelineState), |
| (void **)&pipelineState); |
| |
| if (FAILED(res)) { |
| D3D12_INTERNAL_LogError(renderer->device, "Could not create compute pipeline state", res); |
| SDL_free(bytecode); |
| return NULL; |
| } |
| |
| D3D12ComputePipeline *computePipeline = |
| (D3D12ComputePipeline *)SDL_calloc(1, sizeof(D3D12ComputePipeline)); |
| |
| if (!computePipeline) { |
| ID3D12PipelineState_Release(pipelineState); |
| SDL_free(bytecode); |
| return NULL; |
| } |
| |
| computePipeline->pipelineState = pipelineState; |
| computePipeline->rootSignature = rootSignature; |
| computePipeline->readOnlyStorageTextureCount = pipelineCreateInfo->readOnlyStorageTextureCount; |
| computePipeline->readOnlyStorageBufferCount = pipelineCreateInfo->readOnlyStorageBufferCount; |
| computePipeline->writeOnlyStorageTextureCount = pipelineCreateInfo->writeOnlyStorageTextureCount; |
| computePipeline->writeOnlyStorageBufferCount = pipelineCreateInfo->writeOnlyStorageBufferCount; |
| computePipeline->uniformBufferCount = pipelineCreateInfo->uniformBufferCount; |
| SDL_AtomicSet(&computePipeline->referenceCount, 0); |
| |
| return (SDL_GPUComputePipeline *)computePipeline; |
| } |
| |
| static bool D3D12_INTERNAL_ConvertRasterizerState(SDL_GPURasterizerState rasterizerState, D3D12_RASTERIZER_DESC *desc) |
| { |
| if (!desc) { |
| return false; |
| } |
| |
| desc->FillMode = SDLToD3D12_FillMode[rasterizerState.fillMode]; |
| desc->CullMode = SDLToD3D12_CullMode[rasterizerState.cullMode]; |
| |
| switch (rasterizerState.frontFace) { |
| case SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE: |
| desc->FrontCounterClockwise = TRUE; |
| break; |
| case SDL_GPU_FRONTFACE_CLOCKWISE: |
| desc->FrontCounterClockwise = FALSE; |
| break; |
| default: |
| return false; |
| } |
| |
| if (rasterizerState.depthBiasEnable) { |
| desc->DepthBias = SDL_lroundf(rasterizerState.depthBiasConstantFactor); |
| desc->DepthBiasClamp = rasterizerState.depthBiasClamp; |
| desc->SlopeScaledDepthBias = rasterizerState.depthBiasSlopeFactor; |
| } else { |
| desc->DepthBias = 0; |
| desc->DepthBiasClamp = 0.0f; |
| desc->SlopeScaledDepthBias = 0.0f; |
| } |
| |
| desc->DepthClipEnable = TRUE; |
| desc->MultisampleEnable = FALSE; |
| desc->AntialiasedLineEnable = FALSE; |
| desc->ForcedSampleCount = 0; |
| desc->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; |
| |
| return true; |
| } |
| |
| static bool D3D12_INTERNAL_ConvertBlendState(SDL_GPUGraphicsPipelineCreateInfo *pipelineInfo, D3D12_BLEND_DESC *blendDesc) |
| { |
| if (!blendDesc) { |
| return false; |
| } |
| |
| SDL_zerop(blendDesc); |
| blendDesc->AlphaToCoverageEnable = FALSE; |
| blendDesc->IndependentBlendEnable = FALSE; |
| |
| for (UINT i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) { |
| D3D12_RENDER_TARGET_BLEND_DESC rtBlendDesc; |
| rtBlendDesc.BlendEnable = FALSE; |
| rtBlendDesc.LogicOpEnable = FALSE; |
| rtBlendDesc.SrcBlend = D3D12_BLEND_ONE; |
| rtBlendDesc.DestBlend = D3D12_BLEND_ZERO; |
| rtBlendDesc.BlendOp = D3D12_BLEND_OP_ADD; |
| rtBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE; |
| rtBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO; |
| rtBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD; |
| rtBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP; |
| rtBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; |
| |
| // If attachmentInfo has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot |
| if (i < pipelineInfo->attachmentInfo.colorAttachmentCount) { |
| |
| SDL_GPUColorAttachmentBlendState sdlBlendState = pipelineInfo->attachmentInfo.colorAttachmentDescriptions[i].blendState; |
| |
| rtBlendDesc.BlendEnable = sdlBlendState.blendEnable; |
| rtBlendDesc.SrcBlend = SDLToD3D12_BlendFactor[sdlBlendState.srcColorBlendFactor]; |
| rtBlendDesc.DestBlend = SDLToD3D12_BlendFactor[sdlBlendState.dstColorBlendFactor]; |
| rtBlendDesc.BlendOp = SDLToD3D12_BlendOp[sdlBlendState.colorBlendOp]; |
| rtBlendDesc.SrcBlendAlpha = SDLToD3D12_BlendFactorAlpha[sdlBlendState.srcAlphaBlendFactor]; |
| rtBlendDesc.DestBlendAlpha = SDLToD3D12_BlendFactorAlpha[sdlBlendState.dstAlphaBlendFactor]; |
| rtBlendDesc.BlendOpAlpha = SDLToD3D12_BlendOp[sdlBlendState.alphaBlendOp]; |
| rtBlendDesc.RenderTargetWriteMask = sdlBlendState.colorWriteMask; |
| |
| if (i > 0) { |
| blendDesc->IndependentBlendEnable = TRUE; |
| } |
| } |
| |
| blendDesc->RenderTarget[i] = rtBlendDesc; |
| } |
| |
| return true; |
| } |
| |
| static bool D3D12_INTERNAL_ConvertDepthStencilState(SDL_GPUDepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC *desc) |
| { |
| if (desc == NULL) { |
| return false; |
| } |
| |
| desc->DepthEnable = depthStencilState.depthTestEnable == true ? TRUE : FALSE; |
| desc->DepthWriteMask = depthStencilState.depthWriteEnable == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; |
| desc->DepthFunc = SDLToD3D12_CompareOp[depthStencilState.compareOp]; |
| desc->StencilEnable = depthStencilState.stencilTestEnable == true ? TRUE : FALSE; |
| desc->StencilReadMask = depthStencilState.compareMask; |
| desc->StencilWriteMask = depthStencilState.writeMask; |
| |
| desc->FrontFace.StencilFailOp = SDLToD3D12_StencilOp[depthStencilState.frontStencilState.failOp]; |
| desc->FrontFace.StencilDepthFailOp = SDLToD3D12_StencilOp[depthStencilState.frontStencilState.depthFailOp]; |
| desc->FrontFace.StencilPassOp = SDLToD3D12_StencilOp[depthStencilState.frontStencilState.passOp]; |
| desc->FrontFace.StencilFunc = SDLToD3D12_CompareOp[depthStencilState.frontStencilState.compareOp]; |
| |
| desc->BackFace.StencilFailOp = SDLToD3D12_StencilOp[depthStencilState.backStencilState.failOp]; |
| desc->BackFace.StencilDepthFailOp = SDLToD3D12_StencilOp[depthStencilState.backStencilState.depthFailOp]; |
| desc->BackFace.StencilPassOp = SDLToD3D12_StencilOp[depthStencilState.backStencilState.passOp]; |
| desc->BackFace.StencilFunc = SDLToD3D12_CompareOp[depthStencilState.backStencilState.compareOp]; |
| |
| return true; |
| } |
| |
| static bool D3D12_INTERNAL_ConvertVertexInputState(SDL_GPUVertexInputState vertexInputState, D3D12_INPUT_ELEMENT_DESC *desc, const char *semantic) |
| { |
| if (desc == NULL || vertexInputState.vertexAttributeCount == 0) { |
| return false; |
| } |
| |
| for (Uint32 i = 0; i < vertexInputState.vertexAttributeCount; i += 1) { |
| SDL_GPUVertexAttribute attribute = vertexInputState.vertexAttributes[i]; |
| |
| desc[i].SemanticName = semantic; |
| desc[i].SemanticIndex = attribute.location; |
| desc[i].Format = SDLToD3D12_VertexFormat[attribute.format]; |
| desc[i].InputSlot = attribute.binding; |
| desc[i].AlignedByteOffset = attribute.offset; |
| desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertexBindings[attribute.binding].inputRate]; |
| desc[i].InstanceDataStepRate = (vertexInputState.vertexBindings[attribute.binding].inputRate == SDL_GPU_VERTEXINPUTRATE_INSTANCE) ? vertexInputState.vertexBindings[attribute.binding].instanceStepRate : 0; |
| } |
| |
| return true; |
| } |
| |
| static void D3D12_INTERNAL_AssignCpuDescriptorHandle( |
| D3D12Renderer *renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE heapType, |
| D3D12CPUDescriptor *cpuDescriptor) |
| { |
| D3D12DescriptorHeap *heap = renderer->stagingDescriptorHeaps[heapType]; |
| Uint32 descriptorIndex; |
| |
| cpuDescriptor->heap = heap; |
| |
| SDL_LockMutex(renderer->stagingDescriptorHeapLock); |
| |
| if (heap->inactiveDescriptorCount > 0) { |
| descriptorIndex = heap->inactiveDescriptorIndices[heap->inactiveDescriptorCount - 1]; |
| heap->inactiveDescriptorCount -= 1; |
| } else if (heap->currentDescriptorIndex < heap->maxDescriptors) { |
| descriptorIndex = heap->currentDescriptorIndex; |
| heap->currentDescriptorIndex += 1; |
| } else { |
| cpuDescriptor->cpuHandleIndex = SDL_MAX_UINT32; |
| cpuDescriptor->cpuHandle.ptr = 0; |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Out of CPU descriptor handles, many bad things are going to happen!"); |
| SDL_UnlockMutex(renderer->stagingDescriptorHeapLock); |
| return; |
| } |
| |
| SDL_UnlockMutex(renderer->stagingDescriptorHeapLock); |
| |
| cpuDescriptor->cpuHandleIndex = descriptorIndex; |
| cpuDescriptor->cpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (descriptorIndex * heap->descriptorSize); |
| } |
| |
| static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline( |
| SDL_GPURenderer *driverData, |
| SDL_GPUGraphicsPipelineCreateInfo *pipelineCreateInfo) |
| { |
| D3D12Renderer *renderer = (D3D12Renderer *)driverData; |
| D3D12Shader *vertShader = (D3D12Shader *)pipelineCreateInfo->vertexShader; |
| D3D12Shader *fragShader = (D3D12Shader *)pipelineCreateInfo->fragmentShader; |
| |
| D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc; |
| SDL_zero(psoDesc); |
| psoDesc.VS.pShaderBytecode = vertShader->bytecode; |
| psoDesc.VS.BytecodeLength = vertShader->bytecodeSize; |
| psoDesc.PS.pShaderBytecode = fragShader->bytecode; |
| psoDesc.PS.BytecodeLength = fragShader->bytecodeSize; |
| |
| D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; |
| if (pipelineCreateInfo->vertexInputState.vertexAttributeCount > 0) { |
| psoDesc.InputLayout.pInputElementDescs = inputElementDescs; |
| psoDesc.InputLayout.NumElements = pipelineCreateInfo->vertexInputState.vertexAttributeCount; |
| D3D12_INTERNAL_ConvertVertexInputState(pipelineCreateInfo->vertexInputState, inputElementDescs, renderer->semantic); |
| } |
| |
| psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; |
| |
| if (!D3D12_INTERNAL_ConvertRasterizerState(pipelineCreateInfo->rasterizerState, &psoDesc.RasterizerState)) { |
| return NULL; |
| } |
| if (!D3D12_INTERNAL_ConvertBlendState(pipelineCreateInfo, &psoDesc.BlendState)) { |
| return NULL; |
| } |
| if (!D3D12_INTERNAL_ConvertDepthStencilState(pipelineCreateInfo->depthStencilState, &psoDesc.DepthStencilState)) { |
| return NULL; |
| } |
| |
| D3D12GraphicsPipeline *pipeline = (D3D12GraphicsPipeline *)SDL_calloc(1, sizeof(D3D12GraphicsPipeline)); |
| if (!pipeline) { |
| return NULL; |
| } |
| |
| psoDesc.SampleMask = UINT_MAX; |
| psoDesc.SampleDesc.Count = SDLToD3D12_SampleCount[pipelineCreateInfo->multisampleState.sampleCount]; |
| psoDesc.SampleDesc.Quality = 0; |
| |
| psoDesc.DSVFormat = SDLToD3D12_TextureFormat[pipelineCreateInfo->attachmentInfo.depthStencilFormat]; |
| psoDesc.NumRenderTargets = pipelineCreateInfo->attachmentInfo.colorAttachmentCount; |
| for (uint32_t i = 0; i < pipelineCreateInfo->attachmentInfo.colorAttachmentCount; i += 1) { |
| psoDesc.RTVFormats[i] = SDLToD3D12_TextureFormat[pipelineCreateInfo->attachmentInfo.colorAttachmentDescriptions[i].format]; |
| } |
| |
| // Assuming some default values or further initialization |
| psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; |
| psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; |
| psoDesc.CachedPSO.pCachedBlob = NULL; |
| |
| psoDesc.NodeMask = 0; |
| |
| D3D12GraphicsRootSignature *rootSignature = D3D12_INTERNAL_CreateGraphicsRootSignature( |
| renderer, |
| vertShader, |
| fragShader); |
| |
| if (rootSignature == NULL) { |
| SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not create root signature!"); |
| D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline); |
| return NULL; |
| } |
| pipeline->rootSignature = rootSignature; |
| |
| psoDesc.pRootSignature = rootSignature->handle; |
| ID3D12PipelineState *pipelineState; |
| |
| HRESULT res = ID3D12Device_CreateGraphicsPipelineState( |
| renderer->device, |
| &psoDesc, |
| D3D_GUID(D3D_IID_ID3D12PipelineState), |
| (void **)&pipelineState); |
| if (FAILED(res)) { |
| D3D12_INTERNAL_LogError(renderer->device, "Could not create graphics pipeline state", res); |
| D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline); |
| return NULL; |
| } |
| |
| pipeline->pipelineState = pipelineState; |
| |
| for (Uint32 i = 0; i < pipelineCreateInfo->vertexInputState.vertexBindingCount; i += 1) { |
| pipeline->vertexStrides[i] = pipelineCreateInfo->vertexInputState.vertexBindings[i].stride; |
| } |
| |
| pipeline->primitiveType = pipelineCreateInfo->primitiveType; |
| pipeline->blendConstants[0] = pipelineCreateInfo->blendConstants[0]; |
| pipeline->blendConstants[1] = pipelineCreateInfo->blendConstants[1]; |
| pipeline->blendConstants[2] = pipelineCreateInfo->blendConstants[2]; |
| pipeline->blendConstants[3] = pipelineCreateInfo->blendConstants[3]; |
| pipeline->stencilRef = pipelineCreateInfo->depthStencilState.reference; |
| |
| pipeline->vertexSamplerCount = vertShader->samplerCount; |
| pipeline->vertexStorageTextureCount = vertShader->storageTextureCount; |
| pipeline->vertexStorageBufferCount = vertShader->storageBufferCount; |
| pipeline->vertexUniformBufferCount = vertShader->uniformBufferCount; |
| |
| pipeline->fragmentSamplerCount = fragShader->samplerCount; |
| pipeline->fragmentStorageTextureCount = fragShader->storageTextureCount; |
| pipeline->fragmentStorageBufferCount = fragShader->storageBufferCount; |
| pipeline->fragmentUniformBufferCount = fragShader->uniformBufferCount; |
| |
| SDL_AtomicSet(&pipeline->referenceCount, 0); |
| return (SDL_GPUGraphicsPipeline *)pipeline; |
| } |
| |
| static SDL_GPUSampler *D3D12_CreateSampler( |
| SDL_GPURenderer *driverData, |
| SDL_GPUSamplerCreateInfo *samplerCreateInfo) |
| { |
| D3D12Renderer *renderer = (D3D12Renderer *)driverData; |
| D3D12Sampler *sampler = (D3D12Sampler *)SDL_calloc(1, sizeof(D3D12Sampler)); |
| if (!sampler) { |
| return NULL; |
| } |
| D3D12_SAMPLER_DESC samplerDesc; |
| |
| samplerDesc.Filter = SDLToD3D12_Filter( |
| samplerCreateInfo->minFilter, |
| samplerCreateInfo->magFilter, |
| samplerCreateInfo->mipmapMode, |
| samplerCreateInfo->compareEnable, |
| samplerCreateInfo->anisotropyEnable); |
| samplerDesc.AddressU = SDLToD3D12_SamplerAddressMode[samplerCreateInfo->addressModeU]; |
| samplerDesc.AddressV = SDLToD3D12_SamplerAddressMode[samplerCreateInfo->addressModeV]; |
| samplerDesc.AddressW = SDLToD3D12_SamplerAddressMode[samplerCreateInfo->addressModeW]; |
| samplerDesc.MaxAnisotropy = (Uint32)samplerCreateInfo->maxAnisotropy; |
| samplerDesc.ComparisonFunc = SDLToD3D12_CompareOp[samplerCreateInfo->compareOp]; |
| samplerDesc.MinLOD = samplerCreateInfo->minLod; |
| samplerDesc.MaxLOD = samplerCreateInfo->maxLod; |
| samplerDesc.MipLODBias = samplerCreateInfo->mipLodBias; |
| samplerDesc.BorderColor[0] = 0; |
| samplerDesc.BorderColor[1] = 0; |
| samplerDesc.BorderColor[2] = 0; |
| samplerDesc.BorderColor[3] = 0; |
| |
| D3D12_INTERNAL_AssignCpuDescriptorHandle( |
| renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, |
| &sampler->handle); |
| |
| ID3D12Device_CreateSampler( |
| renderer->device, |
| &samplerDesc, |
| sampler->handle.cpuHandle); |
| |
| sampler->createInfo = *samplerCreateInfo; |
| SDL_AtomicSet(&sampler->referenceCount, 0); |
| return (SDL_GPUSampler *)sampler; |
| } |
| |
| static SDL_GPUShader *D3D12_CreateShader( |
| SDL_GPURenderer *driverData, |
| SDL_GPUShaderCreateInfo *shaderCreateInfo) |
| { |
| D3D12Renderer *renderer = (D3D12Renderer *)driverData; |
| void *bytecode; |
| size_t bytecodeSize; |
| D3D12Shader *shader; |
| |
| if (!D3D12_INTERNAL_CreateShaderBytecode( |
| renderer, |
| shaderCreateInfo->stage, |
| shaderCreateInfo->format, |
| shaderCreateInfo->code, |
| shaderCreateInfo->codeSize, |
| shaderCreateInfo->entryPointName, |
| &bytecode, |
| &bytecodeSize)) { |
| return NULL; |
| } |
| shader = (D3D12Shader *)SDL_calloc(1, sizeof(D3D12Shader)); |
| if (!shader) { |
| SDL_free(bytecode); |
| return NULL; |
| } |
| shader->samplerCount = shaderCreateInfo->samplerCount; |
| shader->storageBufferCount = shaderCreateInfo->storageBufferCount; |
| shader->storageTextureCount = shaderCreateInfo->storageTextureCount; |
| shader->uniformBufferCount = shaderCreateInfo->uniformBufferCount; |
| |
| shader->bytecode = bytecode; |
| shader->bytecodeSize = bytecodeSize; |
| |
| return (SDL_GPUShader *)shader; |
| } |
| |
| static D3D12Texture *D3D12_INTERNAL_CreateTexture( |
| D3D12Renderer *renderer, |
| SDL_GPUTextureCreateInfo *textureCreateInfo, |
| bool isSwapchainTexture) |
| { |
| D3D12Texture *texture; |
| ID3D12Resource *handle; |
| D3D12_HEAP_PROPERTIES heapProperties; |
| D3D12_HEAP_FLAGS heapFlags = (D3D12_HEAP_FLAGS)0; |
| D3D12_RESOURCE_DESC desc; |
| D3D12_RESOURCE_FLAGS resourceFlags = (D3D12_RESOURCE_FLAGS)0; |
| D3D12_RESOURCE_STATES initialState = (D3D12_RESOURCE_STATES)0; |
| D3D12_CLEAR_VALUE clearValue; |
| bool useClearValue = false; |
| HRESULT res; |
| |
| texture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture)); |
| if (!texture) { |
| return NULL; |
| } |
| |
| Uint32 layerCount = textureCreateInfo->type == SDL_GPU_TEXTURETYPE_3D ? 1 : textureCreateInfo->layerCountOrDepth; |
| Uint32 depth = textureCreateInfo->type == SDL_GPU_TEXTURETYPE_3D ? textureCreateInfo->layerCountOrDepth : 1; |
| |
| if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT) { |
| resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; |
| useClearValue = true; |
| clearValue.Color[0] = SDL_GetFloatProperty(textureCreateInfo->props, SDL_PROP_GPU_CREATETEXTURE_D3D12_CLEAR_R_FLOAT, 0); |
| clearValue.Color[1] = SDL_GetFloatProperty(textureCreateInfo->props, SDL_PROP_GPU_CREATETEXTURE_D3D12_CLEAR_G_FLOAT, 0); |
| clearValue.Color[2] = SDL_GetFloatProperty(textureCreateInfo->props, SDL_PROP_GPU_CREATETEXTURE_D3D12_CLEAR_B_FLOAT, 0); |
| clearValue.Color[3] = SDL_GetFloatProperty(textureCreateInfo->props, SDL_PROP_GPU_CREATETEXTURE_D3D12_CLEAR_A_FLOAT, 0); |
| } |
| |
| if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT) { |
| resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; |
| useClearValue = true; |
| clearValue.DepthStencil.Depth = SDL_GetFloatProperty(textureCreateInfo->props, SDL_PROP_GPU_CREATETEXTURE_D3D12_CLEAR_DEPTH_FLOAT, 0); |
| clearValue.DepthStencil.Stencil = (UINT8)SDL_GetNumberProperty(textureCreateInfo->props, SDL_PROP_GPU_CREATETEXTURE_D3D12_CLEAR_STENCIL_UINT8, 0); |
| } |
| |
| if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT) { |
| resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; |
| } |
| |
| heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; |
| heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; |
| heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; |
| heapProperties.CreationNodeMask = 0; // We don't do multi-adapter operation |
| heapProperties.VisibleNodeMask = 0; // We don't do multi-adapter operation |
| |
| heapFlags = isSwapchainTexture ? D3D12_HEAP_FLAG_ALLOW_DISPLAY : D3D12_HEAP_FLAG_NONE; |
| |
| if (textureCreateInfo->type != SDL_GPU_TEXTURETYPE_3D) { |
| desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; |
| desc.Alignment = isSwapchainTexture ? 0 : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; |
| desc.Width = textureCreateInfo->width; |
| desc.Height = textureCreateInfo->height; |
| desc.DepthOrArraySize = textureCreateInfo->layerCountOrDepth; |
| desc.MipLevels = textureCreateInfo->levelCount; |
| desc.Format = SDLToD3D12_TextureFormat[textureCreateInfo->format]; |
| desc.SampleDesc.Count = 1; |
| desc.SampleDesc.Quality = 0; |
| desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // Apparently this is the most efficient choice |
| desc.Flags = resourceFlags; |
| } else { |
| desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; |
| desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT; |
| desc.Width = textureCreateInfo->width; |
| desc.Height = textureCreateInfo->height; |
| desc.DepthOrArraySize = textureCreateInfo->layerCountOrDepth; |
| desc.MipLevels = textureCreateInfo->levelCount; |
| desc.Format = SDLToD3D12_TextureFormat[textureCreateInfo->format]; |
| desc.SampleDesc.Count = 1; |
| desc.SampleDesc.Quality = 0; |
| desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; |
| desc.Flags = resourceFlags; |
| } |
| |
| initialState = isSwapchainTexture ? D3D12_RESOURCE_STATE_PRESENT : D3D12_INTERNAL_DefaultTextureResourceState(textureCreateInfo->usageFlags); |
| clearValue.Format = desc.Format; |
| |
| res = ID3D12Device_CreateCommittedResource( |
| renderer->device, |
| &heapProperties, |
| heapFlags, |
| &desc, |
| initialState, |
| useClearValue ? &clearValue : NULL, |
| D3D_GUID(D3D_IID_ID3D12Resource), |
| (void **)&handle); |
| if (FAILED(res)) { |
| D3D12_INTERNAL_LogError(renderer->device, "Failed to create texture!", res); |
| D3D12_INTERNAL_DestroyTexture(renderer, texture); |
| return NULL; |
| } |
| |
| texture->resource = handle; |
| |
| // Create the SRV if applicable |
| if ((textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_SAMPLER_BIT) || |
| (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ_BIT) || |
| (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ_BIT)) { |
| D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; |
| |
| D3D12_INTERNAL_AssignCpuDescriptorHandle( |
| renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, |
| &texture->srvHandle); |
| |
| srvDesc.Format = SDLToD3D12_TextureFormat[textureCreateInfo->format]; |
| srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; |
| |
| if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_CUBE) { |
| srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE; |
| srvDesc.TextureCube.MipLevels = textureCreateInfo->levelCount; |
| srvDesc.TextureCube.MostDetailedMip = 0; |
| srvDesc.TextureCube.ResourceMinLODClamp = 0; |
| } else if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) { |
| srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY; |
| srvDesc.Texture2DArray.MipLevels = textureCreateInfo->levelCount; |
| srvDesc.Texture2DArray.MostDetailedMip = 0; |
| srvDesc.Texture2DArray.FirstArraySlice = 0; |
| srvDesc.Texture2DArray.ArraySize = layerCount; |
| srvDesc.Texture2DArray.ResourceMinLODClamp = 0; |
| srvDesc.Texture2DArray.PlaneSlice = 0; |
| } else if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_3D) { |
| srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D; |
| srvDesc.Texture3D.MipLevels = textureCreateInfo->levelCount; |
| srvDesc.Texture3D.MostDetailedMip = 0; |
| srvDesc.Texture3D.ResourceMinLODClamp = 0; // default behavior |
| } else { |
| srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; |
| srvDesc.Texture2D.MipLevels = textureCreateInfo->levelCount; |
| srvDesc.Texture2D.MostDetailedMip = 0; |
| srvDesc.Texture2D.PlaneSlice = 0; |
| srvDesc.Texture2D.ResourceMinLODClamp = 0; // default behavior |
| } |
| |
| ID3D12Device_CreateShaderResourceView( |
| renderer->device, |
| handle, |
| &srvDesc, |
| texture->srvHandle.cpuHandle); |
| } |
| |
| SDL_AtomicSet(&texture->referenceCount, 0); |
| |
| texture->subresourceCount = textureCreateInfo->levelCount * layerCount; |
| texture->subresources = (D3D12TextureSubresource *)SDL_calloc( |
| texture->subresourceCount, sizeof(D3D12TextureSubresource)); |
| if (!texture->subresources) { |
| D3D12_INTERNAL_DestroyTexture(renderer, texture); |
| return NULL; |
| } |
| for (Uint32 layerIndex = 0; layerIndex < layerCount; layerIndex += 1) { |
| for (Uint32 levelIndex = 0; levelIndex < textureCreateInfo->levelCount; levelIndex += 1) { |
| Uint32 subresourceIndex = D3D12_INTERNAL_CalcSubresource( |
| levelIndex, |
| layerIndex, |
| textureCreateInfo->levelCount); |
| |
| texture->subresources[subresourceIndex].parent = texture; |
| texture->subresources[subresourceIndex].layer = layerIndex; |
| texture->subresources[subresourceIndex].level = levelIndex; |
| texture->subresources[subresourceIndex].depth = depth; |
| texture->subresources[subresourceIndex].index = subresourceIndex; |
| |
| texture->subresources[subresourceIndex].rtvHandles = NULL; |
| texture->subresources[subresourceIndex].uavHandle.heap = NULL; |
| texture->subresources[subresourceIndex].dsvHandle.heap = NULL; |
| |
| // Create RTV if needed |
| if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET_BIT) { |
| texture->subresources[subresourceIndex].rtvHandles = (D3D12CPUDescriptor *)SDL_calloc(depth, sizeof(D3D12CPUDescriptor)); |
| |
| for (Uint32 depthIndex = 0; depthIndex < depth; depthIndex += 1) { |
| D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; |
| |
| D3D12_INTERNAL_AssignCpuDescriptorHandle( |
| renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE_RTV, |
| &texture->subresources[subresourceIndex].rtvHandles[depthIndex]); |
| |
| rtvDesc.Format = SDLToD3D12_TextureFormat[textureCreateInfo->format]; |
| |
| if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || textureCreateInfo->type == SDL_GPU_TEXTURETYPE_CUBE) { |
| rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY; |
| rtvDesc.Texture2DArray.MipSlice = levelIndex; |
| rtvDesc.Texture2DArray.FirstArraySlice = layerIndex; |
| rtvDesc.Texture2DArray.ArraySize = 1; |
| rtvDesc.Texture2DArray.PlaneSlice = 0; |
| } else if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_3D) { |
| rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D; |
| rtvDesc.Texture3D.MipSlice = levelIndex; |
| rtvDesc.Texture3D.FirstWSlice = depthIndex; |
| rtvDesc.Texture3D.WSize = 1; |
| } else { |
| rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; |
| rtvDesc.Texture2D.MipSlice = levelIndex; |
| rtvDesc.Texture2D.PlaneSlice = 0; |
| } |
| |
| ID3D12Device_CreateRenderTargetView( |
| renderer->device, |
| texture->resource, |
| &rtvDesc, |
| texture->subresources[subresourceIndex].rtvHandles[depthIndex].cpuHandle); |
| } |
| } |
| |
| // Create DSV if needed |
| if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET_BIT) { |
| D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc; |
| |
| D3D12_INTERNAL_AssignCpuDescriptorHandle( |
| renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE_DSV, |
| &texture->subresources[subresourceIndex].dsvHandle); |
| |
| dsvDesc.Format = SDLToD3D12_TextureFormat[textureCreateInfo->format]; |
| dsvDesc.Flags = (D3D12_DSV_FLAGS)0; |
| dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; |
| dsvDesc.Texture2D.MipSlice = levelIndex; |
| |
| ID3D12Device_CreateDepthStencilView( |
| renderer->device, |
| texture->resource, |
| &dsvDesc, |
| texture->subresources[subresourceIndex].dsvHandle.cpuHandle); |
| } |
| |
| // Create subresource UAV if necessary |
| if (textureCreateInfo->usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE_BIT) { |
| D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; |
| |
| D3D12_INTERNAL_AssignCpuDescriptorHandle( |
| renderer, |
| D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, |
| &texture->subresources[subresourceIndex].uavHandle); |
| |
| uavDesc.Format = SDLToD3D12_TextureFormat[textureCreateInfo->format]; |
| |
| if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || textureCreateInfo->type == SDL_GPU_TEXTURETYPE_CUBE) { |
| uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY; |
| uavDesc.Texture2DArray.MipSlice = levelIndex; |
| uavDesc.Texture2DArray.FirstArraySlice = layerIndex; |
| uavDesc.Texture2DArray.ArraySize = 1; |
| } else if (textureCreateInfo->type == SDL_GPU_TEXTURETYPE_3D) { |
| uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE3D; |
| uavDesc.Texture3D.MipSlice = levelIndex; |
| uavDesc.Texture3D.FirstWSlice = 0; |
| uavDesc.Texture3D.WSize = depth; |
| } else { |
| uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; |
| uavDesc.Texture2D.MipSlice = levelIndex; |
| uavDesc.Texture2D.PlaneSlice = 0; |
| } |
| |
| ID3D12Device_CreateUnorderedAccessView( |
| renderer->device, |
| texture->resource, |
| NULL, |
| &uavDesc, |
| texture->subresources[subresourceIndex].uavHandle.cpuHandle); |
| } |
| } |
| } |
| |
| return texture; |
| } |
| |
| static SDL_GPUTexture *D3D12_CreateTexture( |
| SDL_GPURenderer *driverData, |
| SDL_GPUTextureCreateInfo *textureCreateInfo) |
| { |
| D3D12TextureContainer *container = (D3D12TextureContainer *)SDL_calloc(1, sizeof(D3D12TextureContainer)); |
| if (!container) { |
| return NULL; |
| } |
| |
| container->header.info = *textureCreateInfo; |
| container->textureCapacity = 1; |
| container->textureCount = 1; |
| container->textures = (D3D12Texture **)SDL_calloc( |
| container->textureCapacity, sizeof(D3D12Texture *)); |
| |
| if (!container->textures) { |
| SDL_free(container); |
| return NULL; |
| } |
| |
| container->debugName = NULL; |
|