#include "SDL_internal.h"
#ifdef SDL_GPU_D3D12
#include "../../events/SDL_windowevents_c.h"
#include "../../core/windows/SDL_windows.h"
#include "../../video/directx/SDL_d3d12.h"
#include "../SDL_sysgpu.h"
#ifdef __IDXGIInfoQueue_INTERFACE_DEFINED__
#define HAVE_IDXGIINFOQUEUE
#endif
#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
#define g_BlitFromCubeArray D3D12_BlitFromCubeArray
#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
#undef g_BlitFromCubeArray
#define SET_ERROR(fmt, msg) \
do { \
if (renderer->debug_mode) { \
SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \
} \
SDL_SetError(fmt, msg); \
} while (0)
#define SET_ERROR_AND_RETURN(fmt, msg, ret) \
do { \
if (renderer->debug_mode) { \
SDL_LogError(SDL_LOG_CATEGORY_GPU, fmt, msg); \
} \
SDL_SetError(fmt, msg); \
return ret; \
} while (0)
#define SET_STRING_ERROR_AND_RETURN(msg, ret) SET_ERROR_AND_RETURN("%s", msg, ret)
#define CHECK_D3D12_ERROR_AND_RETURN(msg, ret) \
do { \
if (FAILED(res)) { \
D3D12_INTERNAL_SetError(renderer, msg, res); \
return (ret); \
} \
} while (0)
#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"
#define USE_PIX_RUNTIME
#define WINPIXEVENTRUNTIME_DLL "WinPixEventRuntime.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 D3D12_GET_INTERFACE_FUNC "D3D12GetInterface"
#define WINDOW_PROPERTY_DATA "SDL.internal.gpu.d3d12.data"
#define D3D_FEATURE_LEVEL_CHOICE D3D_FEATURE_LEVEL_11_0
#define D3D_FEATURE_LEVEL_CHOICE_STR "11_0"
#define MAX_ROOT_SIGNATURE_PARAMETERS 64
#define D3D12_FENCE_UNSIGNALED_VALUE 0
#define D3D12_FENCE_SIGNAL_VALUE 1
#define VIEW_GPU_DESCRIPTOR_COUNT 65536
#define SAMPLER_GPU_DESCRIPTOR_COUNT 2048
#define STAGING_HEAP_DESCRIPTOR_COUNT 1024
#define SDL_GPU_SHADERSTAGE_COMPUTE (SDL_GPUShaderStage)2
#ifdef _WIN32
#define HRESULT_FMT "(0x%08lX)"
#else
#define HRESULT_FMT "(0x%08X)"
#endif
typedef HRESULT (WINAPI *pfnCreateDXGIFactory1)(const GUID *riid, void **ppFactory);
typedef HRESULT (WINAPI *pfnDXGIGetDebugInterface)(const GUID *riid, void **ppDebug);
#ifdef USE_PIX_RUNTIME
#define PIX_BEGIN_EVENT_ON_COMMAND_LIST_FUNC "PIXBeginEventOnCommandList"
#define PIX_END_EVENT_ON_COMMAND_LIST_FUNC "PIXEndEventOnCommandList"
#define PIX_SET_MARKER_ON_COMMAND_LIST_FUNC "PIXSetMarkerOnCommandList"
typedef void(WINAPI* pfnBeginEventOnCommandList)(ID3D12GraphicsCommandList* commandList, UINT64 color, _In_ PCSTR formatString);
typedef void(WINAPI* pfnEndEventOnCommandList)(ID3D12GraphicsCommandList* commandList);
typedef void(WINAPI* pfnSetMarkerOnCommandList)(ID3D12GraphicsCommandList* commandList, UINT64 color, _In_ PCSTR formatString);
#endif
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 } };
#else
static const IID D3D_IID_IDXGIDevice = { 0x54ec77fa, 0x1377, 0x44e6, { 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8, 0x4c } };
#endif
static const IID D3D_IID_IDXGISwapChain3 = { 0x94d99bdb, 0xf1f8, 0x4ab0, { 0xb2, 0x36, 0x7d, 0xa0, 0x17, 0x0e, 0xda, 0xb1 } };
#ifdef HAVE_IDXGIINFOQUEUE
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 } };
#endif
static const GUID D3D_IID_DXGI_DEBUG_ALL = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x08 } };
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 } };
static const IID D3D_IID_ID3D12InfoQueue1 = { 0x2852dd88, 0xb484, 0x4c0c, { 0xb6, 0xb1, 0x67, 0x16, 0x85, 0x00, 0xe6, 0x00 } };
static const GUID D3D_CLSID_ID3D12SDKConfiguration = { 0x7cda6aca, 0xa03e, 0x49c8, { 0x94, 0x58, 0x03, 0x34, 0xd2, 0x0e, 0x07, 0xce } };
static const GUID D3D_CLSID_ID3D12Debug = { 0xf2352aeb, 0xdd84, 0x49fe, { 0xb9, 0x7b, 0xa9, 0xdc, 0xfd, 0xcc, 0x1b, 0x4f } };
static const IID D3D_IID_ID3D12SDKConfiguration = { 0xe9eb5314, 0x33aa, 0x42b2, { 0xa7, 0x18, 0xd7, 0x7f, 0x58, 0xb1, 0xf1, 0xc7 } };
static const IID D3D_IID_ID3D12SDKConfiguration1 = { 0x8aaf9303, 0xad25, 0x48b9, { 0x9a, 0x57, 0xd9, 0xc3, 0x7e, 0x00, 0x9d, 0x9f } };
static const IID D3D_IID_ID3D12DeviceFactory = { 0x61f307d3, 0xd34e, 0x4e7c, { 0x83, 0x74, 0x3b, 0xa4, 0xde, 0x23, 0xcc, 0xcb } };
typedef enum D3D12BufferType
{
D3D12_BUFFER_TYPE_GPU,
D3D12_BUFFER_TYPE_UNIFORM,
D3D12_BUFFER_TYPE_UPLOAD,
D3D12_BUFFER_TYPE_DOWNLOAD
} D3D12BufferType;
static SDL_GPUTextureFormat SwapchainCompositionToSDLTextureFormat[] = {
SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT, SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM, };
static DXGI_FORMAT SwapchainCompositionToTextureFormat[] = {
DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R10G10B10A2_UNORM, };
static DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = {
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 };
static D3D12_BLEND SDLToD3D12_BlendFactor[] = {
D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_SRC_COLOR, D3D12_BLEND_INV_SRC_COLOR, D3D12_BLEND_DEST_COLOR, D3D12_BLEND_INV_DEST_COLOR, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_DEST_ALPHA, D3D12_BLEND_INV_DEST_ALPHA, D3D12_BLEND_BLEND_FACTOR, D3D12_BLEND_INV_BLEND_FACTOR, D3D12_BLEND_SRC_ALPHA_SAT, };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendFactor, SDL_arraysize(SDLToD3D12_BlendFactor) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE);
static D3D12_BLEND SDLToD3D12_BlendFactorAlpha[] = {
D3D12_BLEND_ZERO, D3D12_BLEND_ZERO, D3D12_BLEND_ONE, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_DEST_ALPHA, D3D12_BLEND_INV_DEST_ALPHA, D3D12_BLEND_SRC_ALPHA, D3D12_BLEND_INV_SRC_ALPHA, D3D12_BLEND_DEST_ALPHA, D3D12_BLEND_INV_DEST_ALPHA, D3D12_BLEND_BLEND_FACTOR, D3D12_BLEND_INV_BLEND_FACTOR, D3D12_BLEND_SRC_ALPHA_SAT, };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendFactorAlpha, SDL_arraysize(SDLToD3D12_BlendFactorAlpha) == SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE);
static D3D12_BLEND_OP SDLToD3D12_BlendOp[] = {
D3D12_BLEND_OP_ADD, D3D12_BLEND_OP_ADD, D3D12_BLEND_OP_SUBTRACT, D3D12_BLEND_OP_REV_SUBTRACT, D3D12_BLEND_OP_MIN, D3D12_BLEND_OP_MAX };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_BlendOp, SDL_arraysize(SDLToD3D12_BlendOp) == SDL_GPU_BLENDOP_MAX_ENUM_VALUE);
static DXGI_FORMAT SDLToD3D12_TextureFormat[] = {
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R10G10B10A2_UNORM, DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC6H_SF16, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16_FLOAT, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R16_SINT, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, DXGI_FORMAT_BC1_UNORM_SRGB, DXGI_FORMAT_BC2_UNORM_SRGB, DXGI_FORMAT_BC3_UNORM_SRGB, DXGI_FORMAT_BC7_UNORM_SRGB, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R24_UNORM_X8_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TextureFormat, SDL_arraysize(SDLToD3D12_TextureFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
static DXGI_FORMAT SDLToD3D12_DepthFormat[] = {
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_D24_UNORM_S8_UINT, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_DepthFormat, SDL_arraysize(SDLToD3D12_DepthFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
static DXGI_FORMAT SDLToD3D12_TypelessFormat[] = {
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_TypelessFormat, SDL_arraysize(SDLToD3D12_TypelessFormat) == SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE);
static D3D12_COMPARISON_FUNC SDLToD3D12_CompareOp[] = {
D3D12_COMPARISON_FUNC_NEVER, D3D12_COMPARISON_FUNC_NEVER, D3D12_COMPARISON_FUNC_LESS, D3D12_COMPARISON_FUNC_EQUAL, D3D12_COMPARISON_FUNC_LESS_EQUAL, D3D12_COMPARISON_FUNC_GREATER, D3D12_COMPARISON_FUNC_NOT_EQUAL, D3D12_COMPARISON_FUNC_GREATER_EQUAL, D3D12_COMPARISON_FUNC_ALWAYS };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_CompareOp, SDL_arraysize(SDLToD3D12_CompareOp) == SDL_GPU_COMPAREOP_MAX_ENUM_VALUE);
static D3D12_STENCIL_OP SDLToD3D12_StencilOp[] = {
D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_ZERO, D3D12_STENCIL_OP_REPLACE, D3D12_STENCIL_OP_INCR_SAT, D3D12_STENCIL_OP_DECR_SAT, D3D12_STENCIL_OP_INVERT, D3D12_STENCIL_OP_INCR, D3D12_STENCIL_OP_DECR };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_StencilOp, SDL_arraysize(SDLToD3D12_StencilOp) == SDL_GPU_STENCILOP_MAX_ENUM_VALUE);
static D3D12_CULL_MODE SDLToD3D12_CullMode[] = {
D3D12_CULL_MODE_NONE, D3D12_CULL_MODE_FRONT, D3D12_CULL_MODE_BACK };
static D3D12_FILL_MODE SDLToD3D12_FillMode[] = {
D3D12_FILL_MODE_SOLID, D3D12_FILL_MODE_WIREFRAME };
static D3D12_INPUT_CLASSIFICATION SDLToD3D12_InputRate[] = {
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA };
static DXGI_FORMAT SDLToD3D12_VertexFormat[] = {
DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R32_SINT, DXGI_FORMAT_R32G32_SINT, DXGI_FORMAT_R32G32B32_SINT, DXGI_FORMAT_R32G32B32A32_SINT, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32G32_UINT, DXGI_FORMAT_R32G32B32_UINT, DXGI_FORMAT_R32G32B32A32_UINT, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT, DXGI_FORMAT_R8G8_SINT, DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8B8A8_SNORM, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R16G16_SINT, DXGI_FORMAT_R16G16B16A16_SINT, DXGI_FORMAT_R16G16_UINT, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16_SNORM, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16_UNORM, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16_FLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT };
SDL_COMPILE_TIME_ASSERT(SDLToD3D12_VertexFormat, SDL_arraysize(SDLToD3D12_VertexFormat) == SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE);
static Uint32 SDLToD3D12_SampleCount[] = {
1, 2, 4, 8, };
static D3D12_PRIMITIVE_TOPOLOGY SDLToD3D12_PrimitiveType[] = {
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, D3D_PRIMITIVE_TOPOLOGY_LINELIST, D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, D3D_PRIMITIVE_TOPOLOGY_POINTLIST };
static D3D12_PRIMITIVE_TOPOLOGY_TYPE SDLToD3D12_PrimitiveTopologyType[] = {
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE, D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT };
static D3D12_TEXTURE_ADDRESS_MODE SDLToD3D12_SamplerAddressMode[] = {
D3D12_TEXTURE_ADDRESS_MODE_WRAP, D3D12_TEXTURE_ADDRESS_MODE_MIRROR, D3D12_TEXTURE_ADDRESS_MODE_CLAMP };
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;
}
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 D3D12StagingDescriptor D3D12StagingDescriptor;
typedef struct D3D12TextureDownload D3D12TextureDownload;
typedef struct D3D12Fence
{
ID3D12Fence *handle;
HANDLE event; SDL_AtomicInt referenceCount;
} D3D12Fence;
struct D3D12DescriptorHeap
{
ID3D12DescriptorHeap *handle;
D3D12_DESCRIPTOR_HEAP_TYPE heapType;
D3D12_CPU_DESCRIPTOR_HANDLE descriptorHeapCPUStart;
D3D12_GPU_DESCRIPTOR_HANDLE descriptorHeapGPUStart; Uint32 maxDescriptors;
Uint32 descriptorSize;
bool staging;
Uint32 currentDescriptorIndex; };
typedef struct D3D12GPUDescriptorHeapPool
{
Uint32 capacity;
Uint32 count;
D3D12DescriptorHeap **heaps;
SDL_Mutex *lock;
} D3D12GPUDescriptorHeapPool;
typedef struct D3D12StagingDescriptorPool
{
Uint32 heapCount;
D3D12DescriptorHeap **heaps;
Uint32 freeDescriptorCapacity;
Uint32 freeDescriptorCount;
D3D12StagingDescriptor *freeDescriptors;
SDL_Mutex *lock;
} D3D12StagingDescriptorPool;
struct D3D12StagingDescriptor
{
D3D12StagingDescriptorPool *pool;
D3D12DescriptorHeap *heap;
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle;
Uint32 cpuHandleIndex;
};
typedef struct D3D12TextureContainer
{
TextureCommonHeader header;
D3D12Texture *activeTexture;
D3D12Texture **textures;
Uint32 textureCapacity;
Uint32 textureCount;
bool canBeCycled;
char *debugName;
} D3D12TextureContainer;
typedef struct D3D12TextureSubresource
{
D3D12Texture *parent;
Uint32 layer;
Uint32 level;
Uint32 depth;
Uint32 index;
D3D12StagingDescriptor *rtvHandles;
D3D12StagingDescriptor uavHandle; D3D12StagingDescriptor dsvHandle; } D3D12TextureSubresource;
struct D3D12Texture
{
D3D12TextureContainer *container;
Uint32 containerIndex;
D3D12TextureSubresource *subresources;
Uint32 subresourceCount;
ID3D12Resource *resource;
D3D12StagingDescriptor srvHandle;
SDL_AtomicInt referenceCount;
};
typedef struct D3D12Sampler
{
SDL_GPUSamplerCreateInfo createInfo;
D3D12StagingDescriptor handle;
SDL_AtomicInt referenceCount;
} D3D12Sampler;
typedef struct D3D12WindowData
{
SDL_Window *window;
D3D12Renderer *renderer;
int refcount;
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
D3D12XBOX_FRAME_PIPELINE_TOKEN frameToken;
#else
IDXGISwapChain3 *swapchain;
#endif
SDL_GPUPresentMode present_mode;
SDL_GPUSwapchainComposition swapchainComposition;
DXGI_COLOR_SPACE_TYPE swapchainColorSpace;
Uint32 frameCounter;
D3D12TextureContainer textureContainers[MAX_FRAMES_IN_FLIGHT];
Uint32 swapchainTextureCount;
SDL_GPUFence *inFlightFences[MAX_FRAMES_IN_FLIGHT];
Uint32 width;
Uint32 height;
bool needsSwapchainRecreate;
} D3D12WindowData;
typedef struct D3D12PresentData
{
D3D12WindowData *windowData;
Uint32 swapchainImageIndex;
} D3D12PresentData;
#ifdef USE_PIX_RUNTIME
typedef struct WinPixEventRuntimeFns {
pfnBeginEventOnCommandList pBeginEventOnCommandList;
pfnEndEventOnCommandList pEndEventOnCommandList;
pfnSetMarkerOnCommandList pSetMarkerOnCommandList;
} WinPixEventRuntimeFns;
#endif
struct D3D12Renderer
{
SDL_GPUDevice *sdlGPUDevice;
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
IDXGIDebug *dxgiDebug;
IDXGIFactory4 *factory;
#ifdef HAVE_IDXGIINFOQUEUE
IDXGIInfoQueue *dxgiInfoQueue;
#endif
IDXGIAdapter1 *adapter;
SDL_SharedObject *dxgi_dll;
SDL_SharedObject *dxgidebug_dll;
#endif
#ifdef USE_PIX_RUNTIME
SDL_SharedObject *winpixeventruntime_dll;
WinPixEventRuntimeFns winpixeventruntimeFns;
#endif
ID3D12Debug *d3d12Debug;
BOOL supportsTearing;
SDL_SharedObject *d3d12_dll;
ID3D12Device *device;
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pD3D12SerializeRootSignature;
char *semantic;
SDL_iconv_t iconv;
ID3D12CommandQueue *commandQueue;
bool debug_mode;
bool GPUUploadHeapSupported;
bool UnrestrictedBufferTextureCopyPitchSupported;
bool UMA;
bool UMACacheCoherent;
SDL_PropertiesID props;
Uint32 allowedFramesInFlight;
ID3D12CommandSignature *indirectDrawCommandSignature;
ID3D12CommandSignature *indirectIndexedDrawCommandSignature;
ID3D12CommandSignature *indirectDispatchCommandSignature;
SDL_GPUShader *blitVertexShader;
SDL_GPUShader *blitFrom2DShader;
SDL_GPUShader *blitFrom2DArrayShader;
SDL_GPUShader *blitFrom3DShader;
SDL_GPUShader *blitFromCubeShader;
SDL_GPUShader *blitFromCubeArrayShader;
SDL_GPUSampler *blitNearestSampler;
SDL_GPUSampler *blitLinearSampler;
BlitPipelineCacheEntry *blitPipelines;
Uint32 blitPipelineCount;
Uint32 blitPipelineCapacity;
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;
D3D12StagingDescriptorPool *stagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
D3D12GPUDescriptorHeapPool gpuDescriptorHeapPools[2];
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;
SDL_Mutex *acquireCommandBufferLock;
SDL_Mutex *acquireUniformBufferLock;
SDL_Mutex *submitLock;
SDL_Mutex *windowLock;
SDL_Mutex *fenceLock;
SDL_Mutex *disposeLock;
};
struct D3D12CommandBuffer
{
CommandBufferCommonHeader common;
D3D12Renderer *renderer;
ID3D12CommandAllocator *commandAllocator;
ID3D12GraphicsCommandList *graphicsCommandList;
D3D12Fence *inFlightFence;
bool autoReleaseFence;
D3D12PresentData *presentDatas;
Uint32 presentDataCount;
Uint32 presentDataCapacity;
D3D12TextureSubresource *colorTargetSubresources[MAX_COLOR_TARGET_BINDINGS];
D3D12TextureSubresource *colorResolveSubresources[MAX_COLOR_TARGET_BINDINGS];
D3D12TextureSubresource *depthStencilTextureSubresource;
D3D12GraphicsPipeline *currentGraphicsPipeline;
D3D12ComputePipeline *currentComputePipeline;
D3D12DescriptorHeap *gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER + 1];
D3D12DescriptorHeap **usedDescriptorHeaps;
Uint32 usedDescriptorHeapCount;
Uint32 usedDescriptorHeapCapacity;
D3D12UniformBuffer **usedUniformBuffers;
Uint32 usedUniformBufferCount;
Uint32 usedUniformBufferCapacity;
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 needComputeSamplerBind;
bool needComputeReadOnlyStorageTextureBind;
bool needComputeReadOnlyStorageBufferBind;
bool needComputeUniformBufferBind[MAX_UNIFORM_BUFFERS_PER_STAGE];
D3D12Buffer *vertexBuffers[MAX_VERTEX_BUFFERS];
Uint32 vertexBufferOffsets[MAX_VERTEX_BUFFERS];
Uint32 vertexBufferCount;
D3D12_CPU_DESCRIPTOR_HANDLE vertexSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE vertexSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE vertexStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE vertexStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE];
D3D12UniformBuffer *vertexUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE fragmentSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE fragmentSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE fragmentStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE fragmentStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE];
D3D12UniformBuffer *fragmentUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE computeSamplerTextureDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE computeSamplerDescriptorHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE computeReadOnlyStorageTextureDescriptorHandles[MAX_STORAGE_TEXTURES_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE computeReadOnlyStorageBufferDescriptorHandles[MAX_STORAGE_BUFFERS_PER_STAGE];
D3D12Texture *computeReadOnlyStorageTextures[MAX_STORAGE_TEXTURES_PER_STAGE];
D3D12Buffer *computeReadOnlyStorageBuffers[MAX_STORAGE_BUFFERS_PER_STAGE];
D3D12_CPU_DESCRIPTOR_HANDLE computeReadWriteStorageTextureDescriptorHandles[MAX_COMPUTE_WRITE_TEXTURES];
D3D12_CPU_DESCRIPTOR_HANDLE computeReadWriteStorageBufferDescriptorHandles[MAX_COMPUTE_WRITE_BUFFERS];
D3D12TextureSubresource *computeReadWriteStorageTextureSubresources[MAX_COMPUTE_WRITE_TEXTURES];
Uint32 computeReadWriteStorageTextureSubresourceCount;
D3D12Buffer *computeReadWriteStorageBuffers[MAX_COMPUTE_WRITE_BUFFERS];
Uint32 computeReadWriteStorageBufferCount;
D3D12UniformBuffer *computeUniformBuffers[MAX_UNIFORM_BUFFERS_PER_STAGE];
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;
D3D12TextureDownload **textureDownloads;
Uint32 textureDownloadCount;
Uint32 textureDownloadCapacity;
};
struct D3D12Shader
{
void *bytecode;
size_t bytecodeSize;
SDL_GPUShaderStage stage;
Uint32 num_samplers;
Uint32 numUniformBuffers;
Uint32 numStorageBuffers;
Uint32 numStorageTextures;
};
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
{
GraphicsPipelineCommonHeader header;
ID3D12PipelineState *pipelineState;
D3D12GraphicsRootSignature *rootSignature;
SDL_GPUPrimitiveType primitiveType;
Uint32 vertexStrides[MAX_VERTEX_BUFFERS];
SDL_AtomicInt referenceCount;
};
typedef struct D3D12ComputeRootSignature
{
ID3D12RootSignature *handle;
Sint32 samplerRootIndex;
Sint32 samplerTextureRootIndex;
Sint32 readOnlyStorageTextureRootIndex;
Sint32 readOnlyStorageBufferRootIndex;
Sint32 readWriteStorageTextureRootIndex;
Sint32 readWriteStorageBufferRootIndex;
Sint32 uniformBufferRootIndex[MAX_UNIFORM_BUFFERS_PER_STAGE];
} D3D12ComputeRootSignature;
struct D3D12ComputePipeline
{
ComputePipelineCommonHeader header;
ID3D12PipelineState *pipelineState;
D3D12ComputeRootSignature *rootSignature;
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;
D3D12StagingDescriptor uavDescriptor;
D3D12StagingDescriptor srvDescriptor;
D3D12StagingDescriptor cbvDescriptor;
D3D12_GPU_VIRTUAL_ADDRESS virtualAddress;
Uint8 *mapPointer; SDL_AtomicInt referenceCount;
bool transitioned; };
struct D3D12BufferContainer
{
SDL_GPUBufferUsageFlags usage;
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;
};
static void D3D12_ReleaseWindow(SDL_GPURenderer *driverData, SDL_Window *window);
static bool D3D12_Wait(SDL_GPURenderer *driverData);
static bool D3D12_WaitForFences(SDL_GPURenderer *driverData, bool waitAll, SDL_GPUFence *const *fences, Uint32 numFences);
static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData);
static Uint32 D3D12_INTERNAL_Align(Uint32 location, Uint32 alignment)
{
return (location + (alignment - 1)) & ~(alignment - 1);
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
static ID3D12Device *s_Device;
static ID3D12CommandQueue *s_CommandQueue;
#endif
#if defined(SDL_PLATFORM_XBOXONE)
typedef HRESULT (D3DAPI* PFN_D3D12_XBOX_CREATE_DEVICE)(_In_opt_ IGraphicsUnknown *, _In_ const D3D12XBOX_CREATE_DEVICE_PARAMETERS*, _In_ REFIID, _Outptr_opt_ void **);
#define D3D12_STANDARD_MULTISAMPLE_PATTERN DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN
#endif
static void D3D12_INTERNAL_SetError(
D3D12Renderer *renderer,
const char *msg,
HRESULT res)
{
#define MAX_ERROR_LEN 1024
char wszMsgBuff[MAX_ERROR_LEN + 1];
DWORD dwChars;
if (res == DXGI_ERROR_DEVICE_REMOVED) {
if (renderer->device) {
res = ID3D12Device_GetDeviceRemovedReason(renderer->device);
}
}
dwChars = FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
res,
0,
wszMsgBuff,
MAX_ERROR_LEN,
NULL);
if (dwChars == 0) {
if (renderer->debug_mode) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: " HRESULT_FMT, msg, res);
}
SDL_SetError("%s! Error Code: " HRESULT_FMT, msg, res);
return;
}
dwChars = SDL_min(dwChars, MAX_ERROR_LEN);
while (dwChars > 0) {
if (wszMsgBuff[dwChars - 1] <= ' ') {
dwChars--;
} else {
break;
}
}
wszMsgBuff[dwChars] = '\0';
if (renderer->debug_mode) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res);
}
SDL_SetError("%s! Error Code: %s " HRESULT_FMT, msg, wszMsgBuff, res);
}
static void D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
D3D12StagingDescriptor *cpuDescriptor)
{
D3D12StagingDescriptorPool *pool = cpuDescriptor->pool;
if (pool != NULL) {
SDL_LockMutex(pool->lock);
SDL_memcpy(&pool->freeDescriptors[pool->freeDescriptorCount], cpuDescriptor, sizeof(D3D12StagingDescriptor));
pool->freeDescriptorCount += 1;
SDL_UnlockMutex(pool->lock);
}
}
static void D3D12_INTERNAL_DestroyBuffer(
D3D12Buffer *buffer)
{
if (!buffer) {
return;
}
if (buffer->mapPointer != NULL) {
ID3D12Resource_Unmap(
buffer->handle,
0,
NULL);
}
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&buffer->srvDescriptor);
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&buffer->uavDescriptor);
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&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]);
}
SDL_free(container->debugName);
SDL_free(container->buffers);
SDL_free(container);
SDL_UnlockMutex(renderer->disposeLock);
}
static void D3D12_INTERNAL_DestroyTexture(
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_ReleaseStagingDescriptorHandle(
&subresource->rtvHandles[depthIndex]);
}
SDL_free(subresource->rtvHandles);
}
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&subresource->uavHandle);
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&subresource->dsvHandle);
}
SDL_free(texture->subresources);
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&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]);
}
SDL_DestroyProperties(container->header.info.props);
SDL_free(container->debugName);
SDL_free(container->textures);
SDL_free(container);
SDL_UnlockMutex(renderer->disposeLock);
}
static void D3D12_INTERNAL_DestroySampler(
D3D12Sampler *sampler)
{
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&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;
}
if (descriptorHeap->handle) {
ID3D12DescriptorHeap_Release(descriptorHeap->handle);
}
SDL_free(descriptorHeap);
}
static void D3D12_INTERNAL_DestroyStagingDescriptorPool(
D3D12StagingDescriptorPool *pool)
{
for (Uint32 i = 0; i < pool->heapCount; i += 1) {
D3D12_INTERNAL_DestroyDescriptorHeap(pool->heaps[i]);
}
SDL_free(pool->heaps);
SDL_free(pool->freeDescriptors);
SDL_DestroyMutex(pool->lock);
SDL_free(pool);
}
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->usedDescriptorHeaps);
SDL_free(commandBuffer->usedUniformBuffers);
SDL_free(commandBuffer->textureDownloads);
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)
{
for (Uint32 i = 0; i < renderer->uniformBufferPoolCount; i += 1) {
D3D12_INTERNAL_DestroyBuffer(
renderer->uniformBufferPool[i]->buffer);
SDL_free(renderer->uniformBufferPool[i]);
}
for (Uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) {
if (renderer->stagingDescriptorPools[i]) {
D3D12_INTERNAL_DestroyStagingDescriptorPool(renderer->stagingDescriptorPools[i]);
renderer->stagingDescriptorPools[i] = NULL;
}
}
for (Uint32 i = 0; i < 2; i += 1) {
if (renderer->gpuDescriptorHeapPools[i].heaps) {
for (Uint32 j = 0; j < renderer->gpuDescriptorHeapPools[i].count; j += 1) {
if (renderer->gpuDescriptorHeapPools[i].heaps[j]) {
D3D12_INTERNAL_DestroyDescriptorHeap(renderer->gpuDescriptorHeapPools[i].heaps[j]);
renderer->gpuDescriptorHeapPools[i].heaps[j] = NULL;
}
}
SDL_free(renderer->gpuDescriptorHeapPools[i].heaps);
}
if (renderer->gpuDescriptorHeapPools[i].lock) {
SDL_DestroyMutex(renderer->gpuDescriptorHeapPools[i].lock);
renderer->gpuDescriptorHeapPools[i].lock = NULL;
}
}
for (Uint32 i = 0; i < renderer->availableCommandBufferCount; i += 1) {
if (renderer->availableCommandBuffers[i]) {
D3D12_INTERNAL_DestroyCommandBuffer(renderer->availableCommandBuffers[i]);
renderer->availableCommandBuffers[i] = NULL;
}
}
for (Uint32 i = 0; i < renderer->availableFenceCount; i += 1) {
if (renderer->availableFences[i]) {
D3D12_INTERNAL_DestroyFence(renderer->availableFences[i]);
renderer->availableFences[i] = NULL;
}
}
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);
SDL_DestroyProperties(renderer->props);
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
#ifdef USE_PIX_RUNTIME
if (renderer->winpixeventruntime_dll) {
SDL_UnloadObject(renderer->winpixeventruntime_dll);
renderer->winpixeventruntime_dll = NULL;
}
#endif
renderer->pD3D12SerializeRootSignature = NULL;
if (renderer->iconv) {
SDL_iconv_close(renderer->iconv);
}
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->semantic);
SDL_free(renderer);
}
static void D3D12_DestroyDevice(SDL_GPUDevice *device)
{
D3D12Renderer *renderer = (D3D12Renderer *)device->driverData;
D3D12_INTERNAL_ReleaseBlitPipelines((SDL_GPURenderer *)renderer);
D3D12_Wait((SDL_GPURenderer *)renderer);
for (Sint32 i = renderer->claimedWindowCount - 1; i >= 0; i -= 1) {
D3D12_ReleaseWindow((SDL_GPURenderer *)renderer, renderer->claimedWindows[i]->window);
}
D3D12_INTERNAL_DestroyRenderer(renderer);
SDL_free(device);
}
static SDL_PropertiesID D3D12_GetDeviceProperties(SDL_GPUDevice *device)
{
D3D12Renderer *renderer = (D3D12Renderer *)device->driverData;
return renderer->props;
}
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;
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)
{
bool needsUAVBarrier =
(textureSubresource->parent->container->header.info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
(textureSubresource->parent->container->header.info.usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE);
D3D12_INTERNAL_ResourceBarrier(
commandBuffer,
sourceState,
destinationState,
textureSubresource->parent->resource,
textureSubresource->index,
needsUAVBarrier);
}
static D3D12_RESOURCE_STATES D3D12_INTERNAL_DefaultTextureResourceState(
SDL_GPUTextureUsageFlags usageFlags)
{
if (usageFlags & SDL_GPU_TEXTUREUSAGE_SAMPLER) {
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
} else if (usageFlags & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) {
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
} else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
return D3D12_RESOURCE_STATE_RENDER_TARGET;
} else if (usageFlags & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
return D3D12_RESOURCE_STATE_DEPTH_WRITE;
} else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ) {
return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
} else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) {
return D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
} else if (usageFlags & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) {
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.usage),
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.usage),
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->usage & SDL_GPU_BUFFERUSAGE_VERTEX) {
return D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
} else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_INDEX) {
return D3D12_RESOURCE_STATE_INDEX_BUFFER;
} else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_INDIRECT) {
return D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
} else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) {
return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
} else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ) {
return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
} else if (buffer->container->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) {
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->usage & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE);
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);
}
#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
static void D3D12_INTERNAL_SetPipelineStateName(
D3D12Renderer *renderer,
ID3D12PipelineState *pipelineState,
const char *text
) {
if (renderer->debug_mode && text != NULL) {
WCHAR *wchar_text = WIN_UTF8ToStringW(text);
ID3D12PipelineState_SetName(
pipelineState,
wchar_text);
SDL_free(wchar_text);
}
}
static void D3D12_INTERNAL_SetResourceName(
D3D12Renderer *renderer,
ID3D12Resource *resource,
const char *text
) {
if (renderer->debug_mode && text != NULL) {
WCHAR *wchar_text = WIN_UTF8ToStringW(text);
ID3D12Resource_SetName(
resource,
wchar_text);
SDL_free(wchar_text);
}
}
static void D3D12_SetBufferName(
SDL_GPURenderer *driverData,
SDL_GPUBuffer *buffer,
const char *text)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12BufferContainer *container = (D3D12BufferContainer *)buffer;
if (renderer->debug_mode && text != NULL) {
SDL_free(container->debugName);
container->debugName = SDL_strdup(text);
for (Uint32 i = 0; i < container->bufferCount; i += 1) {
D3D12_INTERNAL_SetResourceName(
renderer,
container->buffers[i]->handle,
text);
}
}
}
static void D3D12_SetTextureName(
SDL_GPURenderer *driverData,
SDL_GPUTexture *texture,
const char *text)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12TextureContainer *container = (D3D12TextureContainer *)texture;
if (renderer->debug_mode && text != NULL) {
SDL_free(container->debugName);
container->debugName = SDL_strdup(text);
for (Uint32 i = 0; i < container->textureCount; i += 1) {
D3D12_INTERNAL_SetResourceName(
renderer,
container->textures[i]->resource,
text);
}
}
}
static void D3D12_InsertDebugLabel(
SDL_GPUCommandBuffer *commandBuffer,
const char *text)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
#ifdef USE_PIX_RUNTIME
WinPixEventRuntimeFns *fns = &d3d12CommandBuffer->renderer->winpixeventruntimeFns;
if (fns->pSetMarkerOnCommandList) {
fns->pSetMarkerOnCommandList(d3d12CommandBuffer->graphicsCommandList, 0 , text);
}
#else
WCHAR *wchar_text = WIN_UTF8ToStringW(text);
ID3D12GraphicsCommandList_SetMarker(
d3d12CommandBuffer->graphicsCommandList,
0,
wchar_text,
(UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR));
SDL_free(wchar_text);
#endif
}
static void D3D12_PushDebugGroup(
SDL_GPUCommandBuffer *commandBuffer,
const char *name)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
#ifdef USE_PIX_RUNTIME
WinPixEventRuntimeFns *fns = &d3d12CommandBuffer->renderer->winpixeventruntimeFns;
if (fns->pBeginEventOnCommandList) {
fns->pBeginEventOnCommandList(d3d12CommandBuffer->graphicsCommandList, 0 , name);
}
#else
WCHAR *wchar_text = WIN_UTF8ToStringW(name);
ID3D12GraphicsCommandList_BeginEvent(
d3d12CommandBuffer->graphicsCommandList,
0,
wchar_text,
(UINT)SDL_wcslen(wchar_text) * sizeof(WCHAR));
SDL_free(wchar_text);
#endif
}
static void D3D12_PopDebugGroup(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
#ifdef USE_PIX_RUNTIME
WinPixEventRuntimeFns *fns = &d3d12CommandBuffer->renderer->winpixeventruntimeFns;
if (fns->pEndEventOnCommandList) {
fns->pEndEventOnCommandList(d3d12CommandBuffer->graphicsCommandList);
}
#else
ID3D12GraphicsCommandList_EndEvent(d3d12CommandBuffer->graphicsCommandList);
#endif
}
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;
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_SetError(renderer, "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 D3D12StagingDescriptorPool *D3D12_INTERNAL_CreateStagingDescriptorPool(
D3D12Renderer *renderer,
D3D12_DESCRIPTOR_HEAP_TYPE heapType
) {
D3D12DescriptorHeap *heap = D3D12_INTERNAL_CreateDescriptorHeap(
renderer,
heapType,
STAGING_HEAP_DESCRIPTOR_COUNT,
true);
if (!heap) {
return NULL;
}
D3D12StagingDescriptorPool *pool = (D3D12StagingDescriptorPool *)SDL_calloc(1, sizeof(D3D12StagingDescriptorPool));
pool->heapCount = 1;
pool->heaps = (D3D12DescriptorHeap **)SDL_malloc(sizeof(D3D12DescriptorHeap *));
pool->heaps[0] = heap;
pool->freeDescriptorCapacity = STAGING_HEAP_DESCRIPTOR_COUNT;
pool->freeDescriptorCount = STAGING_HEAP_DESCRIPTOR_COUNT;
pool->freeDescriptors = (D3D12StagingDescriptor *)SDL_malloc(STAGING_HEAP_DESCRIPTOR_COUNT * sizeof(D3D12StagingDescriptor));
for (Uint32 i = 0; i < STAGING_HEAP_DESCRIPTOR_COUNT; i += 1) {
pool->freeDescriptors[i].pool = pool;
pool->freeDescriptors[i].heap = heap;
pool->freeDescriptors[i].cpuHandleIndex = i;
pool->freeDescriptors[i].cpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (i * heap->descriptorSize);
}
pool->lock = SDL_CreateMutex();
return pool;
}
static bool D3D12_INTERNAL_ExpandStagingDescriptorPool(
D3D12Renderer *renderer,
D3D12StagingDescriptorPool *pool
) {
D3D12DescriptorHeap *heap = D3D12_INTERNAL_CreateDescriptorHeap(
renderer,
pool->heaps[0]->heapType,
STAGING_HEAP_DESCRIPTOR_COUNT,
true);
if (!heap) {
return false;
}
pool->heapCount += 1;
pool->heaps = (D3D12DescriptorHeap **)SDL_realloc(pool->heaps, pool->heapCount * sizeof(D3D12DescriptorHeap *));
pool->heaps[pool->heapCount - 1] = heap;
pool->freeDescriptorCapacity += STAGING_HEAP_DESCRIPTOR_COUNT;
pool->freeDescriptorCount += STAGING_HEAP_DESCRIPTOR_COUNT;
pool->freeDescriptors = (D3D12StagingDescriptor *)SDL_realloc(pool->freeDescriptors, pool->freeDescriptorCapacity * sizeof(D3D12StagingDescriptor));
for (Uint32 i = 0; i < STAGING_HEAP_DESCRIPTOR_COUNT; i += 1) {
pool->freeDescriptors[i].pool = pool;
pool->freeDescriptors[i].heap = heap;
pool->freeDescriptors[i].cpuHandleIndex = i;
pool->freeDescriptors[i].cpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (i * heap->descriptorSize);
}
return true;
}
static void D3D12_INTERNAL_TrackGPUDescriptorHeap(
D3D12CommandBuffer *commandBuffer,
D3D12DescriptorHeap *descriptorHeap)
{
Uint32 i;
for (i = 0; i < commandBuffer->usedDescriptorHeapCount; i += 1) {
if (commandBuffer->usedDescriptorHeaps[i] == descriptorHeap) {
return;
}
}
if (commandBuffer->usedDescriptorHeapCount == commandBuffer->usedDescriptorHeapCapacity) {
commandBuffer->usedDescriptorHeapCapacity += 1;
commandBuffer->usedDescriptorHeaps = (D3D12DescriptorHeap **)SDL_realloc(
commandBuffer->usedDescriptorHeaps,
commandBuffer->usedDescriptorHeapCapacity * sizeof(D3D12DescriptorHeap *));
}
commandBuffer->usedDescriptorHeaps[commandBuffer->usedDescriptorHeapCount] = descriptorHeap;
commandBuffer->usedDescriptorHeapCount += 1;
}
static D3D12DescriptorHeap *D3D12_INTERNAL_AcquireGPUDescriptorHeapFromPool(
D3D12CommandBuffer *commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE descriptorHeapType)
{
D3D12DescriptorHeap *result;
D3D12Renderer *renderer = commandBuffer->renderer;
D3D12GPUDescriptorHeapPool *pool = &renderer->gpuDescriptorHeapPools[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);
D3D12_INTERNAL_TrackGPUDescriptorHeap(commandBuffer, result);
return result;
}
static void D3D12_INTERNAL_ReturnGPUDescriptorHeapToPool(
D3D12Renderer *renderer,
D3D12DescriptorHeap *heap)
{
if (heap == NULL) {
return;
}
D3D12GPUDescriptorHeapPool *pool = &renderer->gpuDescriptorHeapPools[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);
}
static D3D12GraphicsRootSignature *D3D12_INTERNAL_CreateGraphicsRootSignature(
D3D12Renderer *renderer,
D3D12Shader *vertexShader,
D3D12Shader *fragmentShader)
{
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->num_samplers > 0) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
descriptorRange.NumDescriptors = vertexShader->num_samplers;
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->num_samplers;
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->numStorageTextures) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = vertexShader->numStorageTextures;
descriptorRange.BaseShaderRegister = vertexShader->num_samplers;
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->numStorageBuffers) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = vertexShader->numStorageBuffers;
descriptorRange.BaseShaderRegister = vertexShader->num_samplers + vertexShader->numStorageTextures;
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;
}
for (Uint32 i = 0; i < vertexShader->numUniformBuffers; 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->num_samplers) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
descriptorRange.NumDescriptors = fragmentShader->num_samplers;
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->num_samplers;
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->numStorageTextures) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = fragmentShader->numStorageTextures;
descriptorRange.BaseShaderRegister = fragmentShader->num_samplers;
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->numStorageBuffers) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = fragmentShader->numStorageBuffers;
descriptorRange.BaseShaderRegister = fragmentShader->num_samplers + fragmentShader->numStorageTextures;
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;
}
for (Uint32 i = 0; i < fragmentShader->numUniformBuffers; 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;
}
SDL_assert(parameterCount <= MAX_ROOT_SIGNATURE_PARAMETERS);
SDL_assert(rangeCount <= MAX_ROOT_SIGNATURE_PARAMETERS);
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;
ID3DBlob *serializedRootSignature;
ID3DBlob *errorBlob;
HRESULT res = renderer->pD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSignature, &errorBlob);
if (FAILED(res)) {
if (errorBlob) {
SET_ERROR("Failed to serialize RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob));
ID3D10Blob_Release(errorBlob);
}
D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature);
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) {
SET_ERROR("Failed to create RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob));
ID3D10Blob_Release(errorBlob);
}
D3D12_INTERNAL_DestroyGraphicsRootSignature(d3d12GraphicsRootSignature);
return NULL;
}
d3d12GraphicsRootSignature->handle = rootSignature;
return d3d12GraphicsRootSignature;
}
static bool D3D12_INTERNAL_IsValidShaderBytecode(
const Uint8 *code,
size_t codeSize)
{
if (codeSize < 4 || code == NULL) {
return false;
}
return SDL_memcmp(code, "DXBC", 4) == 0;
}
static bool D3D12_INTERNAL_CreateShaderBytecode(
D3D12Renderer *renderer,
const Uint8 *code,
size_t codeSize,
SDL_GPUShaderFormat format,
void **pBytecode,
size_t *pBytecodeSize)
{
if (!D3D12_INTERNAL_IsValidShaderBytecode(code, codeSize)) {
if (format == SDL_GPU_SHADERFORMAT_DXBC) {
SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid DXBC!", false);
}
SET_STRING_ERROR_AND_RETURN("The provided shader code is not valid DXIL!", false);
}
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,
const SDL_GPUComputePipelineCreateInfo *createInfo)
{
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->samplerRootIndex = -1;
d3d12ComputeRootSignature->samplerTextureRootIndex = -1;
d3d12ComputeRootSignature->readOnlyStorageTextureRootIndex = -1;
d3d12ComputeRootSignature->readOnlyStorageBufferRootIndex = -1;
d3d12ComputeRootSignature->readWriteStorageTextureRootIndex = -1;
d3d12ComputeRootSignature->readWriteStorageBufferRootIndex = -1;
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
d3d12ComputeRootSignature->uniformBufferRootIndex[i] = -1;
}
if (createInfo->num_samplers) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER;
descriptorRange.NumDescriptors = createInfo->num_samplers;
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; rootParameters[parameterCount] = rootParameter;
d3d12ComputeRootSignature->samplerRootIndex = parameterCount;
rangeCount += 1;
parameterCount += 1;
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = createInfo->num_samplers;
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; rootParameters[parameterCount] = rootParameter;
d3d12ComputeRootSignature->samplerTextureRootIndex = parameterCount;
rangeCount += 1;
parameterCount += 1;
}
if (createInfo->num_readonly_storage_textures) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = createInfo->num_readonly_storage_textures;
descriptorRange.BaseShaderRegister = createInfo->num_samplers;
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; rootParameters[parameterCount] = rootParameter;
d3d12ComputeRootSignature->readOnlyStorageTextureRootIndex = parameterCount;
rangeCount += 1;
parameterCount += 1;
}
if (createInfo->num_readonly_storage_buffers) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descriptorRange.NumDescriptors = createInfo->num_readonly_storage_buffers;
descriptorRange.BaseShaderRegister = createInfo->num_samplers + createInfo->num_readonly_storage_textures;
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; rootParameters[parameterCount] = rootParameter;
d3d12ComputeRootSignature->readOnlyStorageBufferRootIndex = parameterCount;
rangeCount += 1;
parameterCount += 1;
}
if (createInfo->num_readwrite_storage_textures) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
descriptorRange.NumDescriptors = createInfo->num_readwrite_storage_textures;
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; rootParameters[parameterCount] = rootParameter;
d3d12ComputeRootSignature->readWriteStorageTextureRootIndex = parameterCount;
rangeCount += 1;
parameterCount += 1;
}
if (createInfo->num_readwrite_storage_buffers) {
descriptorRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
descriptorRange.NumDescriptors = createInfo->num_readwrite_storage_buffers;
descriptorRange.BaseShaderRegister = createInfo->num_readwrite_storage_textures;
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; rootParameters[parameterCount] = rootParameter;
d3d12ComputeRootSignature->readWriteStorageBufferRootIndex = parameterCount;
rangeCount += 1;
parameterCount += 1;
}
for (Uint32 i = 0; i < createInfo->num_uniform_buffers; i += 1) {
rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
rootParameter.Descriptor.ShaderRegister = i;
rootParameter.Descriptor.RegisterSpace = 2;
rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; 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->pD3D12SerializeRootSignature(
&rootSignatureDesc,
D3D_ROOT_SIGNATURE_VERSION_1,
&serializedRootSignature,
&errorBlob);
if (FAILED(res)) {
if (errorBlob) {
SET_ERROR("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) {
SET_ERROR("Failed to create RootSignature: %s", (const char *)ID3D10Blob_GetBufferPointer(errorBlob));
ID3D10Blob_Release(errorBlob);
}
D3D12_INTERNAL_DestroyComputeRootSignature(d3d12ComputeRootSignature);
return NULL;
}
d3d12ComputeRootSignature->handle = rootSignature;
return d3d12ComputeRootSignature;
}
static SDL_GPUComputePipeline *D3D12_CreateComputePipeline(
SDL_GPURenderer *driverData,
const SDL_GPUComputePipelineCreateInfo *createinfo)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
ID3D12PipelineState *pipelineState;
if (!D3D12_INTERNAL_CreateShaderBytecode(
renderer,
createinfo->code,
createinfo->code_size,
createinfo->format,
NULL,
NULL)) {
return NULL;
}
D3D12ComputeRootSignature *rootSignature = D3D12_INTERNAL_CreateComputeRootSignature(
renderer,
createinfo);
if (rootSignature == NULL) {
SET_STRING_ERROR_AND_RETURN("Could not create root signature!", NULL);
}
D3D12_COMPUTE_PIPELINE_STATE_DESC pipelineDesc;
pipelineDesc.CS.pShaderBytecode = createinfo->code;
pipelineDesc.CS.BytecodeLength = createinfo->code_size;
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_SetError(renderer, "Could not create compute pipeline state", res);
return NULL;
}
D3D12ComputePipeline *computePipeline =
(D3D12ComputePipeline *)SDL_calloc(1, sizeof(D3D12ComputePipeline));
if (!computePipeline) {
ID3D12PipelineState_Release(pipelineState);
return NULL;
}
computePipeline->pipelineState = pipelineState;
computePipeline->rootSignature = rootSignature;
computePipeline->header.numSamplers = createinfo->num_samplers;
computePipeline->header.numReadonlyStorageTextures = createinfo->num_readonly_storage_textures;
computePipeline->header.numReadonlyStorageBuffers = createinfo->num_readonly_storage_buffers;
computePipeline->header.numReadWriteStorageTextures = createinfo->num_readwrite_storage_textures;
computePipeline->header.numReadWriteStorageBuffers = createinfo->num_readwrite_storage_buffers;
computePipeline->header.numUniformBuffers = createinfo->num_uniform_buffers;
SDL_SetAtomicInt(&computePipeline->referenceCount, 0);
if (renderer->debug_mode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING)) {
D3D12_INTERNAL_SetPipelineStateName(
renderer,
computePipeline->pipelineState,
SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_COMPUTEPIPELINE_CREATE_NAME_STRING, NULL));
}
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.fill_mode];
desc->CullMode = SDLToD3D12_CullMode[rasterizerState.cull_mode];
switch (rasterizerState.front_face) {
case SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE:
desc->FrontCounterClockwise = TRUE;
break;
case SDL_GPU_FRONTFACE_CLOCKWISE:
desc->FrontCounterClockwise = FALSE;
break;
default:
return false;
}
if (rasterizerState.enable_depth_bias) {
desc->DepthBias = SDL_lroundf(rasterizerState.depth_bias_constant_factor);
desc->DepthBiasClamp = rasterizerState.depth_bias_clamp;
desc->SlopeScaledDepthBias = rasterizerState.depth_bias_slope_factor;
} else {
desc->DepthBias = 0;
desc->DepthBiasClamp = 0.0f;
desc->SlopeScaledDepthBias = 0.0f;
}
desc->DepthClipEnable = rasterizerState.enable_depth_clip;
desc->MultisampleEnable = FALSE;
desc->AntialiasedLineEnable = FALSE;
desc->ForcedSampleCount = 0;
desc->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
return true;
}
static bool D3D12_INTERNAL_ConvertBlendState(
const SDL_GPUGraphicsPipelineCreateInfo *pipelineInfo,
D3D12_BLEND_DESC *blendDesc)
{
if (!blendDesc) {
return false;
}
SDL_zerop(blendDesc);
blendDesc->AlphaToCoverageEnable = pipelineInfo->multisample_state.enable_alpha_to_coverage;
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 (i < pipelineInfo->target_info.num_color_targets) {
SDL_GPUColorTargetBlendState sdlBlendState = pipelineInfo->target_info.color_target_descriptions[i].blend_state;
SDL_GPUColorComponentFlags colorWriteMask = sdlBlendState.enable_color_write_mask ?
sdlBlendState.color_write_mask :
0xF;
rtBlendDesc.BlendEnable = sdlBlendState.enable_blend;
rtBlendDesc.SrcBlend = SDLToD3D12_BlendFactor[sdlBlendState.src_color_blendfactor];
rtBlendDesc.DestBlend = SDLToD3D12_BlendFactor[sdlBlendState.dst_color_blendfactor];
rtBlendDesc.BlendOp = SDLToD3D12_BlendOp[sdlBlendState.color_blend_op];
rtBlendDesc.SrcBlendAlpha = SDLToD3D12_BlendFactorAlpha[sdlBlendState.src_alpha_blendfactor];
rtBlendDesc.DestBlendAlpha = SDLToD3D12_BlendFactorAlpha[sdlBlendState.dst_alpha_blendfactor];
rtBlendDesc.BlendOpAlpha = SDLToD3D12_BlendOp[sdlBlendState.alpha_blend_op];
rtBlendDesc.RenderTargetWriteMask = 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.enable_depth_test == true ? TRUE : FALSE;
desc->DepthWriteMask = depthStencilState.enable_depth_write == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
desc->DepthFunc = SDLToD3D12_CompareOp[depthStencilState.compare_op];
desc->StencilEnable = depthStencilState.enable_stencil_test == true ? TRUE : FALSE;
desc->StencilReadMask = depthStencilState.compare_mask;
desc->StencilWriteMask = depthStencilState.write_mask;
desc->FrontFace.StencilFailOp = SDLToD3D12_StencilOp[depthStencilState.front_stencil_state.fail_op];
desc->FrontFace.StencilDepthFailOp = SDLToD3D12_StencilOp[depthStencilState.front_stencil_state.depth_fail_op];
desc->FrontFace.StencilPassOp = SDLToD3D12_StencilOp[depthStencilState.front_stencil_state.pass_op];
desc->FrontFace.StencilFunc = SDLToD3D12_CompareOp[depthStencilState.front_stencil_state.compare_op];
desc->BackFace.StencilFailOp = SDLToD3D12_StencilOp[depthStencilState.back_stencil_state.fail_op];
desc->BackFace.StencilDepthFailOp = SDLToD3D12_StencilOp[depthStencilState.back_stencil_state.depth_fail_op];
desc->BackFace.StencilPassOp = SDLToD3D12_StencilOp[depthStencilState.back_stencil_state.pass_op];
desc->BackFace.StencilFunc = SDLToD3D12_CompareOp[depthStencilState.back_stencil_state.compare_op];
return true;
}
static bool D3D12_INTERNAL_ConvertVertexInputState(SDL_GPUVertexInputState vertexInputState, D3D12_INPUT_ELEMENT_DESC *desc, const char *semantic)
{
if (desc == NULL || vertexInputState.num_vertex_attributes == 0) {
return false;
}
for (Uint32 i = 0; i < vertexInputState.num_vertex_attributes; i += 1) {
SDL_GPUVertexAttribute attribute = vertexInputState.vertex_attributes[i];
desc[i].SemanticName = semantic;
desc[i].SemanticIndex = attribute.location;
desc[i].Format = SDLToD3D12_VertexFormat[attribute.format];
desc[i].InputSlot = attribute.buffer_slot;
desc[i].AlignedByteOffset = attribute.offset;
desc[i].InputSlotClass = SDLToD3D12_InputRate[vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate];
desc[i].InstanceDataStepRate = (vertexInputState.vertex_buffer_descriptions[attribute.buffer_slot].input_rate == SDL_GPU_VERTEXINPUTRATE_INSTANCE)
? 1
: 0;
}
return true;
}
static bool D3D12_INTERNAL_AssignStagingDescriptorHandle(
D3D12Renderer *renderer,
D3D12_DESCRIPTOR_HEAP_TYPE heapType,
D3D12StagingDescriptor *cpuDescriptor)
{
D3D12StagingDescriptor *descriptor;
D3D12StagingDescriptorPool *pool = renderer->stagingDescriptorPools[heapType];
SDL_LockMutex(pool->lock);
if (pool->freeDescriptorCount == 0) {
if (!D3D12_INTERNAL_ExpandStagingDescriptorPool(renderer, pool))
{
SDL_UnlockMutex(pool->lock);
return false;
}
}
descriptor = &pool->freeDescriptors[pool->freeDescriptorCount - 1];
SDL_memcpy(cpuDescriptor, descriptor, sizeof(D3D12StagingDescriptor));
pool->freeDescriptorCount -= 1;
SDL_UnlockMutex(pool->lock);
return true;
}
static SDL_GPUGraphicsPipeline *D3D12_CreateGraphicsPipeline(
SDL_GPURenderer *driverData,
const SDL_GPUGraphicsPipelineCreateInfo *createinfo)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12Shader *vertShader = (D3D12Shader *)createinfo->vertex_shader;
D3D12Shader *fragShader = (D3D12Shader *)createinfo->fragment_shader;
if (renderer->debug_mode) {
if (vertShader->stage != SDL_GPU_SHADERSTAGE_VERTEX) {
SDL_assert_release(!"CreateGraphicsPipeline was passed a fragment shader for the vertex stage");
}
if (fragShader->stage != SDL_GPU_SHADERSTAGE_FRAGMENT) {
SDL_assert_release(!"CreateGraphicsPipeline was passed a vertex shader for the fragment stage");
}
}
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 (createinfo->vertex_input_state.num_vertex_attributes > 0) {
psoDesc.InputLayout.pInputElementDescs = inputElementDescs;
psoDesc.InputLayout.NumElements = createinfo->vertex_input_state.num_vertex_attributes;
D3D12_INTERNAL_ConvertVertexInputState(createinfo->vertex_input_state, inputElementDescs, renderer->semantic);
}
psoDesc.PrimitiveTopologyType = SDLToD3D12_PrimitiveTopologyType[createinfo->primitive_type];
if (!D3D12_INTERNAL_ConvertRasterizerState(createinfo->rasterizer_state, &psoDesc.RasterizerState)) {
return NULL;
}
if (!D3D12_INTERNAL_ConvertBlendState(createinfo, &psoDesc.BlendState)) {
return NULL;
}
if (!D3D12_INTERNAL_ConvertDepthStencilState(createinfo->depth_stencil_state, &psoDesc.DepthStencilState)) {
return NULL;
}
D3D12GraphicsPipeline *pipeline = (D3D12GraphicsPipeline *)SDL_calloc(1, sizeof(D3D12GraphicsPipeline));
if (!pipeline) {
return NULL;
}
psoDesc.SampleMask = 0xFFFFFFFF;
psoDesc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->multisample_state.sample_count];
psoDesc.SampleDesc.Quality = (createinfo->multisample_state.sample_count > SDL_GPU_SAMPLECOUNT_1) ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0;
if (createinfo->target_info.has_depth_stencil_target) {
psoDesc.DSVFormat = SDLToD3D12_DepthFormat[createinfo->target_info.depth_stencil_format];
}
psoDesc.NumRenderTargets = createinfo->target_info.num_color_targets;
for (uint32_t i = 0; i < createinfo->target_info.num_color_targets; i += 1) {
psoDesc.RTVFormats[i] = SDLToD3D12_TextureFormat[createinfo->target_info.color_target_descriptions[i].format];
}
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) {
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_SetError(renderer, "Could not create graphics pipeline state", res);
D3D12_INTERNAL_DestroyGraphicsPipeline(pipeline);
return NULL;
}
pipeline->pipelineState = pipelineState;
for (Uint32 i = 0; i < createinfo->vertex_input_state.num_vertex_buffers; i += 1) {
pipeline->vertexStrides[createinfo->vertex_input_state.vertex_buffer_descriptions[i].slot] =
createinfo->vertex_input_state.vertex_buffer_descriptions[i].pitch;
}
pipeline->primitiveType = createinfo->primitive_type;
pipeline->header.num_vertex_samplers = vertShader->num_samplers;
pipeline->header.num_vertex_storage_textures = vertShader->numStorageTextures;
pipeline->header.num_vertex_storage_buffers = vertShader->numStorageBuffers;
pipeline->header.num_vertex_uniform_buffers = vertShader->numUniformBuffers;
pipeline->header.num_fragment_samplers = fragShader->num_samplers;
pipeline->header.num_fragment_storage_textures = fragShader->numStorageTextures;
pipeline->header.num_fragment_storage_buffers = fragShader->numStorageBuffers;
pipeline->header.num_fragment_uniform_buffers = fragShader->numUniformBuffers;
SDL_SetAtomicInt(&pipeline->referenceCount, 0);
if (renderer->debug_mode && SDL_HasProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING)) {
D3D12_INTERNAL_SetPipelineStateName(
renderer,
pipeline->pipelineState,
SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_GRAPHICSPIPELINE_CREATE_NAME_STRING, NULL));
}
return (SDL_GPUGraphicsPipeline *)pipeline;
}
static SDL_GPUSampler *D3D12_CreateSampler(
SDL_GPURenderer *driverData,
const SDL_GPUSamplerCreateInfo *createinfo)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12Sampler *sampler = (D3D12Sampler *)SDL_calloc(1, sizeof(D3D12Sampler));
if (!sampler) {
return NULL;
}
D3D12_SAMPLER_DESC samplerDesc;
samplerDesc.Filter = SDLToD3D12_Filter(
createinfo->min_filter,
createinfo->mag_filter,
createinfo->mipmap_mode,
createinfo->enable_compare,
createinfo->enable_anisotropy);
samplerDesc.AddressU = SDLToD3D12_SamplerAddressMode[createinfo->address_mode_u];
samplerDesc.AddressV = SDLToD3D12_SamplerAddressMode[createinfo->address_mode_v];
samplerDesc.AddressW = SDLToD3D12_SamplerAddressMode[createinfo->address_mode_w];
samplerDesc.MaxAnisotropy = (Uint32)createinfo->max_anisotropy;
samplerDesc.ComparisonFunc = SDLToD3D12_CompareOp[createinfo->compare_op];
samplerDesc.MinLOD = createinfo->min_lod;
samplerDesc.MaxLOD = createinfo->max_lod;
samplerDesc.MipLODBias = createinfo->mip_lod_bias;
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
&sampler->handle);
ID3D12Device_CreateSampler(
renderer->device,
&samplerDesc,
sampler->handle.cpuHandle);
sampler->createInfo = *createinfo;
SDL_SetAtomicInt(&sampler->referenceCount, 0);
return (SDL_GPUSampler *)sampler;
}
static SDL_GPUShader *D3D12_CreateShader(
SDL_GPURenderer *driverData,
const SDL_GPUShaderCreateInfo *createinfo)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
void *bytecode;
size_t bytecodeSize;
D3D12Shader *shader;
if (!D3D12_INTERNAL_CreateShaderBytecode(
renderer,
createinfo->code,
createinfo->code_size,
createinfo->format,
&bytecode,
&bytecodeSize)) {
return NULL;
}
shader = (D3D12Shader *)SDL_calloc(1, sizeof(D3D12Shader));
if (!shader) {
SDL_free(bytecode);
return NULL;
}
shader->stage = createinfo->stage;
shader->num_samplers = createinfo->num_samplers;
shader->numStorageBuffers = createinfo->num_storage_buffers;
shader->numStorageTextures = createinfo->num_storage_textures;
shader->numUniformBuffers = createinfo->num_uniform_buffers;
shader->bytecode = bytecode;
shader->bytecodeSize = bytecodeSize;
return (SDL_GPUShader *)shader;
}
static D3D12Texture *D3D12_INTERNAL_CreateTexture(
D3D12Renderer *renderer,
const SDL_GPUTextureCreateInfo *createinfo,
bool isSwapchainTexture,
const char *debugName)
{
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;
DXGI_FORMAT format;
bool useClearValue = false;
bool needsSRV =
(createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) ||
(createinfo->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) ||
(createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ);
bool needsUAV =
(createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) ||
(createinfo->usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE);
HRESULT res;
texture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture));
if (!texture) {
return NULL;
}
Uint32 layerCount = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? 1 : createinfo->layer_count_or_depth;
Uint32 depth = createinfo->type == SDL_GPU_TEXTURETYPE_3D ? createinfo->layer_count_or_depth : 1;
bool isMultisample = createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1;
format = SDLToD3D12_TextureFormat[createinfo->format];
if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
useClearValue = true;
clearValue.Format = format;
clearValue.Color[0] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT, 0);
clearValue.Color[1] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT, 0);
clearValue.Color[2] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT, 0);
clearValue.Color[3] = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT, 0);
}
if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
useClearValue = true;
clearValue.Format = SDLToD3D12_DepthFormat[createinfo->format];
clearValue.DepthStencil.Depth = SDL_GetFloatProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT, 0);
clearValue.DepthStencil.Stencil = (UINT8)SDL_GetNumberProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER, 0);
format = needsSRV ? SDLToD3D12_TypelessFormat[createinfo->format] : SDLToD3D12_DepthFormat[createinfo->format];
}
if (needsUAV) {
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; heapProperties.VisibleNodeMask = 0;
heapFlags = isSwapchainTexture ? D3D12_HEAP_FLAG_ALLOW_DISPLAY : D3D12_HEAP_FLAG_NONE;
if (createinfo->type != SDL_GPU_TEXTURETYPE_3D) {
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Alignment = isSwapchainTexture ? 0 : isMultisample ? D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = createinfo->width;
desc.Height = createinfo->height;
desc.DepthOrArraySize = (UINT16)createinfo->layer_count_or_depth;
desc.MipLevels = (UINT16)createinfo->num_levels;
desc.Format = format;
desc.SampleDesc.Count = SDLToD3D12_SampleCount[createinfo->sample_count];
desc.SampleDesc.Quality = isMultisample ? D3D12_STANDARD_MULTISAMPLE_PATTERN : 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; desc.Flags = resourceFlags;
} else {
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = createinfo->width;
desc.Height = createinfo->height;
desc.DepthOrArraySize = (UINT16)createinfo->layer_count_or_depth;
desc.MipLevels = (UINT16)createinfo->num_levels;
desc.Format = 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(createinfo->usage);
res = ID3D12Device_CreateCommittedResource(
renderer->device,
&heapProperties,
heapFlags,
&desc,
initialState,
useClearValue ? &clearValue : NULL,
D3D_GUID(D3D_IID_ID3D12Resource),
(void **)&handle);
if (FAILED(res)) {
D3D12_INTERNAL_SetError(renderer, "Failed to create texture!", res);
D3D12_INTERNAL_DestroyTexture(texture);
return NULL;
}
texture->resource = handle;
if (needsSRV) {
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
&texture->srvHandle);
srvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format];
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
srvDesc.TextureCube.MipLevels = createinfo->num_levels;
srvDesc.TextureCube.MostDetailedMip = 0;
srvDesc.TextureCube.ResourceMinLODClamp = 0;
} else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
srvDesc.TextureCubeArray.MipLevels = createinfo->num_levels;
srvDesc.TextureCubeArray.MostDetailedMip = 0;
srvDesc.TextureCubeArray.First2DArrayFace = 0;
srvDesc.TextureCubeArray.NumCubes = createinfo->layer_count_or_depth / 6;
srvDesc.TextureCubeArray.ResourceMinLODClamp = 0;
} else if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
srvDesc.Texture2DArray.MipLevels = createinfo->num_levels;
srvDesc.Texture2DArray.MostDetailedMip = 0;
srvDesc.Texture2DArray.FirstArraySlice = 0;
srvDesc.Texture2DArray.ArraySize = layerCount;
srvDesc.Texture2DArray.ResourceMinLODClamp = 0;
srvDesc.Texture2DArray.PlaneSlice = 0;
} else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE3D;
srvDesc.Texture3D.MipLevels = createinfo->num_levels;
srvDesc.Texture3D.MostDetailedMip = 0;
srvDesc.Texture3D.ResourceMinLODClamp = 0; } else {
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = createinfo->num_levels;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.PlaneSlice = 0;
srvDesc.Texture2D.ResourceMinLODClamp = 0; }
ID3D12Device_CreateShaderResourceView(
renderer->device,
handle,
&srvDesc,
texture->srvHandle.cpuHandle);
}
SDL_SetAtomicInt(&texture->referenceCount, 0);
texture->subresourceCount = createinfo->num_levels * layerCount;
texture->subresources = (D3D12TextureSubresource *)SDL_calloc(
texture->subresourceCount, sizeof(D3D12TextureSubresource));
if (!texture->subresources) {
D3D12_INTERNAL_DestroyTexture(texture);
return NULL;
}
for (Uint32 layerIndex = 0; layerIndex < layerCount; layerIndex += 1) {
for (Uint32 levelIndex = 0; levelIndex < createinfo->num_levels; levelIndex += 1) {
Uint32 subresourceIndex = D3D12_INTERNAL_CalcSubresource(
levelIndex,
layerIndex,
createinfo->num_levels);
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;
if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) {
texture->subresources[subresourceIndex].rtvHandles = (D3D12StagingDescriptor *)SDL_calloc(depth, sizeof(D3D12StagingDescriptor));
for (Uint32 depthIndex = 0; depthIndex < depth; depthIndex += 1) {
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
&texture->subresources[subresourceIndex].rtvHandles[depthIndex]);
rtvDesc.Format = SDLToD3D12_TextureFormat[createinfo->format];
if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.MipSlice = levelIndex;
rtvDesc.Texture2DArray.FirstArraySlice = layerIndex;
rtvDesc.Texture2DArray.ArraySize = 1;
rtvDesc.Texture2DArray.PlaneSlice = 0;
} else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
rtvDesc.Texture3D.MipSlice = levelIndex;
rtvDesc.Texture3D.FirstWSlice = depthIndex;
rtvDesc.Texture3D.WSize = 1;
} else if (isMultisample) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
} 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);
}
}
if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_DSV,
&texture->subresources[subresourceIndex].dsvHandle);
dsvDesc.Format = SDLToD3D12_DepthFormat[createinfo->format];
dsvDesc.Flags = (D3D12_DSV_FLAGS)0;
if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
dsvDesc.Texture2DArray.MipSlice = levelIndex;
dsvDesc.Texture2DArray.FirstArraySlice = layerIndex;
dsvDesc.Texture2DArray.ArraySize = 1;
} else if (isMultisample) {
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
} else {
dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
dsvDesc.Texture2D.MipSlice = levelIndex;
}
ID3D12Device_CreateDepthStencilView(
renderer->device,
texture->resource,
&dsvDesc,
texture->subresources[subresourceIndex].dsvHandle.cpuHandle);
}
if (needsUAV) {
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
&texture->subresources[subresourceIndex].uavHandle);
uavDesc.Format = SDLToD3D12_TextureFormat[createinfo->format];
if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE || createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
uavDesc.Texture2DArray.MipSlice = levelIndex;
uavDesc.Texture2DArray.FirstArraySlice = layerIndex;
uavDesc.Texture2DArray.ArraySize = 1;
uavDesc.Texture2DArray.PlaneSlice = 0;
} else if (createinfo->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);
}
}
}
D3D12_INTERNAL_SetResourceName(
renderer,
texture->resource,
debugName);
return texture;
}
static SDL_GPUTexture *D3D12_CreateTexture(
SDL_GPURenderer *driverData,
const SDL_GPUTextureCreateInfo *createinfo)
{
D3D12TextureContainer *container = (D3D12TextureContainer *)SDL_calloc(1, sizeof(D3D12TextureContainer));
if (!container) {
return NULL;
}
container->header.info = *createinfo;
container->header.info.props = SDL_CreateProperties();
if (createinfo->props) {
SDL_CopyProperties(createinfo->props, container->header.info.props);
}
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;
if (SDL_HasProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING)) {
container->debugName = SDL_strdup(SDL_GetStringProperty(createinfo->props, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, NULL));
}
container->canBeCycled = true;
D3D12Texture *texture = D3D12_INTERNAL_CreateTexture(
(D3D12Renderer *)driverData,
createinfo,
false,
container->debugName);
if (!texture) {
SDL_free(container->textures);
SDL_free(container);
return NULL;
}
container->textures[0] = texture;
container->activeTexture = texture;
texture->container = container;
texture->containerIndex = 0;
return (SDL_GPUTexture *)container;
}
static D3D12Buffer *D3D12_INTERNAL_CreateBuffer(
D3D12Renderer *renderer,
SDL_GPUBufferUsageFlags usageFlags,
Uint32 size,
D3D12BufferType type,
const char *debugName)
{
D3D12Buffer *buffer;
ID3D12Resource *handle;
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc;
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
D3D12_HEAP_PROPERTIES heapProperties;
D3D12_RESOURCE_DESC desc;
D3D12_HEAP_FLAGS heapFlags = (D3D12_HEAP_FLAGS)0;
D3D12_RESOURCE_FLAGS resourceFlags = (D3D12_RESOURCE_FLAGS)0;
D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON;
HRESULT res;
buffer = (D3D12Buffer *)SDL_calloc(1, sizeof(D3D12Buffer));
if (!buffer) {
return NULL;
}
if (usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) {
resourceFlags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
if (usageFlags & SDL_GPU_BUFFERUSAGE_INDIRECT) {
resourceFlags |= D3D12XBOX_RESOURCE_FLAG_ALLOW_INDIRECT_BUFFER;
}
#endif
heapProperties.CreationNodeMask = 0; heapProperties.VisibleNodeMask = 0;
if (type == D3D12_BUFFER_TYPE_GPU) {
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
} else if (type == D3D12_BUFFER_TYPE_UPLOAD) {
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
} else if (type == D3D12_BUFFER_TYPE_DOWNLOAD) {
heapProperties.Type = D3D12_HEAP_TYPE_READBACK;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapFlags = D3D12_HEAP_FLAG_NONE;
initialState = D3D12_RESOURCE_STATE_COPY_DEST;
} else if (type == D3D12_BUFFER_TYPE_UNIFORM) {
if (renderer->GPUUploadHeapSupported) {
heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
} else {
heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD;
heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
initialState = D3D12_RESOURCE_STATE_GENERIC_READ;
}
heapFlags = D3D12_HEAP_FLAG_NONE;
} else {
SET_STRING_ERROR_AND_RETURN("Unrecognized buffer type!", NULL);
}
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
desc.Width = size;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = resourceFlags;
res = ID3D12Device_CreateCommittedResource(
renderer->device,
&heapProperties,
heapFlags,
&desc,
initialState,
NULL,
D3D_GUID(D3D_IID_ID3D12Resource),
(void **)&handle);
if (FAILED(res)) {
D3D12_INTERNAL_SetError(renderer, "Could not create buffer!", res);
D3D12_INTERNAL_DestroyBuffer(buffer);
return NULL;
}
buffer->handle = handle;
SDL_SetAtomicInt(&buffer->referenceCount, 0);
buffer->uavDescriptor.heap = NULL;
buffer->srvDescriptor.heap = NULL;
buffer->cbvDescriptor.heap = NULL;
if (usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_WRITE) {
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
&buffer->uavDescriptor);
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = size / sizeof(Uint32);
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
uavDesc.Buffer.CounterOffsetInBytes = 0; uavDesc.Buffer.StructureByteStride = 0;
ID3D12Device_CreateUnorderedAccessView(
renderer->device,
handle,
NULL, &uavDesc,
buffer->uavDescriptor.cpuHandle);
}
if (
(usageFlags & SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ) ||
(usageFlags & SDL_GPU_BUFFERUSAGE_COMPUTE_STORAGE_READ)) {
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
&buffer->srvDescriptor);
srvDesc.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
srvDesc.Buffer.FirstElement = 0;
srvDesc.Buffer.NumElements = size / sizeof(Uint32);
srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
srvDesc.Buffer.StructureByteStride = 0;
ID3D12Device_CreateShaderResourceView(
renderer->device,
handle,
&srvDesc,
buffer->srvDescriptor.cpuHandle);
}
if (type == D3D12_BUFFER_TYPE_UNIFORM) {
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
&buffer->cbvDescriptor);
cbvDesc.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(handle);
cbvDesc.SizeInBytes = size;
ID3D12Device_CreateConstantBufferView(
renderer->device,
&cbvDesc,
buffer->cbvDescriptor.cpuHandle);
}
buffer->virtualAddress = 0;
if (type == D3D12_BUFFER_TYPE_GPU || type == D3D12_BUFFER_TYPE_UNIFORM) {
buffer->virtualAddress = ID3D12Resource_GetGPUVirtualAddress(buffer->handle);
}
buffer->mapPointer = NULL;
if (type == D3D12_BUFFER_TYPE_UPLOAD) {
res = ID3D12Resource_Map(
buffer->handle,
0,
NULL,
(void **)&buffer->mapPointer);
if (FAILED(res)) {
D3D12_INTERNAL_SetError(renderer, "Failed to map upload buffer!", res);
D3D12_INTERNAL_DestroyBuffer(buffer);
return NULL;
}
}
buffer->container = NULL;
buffer->containerIndex = 0;
buffer->transitioned = initialState != D3D12_RESOURCE_STATE_COMMON;
SDL_SetAtomicInt(&buffer->referenceCount, 0);
D3D12_INTERNAL_SetResourceName(
renderer,
buffer->handle,
debugName);
return buffer;
}
static D3D12BufferContainer *D3D12_INTERNAL_CreateBufferContainer(
D3D12Renderer *renderer,
SDL_GPUBufferUsageFlags usageFlags,
Uint32 size,
D3D12BufferType type,
const char *debugName)
{
D3D12BufferContainer *container;
D3D12Buffer *buffer;
container = (D3D12BufferContainer *)SDL_calloc(1, sizeof(D3D12BufferContainer));
if (!container) {
return NULL;
}
container->usage = usageFlags;
container->size = size;
container->type = type;
container->bufferCapacity = 1;
container->bufferCount = 1;
container->buffers = (D3D12Buffer **)SDL_calloc(
container->bufferCapacity, sizeof(D3D12Buffer *));
if (!container->buffers) {
SDL_free(container);
return NULL;
}
container->debugName = NULL;
buffer = D3D12_INTERNAL_CreateBuffer(
renderer,
usageFlags,
size,
type,
debugName);
if (buffer == NULL) {
SDL_free(container->buffers);
SDL_free(container);
return NULL;
}
container->activeBuffer = buffer;
container->buffers[0] = buffer;
buffer->container = container;
buffer->containerIndex = 0;
if (debugName != NULL) {
container->debugName = SDL_strdup(debugName);
}
return container;
}
static SDL_GPUBuffer *D3D12_CreateBuffer(
SDL_GPURenderer *driverData,
SDL_GPUBufferUsageFlags usageFlags,
Uint32 size,
const char *debugName)
{
return (SDL_GPUBuffer *)D3D12_INTERNAL_CreateBufferContainer(
(D3D12Renderer *)driverData,
usageFlags,
size,
D3D12_BUFFER_TYPE_GPU,
debugName);
}
static SDL_GPUTransferBuffer *D3D12_CreateTransferBuffer(
SDL_GPURenderer *driverData,
SDL_GPUTransferBufferUsage usage,
Uint32 size,
const char *debugName)
{
return (SDL_GPUTransferBuffer *)D3D12_INTERNAL_CreateBufferContainer(
(D3D12Renderer *)driverData,
0,
size,
usage == SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD ? D3D12_BUFFER_TYPE_UPLOAD : D3D12_BUFFER_TYPE_DOWNLOAD,
debugName);
}
static void D3D12_ReleaseTexture(
SDL_GPURenderer *driverData,
SDL_GPUTexture *texture)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12TextureContainer *container = (D3D12TextureContainer *)texture;
D3D12_INTERNAL_ReleaseTextureContainer(
renderer,
container);
}
static void D3D12_ReleaseSampler(
SDL_GPURenderer *driverData,
SDL_GPUSampler *sampler)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12Sampler *d3d12Sampler = (D3D12Sampler *)sampler;
SDL_LockMutex(renderer->disposeLock);
EXPAND_ARRAY_IF_NEEDED(
renderer->samplersToDestroy,
D3D12Sampler *,
renderer->samplersToDestroyCount + 1,
renderer->samplersToDestroyCapacity,
renderer->samplersToDestroyCapacity * 2);
renderer->samplersToDestroy[renderer->samplersToDestroyCount] = d3d12Sampler;
renderer->samplersToDestroyCount += 1;
SDL_UnlockMutex(renderer->disposeLock);
}
static void D3D12_ReleaseBuffer(
SDL_GPURenderer *driverData,
SDL_GPUBuffer *buffer)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12BufferContainer *bufferContainer = (D3D12BufferContainer *)buffer;
D3D12_INTERNAL_ReleaseBufferContainer(
renderer,
bufferContainer);
}
static void D3D12_ReleaseTransferBuffer(
SDL_GPURenderer *driverData,
SDL_GPUTransferBuffer *transferBuffer)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12BufferContainer *transferBufferContainer = (D3D12BufferContainer *)transferBuffer;
D3D12_INTERNAL_ReleaseBufferContainer(
renderer,
transferBufferContainer);
}
static void D3D12_ReleaseShader(
SDL_GPURenderer *driverData,
SDL_GPUShader *shader)
{
D3D12Shader *d3d12shader = (D3D12Shader *)shader;
if (d3d12shader->bytecode) {
SDL_free(d3d12shader->bytecode);
d3d12shader->bytecode = NULL;
}
SDL_free(d3d12shader);
}
static void D3D12_ReleaseComputePipeline(
SDL_GPURenderer *driverData,
SDL_GPUComputePipeline *computePipeline)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12ComputePipeline *d3d12ComputePipeline = (D3D12ComputePipeline *)computePipeline;
SDL_LockMutex(renderer->disposeLock);
EXPAND_ARRAY_IF_NEEDED(
renderer->computePipelinesToDestroy,
D3D12ComputePipeline *,
renderer->computePipelinesToDestroyCount + 1,
renderer->computePipelinesToDestroyCapacity,
renderer->computePipelinesToDestroyCapacity * 2);
renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount] = d3d12ComputePipeline;
renderer->computePipelinesToDestroyCount += 1;
SDL_UnlockMutex(renderer->disposeLock);
}
static void D3D12_ReleaseGraphicsPipeline(
SDL_GPURenderer *driverData,
SDL_GPUGraphicsPipeline *graphicsPipeline)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12GraphicsPipeline *d3d12GraphicsPipeline = (D3D12GraphicsPipeline *)graphicsPipeline;
SDL_LockMutex(renderer->disposeLock);
EXPAND_ARRAY_IF_NEEDED(
renderer->graphicsPipelinesToDestroy,
D3D12GraphicsPipeline *,
renderer->graphicsPipelinesToDestroyCount + 1,
renderer->graphicsPipelinesToDestroyCapacity,
renderer->graphicsPipelinesToDestroyCapacity * 2);
renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount] = d3d12GraphicsPipeline;
renderer->graphicsPipelinesToDestroyCount += 1;
SDL_UnlockMutex(renderer->disposeLock);
}
static void D3D12_INTERNAL_ReleaseBlitPipelines(SDL_GPURenderer *driverData)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12_ReleaseSampler(driverData, renderer->blitLinearSampler);
D3D12_ReleaseSampler(driverData, renderer->blitNearestSampler);
D3D12_ReleaseShader(driverData, renderer->blitVertexShader);
D3D12_ReleaseShader(driverData, renderer->blitFrom2DShader);
D3D12_ReleaseShader(driverData, renderer->blitFrom2DArrayShader);
D3D12_ReleaseShader(driverData, renderer->blitFrom3DShader);
D3D12_ReleaseShader(driverData, renderer->blitFromCubeShader);
D3D12_ReleaseShader(driverData, renderer->blitFromCubeArrayShader);
for (Uint32 i = 0; i < renderer->blitPipelineCount; i += 1) {
D3D12_ReleaseGraphicsPipeline(driverData, renderer->blitPipelines[i].pipeline);
}
SDL_free(renderer->blitPipelines);
}
static void D3D12_SetViewport(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUViewport *viewport)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_VIEWPORT d3d12Viewport;
d3d12Viewport.TopLeftX = viewport->x;
d3d12Viewport.TopLeftY = viewport->y;
d3d12Viewport.Width = viewport->w;
d3d12Viewport.Height = viewport->h;
d3d12Viewport.MinDepth = viewport->min_depth;
d3d12Viewport.MaxDepth = viewport->max_depth;
ID3D12GraphicsCommandList_RSSetViewports(d3d12CommandBuffer->graphicsCommandList, 1, &d3d12Viewport);
}
static void D3D12_SetScissor(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_Rect *scissor)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_RECT scissorRect;
scissorRect.left = scissor->x;
scissorRect.top = scissor->y;
scissorRect.right = scissor->x + scissor->w;
scissorRect.bottom = scissor->y + scissor->h;
ID3D12GraphicsCommandList_RSSetScissorRects(d3d12CommandBuffer->graphicsCommandList, 1, &scissorRect);
}
static void D3D12_SetBlendConstants(
SDL_GPUCommandBuffer *commandBuffer,
SDL_FColor blendConstants)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
FLOAT blendFactor[4] = { blendConstants.r, blendConstants.g, blendConstants.b, blendConstants.a };
ID3D12GraphicsCommandList_OMSetBlendFactor(d3d12CommandBuffer->graphicsCommandList, blendFactor);
}
static void D3D12_SetStencilReference(
SDL_GPUCommandBuffer *commandBuffer,
Uint8 reference
) {
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandBuffer->graphicsCommandList, reference);
}
static D3D12TextureSubresource *D3D12_INTERNAL_FetchTextureSubresource(
D3D12TextureContainer *container,
Uint32 layer,
Uint32 level)
{
Uint32 index = D3D12_INTERNAL_CalcSubresource(
level,
layer,
container->header.info.num_levels);
return &container->activeTexture->subresources[index];
}
static void D3D12_INTERNAL_CycleActiveTexture(
D3D12Renderer *renderer,
D3D12TextureContainer *container)
{
D3D12Texture *texture;
for (Uint32 i = 0; i < container->textureCount; i += 1) {
texture = container->textures[i];
if (SDL_GetAtomicInt(&texture->referenceCount) == 0) {
container->activeTexture = texture;
return;
}
}
texture = D3D12_INTERNAL_CreateTexture(
renderer,
&container->header.info,
false,
container->debugName);
if (!texture) {
return;
}
EXPAND_ARRAY_IF_NEEDED(
container->textures,
D3D12Texture *,
container->textureCount + 1,
container->textureCapacity,
container->textureCapacity * 2);
container->textures[container->textureCount] = texture;
texture->container = container;
texture->containerIndex = container->textureCount;
container->textureCount += 1;
container->activeTexture = texture;
}
static D3D12TextureSubresource *D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
D3D12CommandBuffer *commandBuffer,
D3D12TextureContainer *container,
Uint32 layer,
Uint32 level,
bool cycle,
D3D12_RESOURCE_STATES destinationUsageMode)
{
D3D12TextureSubresource *subresource = D3D12_INTERNAL_FetchTextureSubresource(
container,
layer,
level);
if (
container->canBeCycled &&
cycle &&
SDL_GetAtomicInt(&subresource->parent->referenceCount) > 0) {
D3D12_INTERNAL_CycleActiveTexture(
commandBuffer->renderer,
container);
subresource = D3D12_INTERNAL_FetchTextureSubresource(
container,
layer,
level);
}
D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
commandBuffer,
destinationUsageMode,
subresource);
return subresource;
}
static void D3D12_INTERNAL_CycleActiveBuffer(
D3D12Renderer *renderer,
D3D12BufferContainer *container)
{
for (Uint32 i = 0; i < container->bufferCount; i += 1) {
D3D12Buffer *buffer = container->buffers[i];
if (SDL_GetAtomicInt(&buffer->referenceCount) == 0) {
container->activeBuffer = buffer;
return;
}
}
D3D12Buffer *buffer = D3D12_INTERNAL_CreateBuffer(
renderer,
container->usage,
container->size,
container->type,
container->debugName);
if (!buffer) {
return;
}
EXPAND_ARRAY_IF_NEEDED(
container->buffers,
D3D12Buffer *,
container->bufferCount + 1,
container->bufferCapacity,
container->bufferCapacity * 2);
container->buffers[container->bufferCount] = buffer;
buffer->container = container;
buffer->containerIndex = container->bufferCount;
container->bufferCount += 1;
container->activeBuffer = buffer;
if (renderer->debug_mode && container->debugName != NULL) {
D3D12_INTERNAL_SetResourceName(
renderer,
container->activeBuffer->handle,
container->debugName);
}
}
static D3D12Buffer *D3D12_INTERNAL_PrepareBufferForWrite(
D3D12CommandBuffer *commandBuffer,
D3D12BufferContainer *container,
bool cycle,
D3D12_RESOURCE_STATES destinationState)
{
if (
cycle &&
SDL_GetAtomicInt(&container->activeBuffer->referenceCount) > 0) {
D3D12_INTERNAL_CycleActiveBuffer(
commandBuffer->renderer,
container);
}
D3D12_INTERNAL_BufferTransitionFromDefaultUsage(
commandBuffer,
destinationState,
container->activeBuffer);
return container->activeBuffer;
}
static void D3D12_BeginRenderPass(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUColorTargetInfo *colorTargetInfos,
Uint32 numColorTargets,
const SDL_GPUDepthStencilTargetInfo *depthStencilTargetInfo)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
Uint32 framebufferWidth = SDL_MAX_UINT32;
Uint32 framebufferHeight = SDL_MAX_UINT32;
for (Uint32 i = 0; i < numColorTargets; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)colorTargetInfos[i].texture;
Uint32 h = container->header.info.height >> colorTargetInfos[i].mip_level;
Uint32 w = container->header.info.width >> colorTargetInfos[i].mip_level;
if (w < framebufferWidth) {
framebufferWidth = w;
}
if (h < framebufferHeight) {
framebufferHeight = h;
}
}
if (depthStencilTargetInfo != NULL) {
D3D12TextureContainer *container = (D3D12TextureContainer *)depthStencilTargetInfo->texture;
Uint32 h = container->header.info.height >> depthStencilTargetInfo->mip_level;
Uint32 w = container->header.info.width >> depthStencilTargetInfo->mip_level;
if (w < framebufferWidth) {
framebufferWidth = w;
}
if (h < framebufferHeight) {
framebufferHeight = h;
}
}
D3D12_CPU_DESCRIPTOR_HANDLE rtvs[MAX_COLOR_TARGET_BINDINGS];
for (Uint32 i = 0; i < numColorTargets; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)colorTargetInfos[i].texture;
D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
d3d12CommandBuffer,
container,
container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? 0 : colorTargetInfos[i].layer_or_depth_plane,
colorTargetInfos[i].mip_level,
colorTargetInfos[i].cycle,
D3D12_RESOURCE_STATE_RENDER_TARGET);
Uint32 rtvIndex = container->header.info.type == SDL_GPU_TEXTURETYPE_3D ? colorTargetInfos[i].layer_or_depth_plane : 0;
D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->rtvHandles[rtvIndex].cpuHandle;
if (colorTargetInfos[i].load_op == SDL_GPU_LOADOP_CLEAR) {
float clearColor[4];
clearColor[0] = colorTargetInfos[i].clear_color.r;
clearColor[1] = colorTargetInfos[i].clear_color.g;
clearColor[2] = colorTargetInfos[i].clear_color.b;
clearColor[3] = colorTargetInfos[i].clear_color.a;
ID3D12GraphicsCommandList_ClearRenderTargetView(
d3d12CommandBuffer->graphicsCommandList,
rtv,
clearColor,
0,
NULL);
}
rtvs[i] = rtv;
d3d12CommandBuffer->colorTargetSubresources[i] = subresource;
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, subresource->parent);
if (colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE || colorTargetInfos[i].store_op == SDL_GPU_STOREOP_RESOLVE_AND_STORE) {
D3D12TextureContainer *resolveContainer = (D3D12TextureContainer *)colorTargetInfos[i].resolve_texture;
D3D12TextureSubresource *resolveSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
d3d12CommandBuffer,
resolveContainer,
colorTargetInfos[i].resolve_layer,
colorTargetInfos[i].resolve_mip_level,
colorTargetInfos[i].cycle_resolve_texture,
D3D12_RESOURCE_STATE_RESOLVE_DEST);
d3d12CommandBuffer->colorResolveSubresources[i] = resolveSubresource;
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, resolveSubresource->parent);
}
}
D3D12_CPU_DESCRIPTOR_HANDLE dsv;
if (depthStencilTargetInfo != NULL) {
D3D12TextureContainer *container = (D3D12TextureContainer *)depthStencilTargetInfo->texture;
D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
d3d12CommandBuffer,
container,
depthStencilTargetInfo->layer,
depthStencilTargetInfo->mip_level,
depthStencilTargetInfo->cycle,
D3D12_RESOURCE_STATE_DEPTH_WRITE);
if (
depthStencilTargetInfo->load_op == SDL_GPU_LOADOP_CLEAR ||
depthStencilTargetInfo->stencil_load_op == SDL_GPU_LOADOP_CLEAR) {
D3D12_CLEAR_FLAGS clearFlags = (D3D12_CLEAR_FLAGS)0;
if (depthStencilTargetInfo->load_op == SDL_GPU_LOADOP_CLEAR) {
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
}
if (depthStencilTargetInfo->stencil_load_op == SDL_GPU_LOADOP_CLEAR) {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
}
ID3D12GraphicsCommandList_ClearDepthStencilView(
d3d12CommandBuffer->graphicsCommandList,
subresource->dsvHandle.cpuHandle,
clearFlags,
depthStencilTargetInfo->clear_depth,
depthStencilTargetInfo->clear_stencil,
0,
NULL);
}
dsv = subresource->dsvHandle.cpuHandle;
d3d12CommandBuffer->depthStencilTextureSubresource = subresource;
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, subresource->parent);
}
ID3D12GraphicsCommandList_OMSetRenderTargets(
d3d12CommandBuffer->graphicsCommandList,
numColorTargets,
rtvs,
false,
(depthStencilTargetInfo == NULL) ? NULL : &dsv);
SDL_GPUViewport defaultViewport;
defaultViewport.x = 0;
defaultViewport.y = 0;
defaultViewport.w = (float)framebufferWidth;
defaultViewport.h = (float)framebufferHeight;
defaultViewport.min_depth = 0;
defaultViewport.max_depth = 1;
D3D12_SetViewport(
commandBuffer,
&defaultViewport);
SDL_Rect defaultScissor;
defaultScissor.x = 0;
defaultScissor.y = 0;
defaultScissor.w = (Sint32)framebufferWidth;
defaultScissor.h = (Sint32)framebufferHeight;
D3D12_SetScissor(
commandBuffer,
&defaultScissor);
D3D12_SetStencilReference(
commandBuffer,
0);
SDL_FColor blendConstants;
blendConstants.r = 1.0f;
blendConstants.g = 1.0f;
blendConstants.b = 1.0f;
blendConstants.a = 1.0f;
D3D12_SetBlendConstants(
commandBuffer,
blendConstants);
}
static void D3D12_INTERNAL_TrackUniformBuffer(
D3D12CommandBuffer *commandBuffer,
D3D12UniformBuffer *uniformBuffer)
{
Uint32 i;
for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) {
if (commandBuffer->usedUniformBuffers[i] == uniformBuffer) {
return;
}
}
if (commandBuffer->usedUniformBufferCount == commandBuffer->usedUniformBufferCapacity) {
commandBuffer->usedUniformBufferCapacity += 1;
commandBuffer->usedUniformBuffers = (D3D12UniformBuffer **)SDL_realloc(
commandBuffer->usedUniformBuffers,
commandBuffer->usedUniformBufferCapacity * sizeof(D3D12UniformBuffer *));
}
commandBuffer->usedUniformBuffers[commandBuffer->usedUniformBufferCount] = uniformBuffer;
commandBuffer->usedUniformBufferCount += 1;
D3D12_INTERNAL_TrackBuffer(
commandBuffer,
uniformBuffer->buffer);
}
static D3D12UniformBuffer *D3D12_INTERNAL_AcquireUniformBufferFromPool(
D3D12CommandBuffer *commandBuffer)
{
D3D12Renderer *renderer = commandBuffer->renderer;
D3D12UniformBuffer *uniformBuffer;
SDL_LockMutex(renderer->acquireUniformBufferLock);
if (renderer->uniformBufferPoolCount > 0) {
uniformBuffer = renderer->uniformBufferPool[renderer->uniformBufferPoolCount - 1];
renderer->uniformBufferPoolCount -= 1;
} else {
uniformBuffer = (D3D12UniformBuffer *)SDL_calloc(1, sizeof(D3D12UniformBuffer));
if (!uniformBuffer) {
SDL_UnlockMutex(renderer->acquireUniformBufferLock);
return NULL;
}
uniformBuffer->buffer = D3D12_INTERNAL_CreateBuffer(
renderer,
0,
UNIFORM_BUFFER_SIZE,
D3D12_BUFFER_TYPE_UNIFORM,
NULL);
if (!uniformBuffer->buffer) {
SDL_UnlockMutex(renderer->acquireUniformBufferLock);
return NULL;
}
}
SDL_UnlockMutex(renderer->acquireUniformBufferLock);
uniformBuffer->drawOffset = 0;
uniformBuffer->writeOffset = 0;
HRESULT res = ID3D12Resource_Map(
uniformBuffer->buffer->handle,
0,
NULL,
(void **)&uniformBuffer->buffer->mapPointer);
CHECK_D3D12_ERROR_AND_RETURN("Failed to map buffer pool!", NULL);
D3D12_INTERNAL_TrackUniformBuffer(commandBuffer, uniformBuffer);
return uniformBuffer;
}
static void D3D12_INTERNAL_ReturnUniformBufferToPool(
D3D12Renderer *renderer,
D3D12UniformBuffer *uniformBuffer)
{
if (renderer->uniformBufferPoolCount >= renderer->uniformBufferPoolCapacity) {
renderer->uniformBufferPoolCapacity *= 2;
renderer->uniformBufferPool = (D3D12UniformBuffer **)SDL_realloc(
renderer->uniformBufferPool,
renderer->uniformBufferPoolCapacity * sizeof(D3D12UniformBuffer *));
}
renderer->uniformBufferPool[renderer->uniformBufferPoolCount] = uniformBuffer;
renderer->uniformBufferPoolCount += 1;
}
static void D3D12_INTERNAL_PushUniformData(
D3D12CommandBuffer *commandBuffer,
SDL_GPUShaderStage shaderStage,
Uint32 slotIndex,
const void *data,
Uint32 length)
{
D3D12UniformBuffer *uniformBuffer;
Uint32 blockSize;
if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
if (commandBuffer->vertexUniformBuffers[slotIndex] == NULL) {
commandBuffer->vertexUniformBuffers[slotIndex] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
commandBuffer);
}
uniformBuffer = commandBuffer->vertexUniformBuffers[slotIndex];
} else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) {
if (commandBuffer->fragmentUniformBuffers[slotIndex] == NULL) {
commandBuffer->fragmentUniformBuffers[slotIndex] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
commandBuffer);
}
uniformBuffer = commandBuffer->fragmentUniformBuffers[slotIndex];
} else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) {
if (commandBuffer->computeUniformBuffers[slotIndex] == NULL) {
commandBuffer->computeUniformBuffers[slotIndex] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
commandBuffer);
}
uniformBuffer = commandBuffer->computeUniformBuffers[slotIndex];
} else {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
return;
}
blockSize =
D3D12_INTERNAL_Align(
length,
256);
if (uniformBuffer->writeOffset + blockSize >= UNIFORM_BUFFER_SIZE) {
ID3D12Resource_Unmap(
uniformBuffer->buffer->handle,
0,
NULL);
uniformBuffer->buffer->mapPointer = NULL;
uniformBuffer = D3D12_INTERNAL_AcquireUniformBufferFromPool(commandBuffer);
uniformBuffer->drawOffset = 0;
uniformBuffer->writeOffset = 0;
if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
commandBuffer->vertexUniformBuffers[slotIndex] = uniformBuffer;
} else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) {
commandBuffer->fragmentUniformBuffers[slotIndex] = uniformBuffer;
} else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) {
commandBuffer->computeUniformBuffers[slotIndex] = uniformBuffer;
} else {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
}
}
uniformBuffer->drawOffset = uniformBuffer->writeOffset;
SDL_memcpy(
(Uint8 *)uniformBuffer->buffer->mapPointer + uniformBuffer->writeOffset,
data,
length);
uniformBuffer->writeOffset += blockSize;
if (shaderStage == SDL_GPU_SHADERSTAGE_VERTEX) {
commandBuffer->needVertexUniformBufferBind[slotIndex] = true;
} else if (shaderStage == SDL_GPU_SHADERSTAGE_FRAGMENT) {
commandBuffer->needFragmentUniformBufferBind[slotIndex] = true;
} else if (shaderStage == SDL_GPU_SHADERSTAGE_COMPUTE) {
commandBuffer->needComputeUniformBufferBind[slotIndex] = true;
} else {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Unrecognized shader stage!");
}
}
static void D3D12_BindGraphicsPipeline(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUGraphicsPipeline *graphicsPipeline)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12GraphicsPipeline *pipeline = (D3D12GraphicsPipeline *)graphicsPipeline;
Uint32 i;
d3d12CommandBuffer->currentGraphicsPipeline = pipeline;
ID3D12GraphicsCommandList_SetPipelineState(d3d12CommandBuffer->graphicsCommandList, pipeline->pipelineState);
ID3D12GraphicsCommandList_SetGraphicsRootSignature(d3d12CommandBuffer->graphicsCommandList, pipeline->rootSignature->handle);
ID3D12GraphicsCommandList_IASetPrimitiveTopology(d3d12CommandBuffer->graphicsCommandList, SDLToD3D12_PrimitiveType[pipeline->primitiveType]);
d3d12CommandBuffer->needVertexSamplerBind = true;
d3d12CommandBuffer->needVertexStorageTextureBind = true;
d3d12CommandBuffer->needVertexStorageBufferBind = true;
d3d12CommandBuffer->needFragmentSamplerBind = true;
d3d12CommandBuffer->needFragmentStorageTextureBind = true;
d3d12CommandBuffer->needFragmentStorageBufferBind = true;
for (i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
d3d12CommandBuffer->needVertexUniformBufferBind[i] = true;
d3d12CommandBuffer->needFragmentUniformBufferBind[i] = true;
}
for (i = 0; i < pipeline->header.num_vertex_uniform_buffers; i += 1) {
if (d3d12CommandBuffer->vertexUniformBuffers[i] == NULL) {
d3d12CommandBuffer->vertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
d3d12CommandBuffer);
}
}
for (i = 0; i < pipeline->header.num_fragment_uniform_buffers; i += 1) {
if (d3d12CommandBuffer->fragmentUniformBuffers[i] == NULL) {
d3d12CommandBuffer->fragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
d3d12CommandBuffer);
}
}
D3D12_INTERNAL_TrackGraphicsPipeline(d3d12CommandBuffer, pipeline);
}
static void D3D12_BindVertexBuffers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
const SDL_GPUBufferBinding *bindings,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12Buffer *currentBuffer = ((D3D12BufferContainer *)bindings[i].buffer)->activeBuffer;
if (d3d12CommandBuffer->vertexBuffers[firstSlot + i] != currentBuffer || d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] != bindings[i].offset) {
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, currentBuffer);
d3d12CommandBuffer->vertexBuffers[firstSlot + i] = currentBuffer;
d3d12CommandBuffer->vertexBufferOffsets[firstSlot + i] = bindings[i].offset;
d3d12CommandBuffer->needVertexBufferBind = true;
}
}
d3d12CommandBuffer->vertexBufferCount =
SDL_max(d3d12CommandBuffer->vertexBufferCount, firstSlot + numBindings);
}
static void D3D12_BindIndexBuffer(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUBufferBinding *binding,
SDL_GPUIndexElementSize indexElementSize)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Buffer *buffer = ((D3D12BufferContainer *)binding->buffer)->activeBuffer;
D3D12_INDEX_BUFFER_VIEW view;
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, buffer);
view.BufferLocation = buffer->virtualAddress + binding->offset;
view.SizeInBytes = buffer->container->size - binding->offset;
view.Format =
indexElementSize == SDL_GPU_INDEXELEMENTSIZE_16BIT ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
ID3D12GraphicsCommandList_IASetIndexBuffer(
d3d12CommandBuffer->graphicsCommandList,
&view);
}
static void D3D12_BindVertexSamplers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
const SDL_GPUTextureSamplerBinding *textureSamplerBindings,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture;
D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler;
if (d3d12CommandBuffer->vertexSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackSampler(
d3d12CommandBuffer,
sampler);
d3d12CommandBuffer->vertexSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle;
d3d12CommandBuffer->needVertexSamplerBind = true;
}
if (d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
container->activeTexture);
d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
d3d12CommandBuffer->needVertexSamplerBind = true;
}
}
}
static void D3D12_BindVertexStorageTextures(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
SDL_GPUTexture *const *storageTextures,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i];
D3D12Texture *texture = container->activeTexture;
if (d3d12CommandBuffer->vertexStorageTextureDescriptorHandles[firstSlot + i].ptr != texture->srvHandle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture);
d3d12CommandBuffer->vertexStorageTextureDescriptorHandles[firstSlot + i] = texture->srvHandle.cpuHandle;
d3d12CommandBuffer->needVertexStorageTextureBind = true;
}
}
}
static void D3D12_BindVertexStorageBuffers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
SDL_GPUBuffer *const *storageBuffers,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i];
if (d3d12CommandBuffer->vertexStorageBufferDescriptorHandles[firstSlot + i].ptr != container->activeBuffer->srvDescriptor.cpuHandle.ptr) {
D3D12_INTERNAL_TrackBuffer(
d3d12CommandBuffer,
container->activeBuffer);
d3d12CommandBuffer->vertexStorageBufferDescriptorHandles[firstSlot + i] = container->activeBuffer->srvDescriptor.cpuHandle;
d3d12CommandBuffer->needVertexStorageBufferBind = true;
}
}
}
static void D3D12_BindFragmentSamplers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
const SDL_GPUTextureSamplerBinding *textureSamplerBindings,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture;
D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler;
if (d3d12CommandBuffer->fragmentSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackSampler(
d3d12CommandBuffer,
sampler);
d3d12CommandBuffer->fragmentSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle;
d3d12CommandBuffer->needFragmentSamplerBind = true;
}
if (d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
container->activeTexture);
d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
d3d12CommandBuffer->needFragmentSamplerBind = true;
}
}
}
static void D3D12_BindFragmentStorageTextures(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
SDL_GPUTexture *const *storageTextures,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i];
D3D12Texture *texture = container->activeTexture;
if (d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles[firstSlot + i].ptr != texture->srvHandle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, texture);
d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles[firstSlot + i] = texture->srvHandle.cpuHandle;
d3d12CommandBuffer->needFragmentStorageTextureBind = true;
}
}
}
static void D3D12_BindFragmentStorageBuffers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
SDL_GPUBuffer *const *storageBuffers,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i];
if (d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles[firstSlot + i].ptr != container->activeBuffer->srvDescriptor.cpuHandle.ptr) {
D3D12_INTERNAL_TrackBuffer(
d3d12CommandBuffer,
container->activeBuffer);
d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles[firstSlot + i] = container->activeBuffer->srvDescriptor.cpuHandle;
d3d12CommandBuffer->needFragmentStorageBufferBind = true;
}
}
}
static void D3D12_PushVertexUniformData(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 slotIndex,
const void *data,
Uint32 length)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_INTERNAL_PushUniformData(
d3d12CommandBuffer,
SDL_GPU_SHADERSTAGE_VERTEX,
slotIndex,
data,
length);
}
static void D3D12_PushFragmentUniformData(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 slotIndex,
const void *data,
Uint32 length)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_INTERNAL_PushUniformData(
d3d12CommandBuffer,
SDL_GPU_SHADERSTAGE_FRAGMENT,
slotIndex,
data,
length);
}
static void D3D12_INTERNAL_SetGPUDescriptorHeaps(D3D12CommandBuffer *commandBuffer)
{
ID3D12DescriptorHeap *heaps[2];
D3D12DescriptorHeap *viewHeap;
D3D12DescriptorHeap *samplerHeap;
viewHeap = D3D12_INTERNAL_AcquireGPUDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
samplerHeap = D3D12_INTERNAL_AcquireGPUDescriptorHeapFromPool(commandBuffer, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
commandBuffer->gpuDescriptorHeaps[0] = viewHeap;
commandBuffer->gpuDescriptorHeaps[1] = samplerHeap;
heaps[0] = viewHeap->handle;
heaps[1] = samplerHeap->handle;
ID3D12GraphicsCommandList_SetDescriptorHeaps(
commandBuffer->graphicsCommandList,
2,
heaps);
}
static void D3D12_INTERNAL_WriteGPUDescriptors(
D3D12CommandBuffer *commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE heapType,
D3D12_CPU_DESCRIPTOR_HANDLE *resourceDescriptorHandles,
Uint32 resourceHandleCount,
D3D12_GPU_DESCRIPTOR_HANDLE *gpuBaseDescriptor)
{
D3D12DescriptorHeap *heap;
D3D12_CPU_DESCRIPTOR_HANDLE gpuHeapCpuHandle;
if (commandBuffer->gpuDescriptorHeaps[heapType]->currentDescriptorIndex >= commandBuffer->gpuDescriptorHeaps[heapType]->maxDescriptors) {
D3D12_INTERNAL_SetGPUDescriptorHeaps(commandBuffer);
}
heap = commandBuffer->gpuDescriptorHeaps[heapType];
gpuHeapCpuHandle.ptr = heap->descriptorHeapCPUStart.ptr + (heap->currentDescriptorIndex * heap->descriptorSize);
gpuBaseDescriptor->ptr = heap->descriptorHeapGPUStart.ptr + (heap->currentDescriptorIndex * heap->descriptorSize);
for (Uint32 i = 0; i < resourceHandleCount; i += 1) {
if (resourceDescriptorHandles[i].ptr != 0)
{
ID3D12Device_CopyDescriptorsSimple(
commandBuffer->renderer->device,
1,
gpuHeapCpuHandle,
resourceDescriptorHandles[i],
heapType);
heap->currentDescriptorIndex += 1;
gpuHeapCpuHandle.ptr += heap->descriptorSize;
}
}
}
static void D3D12_INTERNAL_BindGraphicsResources(
D3D12CommandBuffer *commandBuffer)
{
D3D12GraphicsPipeline *graphicsPipeline = commandBuffer->currentGraphicsPipeline;
if (commandBuffer->gpuDescriptorHeaps[0] == NULL) {
D3D12_INTERNAL_SetGPUDescriptorHeaps(commandBuffer);
}
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle;
D3D12_VERTEX_BUFFER_VIEW vertexBufferViews[MAX_VERTEX_BUFFERS];
if (commandBuffer->needVertexBufferBind) {
for (Uint32 i = 0; i < commandBuffer->vertexBufferCount; i += 1) {
vertexBufferViews[i].BufferLocation = commandBuffer->vertexBuffers[i]->virtualAddress + commandBuffer->vertexBufferOffsets[i];
vertexBufferViews[i].SizeInBytes = commandBuffer->vertexBuffers[i]->container->size - commandBuffer->vertexBufferOffsets[i];
vertexBufferViews[i].StrideInBytes = graphicsPipeline->vertexStrides[i];
}
ID3D12GraphicsCommandList_IASetVertexBuffers(
commandBuffer->graphicsCommandList,
0,
commandBuffer->vertexBufferCount,
vertexBufferViews);
commandBuffer->needVertexBufferBind = false;
}
if (commandBuffer->needVertexSamplerBind) {
if (graphicsPipeline->header.num_vertex_samplers > 0) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_samplers; i += 1) {
cpuHandles[i] = commandBuffer->vertexSamplerDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
cpuHandles,
graphicsPipeline->header.num_vertex_samplers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->vertexSamplerRootIndex,
gpuDescriptorHandle);
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_samplers; i += 1) {
cpuHandles[i] = commandBuffer->vertexSamplerTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
graphicsPipeline->header.num_vertex_samplers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->vertexSamplerTextureRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needVertexSamplerBind = false;
}
if (commandBuffer->needVertexStorageTextureBind) {
if (graphicsPipeline->header.num_vertex_storage_textures > 0) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_storage_textures; i += 1) {
cpuHandles[i] = commandBuffer->vertexStorageTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
graphicsPipeline->header.num_vertex_storage_textures,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->vertexStorageTextureRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needVertexStorageTextureBind = false;
}
if (commandBuffer->needVertexStorageBufferBind) {
if (graphicsPipeline->header.num_vertex_storage_buffers > 0) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_vertex_storage_buffers; i += 1) {
cpuHandles[i] = commandBuffer->vertexStorageBufferDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
graphicsPipeline->header.num_vertex_storage_buffers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->vertexStorageBufferRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needVertexStorageBufferBind = false;
}
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
if (commandBuffer->needVertexUniformBufferBind[i]) {
if (graphicsPipeline->header.num_vertex_uniform_buffers > i) {
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->vertexUniformBufferRootIndex[i],
commandBuffer->vertexUniformBuffers[i]->buffer->virtualAddress + commandBuffer->vertexUniformBuffers[i]->drawOffset);
}
commandBuffer->needVertexUniformBufferBind[i] = false;
}
}
if (commandBuffer->needFragmentSamplerBind) {
if (graphicsPipeline->header.num_fragment_samplers > 0) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_samplers; i += 1) {
cpuHandles[i] = commandBuffer->fragmentSamplerDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
cpuHandles,
graphicsPipeline->header.num_fragment_samplers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->fragmentSamplerRootIndex,
gpuDescriptorHandle);
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_samplers; i += 1) {
cpuHandles[i] = commandBuffer->fragmentSamplerTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
graphicsPipeline->header.num_fragment_samplers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->fragmentSamplerTextureRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needFragmentSamplerBind = false;
}
if (commandBuffer->needFragmentStorageTextureBind) {
if (graphicsPipeline->header.num_fragment_storage_textures > 0) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_storage_textures; i += 1) {
cpuHandles[i] = commandBuffer->fragmentStorageTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
graphicsPipeline->header.num_fragment_storage_textures,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->fragmentStorageTextureRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needFragmentStorageTextureBind = false;
}
if (commandBuffer->needFragmentStorageBufferBind) {
if (graphicsPipeline->header.num_fragment_storage_buffers > 0) {
for (Uint32 i = 0; i < graphicsPipeline->header.num_fragment_storage_buffers; i += 1) {
cpuHandles[i] = commandBuffer->fragmentStorageBufferDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
graphicsPipeline->header.num_fragment_storage_buffers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->fragmentStorageBufferRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needFragmentStorageBufferBind = false;
}
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
if (commandBuffer->needFragmentUniformBufferBind[i]) {
if (graphicsPipeline->header.num_fragment_uniform_buffers > i) {
ID3D12GraphicsCommandList_SetGraphicsRootConstantBufferView(
commandBuffer->graphicsCommandList,
graphicsPipeline->rootSignature->fragmentUniformBufferRootIndex[i],
commandBuffer->fragmentUniformBuffers[i]->buffer->virtualAddress + commandBuffer->fragmentUniformBuffers[i]->drawOffset);
}
commandBuffer->needFragmentUniformBufferBind[i] = false;
}
}
}
static void D3D12_DrawIndexedPrimitives(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 numIndices,
Uint32 numInstances,
Uint32 firstIndex,
Sint32 vertexOffset,
Uint32 firstInstance)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer);
ID3D12GraphicsCommandList_DrawIndexedInstanced(
d3d12CommandBuffer->graphicsCommandList,
numIndices,
numInstances,
firstIndex,
vertexOffset,
firstInstance);
}
static void D3D12_DrawPrimitives(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 numVertices,
Uint32 numInstances,
Uint32 firstVertex,
Uint32 firstInstance)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer);
ID3D12GraphicsCommandList_DrawInstanced(
d3d12CommandBuffer->graphicsCommandList,
numVertices,
numInstances,
firstVertex,
firstInstance);
}
static void D3D12_DrawPrimitivesIndirect(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUBuffer *buffer,
Uint32 offset,
Uint32 drawCount)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Buffer *d3d12Buffer = ((D3D12BufferContainer *)buffer)->activeBuffer;
D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer);
ID3D12GraphicsCommandList_ExecuteIndirect(
d3d12CommandBuffer->graphicsCommandList,
d3d12CommandBuffer->renderer->indirectDrawCommandSignature,
drawCount,
d3d12Buffer->handle,
offset,
NULL,
0);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, d3d12Buffer);
}
static void D3D12_DrawIndexedPrimitivesIndirect(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUBuffer *buffer,
Uint32 offset,
Uint32 drawCount)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Buffer *d3d12Buffer = ((D3D12BufferContainer *)buffer)->activeBuffer;
D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer);
ID3D12GraphicsCommandList_ExecuteIndirect(
d3d12CommandBuffer->graphicsCommandList,
d3d12CommandBuffer->renderer->indirectIndexedDrawCommandSignature,
drawCount,
d3d12Buffer->handle,
offset,
NULL,
0);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, d3d12Buffer);
}
static void D3D12_EndRenderPass(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
Uint32 i;
for (i = 0; i < MAX_COLOR_TARGET_BINDINGS; i += 1) {
if (d3d12CommandBuffer->colorTargetSubresources[i] != NULL) {
if (d3d12CommandBuffer->colorResolveSubresources[i] != NULL) {
D3D12_INTERNAL_TextureSubresourceBarrier(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
d3d12CommandBuffer->colorTargetSubresources[i]
);
ID3D12GraphicsCommandList_ResolveSubresource(
d3d12CommandBuffer->graphicsCommandList,
d3d12CommandBuffer->colorResolveSubresources[i]->parent->resource,
d3d12CommandBuffer->colorResolveSubresources[i]->index,
d3d12CommandBuffer->colorTargetSubresources[i]->parent->resource,
d3d12CommandBuffer->colorTargetSubresources[i]->index,
SDLToD3D12_TextureFormat[d3d12CommandBuffer->colorTargetSubresources[i]->parent->container->header.info.format]);
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE,
d3d12CommandBuffer->colorTargetSubresources[i]);
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_RESOLVE_DEST,
d3d12CommandBuffer->colorResolveSubresources[i]);
} else {
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_RENDER_TARGET,
d3d12CommandBuffer->colorTargetSubresources[i]);
}
}
}
if (d3d12CommandBuffer->depthStencilTextureSubresource != NULL) {
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_DEPTH_WRITE,
d3d12CommandBuffer->depthStencilTextureSubresource);
d3d12CommandBuffer->depthStencilTextureSubresource = NULL;
}
d3d12CommandBuffer->currentGraphicsPipeline = NULL;
ID3D12GraphicsCommandList_OMSetRenderTargets(
d3d12CommandBuffer->graphicsCommandList,
0,
NULL,
false,
NULL);
SDL_zeroa(d3d12CommandBuffer->colorTargetSubresources);
SDL_zeroa(d3d12CommandBuffer->colorResolveSubresources);
d3d12CommandBuffer->depthStencilTextureSubresource = NULL;
SDL_zeroa(d3d12CommandBuffer->vertexBuffers);
SDL_zeroa(d3d12CommandBuffer->vertexBufferOffsets);
d3d12CommandBuffer->vertexBufferCount = 0;
SDL_zeroa(d3d12CommandBuffer->vertexSamplerTextureDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->vertexSamplerDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->vertexStorageTextureDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->vertexStorageBufferDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->fragmentSamplerTextureDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->fragmentSamplerDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->fragmentStorageTextureDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->fragmentStorageBufferDescriptorHandles);
}
static void D3D12_BeginComputePass(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUStorageTextureReadWriteBinding *storageTextureBindings,
Uint32 numStorageTextureBindings,
const SDL_GPUStorageBufferReadWriteBinding *storageBufferBindings,
Uint32 numStorageBufferBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount = numStorageTextureBindings;
d3d12CommandBuffer->computeReadWriteStorageBufferCount = numStorageBufferBindings;
if (numStorageTextureBindings > 0) {
for (Uint32 i = 0; i < numStorageTextureBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextureBindings[i].texture;
D3D12TextureSubresource *subresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
d3d12CommandBuffer,
container,
storageTextureBindings[i].layer,
storageTextureBindings[i].mip_level,
storageTextureBindings[i].cycle,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i] = subresource;
d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles[i] = subresource->uavHandle.cpuHandle;
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
subresource->parent);
}
}
if (numStorageBufferBindings > 0) {
for (Uint32 i = 0; i < numStorageBufferBindings; i += 1) {
D3D12BufferContainer *container = (D3D12BufferContainer *)storageBufferBindings[i].buffer;
D3D12Buffer *buffer = D3D12_INTERNAL_PrepareBufferForWrite(
d3d12CommandBuffer,
container,
storageBufferBindings[i].cycle,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
d3d12CommandBuffer->computeReadWriteStorageBuffers[i] = buffer;
d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles[i] = buffer->uavDescriptor.cpuHandle;
D3D12_INTERNAL_TrackBuffer(
d3d12CommandBuffer,
buffer);
}
}
}
static void D3D12_BindComputePipeline(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUComputePipeline *computePipeline)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
if (d3d12CommandBuffer->gpuDescriptorHeaps[0] == NULL) {
D3D12_INTERNAL_SetGPUDescriptorHeaps(d3d12CommandBuffer);
}
D3D12ComputePipeline *pipeline = (D3D12ComputePipeline *)computePipeline;
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle;
ID3D12GraphicsCommandList_SetPipelineState(
d3d12CommandBuffer->graphicsCommandList,
pipeline->pipelineState);
ID3D12GraphicsCommandList_SetComputeRootSignature(
d3d12CommandBuffer->graphicsCommandList,
pipeline->rootSignature->handle);
d3d12CommandBuffer->currentComputePipeline = pipeline;
d3d12CommandBuffer->needComputeSamplerBind = true;
d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true;
d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true;
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
d3d12CommandBuffer->needComputeUniformBufferBind[i] = true;
}
for (Uint32 i = 0; i < pipeline->header.numUniformBuffers; i += 1) {
if (d3d12CommandBuffer->computeUniformBuffers[i] == NULL) {
d3d12CommandBuffer->computeUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(
d3d12CommandBuffer);
}
}
D3D12_INTERNAL_TrackComputePipeline(d3d12CommandBuffer, pipeline);
if (pipeline->header.numReadWriteStorageTextures > 0) {
for (Uint32 i = 0; i < pipeline->header.numReadWriteStorageTextures; i += 1) {
cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
d3d12CommandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
d3d12CommandBuffer->graphicsCommandList,
d3d12CommandBuffer->currentComputePipeline->rootSignature->readWriteStorageTextureRootIndex,
gpuDescriptorHandle);
}
if (pipeline->header.numReadWriteStorageBuffers > 0) {
for (Uint32 i = 0; i < pipeline->header.numReadWriteStorageBuffers; i += 1) {
cpuHandles[i] = d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
d3d12CommandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
d3d12CommandBuffer->computeReadWriteStorageBufferCount,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
d3d12CommandBuffer->graphicsCommandList,
d3d12CommandBuffer->currentComputePipeline->rootSignature->readWriteStorageBufferRootIndex,
gpuDescriptorHandle);
}
}
static void D3D12_BindComputeSamplers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
const SDL_GPUTextureSamplerBinding *textureSamplerBindings,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)textureSamplerBindings[i].texture;
D3D12Sampler *sampler = (D3D12Sampler *)textureSamplerBindings[i].sampler;
if (d3d12CommandBuffer->computeSamplerDescriptorHandles[firstSlot + i].ptr != sampler->handle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackSampler(
d3d12CommandBuffer,
(D3D12Sampler *)textureSamplerBindings[i].sampler);
d3d12CommandBuffer->computeSamplerDescriptorHandles[firstSlot + i] = sampler->handle.cpuHandle;
d3d12CommandBuffer->needComputeSamplerBind = true;
}
if (d3d12CommandBuffer->computeSamplerTextureDescriptorHandles[firstSlot + i].ptr != container->activeTexture->srvHandle.cpuHandle.ptr) {
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
container->activeTexture);
d3d12CommandBuffer->computeSamplerTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
d3d12CommandBuffer->needComputeSamplerBind = true;
}
}
}
static void D3D12_BindComputeStorageTextures(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
SDL_GPUTexture *const *storageTextures,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12TextureContainer *container = (D3D12TextureContainer *)storageTextures[i];
if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != container->activeTexture) {
if (d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] != NULL) {
D3D12_INTERNAL_TextureTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i]);
}
D3D12_INTERNAL_TextureTransitionFromDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
container->activeTexture);
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
container->activeTexture);
d3d12CommandBuffer->computeReadOnlyStorageTextures[firstSlot + i] = container->activeTexture;
d3d12CommandBuffer->computeReadOnlyStorageTextureDescriptorHandles[firstSlot + i] = container->activeTexture->srvHandle.cpuHandle;
d3d12CommandBuffer->needComputeReadOnlyStorageTextureBind = true;
}
}
}
static void D3D12_BindComputeStorageBuffers(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 firstSlot,
SDL_GPUBuffer *const *storageBuffers,
Uint32 numBindings)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < numBindings; i += 1) {
D3D12BufferContainer *container = (D3D12BufferContainer *)storageBuffers[i];
D3D12Buffer *buffer = container->activeBuffer;
if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != buffer) {
if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] != NULL) {
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i]);
}
D3D12_INTERNAL_BufferTransitionFromDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
buffer);
D3D12_INTERNAL_TrackBuffer(
d3d12CommandBuffer,
buffer);
d3d12CommandBuffer->computeReadOnlyStorageBuffers[firstSlot + i] = buffer;
d3d12CommandBuffer->computeReadOnlyStorageBufferDescriptorHandles[firstSlot + i] = buffer->srvDescriptor.cpuHandle;
d3d12CommandBuffer->needComputeReadOnlyStorageBufferBind = true;
}
}
}
static void D3D12_PushComputeUniformData(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 slotIndex,
const void *data,
Uint32 length)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_INTERNAL_PushUniformData(
d3d12CommandBuffer,
SDL_GPU_SHADERSTAGE_COMPUTE,
slotIndex,
data,
length);
}
static void D3D12_INTERNAL_BindComputeResources(
D3D12CommandBuffer *commandBuffer)
{
D3D12ComputePipeline *computePipeline = commandBuffer->currentComputePipeline;
if (commandBuffer->gpuDescriptorHeaps[0] == NULL) {
D3D12_INTERNAL_SetGPUDescriptorHeaps(commandBuffer);
}
D3D12_CPU_DESCRIPTOR_HANDLE cpuHandles[MAX_TEXTURE_SAMPLERS_PER_STAGE];
D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle;
if (commandBuffer->needComputeSamplerBind) {
if (computePipeline->header.numSamplers > 0) {
for (Uint32 i = 0; i < computePipeline->header.numSamplers; i += 1) {
cpuHandles[i] = commandBuffer->computeSamplerDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
cpuHandles,
computePipeline->header.numSamplers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
commandBuffer->graphicsCommandList,
computePipeline->rootSignature->samplerRootIndex,
gpuDescriptorHandle);
for (Uint32 i = 0; i < computePipeline->header.numSamplers; i += 1) {
cpuHandles[i] = commandBuffer->computeSamplerTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
computePipeline->header.numSamplers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
commandBuffer->graphicsCommandList,
computePipeline->rootSignature->samplerTextureRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needComputeSamplerBind = false;
}
if (commandBuffer->needComputeReadOnlyStorageTextureBind) {
if (computePipeline->header.numReadonlyStorageTextures > 0) {
for (Uint32 i = 0; i < computePipeline->header.numReadonlyStorageTextures; i += 1) {
cpuHandles[i] = commandBuffer->computeReadOnlyStorageTextureDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
computePipeline->header.numReadonlyStorageTextures,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
commandBuffer->graphicsCommandList,
computePipeline->rootSignature->readOnlyStorageTextureRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needComputeReadOnlyStorageTextureBind = false;
}
if (commandBuffer->needComputeReadOnlyStorageBufferBind) {
if (computePipeline->header.numReadonlyStorageBuffers > 0) {
for (Uint32 i = 0; i < computePipeline->header.numReadonlyStorageBuffers; i += 1) {
cpuHandles[i] = commandBuffer->computeReadOnlyStorageBufferDescriptorHandles[i];
}
D3D12_INTERNAL_WriteGPUDescriptors(
commandBuffer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
cpuHandles,
computePipeline->header.numReadonlyStorageBuffers,
&gpuDescriptorHandle);
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
commandBuffer->graphicsCommandList,
computePipeline->rootSignature->readOnlyStorageBufferRootIndex,
gpuDescriptorHandle);
}
commandBuffer->needComputeReadOnlyStorageBufferBind = false;
}
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
if (commandBuffer->needComputeUniformBufferBind[i]) {
if (computePipeline->header.numUniformBuffers > i) {
ID3D12GraphicsCommandList_SetComputeRootConstantBufferView(
commandBuffer->graphicsCommandList,
computePipeline->rootSignature->uniformBufferRootIndex[i],
commandBuffer->computeUniformBuffers[i]->buffer->virtualAddress + commandBuffer->computeUniformBuffers[i]->drawOffset);
}
}
commandBuffer->needComputeUniformBufferBind[i] = false;
}
}
static void D3D12_DispatchCompute(
SDL_GPUCommandBuffer *commandBuffer,
Uint32 groupcountX,
Uint32 groupcountY,
Uint32 groupcountZ)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_INTERNAL_BindComputeResources(d3d12CommandBuffer);
ID3D12GraphicsCommandList_Dispatch(
d3d12CommandBuffer->graphicsCommandList,
groupcountX,
groupcountY,
groupcountZ);
}
static void D3D12_DispatchComputeIndirect(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUBuffer *buffer,
Uint32 offset)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Buffer *d3d12Buffer = ((D3D12BufferContainer *)buffer)->activeBuffer;
D3D12_INTERNAL_BindComputeResources(d3d12CommandBuffer);
ID3D12GraphicsCommandList_ExecuteIndirect(
d3d12CommandBuffer->graphicsCommandList,
d3d12CommandBuffer->renderer->indirectDispatchCommandSignature,
1,
d3d12Buffer->handle,
offset,
NULL,
0);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, d3d12Buffer);
}
static void D3D12_EndComputePass(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
for (Uint32 i = 0; i < d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount; i += 1) {
if (d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i]) {
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i]);
d3d12CommandBuffer->computeReadWriteStorageTextureSubresources[i] = NULL;
}
}
d3d12CommandBuffer->computeReadWriteStorageTextureSubresourceCount = 0;
for (Uint32 i = 0; i < d3d12CommandBuffer->computeReadWriteStorageBufferCount; i += 1) {
if (d3d12CommandBuffer->computeReadWriteStorageBuffers[i]) {
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
d3d12CommandBuffer->computeReadWriteStorageBuffers[i]);
d3d12CommandBuffer->computeReadWriteStorageBuffers[i] = NULL;
}
}
d3d12CommandBuffer->computeReadWriteStorageBufferCount = 0;
for (Uint32 i = 0; i < MAX_STORAGE_TEXTURES_PER_STAGE; i += 1) {
if (d3d12CommandBuffer->computeReadOnlyStorageTextures[i]) {
D3D12_INTERNAL_TextureTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
d3d12CommandBuffer->computeReadOnlyStorageTextures[i]);
d3d12CommandBuffer->computeReadOnlyStorageTextures[i] = NULL;
}
}
for (Uint32 i = 0; i < MAX_STORAGE_BUFFERS_PER_STAGE; i += 1) {
if (d3d12CommandBuffer->computeReadOnlyStorageBuffers[i]) {
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
d3d12CommandBuffer->computeReadOnlyStorageBuffers[i]);
d3d12CommandBuffer->computeReadOnlyStorageBuffers[i] = NULL;
}
}
SDL_zeroa(d3d12CommandBuffer->computeSamplerTextureDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->computeSamplerDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->computeReadWriteStorageTextureDescriptorHandles);
SDL_zeroa(d3d12CommandBuffer->computeReadWriteStorageBufferDescriptorHandles);
d3d12CommandBuffer->currentComputePipeline = NULL;
}
static void *D3D12_MapTransferBuffer(
SDL_GPURenderer *driverData,
SDL_GPUTransferBuffer *transferBuffer,
bool cycle)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12BufferContainer *container = (D3D12BufferContainer *)transferBuffer;
void *dataPointer;
if (
cycle &&
SDL_GetAtomicInt(&container->activeBuffer->referenceCount) > 0) {
D3D12_INTERNAL_CycleActiveBuffer(
renderer,
container);
}
if (container->type == D3D12_BUFFER_TYPE_UPLOAD) {
dataPointer = container->activeBuffer->mapPointer;
} else {
ID3D12Resource_Map(
container->activeBuffer->handle,
0,
NULL,
(void **)&dataPointer);
}
return dataPointer;
}
static void D3D12_UnmapTransferBuffer(
SDL_GPURenderer *driverData,
SDL_GPUTransferBuffer *transferBuffer)
{
(void)driverData;
D3D12BufferContainer *container = (D3D12BufferContainer *)transferBuffer;
if (container->type == D3D12_BUFFER_TYPE_DOWNLOAD) {
ID3D12Resource_Unmap(
container->activeBuffer->handle,
0,
NULL);
}
}
static void D3D12_BeginCopyPass(
SDL_GPUCommandBuffer *commandBuffer)
{
(void)commandBuffer;
}
static void D3D12_UploadToTexture(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUTextureTransferInfo *source,
const SDL_GPUTextureRegion *destination,
bool cycle)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = (D3D12Renderer *)d3d12CommandBuffer->renderer;
D3D12BufferContainer *transferBufferContainer = (D3D12BufferContainer *)source->transfer_buffer;
D3D12Buffer *temporaryBuffer = NULL;
D3D12_TEXTURE_COPY_LOCATION sourceLocation;
D3D12_TEXTURE_COPY_LOCATION destinationLocation;
Uint32 pixelsPerRow = source->pixels_per_row;
Uint32 blockWidth;
Uint32 blockSize;
Uint32 rowPitch;
Uint32 blockHeight;
Uint32 alignedRowPitch;
Uint32 rowsPerSlice = source->rows_per_layer;
Uint32 bytesPerSlice;
Uint32 alignedBytesPerSlice;
bool needsRealignment;
bool needsPlacementCopy;
D3D12TextureContainer *textureContainer = (D3D12TextureContainer *)destination->texture;
D3D12TextureSubresource *textureSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
d3d12CommandBuffer,
textureContainer,
destination->layer,
destination->mip_level,
cycle,
D3D12_RESOURCE_STATE_COPY_DEST);
if (pixelsPerRow == 0) {
pixelsPerRow = destination->w;
}
if (rowsPerSlice == 0) {
rowsPerSlice = destination->h;
}
blockWidth = Texture_GetBlockWidth(textureContainer->header.info.format);
blockSize = SDL_GPUTextureFormatTexelBlockSize(textureContainer->header.info.format);
rowPitch = (pixelsPerRow + (blockWidth - 1)) / blockWidth * blockSize;
blockHeight = (rowsPerSlice + (blockWidth - 1)) / blockWidth;
bytesPerSlice = rowsPerSlice * rowPitch;
if (renderer->UnrestrictedBufferTextureCopyPitchSupported) {
alignedRowPitch = rowPitch;
needsRealignment = false;
needsPlacementCopy = false;
} else {
alignedRowPitch = (destination->w + (blockWidth - 1)) / blockWidth * blockSize;
alignedRowPitch = D3D12_INTERNAL_Align(alignedRowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
needsRealignment = rowsPerSlice != destination->h || rowPitch != alignedRowPitch;
needsPlacementCopy = source->offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT != 0;
}
alignedBytesPerSlice = alignedRowPitch * destination->h;
sourceLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
sourceLocation.PlacedFootprint.Footprint.Format = SDLToD3D12_TextureFormat[textureContainer->header.info.format];
sourceLocation.PlacedFootprint.Footprint.RowPitch = alignedRowPitch;
destinationLocation.pResource = textureContainer->activeTexture->resource;
destinationLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
destinationLocation.SubresourceIndex = textureSubresource->index;
if (needsRealignment) {
temporaryBuffer = D3D12_INTERNAL_CreateBuffer(
d3d12CommandBuffer->renderer,
0,
alignedRowPitch * blockHeight * destination->d,
D3D12_BUFFER_TYPE_UPLOAD,
NULL);
if (!temporaryBuffer) {
return;
}
sourceLocation.pResource = temporaryBuffer->handle;
for (Uint32 sliceIndex = 0; sliceIndex < destination->d; sliceIndex += 1) {
for (Uint32 rowIndex = 0; rowIndex < blockHeight; rowIndex += 1) {
SDL_memcpy(
temporaryBuffer->mapPointer + (sliceIndex * alignedBytesPerSlice) + (rowIndex * alignedRowPitch),
transferBufferContainer->activeBuffer->mapPointer + source->offset + (sliceIndex * bytesPerSlice) + (rowIndex * rowPitch),
rowPitch);
}
sourceLocation.PlacedFootprint.Footprint.Width = destination->w;
sourceLocation.PlacedFootprint.Footprint.Height = destination->h;
sourceLocation.PlacedFootprint.Footprint.Depth = 1;
sourceLocation.PlacedFootprint.Offset = (sliceIndex * alignedBytesPerSlice);
ID3D12GraphicsCommandList_CopyTextureRegion(
d3d12CommandBuffer->graphicsCommandList,
&destinationLocation,
destination->x,
destination->y,
destination->z + sliceIndex,
&sourceLocation,
NULL);
}
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, temporaryBuffer);
D3D12_INTERNAL_ReleaseBuffer(
d3d12CommandBuffer->renderer,
temporaryBuffer);
if (d3d12CommandBuffer->renderer->debug_mode) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Texture upload row pitch not aligned to 256 bytes! This is suboptimal on D3D12!");
}
} else if (needsPlacementCopy) {
temporaryBuffer = D3D12_INTERNAL_CreateBuffer(
d3d12CommandBuffer->renderer,
0,
alignedRowPitch * blockHeight * destination->d,
D3D12_BUFFER_TYPE_UPLOAD,
NULL);
if (!temporaryBuffer) {
return;
}
SDL_memcpy(
temporaryBuffer->mapPointer,
transferBufferContainer->activeBuffer->mapPointer + source->offset,
alignedRowPitch * blockHeight * destination->d);
sourceLocation.pResource = temporaryBuffer->handle;
sourceLocation.PlacedFootprint.Offset = 0;
sourceLocation.PlacedFootprint.Footprint.Width = destination->w;
sourceLocation.PlacedFootprint.Footprint.Height = destination->h;
sourceLocation.PlacedFootprint.Footprint.Depth = destination->d;
ID3D12GraphicsCommandList_CopyTextureRegion(
d3d12CommandBuffer->graphicsCommandList,
&destinationLocation,
destination->x,
destination->y,
destination->z,
&sourceLocation,
NULL);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, temporaryBuffer);
D3D12_INTERNAL_ReleaseBuffer(
d3d12CommandBuffer->renderer,
temporaryBuffer);
if (d3d12CommandBuffer->renderer->debug_mode) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Texture upload offset not aligned to 512 bytes! This is suboptimal on D3D12!");
}
} else {
sourceLocation.pResource = transferBufferContainer->activeBuffer->handle;
sourceLocation.PlacedFootprint.Offset = source->offset;
sourceLocation.PlacedFootprint.Footprint.Width = destination->w;
sourceLocation.PlacedFootprint.Footprint.Height = destination->h;
sourceLocation.PlacedFootprint.Footprint.Depth = destination->d;
ID3D12GraphicsCommandList_CopyTextureRegion(
d3d12CommandBuffer->graphicsCommandList,
&destinationLocation,
destination->x,
destination->y,
destination->z,
&sourceLocation,
NULL);
}
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_DEST,
textureSubresource);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, transferBufferContainer->activeBuffer);
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, textureSubresource->parent);
}
static void D3D12_UploadToBuffer(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUTransferBufferLocation *source,
const SDL_GPUBufferRegion *destination,
bool cycle)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12BufferContainer *transferBufferContainer = (D3D12BufferContainer *)source->transfer_buffer;
D3D12BufferContainer *bufferContainer = (D3D12BufferContainer *)destination->buffer;
D3D12Buffer *buffer = D3D12_INTERNAL_PrepareBufferForWrite(
d3d12CommandBuffer,
bufferContainer,
cycle,
D3D12_RESOURCE_STATE_COPY_DEST);
ID3D12GraphicsCommandList_CopyBufferRegion(
d3d12CommandBuffer->graphicsCommandList,
buffer->handle,
destination->offset,
transferBufferContainer->activeBuffer->handle,
source->offset,
destination->size);
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_DEST,
buffer);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, transferBufferContainer->activeBuffer);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, buffer);
}
static void D3D12_CopyTextureToTexture(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUTextureLocation *source,
const SDL_GPUTextureLocation *destination,
Uint32 w,
Uint32 h,
Uint32 d,
bool cycle)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12_TEXTURE_COPY_LOCATION sourceLocation;
D3D12_TEXTURE_COPY_LOCATION destinationLocation;
D3D12TextureSubresource *sourceSubresource = D3D12_INTERNAL_FetchTextureSubresource(
(D3D12TextureContainer *)source->texture,
source->layer,
source->mip_level);
D3D12TextureSubresource *destinationSubresource = D3D12_INTERNAL_PrepareTextureSubresourceForWrite(
d3d12CommandBuffer,
(D3D12TextureContainer *)destination->texture,
destination->layer,
destination->mip_level,
cycle,
D3D12_RESOURCE_STATE_COPY_DEST);
D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceSubresource);
sourceLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
sourceLocation.SubresourceIndex = sourceSubresource->index;
sourceLocation.pResource = sourceSubresource->parent->resource;
destinationLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
destinationLocation.SubresourceIndex = destinationSubresource->index;
destinationLocation.pResource = destinationSubresource->parent->resource;
D3D12_BOX sourceBox = { source->x, source->y, source->z, source->x + w, source->y + h, source->z + d };
ID3D12GraphicsCommandList_CopyTextureRegion(
d3d12CommandBuffer->graphicsCommandList,
&destinationLocation,
destination->x,
destination->y,
destination->z,
&sourceLocation,
&sourceBox);
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceSubresource);
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_DEST,
destinationSubresource);
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
sourceSubresource->parent);
D3D12_INTERNAL_TrackTexture(
d3d12CommandBuffer,
destinationSubresource->parent);
}
static void D3D12_CopyBufferToBuffer(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUBufferLocation *source,
const SDL_GPUBufferLocation *destination,
Uint32 size,
bool cycle)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12BufferContainer *sourceContainer = (D3D12BufferContainer *)source->buffer;
D3D12BufferContainer *destinationContainer = (D3D12BufferContainer *)destination->buffer;
D3D12Buffer *sourceBuffer = sourceContainer->activeBuffer;
D3D12Buffer *destinationBuffer = D3D12_INTERNAL_PrepareBufferForWrite(
d3d12CommandBuffer,
destinationContainer,
cycle,
D3D12_RESOURCE_STATE_COPY_DEST);
D3D12_INTERNAL_BufferTransitionFromDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceBuffer);
ID3D12GraphicsCommandList_CopyBufferRegion(
d3d12CommandBuffer->graphicsCommandList,
destinationBuffer->handle,
destination->offset,
sourceBuffer->handle,
source->offset,
size);
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceBuffer);
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_DEST,
destinationBuffer);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, sourceBuffer);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, destinationBuffer);
}
static void D3D12_DownloadFromTexture(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUTextureRegion *source,
const SDL_GPUTextureTransferInfo *destination)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
D3D12_TEXTURE_COPY_LOCATION sourceLocation;
D3D12_TEXTURE_COPY_LOCATION destinationLocation;
Uint32 pixelsPerRow = destination->pixels_per_row;
Uint32 rowPitch;
Uint32 alignedRowPitch;
Uint32 rowsPerSlice = destination->rows_per_layer;
bool needsRealignment;
bool needsPlacementCopy;
D3D12TextureDownload *textureDownload = NULL;
D3D12TextureContainer *sourceContainer = (D3D12TextureContainer *)source->texture;
D3D12TextureSubresource *sourceSubresource = D3D12_INTERNAL_FetchTextureSubresource(
sourceContainer,
source->layer,
source->mip_level);
D3D12BufferContainer *destinationContainer = (D3D12BufferContainer *)destination->transfer_buffer;
D3D12Buffer *destinationBuffer = destinationContainer->activeBuffer;
if (pixelsPerRow == 0) {
pixelsPerRow = source->w;
}
rowPitch = BytesPerRow(pixelsPerRow, sourceContainer->header.info.format);
if (rowsPerSlice == 0) {
rowsPerSlice = source->h;
}
if (renderer->UnrestrictedBufferTextureCopyPitchSupported) {
alignedRowPitch = rowPitch;
needsRealignment = false;
needsPlacementCopy = false;
} else {
alignedRowPitch = D3D12_INTERNAL_Align(rowPitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
needsRealignment = rowsPerSlice != source->h || rowPitch != alignedRowPitch;
needsPlacementCopy = destination->offset % D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT != 0;
}
sourceLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
sourceLocation.SubresourceIndex = sourceSubresource->index;
sourceLocation.pResource = sourceSubresource->parent->resource;
D3D12_BOX sourceBox = { source->x, source->y, source->z, source->x + source->w, source->y + rowsPerSlice, source->z + source->d };
destinationLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
destinationLocation.PlacedFootprint.Footprint.Format = SDLToD3D12_TextureFormat[sourceContainer->header.info.format];
destinationLocation.PlacedFootprint.Footprint.Width = source->w;
destinationLocation.PlacedFootprint.Footprint.Height = rowsPerSlice;
destinationLocation.PlacedFootprint.Footprint.Depth = source->d;
destinationLocation.PlacedFootprint.Footprint.RowPitch = alignedRowPitch;
if (needsRealignment || needsPlacementCopy) {
textureDownload = (D3D12TextureDownload *)SDL_malloc(sizeof(D3D12TextureDownload));
if (!textureDownload) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create texture download structure!");
return;
}
textureDownload->temporaryBuffer = D3D12_INTERNAL_CreateBuffer(
d3d12CommandBuffer->renderer,
0,
alignedRowPitch * rowsPerSlice * source->d,
D3D12_BUFFER_TYPE_DOWNLOAD,
NULL);
if (!textureDownload->temporaryBuffer) {
SDL_free(textureDownload);
return;
}
textureDownload->destinationBuffer = destinationBuffer;
textureDownload->bufferOffset = destination->offset;
textureDownload->width = source->w;
textureDownload->height = rowsPerSlice;
textureDownload->depth = source->d;
textureDownload->bytesPerRow = rowPitch;
textureDownload->bytesPerDepthSlice = rowPitch * rowsPerSlice;
textureDownload->alignedBytesPerRow = alignedRowPitch;
destinationLocation.pResource = textureDownload->temporaryBuffer->handle;
destinationLocation.PlacedFootprint.Offset = 0;
if (d3d12CommandBuffer->renderer->debug_mode) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Texture pitch or offset not aligned properly! This is suboptimal on D3D12!");
}
} else {
destinationLocation.pResource = destinationBuffer->handle;
destinationLocation.PlacedFootprint.Offset = destination->offset;
}
D3D12_INTERNAL_TextureSubresourceTransitionFromDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceSubresource);
ID3D12GraphicsCommandList_CopyTextureRegion(
d3d12CommandBuffer->graphicsCommandList,
&destinationLocation,
0,
0,
0,
&sourceLocation,
&sourceBox);
D3D12_INTERNAL_TextureSubresourceTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceSubresource);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, destinationBuffer);
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, sourceSubresource->parent);
if (textureDownload != NULL) {
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, textureDownload->temporaryBuffer);
if (d3d12CommandBuffer->textureDownloadCount >= d3d12CommandBuffer->textureDownloadCapacity) {
d3d12CommandBuffer->textureDownloadCapacity *= 2;
d3d12CommandBuffer->textureDownloads = (D3D12TextureDownload **)SDL_realloc(
d3d12CommandBuffer->textureDownloads,
d3d12CommandBuffer->textureDownloadCapacity * sizeof(D3D12TextureDownload *));
}
d3d12CommandBuffer->textureDownloads[d3d12CommandBuffer->textureDownloadCount] = textureDownload;
d3d12CommandBuffer->textureDownloadCount += 1;
D3D12_INTERNAL_ReleaseBuffer(d3d12CommandBuffer->renderer, textureDownload->temporaryBuffer);
}
}
static void D3D12_DownloadFromBuffer(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUBufferRegion *source,
const SDL_GPUTransferBufferLocation *destination)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12BufferContainer *sourceContainer = (D3D12BufferContainer *)source->buffer;
D3D12BufferContainer *destinationContainer = (D3D12BufferContainer *)destination->transfer_buffer;
D3D12Buffer *sourceBuffer = sourceContainer->activeBuffer;
D3D12_INTERNAL_BufferTransitionFromDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceBuffer);
D3D12Buffer *destinationBuffer = destinationContainer->activeBuffer;
ID3D12GraphicsCommandList_CopyBufferRegion(
d3d12CommandBuffer->graphicsCommandList,
destinationBuffer->handle,
destination->offset,
sourceBuffer->handle,
source->offset,
source->size);
D3D12_INTERNAL_BufferTransitionToDefaultUsage(
d3d12CommandBuffer,
D3D12_RESOURCE_STATE_COPY_SOURCE,
sourceBuffer);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, sourceBuffer);
D3D12_INTERNAL_TrackBuffer(d3d12CommandBuffer, destinationBuffer);
}
static void D3D12_EndCopyPass(
SDL_GPUCommandBuffer *commandBuffer)
{
(void)commandBuffer;
}
static void D3D12_GenerateMipmaps(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUTexture *texture)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
D3D12TextureContainer *container = (D3D12TextureContainer *)texture;
SDL_GPUGraphicsPipeline *blitPipeline;
blitPipeline = SDL_GPU_FetchBlitPipeline(
renderer->sdlGPUDevice,
container->header.info.type,
container->header.info.format,
renderer->blitVertexShader,
renderer->blitFrom2DShader,
renderer->blitFrom2DArrayShader,
renderer->blitFrom3DShader,
renderer->blitFromCubeShader,
renderer->blitFromCubeArrayShader,
&renderer->blitPipelines,
&renderer->blitPipelineCount,
&renderer->blitPipelineCapacity);
if (blitPipeline == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Could not fetch blit pipeline");
return;
}
for (Uint32 layerOrDepthIndex = 0; layerOrDepthIndex < container->header.info.layer_count_or_depth; layerOrDepthIndex += 1) {
for (Uint32 levelIndex = 1; levelIndex < container->header.info.num_levels; levelIndex += 1) {
SDL_GPUBlitInfo blitInfo;
SDL_zero(blitInfo);
blitInfo.source.texture = texture;
blitInfo.source.mip_level = levelIndex - 1;
blitInfo.source.layer_or_depth_plane = layerOrDepthIndex;
blitInfo.source.x = 0;
blitInfo.source.y = 0;
blitInfo.source.w = SDL_max(container->header.info.width >> (levelIndex - 1), 1);
blitInfo.source.h = SDL_max(container->header.info.height >> (levelIndex - 1), 1);
blitInfo.destination.texture = texture;
blitInfo.destination.mip_level = levelIndex;
blitInfo.destination.layer_or_depth_plane = layerOrDepthIndex;
blitInfo.destination.x = 0;
blitInfo.destination.y = 0;
blitInfo.destination.w = SDL_max(container->header.info.width >> levelIndex, 1);
blitInfo.destination.h = SDL_max(container->header.info.height >> levelIndex, 1);
blitInfo.load_op = SDL_GPU_LOADOP_DONT_CARE;
blitInfo.filter = SDL_GPU_FILTER_LINEAR;
SDL_BlitGPUTexture(
commandBuffer,
&blitInfo);
}
}
D3D12_INTERNAL_TrackTexture(d3d12CommandBuffer, container->activeTexture);
}
static void D3D12_Blit(
SDL_GPUCommandBuffer *commandBuffer,
const SDL_GPUBlitInfo *info)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = (D3D12Renderer *)d3d12CommandBuffer->renderer;
SDL_GPU_BlitCommon(
commandBuffer,
info,
renderer->blitLinearSampler,
renderer->blitNearestSampler,
renderer->blitVertexShader,
renderer->blitFrom2DShader,
renderer->blitFrom2DArrayShader,
renderer->blitFrom3DShader,
renderer->blitFromCubeShader,
renderer->blitFromCubeArrayShader,
&renderer->blitPipelines,
&renderer->blitPipelineCount,
&renderer->blitPipelineCapacity);
}
static D3D12WindowData *D3D12_INTERNAL_FetchWindowData(
SDL_Window *window)
{
SDL_PropertiesID properties = SDL_GetWindowProperties(window);
return (D3D12WindowData *)SDL_GetPointerProperty(properties, WINDOW_PROPERTY_DATA, NULL);
}
static bool D3D12_INTERNAL_OnWindowResize(void *userdata, SDL_Event *e)
{
SDL_Window *w = (SDL_Window *)userdata;
D3D12WindowData *data;
if (e->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED && e->window.windowID == SDL_GetWindowID(w)) {
data = D3D12_INTERNAL_FetchWindowData(w);
data->needsSwapchainRecreate = true;
}
return true;
}
static bool D3D12_SupportsSwapchainComposition(
SDL_GPURenderer *driverData,
SDL_Window *window,
SDL_GPUSwapchainComposition swapchainComposition)
{
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
return swapchainComposition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR ||
swapchainComposition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR;
#else
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
DXGI_FORMAT format;
D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport;
Uint32 colorSpaceSupport;
HRESULT res;
format = SwapchainCompositionToTextureFormat[swapchainComposition];
formatSupport.Format = format;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_FORMAT_SUPPORT,
&formatSupport,
sizeof(formatSupport));
if (FAILED(res)) {
return false;
}
if (!(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_DISPLAY)) {
return false;
}
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Must claim window before querying swapchain composition support!", false);
}
if (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR) {
IDXGISwapChain3_CheckColorSpaceSupport(
windowData->swapchain,
SwapchainCompositionToColorSpace[swapchainComposition],
&colorSpaceSupport);
if (!(colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)) {
return false;
}
}
#endif
return true;
}
static bool D3D12_SupportsPresentMode(
SDL_GPURenderer *driverData,
SDL_Window *window,
SDL_GPUPresentMode presentMode)
{
(void)driverData;
(void)window;
switch (presentMode) {
case SDL_GPU_PRESENTMODE_IMMEDIATE:
case SDL_GPU_PRESENTMODE_VSYNC:
return true;
case SDL_GPU_PRESENTMODE_MAILBOX:
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
return false;
#else
return true;
#endif
default:
SDL_assert(!"Unrecognized present mode");
return false;
}
}
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
static bool D3D12_INTERNAL_CreateSwapchain(
D3D12Renderer *renderer,
D3D12WindowData *windowData,
SDL_GPUSwapchainComposition swapchain_composition,
SDL_GPUPresentMode present_mode)
{
int width, height;
SDL_GPUTextureCreateInfo createInfo;
D3D12Texture *texture;
SDL_SyncWindow(windowData->window);
SDL_GetWindowSizeInPixels(windowData->window, &width, &height);
windowData->swapchainTextureCount = SDL_clamp(renderer->allowedFramesInFlight, 2, 3);
SDL_zero(createInfo);
createInfo.type = SDL_GPU_TEXTURETYPE_2D;
createInfo.width = width;
createInfo.height = height;
createInfo.format = SwapchainCompositionToSDLTextureFormat[swapchain_composition];
createInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
createInfo.layer_count_or_depth = 1;
createInfo.num_levels = 1;
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
texture = D3D12_INTERNAL_CreateTexture(renderer, &createInfo, true, "Swapchain");
texture->container = &windowData->textureContainers[i];
windowData->textureContainers[i].activeTexture = texture;
windowData->textureContainers[i].canBeCycled = false;
windowData->textureContainers[i].header.info = createInfo;
windowData->textureContainers[i].textureCapacity = 1;
windowData->textureContainers[i].textureCount = 1;
windowData->textureContainers[i].textures = &windowData->textureContainers[i].activeTexture;
}
windowData->present_mode = present_mode;
windowData->swapchainComposition = swapchain_composition;
windowData->swapchainColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
windowData->frameCounter = 0;
windowData->width = width;
windowData->height = height;
for (Uint32 i = 0; i < 5; i += 1) {
SDL_GPU_FetchBlitPipeline(
renderer->sdlGPUDevice,
(SDL_GPUTextureType)i,
createInfo.format,
renderer->blitVertexShader,
renderer->blitFrom2DShader,
renderer->blitFrom2DArrayShader,
renderer->blitFrom3DShader,
renderer->blitFromCubeShader,
renderer->blitFromCubeArrayShader,
&renderer->blitPipelines,
&renderer->blitPipelineCount,
&renderer->blitPipelineCapacity);
}
return true;
}
static void D3D12_INTERNAL_DestroySwapchain(
D3D12Renderer *renderer,
D3D12WindowData *windowData)
{
renderer->commandQueue->PresentX(0, NULL, NULL);
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
D3D12_INTERNAL_DestroyTexture(windowData->textureContainers[i].activeTexture);
}
}
static bool D3D12_INTERNAL_ResizeSwapchain(
D3D12Renderer *renderer,
D3D12WindowData *windowData)
{
D3D12_Wait((SDL_GPURenderer *)renderer);
renderer->commandQueue->PresentX(0, NULL, NULL);
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
D3D12_INTERNAL_DestroyTexture(windowData->textureContainers[i].activeTexture);
}
D3D12_INTERNAL_CreateSwapchain(
renderer,
windowData,
windowData->swapchainComposition,
windowData->present_mode);
windowData->needsSwapchainRecreate = false;
return true;
}
#else
static bool D3D12_INTERNAL_InitializeSwapchainTexture(
D3D12Renderer *renderer,
IDXGISwapChain3 *swapchain,
SDL_GPUSwapchainComposition composition,
Uint32 index,
D3D12TextureContainer *pTextureContainer)
{
D3D12Texture *pTexture;
ID3D12Resource *swapchainTexture;
D3D12_RESOURCE_DESC textureDesc;
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[composition];
HRESULT res;
res = IDXGISwapChain_GetBuffer(
swapchain,
index,
D3D_GUID(D3D_IID_ID3D12Resource),
(void **)&swapchainTexture);
CHECK_D3D12_ERROR_AND_RETURN("Could not get buffer from swapchain!", false);
pTexture = (D3D12Texture *)SDL_calloc(1, sizeof(D3D12Texture));
if (!pTexture) {
ID3D12Resource_Release(swapchainTexture);
return false;
}
pTexture->resource = NULL; SDL_SetAtomicInt(&pTexture->referenceCount, 0);
pTexture->subresourceCount = 1;
pTexture->subresources = (D3D12TextureSubresource *)SDL_calloc(1, sizeof(D3D12TextureSubresource));
if (!pTexture->subresources) {
SDL_free(pTexture);
ID3D12Resource_Release(swapchainTexture);
return false;
}
pTexture->subresources[0].rtvHandles = SDL_calloc(1, sizeof(D3D12StagingDescriptor));
pTexture->subresources[0].uavHandle.heap = NULL;
pTexture->subresources[0].dsvHandle.heap = NULL;
pTexture->subresources[0].parent = pTexture;
pTexture->subresources[0].index = 0;
pTexture->subresources[0].layer = 0;
pTexture->subresources[0].depth = 1;
pTexture->subresources[0].level = 0;
ID3D12Resource_GetDesc(swapchainTexture, &textureDesc);
pTextureContainer->header.info.width = (Uint32)textureDesc.Width;
pTextureContainer->header.info.height = (Uint32)textureDesc.Height;
pTextureContainer->header.info.layer_count_or_depth = 1;
pTextureContainer->header.info.num_levels = 1;
pTextureContainer->header.info.type = SDL_GPU_TEXTURETYPE_2D;
pTextureContainer->header.info.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
pTextureContainer->header.info.sample_count = SDL_GPU_SAMPLECOUNT_1;
pTextureContainer->header.info.format = SwapchainCompositionToSDLTextureFormat[composition];
pTextureContainer->debugName = NULL;
pTextureContainer->textures = (D3D12Texture **)SDL_calloc(1, sizeof(D3D12Texture *));
if (!pTextureContainer->textures) {
SDL_free(pTexture->subresources);
SDL_free(pTexture);
ID3D12Resource_Release(swapchainTexture);
return false;
}
pTextureContainer->textureCapacity = 1;
pTextureContainer->textureCount = 1;
pTextureContainer->textures[0] = pTexture;
pTextureContainer->activeTexture = pTexture;
pTextureContainer->canBeCycled = false;
pTexture->container = pTextureContainer;
pTexture->containerIndex = 0;
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
&pTexture->srvHandle);
srvDesc.Format = SwapchainCompositionToTextureFormat[composition];
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Texture2D.ResourceMinLODClamp = 0;
srvDesc.Texture2D.PlaneSlice = 0;
ID3D12Device_CreateShaderResourceView(
renderer->device,
swapchainTexture,
&srvDesc,
pTexture->srvHandle.cpuHandle);
D3D12_INTERNAL_AssignStagingDescriptorHandle(
renderer,
D3D12_DESCRIPTOR_HEAP_TYPE_RTV,
&pTexture->subresources[0].rtvHandles[0]);
rtvDesc.Format = (composition == SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = 0;
rtvDesc.Texture2D.PlaneSlice = 0;
ID3D12Device_CreateRenderTargetView(
renderer->device,
swapchainTexture,
&rtvDesc,
pTexture->subresources[0].rtvHandles[0].cpuHandle);
ID3D12Resource_Release(swapchainTexture);
return true;
}
static bool D3D12_INTERNAL_ResizeSwapchain(
D3D12Renderer *renderer,
D3D12WindowData *windowData)
{
D3D12_Wait((SDL_GPURenderer *)renderer);
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&windowData->textureContainers[i].activeTexture->srvHandle);
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles[0]);
SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles);
SDL_free(windowData->textureContainers[i].activeTexture->subresources);
SDL_free(windowData->textureContainers[i].activeTexture);
SDL_free(windowData->textureContainers[i].textures);
}
HRESULT res = IDXGISwapChain_ResizeBuffers(
windowData->swapchain,
0, 0, 0, DXGI_FORMAT_UNKNOWN, renderer->supportsTearing ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0);
CHECK_D3D12_ERROR_AND_RETURN("Could not resize swapchain buffers", false);
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
if (!D3D12_INTERNAL_InitializeSwapchainTexture(
renderer,
windowData->swapchain,
windowData->swapchainComposition,
i,
&windowData->textureContainers[i])) {
return false;
}
}
DXGI_SWAP_CHAIN_DESC1 swapchainDesc;
IDXGISwapChain3_GetDesc1(windowData->swapchain, &swapchainDesc);
CHECK_D3D12_ERROR_AND_RETURN("Failed to retrieve swapchain descriptor!", false);
windowData->width = swapchainDesc.Width;
windowData->height = swapchainDesc.Height;
windowData->needsSwapchainRecreate = false;
return true;
}
static void D3D12_INTERNAL_DestroySwapchain(
D3D12Renderer *renderer,
D3D12WindowData *windowData)
{
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&windowData->textureContainers[i].activeTexture->srvHandle);
D3D12_INTERNAL_ReleaseStagingDescriptorHandle(
&windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles[0]);
SDL_free(windowData->textureContainers[i].activeTexture->subresources[0].rtvHandles);
SDL_free(windowData->textureContainers[i].activeTexture->subresources);
SDL_free(windowData->textureContainers[i].activeTexture);
SDL_free(windowData->textureContainers[i].textures);
}
IDXGISwapChain_Release(windowData->swapchain);
windowData->swapchain = NULL;
}
static bool D3D12_INTERNAL_CreateSwapchain(
D3D12Renderer *renderer,
D3D12WindowData *windowData,
SDL_GPUSwapchainComposition swapchainComposition,
SDL_GPUPresentMode presentMode)
{
HWND dxgiHandle;
DXGI_SWAP_CHAIN_DESC1 swapchainDesc;
DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreenDesc;
DXGI_FORMAT swapchainFormat;
IDXGIFactory1 *pParent;
IDXGISwapChain1 *swapchain;
IDXGISwapChain3 *swapchain3;
HRESULT res;
#ifdef _WIN32
dxgiHandle = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(windowData->window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
#else
dxgiHandle = (HWND)windowData->window;
#endif
swapchainFormat = SwapchainCompositionToTextureFormat[swapchainComposition];
windowData->swapchainTextureCount = SDL_clamp(renderer->allowedFramesInFlight, 2, 3);
swapchainDesc.Width = 0; swapchainDesc.Height = 0; swapchainDesc.Format = swapchainFormat;
swapchainDesc.SampleDesc.Count = 1;
swapchainDesc.SampleDesc.Quality = 0;
swapchainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapchainDesc.BufferCount = windowData->swapchainTextureCount;
swapchainDesc.Scaling = DXGI_SCALING_NONE;
swapchainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapchainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapchainDesc.Flags = 0;
swapchainDesc.Stereo = 0;
fullscreenDesc.RefreshRate.Numerator = 0;
fullscreenDesc.RefreshRate.Denominator = 0;
fullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
fullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
fullscreenDesc.Windowed = true;
if (renderer->supportsTearing) {
swapchainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
} else {
swapchainDesc.Flags = 0;
}
if (!IsWindow(dxgiHandle)) {
return false;
}
res = IDXGIFactory4_CreateSwapChainForHwnd(
renderer->factory,
(IUnknown *)renderer->commandQueue,
dxgiHandle,
&swapchainDesc,
&fullscreenDesc,
NULL,
&swapchain);
CHECK_D3D12_ERROR_AND_RETURN("Could not create swapchain", false);
res = IDXGISwapChain1_QueryInterface(
swapchain,
D3D_GUID(D3D_IID_IDXGISwapChain3),
(void **)&swapchain3);
IDXGISwapChain1_Release(swapchain);
CHECK_D3D12_ERROR_AND_RETURN("Could not create IDXGISwapChain3", false);
if (swapchainComposition != SDL_GPU_SWAPCHAINCOMPOSITION_SDR) {
IDXGISwapChain3_SetColorSpace1(
swapchain3,
SwapchainCompositionToColorSpace[swapchainComposition]);
}
res = IDXGISwapChain3_GetParent(
swapchain3,
D3D_GUID(D3D_IID_IDXGIFactory1),
(void **)&pParent);
if (FAILED(res)) {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"Could not get swapchain parent! Error Code: " HRESULT_FMT,
res);
} else {
res = IDXGIFactory1_MakeWindowAssociation(
pParent,
dxgiHandle,
DXGI_MWA_NO_WINDOW_CHANGES);
if (FAILED(res)) {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"MakeWindowAssociation failed! Error Code: " HRESULT_FMT,
res);
}
IDXGIFactory1_Release(pParent);
}
IDXGISwapChain3_GetDesc1(swapchain3, &swapchainDesc);
CHECK_D3D12_ERROR_AND_RETURN("Failed to retrieve swapchain descriptor!", false);
windowData->swapchain = swapchain3;
windowData->present_mode = presentMode;
windowData->swapchainComposition = swapchainComposition;
windowData->swapchainColorSpace = SwapchainCompositionToColorSpace[swapchainComposition];
windowData->frameCounter = 0;
windowData->width = swapchainDesc.Width;
windowData->height = swapchainDesc.Height;
for (Uint32 i = 0; i < 5; i += 1) {
SDL_GPU_FetchBlitPipeline(
renderer->sdlGPUDevice,
(SDL_GPUTextureType)i,
SwapchainCompositionToSDLTextureFormat[swapchainComposition],
renderer->blitVertexShader,
renderer->blitFrom2DShader,
renderer->blitFrom2DArrayShader,
renderer->blitFrom3DShader,
renderer->blitFromCubeShader,
renderer->blitFromCubeArrayShader,
&renderer->blitPipelines,
&renderer->blitPipelineCount,
&renderer->blitPipelineCapacity);
}
for (Uint32 i = 0; i < windowData->swapchainTextureCount; i += 1) {
if (!D3D12_INTERNAL_InitializeSwapchainTexture(
renderer,
swapchain3,
swapchainComposition,
i,
&windowData->textureContainers[i])) {
IDXGISwapChain3_Release(swapchain3);
return false;
}
}
return true;
}
#endif
static bool D3D12_ClaimWindow(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
windowData = (D3D12WindowData *)SDL_calloc(1, sizeof(D3D12WindowData));
if (!windowData) {
return false;
}
windowData->window = window;
windowData->renderer = renderer;
windowData->refcount = 1;
if (D3D12_INTERNAL_CreateSwapchain(renderer, windowData, SDL_GPU_SWAPCHAINCOMPOSITION_SDR, SDL_GPU_PRESENTMODE_VSYNC)) {
SDL_SetPointerProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA, windowData);
SDL_LockMutex(renderer->windowLock);
if (renderer->claimedWindowCount >= renderer->claimedWindowCapacity) {
renderer->claimedWindowCapacity *= 2;
renderer->claimedWindows = (D3D12WindowData **)SDL_realloc(
renderer->claimedWindows,
renderer->claimedWindowCapacity * sizeof(D3D12WindowData *));
}
renderer->claimedWindows[renderer->claimedWindowCount] = windowData;
renderer->claimedWindowCount += 1;
SDL_UnlockMutex(renderer->windowLock);
SDL_AddWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, D3D12_INTERNAL_OnWindowResize, window);
return true;
} else {
SDL_free(windowData);
return false;
}
} else if (windowData->renderer == renderer) {
++windowData->refcount;
return true;
} else {
SET_STRING_ERROR_AND_RETURN("Window already claimed", false);
}
}
static void D3D12_ReleaseWindow(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
return;
}
if (windowData->renderer != renderer) {
SDL_SetError("Window not claimed by this device");
return;
}
if (windowData->refcount > 1) {
--windowData->refcount;
return;
}
D3D12_Wait(driverData);
for (Uint32 i = 0; i < MAX_FRAMES_IN_FLIGHT; i += 1) {
if (windowData->inFlightFences[i] != NULL) {
D3D12_ReleaseFence(
driverData,
windowData->inFlightFences[i]);
windowData->inFlightFences[i] = NULL;
}
}
D3D12_INTERNAL_DestroySwapchain(renderer, windowData);
SDL_LockMutex(renderer->windowLock);
for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) {
if (renderer->claimedWindows[i]->window == window) {
renderer->claimedWindows[i] = renderer->claimedWindows[renderer->claimedWindowCount - 1];
renderer->claimedWindowCount -= 1;
break;
}
}
SDL_UnlockMutex(renderer->windowLock);
SDL_free(windowData);
SDL_ClearProperty(SDL_GetWindowProperties(window), WINDOW_PROPERTY_DATA);
SDL_RemoveWindowEventWatch(SDL_WINDOW_EVENT_WATCH_NORMAL, D3D12_INTERNAL_OnWindowResize, window);
}
static bool D3D12_SetSwapchainParameters(
SDL_GPURenderer *driverData,
SDL_Window *window,
SDL_GPUSwapchainComposition swapchainComposition,
SDL_GPUPresentMode presentMode)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot set swapchain parameters on unclaimed window!", false);
}
if (!D3D12_SupportsSwapchainComposition(driverData, window, swapchainComposition)) {
SET_STRING_ERROR_AND_RETURN("Swapchain composition not supported!", false);
}
if (!D3D12_SupportsPresentMode(driverData, window, presentMode)) {
SET_STRING_ERROR_AND_RETURN("Present mode not supported!", false);
}
if (
swapchainComposition != windowData->swapchainComposition ||
presentMode != windowData->present_mode) {
D3D12_Wait(driverData);
D3D12_INTERNAL_DestroySwapchain(
renderer,
windowData);
return D3D12_INTERNAL_CreateSwapchain(
renderer,
windowData,
swapchainComposition,
presentMode);
}
return true;
}
static bool D3D12_SetAllowedFramesInFlight(
SDL_GPURenderer *driverData,
Uint32 allowedFramesInFlight)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
if (!D3D12_Wait(driverData)) {
return false;
}
for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) {
D3D12WindowData *windowData = renderer->claimedWindows[i];
D3D12_INTERNAL_DestroySwapchain(renderer, windowData);
}
renderer->allowedFramesInFlight = allowedFramesInFlight;
for (Uint32 i = 0; i < renderer->claimedWindowCount; i += 1) {
D3D12WindowData *windowData = renderer->claimedWindows[i];
if (!D3D12_INTERNAL_CreateSwapchain(
renderer,
windowData,
windowData->swapchainComposition,
windowData->present_mode)) {
return false;
}
}
return true;
}
static SDL_GPUTextureFormat D3D12_GetSwapchainTextureFormat(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot get swapchain format, window has not been claimed!", SDL_GPU_TEXTUREFORMAT_INVALID);
}
return windowData->textureContainers[windowData->frameCounter].header.info.format;
}
static D3D12Fence *D3D12_INTERNAL_AcquireFence(
D3D12Renderer *renderer)
{
D3D12Fence *fence;
ID3D12Fence *handle;
HRESULT res;
SDL_LockMutex(renderer->fenceLock);
if (renderer->availableFenceCount == 0) {
res = ID3D12Device_CreateFence(
renderer->device,
D3D12_FENCE_UNSIGNALED_VALUE,
D3D12_FENCE_FLAG_NONE,
D3D_GUID(D3D_IID_ID3D12Fence),
(void **)&handle);
if (FAILED(res)) {
D3D12_INTERNAL_SetError(renderer, "Failed to create fence!", res);
SDL_UnlockMutex(renderer->fenceLock);
return NULL;
}
fence = (D3D12Fence *)SDL_calloc(1, sizeof(D3D12Fence));
if (!fence) {
ID3D12Fence_Release(handle);
SDL_UnlockMutex(renderer->fenceLock);
return NULL;
}
fence->handle = handle;
fence->event = CreateEvent(NULL, FALSE, FALSE, NULL);
SDL_SetAtomicInt(&fence->referenceCount, 0);
} else {
fence = renderer->availableFences[renderer->availableFenceCount - 1];
renderer->availableFenceCount -= 1;
ID3D12Fence_Signal(fence->handle, D3D12_FENCE_UNSIGNALED_VALUE);
}
SDL_UnlockMutex(renderer->fenceLock);
(void)SDL_AtomicIncRef(&fence->referenceCount);
return fence;
}
static bool D3D12_INTERNAL_AllocateCommandBuffer(
D3D12Renderer *renderer)
{
D3D12CommandBuffer *commandBuffer;
HRESULT res;
ID3D12CommandAllocator *commandAllocator;
ID3D12GraphicsCommandList *commandList;
commandBuffer = (D3D12CommandBuffer *)SDL_calloc(1, sizeof(D3D12CommandBuffer));
if (!commandBuffer) {
SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false);
}
res = ID3D12Device_CreateCommandAllocator(
renderer->device,
D3D12_COMMAND_LIST_TYPE_DIRECT,
D3D_GUID(D3D_IID_ID3D12CommandAllocator),
(void **)&commandAllocator);
if (FAILED(res)) {
D3D12_INTERNAL_SetError(renderer, "Failed to create ID3D12CommandAllocator", res);
D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer);
return false;
}
commandBuffer->commandAllocator = commandAllocator;
res = ID3D12Device_CreateCommandList(
renderer->device,
0,
D3D12_COMMAND_LIST_TYPE_DIRECT,
commandAllocator,
NULL,
D3D_GUID(D3D_IID_ID3D12GraphicsCommandList),
(void **)&commandList);
if (FAILED(res)) {
D3D12_INTERNAL_SetError(renderer, "Failed to create ID3D12CommandList", res);
D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer);
return false;
}
commandBuffer->graphicsCommandList = commandList;
commandBuffer->renderer = renderer;
commandBuffer->inFlightFence = NULL;
commandBuffer->presentDataCapacity = 1;
commandBuffer->presentDataCount = 0;
commandBuffer->presentDatas = (D3D12PresentData *)SDL_calloc(
commandBuffer->presentDataCapacity, sizeof(D3D12PresentData));
commandBuffer->usedTextureCapacity = 4;
commandBuffer->usedTextureCount = 0;
commandBuffer->usedTextures = (D3D12Texture **)SDL_calloc(
commandBuffer->usedTextureCapacity, sizeof(D3D12Texture *));
commandBuffer->usedBufferCapacity = 4;
commandBuffer->usedBufferCount = 0;
commandBuffer->usedBuffers = (D3D12Buffer **)SDL_calloc(
commandBuffer->usedBufferCapacity, sizeof(D3D12Buffer *));
commandBuffer->usedSamplerCapacity = 4;
commandBuffer->usedSamplerCount = 0;
commandBuffer->usedSamplers = (D3D12Sampler **)SDL_calloc(
commandBuffer->usedSamplerCapacity, sizeof(D3D12Sampler *));
commandBuffer->usedGraphicsPipelineCapacity = 4;
commandBuffer->usedGraphicsPipelineCount = 0;
commandBuffer->usedGraphicsPipelines = (D3D12GraphicsPipeline **)SDL_calloc(
commandBuffer->usedGraphicsPipelineCapacity, sizeof(D3D12GraphicsPipeline *));
commandBuffer->usedComputePipelineCapacity = 4;
commandBuffer->usedComputePipelineCount = 0;
commandBuffer->usedComputePipelines = (D3D12ComputePipeline **)SDL_calloc(
commandBuffer->usedComputePipelineCapacity, sizeof(D3D12ComputePipeline *));
commandBuffer->usedDescriptorHeapCapacity = 4;
commandBuffer->usedDescriptorHeapCount = 0;
commandBuffer->usedDescriptorHeaps = (D3D12DescriptorHeap **)SDL_calloc(
commandBuffer->usedDescriptorHeapCapacity, sizeof(D3D12DescriptorHeap *));
commandBuffer->usedUniformBufferCapacity = 4;
commandBuffer->usedUniformBufferCount = 0;
commandBuffer->usedUniformBuffers = (D3D12UniformBuffer **)SDL_calloc(
commandBuffer->usedUniformBufferCapacity, sizeof(D3D12UniformBuffer *));
commandBuffer->textureDownloadCapacity = 4;
commandBuffer->textureDownloadCount = 0;
commandBuffer->textureDownloads = (D3D12TextureDownload **)SDL_calloc(
commandBuffer->textureDownloadCapacity, sizeof(D3D12TextureDownload *));
if (
(!commandBuffer->presentDatas) ||
(!commandBuffer->usedTextures) ||
(!commandBuffer->usedBuffers) ||
(!commandBuffer->usedSamplers) ||
(!commandBuffer->usedGraphicsPipelines) ||
(!commandBuffer->usedComputePipelines) ||
(!commandBuffer->usedUniformBuffers) ||
(!commandBuffer->textureDownloads)) {
D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer);
SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false);
}
D3D12CommandBuffer **resizedAvailableCommandBuffers = (D3D12CommandBuffer **)SDL_realloc(
renderer->availableCommandBuffers,
sizeof(D3D12CommandBuffer *) * (renderer->availableCommandBufferCapacity + 1));
if (!resizedAvailableCommandBuffers) {
D3D12_INTERNAL_DestroyCommandBuffer(commandBuffer);
SET_STRING_ERROR_AND_RETURN("Failed to create ID3D12CommandList. Out of Memory", false);
}
renderer->availableCommandBufferCapacity += 1;
renderer->availableCommandBuffers = resizedAvailableCommandBuffers;
renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer;
renderer->availableCommandBufferCount += 1;
return true;
}
static D3D12CommandBuffer *D3D12_INTERNAL_AcquireCommandBufferFromPool(
D3D12Renderer *renderer)
{
D3D12CommandBuffer *commandBuffer;
if (renderer->availableCommandBufferCount == 0) {
if (!D3D12_INTERNAL_AllocateCommandBuffer(renderer)) {
return NULL;
}
}
commandBuffer = renderer->availableCommandBuffers[renderer->availableCommandBufferCount - 1];
renderer->availableCommandBufferCount -= 1;
return commandBuffer;
}
static SDL_GPUCommandBuffer *D3D12_AcquireCommandBuffer(
SDL_GPURenderer *driverData)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12CommandBuffer *commandBuffer;
ID3D12DescriptorHeap *heaps[2];
SDL_zeroa(heaps);
SDL_LockMutex(renderer->acquireCommandBufferLock);
commandBuffer = D3D12_INTERNAL_AcquireCommandBufferFromPool(renderer);
SDL_UnlockMutex(renderer->acquireCommandBufferLock);
if (commandBuffer == NULL) {
return NULL;
}
commandBuffer->currentGraphicsPipeline = NULL;
SDL_zeroa(commandBuffer->colorTargetSubresources);
SDL_zeroa(commandBuffer->colorResolveSubresources);
commandBuffer->depthStencilTextureSubresource = NULL;
SDL_zeroa(commandBuffer->vertexBuffers);
SDL_zeroa(commandBuffer->vertexBufferOffsets);
commandBuffer->vertexBufferCount = 0;
SDL_zeroa(commandBuffer->vertexSamplerTextureDescriptorHandles);
SDL_zeroa(commandBuffer->vertexSamplerDescriptorHandles);
SDL_zeroa(commandBuffer->vertexStorageTextureDescriptorHandles);
SDL_zeroa(commandBuffer->vertexStorageBufferDescriptorHandles);
SDL_zeroa(commandBuffer->vertexUniformBuffers);
SDL_zeroa(commandBuffer->fragmentSamplerTextureDescriptorHandles);
SDL_zeroa(commandBuffer->fragmentSamplerDescriptorHandles);
SDL_zeroa(commandBuffer->fragmentStorageTextureDescriptorHandles);
SDL_zeroa(commandBuffer->fragmentStorageBufferDescriptorHandles);
SDL_zeroa(commandBuffer->fragmentUniformBuffers);
SDL_zeroa(commandBuffer->computeSamplerTextureDescriptorHandles);
SDL_zeroa(commandBuffer->computeSamplerDescriptorHandles);
SDL_zeroa(commandBuffer->computeReadOnlyStorageTextureDescriptorHandles);
SDL_zeroa(commandBuffer->computeReadOnlyStorageBufferDescriptorHandles);
SDL_zeroa(commandBuffer->computeReadOnlyStorageTextures);
SDL_zeroa(commandBuffer->computeReadOnlyStorageBuffers);
SDL_zeroa(commandBuffer->computeReadWriteStorageTextureSubresources);
SDL_zeroa(commandBuffer->computeReadWriteStorageBuffers);
SDL_zeroa(commandBuffer->computeUniformBuffers);
commandBuffer->autoReleaseFence = true;
return (SDL_GPUCommandBuffer *)commandBuffer;
}
static bool D3D12_WaitForSwapchain(
SDL_GPURenderer *driverData,
SDL_Window *window)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12WindowData *windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot wait for a swapchain from an unclaimed window!", false);
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (!D3D12_WaitForFences(
driverData,
true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
return false;
}
}
return true;
}
static bool D3D12_INTERNAL_AcquireSwapchainTexture(
bool block,
SDL_GPUCommandBuffer *commandBuffer,
SDL_Window *window,
SDL_GPUTexture **swapchainTexture,
Uint32 *swapchainTextureWidth,
Uint32 *swapchainTextureHeight)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
D3D12WindowData *windowData;
Uint32 swapchainIndex;
HRESULT res;
*swapchainTexture = NULL;
if (swapchainTextureWidth) {
*swapchainTextureWidth = 0;
}
if (swapchainTextureHeight) {
*swapchainTextureHeight = 0;
}
windowData = D3D12_INTERNAL_FetchWindowData(window);
if (windowData == NULL) {
SET_STRING_ERROR_AND_RETURN("Cannot acquire swapchain texture from an unclaimed window!", false);
}
if (windowData->needsSwapchainRecreate) {
if (!D3D12_INTERNAL_ResizeSwapchain(renderer, windowData)) {
return false;
}
}
if (swapchainTextureWidth) {
*swapchainTextureWidth = windowData->width;
}
if (swapchainTextureHeight) {
*swapchainTextureHeight = windowData->height;
}
if (windowData->inFlightFences[windowData->frameCounter] != NULL) {
if (block) {
if (!D3D12_WaitForFences(
(SDL_GPURenderer *)renderer,
true,
&windowData->inFlightFences[windowData->frameCounter],
1)) {
return false;
}
} else {
if (!D3D12_QueryFence(
(SDL_GPURenderer *)renderer,
windowData->inFlightFences[windowData->frameCounter])) {
return true;
}
}
D3D12_ReleaseFence(
(SDL_GPURenderer *)renderer,
windowData->inFlightFences[windowData->frameCounter]);
windowData->inFlightFences[windowData->frameCounter] = NULL;
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
windowData->frameToken = D3D12XBOX_FRAME_PIPELINE_TOKEN_NULL;
renderer->device->WaitFrameEventX(D3D12XBOX_FRAME_EVENT_ORIGIN, INFINITE, NULL, D3D12XBOX_WAIT_FRAME_EVENT_FLAG_NONE, &windowData->frameToken);
swapchainIndex = windowData->frameCounter;
#else
swapchainIndex = IDXGISwapChain3_GetCurrentBackBufferIndex(windowData->swapchain);
res = IDXGISwapChain_GetBuffer(
windowData->swapchain,
swapchainIndex,
D3D_GUID(D3D_IID_ID3D12Resource),
(void **)&windowData->textureContainers[swapchainIndex].activeTexture->resource);
CHECK_D3D12_ERROR_AND_RETURN("Could not acquire swapchain!", false);
#endif
if (d3d12CommandBuffer->presentDataCount == d3d12CommandBuffer->presentDataCapacity) {
d3d12CommandBuffer->presentDataCapacity += 1;
d3d12CommandBuffer->presentDatas = (D3D12PresentData *)SDL_realloc(
d3d12CommandBuffer->presentDatas,
d3d12CommandBuffer->presentDataCapacity * sizeof(D3D12PresentData));
}
d3d12CommandBuffer->presentDatas[d3d12CommandBuffer->presentDataCount].windowData = windowData;
d3d12CommandBuffer->presentDatas[d3d12CommandBuffer->presentDataCount].swapchainImageIndex = swapchainIndex;
d3d12CommandBuffer->presentDataCount += 1;
D3D12_RESOURCE_BARRIER barrierDesc;
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrierDesc.Transition.pResource = windowData->textureContainers[swapchainIndex].activeTexture->resource;
barrierDesc.Transition.Subresource = 0;
ID3D12GraphicsCommandList_ResourceBarrier(
d3d12CommandBuffer->graphicsCommandList,
1,
&barrierDesc);
*swapchainTexture = (SDL_GPUTexture *)&windowData->textureContainers[swapchainIndex];
return true;
}
static bool D3D12_AcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return D3D12_INTERNAL_AcquireSwapchainTexture(
false,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static bool D3D12_WaitAndAcquireSwapchainTexture(
SDL_GPUCommandBuffer *command_buffer,
SDL_Window *window,
SDL_GPUTexture **swapchain_texture,
Uint32 *swapchain_texture_width,
Uint32 *swapchain_texture_height
) {
return D3D12_INTERNAL_AcquireSwapchainTexture(
true,
command_buffer,
window,
swapchain_texture,
swapchain_texture_width,
swapchain_texture_height);
}
static void D3D12_INTERNAL_PerformPendingDestroys(D3D12Renderer *renderer)
{
SDL_LockMutex(renderer->disposeLock);
for (Sint32 i = renderer->buffersToDestroyCount - 1; i >= 0; i -= 1) {
if (SDL_GetAtomicInt(&renderer->buffersToDestroy[i]->referenceCount) == 0) {
D3D12_INTERNAL_DestroyBuffer(
renderer->buffersToDestroy[i]);
renderer->buffersToDestroy[i] = renderer->buffersToDestroy[renderer->buffersToDestroyCount - 1];
renderer->buffersToDestroyCount -= 1;
}
}
for (Sint32 i = renderer->texturesToDestroyCount - 1; i >= 0; i -= 1) {
if (SDL_GetAtomicInt(&renderer->texturesToDestroy[i]->referenceCount) == 0) {
D3D12_INTERNAL_DestroyTexture(
renderer->texturesToDestroy[i]);
renderer->texturesToDestroy[i] = renderer->texturesToDestroy[renderer->texturesToDestroyCount - 1];
renderer->texturesToDestroyCount -= 1;
}
}
for (Sint32 i = renderer->samplersToDestroyCount - 1; i >= 0; i -= 1) {
if (SDL_GetAtomicInt(&renderer->samplersToDestroy[i]->referenceCount) == 0) {
D3D12_INTERNAL_DestroySampler(
renderer->samplersToDestroy[i]);
renderer->samplersToDestroy[i] = renderer->samplersToDestroy[renderer->samplersToDestroyCount - 1];
renderer->samplersToDestroyCount -= 1;
}
}
for (Sint32 i = renderer->graphicsPipelinesToDestroyCount - 1; i >= 0; i -= 1) {
if (SDL_GetAtomicInt(&renderer->graphicsPipelinesToDestroy[i]->referenceCount) == 0) {
D3D12_INTERNAL_DestroyGraphicsPipeline(
renderer->graphicsPipelinesToDestroy[i]);
renderer->graphicsPipelinesToDestroy[i] = renderer->graphicsPipelinesToDestroy[renderer->graphicsPipelinesToDestroyCount - 1];
renderer->graphicsPipelinesToDestroyCount -= 1;
}
}
for (Sint32 i = renderer->computePipelinesToDestroyCount - 1; i >= 0; i -= 1) {
if (SDL_GetAtomicInt(&renderer->computePipelinesToDestroy[i]->referenceCount) == 0) {
D3D12_INTERNAL_DestroyComputePipeline(
renderer->computePipelinesToDestroy[i]);
renderer->computePipelinesToDestroy[i] = renderer->computePipelinesToDestroy[renderer->computePipelinesToDestroyCount - 1];
renderer->computePipelinesToDestroyCount -= 1;
}
}
SDL_UnlockMutex(renderer->disposeLock);
}
static bool D3D12_INTERNAL_CopyTextureDownload(
D3D12CommandBuffer *commandBuffer,
D3D12TextureDownload *download)
{
D3D12Renderer *renderer = commandBuffer->renderer;
Uint8 *sourcePtr;
Uint8 *destPtr;
HRESULT res;
res = ID3D12Resource_Map(
download->temporaryBuffer->handle,
0,
NULL,
(void **)&sourcePtr);
CHECK_D3D12_ERROR_AND_RETURN("Failed to map temporary buffer", false);
res = ID3D12Resource_Map(
download->destinationBuffer->handle,
0,
NULL,
(void **)&destPtr);
CHECK_D3D12_ERROR_AND_RETURN("Failed to map destination buffer", false);
for (Uint32 sliceIndex = 0; sliceIndex < download->depth; sliceIndex += 1) {
for (Uint32 rowIndex = 0; rowIndex < download->height; rowIndex += 1) {
SDL_memcpy(
destPtr + download->bufferOffset + (sliceIndex * download->bytesPerDepthSlice) + (rowIndex * download->bytesPerRow),
sourcePtr + (sliceIndex * download->height) + (rowIndex * download->alignedBytesPerRow),
download->bytesPerRow);
}
}
ID3D12Resource_Unmap(
download->temporaryBuffer->handle,
0,
NULL);
ID3D12Resource_Unmap(
download->destinationBuffer->handle,
0,
NULL);
return true;
}
static bool D3D12_INTERNAL_CleanCommandBuffer(
D3D12Renderer *renderer,
D3D12CommandBuffer *commandBuffer,
bool cancel)
{
Uint32 i;
HRESULT res;
bool result = true;
for (i = 0; i < commandBuffer->textureDownloadCount; i += 1) {
if (!cancel) {
result &= D3D12_INTERNAL_CopyTextureDownload(
commandBuffer,
commandBuffer->textureDownloads[i]);
}
SDL_free(commandBuffer->textureDownloads[i]);
}
commandBuffer->textureDownloadCount = 0;
if (!result) {
return false;
}
res = ID3D12CommandAllocator_Reset(commandBuffer->commandAllocator);
CHECK_D3D12_ERROR_AND_RETURN("Could not reset command allocator", false);
res = ID3D12GraphicsCommandList_Reset(
commandBuffer->graphicsCommandList,
commandBuffer->commandAllocator,
NULL);
CHECK_D3D12_ERROR_AND_RETURN("Could not reset command list", false);
for (i = 0; i < commandBuffer->usedDescriptorHeapCount; i += 1) {
D3D12_INTERNAL_ReturnGPUDescriptorHeapToPool(
renderer,
commandBuffer->usedDescriptorHeaps[i]);
}
commandBuffer->usedDescriptorHeapCount = 0;
commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV] = NULL;
commandBuffer->gpuDescriptorHeaps[D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER] = NULL;
SDL_LockMutex(renderer->acquireUniformBufferLock);
for (i = 0; i < commandBuffer->usedUniformBufferCount; i += 1) {
D3D12_INTERNAL_ReturnUniformBufferToPool(
renderer,
commandBuffer->usedUniformBuffers[i]);
}
commandBuffer->usedUniformBufferCount = 0;
SDL_UnlockMutex(renderer->acquireUniformBufferLock);
for (i = 0; i < commandBuffer->usedTextureCount; i += 1) {
(void)SDL_AtomicDecRef(&commandBuffer->usedTextures[i]->referenceCount);
}
commandBuffer->usedTextureCount = 0;
for (i = 0; i < commandBuffer->usedBufferCount; i += 1) {
(void)SDL_AtomicDecRef(&commandBuffer->usedBuffers[i]->referenceCount);
}
commandBuffer->usedBufferCount = 0;
for (i = 0; i < commandBuffer->usedSamplerCount; i += 1) {
(void)SDL_AtomicDecRef(&commandBuffer->usedSamplers[i]->referenceCount);
}
commandBuffer->usedSamplerCount = 0;
for (i = 0; i < commandBuffer->usedGraphicsPipelineCount; i += 1) {
(void)SDL_AtomicDecRef(&commandBuffer->usedGraphicsPipelines[i]->referenceCount);
}
commandBuffer->usedGraphicsPipelineCount = 0;
for (i = 0; i < commandBuffer->usedComputePipelineCount; i += 1) {
(void)SDL_AtomicDecRef(&commandBuffer->usedComputePipelines[i]->referenceCount);
}
commandBuffer->usedComputePipelineCount = 0;
commandBuffer->presentDataCount = 0;
if (commandBuffer->autoReleaseFence) {
D3D12_ReleaseFence(
(SDL_GPURenderer *)renderer,
(SDL_GPUFence *)commandBuffer->inFlightFence);
commandBuffer->inFlightFence = NULL;
}
SDL_LockMutex(renderer->acquireCommandBufferLock);
if (renderer->availableCommandBufferCount == renderer->availableCommandBufferCapacity) {
renderer->availableCommandBufferCapacity += 1;
renderer->availableCommandBuffers = (D3D12CommandBuffer **)SDL_realloc(
renderer->availableCommandBuffers,
renderer->availableCommandBufferCapacity * sizeof(D3D12CommandBuffer *));
}
renderer->availableCommandBuffers[renderer->availableCommandBufferCount] = commandBuffer;
renderer->availableCommandBufferCount += 1;
SDL_UnlockMutex(renderer->acquireCommandBufferLock);
if (!cancel) {
for (i = 0; i < renderer->submittedCommandBufferCount; i += 1) {
if (renderer->submittedCommandBuffers[i] == commandBuffer) {
renderer->submittedCommandBuffers[i] = renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount - 1];
renderer->submittedCommandBufferCount -= 1;
}
}
}
return true;
}
static bool D3D12_Submit(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
ID3D12CommandList *commandLists[1];
HRESULT res;
SDL_LockMutex(renderer->submitLock);
for (Uint32 i = 0; i < MAX_UNIFORM_BUFFERS_PER_STAGE; i += 1) {
if (d3d12CommandBuffer->vertexUniformBuffers[i] != NULL) {
ID3D12Resource_Unmap(
d3d12CommandBuffer->vertexUniformBuffers[i]->buffer->handle,
0,
NULL);
d3d12CommandBuffer->vertexUniformBuffers[i]->buffer->mapPointer = NULL;
}
if (d3d12CommandBuffer->fragmentUniformBuffers[i] != NULL) {
ID3D12Resource_Unmap(
d3d12CommandBuffer->fragmentUniformBuffers[i]->buffer->handle,
0,
NULL);
d3d12CommandBuffer->fragmentUniformBuffers[i]->buffer->mapPointer = NULL;
}
}
for (Uint32 i = 0; i < d3d12CommandBuffer->presentDataCount; i += 1) {
Uint32 swapchainIndex = d3d12CommandBuffer->presentDatas[i].swapchainImageIndex;
D3D12TextureContainer *container = &d3d12CommandBuffer->presentDatas[i].windowData->textureContainers[swapchainIndex];
D3D12TextureSubresource *subresource = D3D12_INTERNAL_FetchTextureSubresource(container, 0, 0);
D3D12_RESOURCE_BARRIER barrierDesc;
barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
barrierDesc.Transition.pResource = subresource->parent->resource;
barrierDesc.Transition.Subresource = subresource->index;
ID3D12GraphicsCommandList_ResourceBarrier(
d3d12CommandBuffer->graphicsCommandList,
1,
&barrierDesc);
}
res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList);
CHECK_D3D12_ERROR_AND_RETURN("Failed to close command list!", false);
res = ID3D12GraphicsCommandList_QueryInterface(
d3d12CommandBuffer->graphicsCommandList,
D3D_GUID(D3D_IID_ID3D12CommandList),
(void **)&commandLists[0]);
if (FAILED(res)) {
SDL_UnlockMutex(renderer->submitLock);
CHECK_D3D12_ERROR_AND_RETURN("Failed to convert command list!", false);
}
ID3D12CommandQueue_ExecuteCommandLists(
renderer->commandQueue,
1,
commandLists);
ID3D12CommandList_Release(commandLists[0]);
d3d12CommandBuffer->inFlightFence = D3D12_INTERNAL_AcquireFence(renderer);
if (!d3d12CommandBuffer->inFlightFence) {
SDL_UnlockMutex(renderer->submitLock);
return false;
}
res = ID3D12CommandQueue_Signal(
renderer->commandQueue,
d3d12CommandBuffer->inFlightFence->handle,
D3D12_FENCE_SIGNAL_VALUE);
if (FAILED(res)) {
SDL_UnlockMutex(renderer->submitLock);
CHECK_D3D12_ERROR_AND_RETURN("Failed to enqueue fence signal!", false);
}
if (renderer->submittedCommandBufferCount + 1 >= renderer->submittedCommandBufferCapacity) {
renderer->submittedCommandBufferCapacity = renderer->submittedCommandBufferCount + 1;
renderer->submittedCommandBuffers = (D3D12CommandBuffer **)SDL_realloc(
renderer->submittedCommandBuffers,
sizeof(D3D12CommandBuffer *) * renderer->submittedCommandBufferCapacity);
}
renderer->submittedCommandBuffers[renderer->submittedCommandBufferCount] = d3d12CommandBuffer;
renderer->submittedCommandBufferCount += 1;
bool result = true;
for (Uint32 i = 0; i < d3d12CommandBuffer->presentDataCount; i += 1) {
D3D12PresentData *presentData = &d3d12CommandBuffer->presentDatas[i];
D3D12WindowData *windowData = presentData->windowData;
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
D3D12XBOX_PRESENT_PLANE_PARAMETERS planeParams;
SDL_zero(planeParams);
planeParams.Token = windowData->frameToken;
planeParams.ResourceCount = 1;
planeParams.ppResources = &windowData->textureContainers[windowData->frameCounter].activeTexture->resource;
planeParams.ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
D3D12XBOX_PRESENT_PARAMETERS presentParams;
SDL_zero(presentParams);
presentParams.Flags = (windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE) ? D3D12XBOX_PRESENT_FLAG_IMMEDIATE : D3D12XBOX_PRESENT_FLAG_NONE;
renderer->commandQueue->PresentX(1, &planeParams, &presentParams);
if (FAILED(res)) {
result = false;
}
#else
Uint32 syncInterval = 1;
if (windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE ||
windowData->present_mode == SDL_GPU_PRESENTMODE_MAILBOX) {
syncInterval = 0;
}
Uint32 presentFlags = 0;
if (renderer->supportsTearing &&
windowData->present_mode == SDL_GPU_PRESENTMODE_IMMEDIATE) {
presentFlags = DXGI_PRESENT_ALLOW_TEARING;
}
res = IDXGISwapChain_Present(
windowData->swapchain,
syncInterval,
presentFlags);
if (FAILED(res)) {
result = false;
}
ID3D12Resource_Release(windowData->textureContainers[presentData->swapchainImageIndex].activeTexture->resource);
#endif
windowData->inFlightFences[windowData->frameCounter] = (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence;
(void)SDL_AtomicIncRef(&d3d12CommandBuffer->inFlightFence->referenceCount);
windowData->frameCounter = (windowData->frameCounter + 1) % windowData->swapchainTextureCount;
}
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
Uint64 fenceValue = ID3D12Fence_GetCompletedValue(
renderer->submittedCommandBuffers[i]->inFlightFence->handle);
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) {
result &= D3D12_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i],
false);
}
}
D3D12_INTERNAL_PerformPendingDestroys(renderer);
SDL_UnlockMutex(renderer->submitLock);
return result;
}
static SDL_GPUFence *D3D12_SubmitAndAcquireFence(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
d3d12CommandBuffer->autoReleaseFence = false;
if (!D3D12_Submit(commandBuffer)) {
return NULL;
}
return (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence;
}
static bool D3D12_Cancel(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
bool result;
HRESULT res;
res = ID3D12GraphicsCommandList_Close(d3d12CommandBuffer->graphicsCommandList);
CHECK_D3D12_ERROR_AND_RETURN("Failed to close command list!", false);
d3d12CommandBuffer->autoReleaseFence = false;
SDL_LockMutex(renderer->submitLock);
result = D3D12_INTERNAL_CleanCommandBuffer(renderer, d3d12CommandBuffer, true);
SDL_UnlockMutex(renderer->submitLock);
return result;
}
static bool D3D12_Wait(
SDL_GPURenderer *driverData)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12Fence *fence = D3D12_INTERNAL_AcquireFence(renderer);
if (!fence) {
return false;
}
HRESULT res;
SDL_LockMutex(renderer->submitLock);
if (renderer->commandQueue) {
ID3D12CommandQueue_Signal(
renderer->commandQueue,
fence->handle,
D3D12_FENCE_SIGNAL_VALUE);
if (ID3D12Fence_GetCompletedValue(fence->handle) != D3D12_FENCE_SIGNAL_VALUE) {
res = ID3D12Fence_SetEventOnCompletion(
fence->handle,
D3D12_FENCE_SIGNAL_VALUE,
fence->event);
CHECK_D3D12_ERROR_AND_RETURN("Setting fence event failed", false);
DWORD waitResult = WaitForSingleObject(fence->event, INFINITE);
if (waitResult == WAIT_FAILED) {
SDL_UnlockMutex(renderer->submitLock);
SET_STRING_ERROR_AND_RETURN("Wait failed", false); }
}
}
D3D12_ReleaseFence(
(SDL_GPURenderer *)renderer,
(SDL_GPUFence *)fence);
bool result = true;
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
result &= D3D12_INTERNAL_CleanCommandBuffer(renderer, renderer->submittedCommandBuffers[i], false);
}
D3D12_INTERNAL_PerformPendingDestroys(renderer);
SDL_UnlockMutex(renderer->submitLock);
return result;
}
static bool D3D12_WaitForFences(
SDL_GPURenderer *driverData,
bool waitAll,
SDL_GPUFence *const *fences,
Uint32 numFences)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12Fence *fence;
HANDLE *events = SDL_stack_alloc(HANDLE, numFences);
HRESULT res;
SDL_LockMutex(renderer->submitLock);
for (Uint32 i = 0; i < numFences; i += 1) {
fence = (D3D12Fence *)fences[i];
res = ID3D12Fence_SetEventOnCompletion(
fence->handle,
D3D12_FENCE_SIGNAL_VALUE,
fence->event);
CHECK_D3D12_ERROR_AND_RETURN("Setting fence event failed", false);
events[i] = fence->event;
}
DWORD waitResult = WaitForMultipleObjects(
numFences,
events,
waitAll,
INFINITE);
if (waitResult == WAIT_FAILED) {
SDL_UnlockMutex(renderer->submitLock);
SET_STRING_ERROR_AND_RETURN("Wait failed", false); }
bool result = true;
for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) {
Uint64 fenceValue = ID3D12Fence_GetCompletedValue(
renderer->submittedCommandBuffers[i]->inFlightFence->handle);
if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) {
result &= D3D12_INTERNAL_CleanCommandBuffer(
renderer,
renderer->submittedCommandBuffers[i],
false);
}
}
D3D12_INTERNAL_PerformPendingDestroys(renderer);
SDL_stack_free(events);
SDL_UnlockMutex(renderer->submitLock);
return result;
}
static bool D3D12_SupportsTextureFormat(
SDL_GPURenderer *driverData,
SDL_GPUTextureFormat format,
SDL_GPUTextureType type,
SDL_GPUTextureUsageFlags usage)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
DXGI_FORMAT dxgiFormat = SDLToD3D12_TextureFormat[format];
D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = { dxgiFormat, D3D12_FORMAT_SUPPORT1_NONE, D3D12_FORMAT_SUPPORT2_NONE };
HRESULT res;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_FORMAT_SUPPORT,
&formatSupport,
sizeof(formatSupport));
if (FAILED(res)) {
return false;
}
if (type == SDL_GPU_TEXTURETYPE_2D && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) {
return false;
}
if (type == SDL_GPU_TEXTURETYPE_2D_ARRAY && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D)) {
return false;
}
if (type == SDL_GPU_TEXTURETYPE_3D && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE3D)) {
return false;
}
if (type == SDL_GPU_TEXTURETYPE_CUBE && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)) {
return false;
}
if (type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURECUBE)) {
return false;
}
if ((usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)) {
return false;
}
if ((usage & (SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ | SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_READ)) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_LOAD)) {
return false;
}
if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_WRITE) && !(formatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE)) {
return false;
}
if ((usage & SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE) && !(formatSupport.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD)) {
return false;
}
if ((usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) {
return false;
}
formatSupport.Format = SDLToD3D12_DepthFormat[format];
formatSupport.Support1 = D3D12_FORMAT_SUPPORT1_NONE;
formatSupport.Support2 = D3D12_FORMAT_SUPPORT2_NONE;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_FORMAT_SUPPORT,
&formatSupport,
sizeof(formatSupport));
if (FAILED(res)) {
return false;
}
if ((usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) && !(formatSupport.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) {
return false;
}
return true;
}
static bool D3D12_SupportsSampleCount(
SDL_GPURenderer *driverData,
SDL_GPUTextureFormat format,
SDL_GPUSampleCount sampleCount)
{
D3D12Renderer *renderer = (D3D12Renderer *)driverData;
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS featureData;
HRESULT res;
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
featureData.Flags = (D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG)0;
#else
featureData.Flags = (D3D12_MULTISAMPLE_QUALITY_LEVEL_FLAGS)0;
#endif
featureData.Format = SDLToD3D12_TextureFormat[format];
featureData.SampleCount = SDLToD3D12_SampleCount[sampleCount];
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS,
&featureData,
sizeof(featureData));
return SUCCEEDED(res) && featureData.NumQualityLevels > 0;
}
static void D3D12_INTERNAL_InitBlitResources(
D3D12Renderer *renderer)
{
SDL_GPUShaderCreateInfo shaderCreateInfo;
SDL_GPUSamplerCreateInfo samplerCreateInfo;
renderer->blitPipelineCapacity = 2;
renderer->blitPipelineCount = 0;
renderer->blitPipelines = (BlitPipelineCacheEntry *)SDL_malloc(
renderer->blitPipelineCapacity * sizeof(BlitPipelineCacheEntry));
SDL_zero(shaderCreateInfo);
shaderCreateInfo.code = (Uint8 *)D3D12_FullscreenVert;
shaderCreateInfo.code_size = sizeof(D3D12_FullscreenVert);
shaderCreateInfo.stage = SDL_GPU_SHADERSTAGE_VERTEX;
shaderCreateInfo.format = SDL_GPU_SHADERFORMAT_DXIL;
renderer->blitVertexShader = D3D12_CreateShader(
(SDL_GPURenderer *)renderer,
&shaderCreateInfo);
if (renderer->blitVertexShader == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile vertex shader for blit!");
}
shaderCreateInfo.code = (Uint8 *)D3D12_BlitFrom2D;
shaderCreateInfo.code_size = sizeof(D3D12_BlitFrom2D);
shaderCreateInfo.stage = SDL_GPU_SHADERSTAGE_FRAGMENT;
shaderCreateInfo.num_samplers = 1;
shaderCreateInfo.num_uniform_buffers = 1;
renderer->blitFrom2DShader = D3D12_CreateShader(
(SDL_GPURenderer *)renderer,
&shaderCreateInfo);
if (renderer->blitFrom2DShader == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom2D pixel shader!");
}
shaderCreateInfo.code = (Uint8 *)D3D12_BlitFrom2DArray;
shaderCreateInfo.code_size = sizeof(D3D12_BlitFrom2DArray);
renderer->blitFrom2DArrayShader = D3D12_CreateShader(
(SDL_GPURenderer *)renderer,
&shaderCreateInfo);
if (renderer->blitFrom2DArrayShader == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom2DArray pixel shader!");
}
shaderCreateInfo.code = (Uint8 *)D3D12_BlitFrom3D;
shaderCreateInfo.code_size = sizeof(D3D12_BlitFrom3D);
renderer->blitFrom3DShader = D3D12_CreateShader(
(SDL_GPURenderer *)renderer,
&shaderCreateInfo);
if (renderer->blitFrom3DShader == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFrom3D pixel shader!");
}
shaderCreateInfo.code = (Uint8 *)D3D12_BlitFromCube;
shaderCreateInfo.code_size = sizeof(D3D12_BlitFromCube);
renderer->blitFromCubeShader = D3D12_CreateShader(
(SDL_GPURenderer *)renderer,
&shaderCreateInfo);
if (renderer->blitFromCubeShader == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFromCube pixel shader!");
}
shaderCreateInfo.code = (Uint8 *)D3D12_BlitFromCubeArray;
shaderCreateInfo.code_size = sizeof(D3D12_BlitFromCubeArray);
renderer->blitFromCubeArrayShader = D3D12_CreateShader(
(SDL_GPURenderer *)renderer,
&shaderCreateInfo);
if (renderer->blitFromCubeArrayShader == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to compile BlitFromCubeArray pixel shader!");
}
samplerCreateInfo.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
samplerCreateInfo.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
samplerCreateInfo.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
samplerCreateInfo.enable_anisotropy = 0;
samplerCreateInfo.enable_compare = 0;
samplerCreateInfo.mag_filter = SDL_GPU_FILTER_NEAREST;
samplerCreateInfo.min_filter = SDL_GPU_FILTER_NEAREST;
samplerCreateInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
samplerCreateInfo.mip_lod_bias = 0.0f;
samplerCreateInfo.min_lod = 0;
samplerCreateInfo.max_lod = 1000;
samplerCreateInfo.max_anisotropy = 1.0f;
samplerCreateInfo.compare_op = SDL_GPU_COMPAREOP_NEVER;
renderer->blitNearestSampler = D3D12_CreateSampler(
(SDL_GPURenderer *)renderer,
&samplerCreateInfo);
if (renderer->blitNearestSampler == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create blit nearest sampler!");
}
samplerCreateInfo.mag_filter = SDL_GPU_FILTER_LINEAR;
samplerCreateInfo.min_filter = SDL_GPU_FILTER_LINEAR;
samplerCreateInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR;
renderer->blitLinearSampler = D3D12_CreateSampler(
(SDL_GPURenderer *)renderer,
&samplerCreateInfo);
if (renderer->blitLinearSampler == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create blit linear sampler!");
}
}
static bool D3D12_PrepareDriver(SDL_VideoDevice *_this, SDL_PropertiesID props)
{
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
return true;
#else
SDL_SharedObject *d3d12Dll;
SDL_SharedObject *dxgiDll;
PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
pfnCreateDXGIFactory1 pCreateDXGIFactory1;
HRESULT res;
ID3D12Device *device;
IDXGIFactory1 *factory;
IDXGIFactory4 *factory4;
IDXGIFactory6 *factory6;
IDXGIAdapter1 *adapter;
bool supports_64UAVs = false;
bool needs_64UAVs = !SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN, false);
bool has_dxbc = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN, false);
bool has_dxil = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN, false);
bool supports_dxil = false;
if (!has_dxbc && !has_dxil) {
return false;
}
d3d12Dll = SDL_LoadObject(D3D12_DLL);
if (d3d12Dll == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find " D3D12_DLL);
return false;
}
pD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction(
d3d12Dll,
D3D12_CREATE_DEVICE_FUNC);
if (pD3D12CreateDevice == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find function " D3D12_CREATE_DEVICE_FUNC " in " D3D12_DLL);
SDL_UnloadObject(d3d12Dll);
return false;
}
dxgiDll = SDL_LoadObject(DXGI_DLL);
if (dxgiDll == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find " DXGI_DLL);
return false;
}
pCreateDXGIFactory1 = (pfnCreateDXGIFactory1)SDL_LoadFunction(
dxgiDll,
CREATE_DXGI_FACTORY1_FUNC);
if (pCreateDXGIFactory1 == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not find function " CREATE_DXGI_FACTORY1_FUNC " in " DXGI_DLL);
SDL_UnloadObject(dxgiDll);
return false;
}
res = pCreateDXGIFactory1(
&D3D_IID_IDXGIFactory1,
(void **)&factory);
if (FAILED(res)) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not create DXGIFactory");
SDL_UnloadObject(d3d12Dll);
SDL_UnloadObject(dxgiDll);
return false;
}
res = IDXGIFactory1_QueryInterface(
factory,
D3D_GUID(D3D_IID_IDXGIFactory4),
(void **)&factory4);
if (FAILED(res)) {
IDXGIFactory1_Release(factory);
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to find DXGI1.4 support, required for DX12");
SDL_UnloadObject(d3d12Dll);
SDL_UnloadObject(dxgiDll);
return false;
}
IDXGIFactory4_Release(factory4);
res = IDXGIFactory1_QueryInterface(
factory,
D3D_GUID(D3D_IID_IDXGIFactory6),
(void **)&factory6);
if (SUCCEEDED(res)) {
res = IDXGIFactory6_EnumAdapterByGpuPreference(
factory6,
0,
DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
D3D_GUID(D3D_IID_IDXGIAdapter1),
(void **)&adapter);
IDXGIFactory6_Release(factory6);
} else {
res = IDXGIFactory1_EnumAdapters1(
factory,
0,
&adapter);
}
if (FAILED(res)) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Failed to find adapter for D3D12Device");
IDXGIFactory1_Release(factory);
SDL_UnloadObject(d3d12Dll);
SDL_UnloadObject(dxgiDll);
return false;
}
SDL_COMPILE_TIME_ASSERT(featurelevel, D3D_FEATURE_LEVEL_CHOICE < D3D_FEATURE_LEVEL_11_1);
if (!needs_64UAVs && !has_dxil && WIN_IsWindows11OrGreater()) {
IDXGIAdapter1_Release(adapter);
IDXGIFactory1_Release(factory);
SDL_UnloadObject(d3d12Dll);
SDL_UnloadObject(dxgiDll);
return true;
}
res = pD3D12CreateDevice(
(IUnknown *)adapter,
D3D_FEATURE_LEVEL_CHOICE,
D3D_GUID(D3D_IID_ID3D12Device),
(void **)&device);
if (SUCCEEDED(res)) {
if (needs_64UAVs) {
D3D12_FEATURE_DATA_D3D12_OPTIONS featureOptions;
SDL_zero(featureOptions);
res = ID3D12Device_CheckFeatureSupport(
device,
D3D12_FEATURE_D3D12_OPTIONS,
&featureOptions,
sizeof(featureOptions));
if (SUCCEEDED(res) && featureOptions.ResourceBindingTier >= D3D12_RESOURCE_BINDING_TIER_2) {
supports_64UAVs = true;
}
}
if (has_dxil) {
D3D12_FEATURE_DATA_SHADER_MODEL shaderModel;
shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0;
res = ID3D12Device_CheckFeatureSupport(
device,
D3D12_FEATURE_SHADER_MODEL,
&shaderModel,
sizeof(shaderModel));
if (SUCCEEDED(res) && shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0) {
supports_dxil = true;
}
}
ID3D12Device_Release(device);
}
IDXGIAdapter1_Release(adapter);
IDXGIFactory1_Release(factory);
SDL_UnloadObject(d3d12Dll);
SDL_UnloadObject(dxgiDll);
if (!supports_64UAVs && needs_64UAVs) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Tier 2 Resource Binding is not supported");
return false;
}
if (!supports_dxil && !has_dxbc) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: DXIL is not supported and DXBC is not being provided");
return false;
}
if (FAILED(res)) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "D3D12: Could not create D3D12Device with feature level " D3D_FEATURE_LEVEL_CHOICE_STR);
return false;
}
return true;
#endif
}
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) && defined(HAVE_IDXGIINFOQUEUE)
static bool D3D12_INTERNAL_TryInitializeDXGIDebug(D3D12Renderer *renderer)
{
pfnDXGIGetDebugInterface pDXGIGetDebugInterface;
HRESULT res;
renderer->dxgidebug_dll = SDL_LoadObject(DXGIDEBUG_DLL);
if (renderer->dxgidebug_dll == NULL) {
return false;
}
pDXGIGetDebugInterface = (pfnDXGIGetDebugInterface)SDL_LoadFunction(
renderer->dxgidebug_dll,
DXGI_GET_DEBUG_INTERFACE_FUNC);
if (pDXGIGetDebugInterface == NULL) {
return false;
}
res = pDXGIGetDebugInterface(&D3D_IID_IDXGIDebug, (void **)&renderer->dxgiDebug);
if (FAILED(res)) {
return false;
}
res = pDXGIGetDebugInterface(&D3D_IID_IDXGIInfoQueue, (void **)&renderer->dxgiInfoQueue);
if (FAILED(res)) {
return false;
}
return true;
}
#endif
static bool D3D12_INTERNAL_TryInitializeD3D12Debug(D3D12Renderer *renderer
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
, ID3D12DeviceFactory * factory
#endif
) {
PFN_D3D12_GET_DEBUG_INTERFACE pD3D12GetDebugInterface;
HRESULT res;
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
if (factory) {
res = ID3D12DeviceFactory_GetConfigurationInterface(factory, &D3D_CLSID_ID3D12Debug, &D3D_IID_ID3D12Debug, (void **)&renderer->d3d12Debug);
if (FAILED(res)) {
return false;
}
ID3D12Debug_EnableDebugLayer(renderer->d3d12Debug);
return true;
}
#endif
pD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)SDL_LoadFunction(
renderer->d3d12_dll,
D3D12_GET_DEBUG_INTERFACE_FUNC);
if (pD3D12GetDebugInterface == NULL) {
return false;
}
res = pD3D12GetDebugInterface(D3D_GUID(D3D_IID_ID3D12Debug), (void **)&renderer->d3d12Debug);
if (FAILED(res)) {
return false;
}
ID3D12Debug_EnableDebugLayer(renderer->d3d12Debug);
return true;
}
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(D3D12Renderer *renderer)
{
ID3D12InfoQueue *infoQueue = NULL;
D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO };
D3D12_INFO_QUEUE_FILTER filter;
HRESULT res;
res = ID3D12Device_QueryInterface(
renderer->device,
D3D_GUID(D3D_IID_ID3D12InfoQueue),
(void **)&infoQueue);
if (FAILED(res)) {
return;
}
SDL_zero(filter);
filter.DenyList.NumSeverities = 1;
filter.DenyList.pSeverityList = severities;
ID3D12InfoQueue_PushStorageFilter(
infoQueue,
&filter);
ID3D12InfoQueue_SetBreakOnSeverity(
infoQueue,
D3D12_MESSAGE_SEVERITY_CORRUPTION,
true);
ID3D12InfoQueue_Release(infoQueue);
}
static void WINAPI D3D12_INTERNAL_OnD3D12DebugInfoMsg(
D3D12_MESSAGE_CATEGORY category,
D3D12_MESSAGE_SEVERITY severity,
D3D12_MESSAGE_ID id,
LPCSTR description,
void *context)
{
char *catStr;
char *sevStr;
switch (category) {
case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED:
catStr = "APPLICATION_DEFINED";
break;
case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS:
catStr = "MISCELLANEOUS";
break;
case D3D12_MESSAGE_CATEGORY_INITIALIZATION:
catStr = "INITIALIZATION";
break;
case D3D12_MESSAGE_CATEGORY_CLEANUP:
catStr = "CLEANUP";
break;
case D3D12_MESSAGE_CATEGORY_COMPILATION:
catStr = "COMPILATION";
break;
case D3D12_MESSAGE_CATEGORY_STATE_CREATION:
catStr = "STATE_CREATION";
break;
case D3D12_MESSAGE_CATEGORY_STATE_SETTING:
catStr = "STATE_SETTING";
break;
case D3D12_MESSAGE_CATEGORY_STATE_GETTING:
catStr = "STATE_GETTING";
break;
case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION:
catStr = "RESOURCE_MANIPULATION";
break;
case D3D12_MESSAGE_CATEGORY_EXECUTION:
catStr = "EXECUTION";
break;
case D3D12_MESSAGE_CATEGORY_SHADER:
catStr = "SHADER";
break;
default:
catStr = "UNKNOWN";
break;
}
switch (severity) {
case D3D12_MESSAGE_SEVERITY_CORRUPTION:
sevStr = "CORRUPTION";
break;
case D3D12_MESSAGE_SEVERITY_ERROR:
sevStr = "ERROR";
break;
case D3D12_MESSAGE_SEVERITY_WARNING:
sevStr = "WARNING";
break;
case D3D12_MESSAGE_SEVERITY_INFO:
sevStr = "INFO";
break;
case D3D12_MESSAGE_SEVERITY_MESSAGE:
sevStr = "MESSAGE";
break;
default:
sevStr = "UNKNOWN";
break;
}
if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) {
SDL_LogError(
SDL_LOG_CATEGORY_GPU,
"D3D12 ERROR: %s [%s %s #%d]",
description,
catStr,
sevStr,
id);
} else {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"D3D12 WARNING: %s [%s %s #%d]",
description,
catStr,
sevStr,
id);
}
}
static void D3D12_INTERNAL_TryInitializeD3D12DebugInfoLogger(D3D12Renderer *renderer)
{
ID3D12InfoQueue1 *infoQueue = NULL;
HRESULT res;
res = ID3D12Device_QueryInterface(
renderer->device,
D3D_GUID(D3D_IID_ID3D12InfoQueue1),
(void **)&infoQueue);
if (FAILED(res)) {
return;
}
ID3D12InfoQueue1_RegisterMessageCallback(
infoQueue,
D3D12_INTERNAL_OnD3D12DebugInfoMsg,
D3D12_MESSAGE_CALLBACK_FLAG_NONE,
NULL,
NULL);
ID3D12InfoQueue1_Release(infoQueue);
}
#endif
static SDL_GPUDevice *D3D12_CreateDevice(bool debugMode, bool preferLowPower, SDL_PropertiesID props)
{
SDL_GPUDevice *result;
D3D12Renderer *renderer;
HRESULT res;
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
PFN_D3D12_XBOX_CREATE_DEVICE D3D12XboxCreateDeviceFunc;
D3D12XBOX_CREATE_DEVICE_PARAMETERS createDeviceParams;
#else
pfnCreateDXGIFactory1 pCreateDXGIFactory1;
IDXGIFactory1 *factory1;
IDXGIFactory5 *factory5;
IDXGIFactory6 *factory6;
DXGI_ADAPTER_DESC1 adapterDesc;
LARGE_INTEGER umdVersion;
PFN_D3D12_GET_INTERFACE pD3D12GetInterface;
PFN_D3D12_CREATE_DEVICE pD3D12CreateDevice;
#endif
D3D12_FEATURE_DATA_ARCHITECTURE architecture;
D3D12_COMMAND_QUEUE_DESC queueDesc;
bool verboseLogs = SDL_GetBooleanProperty(
props,
SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN,
true);
renderer = (D3D12Renderer *)SDL_calloc(1, sizeof(D3D12Renderer));
bool hasDxgiDebug = false;
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
renderer->dxgi_dll = SDL_LoadObject(DXGI_DLL);
if (renderer->dxgi_dll == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Could not find " DXGI_DLL, NULL);
}
#ifdef HAVE_IDXGIINFOQUEUE
if (debugMode) {
hasDxgiDebug = D3D12_INTERNAL_TryInitializeDXGIDebug(renderer);
}
#else
hasDxgiDebug = true;
#endif
#ifdef USE_PIX_RUNTIME
renderer->winpixeventruntime_dll = SDL_LoadObject(WINPIXEVENTRUNTIME_DLL);
WinPixEventRuntimeFns *fns = &renderer->winpixeventruntimeFns;
if (renderer->winpixeventruntime_dll) {
fns->pBeginEventOnCommandList = (pfnBeginEventOnCommandList)SDL_LoadFunction(
renderer->winpixeventruntime_dll,
PIX_BEGIN_EVENT_ON_COMMAND_LIST_FUNC);
fns->pEndEventOnCommandList = (pfnEndEventOnCommandList)SDL_LoadFunction(
renderer->winpixeventruntime_dll,
PIX_END_EVENT_ON_COMMAND_LIST_FUNC);
fns->pSetMarkerOnCommandList = (pfnSetMarkerOnCommandList)SDL_LoadFunction(
renderer->winpixeventruntime_dll,
PIX_SET_MARKER_ON_COMMAND_LIST_FUNC);
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU,
"WinPixEventRuntime.dll is not available. "
"It is required for SDL_Push/PopGPUDebugGroup and SDL_InsertGPUDebugLabel to function correctly. "
"See here for instructions on how to obtain it: https://devblogs.microsoft.com/pix/winpixeventruntime/");
fns->pBeginEventOnCommandList = NULL;
fns->pEndEventOnCommandList = NULL;
fns->pSetMarkerOnCommandList = NULL;
}
#endif
pCreateDXGIFactory1 = (pfnCreateDXGIFactory1)SDL_LoadFunction(
renderer->dxgi_dll,
CREATE_DXGI_FACTORY1_FUNC);
if (pCreateDXGIFactory1 == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Could not load function: " CREATE_DXGI_FACTORY1_FUNC, NULL);
}
res = pCreateDXGIFactory1(
&D3D_IID_IDXGIFactory1,
(void **)&factory1);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create DXGIFactory", NULL);
}
res = IDXGIFactory1_QueryInterface(
factory1,
D3D_GUID(D3D_IID_IDXGIFactory4),
(void **)&renderer->factory);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("DXGI1.4 support not found, required for DX12", NULL);
}
IDXGIFactory1_Release(factory1);
res = IDXGIFactory4_QueryInterface(
renderer->factory,
D3D_GUID(D3D_IID_IDXGIFactory5),
(void **)&factory5);
if (SUCCEEDED(res)) {
res = IDXGIFactory5_CheckFeatureSupport(
factory5,
DXGI_FEATURE_PRESENT_ALLOW_TEARING,
&renderer->supportsTearing,
sizeof(renderer->supportsTearing));
if (FAILED(res)) {
renderer->supportsTearing = false;
}
IDXGIFactory5_Release(factory5);
}
res = IDXGIFactory4_QueryInterface(
renderer->factory,
D3D_GUID(D3D_IID_IDXGIFactory6),
(void **)&factory6);
if (SUCCEEDED(res)) {
res = IDXGIFactory6_EnumAdapterByGpuPreference(
factory6,
0,
preferLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE,
D3D_GUID(D3D_IID_IDXGIAdapter1),
(void **)&renderer->adapter);
IDXGIFactory6_Release(factory6);
} else {
res = IDXGIFactory4_EnumAdapters1(
renderer->factory,
0,
&renderer->adapter);
}
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not find adapter for D3D12Device", NULL);
}
res = IDXGIAdapter1_GetDesc1(renderer->adapter, &adapterDesc);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not get adapter description", NULL);
}
res = IDXGIAdapter1_CheckInterfaceSupport(renderer->adapter, D3D_GUID(D3D_IID_IDXGIDevice), &umdVersion);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not get adapter driver version", NULL);
}
renderer->props = SDL_CreateProperties();
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "SDL_GPU Driver: D3D12");
}
char *deviceName = SDL_iconv_wchar_utf8(&adapterDesc.Description[0]);
SDL_SetStringProperty(
renderer->props,
SDL_PROP_GPU_DEVICE_NAME_STRING,
deviceName);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Adapter: %s", deviceName);
}
SDL_free(deviceName);
char driverVer[64];
(void)SDL_snprintf(
driverVer,
SDL_arraysize(driverVer),
"%d.%d.%d.%d",
HIWORD(umdVersion.HighPart),
LOWORD(umdVersion.HighPart),
HIWORD(umdVersion.LowPart),
LOWORD(umdVersion.LowPart));
SDL_SetStringProperty(
renderer->props,
SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING,
driverVer);
if (verboseLogs) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "D3D12 Driver: %s", driverVer);
}
#endif
renderer->d3d12_dll = SDL_LoadObject(D3D12_DLL);
if (renderer->d3d12_dll == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Could not find " D3D12_DLL, NULL);
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
D3D12XboxCreateDeviceFunc = (PFN_D3D12_XBOX_CREATE_DEVICE)SDL_LoadFunction(
renderer->d3d12_dll,
"D3D12XboxCreateDevice");
if (D3D12XboxCreateDeviceFunc == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Could not load function: D3D12XboxCreateDevice", NULL);
}
#else
pD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)SDL_LoadFunction(
renderer->d3d12_dll,
D3D12_CREATE_DEVICE_FUNC);
if (pD3D12CreateDevice == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_CREATE_DEVICE_FUNC, NULL);
}
#endif
renderer->pD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)SDL_LoadFunction(
renderer->d3d12_dll,
D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC);
if (renderer->pD3D12SerializeRootSignature == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
SET_STRING_ERROR_AND_RETURN("Could not load function: " D3D12_SERIALIZE_ROOT_SIGNATURE_FUNC, NULL);
}
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
ID3D12DeviceFactory *factory = NULL;
if (SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING) && SDL_HasProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER)) {
int d3d12SDKVersion = SDL_GetNumberProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_VERSION_NUMBER, 0);
const char *d3d12SDKPath = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_AGILITY_SDK_PATH_STRING, ".\\D3D12\\");
pD3D12GetInterface = (PFN_D3D12_GET_INTERFACE)SDL_LoadFunction(
renderer->d3d12_dll,
D3D12_GET_INTERFACE_FUNC);
if (pD3D12GetInterface == NULL) {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Could not load D3D12GetInterface, custom D3D12 SDK will not load.");
}
ID3D12SDKConfiguration *sdk_config = NULL;
if (SUCCEEDED(pD3D12GetInterface(D3D_GUID(D3D_CLSID_ID3D12SDKConfiguration), D3D_GUID(D3D_IID_ID3D12SDKConfiguration), (void**) &sdk_config))) {
ID3D12SDKConfiguration1 *sdk_config1 = NULL;
if (SUCCEEDED(IUnknown_QueryInterface(sdk_config, &D3D_IID_ID3D12SDKConfiguration1, (void**) &sdk_config1))) {
if (SUCCEEDED(ID3D12SDKConfiguration1_CreateDeviceFactory(sdk_config1, d3d12SDKVersion, d3d12SDKPath, &D3D_IID_ID3D12DeviceFactory, (void**) &factory))) {
SDL_LogInfo(SDL_LOG_CATEGORY_GPU, "Loaded vendored D3D12Core.dll");
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to load vendored D3D12Core.dll");
}
ID3D12SDKConfiguration1_Release(sdk_config1);
}
ID3D12SDKConfiguration_Release(sdk_config);
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Failed to load vendored D3D12 SDK Configuration");
}
}
#endif
if (debugMode) {
bool hasD3d12Debug = D3D12_INTERNAL_TryInitializeD3D12Debug(renderer
#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
, factory
#endif
);
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
if (hasD3d12Debug) {
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"Validation layers enabled, expect debug level performance!");
#else
if (hasDxgiDebug && hasD3d12Debug) {
SDL_LogInfo(
SDL_LOG_CATEGORY_GPU,
"Validation layers enabled, expect debug level performance!");
} else if (hasDxgiDebug || hasD3d12Debug) {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"Validation layers partially enabled, some warnings may not be available");
#endif
} else {
SDL_LogWarn(
SDL_LOG_CATEGORY_GPU,
"Validation layers not found, continuing without validation");
}
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
if (s_Device != NULL) {
renderer->device = s_Device;
} else {
SDL_zero(createDeviceParams);
createDeviceParams.Version = D3D12_SDK_VERSION;
createDeviceParams.GraphicsCommandQueueRingSizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES;
createDeviceParams.GraphicsScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES;
createDeviceParams.ComputeScratchMemorySizeBytes = D3D12XBOX_DEFAULT_SIZE_BYTES;
createDeviceParams.DisableGeometryShaderAllocations = TRUE;
createDeviceParams.DisableTessellationShaderAllocations = TRUE;
#if defined(SDL_PLATFORM_XBOXSERIES)
createDeviceParams.DisableDXR = TRUE;
#endif
if (debugMode) {
createDeviceParams.ProcessDebugFlags = D3D12XBOX_PROCESS_DEBUG_FLAG_DEBUG;
}
res = D3D12XboxCreateDeviceFunc(
NULL,
&createDeviceParams,
IID_GRAPHICS_PPV_ARGS(&renderer->device));
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL);
}
s_Device = renderer->device;
}
#else
if (factory) {
ID3D12DeviceFactory_SetFlags(factory, D3D12_DEVICE_FACTORY_FLAG_ALLOW_RETURNING_EXISTING_DEVICE);
res = ID3D12DeviceFactory_CreateDevice(
factory,
(IUnknown *)renderer->adapter,
D3D_FEATURE_LEVEL_CHOICE,
D3D_GUID(D3D_IID_ID3D12Device),
(void**)&renderer->device);
ID3D12DeviceFactory_Release(factory);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL);
}
} else {
res = pD3D12CreateDevice(
(IUnknown *)renderer->adapter,
D3D_FEATURE_LEVEL_CHOICE,
D3D_GUID(D3D_IID_ID3D12Device),
(void **)&renderer->device);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12Device", NULL);
}
}
if (debugMode) {
D3D12_INTERNAL_TryInitializeD3D12DebugInfoQueue(renderer);
D3D12_INTERNAL_TryInitializeD3D12DebugInfoLogger(renderer);
}
#endif
architecture.NodeIndex = 0;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_ARCHITECTURE,
&architecture,
sizeof(D3D12_FEATURE_DATA_ARCHITECTURE));
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not get device architecture", NULL);
}
renderer->UMA = (bool)architecture.UMA;
renderer->UMACacheCoherent = (bool)architecture.CacheCoherentUMA;
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
renderer->GPUUploadHeapSupported = false;
#else
D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16; renderer->GPUUploadHeapSupported = false;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_D3D12_OPTIONS16,
&options16,
sizeof(options16));
if (SUCCEEDED(res)) {
renderer->GPUUploadHeapSupported = options16.GPUUploadHeapSupported;
}
#endif
D3D12_FEATURE_DATA_D3D12_OPTIONS13 options13;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_D3D12_OPTIONS13,
&options13,
sizeof(options13));
if (SUCCEEDED(res)) {
renderer->UnrestrictedBufferTextureCopyPitchSupported = options13.UnrestrictedBufferTextureCopyPitchSupported;
}
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "CheckFeatureSupport for UnrestrictedBufferTextureCopyPitchSupported failed. You may need to provide a vendored D3D12Core.dll through the Agility SDK on older platforms.");
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
if (s_CommandQueue != NULL) {
renderer->commandQueue = s_CommandQueue;
} else {
#endif
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.NodeMask = 0;
queueDesc.Priority = 0;
res = ID3D12Device_CreateCommandQueue(
renderer->device,
&queueDesc,
D3D_GUID(D3D_IID_ID3D12CommandQueue),
(void **)&renderer->commandQueue);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create D3D12CommandQueue", NULL);
}
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
s_CommandQueue = renderer->commandQueue;
}
#endif
D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc;
D3D12_INDIRECT_ARGUMENT_DESC indirectArgumentDesc;
SDL_zero(indirectArgumentDesc);
indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW;
commandSignatureDesc.NodeMask = 0;
commandSignatureDesc.ByteStride = sizeof(SDL_GPUIndirectDrawCommand);
commandSignatureDesc.NumArgumentDescs = 1;
commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc;
res = ID3D12Device_CreateCommandSignature(
renderer->device,
&commandSignatureDesc,
NULL,
D3D_GUID(D3D_IID_ID3D12CommandSignature),
(void **)&renderer->indirectDrawCommandSignature);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect draw command signature", NULL);
}
indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED;
commandSignatureDesc.ByteStride = sizeof(SDL_GPUIndexedIndirectDrawCommand);
commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc;
res = ID3D12Device_CreateCommandSignature(
renderer->device,
&commandSignatureDesc,
NULL,
D3D_GUID(D3D_IID_ID3D12CommandSignature),
(void **)&renderer->indirectIndexedDrawCommandSignature);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect indexed draw command signature", NULL);
}
indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH;
commandSignatureDesc.ByteStride = sizeof(SDL_GPUIndirectDispatchCommand);
commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc;
res = ID3D12Device_CreateCommandSignature(
renderer->device,
&commandSignatureDesc,
NULL,
D3D_GUID(D3D_IID_ID3D12CommandSignature),
(void **)&renderer->indirectDispatchCommandSignature);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not create indirect dispatch command signature", NULL);
}
renderer->submittedCommandBufferCapacity = 4;
renderer->submittedCommandBufferCount = 0;
renderer->submittedCommandBuffers = (D3D12CommandBuffer **)SDL_calloc(
renderer->submittedCommandBufferCapacity, sizeof(D3D12CommandBuffer *));
if (!renderer->submittedCommandBuffers) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->uniformBufferPoolCapacity = 4;
renderer->uniformBufferPoolCount = 0;
renderer->uniformBufferPool = (D3D12UniformBuffer **)SDL_calloc(
renderer->uniformBufferPoolCapacity, sizeof(D3D12UniformBuffer *));
if (!renderer->uniformBufferPool) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->claimedWindowCapacity = 4;
renderer->claimedWindowCount = 0;
renderer->claimedWindows = (D3D12WindowData **)SDL_calloc(
renderer->claimedWindowCapacity, sizeof(D3D12WindowData *));
if (!renderer->claimedWindows) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->availableFenceCapacity = 4;
renderer->availableFenceCount = 0;
renderer->availableFences = (D3D12Fence **)SDL_calloc(
renderer->availableFenceCapacity, sizeof(D3D12Fence *));
if (!renderer->availableFences) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
for (Uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) {
renderer->stagingDescriptorPools[i] = D3D12_INTERNAL_CreateStagingDescriptorPool(
renderer,
(D3D12_DESCRIPTOR_HEAP_TYPE)i);
if (renderer->stagingDescriptorPools[i] == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
}
for (Uint32 i = 0; i < 2; i += 1) {
renderer->gpuDescriptorHeapPools[i].lock = SDL_CreateMutex();
renderer->gpuDescriptorHeapPools[i].capacity = 4;
renderer->gpuDescriptorHeapPools[i].count = 4;
renderer->gpuDescriptorHeapPools[i].heaps = (D3D12DescriptorHeap **)SDL_calloc(
renderer->gpuDescriptorHeapPools[i].capacity, sizeof(D3D12DescriptorHeap *));
for (Uint32 j = 0; j < renderer->gpuDescriptorHeapPools[i].capacity; j += 1) {
renderer->gpuDescriptorHeapPools[i].heaps[j] = D3D12_INTERNAL_CreateDescriptorHeap(
renderer,
(D3D12_DESCRIPTOR_HEAP_TYPE)i,
i == D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV ? VIEW_GPU_DESCRIPTOR_COUNT : SAMPLER_GPU_DESCRIPTOR_COUNT,
false);
if (renderer->gpuDescriptorHeapPools[i].heaps[j] == NULL) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
}
}
renderer->buffersToDestroyCapacity = 4;
renderer->buffersToDestroyCount = 0;
renderer->buffersToDestroy = (D3D12Buffer **)SDL_calloc(
renderer->buffersToDestroyCapacity, sizeof(D3D12Buffer *));
if (!renderer->buffersToDestroy) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->texturesToDestroyCapacity = 4;
renderer->texturesToDestroyCount = 0;
renderer->texturesToDestroy = (D3D12Texture **)SDL_calloc(
renderer->texturesToDestroyCapacity, sizeof(D3D12Texture *));
if (!renderer->texturesToDestroy) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->samplersToDestroyCapacity = 4;
renderer->samplersToDestroyCount = 0;
renderer->samplersToDestroy = (D3D12Sampler **)SDL_calloc(
renderer->samplersToDestroyCapacity, sizeof(D3D12Sampler *));
if (!renderer->samplersToDestroy) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->graphicsPipelinesToDestroyCapacity = 4;
renderer->graphicsPipelinesToDestroyCount = 0;
renderer->graphicsPipelinesToDestroy = (D3D12GraphicsPipeline **)SDL_calloc(
renderer->graphicsPipelinesToDestroyCapacity, sizeof(D3D12GraphicsPipeline *));
if (!renderer->graphicsPipelinesToDestroy) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->computePipelinesToDestroyCapacity = 4;
renderer->computePipelinesToDestroyCount = 0;
renderer->computePipelinesToDestroy = (D3D12ComputePipeline **)SDL_calloc(
renderer->computePipelinesToDestroyCapacity, sizeof(D3D12ComputePipeline *));
if (!renderer->computePipelinesToDestroy) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
renderer->acquireCommandBufferLock = SDL_CreateMutex();
renderer->acquireUniformBufferLock = SDL_CreateMutex();
renderer->submitLock = SDL_CreateMutex();
renderer->windowLock = SDL_CreateMutex();
renderer->fenceLock = SDL_CreateMutex();
renderer->disposeLock = SDL_CreateMutex();
renderer->debug_mode = debugMode;
renderer->allowedFramesInFlight = 2;
renderer->semantic = SDL_strdup(SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING, "TEXCOORD"));
D3D12_INTERNAL_InitBlitResources(renderer);
#if (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
res = renderer->device->SetFrameIntervalX(
NULL,
D3D12XBOX_FRAME_INTERVAL_60_HZ,
renderer->allowedFramesInFlight - 1,
D3D12XBOX_FRAME_INTERVAL_FLAG_NONE);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not get set frame interval", NULL);
}
res = renderer->device->ScheduleFrameEventX(
D3D12XBOX_FRAME_EVENT_ORIGIN,
0,
NULL,
D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE);
if (FAILED(res)) {
D3D12_INTERNAL_DestroyRenderer(renderer);
CHECK_D3D12_ERROR_AND_RETURN("Could not schedule frame events", NULL);
}
#endif
result = (SDL_GPUDevice *)SDL_calloc(1, sizeof(SDL_GPUDevice));
if (!result) {
D3D12_INTERNAL_DestroyRenderer(renderer);
return NULL;
}
SDL_GPUShaderFormat shaderFormats = SDL_GPU_SHADERFORMAT_DXBC;
D3D12_FEATURE_DATA_SHADER_MODEL shaderModel;
shaderModel.HighestShaderModel = D3D_SHADER_MODEL_6_0;
res = ID3D12Device_CheckFeatureSupport(
renderer->device,
D3D12_FEATURE_SHADER_MODEL,
&shaderModel,
sizeof(shaderModel));
if (SUCCEEDED(res) && shaderModel.HighestShaderModel >= D3D_SHADER_MODEL_6_0) {
shaderFormats |= SDL_GPU_SHADERFORMAT_DXIL;
}
ASSIGN_DRIVER(D3D12)
result->driverData = (SDL_GPURenderer *)renderer;
result->shader_formats = shaderFormats;
result->debug_mode = debugMode;
renderer->sdlGPUDevice = result;
return result;
}
SDL_GPUBootstrap D3D12Driver = {
"direct3d12",
D3D12_PrepareDriver,
D3D12_CreateDevice
};
#endif
#ifdef SDL_PLATFORM_GDK
void SDL_GDKSuspendGPU(SDL_GPUDevice *device)
{
#if defined(SDL_GPU_D3D12) && (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
D3D12Renderer *renderer = (D3D12Renderer *)device->driverData;
HRESULT res;
if (device == NULL) {
SET_STRING_ERROR_AND_RETURN("Invalid GPU device", );
}
SDL_LockMutex(renderer->submitLock);
res = renderer->commandQueue->SuspendX(0);
if (FAILED(res)) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "SuspendX failed: %X", res);
}
SDL_UnlockMutex(renderer->submitLock);
#endif
}
void SDL_GDKResumeGPU(SDL_GPUDevice *device)
{
#if defined(SDL_GPU_D3D12) && (defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
D3D12Renderer *renderer = (D3D12Renderer *)device->driverData;
HRESULT res;
if (device == NULL) {
SET_STRING_ERROR_AND_RETURN("Invalid GPU device", );
}
SDL_LockMutex(renderer->submitLock);
res = renderer->commandQueue->ResumeX();
if (FAILED(res)) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "ResumeX failed: %X", res);
}
SDL_UnlockMutex(renderer->submitLock);
res = renderer->device->SetFrameIntervalX(
NULL,
D3D12XBOX_FRAME_INTERVAL_60_HZ,
renderer->allowedFramesInFlight - 1,
D3D12XBOX_FRAME_INTERVAL_FLAG_NONE);
if (FAILED(res)) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not set frame interval: %X", res);
}
res = renderer->device->ScheduleFrameEventX(
D3D12XBOX_FRAME_EVENT_ORIGIN,
0,
NULL,
D3D12XBOX_SCHEDULE_FRAME_EVENT_FLAG_NONE);
if (FAILED(res)) {
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Could not schedule frame events: %X", res);
}
#endif
}
#endif