4#include <SDL3/SDL_system.h>
5#include <d3dcompiler.h>
26const D3D12_INPUT_ELEMENT_DESC kVertexInputLayout[] = {
27 {
"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,
28 static_cast<UINT
>(offsetof(Sleak::Vertex, px)),
29 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
30 {
"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,
31 static_cast<UINT
>(offsetof(Sleak::Vertex, nx)),
32 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
33 {
"TANGENT", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0,
34 static_cast<UINT
>(offsetof(Sleak::Vertex, tx)),
35 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
36 {
"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0,
37 static_cast<UINT
>(offsetof(Sleak::Vertex, r)),
38 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
39 {
"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0,
40 static_cast<UINT
>(offsetof(Sleak::Vertex, u)),
41 D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0},
44uint64_t HashBytecode(ID3DBlob* blob) {
46 const auto* bytes =
static_cast<const uint8_t*
>(blob->GetBufferPointer());
47 uint64_t hash = 14695981039346656037ull;
48 for (SIZE_T i = 0; i < blob->GetBufferSize(); ++i) {
50 hash *= 1099511628211ull;
55Microsoft::WRL::ComPtr<ID3DBlob> CompileStage(
const wchar_t* path,
57 const char* profile) {
58 Microsoft::WRL::ComPtr<ID3DBlob> blob, errorBlob;
59 HRESULT hr = D3DCompileFromFile(path,
nullptr,
nullptr, entry, profile, 0,
60 0, &blob, &errorBlob);
63 SLEAK_ERROR(
"{} ({}) compile error: {}", entry, profile,
64 (
char*)errorBlob->GetBufferPointer());
73DirectX12Renderer::DirectX12Renderer(
Window* window) : window(window) {
74 fenceEvent = CreateEvent(
nullptr, FALSE, FALSE,
nullptr);
75 if (fenceEvent ==
nullptr) {
76 throw std::runtime_error(
"Failed to create fence event.");
78 this->Type = RendererType::DirectX12;
79 m_lightData.assign(
sizeof(RenderEngine::ShadowLightUBO), 0);
81 ResourceManager::RegisterCreateBuffer(
82 this, &DirectX12Renderer::CreateBuffer);
83 ResourceManager::RegisterCreateShader(
84 this, &DirectX12Renderer::CreateShader);
85 ResourceManager::RegisterCreateTexture(
86 this, &DirectX12Renderer::CreateTexture);
87 ResourceManager::RegisterCreateCubemapTexture(
88 this, &DirectX12Renderer::CreateCubemapTexture);
89 ResourceManager::RegisterCreateCubemapTextureFromPanorama(
90 this, &DirectX12Renderer::CreateCubemapTextureFromPanorama);
91 ResourceManager::RegisterCreateTextureFromMemory(
92 [
this](
const void* data, uint32_t w, uint32_t h, TextureFormat fmt,
93 uint32_t) -> Texture* {
94 auto* tex =
new DirectX12Texture(device.Get(), commandQueue.Get(),
95 commandList.Get(), &m_uploader);
96 if (!tex->LoadFromMemory(data, w, h, fmt)) {
100 UINT slot = AllocateSRVSlot();
101 tex->CreateSRVIntoHandle(DXGI_FORMAT_R8G8B8A8_UNORM,
102 GetSharedSrvCPUHandle(slot));
103 tex->SetSharedSrvGPUHandle(GetSharedSrvGPUHandle(slot));
108DirectX12Renderer::~DirectX12Renderer() {
110 delete m_defaultTexture;
111 m_defaultTexture =
nullptr;
114 CloseHandle(fenceEvent);
115 fenceEvent =
nullptr;
119bool DirectX12Renderer::Initialize() {
120 if (m_Initialized)
return true;
122 if (!CreateDevice())
return false;
123 if (!CreateCommandQueue())
return false;
124 if (!CreateCommandAllocatorAndList())
return false;
125 if (!CreateSwapChain())
return false;
126 if (!CreateRenderTargetViews())
return false;
127 if (!CreateDepthStencilView())
return false;
128 if (!CreateFence())
return false;
129 m_uploadRing.Initialize(device.Get(), FrameCount, 64 * 1024);
130 if (!m_uploader.Initialize(device.Get(), commandQueue.Get()))
return false;
131 if (!CreateRootSignature())
return false;
132 if (!CreateSharedSrvHeap())
return false;
137 uint32_t whitePixel = 0xFFFFFFFF;
138 m_defaultTexture =
new DirectX12Texture(
139 device.Get(), commandQueue.Get(), commandList.Get(), &m_uploader);
140 if (!m_defaultTexture->LoadFromMemory(
141 &whitePixel, 1, 1, TextureFormat::RGBA8)) {
142 SLEAK_WARN(
"Failed to create default white texture for DX12");
143 delete m_defaultTexture;
144 m_defaultTexture =
nullptr;
146 UINT slot = AllocateSRVSlot();
147 m_defaultTexture->CreateSRVIntoHandle(DXGI_FORMAT_R8G8B8A8_UNORM,
148 GetSharedSrvCPUHandle(slot));
149 m_defaultTexture->SetSharedSrvGPUHandle(GetSharedSrvGPUHandle(slot));
154 int w = Window::GetWidth();
155 int h = Window::GetHeight();
156 viewport.TopLeftX = 0.0f;
157 viewport.TopLeftY = 0.0f;
158 viewport.Width =
static_cast<float>(w);
159 viewport.Height =
static_cast<float>(h);
160 viewport.MinDepth = 0.0f;
161 viewport.MaxDepth = 1.0f;
163 scissorRect.left = 0;
165 scissorRect.right = w;
166 scissorRect.bottom = h;
168 SetPerformanceCounter(
true);
170 m_Initialized =
true;
171 SLEAK_INFO(
"DirectX 12 has been initialized successfully!");
176bool DirectX12Renderer::CreateDevice() {
178 if (SUCCEEDED(D3D12CreateDevice(
nullptr, D3D_FEATURE_LEVEL_12_0,
179 IID_PPV_ARGS(&device)))) {
180 SLEAK_INFO(
"DirectX 12 device created with feature level 12.0");
185 if (SUCCEEDED(D3D12CreateDevice(
nullptr, D3D_FEATURE_LEVEL_11_0,
186 IID_PPV_ARGS(&device)))) {
187 SLEAK_INFO(
"DirectX 12 device created with feature level 11.0");
191 SLEAK_ERROR(
"Failed to create DirectX 12 device!");
195bool DirectX12Renderer::CreateCommandQueue() {
196 D3D12_COMMAND_QUEUE_DESC queueDesc = {};
197 queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
198 queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
200 if (FAILED(device->CreateCommandQueue(&queueDesc,
201 IID_PPV_ARGS(&commandQueue)))) {
208bool DirectX12Renderer::CreateCommandAllocatorAndList() {
211 for (UINT i = 0; i < FrameCount; i++) {
212 if (FAILED(device->CreateCommandAllocator(
213 D3D12_COMMAND_LIST_TYPE_DIRECT,
214 IID_PPV_ARGS(&commandAllocators[i])))) {
215 SLEAK_ERROR(
"Failed to create command allocator {}!", i);
220 if (FAILED(device->CreateCommandList(
221 0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocators[0].Get(),
222 nullptr, IID_PPV_ARGS(&commandList)))) {
228 commandList->Close();
232bool DirectX12Renderer::CreateSwapChain() {
233 HWND hwnd = (HWND)SDL_GetPointerProperty(
234 SDL_GetWindowProperties(window->GetSDLWindow()),
235 SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
237 DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
238 swapChainDesc.BufferCount = FrameCount;
239 swapChainDesc.Width = 0;
240 swapChainDesc.Height = 0;
241 swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
242 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
243 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
244 swapChainDesc.SampleDesc.Count = 1;
246 Microsoft::WRL::ComPtr<IDXGIFactory4> factory;
247 if (FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) {
252 HRESULT hr = factory->CreateSwapChainForHwnd(
253 commandQueue.Get(), hwnd, &swapChainDesc,
nullptr,
nullptr,
254 reinterpret_cast<IDXGISwapChain1**
>(swapChain.GetAddressOf()));
261 frameIndex = swapChain->GetCurrentBackBufferIndex();
263 EnumerateDevices(factory);
268bool DirectX12Renderer::CreateRenderTargetViews() {
269 D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
270 rtvHeapDesc.NumDescriptors = FrameCount;
271 rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
272 rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
274 if (FAILED(device->CreateDescriptorHeap(&rtvHeapDesc,
275 IID_PPV_ARGS(&rtvHeap)))) {
276 SLEAK_ERROR(
"Failed to create RTV descriptor heap!");
280 rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(
281 D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
283 D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle =
284 rtvHeap->GetCPUDescriptorHandleForHeapStart();
286 for (UINT i = 0; i < FrameCount; i++) {
287 if (FAILED(swapChain->GetBuffer(i,
288 IID_PPV_ARGS(&renderTargets[i])))) {
289 SLEAK_ERROR(
"Failed to get swap chain buffer {}!", i);
292 device->CreateRenderTargetView(renderTargets[i].Get(),
nullptr,
294 rtvHandle.ptr += rtvDescriptorSize;
300bool DirectX12Renderer::CreateDepthStencilView() {
302 D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
303 dsvHeapDesc.NumDescriptors = 1;
304 dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
305 dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
307 if (FAILED(device->CreateDescriptorHeap(&dsvHeapDesc,
308 IID_PPV_ARGS(&dsvHeap)))) {
309 SLEAK_ERROR(
"Failed to create DSV descriptor heap!");
314 DXGI_SWAP_CHAIN_DESC1 scDesc;
315 swapChain->GetDesc1(&scDesc);
316 UINT
width = scDesc.Width;
317 UINT
height = scDesc.Height;
320 D3D12_RESOURCE_DESC depthDesc = {};
321 depthDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
322 depthDesc.Width =
width;
323 depthDesc.Height =
height;
324 depthDesc.DepthOrArraySize = 1;
325 depthDesc.MipLevels = 1;
326 depthDesc.Format = DXGI_FORMAT_D32_FLOAT;
327 depthDesc.SampleDesc.Count = 1;
328 depthDesc.SampleDesc.Quality = 0;
329 depthDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
331 D3D12_CLEAR_VALUE clearValue = {};
332 clearValue.Format = DXGI_FORMAT_D32_FLOAT;
333 clearValue.DepthStencil.Depth = 1.0f;
334 clearValue.DepthStencil.Stencil = 0;
336 D3D12_HEAP_PROPERTIES heapProps = {};
337 heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
339 if (FAILED(device->CreateCommittedResource(
340 &heapProps, D3D12_HEAP_FLAG_NONE, &depthDesc,
341 D3D12_RESOURCE_STATE_DEPTH_WRITE, &clearValue,
342 IID_PPV_ARGS(&depthStencilBuffer)))) {
343 SLEAK_ERROR(
"Failed to create depth stencil buffer!");
348 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
349 dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
350 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
351 dsvDesc.Flags = D3D12_DSV_FLAG_NONE;
353 device->CreateDepthStencilView(
354 depthStencilBuffer.Get(), &dsvDesc,
355 dsvHeap->GetCPUDescriptorHandleForHeapStart());
360bool DirectX12Renderer::CreateFence() {
361 if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
362 IID_PPV_ARGS(&fence)))) {
367 for (UINT i = 0; i < FrameCount; i++)
372bool DirectX12Renderer::CreateRootSignature() {
378 D3D12_ROOT_PARAMETER rootParams[5] = {};
379 rootParams[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
380 rootParams[0].Descriptor.ShaderRegister = 0;
381 rootParams[0].Descriptor.RegisterSpace = 0;
382 rootParams[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
384 rootParams[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
385 rootParams[1].Descriptor.ShaderRegister = 1;
386 rootParams[1].Descriptor.RegisterSpace = 0;
387 rootParams[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
389 D3D12_DESCRIPTOR_RANGE srvRange = {};
390 srvRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
391 srvRange.NumDescriptors = 1;
392 srvRange.BaseShaderRegister = 0;
393 srvRange.RegisterSpace = 0;
394 srvRange.OffsetInDescriptorsFromTableStart =
395 D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
397 rootParams[2].ParameterType =
398 D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
399 rootParams[2].DescriptorTable.NumDescriptorRanges = 1;
400 rootParams[2].DescriptorTable.pDescriptorRanges = &srvRange;
401 rootParams[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
403 rootParams[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
404 rootParams[3].Descriptor.ShaderRegister = 2;
405 rootParams[3].Descriptor.RegisterSpace = 0;
406 rootParams[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
408 D3D12_DESCRIPTOR_RANGE shadowSrvRange = {};
409 shadowSrvRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
410 shadowSrvRange.NumDescriptors = 1;
411 shadowSrvRange.BaseShaderRegister = 3;
412 shadowSrvRange.RegisterSpace = 0;
413 shadowSrvRange.OffsetInDescriptorsFromTableStart =
414 D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
416 rootParams[4].ParameterType =
417 D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
418 rootParams[4].DescriptorTable.NumDescriptorRanges = 1;
419 rootParams[4].DescriptorTable.pDescriptorRanges = &shadowSrvRange;
420 rootParams[4].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
423 D3D12_STATIC_SAMPLER_DESC staticSamplers[3] = {};
426 staticSamplers[0].Filter = D3D12_FILTER_ANISOTROPIC;
427 staticSamplers[0].AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
428 staticSamplers[0].AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
429 staticSamplers[0].AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
430 staticSamplers[0].MipLODBias = 0.0f;
431 staticSamplers[0].MaxAnisotropy = 16;
432 staticSamplers[0].ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
433 staticSamplers[0].BorderColor =
434 D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
435 staticSamplers[0].MinLOD = 0.0f;
436 staticSamplers[0].MaxLOD = D3D12_FLOAT32_MAX;
437 staticSamplers[0].ShaderRegister = 0;
438 staticSamplers[0].RegisterSpace = 0;
439 staticSamplers[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
442 staticSamplers[1].Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
443 staticSamplers[1].AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
444 staticSamplers[1].AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
445 staticSamplers[1].AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
446 staticSamplers[1].MipLODBias = 0.0f;
447 staticSamplers[1].MaxAnisotropy = 1;
448 staticSamplers[1].ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
449 staticSamplers[1].BorderColor =
450 D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK;
451 staticSamplers[1].MinLOD = 0.0f;
452 staticSamplers[1].MaxLOD = D3D12_FLOAT32_MAX;
453 staticSamplers[1].ShaderRegister = 1;
454 staticSamplers[1].RegisterSpace = 0;
455 staticSamplers[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
458 staticSamplers[2].Filter = D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
459 staticSamplers[2].AddressU = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
460 staticSamplers[2].AddressV = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
461 staticSamplers[2].AddressW = D3D12_TEXTURE_ADDRESS_MODE_BORDER;
462 staticSamplers[2].MipLODBias = 0.0f;
463 staticSamplers[2].MaxAnisotropy = 1;
464 staticSamplers[2].ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
465 staticSamplers[2].BorderColor = D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE;
466 staticSamplers[2].MinLOD = 0.0f;
467 staticSamplers[2].MaxLOD = 0.0f;
468 staticSamplers[2].ShaderRegister = 3;
469 staticSamplers[2].RegisterSpace = 0;
470 staticSamplers[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
472 D3D12_ROOT_SIGNATURE_DESC rootSigDesc = {};
473 rootSigDesc.NumParameters = 5;
474 rootSigDesc.pParameters = rootParams;
475 rootSigDesc.NumStaticSamplers = 3;
476 rootSigDesc.pStaticSamplers = staticSamplers;
478 D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
480 Microsoft::WRL::ComPtr<ID3DBlob> serializedRootSig;
481 Microsoft::WRL::ComPtr<ID3DBlob> errorBlob;
483 HRESULT hr = D3D12SerializeRootSignature(
484 &rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
485 &serializedRootSig, &errorBlob);
489 SLEAK_ERROR(
"Root signature serialization error: {}",
490 (
char*)errorBlob->GetBufferPointer());
495 hr = device->CreateRootSignature(
496 0, serializedRootSig->GetBufferPointer(),
497 serializedRootSig->GetBufferSize(),
498 IID_PPV_ARGS(&rootSignature));
508ID3D12PipelineState* DirectX12Renderer::GetPipeline(
const PipelineKey& key,
511 for (
auto& [cachedKey, pso] : m_pipelineCache) {
512 if (cachedKey == key)
return pso.Get();
514 if (!vs || key.vertexFormat != 0)
return nullptr;
516 D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
517 psoDesc.InputLayout = {kVertexInputLayout, _countof(kVertexInputLayout)};
518 psoDesc.pRootSignature = rootSignature.Get();
519 psoDesc.VS = {vs->GetBufferPointer(), vs->GetBufferSize()};
520 if (ps) psoDesc.PS = {ps->GetBufferPointer(), ps->GetBufferSize()};
522 D3D12_RASTERIZER_DESC rasterDesc = {};
523 rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
524 rasterDesc.CullMode = key.cullMode;
525 rasterDesc.FrontCounterClockwise = FALSE;
526 rasterDesc.DepthBias = key.depthBias;
527 rasterDesc.DepthBiasClamp = key.depthBiasClamp;
528 rasterDesc.SlopeScaledDepthBias = key.slopeScaledDepthBias;
529 rasterDesc.DepthClipEnable = key.depthClip;
530 rasterDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
531 psoDesc.RasterizerState = rasterDesc;
533 const bool hasColor = key.rtvFormat != DXGI_FORMAT_UNKNOWN;
534 D3D12_RENDER_TARGET_BLEND_DESC rtBlend = {};
535 rtBlend.BlendEnable = key.blendEnable;
537 key.blendEnable ? D3D12_BLEND_SRC_ALPHA : D3D12_BLEND_ONE;
539 key.blendEnable ? D3D12_BLEND_INV_SRC_ALPHA : D3D12_BLEND_ZERO;
540 rtBlend.BlendOp = D3D12_BLEND_OP_ADD;
541 rtBlend.SrcBlendAlpha = D3D12_BLEND_ONE;
542 rtBlend.DestBlendAlpha =
543 key.blendEnable ? D3D12_BLEND_INV_SRC_ALPHA : D3D12_BLEND_ZERO;
544 rtBlend.BlendOpAlpha = D3D12_BLEND_OP_ADD;
545 rtBlend.LogicOp = D3D12_LOGIC_OP_NOOP;
546 rtBlend.RenderTargetWriteMask = hasColor ? D3D12_COLOR_WRITE_ENABLE_ALL : 0;
547 for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
548 psoDesc.BlendState.RenderTarget[i] = rtBlend;
550 psoDesc.DepthStencilState.DepthEnable = TRUE;
551 psoDesc.DepthStencilState.DepthWriteMask = key.depthWrite;
552 psoDesc.DepthStencilState.DepthFunc = key.depthFunc;
553 psoDesc.DepthStencilState.StencilEnable = FALSE;
555 psoDesc.SampleMask = UINT_MAX;
556 psoDesc.PrimitiveTopologyType = key.topology;
557 psoDesc.NumRenderTargets = hasColor ? 1 : 0;
558 psoDesc.RTVFormats[0] = key.rtvFormat;
559 psoDesc.DSVFormat = key.dsvFormat;
560 psoDesc.SampleDesc.Count = 1;
562 Microsoft::WRL::ComPtr<ID3D12PipelineState> pso;
564 device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pso));
566 SLEAK_ERROR(
"Failed to create pipeline state! HRESULT: 0x{:08X}",
567 static_cast<unsigned int>(hr));
571 m_pipelineCache.emplace_back(key, pso);
575bool DirectX12Renderer::CreateShadowPassPSO() {
576 if (m_shadowPassPSO)
return true;
578 if (!m_shadowVSCompiled) {
579 m_shadowVSCompiled =
true;
580 m_shadowVSBlob = CompileStage(
581 L
"assets/shaders/default_shader_dx12.hlsl",
"VS_Main",
"vs_5_0");
583 ID3DBlob* vs = m_shadowVSBlob ? m_shadowVSBlob.Get() : m_cachedVSBlob.Get();
585 SLEAK_WARN(
"CreateShadowPassPSO: no vertex shader available yet");
590 key.vsHash = HashBytecode(vs);
591 key.cullMode = D3D12_CULL_MODE_NONE;
592 key.depthBias = 1000;
593 key.depthBiasClamp = 0.01f;
594 key.slopeScaledDepthBias = 2.0f;
595 key.rtvFormat = DXGI_FORMAT_UNKNOWN;
597 m_shadowPassPSO = GetPipeline(key, vs,
nullptr);
598 if (!m_shadowPassPSO)
return false;
603void DirectX12Renderer::BeginRender() {
604 frameIndex = swapChain->GetCurrentBackBufferIndex();
607 if (m_hasPendingLightVP) {
608 memcpy(m_lightVP, m_pendingLightVP,
sizeof(m_lightVP));
613 const UINT64 slotFence = fenceValues[frameIndex];
614 if (fence->GetCompletedValue() < slotFence) {
615 fence->SetEventOnCompletion(slotFence, fenceEvent);
616 WaitForSingleObject(fenceEvent, INFINITE);
619 DirectX12Buffer::ProcessDeferredCleanup(fence->GetCompletedValue());
622 m_uploadRing.BeginFrame(frameIndex);
624 m_frameActive =
true;
625 m_shaderPipeline =
nullptr;
626 m_passPipeline =
nullptr;
629 commandAllocators[frameIndex]->Reset();
630 commandList->Reset(commandAllocators[frameIndex].Get(),
631 m_defaultPipelineState);
633 if (!m_defaultPipelineState) {
634 SLEAK_WARN(
"BeginRender: no pipeline state yet, nothing will draw");
638 commandList->SetGraphicsRootSignature(rootSignature.Get());
641 ID3D12DescriptorHeap* srvHeaps[] = {m_sharedSrvHeap.Get()};
642 commandList->SetDescriptorHeaps(1, srvHeaps);
644 commandList->RSSetViewports(1, &viewport);
645 commandList->RSSetScissorRects(1, &scissorRect);
648 D3D12_RESOURCE_BARRIER barrier = {};
649 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
650 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
651 barrier.Transition.pResource = renderTargets[frameIndex].Get();
652 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
653 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
654 barrier.Transition.Subresource =
655 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
656 commandList->ResourceBarrier(1, &barrier);
659 const float clearColor[] = {0.39f, 0.58f, 0.93f, 1.0f};
660 D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle =
661 rtvHeap->GetCPUDescriptorHandleForHeapStart();
662 rtvHandle.ptr += frameIndex * rtvDescriptorSize;
664 D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle =
665 dsvHeap->GetCPUDescriptorHandleForHeapStart();
667 commandList->ClearRenderTargetView(rtvHandle, clearColor, 0,
nullptr);
668 commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH,
669 1.0f, 0, 0,
nullptr);
672 if (m_shadowPassEnabled) {
674 if (m_defaultPipelineState)
675 commandList->SetPipelineState(m_defaultPipelineState);
679 commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
681 commandList->RSSetViewports(1, &viewport);
682 commandList->RSSetScissorRects(1, &scissorRect);
685 commandList->IASetPrimitiveTopology(
686 D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
690 commandList->SetGraphicsRootSignature(rootSignature.Get());
692 ID3D12DescriptorHeap* heaps[] = {m_sharedSrvHeap.Get()};
693 commandList->SetDescriptorHeaps(1, heaps);
697 if (m_defaultTexture) {
698 m_defaultTexture->Bind(0);
702 BindLightConstants();
705 if (m_shadowMapCreated) {
706 commandList->SetGraphicsRootDescriptorTable(
707 4, GetSharedSrvGPUHandle(m_shadowSrvIndex));
710 bImFrameActive =
false;
711 if (bImInitialized) {
712 ImGui_ImplDX12_NewFrame();
713 ImGui_ImplSDL3_NewFrame();
715 auto& io = ImGui::GetIO();
716 if (io.DisplaySize.x > 0.0f && io.DisplaySize.y > 0.0f) {
718 bImFrameActive =
true;
723void DirectX12Renderer::EndRender() {
724 if (bImFrameActive) {
727 ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(),
732 D3D12_RESOURCE_BARRIER barrier = {};
733 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
734 barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
735 barrier.Transition.pResource = renderTargets[frameIndex].Get();
736 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
737 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
738 barrier.Transition.Subresource =
739 D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
740 commandList->ResourceBarrier(1, &barrier);
743 commandList->Close();
745 ID3D12CommandList* ppCommandLists[] = {commandList.Get()};
746 commandQueue->ExecuteCommandLists(_countof(ppCommandLists),
749 swapChain->Present(m_vsync ? 1 : 0, 0);
753 fenceValues[frameIndex] = ++m_fenceValue;
754 commandQueue->Signal(fence.Get(), m_fenceValue);
755 DirectX12Buffer::TagDeferredCleanup(m_fenceValue);
756 m_frameActive =
false;
758 UpdateFrameMetrics();
761void DirectX12Renderer::WaitForGPU() {
762 if (!commandQueue || !fence || !fenceEvent)
return;
765 const UINT64 waitValue = ++m_fenceValue;
766 commandQueue->Signal(fence.Get(), waitValue);
768 if (fence->GetCompletedValue() < waitValue) {
769 fence->SetEventOnCompletion(waitValue, fenceEvent);
770 WaitForSingleObject(fenceEvent, INFINITE);
775bool DirectX12Renderer::CreateSharedSrvHeap() {
776 D3D12_DESCRIPTOR_HEAP_DESC heapDesc{};
777 heapDesc.NumDescriptors = MAX_SRV_DESCRIPTORS;
778 heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
779 heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
781 HRESULT hr = device->CreateDescriptorHeap(
782 &heapDesc, IID_PPV_ARGS(&m_sharedSrvHeap));
784 SLEAK_ERROR(
"Failed to create shared SRV descriptor heap!");
787 m_srvDescriptorSize = device->GetDescriptorHandleIncrementSize(
788 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
793UINT DirectX12Renderer::AllocateSRVSlot() {
794 if (m_nextSrvSlot >= MAX_SRV_DESCRIPTORS) {
795 SLEAK_ERROR(
"Shared SRV heap full! Increase MAX_SRV_DESCRIPTORS.");
798 return m_nextSrvSlot++;
801D3D12_CPU_DESCRIPTOR_HANDLE DirectX12Renderer::GetSharedSrvCPUHandle(UINT slot)
const {
802 D3D12_CPU_DESCRIPTOR_HANDLE handle = m_sharedSrvHeap->GetCPUDescriptorHandleForHeapStart();
803 handle.ptr +=
static_cast<SIZE_T
>(slot) * m_srvDescriptorSize;
807D3D12_GPU_DESCRIPTOR_HANDLE DirectX12Renderer::GetSharedSrvGPUHandle(UINT slot)
const {
808 D3D12_GPU_DESCRIPTOR_HANDLE handle = m_sharedSrvHeap->GetGPUDescriptorHandleForHeapStart();
809 handle.ptr +=
static_cast<UINT64
>(slot) * m_srvDescriptorSize;
813void DirectX12Renderer::Cleanup() {
814 if (!m_Initialized)
return;
817 DirectX12Buffer::TagDeferredCleanup(m_fenceValue);
818 DirectX12Buffer::ProcessDeferredCleanup(UINT64_MAX);
820 if (bImInitialized) {
821 ImGui_ImplDX12_Shutdown();
822 ImGui_ImplSDL3_Shutdown();
823 ImGui::DestroyContext();
824 bImInitialized =
false;
826 m_uploader.Release();
827 m_uploadRing.Release();
829 imguiSrvHeap.Reset();
830 m_sharedSrvHeap.Reset();
832 m_skyboxPipelineState =
nullptr;
833 m_debugLinePipelineState =
nullptr;
834 m_shadowPassPSO =
nullptr;
835 m_defaultPipelineState =
nullptr;
836 m_shaderPipeline =
nullptr;
837 m_passPipeline =
nullptr;
838 m_pipelineCache.clear();
839 rootSignature.Reset();
840 depthStencilBuffer.Reset();
842 for (
auto& rt : renderTargets) {
848 for (UINT i = 0; i < FrameCount; i++)
849 commandAllocators[i].Reset();
850 commandQueue.Reset();
854 m_Initialized =
false;
857void DirectX12Renderer::Resize(uint32_t
width, uint32_t
height) {
858 if (!m_Initialized || !swapChain)
return;
863 for (
auto& rt : renderTargets) {
866 depthStencilBuffer.Reset();
871 HRESULT hr = swapChain->ResizeBuffers(FrameCount,
width,
height,
872 DXGI_FORMAT_R8G8B8A8_UNORM, 0);
874 SLEAK_ERROR(
"Failed to resize swap chain buffers!");
878 frameIndex = swapChain->GetCurrentBackBufferIndex();
881 if (!CreateRenderTargetViews() || !CreateDepthStencilView()) {
882 SLEAK_ERROR(
"Failed to recreate views after resize!");
887 viewport.Width =
static_cast<float>(
width);
888 viewport.Height =
static_cast<float>(
height);
889 scissorRect.right =
width;
890 scissorRect.bottom =
height;
895void DirectX12Renderer::Draw(uint32_t vertexCount) {
Draw(vertexCount, 0); }
897void DirectX12Renderer::Draw(uint32_t vertexCount, uint32_t firstVertex) {
898 commandList->DrawInstanced(vertexCount, 1, firstVertex, 0);
899 DrawnVertices += vertexCount;
900 DrawnTriangles += vertexCount / 3;
903void DirectX12Renderer::DrawIndexed(uint32_t indexCount) {
907void DirectX12Renderer::DrawIndexed(uint32_t indexCount, uint32_t firstIndex,
908 int32_t baseVertex) {
909 commandList->DrawIndexedInstanced(indexCount, 1, firstIndex, baseVertex, 0);
910 DrawnVertices += indexCount;
911 DrawnTriangles += indexCount / 3;
914void DirectX12Renderer::DrawInstance(uint32_t instanceCount,
915 uint32_t vertexPerInstance) {
916 commandList->DrawInstanced(vertexPerInstance, instanceCount, 0, 0);
917 DrawnVertices += vertexPerInstance * instanceCount;
918 DrawnTriangles += (vertexPerInstance / 3) * instanceCount;
921void DirectX12Renderer::DrawIndexedInstance(uint32_t instanceCount,
922 uint32_t indexPerInstance) {
923 DrawIndexedInstance(instanceCount, indexPerInstance, 0, 0);
926void DirectX12Renderer::DrawIndexedInstance(uint32_t instanceCount,
927 uint32_t indexPerInstance,
929 int32_t baseVertex) {
930 commandList->DrawIndexedInstanced(indexPerInstance, instanceCount,
931 firstIndex, baseVertex, 0);
932 DrawnVertices += indexPerInstance * instanceCount;
933 DrawnTriangles += (indexPerInstance / 3) * instanceCount;
936void DirectX12Renderer::SetRenderFace(RenderFace face) {
938 ConfigureRenderFace();
941void DirectX12Renderer::SetRenderMode(RenderMode mode) {
943 ConfigureRenderMode();
946void DirectX12Renderer::SetViewport(
float x,
float y,
float width,
947 float height,
float minDepth,
949 viewport.TopLeftX = x;
950 viewport.TopLeftY = y;
951 viewport.Width =
width;
953 viewport.MinDepth = minDepth;
954 viewport.MaxDepth = maxDepth;
956 scissorRect.left =
static_cast<LONG
>(x);
957 scissorRect.top =
static_cast<LONG
>(y);
958 scissorRect.right =
static_cast<LONG
>(x +
width);
959 scissorRect.bottom =
static_cast<LONG
>(y +
height);
962 commandList->RSSetViewports(1, &viewport);
963 commandList->RSSetScissorRects(1, &scissorRect);
967void DirectX12Renderer::ClearRenderTarget(
float r,
float g,
float b,
969 const float clearColor[] = {r, g, b, a};
970 D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle =
971 rtvHeap->GetCPUDescriptorHandleForHeapStart();
972 rtvHandle.ptr += frameIndex * rtvDescriptorSize;
973 commandList->ClearRenderTargetView(rtvHandle, clearColor, 0,
nullptr);
976void DirectX12Renderer::ClearDepthStencil(
bool clearDepth,
977 bool clearStencil,
float depth,
979 D3D12_CLEAR_FLAGS flags = {};
981 flags =
static_cast<D3D12_CLEAR_FLAGS
>(
982 flags | D3D12_CLEAR_FLAG_DEPTH);
984 flags =
static_cast<D3D12_CLEAR_FLAGS
>(
985 flags | D3D12_CLEAR_FLAG_STENCIL);
987 if (flags && dsvHeap) {
988 D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle =
989 dsvHeap->GetCPUDescriptorHandleForHeapStart();
990 commandList->ClearDepthStencilView(dsvHandle, flags, depth,
991 stencil, 0,
nullptr);
995void DirectX12Renderer::BindVertexBuffer(RefPtr<BufferBase> buffer,
997 auto* dx12Buf =
static_cast<DirectX12Buffer*
>(buffer.get());
998 if (!dx12Buf)
return;
1000 D3D12_VERTEX_BUFFER_VIEW vbView = {};
1001 vbView.BufferLocation =
1002 dx12Buf->GetD3DBuffer()->GetGPUVirtualAddress();
1004 vbView.SizeInBytes =
static_cast<UINT
>(dx12Buf->GetSize());
1006 commandList->IASetVertexBuffers(slot, 1, &vbView);
1009void DirectX12Renderer::BindIndexBuffer(RefPtr<BufferBase> buffer,
1011 auto* dx12Buf =
static_cast<DirectX12Buffer*
>(buffer.get());
1012 if (!dx12Buf)
return;
1014 D3D12_INDEX_BUFFER_VIEW ibView = {};
1015 ibView.BufferLocation =
1016 dx12Buf->GetD3DBuffer()->GetGPUVirtualAddress();
1017 ibView.Format = DXGI_FORMAT_R32_UINT;
1018 ibView.SizeInBytes =
static_cast<UINT
>(dx12Buf->GetSize());
1020 commandList->IASetIndexBuffer(&ibView);
1023void DirectX12Renderer::BindConstantBuffer(RefPtr<BufferBase> buffer,
1025 auto* dx12Buf =
static_cast<DirectX12Buffer*
>(buffer.get());
1026 if (!dx12Buf)
return;
1029 if (m_inShadowPass && slot == 0 && dx12Buf->GetCPUShadowCopySize() >= 128) {
1030 const float* srcWorld =
reinterpret_cast<const float*
>(
1031 static_cast<const char*
>(dx12Buf->GetCPUShadowCopy()) + 64);
1034 for (
int r = 0; r < 4; ++r) {
1035 for (
int c = 0; c < 4; ++c) {
1037 for (
int k = 0; k < 4; ++k) {
1038 sum += srcWorld[r * 4 + k] * m_lightVP[k * 4 + c];
1040 shadowPC[r * 4 + c] = sum;
1043 memcpy(&shadowPC[16], srcWorld,
sizeof(
float) * 16);
1045 DirectX12UploadRing::Allocation alloc;
1046 if (!m_uploadRing.Allocate(
sizeof(shadowPC), alloc))
return;
1047 memcpy(alloc.cpu, shadowPC,
sizeof(shadowPC));
1048 commandList->SetGraphicsRootConstantBufferView(slot, alloc.gpu);
1054 if (
const void* data = dx12Buf->GetConstantData()) {
1055 D3D12_GPU_VIRTUAL_ADDRESS address =
1056 dx12Buf->GetFrameAddress(m_frameSerial);
1058 const size_t size = dx12Buf->GetConstantDataSize();
1059 DirectX12UploadRing::Allocation alloc;
1060 if (m_uploadRing.Allocate(size, alloc)) {
1061 memcpy(alloc.cpu, data, size);
1062 address = alloc.gpu;
1063 dx12Buf->SetFrameAddress(m_frameSerial, address);
1067 commandList->SetGraphicsRootConstantBufferView(slot, address);
1072 if (!dx12Buf->GetD3DBuffer())
return;
1073 commandList->SetGraphicsRootConstantBufferView(
1074 slot, dx12Buf->GetD3DBuffer()->GetGPUVirtualAddress());
1077BufferBase* DirectX12Renderer::CreateBuffer(BufferType Type, uint32_t size,
1080 auto* buffer =
new DirectX12Buffer(device.Get(), commandQueue.Get(), size,
1082 if (!buffer->Initialize(data)) {
1089Shader* DirectX12Renderer::CreateShader(
const std::string& shaderSource) {
1090 auto* shader =
new DirectX12Shader(device.Get());
1091 if (!shader->compile(shaderSource)) {
1096 ID3DBlob* vs = shader->getVertexShaderBlob();
1097 ID3DBlob* ps = shader->getPixelShaderBlob();
1099 key.vsHash = HashBytecode(vs);
1100 key.psHash = HashBytecode(ps);
1101 if (ID3D12PipelineState* pso = GetPipeline(key, vs, ps)) {
1102 shader->SetPipelineState(
1103 Microsoft::WRL::ComPtr<ID3D12PipelineState>(pso));
1104 if (!m_defaultPipelineState) {
1105 m_defaultPipelineState = pso;
1106 m_cachedVSBlob = vs;
1109 shader->SetCommandList(commandList.Get());
1110 shader->SetRenderer(
this);
1114Texture* DirectX12Renderer::CreateTexture(
1115 const std::string& TexturePath) {
1116 auto* texture =
new DirectX12Texture(device.Get(), commandQueue.Get(),
1117 commandList.Get(), &m_uploader);
1118 if (!texture->LoadFromFile(TexturePath)) {
1123 UINT slot = AllocateSRVSlot();
1124 texture->CreateSRVIntoHandle(
1125 texture->GetFormat() == TextureFormat::RGBA8 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM,
1126 GetSharedSrvCPUHandle(slot));
1127 texture->SetSharedSrvGPUHandle(GetSharedSrvGPUHandle(slot));
1131Texture* DirectX12Renderer::CreateTextureFromData(uint32_t
width,
1134 auto* texture =
new DirectX12Texture(device.Get(), commandQueue.Get(),
1135 commandList.Get(), &m_uploader);
1137 TextureFormat::RGBA8)) {
1142 UINT slot = AllocateSRVSlot();
1143 texture->CreateSRVIntoHandle(DXGI_FORMAT_R8G8B8A8_UNORM,
1144 GetSharedSrvCPUHandle(slot));
1145 texture->SetSharedSrvGPUHandle(GetSharedSrvGPUHandle(slot));
1149Texture* DirectX12Renderer::CreateCubemapTexture(
1150 const std::array<std::string, 6>& facePaths) {
1151 auto* texture =
new DirectX12CubemapTexture(
1152 device.Get(), commandQueue.Get(), &m_uploader);
1153 if (!texture->LoadCubemap(facePaths)) {
1157 UINT slot = AllocateSRVSlot();
1158 texture->CreateSRVIntoHandle(GetSharedSrvCPUHandle(slot));
1159 texture->SetSharedSrvGPUHandle(GetSharedSrvGPUHandle(slot));
1163Texture* DirectX12Renderer::CreateCubemapTextureFromPanorama(
1164 const std::string& panoramaPath) {
1165 auto* texture =
new DirectX12CubemapTexture(
1166 device.Get(), commandQueue.Get(), &m_uploader);
1167 if (!texture->LoadEquirectangular(panoramaPath)) {
1171 UINT slot = AllocateSRVSlot();
1172 texture->CreateSRVIntoHandle(GetSharedSrvCPUHandle(slot));
1173 texture->SetSharedSrvGPUHandle(GetSharedSrvGPUHandle(slot));
1177void DirectX12Renderer::BindTexture(RefPtr<Sleak::Texture> texture,
1179 if (!texture.IsValid() || !commandList)
return;
1181 if (texture->GetType() == TextureType::TextureCube) {
1182 static_cast<DirectX12CubemapTexture*
>(texture.get())
1183 ->BindToCommandList(commandList.Get(), 2);
1185 static_cast<DirectX12Texture*
>(texture.get())
1186 ->BindToCommandList(commandList.Get(), 2);
1190void DirectX12Renderer::BindTextureRaw(
Sleak::Texture* texture, uint32_t slot) {
1191 if (!texture || !commandList)
return;
1193 if (texture->
GetType() == TextureType::TextureCube) {
1194 static_cast<DirectX12CubemapTexture*
>(texture)
1195 ->BindToCommandList(commandList.Get(), 2);
1199 auto* dx12Tex =
static_cast<DirectX12Texture*
>(texture);
1201 dx12Tex->BindToCommandList(commandList.Get(), 2);
1205void DirectX12Renderer::BindLightConstants() {
1206 DirectX12UploadRing::Allocation alloc;
1207 if (!m_uploadRing.Allocate(m_lightData.size(), alloc))
return;
1208 memcpy(alloc.cpu, m_lightData.data(), m_lightData.size());
1209 commandList->SetGraphicsRootConstantBufferView(3, alloc.gpu);
1212void DirectX12Renderer::UpdateShadowLightUBO(
const void* data, uint32_t size) {
1215 size_t copySize = size;
1216 if (copySize > m_lightData.size()) copySize = m_lightData.size();
1217 memcpy(m_lightData.data(), data, copySize);
1220 if (m_frameActive) BindLightConstants();
1223void DirectX12Renderer::SetLightVP(
const float* mat) {
1225 memcpy(m_pendingLightVP, mat,
sizeof(m_pendingLightVP));
1226 m_hasPendingLightVP =
true;
1230bool DirectX12Renderer::CreateShadowMapResources() {
1231 if (m_shadowMapCreated)
return true;
1234 D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
1235 dsvHeapDesc.NumDescriptors = 1;
1236 dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
1237 dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
1238 if (FAILED(device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&m_shadowDsvHeap)))) {
1242 m_shadowDsvHandle = m_shadowDsvHeap->GetCPUDescriptorHandleForHeapStart();
1245 D3D12_RESOURCE_DESC depthDesc = {};
1246 depthDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
1247 depthDesc.Width = m_shadowMapResolution;
1248 depthDesc.Height = m_shadowMapResolution;
1249 depthDesc.DepthOrArraySize = 1;
1250 depthDesc.MipLevels = 1;
1251 depthDesc.Format = DXGI_FORMAT_R32_TYPELESS;
1252 depthDesc.SampleDesc.Count = 1;
1253 depthDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
1255 D3D12_CLEAR_VALUE clearValue = {};
1256 clearValue.Format = DXGI_FORMAT_D32_FLOAT;
1257 clearValue.DepthStencil.Depth = 1.0f;
1259 D3D12_HEAP_PROPERTIES heapProps = {};
1260 heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
1262 if (FAILED(device->CreateCommittedResource(
1263 &heapProps, D3D12_HEAP_FLAG_NONE, &depthDesc,
1264 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, &clearValue,
1265 IID_PPV_ARGS(&m_shadowDepthBuffer)))) {
1266 SLEAK_ERROR(
"Failed to create shadow depth buffer!");
1271 D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
1272 dsvDesc.Format = DXGI_FORMAT_D32_FLOAT;
1273 dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
1274 device->CreateDepthStencilView(m_shadowDepthBuffer.Get(), &dsvDesc, m_shadowDsvHandle);
1277 m_shadowSrvIndex = AllocateSRVSlot();
1278 D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
1279 srvDesc.Format = DXGI_FORMAT_R32_FLOAT;
1280 srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
1281 srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
1282 srvDesc.Texture2D.MipLevels = 1;
1283 device->CreateShaderResourceView(m_shadowDepthBuffer.Get(), &srvDesc,
1284 GetSharedSrvCPUHandle(m_shadowSrvIndex));
1286 m_shadowMapCreated =
true;
1287 m_shadowResourcesCreated =
true;
1288 SLEAK_INFO(
"D3D12 shadow map resources created ({}x{})", m_shadowMapResolution, m_shadowMapResolution);
1292void DirectX12Renderer::RenderShadowPass() {
1294 auto* queue = RenderCommandQueue::GetInstance();
1295 if (!queue || !queue->HasCachedShadowDraws())
return;
1297 if (!m_shadowMapCreated) {
1298 if (!CreateShadowMapResources())
return;
1300 if (!CreateShadowPassPSO())
return;
1303 D3D12_RESOURCE_BARRIER barrier = {};
1304 barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
1305 barrier.Transition.pResource = m_shadowDepthBuffer.Get();
1306 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1307 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_DEPTH_WRITE;
1308 barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
1309 commandList->ResourceBarrier(1, &barrier);
1312 commandList->OMSetRenderTargets(0,
nullptr, FALSE, &m_shadowDsvHandle);
1313 commandList->ClearDepthStencilView(m_shadowDsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0,
nullptr);
1316 D3D12_VIEWPORT shadowViewport = {};
1317 shadowViewport.Width =
static_cast<float>(m_shadowMapResolution);
1318 shadowViewport.Height =
static_cast<float>(m_shadowMapResolution);
1319 shadowViewport.MinDepth = 0.0f;
1320 shadowViewport.MaxDepth = 1.0f;
1321 commandList->RSSetViewports(1, &shadowViewport);
1323 D3D12_RECT shadowScissor = {};
1324 shadowScissor.right = m_shadowMapResolution;
1325 shadowScissor.bottom = m_shadowMapResolution;
1326 commandList->RSSetScissorRects(1, &shadowScissor);
1329 commandList->SetPipelineState(m_shadowPassPSO);
1330 commandList->SetGraphicsRootSignature(rootSignature.Get());
1331 commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1334 ID3D12DescriptorHeap* srvHeaps[] = {m_sharedSrvHeap.Get()};
1335 commandList->SetDescriptorHeaps(1, srvHeaps);
1338 if (m_defaultTexture) {
1339 m_defaultTexture->Bind(0);
1341 BindLightConstants();
1344 m_inShadowPass =
true;
1346 queue->ExecuteShadowPass(
this);
1348 m_inShadowPass =
false;
1351 barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_DEPTH_WRITE;
1352 barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
1353 commandList->ResourceBarrier(1, &barrier);
1356bool DirectX12Renderer::CreateSkyboxPipelineState() {
1357 if (m_skyboxPipelineState)
return true;
1358 if (m_skyboxPipelineFailed)
return false;
1359 m_skyboxPipelineFailed =
true;
1362 CompileStage(L
"assets/shaders/skybox_dx12.hlsl",
"VS_Main",
"vs_5_0");
1364 CompileStage(L
"assets/shaders/skybox_dx12.hlsl",
"PS_Main",
"ps_5_0");
1365 if (!vs || !ps)
return false;
1370 key.vsHash = HashBytecode(vs.Get());
1371 key.psHash = HashBytecode(ps.Get());
1372 key.cullMode = D3D12_CULL_MODE_NONE;
1373 key.depthClip = FALSE;
1374 key.depthWrite = D3D12_DEPTH_WRITE_MASK_ZERO;
1375 key.depthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
1377 m_skyboxPipelineState = GetPipeline(key, vs.Get(), ps.Get());
1378 if (!m_skyboxPipelineState)
return false;
1380 m_skyboxPipelineFailed =
false;
1381 SLEAK_INFO(
"DirectX 12 skybox pipeline state created successfully");
1385void DirectX12Renderer::BindShaderPipeline(ID3D12PipelineState* pso) {
1386 if (!pso || !commandList)
return;
1387 m_shaderPipeline = pso;
1388 if (m_passPipeline)
return;
1389 commandList->SetPipelineState(pso);
1392void DirectX12Renderer::RestoreShaderPipeline() {
1393 ID3D12PipelineState* pso =
1394 m_shaderPipeline ? m_shaderPipeline : m_defaultPipelineState;
1395 if (pso) commandList->SetPipelineState(pso);
1398void DirectX12Renderer::BeginSkyboxPass() {
1399 if (!CreateSkyboxPipelineState()) {
1400 SLEAK_WARN(
"BeginSkyboxPass: failed to create skybox PSO");
1403 m_passPipeline = m_skyboxPipelineState;
1404 commandList->SetPipelineState(m_skyboxPipelineState);
1407void DirectX12Renderer::EndSkyboxPass() {
1408 m_passPipeline =
nullptr;
1409 RestoreShaderPipeline();
1412bool DirectX12Renderer::CreateDebugLinePipelineState() {
1413 if (m_debugLinePipelineState)
return true;
1414 if (m_debugLinePipelineFailed)
return false;
1415 m_debugLinePipelineFailed =
true;
1417 auto vs = CompileStage(L
"assets/shaders/debug_line_dx12.hlsl",
"VS_Main",
1419 auto ps = CompileStage(L
"assets/shaders/debug_line_dx12.hlsl",
"PS_Main",
1421 if (!vs || !ps)
return false;
1424 key.vsHash = HashBytecode(vs.Get());
1425 key.psHash = HashBytecode(ps.Get());
1426 key.cullMode = D3D12_CULL_MODE_NONE;
1427 key.depthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
1428 key.topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
1430 m_debugLinePipelineState = GetPipeline(key, vs.Get(), ps.Get());
1431 if (!m_debugLinePipelineState)
return false;
1433 m_debugLinePipelineFailed =
false;
1434 SLEAK_INFO(
"DirectX 12 debug line pipeline state created successfully");
1438void DirectX12Renderer::BeginDebugLinePass() {
1439 if (!CreateDebugLinePipelineState()) {
1440 SLEAK_WARN(
"BeginDebugLinePass: failed to create debug line PSO");
1443 m_passPipeline = m_debugLinePipelineState;
1444 commandList->SetPipelineState(m_debugLinePipelineState);
1445 commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST);
1448void DirectX12Renderer::EndDebugLinePass() {
1449 m_passPipeline =
nullptr;
1450 RestoreShaderPipeline();
1451 commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
1454void DirectX12Renderer::ConfigureRenderMode() {
1460void DirectX12Renderer::ConfigureRenderFace() {
1465void DirectX12Renderer::EnumerateDevices(
1466 Microsoft::WRL::ComPtr<IDXGIFactory4> factory) {
1467 UINT adapter_index = 0;
1468 IDXGIAdapter1* tempadapter;
1469 while (factory->EnumAdapters1(adapter_index, &tempadapter) !=
1470 DXGI_ERROR_NOT_FOUND) {
1471 DXGI_ADAPTER_DESC1 desc;
1472 tempadapter->GetDesc1(&desc);
1475 std::wstring wgpu_name = L
"Found GPU: ";
1476 wgpu_name += desc.Description;
1477 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
1478 std::string gpu_name = converter.to_bytes(wgpu_name);
1482 if (adapter ==
nullptr &&
1483 (desc.VendorId == 0x10DE || desc.VendorId == 0x1002)) {
1484 adapter.Attach(tempadapter);
1486 tempadapter->Release();
1495bool DirectX12Renderer::IsSupport() {
1496 Microsoft::WRL::ComPtr<ID3D12Device> testDevice;
1497 HRESULT hr = D3D12CreateDevice(
nullptr, D3D_FEATURE_LEVEL_11_0,
1498 IID_PPV_ARGS(&testDevice));
1499 return SUCCEEDED(hr);
1502bool DirectX12Renderer::CreateImGUI() {
1503 if (!device || !commandQueue || !m_sharedSrvHeap)
1507 UINT imguiSlot = AllocateSRVSlot();
1508 D3D12_CPU_DESCRIPTOR_HANDLE imguiCpuHandle = GetSharedSrvCPUHandle(imguiSlot);
1509 D3D12_GPU_DESCRIPTOR_HANDLE imguiGpuHandle = GetSharedSrvGPUHandle(imguiSlot);
1511 IMGUI_CHECKVERSION();
1512 ImGui::CreateContext();
1513 ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
1514 ImGui::StyleColorsDark();
1516 if (!ImGui_ImplSDL3_InitForD3D(window->GetSDLWindow()))
1519 ImGui_ImplDX12_InitInfo imguiInit;
1520 imguiInit.Device = device.Get();
1521 imguiInit.CommandQueue = commandQueue.Get();
1522 imguiInit.NumFramesInFlight = FrameCount;
1523 imguiInit.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
1524 imguiInit.DSVFormat = DXGI_FORMAT_D32_FLOAT;
1525 imguiInit.SrvDescriptorHeap = m_sharedSrvHeap.Get();
1526 imguiInit.LegacySingleSrvCpuDescriptor = imguiCpuHandle;
1527 imguiInit.LegacySingleSrvGpuDescriptor = imguiGpuHandle;
1529 if (!ImGui_ImplDX12_Init(&imguiInit))
return false;
1531 bImInitialized =
true;
virtual TextureType GetType() const =0
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.