From ab158e8b3d2899da1317865176c142f71e00278d Mon Sep 17 00:00:00 2001 From: Patedam Date: Sat, 8 Aug 2026 23:06:29 -0400 Subject: [PATCH] Merged all d3d12 files into one file --- Juliet/include/Core/HAL/OS/OS.h | 1 - Juliet/src/Graphics/D3D12/D3D12Buffer.cpp | 357 -- Juliet/src/Graphics/D3D12/D3D12Buffer.h | 42 - .../src/Graphics/D3D12/D3D12CommandList.cpp | 558 -- Juliet/src/Graphics/D3D12/D3D12CommandList.h | 115 - Juliet/src/Graphics/D3D12/D3D12Common.cpp | 122 - Juliet/src/Graphics/D3D12/D3D12Common.h | 51 - .../Graphics/D3D12/D3D12DescriptorHeap.cpp | 166 - .../src/Graphics/D3D12/D3D12DescriptorHeap.h | 62 - .../Graphics/D3D12/D3D12GraphicsDevice.cpp | 5521 ++++++++++++++--- .../src/Graphics/D3D12/D3D12GraphicsDevice.h | 119 - .../Graphics/D3D12/D3D12GraphicsPipeline.cpp | 557 -- .../Graphics/D3D12/D3D12GraphicsPipeline.h | 65 - .../src/Graphics/D3D12/D3D12InternalTests.cpp | 13 - .../src/Graphics/D3D12/D3D12InternalTests.h | 8 - Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp | 294 - Juliet/src/Graphics/D3D12/D3D12RenderPass.h | 18 - Juliet/src/Graphics/D3D12/D3D12Shader.cpp | 48 - Juliet/src/Graphics/D3D12/D3D12Shader.h | 22 - Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp | 372 -- Juliet/src/Graphics/D3D12/D3D12SwapChain.h | 21 - .../Graphics/D3D12/D3D12Synchronization.cpp | 268 - .../src/Graphics/D3D12/D3D12Synchronization.h | 43 - Juliet/src/Graphics/D3D12/D3D12Texture.cpp | 579 -- Juliet/src/Graphics/D3D12/D3D12Texture.h | 97 - Juliet/src/Graphics/D3D12/D3D12Utils.cpp | 71 - Juliet/src/Graphics/D3D12/D3D12Utils.h | 22 - 27 files changed, 4555 insertions(+), 5057 deletions(-) delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Buffer.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Buffer.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12CommandList.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12CommandList.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Common.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Common.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12InternalTests.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12InternalTests.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12RenderPass.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Shader.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Shader.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12SwapChain.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Synchronization.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Texture.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Texture.h delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Utils.cpp delete mode 100644 Juliet/src/Graphics/D3D12/D3D12Utils.h diff --git a/Juliet/include/Core/HAL/OS/OS.h b/Juliet/include/Core/HAL/OS/OS.h index 87f162c..406ebdd 100644 --- a/Juliet/include/Core/HAL/OS/OS.h +++ b/Juliet/include/Core/HAL/OS/OS.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include namespace Juliet diff --git a/Juliet/src/Graphics/D3D12/D3D12Buffer.cpp b/Juliet/src/Graphics/D3D12/D3D12Buffer.cpp deleted file mode 100644 index 7d327eb..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Buffer.cpp +++ /dev/null @@ -1,357 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - // Linked List of free buffers - D3D12Buffer* FreeBuffers = nullptr; - - enum class D3D12BufferType : uint8 - { - Base, - TransferDownload, - TransferUpload, - }; - - [[nodiscard]] const char* D3D12BufferTypeToString(D3D12BufferType type) - { - switch (type) - { - case D3D12BufferType::Base: return "Base"; - case D3D12BufferType::TransferDownload: return "TransferDownload"; - case D3D12BufferType::TransferUpload: return "TransferUpload"; - } - return "Unknown"; - } - - [[nodiscard]] const char* BufferUsageToString(BufferUsage usage) - { - switch (usage) - { - case BufferUsage::None: return "None"; - case BufferUsage::ConstantBuffer: return "ConstantBuffer"; - case BufferUsage::StructuredBuffer: return "StructuredBuffer"; - case BufferUsage::IndexBuffer: return "IndexBuffer"; - } - return "Unknown"; - } - - void DestroyBuffer(D3D12Buffer* buffer) - { - if (!buffer) - { - return; - } - - if (buffer->Descriptor.Index != UINT32_MAX) - { - Internal::ReleaseDescriptor(buffer->Descriptor); - } - buffer->Descriptor = {}; - - if (buffer->Handle) - { - buffer->Handle->Release(); - buffer->Handle = nullptr; - } - buffer->CurrentState = D3D12_RESOURCE_STATE_COMMON; - buffer->Size = 0; - - buffer->Next = FreeBuffers; - FreeBuffers = buffer; - } - - D3D12Buffer* CreateBuffer(NonNullPtr d3d12Driver, size_t size, size_t stride, BufferUsage usage, - D3D12BufferType type, bool isDynamic) - { - D3D12Buffer* buffer = nullptr; - if (FreeBuffers) - { - buffer = FreeBuffers; - FreeBuffers = buffer->Next; - buffer->Next = nullptr; - } - - if (!buffer) - { - buffer = ArenaPushStruct(d3d12Driver->DriverArena JULIET_DEBUG_PARAM("D3D12Buffer")); - } - - if (!buffer) - { - return nullptr; - } - - if (type == D3D12BufferType::Base && usage == BufferUsage::None) - { - Assert(false, "Creating Base buffer with BufferUsage::None is invalid"); - DestroyBuffer(buffer); - return nullptr; - } - - // Align size for Constant Buffers - if (usage == BufferUsage::ConstantBuffer) - { - size = (size + 255U) & ~255U; - } - - D3D12_HEAP_PROPERTIES heapProperties = {}; - heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - - D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON; - D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; - - // Constant buffers or Dynamic buffers generally need to be uploaded every frame - const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer); - - if (type == D3D12BufferType::TransferDownload) - { - heapProperties.Type = D3D12_HEAP_TYPE_READBACK; - initialState = D3D12_RESOURCE_STATE_COPY_DEST; - } - else if (isUpload) - { - if (d3d12Driver->GPUUploadHeapSupported) - { - heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD; - initialState = D3D12_RESOURCE_STATE_COMMON; - } - else - { - heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; - initialState = D3D12_RESOURCE_STATE_GENERIC_READ; - } - } - else - { - // Must be a static buffer (Base type) - heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; - initialState = D3D12_RESOURCE_STATE_COMMON; - } - - D3D12_RESOURCE_DESC desc = {}; - desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - desc.Alignment = 0; - 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 = D3D12_RESOURCE_FLAG_NONE; - - Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s", - (void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage)); - - ID3D12Resource* handle = nullptr; - HRESULT result = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc, - initialState, nullptr, IID_ID3D12Resource, - reinterpret_cast(&handle)); - - if (FAILED(result)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast(result)); - Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d", - (unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type); - - HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason(); - if (FAILED(removeReason)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast(removeReason)); - } - - DestroyBuffer(buffer); - return nullptr; - } - - buffer->Handle = handle; - buffer->CurrentState = initialState; - buffer->Descriptor.Index = UINT32_MAX; - buffer->Size = size; - - if (usage == BufferUsage::ConstantBuffer || usage == BufferUsage::StructuredBuffer) - { - auto& heap = d3d12Driver->BindlessDescriptorHeap; - - Internal::D3D12Descriptor descriptor; - if (Internal::AssignDescriptor(heap, descriptor)) - { - buffer->Descriptor = descriptor; - - D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.CpuHandle; - - if (usage == BufferUsage::ConstantBuffer) - { - D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; - cbvDesc.BufferLocation = handle->GetGPUVirtualAddress(); - cbvDesc.SizeInBytes = static_cast(size); - d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle); - } - else if (usage == BufferUsage::StructuredBuffer) - { - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.Buffer.FirstElement = 0; - - if (stride > 0) - { - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.Buffer.NumElements = static_cast(size / stride); - srvDesc.Buffer.StructureByteStride = static_cast(stride); - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - } - else - { - srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; - srvDesc.Buffer.NumElements = static_cast(size / 4); - srvDesc.Buffer.StructureByteStride = 0; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; - } - - d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle); - Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index); - } - } - else - { - LogError(LogCategory::Graphics, "Bindless Heap Full or Invalid!"); - } - } - - return buffer; - } - } // namespace - - GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic) - { - auto d3d12Driver = static_cast(driver.Get()); - return reinterpret_cast(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic)); - } - - void DestroyGraphicsBuffer(NonNullPtr buffer) - { - DestroyBuffer(reinterpret_cast(buffer.Get())); - } - - GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr driver, size_t size, TransferBufferUsage usage) - { - auto d3d12Driver = static_cast(driver.Get()); - return reinterpret_cast( - CreateBuffer(d3d12Driver, size, 0, BufferUsage::None, - usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload, - false)); - } - - void DestroyGraphicsTransferBuffer(NonNullPtr buffer) - { - DestroyBuffer(reinterpret_cast(buffer.Get())); - } - - void* MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - void* ptr = nullptr; - - // 0-0 range means we don't intend to read anything. - D3D12_RANGE readRange = { 0, 0 }; - if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) - { - return nullptr; - } - return ptr; - } - - void UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - d3d12Buffer->Handle->Unmap(0, nullptr); - } - - void* MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - void* ptr = nullptr; - D3D12_RANGE readRange = { 0, 0 }; - if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) - { - return nullptr; - } - return ptr; - } - - void UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - d3d12Buffer->Handle->Unmap(0, nullptr); - } - - uint32 GetDescriptorIndex(NonNullPtr /*driver*/, NonNullPtr buffer) - { - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - return d3d12Buffer->Descriptor.Index; - } - - void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset) - { - auto d3d12CmdList = reinterpret_cast(commandList.Get()); - auto d3d12Dst = reinterpret_cast(dst.Get()); - auto d3d12Src = reinterpret_cast(src.Get()); - - // Transition DST to COPY_DEST if needed - if (d3d12Dst->CurrentState != D3D12_RESOURCE_STATE_COPY_DEST) - { - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = d3d12Dst->Handle; - barrier.Transition.StateBefore = d3d12Dst->CurrentState; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); - d3d12Dst->CurrentState = D3D12_RESOURCE_STATE_COPY_DEST; - } - - // Src is Upload Buffer, usually effectively GenericRead/Common but for Upload heaps it's simpler. - // We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc. - // D3D12 Upload heaps start in GENERIC_READ and cannot transition. - - d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle, dstOffset, d3d12Src->Handle, - srcOffset, size); - } - - void TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer) - { - auto d3d12CmdList = reinterpret_cast(commandList.Get()); - auto d3d12Buffer = reinterpret_cast(buffer.Get()); - - D3D12_RESOURCE_STATES neededState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - - if (d3d12Buffer->CurrentState != neededState) - { - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = d3d12Buffer->Handle; - barrier.Transition.StateBefore = d3d12Buffer->CurrentState; - barrier.Transition.StateAfter = neededState; - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); - d3d12Buffer->CurrentState = neededState; - } - } - -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Buffer.h b/Juliet/src/Graphics/D3D12/D3D12Buffer.h deleted file mode 100644 index d179b2b..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Buffer.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Juliet -{ - struct CommandList; - struct GPUDriver; -} // namespace Juliet -namespace Juliet::D3D12 -{ - struct D3D12Buffer - { - // Note: This three variables need to stay at the top and in this order - Internal::D3D12Descriptor Descriptor; - ID3D12Resource* Handle; - D3D12_RESOURCE_STATES CurrentState; - - // Anything here can be any order - D3D12Buffer* Next; - size_t Size; - }; - - extern GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, - BufferUsage usage, bool isDynamic); - extern void DestroyGraphicsBuffer(NonNullPtr buffer); - - extern GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr driver, size_t size, TransferBufferUsage usage); - extern void DestroyGraphicsTransferBuffer(NonNullPtr buffer); - - extern void* MapBuffer(NonNullPtr driver, NonNullPtr buffer); - extern void UnmapBuffer(NonNullPtr driver, NonNullPtr buffer); - extern void* MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer); - extern void UnmapBuffer(NonNullPtr driver, NonNullPtr buffer); - - extern uint32 GetDescriptorIndex(NonNullPtr driver, NonNullPtr buffer); - extern void CopyBuffer(NonNullPtr commandList, NonNullPtr dst, - NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset); - extern void TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer); -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp b/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp deleted file mode 100644 index adebd33..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp +++ /dev/null @@ -1,558 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - constexpr size_t kMaxTexturePerCommandList = 1024; - constexpr size_t kMaxGraphicsPipelinePerCommandList = 1024; - constexpr size_t kMaxPresentDataPerCommandList = 1; - constexpr size_t kMaxCommandListCount = 4; - - index_t CommandListID = 0; - - index_t GetNewCommandListID() - { - return CommandListID++; - } - - bool HasD3D12CommandListForQueueType(NonNullPtr commandList, QueueType queueType) - { - switch (queueType) - { - case QueueType::Graphics: return commandList->GraphicsCommandList.CommandList != nullptr; - case QueueType::Compute: return commandList->ComputeCommandList.CommandList != nullptr; - case QueueType::Copy: return commandList->CopyCommandList.CommandList != nullptr; - default: return false; - } - } - - bool CreateAllocator(NonNullPtr driver, NonNullPtr baseData, - D3D12_COMMAND_QUEUE_DESC queueDesc) - { - HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator, - reinterpret_cast(&baseData->Allocator)); - if (FAILED(result)) - { - AssertHR(result, "Cannot create ID3D12CommandAllocator"); - return false; - } - - baseData->Allocator->Reset(); - return true; - } - - bool CreateD3D12CommandListForQueueType(NonNullPtr driver, NonNullPtr commandList, QueueType queueType) - { - // TODO: String library - std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID); - - // TODO: Factorize this. Flemme - - // Get Proper allocator for the frame. Reset all allocators and the command list with current frame allocator - auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)]; - switch (queueType) - { - case QueueType::Graphics: - { - CreateAllocator(driver, &commandList->GraphicsCommandList, queueDesc); - ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; - HRESULT result = - driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, - D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, - reinterpret_cast(&d3d12GraphicsCommandList)); - if (FAILED(result)) - { - Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " - "compute command list"); - return false; - } - - commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList; - d3d12GraphicsCommandList->SetName(wide_str.c_str()); - d3d12GraphicsCommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); - - return true; - } - case QueueType::Compute: - { - CreateAllocator(driver, &commandList->ComputeCommandList, queueDesc); - ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; - HRESULT result = - driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, - D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, - reinterpret_cast(&d3d12GraphicsCommandList)); - if (FAILED(result)) - { - Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " - "compute command list"); - return false; - } - - commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList; - d3d12GraphicsCommandList->SetName(wide_str.c_str()); - d3d12GraphicsCommandList->Reset(commandList->ComputeCommandList.Allocator, nullptr); - - return true; - } - case QueueType::Copy: - { - CreateAllocator(driver, &commandList->CopyCommandList, queueDesc); - ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr; - HRESULT result = - driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, - D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList, - reinterpret_cast(&d3d12CopyCommandList)); - - if (FAILED(result)) - { - AssertHR(result, "cannot create ID3D12GraphicsCommandList (copy command list)"); - return false; - } - commandList->CopyCommandList.CommandList = d3d12CopyCommandList; - d3d12CopyCommandList->SetName(wide_str.c_str()); - d3d12CopyCommandList->Reset(commandList->CopyCommandList.Allocator, nullptr); - - return true; - } - default: return false; - } - } - - bool AllocateCommandList(NonNullPtr driver, QueueType queueType) - { - if (driver->AvailableCommandLists == nullptr) - { - driver->AvailableCommandLists = - ArenaPushArray(driver->DriverArena, - kMaxCommandListCount JULIET_DEBUG_PARAM("Command list count {}", - kMaxCommandListCount)); - driver->AvailableCommandListCapacity = kMaxCommandListCount; - } - const index_t id = GetNewCommandListID(); - - auto* commandList = - ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12CommandList [{}]", id)); - if (!commandList) - { - Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); - Internal::DestroyCommandList(commandList); - return false; - } - - driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; - driver->AvailableCommandListCount += 1; - - commandList->ID = id; - commandList->Driver = driver; - - // Window Handling - commandList->PresentDataCapacity = kMaxPresentDataPerCommandList; - commandList->PresentDataCount = 0; - commandList->PresentDatas = ArenaPushArray( - driver->DriverArena, - kMaxPresentDataPerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12PresentData ptr array count " - "{}", - id, kMaxPresentDataPerCommandList)); - - // Resource tracking - commandList->UsedTextureCapacity = kMaxTexturePerCommandList; - commandList->UsedTextureCount = 0; - commandList->UsedTextures = ArenaPushArray( - driver->DriverArena, - kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12Texture ptr array count " - "{}", - id, kMaxTexturePerCommandList)); - - commandList->UsedGraphicsPipelineCapacity = kMaxGraphicsPipelinePerCommandList; - commandList->UsedGraphicsPipelineCount = 0; - commandList->UsedGraphicsPipelines = ArenaPushArray( - driver->DriverArena, - kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12GraphicsPipeline ptr array count " - "{}", - id, kMaxTexturePerCommandList)); - - // TODO : Simplify this - if (!HasD3D12CommandListForQueueType(commandList, queueType)) - { - if (!CreateD3D12CommandListForQueueType(driver, commandList, queueType)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list"); - Internal::DestroyCommandList(commandList); - return false; - } - } - - return true; - } - - D3D12CommandList* AcquireCommandListFromPool(NonNullPtr driver, QueueType queueType) - { - if (driver->AvailableCommandListCount == 0) - { - if (!AllocateCommandList(driver, queueType)) - { - return nullptr; - } - } - - D3D12CommandList* commandList = driver->AvailableCommandLists[driver->AvailableCommandListCount - 1]; - driver->AvailableCommandListCount -= 1; - - return commandList; - } - } // namespace - - CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType) - { - auto* d3d12Driver = static_cast(driver.Get()); - - D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType); - - commandList->AutoReleaseFence = true; - - return reinterpret_cast(commandList); - } - - bool SubmitCommandLists(NonNullPtr commandList) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto* d3d12Driver = d3d12CommandList->Driver; - // TODO : Use QueueType to choose the correct CommandList and Command Queue - // Only use graphics for now - - // Transition present textures to present mode - for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) - { - uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; - D3D12TextureContainer* container = - &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; - D3D12TextureSubresource* subresource = 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; - - d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); - } - - // Notify the command buffer that we have completed recording - HRESULT result = d3d12CommandList->GraphicsCommandList.CommandList->Close(); - if (FAILED(result)) - { - LogError(d3d12Driver->D3D12Device, "Failed to close command list!", result); - return false; - } - - ID3D12CommandList* ppCommandLists[] = { d3d12CommandList->GraphicsCommandList.CommandList }; - - // Submit the command list to the queue - d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists); - - // Acquire a fence and set it to the in-flight fence - d3d12CommandList->InFlightFence = - Internal::AcquireFence(d3d12Driver JULIET_DEBUG_PARAM(ConstString("SubmitCommandLists"))); - if (!d3d12CommandList->InFlightFence) - { - return false; - } - - // Mark that a fence should be signaled after command list execution - result = d3d12Driver->GraphicsQueue->Signal(d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE); - if (FAILED(result)) - { - LogError(d3d12Driver->D3D12Device, "Failed to enqueue fence signal!", result); - return false; - } - - // Mark the command list as submitted - [[maybe_unused]] const uint32 newValue = static_cast(d3d12Driver->SubmittedCommandListCount) + 1U; - Assert(newValue <= 0xFF && "Command List count exceeded uint8 capacity!"); - Assert(newValue <= d3d12Driver->SubmittedCommandListCapacity); - - d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList; - d3d12Driver->SubmittedCommandListCount += 1; - - bool success = true; - for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) - { - D3D12PresentData* presentData = &d3d12CommandList->PresentDatas[i]; - auto* windowData = presentData->WindowData; - - // NOTE: flip discard always supported since DXGI 1.4 is required - uint32 syncInterval = 1; - if (windowData->PresentMode == PresentMode::Immediate || windowData->PresentMode == PresentMode::Mailbox) - { - syncInterval = 0; - } - - uint32 presentFlags = 0; - if (d3d12Driver->IsTearingSupported && windowData->PresentMode == PresentMode::Immediate) - { - presentFlags = DXGI_PRESENT_ALLOW_TEARING; - } - - result = windowData->SwapChain->Present(syncInterval, presentFlags); - if (FAILED(result)) - { - success = false; - } - - windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource->Release(); - - windowData->InFlightFences[windowData->WindowFrameCounter] = reinterpret_cast(d3d12CommandList->InFlightFence); - d3d12CommandList->InFlightFence->ReferenceCount += 1; - windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight; - } - - // Check for cleanups - { - int32 i = 0; - while (i < d3d12Driver->SubmittedCommandListCount) - { - uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue(); - if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) - { - success &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false); - // CleanCommandList swaps [i] with last and decrements count. - // Don't increment — re-check the swapped-in element. - } - else - { - i += 1; - } - } - } - - Internal::DisposePendingResourcces(d3d12Driver); - - ++d3d12Driver->FrameCounter; - - return success; - } - - void SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - - D3D12_VIEWPORT d3d12Viewport; - d3d12Viewport.TopLeftX = viewPort.X; - d3d12Viewport.TopLeftY = viewPort.Y; - d3d12Viewport.Width = viewPort.Width; - d3d12Viewport.Height = viewPort.Height; - d3d12Viewport.MinDepth = viewPort.MinDepth; - d3d12Viewport.MaxDepth = viewPort.MaxDepth; - d3d12CommandList->GraphicsCommandList.CommandList->RSSetViewports(1, &d3d12Viewport); - } - - void SetScissorRect(NonNullPtr commandList, const Rectangle& rectangle) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - D3D12_RECT scissorRect; - scissorRect.left = rectangle.X; - scissorRect.top = rectangle.Y; - scissorRect.right = rectangle.X + rectangle.Width; - scissorRect.bottom = rectangle.Y + rectangle.Height; - d3d12CommandList->GraphicsCommandList.CommandList->RSSetScissorRects(1, &scissorRect); - } - - void SetBlendConstants(NonNullPtr commandList, FColor blendConstants) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - FLOAT blendFactor[4] = { blendConstants.R, blendConstants.G, blendConstants.B, blendConstants.A }; - d3d12CommandList->GraphicsCommandList.CommandList->OMSetBlendFactor(blendFactor); - } - - void SetStencilReference(NonNullPtr commandList, uint8 reference) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference); - } - - void SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, IndexFormat format, - size_t indexCount, index_t offset) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto* d3d12Buffer = reinterpret_cast(buffer.Get()); - - // Transition to INDEX_BUFFER state if needed - if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ) - { - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; - barrier.Transition.pResource = d3d12Buffer->Handle; - barrier.Transition.StateBefore = d3d12Buffer->CurrentState; - barrier.Transition.StateAfter = - D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER - barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - - d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); - d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ; - } - - D3D12_INDEX_BUFFER_VIEW ibView; - ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset; - if (format == IndexFormat::UInt16) - { - ibView.SizeInBytes = static_cast(indexCount * sizeof(uint16)); - ibView.Format = DXGI_FORMAT_R16_UINT; - } - else - { - ibView.SizeInBytes = static_cast(indexCount * sizeof(uint32)); - ibView.Format = DXGI_FORMAT_R32_UINT; - } - - d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView); - } - - void SetPushConstants(NonNullPtr commandList, ShaderStage /*stage*/, uint32 rootParameterIndex, - uint32 numConstants, const void* constants) - { - auto d3d12CommandList = reinterpret_cast(commandList.Get()); - // For now we assume Graphics Root Signature. Compute support would need a check or separate function. - d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(rootParameterIndex, - numConstants, constants, 0); - } - - namespace Internal - { - void SetDescriptorHeaps(NonNullPtr commandList) - { - ID3D12DescriptorHeap* heaps[2]; - D3D12DescriptorHeap* viewHeap = nullptr; - D3D12DescriptorHeap* samplerHeap = nullptr; - - viewHeap = commandList->Driver->BindlessDescriptorHeap; - - samplerHeap = AcquireSamplerHeapFromPool(commandList->Driver); - - commandList->CRB_SRV_UAV_Heap = viewHeap; - commandList->Sampler_Heap = samplerHeap; - - heaps[0] = viewHeap->Handle; - heaps[1] = samplerHeap->Handle; - - commandList->GraphicsCommandList.CommandList->SetDescriptorHeaps(2, heaps); - } - - void DestroyCommandList(NonNullPtr commandList) - { - // TODO : Handle other kind of command list (copy compute) - if (commandList->GraphicsCommandList.CommandList) - { - commandList->GraphicsCommandList.CommandList->Release(); - } - - commandList->GraphicsCommandList.Allocator->Release(); - } - - bool CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel) - { - // No more presentation data - commandList->PresentDataCount = 0; - - HRESULT result = commandList->GraphicsCommandList.Allocator->Reset(); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Could not reset command allocator", result); - return false; - } - - result = commandList->GraphicsCommandList.CommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Could not reset command list", result); - return false; - } - - if (commandList->Sampler_Heap) [[likely]] - { - ReturnSamplerHeapToPool(driver, commandList->Sampler_Heap); - commandList->Sampler_Heap = nullptr; - } - commandList->CRB_SRV_UAV_Heap = nullptr; - - // Clean up resource tracking - for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx) - { - --commandList->UsedTextures[idx]->ReferenceCount; - } - commandList->UsedTextureCount = 0; - - for (uint32 idx = 0; idx < commandList->UsedGraphicsPipelineCount; ++idx) - { - --commandList->UsedGraphicsPipelines[idx]->ReferenceCount; - } - commandList->UsedGraphicsPipelineCount = 0; - - // Release Fence if needed - if (commandList->AutoReleaseFence) - { - ReleaseFence(driver.Get(), reinterpret_cast(commandList->InFlightFence) - JULIET_DEBUG_PARAM(ConstString("CleanCommandList"))); - commandList->InFlightFence = nullptr; - } - - // Return the command list to the pool - Assert(driver->AvailableCommandListCount + 1 <= driver->AvailableCommandListCapacity); - driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; - driver->AvailableCommandListCount += 1; - - // Remove this command list from the submitted list - if (!cancel) - { - for (uint32 idx = 0; idx < driver->SubmittedCommandListCount; idx += 1) - { - if (driver->SubmittedCommandLists[idx] == commandList) - { - driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1]; - driver->SubmittedCommandListCount -= 1; - break; - } - } - } - - return true; - } - -#define TRACK_RESOURCE(resource, type, array, count, capacity) \ - uint32 i; \ - \ - for (i = 0; i < commandList->count; i += 1) \ - { \ - if (commandList->array[i] == (resource)) \ - { \ - return; \ - } \ - } \ - \ - Assert(commandList->count + 1 <= commandList->capacity); \ - commandList->array[commandList->count] = resource; \ - commandList->count += 1; \ - ++(resource)->ReferenceCount; - - void TrackGraphicsPipeline(NonNullPtr commandList, NonNullPtr pipeline) - { - TRACK_RESOURCE(pipeline, D3D12GraphicsPipeline*, UsedGraphicsPipelines, UsedGraphicsPipelineCount, UsedGraphicsPipelineCapacity) - } - - void TrackTexture(NonNullPtr commandList, NonNullPtr texture) - { - TRACK_RESOURCE(texture, D3D12Texture*, UsedTextures, UsedTextureCount, UsedTextureCapacity) - } - - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12CommandList.h b/Juliet/src/Graphics/D3D12/D3D12CommandList.h deleted file mode 100644 index dfb2048..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12CommandList.h +++ /dev/null @@ -1,115 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - // Forward Declare - struct D3D12Driver; - struct D3D12Fence; - struct D3D12Texture; - struct D3D12TextureSubresource; - struct D3D12WindowData; - - struct D3D12CommandListBaseData - { - ID3D12CommandAllocator* Allocator; - }; - - struct D3D12CopyCommandListData : D3D12CommandListBaseData - { - ID3D12GraphicsCommandList* CommandList; - }; - - struct D3D12GraphicsCommandListData : D3D12CommandListBaseData - { - ID3D12GraphicsCommandList6* CommandList; - }; - - struct D3D12PresentData - { - D3D12WindowData* WindowData; - uint32 SwapChainImageIndex; - }; - - struct D3D12CommandList - { - CommandListHeader Common; - - index_t ID; - - D3D12Driver* Driver; - - D3D12PresentData* PresentDatas; - uint32 PresentDataCapacity; - uint32 PresentDataCount; - - D3D12Fence* InFlightFence; - bool AutoReleaseFence; - - D3D12GraphicsCommandListData GraphicsCommandList; - D3D12GraphicsCommandListData ComputeCommandList; - D3D12CopyCommandListData CopyCommandList; - - D3D12GraphicsPipeline* CurrentGraphicsPipeline; - - D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo]; - D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo]; - D3D12TextureSubresource* DepthStencilSubresource; - - bool NeedVertexBufferBind : 1; - bool NeedVertexSamplerBind : 1; - bool NeedVertexStorageTextureBind : 1; - bool NeedVertexStorageBufferBind : 1; - - bool NeedFragmentSamplerBind : 1; - bool NeedFragmentStorageTextureBind : 1; - bool NeedFragmentStorageBufferBind : 1; - - bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; - bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; - - // D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; - // D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; - - Internal::D3D12DescriptorHeap* CRB_SRV_UAV_Heap; - Internal::D3D12DescriptorHeap* Sampler_Heap; - - // Resource Tracking - D3D12Texture** UsedTextures; - uint32 UsedTextureCount; - uint32 UsedTextureCapacity; - - D3D12GraphicsPipeline** UsedGraphicsPipelines; - uint32 UsedGraphicsPipelineCount; - uint32 UsedGraphicsPipelineCapacity; - }; - - extern CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType); - extern bool SubmitCommandLists(NonNullPtr commandList); - extern void SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort); - extern void SetScissorRect(NonNullPtr commandList, const Rectangle& rectangle); - extern void SetBlendConstants(NonNullPtr commandList, FColor blendConstants); - extern void SetBlendConstants(NonNullPtr commandList, FColor blendConstants); - extern void SetStencilReference(NonNullPtr commandList, uint8 reference); - extern void SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, - IndexFormat format, size_t indexCount, index_t offset); - extern void SetPushConstants(NonNullPtr commandList, ShaderStage stage, uint32 rootParameterIndex, - uint32 numConstants, const void* constants); - - namespace Internal - { - extern void SetDescriptorHeaps(NonNullPtr commandList); - - extern void DestroyCommandList(NonNullPtr commandList); - extern bool CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel); - - extern void TrackGraphicsPipeline(NonNullPtr commandList, NonNullPtr pipeline); - extern void TrackTexture(NonNullPtr commandList, NonNullPtr texture); - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Common.cpp b/Juliet/src/Graphics/D3D12/D3D12Common.cpp deleted file mode 100644 index 01e5806..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Common.cpp +++ /dev/null @@ -1,122 +0,0 @@ - -#include -#include -#include -#include -#include - -// TODO: Convert the whole file to memory arenas -// Use the driver arena -// Use a linked list to support "free" descriptors -// Extend -> Push a new descriptor thats it... -namespace Juliet::D3D12::Internal -{ - namespace - { - constexpr size_t kStagingHeapDescriptorExpectedCount = 1024; - - void InitStagingDescriptorPool(NonNullPtr heap, NonNullPtr pool) - { - for (uint32 idx = 0; idx < kStagingHeapDescriptorExpectedCount; ++idx) - { - pool->FreeDescriptors[idx].Pool = pool; - pool->FreeDescriptors[idx].Heap = heap.Get(); - pool->FreeDescriptors[idx].CpuHandleIndex = idx; - pool->FreeDescriptors[idx].CpuHandle.ptr = heap->DescriptorHeapCPUStart.ptr + (idx * heap->DescriptorSize); - } - } - - bool ExtendStagingDescriptorPool(NonNullPtr driver, D3D12StagingDescriptorPool& pool) - { - D3D12DescriptorHeap* heap = - Internal::CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); - if (!heap) - { - return false; - } - - pool.HeapCount += 1; - pool.Heaps = static_cast(Realloc(pool.Heaps, pool.HeapCount * sizeof(D3D12DescriptorHeap*))); - pool.Heaps[pool.HeapCount - 1] = heap; - - pool.FreeDescriptorCapacity += kStagingHeapDescriptorExpectedCount; - pool.FreeDescriptorCount += kStagingHeapDescriptorExpectedCount; - pool.FreeDescriptors = static_cast( - Realloc(pool.FreeDescriptors, pool.FreeDescriptorCapacity * sizeof(D3D12StagingDescriptor))); - - InitStagingDescriptorPool(heap, &pool); - - return true; - } - } // namespace - - D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type) - { - D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true); - if (!heap) - { - return nullptr; - } - - auto pool = static_cast(Calloc(1, sizeof(D3D12StagingDescriptorPool))); - - // First create the heaps - pool->HeapCount = 1; - pool->Heaps = static_cast(Malloc(sizeof(D3D12DescriptorHeap*))); - pool->Heaps[0] = heap; - - pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount; - pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount; - pool->FreeDescriptors = - static_cast(Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor))); - - InitStagingDescriptorPool(heap, pool); - - return pool; - } - - bool AssignStagingDescriptor(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12StagingDescriptor& outDescriptor) - { - // TODO: Make it thread safe - D3D12StagingDescriptor* descriptor = nullptr; - D3D12StagingDescriptorPool* pool = driver->StagingDescriptorPools[type]; - - if (pool->FreeDescriptorCount == 0) - { - if (!ExtendStagingDescriptorPool(driver, *pool)) - { - return false; - } - } - - descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1]; - MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor)); - pool->FreeDescriptorCount -= 1; - - return true; - } - - void ReleaseStagingDescriptor(NonNullPtr /*driver*/, D3D12StagingDescriptor& cpuDescriptor) - { - D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool; - - if (pool != nullptr) - { - MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor)); - pool->FreeDescriptorCount += 1; - } - } - - void DestroyStagingDescriptorPool(NonNullPtr pool) - { - for (uint32 i = 0; i < pool->HeapCount; i += 1) - { - DestroyDescriptorHeap(pool->Heaps[i]); - } - - Free(pool->Heaps); - Free(pool->FreeDescriptors); - - Free(pool.Get()); - } -} // namespace Juliet::D3D12::Internal diff --git a/Juliet/src/Graphics/D3D12/D3D12Common.h b/Juliet/src/Graphics/D3D12/D3D12Common.h deleted file mode 100644 index 37f90d4..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Common.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -// Definitions: -// RTV = Render Target View -// DSV = Depth Stencil View -// SRV = Shader Resource View -// UAV = Unordered Access View -// CBV = Constant Buffer View -// PSO = Pipeline State Object - -// Inspired (copy pasted a lot) by SDL GPU -namespace Juliet::D3D12 -{ - // Forward declare - struct D3D12Driver; - struct D3D12StagingDescriptor; - - struct D3D12StagingDescriptorPool - { - Internal::D3D12DescriptorHeap** Heaps; - uint32 HeapCount; - - // Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap. - uint32 FreeDescriptorCapacity; - uint32 FreeDescriptorCount; - D3D12StagingDescriptor* FreeDescriptors; - }; - - // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptors-overview - struct D3D12StagingDescriptor - { - D3D12StagingDescriptorPool* Pool; - Internal::D3D12DescriptorHeap* Heap; - D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; - uint32 CpuHandleIndex; - }; - - namespace Internal - { - extern D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type); - extern bool AssignStagingDescriptor(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, - D3D12StagingDescriptor& outDescriptor); - extern void ReleaseStagingDescriptor(NonNullPtr driver, D3D12StagingDescriptor& cpuDescriptor); - extern void DestroyStagingDescriptorPool(NonNullPtr pool); - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp b/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp deleted file mode 100644 index 22ed1da..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -namespace Juliet::D3D12::Internal -{ - void CreateDescriptorHeapPool(NonNullPtr driver, D3D12DescriptorHeapPool& heapPool, - D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count) - { - // Heap pool is just single linked list of free elements - constexpr size_t kInitialCapacity = 4; - heapPool.FirstFreeDescriptorHeap = nullptr; - - // Pre allocate 4 - for (uint32 i = 0; i < kInitialCapacity; ++i) - { - D3D12DescriptorHeap* descriptorHeap = CreateDescriptorHeap(driver, type, count, false); - descriptorHeap->Next = heapPool.FirstFreeDescriptorHeap; - heapPool.FirstFreeDescriptorHeap = descriptorHeap; - } - } - - void DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& heapPool) - { - D3D12DescriptorHeap* current = heapPool.FirstFreeDescriptorHeap; - while (current != nullptr) - { - D3D12DescriptorHeap* next = current->Next; - DestroyDescriptorHeap(current); - current = next; - } - } - - D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging) - { - D3D12DescriptorHeap* heap = ArenaPushStruct( - driver->DriverArena JULIET_DEBUG_PARAM("Descriptor Heap Type {}", CStr(GetDescriptorTypeNane(type)))); - Assert(heap); - - heap->CurrentDescriptorIndex = 0; - - heap->FreeIndices.Create(driver->DriverArena JULIET_DEBUG_PARAM("DescriptorHeap Free Indices")); - heap->FreeIndices.Resize(16); - heap->CurrentFreeIndex = 0; - - D3D12_DESCRIPTOR_HEAP_DESC heapDesc; - heapDesc.NumDescriptors = count; - heapDesc.Type = type; - heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; - heapDesc.NodeMask = 0; - - ID3D12DescriptorHeap* handle; - HRESULT result = - driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, reinterpret_cast(&handle)); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Failed to create descriptor heap!", result); - DestroyDescriptorHeap(heap); - return nullptr; - } - - heap->Handle = handle; - heap->HeapType = type; - heap->MaxDescriptors = count; - heap->Staging = isStaging; - heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type); - heap->DescriptorHeapCPUStart = handle->GetCPUDescriptorHandleForHeapStart(); - if (!isStaging) - { - heap->DescriptorHeapGPUStart = handle->GetGPUDescriptorHandleForHeapStart(); - } - - return heap; - } - - void DestroyDescriptorHeap(NonNullPtr heap) - { - heap->FreeIndices.Destroy(); - if (heap->Handle) - { - heap->Handle->Release(); - } - } - - bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor) - { - uint32 index = UINT32_MAX; - - if (heap->CurrentFreeIndex > 0) - { - heap->CurrentFreeIndex -= 1; - index = heap->FreeIndices[heap->CurrentFreeIndex]; - } - else if (heap->CurrentDescriptorIndex < heap->MaxDescriptors) - { - index = heap->CurrentDescriptorIndex; - heap->CurrentDescriptorIndex++; - } - else - { - Assert(false, "Descriptor Heap Full!"); - return false; - } - - outDescriptor.Heap = heap; - outDescriptor.Index = index; - outDescriptor.CpuHandle = heap->DescriptorHeapCPUStart; - outDescriptor.CpuHandle.ptr += heap->DescriptorSize * index; - outDescriptor.GpuHandle = heap->DescriptorHeapGPUStart; - outDescriptor.GpuHandle.ptr += heap->DescriptorSize * index; - - return true; - } - - void ReleaseDescriptor(const D3D12Descriptor& descriptor) - { - if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr) - { - return; - } - - D3D12DescriptorHeap* heap = descriptor.Heap; - - if (heap->CurrentFreeIndex >= heap->FreeIndices.Count) - { - heap->FreeIndices.PushBack(descriptor.Index); - } - else - { - heap->FreeIndices[heap->CurrentFreeIndex] = descriptor.Index; - heap->CurrentFreeIndex++; - } - } - - D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr d3d12Driver) - { - D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; - - D3D12DescriptorHeap* result = pool.FirstFreeDescriptorHeap; - if (result) - { - pool.FirstFreeDescriptorHeap = pool.FirstFreeDescriptorHeap->Next; - } - else - { - result = CreateDescriptorHeap(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - GPUDriver::kSampler_HeapDescriptorCount, false); - } - - return result; - } - - void ReturnSamplerHeapToPool(NonNullPtr d3d12Driver, NonNullPtr heap) - { - D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; - - heap->CurrentDescriptorIndex = 0; - - heap->Next = pool.FirstFreeDescriptorHeap; - pool.FirstFreeDescriptorHeap = heap; - } -} // namespace Juliet::D3D12::Internal diff --git a/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.h b/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.h deleted file mode 100644 index d94443f..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12DescriptorHeap.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include -#include - -// Forward declare -namespace Juliet::D3D12 -{ - struct D3D12Driver; -} - -namespace Juliet::D3D12::Internal -{ - // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps - struct D3D12DescriptorHeap - { - D3D12DescriptorHeap* Next; - ID3D12DescriptorHeap* Handle; - D3D12_DESCRIPTOR_HEAP_TYPE HeapType; - D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapCPUStart; - D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapGPUStart; // only used by GPU heaps - uint32 MaxDescriptors; - uint32 DescriptorSize; - uint32 CurrentDescriptorIndex; // only used by GPU heaps - - VectorArena FreeIndices; - index_t CurrentFreeIndex; - - bool Staging : 1; - }; - - struct D3D12Descriptor - { - D3D12DescriptorHeap* Heap; - uint32 Index; - D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; - D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle; - }; - - struct D3D12DescriptorHeapPool - { - D3D12DescriptorHeap* FirstFreeDescriptorHeap; - }; - - using DescriptorHeapCreator = D3D12DescriptorHeap* (*)(NonNullPtr, D3D12DescriptorHeapPool& heapPool, - D3D12_DESCRIPTOR_HEAP_TYPE, uint32, bool); - - extern void CreateDescriptorHeapPool(NonNullPtr driver, D3D12DescriptorHeapPool& heapPool, - D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count); - extern void DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& pool); - - extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, - uint32 count, bool isStaging); - extern void DestroyDescriptorHeap(NonNullPtr heap); - - extern D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr d3d12Driver); - extern void ReturnSamplerHeapToPool(NonNullPtr d3d12Driver, NonNullPtr heap); - - extern bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor); - extern void ReleaseDescriptor(const D3D12Descriptor& descriptor); -} // namespace Juliet::D3D12::Internal diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp index 5e4d117..e6ae2cd 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp @@ -1,21 +1,12 @@ +#include #include +#include +#include #include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -23,198 +14,1070 @@ #define D3D12_CREATEDEVICE_FUNC "D3D12CreateDevice" #define D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC "D3D12SerializeVersionedRootSignature" +#define D3D12_FENCE_UNSIGNALED_VALUE 0 +#define D3D12_FENCE_SIGNAL_VALUE 1 + +#ifdef _WIN32 +#define HRESULT_FMT "(0x%08lX)" +#else +#define HRESULT_FMT "(0x%08X)" +#endif + +#define TOD3D12FuncPtr(type, ptr) reinterpret_cast(reinterpret_cast(ptr)) + +// Definitions: +// RTV = Render Target View +// DSV = Depth Stencil View +// SRV = Shader Resource View +// UAV = Unordered Access View +// CBV = Constant Buffer View +// PSO = Pipeline State Object + +// Inspired (copy pasted a lot) by SDL GPU + // TODO : Use LoadLibrary and not link to the lib. Allows failing earlier if Dx12 is not installed for some reason // + Will load the dll when needed // This will prevent us from using IID_ variables as they are defined in dxguid.lib -namespace Juliet::D3D12 +namespace Juliet { - namespace - { - // Note: This is the highest my Gfx Card supports (5700XT) - // https://en.wikipedia.org/wiki/Feature_levels_in_Direct3D#Direct3D_12 - // 12_2 Adds RayTracing and others feature supported by RDNA2 and greater and Gefore 20xx and greater - constexpr D3D_FEATURE_LEVEL kD3DFeatureLevel = D3D_FEATURE_LEVEL_12_1; - constexpr auto kD3DFeatureLevelStr = "12_1"; + struct D3D12GraphicsRootSignature; + struct D3D12GraphicsPipeline; + struct D3D12Texture; + struct D3D12TextureSubresource; + struct D3D12Fence; + struct D3D12CommandList; + struct D3D12StagingDescriptorPool; - bool CheckResourceTypeTier(ID3D12Device5* device) + // Note: This is the highest my Gfx Card supports (5700XT) + // https://en.wikipedia.org/wiki/Feature_levels_in_Direct3D#Direct3D_12 + // 12_2 Adds RayTracing and others feature supported by RDNA2 and greater and Gefore 20xx and greater + constexpr D3D_FEATURE_LEVEL kD3DFeatureLevel = D3D_FEATURE_LEVEL_12_1; + constexpr auto kD3DFeatureLevelStr = "12_1"; + constexpr size_t kStagingHeapDescriptorExpectedCount = 1024; + constexpr size_t kMaxTexturePerCommandList = 1024; + constexpr size_t kMaxGraphicsPipelinePerCommandList = 1024; + constexpr size_t kMaxPresentDataPerCommandList = 1; + constexpr size_t kMaxCommandListCount = 4; + + index_t CommandListID = 0; + + uint32 JulietToD3D12_SampleCount[] = { + 1, // MSAA 1x + 2, // MSAA 2x + 4, // MSAA 4x + 8, // MSAA 8x + }; + + DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = { + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR + DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR + DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR + DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084 + }; + + DXGI_FORMAT SwapchainCompositionToTextureFormat[] = { + DXGI_FORMAT_B8G8R8A8_UNORM, // SDR + DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format) + DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR + DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084 + }; + + TextureFormat SwapchainCompositionToJulietTextureFormat[] = { + TextureFormat::B8G8R8A8_UNORM, // SDR + TextureFormat::B8G8R8A8_UNORM_SRGB, // SDR_LINEAR + TextureFormat::R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR + TextureFormat::R10G10B10A2_UNORM, // HDR10_ST2084 + }; + + DXGI_FORMAT JulietToD3D12_TextureFormat[] = { + DXGI_FORMAT_UNKNOWN, // INVALID + DXGI_FORMAT_A8_UNORM, // A8_UNORM + DXGI_FORMAT_R8_UNORM, // R8_UNORM + DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM + DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM + DXGI_FORMAT_R16_UNORM, // R16_UNORM + DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM + DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM + DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM + DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM + DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM + DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM + DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM + DXGI_FORMAT_BC1_UNORM, // BC1_UNORM + DXGI_FORMAT_BC2_UNORM, // BC2_UNORM + DXGI_FORMAT_BC3_UNORM, // BC3_UNORM + DXGI_FORMAT_BC4_UNORM, // BC4_UNORM + DXGI_FORMAT_BC5_UNORM, // BC5_UNORM + DXGI_FORMAT_BC7_UNORM, // BC7_UNORM + DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT + DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT + DXGI_FORMAT_R8_SNORM, // R8_SNORM + DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM + DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM + DXGI_FORMAT_R16_SNORM, // R16_SNORM + DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM + DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM + DXGI_FORMAT_R16_FLOAT, // R16_FLOAT + DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT + DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT + DXGI_FORMAT_R32_FLOAT, // R32_FLOAT + DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT + DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT + DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT + DXGI_FORMAT_R8_UINT, // R8_UINT + DXGI_FORMAT_R8G8_UINT, // R8G8_UINT + DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT + DXGI_FORMAT_R16_UINT, // R16_UINT + DXGI_FORMAT_R16G16_UINT, // R16G16_UINT + DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT + DXGI_FORMAT_R32_UINT, // R32_UINT + DXGI_FORMAT_R32G32_UINT, // R32G32_UINT + DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT + DXGI_FORMAT_R8_SINT, // R8_INT + DXGI_FORMAT_R8G8_SINT, // R8G8_INT + DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT + DXGI_FORMAT_R16_SINT, // R16_INT + DXGI_FORMAT_R16G16_SINT, // R16G16_INT + DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT + DXGI_FORMAT_R32_SINT, // R32_INT + DXGI_FORMAT_R32G32_SINT, // R32G32_INT + DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB + DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB + DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB + DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB + DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB + DXGI_FORMAT_R16_TYPELESS, // D16_UNORM + DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM + DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT + DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT + DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT + }; + static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) == ToUnderlying(TextureFormat::Count)); + + DXGI_FORMAT JulietToD3D12_DepthFormat[] = { + DXGI_FORMAT_UNKNOWN, // INVALID + DXGI_FORMAT_UNKNOWN, // A8_UNORM + DXGI_FORMAT_UNKNOWN, // R8_UNORM + DXGI_FORMAT_UNKNOWN, // R8G8_UNORM + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM + DXGI_FORMAT_UNKNOWN, // R16_UNORM + DXGI_FORMAT_UNKNOWN, // R16G16_UNORM + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM + DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM + DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM + DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM + DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM + DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM + DXGI_FORMAT_UNKNOWN, // BC1_UNORM + DXGI_FORMAT_UNKNOWN, // BC2_UNORM + DXGI_FORMAT_UNKNOWN, // BC3_UNORM + DXGI_FORMAT_UNKNOWN, // BC4_UNORM + DXGI_FORMAT_UNKNOWN, // BC5_UNORM + DXGI_FORMAT_UNKNOWN, // BC7_UNORM + DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT + DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT + DXGI_FORMAT_UNKNOWN, // R8_SNORM + DXGI_FORMAT_UNKNOWN, // R8G8_SNORM + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM + DXGI_FORMAT_UNKNOWN, // R16_SNORM + DXGI_FORMAT_UNKNOWN, // R16G16_SNORM + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM + DXGI_FORMAT_UNKNOWN, // R16_FLOAT + DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT + DXGI_FORMAT_UNKNOWN, // R32_FLOAT + DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT + DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT + DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT + DXGI_FORMAT_UNKNOWN, // R8_UINT + DXGI_FORMAT_UNKNOWN, // R8G8_UINT + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT + DXGI_FORMAT_UNKNOWN, // R16_UINT + DXGI_FORMAT_UNKNOWN, // R16G16_UINT + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT + DXGI_FORMAT_UNKNOWN, // R32_UINT + DXGI_FORMAT_UNKNOWN, // R32G32_UINT + DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT + DXGI_FORMAT_UNKNOWN, // R8_INT + DXGI_FORMAT_UNKNOWN, // R8G8_INT + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT + DXGI_FORMAT_UNKNOWN, // R16_INT + DXGI_FORMAT_UNKNOWN, // R16G16_INT + DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT + DXGI_FORMAT_UNKNOWN, // R32_INT + DXGI_FORMAT_UNKNOWN, // R32G32_INT + DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT + DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB + DXGI_FORMAT_D16_UNORM, // D16_UNORM + DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM + DXGI_FORMAT_D32_FLOAT, // D32_FLOAT + DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT + DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB + DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT + DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT + }; + static_assert(sizeof(JulietToD3D12_DepthFormat) / sizeof(JulietToD3D12_DepthFormat[0]) == ToUnderlying(TextureFormat::Count)); + + // clang-format off + D3D12_INPUT_CLASSIFICATION JulietToD3D12_InputRate[] = { - D3D12_FEATURE_DATA_D3D12_OPTIONS options = {}; - HRESULT result = - device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)); - if (SUCCEEDED(result)) - { - if (options.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_3) - { - Juliet::LogError(LogCategory::Graphics, "Resource Binding Tier 3 not supported. :("); - return false; - } - return true; - } + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_InputRate) / sizeof(JulietToD3D12_InputRate[0]) == ToUnderlying(VertexInputRate::Count)); - Juliet::LogError(LogCategory::Graphics, "Couldn't fetch D3D12_FEATURE_D3D12_OPTIONS :("); - return false; + // clang-format off + D3D12_CULL_MODE JulietToD3D12_CullMode[] = + { + D3D12_CULL_MODE_NONE, + D3D12_CULL_MODE_FRONT, + D3D12_CULL_MODE_BACK + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_CullMode) / sizeof(JulietToD3D12_CullMode[0]) == ToUnderlying(CullMode::Count)); + + // clang-format off + D3D12_FILL_MODE JulietToD3D12_FillMode[] = + { + D3D12_FILL_MODE_SOLID, + D3D12_FILL_MODE_WIREFRAME + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_FillMode) / sizeof(JulietToD3D12_FillMode[0]) == ToUnderlying(FillMode::Count)); + + DXGI_FORMAT JulietToD3D12_VertexFormat[] = { + DXGI_FORMAT_UNKNOWN, // Unknown + DXGI_FORMAT_R32_SINT, // Int + DXGI_FORMAT_R32G32_SINT, // Int2 + DXGI_FORMAT_R32G32B32_SINT, // Int3 + DXGI_FORMAT_R32G32B32A32_SINT, // Int4 + DXGI_FORMAT_R32_UINT, // UInt + DXGI_FORMAT_R32G32_UINT, // UInt2 + DXGI_FORMAT_R32G32B32_UINT, // UInt3 + DXGI_FORMAT_R32G32B32A32_UINT, // UInt4 + DXGI_FORMAT_R32_FLOAT, // Float + DXGI_FORMAT_R32G32_FLOAT, // Float2 + DXGI_FORMAT_R32G32B32_FLOAT, // Float3 + DXGI_FORMAT_R32G32B32A32_FLOAT, // Float4 + DXGI_FORMAT_R8G8_SINT, // Byte2 + DXGI_FORMAT_R8G8B8A8_SINT, // Byte4 + DXGI_FORMAT_R8G8_UINT, // UByte2 + DXGI_FORMAT_R8G8B8A8_UINT, // UByte4 + DXGI_FORMAT_R8G8_SNORM, // Byte2_Norm + DXGI_FORMAT_R8G8B8A8_SNORM, // Byte4_Norm + DXGI_FORMAT_R8G8_UNORM, // UByte2_Norm + DXGI_FORMAT_R8G8B8A8_UNORM, // UByte4_Norm + DXGI_FORMAT_R16G16_SINT, // Short2 + DXGI_FORMAT_R16G16B16A16_SINT, // Short4 + DXGI_FORMAT_R16G16_UINT, // UShort2 + DXGI_FORMAT_R16G16B16A16_UINT, // UShort4 + DXGI_FORMAT_R16G16_SNORM, // Short2_Norm + DXGI_FORMAT_R16G16B16A16_SNORM, // Short4_Norm + DXGI_FORMAT_R16G16_UNORM, // UShort2_Norm + DXGI_FORMAT_R16G16B16A16_UNORM, // UShort4_Norm + DXGI_FORMAT_R16G16_FLOAT, // Half2 + DXGI_FORMAT_R16G16B16A16_FLOAT // Half4 + }; + static_assert(sizeof(JulietToD3D12_VertexFormat) / sizeof(JulietToD3D12_VertexFormat[0]) == + ToUnderlying(VertexElementFormat::Count)); + + // clang-format off + D3D12_PRIMITIVE_TOPOLOGY_TYPE JulietToD3D12_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 + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_PrimitiveTopologyType) / sizeof(JulietToD3D12_PrimitiveTopologyType[0]) == + ToUnderlying(PrimitiveType::Count)); + + // clang-format off + D3D12_BLEND JulietToD3D12_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, + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_BlendFactor) / sizeof(JulietToD3D12_BlendFactor[0]) == ToUnderlying(BlendFactor::Count)); + + // clang-format off + D3D12_BLEND JulietToD3D12_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, + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_BlendFactorAlpha) / sizeof(JulietToD3D12_BlendFactorAlpha[0]) == + ToUnderlying(BlendFactor::Count)); + + // clang-format off + D3D12_BLEND_OP JulietToD3D12_BlendOperation[] = + { + 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 + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_BlendOperation) / sizeof(JulietToD3D12_BlendOperation[0]) == + ToUnderlying(BlendOperation::Count)); + + // clang-format off + D3D12_COMPARISON_FUNC JulietToD3D12_CompareOperation[] = + { + 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 + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_CompareOperation) / sizeof(JulietToD3D12_CompareOperation[0]) == + ToUnderlying(CompareOperation::Count)); + + // clang-format off + D3D12_STENCIL_OP JulietToD3D12_StencilOperation[] = + { + 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 + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_StencilOperation) / sizeof(JulietToD3D12_StencilOperation[0]) == + ToUnderlying(StencilOperation::Count)); + + // clang-format off + D3D12_PRIMITIVE_TOPOLOGY JulietToD3D12_PrimitiveType[] = + { + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + D3D_PRIMITIVE_TOPOLOGY_LINELIST, + D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, + D3D_PRIMITIVE_TOPOLOGY_POINTLIST + }; + // clang-format on + static_assert(sizeof(JulietToD3D12_PrimitiveType) / sizeof(JulietToD3D12_PrimitiveType[0]) == ToUnderlying(PrimitiveType::Count)); + + enum class RootParameters : uint8 + { + Constants32Bits, + Count, + }; + + struct D3D12TextureContainer + { + TextureHeader Header; + + D3D12Texture* ActiveTexture; + D3D12Texture** Textures; + uint32 Capacity; + uint32 Count; + + // Note: Swapchain images cannot be cycled + bool CanBeCycled; + +#if JULIET_DEBUG + char* DebugName; +#endif + }; + + struct D3D12WindowData + { + Window* Window; + + IDXGISwapChain3* SwapChain; + D3D12TextureContainer SwapChainTextureContainers[GPUDriver::kMaxFramesInFlight]; + DXGI_COLOR_SPACE_TYPE SwapChainColorSpace; + SwapChainComposition SwapChainComposition; + uint8 SwapChainTextureCount; + + PresentMode PresentMode; + + Fence* InFlightFences[GPUDriver::kMaxFramesInFlight]; + + uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter + uint32 Width; + uint32 Height; + }; + + struct D3D12CommandListBaseData + { + ID3D12CommandAllocator* Allocator; + }; + + struct D3D12CopyCommandListData : D3D12CommandListBaseData + { + ID3D12GraphicsCommandList* CommandList; + }; + + struct D3D12GraphicsCommandListData : D3D12CommandListBaseData + { + ID3D12GraphicsCommandList6* CommandList; + }; + + struct D3D12Shader + { + ByteBuffer ByteCode; + + uint32 NumSamplers; + uint32 NumUniformBuffers; + uint32 NumStorageBuffers; + uint32 NumStorageTextures; + }; + + struct D3D12PresentData + { + D3D12WindowData* WindowData; + uint32 SwapChainImageIndex; + }; + + // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptor-heaps + struct D3D12DescriptorHeap + { + D3D12DescriptorHeap* Next; + ID3D12DescriptorHeap* Handle; + D3D12_DESCRIPTOR_HEAP_TYPE HeapType; + D3D12_CPU_DESCRIPTOR_HANDLE DescriptorHeapCPUStart; + D3D12_GPU_DESCRIPTOR_HANDLE DescriptorHeapGPUStart; // only used by GPU heaps + uint32 MaxDescriptors; + uint32 DescriptorSize; + uint32 CurrentDescriptorIndex; // only used by GPU heaps + + VectorArena FreeIndices; + index_t CurrentFreeIndex; + + bool Staging : 1; + }; + + struct D3D12Descriptor + { + D3D12DescriptorHeap* Heap; + uint32 Index; + D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; + D3D12_GPU_DESCRIPTOR_HANDLE GpuHandle; + }; + + struct D3D12DescriptorHeapPool + { + D3D12DescriptorHeap* FirstFreeDescriptorHeap; + }; + + // https://learn.microsoft.com/en-us/windows/win32/direct3d12/descriptors-overview + struct D3D12StagingDescriptor + { + D3D12StagingDescriptorPool* Pool; + D3D12DescriptorHeap* Heap; + D3D12_CPU_DESCRIPTOR_HANDLE CpuHandle; + uint32 CpuHandleIndex; + }; + + struct D3D12StagingDescriptorPool + { + D3D12DescriptorHeap** Heaps; + uint32 HeapCount; + + // Descriptor handles are owned by resources, so these can be thought of as descriptions of a free index within a heap. + uint32 FreeDescriptorCapacity; + uint32 FreeDescriptorCount; + D3D12StagingDescriptor* FreeDescriptors; + }; + + struct D3D12Buffer + { + // Note: This three variables need to stay at the top and in this order + D3D12Descriptor Descriptor; + ID3D12Resource* Handle; + D3D12_RESOURCE_STATES CurrentState; + + // Anything here can be any order + D3D12Buffer* Next; + size_t Size; + }; + + struct D3D12Driver : GPUDriver + { + GraphicsDevice* GraphicsDevice; + + // D3D12 + DynamicLibrary* D3D12DLL; + ID3D12Device5* D3D12Device; + PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignatureFct; + ID3D12CommandQueue* GraphicsQueue; + D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Count)]; +#if JULIET_DEBUG + ID3D12Debug1* D3D12Debug; +#endif + + // Indirect commands signature + ID3D12CommandSignature* IndirectDrawCommandSignature; + ID3D12CommandSignature* IndirectIndexedDrawCommandSignature; + ID3D12CommandSignature* IndirectDispatchCommandSignature; + + // DXGI + IDXGIFactory4* DXGIFactory; + IDXGIAdapter1* DXGIAdapter; +#if JULIET_DEBUG + DynamicLibrary* DXGIDebugDLL; + IDXGIDebug* DXGIDebug; +#ifdef IDXGIINFOQUEUE_SUPPORTED + IDXGIInfoQueue* DXGIInfoQueue; +#endif +#endif + + // Windows + // TODO: Support more than one window + D3D12WindowData* WindowData; + + // Resources + D3D12CommandList** AvailableCommandLists; + uint8 AvailableCommandListCapacity; + uint8 AvailableCommandListCount; + + D3D12CommandList** SubmittedCommandLists; + uint8 SubmittedCommandListCapacity; + uint8 SubmittedCommandListCount; + + D3D12Fence** AvailableFences; + uint32 AvailableFenceCount; + uint32 AvailableFenceCapacity; + + D3D12GraphicsPipeline** GraphicsPipelinesToDispose; + uint32 GraphicsPipelinesToDisposeCount; + uint32 GraphicsPipelinesToDisposeCapacity; + + D3D12GraphicsRootSignature* BindlessRootSignature; + + D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; + D3D12DescriptorHeap* BindlessDescriptorHeap; + D3D12DescriptorHeapPool SamplerHeapPool; + + String Semantic; + + uint8 FramesInFlight; + uint64 FrameCounter = 0; // Number of frame since inception + + bool IsTearingSupported : 1; + bool IsUMAAvailable : 1; + bool IsUMACacheCoherent : 1; + bool GPUUploadHeapSupported : 1; + }; + + struct D3D12GraphicsRootSignature + { + ID3D12RootSignature* Handle; + }; + + struct D3D12GraphicsPipeline + { +#if ALLOW_SHADER_HOT_RELOAD + // Template to recreate an ID3D12PipelineState when shader are hot reloaded + // Stripped out in shipping build as the struct is huge + D3D12_GRAPHICS_PIPELINE_STATE_DESC PSODescTemplate; + + // Keeping shaders byte code to make it easier to recreate the ID3D12PipelineState + // Those will be freed when the pipeline is destroyed or updated + D3D12Shader* VertexShaderCache; + D3D12Shader* FragmentShaderCache; +#endif + + ID3D12PipelineState* PipelineState; + D3D12GraphicsRootSignature* RootSignature; + PrimitiveType PrimitiveType; + + uint32 VertexStrides[GPUDriver::kMaxVertexBuffers]; + + uint32 VertexSamplerCount; + uint32 VertexUniformBufferCount; + uint32 VertexStorageBufferCount; + uint32 VertexStorageTextureCount; + + uint32 FragmentSamplerCount; + uint32 FragmentUniformBufferCount; + uint32 FragmentStorageBufferCount; + uint32 FragmentStorageTextureCount; + + int ReferenceCount; + }; + + struct D3D12CommandList + { + CommandListHeader Common; + + index_t ID; + + D3D12Driver* Driver; + + D3D12PresentData* PresentDatas; + uint32 PresentDataCapacity; + uint32 PresentDataCount; + + D3D12Fence* InFlightFence; + bool AutoReleaseFence; + + D3D12GraphicsCommandListData GraphicsCommandList; + D3D12GraphicsCommandListData ComputeCommandList; + D3D12CopyCommandListData CopyCommandList; + + D3D12GraphicsPipeline* CurrentGraphicsPipeline; + + D3D12TextureSubresource* ColorTargetSubresources[GPUDriver::kMaxColorTargetInfo]; + D3D12TextureSubresource* ColorResolveSubresources[GPUDriver::kMaxColorTargetInfo]; + D3D12TextureSubresource* DepthStencilSubresource; + + bool NeedVertexBufferBind : 1; + bool NeedVertexSamplerBind : 1; + bool NeedVertexStorageTextureBind : 1; + bool NeedVertexStorageBufferBind : 1; + + bool NeedFragmentSamplerBind : 1; + bool NeedFragmentStorageTextureBind : 1; + bool NeedFragmentStorageBufferBind : 1; + + bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; + bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; + + // D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + // D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + + D3D12DescriptorHeap* CRB_SRV_UAV_Heap; + D3D12DescriptorHeap* Sampler_Heap; + + // Resource Tracking + D3D12Texture** UsedTextures; + uint32 UsedTextureCount; + uint32 UsedTextureCapacity; + + D3D12GraphicsPipeline** UsedGraphicsPipelines; + uint32 UsedGraphicsPipelineCount; + uint32 UsedGraphicsPipelineCapacity; + }; + + // D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..) + struct D3D12TextureSubresource + { + D3D12Texture* Parent; + uint32 Layer; + uint32 Level; + uint32 Depth; + uint32 Index; + + // One per depth slice + D3D12StagingDescriptor* RTVHandles; // NULL if not a color target + + D3D12StagingDescriptor UAVHandle; // NULL if not a compute storage write texture + D3D12StagingDescriptor DSVHandle; // NULL if not a depth stencil target + }; + + struct D3D12Texture + { + D3D12TextureContainer* Container; + uint32 IndexInContainer; + + ID3D12Resource* Resource; + + D3D12TextureSubresource* Subresources; + uint32 SubresourceCount; // Layer Count * number of Levels + + D3D12StagingDescriptor SRVHandle; + + // TODO: Should be atomic to support multithreading + int32 ReferenceCount; + }; + + struct D3D12Fence + { + ID3D12Fence* Handle; + HANDLE Event; // used for blocking + int32 ReferenceCount; // TODO : Atomic + }; + + // -------------- + // End Data Types + + // ------------- + // Foward declare Functions + bool CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel); + + DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format) + { + return JulietToD3D12_TextureFormat[ToUnderlying(format)]; + } + + DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format) + { + return JulietToD3D12_DepthFormat[ToUnderlying(format)]; + } + + // From SDLGPU + // TODO Do my own version. + extern void LogError(NonNullPtr D3D12Device, const char* errorMessage, HRESULT result) + { +#define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! + + // Buffer for text, ensure space for \0 terminator after buffer + char wszMsgBuff[MAX_ERROR_LEN + 1]; + // Number of chars returned. + + if (result == DXGI_ERROR_DEVICE_REMOVED) + { + result = D3D12Device->GetDeviceRemovedReason(); } - bool CheckShaderModel(ID3D12Device5* device) + // Try to get the message from the system errors. + DWORD dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, + static_cast(result), 0, wszMsgBuff, MAX_ERROR_LEN, nullptr); + + // No message? Screw it, just post the code. + if (dwChars == 0) { - // Check Shader Model - bool foundShaderModel = false; - D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {}; - constexpr D3D_SHADER_MODEL allModelVersions[] = { -#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 612) - D3D_SHADER_MODEL_6_9, -#endif -#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606) - D3D_SHADER_MODEL_6_8, -#endif -#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3) - D3D_SHADER_MODEL_6_7, -#endif - D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5, D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, - D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0, D3D_SHADER_MODEL_5_1 - }; - for (auto allModelVersion : allModelVersions) - { - shaderModel.HighestShaderModel = allModelVersion; - HRESULT result = device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, - sizeof(D3D12_FEATURE_DATA_SHADER_MODEL)); - if (result != E_INVALIDARG) - { - if (FAILED(result)) - { - shaderModel.HighestShaderModel = static_cast(0); - } - else - { - foundShaderModel = true; - break; - } - } - } + Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: " HRESULT_FMT, errorMessage, result); + return; + } - if (!foundShaderModel) - { - shaderModel.HighestShaderModel = static_cast(0); - } + // Ensure valid range + dwChars = Min(dwChars, MAX_ERROR_LEN); - if (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_6) + // Trim whitespace from tail of message + while (dwChars > 0) + { + if (wszMsgBuff[dwChars - 1] <= ' ') { - Juliet::LogError(LogCategory::Graphics, "Shader Model 6.6 not supported. :("); + dwChars--; + } + else + { + break; + } + } + + // Ensure null-terminated string + wszMsgBuff[dwChars] = '\0'; + + Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: %s" HRESULT_FMT, errorMessage, wszMsgBuff, result); + } + +#if JULIET_DEBUG + String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type) + { + switch (type) + { + case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV"); + case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER"); + case D3D12_DESCRIPTOR_HEAP_TYPE_RTV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_RTV"); + case D3D12_DESCRIPTOR_HEAP_TYPE_DSV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_DSV"); + case D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES: return WrapString("Invalid"); + } + return WrapString("Invalid"); + } +#endif + + bool CheckResourceTypeTier(ID3D12Device5* device) + { + D3D12_FEATURE_DATA_D3D12_OPTIONS options = {}; + HRESULT result = + device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(D3D12_FEATURE_DATA_D3D12_OPTIONS)); + if (SUCCEEDED(result)) + { + if (options.ResourceBindingTier < D3D12_RESOURCE_BINDING_TIER_3) + { + LogError(LogCategory::Graphics, "Resource Binding Tier 3 not supported. :("); return false; } return true; } - bool CheckDriver() + LogError(LogCategory::Graphics, "Couldn't fetch D3D12_FEATURE_D3D12_OPTIONS :("); + return false; + } + + bool CheckShaderModel(ID3D12Device5* device) + { + // Check Shader Model + bool foundShaderModel = false; + D3D12_FEATURE_DATA_SHADER_MODEL shaderModel = {}; + constexpr D3D_SHADER_MODEL allModelVersions[] = { +#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 612) + D3D_SHADER_MODEL_6_9, +#endif +#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 606) + D3D_SHADER_MODEL_6_8, +#endif +#if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 3) + D3D_SHADER_MODEL_6_7, +#endif + D3D_SHADER_MODEL_6_6, D3D_SHADER_MODEL_6_5, D3D_SHADER_MODEL_6_4, D3D_SHADER_MODEL_6_3, + D3D_SHADER_MODEL_6_2, D3D_SHADER_MODEL_6_1, D3D_SHADER_MODEL_6_0, D3D_SHADER_MODEL_5_1 + }; + for (auto allModelVersion : allModelVersions) { - // Can we Load D3D12.dll and the create device function - DynamicLibrary* d3d12_dll = LoadDynamicLibrary(D3D12_DLL); - if (d3d12_dll == nullptr) + shaderModel.HighestShaderModel = allModelVersion; + HRESULT result = device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shaderModel, + sizeof(D3D12_FEATURE_DATA_SHADER_MODEL)); + if (result != E_INVALIDARG) { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); - return false; + if (FAILED(result)) + { + shaderModel.HighestShaderModel = static_cast(0); + } + else + { + foundShaderModel = true; + break; + } } + } - auto* D3D12CreateDeviceFuncPtr = - TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(d3d12_dll, D3D12_CREATEDEVICE_FUNC)); - if (D3D12CreateDeviceFuncPtr == nullptr) - { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); - UnloadDynamicLibrary(d3d12_dll); - return false; - } + if (!foundShaderModel) + { + shaderModel.HighestShaderModel = static_cast(0); + } - // Can create DXGI factory ? - IDXGIFactory1* factory1 = nullptr; - HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Cannot create DXGIFactory1"); - return false; - } + if (shaderModel.HighestShaderModel < D3D_SHADER_MODEL_6_6) + { + Juliet::LogError(LogCategory::Graphics, "Shader Model 6.6 not supported. :("); + return false; + } + return true; + } - // Can query the 1.4 factory ? - IDXGIFactory4* factory4 = nullptr; - result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&factory4)); - if (FAILED(result)) - { - factory1->Release(); - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to query DXGI1.4."); - return false; - } - factory4->Release(); + bool D3D12_CheckDriver() + { + // Can we Load D3D12.dll and the create device function + DynamicLibrary* d3d12_dll = LoadDynamicLibrary(D3D12_DLL); + if (d3d12_dll == nullptr) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); + return false; + } - // Check for 1.6. (It's not mandatory). - IDXGIAdapter1* adapter = nullptr; - IDXGIFactory6* factory6 = nullptr; - result = factory1->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); - if (SUCCEEDED(result)) - { - result = factory6->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - IID_IDXGIAdapter1, reinterpret_cast(&adapter)); - factory6->Release(); - } - else - { - result = factory1->EnumAdapters1(0, &adapter); - } + auto* D3D12CreateDeviceFuncPtr = + TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(d3d12_dll, D3D12_CREATEDEVICE_FUNC)); + if (D3D12CreateDeviceFuncPtr == nullptr) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Couldn't find function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); + UnloadDynamicLibrary(d3d12_dll); + return false; + } - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to find an adapter for D3D12."); + // Can create DXGI factory ? + IDXGIFactory1* factory1 = nullptr; + HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Cannot create DXGIFactory1"); + return false; + } - factory1->Release(); - return false; - } - - ID3D12Device5* device = nullptr; - result = D3D12CreateDeviceFuncPtr(static_cast(adapter), kD3DFeatureLevel, IID_ID3D12Device5, - reinterpret_cast(&device)); - - bool driverIsValid = true; - if (SUCCEEDED(result)) - { - driverIsValid &= CheckShaderModel(device); - driverIsValid &= CheckResourceTypeTier(device); - - device->Release(); - } - else - { - Log(LogLevel::Warning, LogCategory::Graphics, - "DX12: Failed to create a D3D12Device with feature level %s.", kD3DFeatureLevelStr); - driverIsValid = false; - } - adapter->Release(); + // Can query the 1.4 factory ? + IDXGIFactory4* factory4 = nullptr; + result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&factory4)); + if (FAILED(result)) + { factory1->Release(); + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to query DXGI1.4."); + return false; + } + factory4->Release(); - return driverIsValid; + // Check for 1.6. (It's not mandatory). + IDXGIAdapter1* adapter = nullptr; + IDXGIFactory6* factory6 = nullptr; + result = factory1->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); + if (SUCCEEDED(result)) + { + result = factory6->EnumAdapterByGpuPreference(0, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_IDXGIAdapter1, + reinterpret_cast(&adapter)); + factory6->Release(); + } + else + { + result = factory1->EnumAdapters1(0, &adapter); } - void DestroyGraphicsRootSignature(D3D12GraphicsRootSignature* rootSignature) + if (FAILED(result)) { - if (!rootSignature) - { - return; - } - if (rootSignature->Handle) - { - rootSignature->Handle->Release(); - } - Free(rootSignature); + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to find an adapter for D3D12."); + + factory1->Release(); + return false; } - D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr d3d12Driver) - { - auto d3d12GraphicsRootSignature = - static_cast(Calloc(1, sizeof(D3D12GraphicsRootSignature))); - if (!d3d12GraphicsRootSignature) - { - return nullptr; - } + ID3D12Device5* device = nullptr; + result = D3D12CreateDeviceFuncPtr(static_cast(adapter), kD3DFeatureLevel, IID_ID3D12Device5, + reinterpret_cast(&device)); - D3D12_ROOT_PARAMETER1 parameters[ToUnderlying(RootParameters::Count)] = {}; - parameters[ToUnderlying(RootParameters::Constants32Bits)] = { + bool driverIsValid = true; + if (SUCCEEDED(result)) + { + driverIsValid &= CheckShaderModel(device); + driverIsValid &= CheckResourceTypeTier(device); + + device->Release(); + } + else + { + Log(LogLevel::Warning, LogCategory::Graphics, "DX12: Failed to create a D3D12Device with feature level %s.", + kD3DFeatureLevelStr); + driverIsValid = false; + } + adapter->Release(); + factory1->Release(); + + return driverIsValid; + } + + void DestroyGraphicsRootSignature(D3D12GraphicsRootSignature* rootSignature) + { + if (!rootSignature) + { + return; + } + if (rootSignature->Handle) + { + rootSignature->Handle->Release(); + } + Free(rootSignature); + } + + D3D12GraphicsRootSignature* CreateGraphicsRootSignature(NonNullPtr d3d12Driver) + { + auto d3d12GraphicsRootSignature = + static_cast(Calloc(1, sizeof(D3D12GraphicsRootSignature))); + if (!d3d12GraphicsRootSignature) + { + return nullptr; + } + + D3D12_ROOT_PARAMETER1 parameters[ToUnderlying(RootParameters::Count)] = {}; + parameters[ToUnderlying(RootParameters::Constants32Bits)] = { .ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS, .Constants = { .ShaderRegister = 0, @@ -224,26 +1087,26 @@ namespace Juliet::D3D12 .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL }; - D3D12_STATIC_SAMPLER_DESC samplers[] = { - { - // s_nearest - .Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR, - .AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP, - .AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP, - .AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP, - .MipLODBias = 0.0f, - .MaxAnisotropy = 0, - .ComparisonFunc = D3D12_COMPARISON_FUNC_NONE, - .BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, - .MinLOD = 0.0f, - .MaxLOD = D3D12_FLOAT32_MAX, - .ShaderRegister = 0, - .RegisterSpace = 0, - .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, - }, - }; + D3D12_STATIC_SAMPLER_DESC samplers[] = { + { + // s_nearest + .Filter = D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR, + .AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP, + .AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP, + .AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP, + .MipLODBias = 0.0f, + .MaxAnisotropy = 0, + .ComparisonFunc = D3D12_COMPARISON_FUNC_NONE, + .BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK, + .MinLOD = 0.0f, + .MaxLOD = D3D12_FLOAT32_MAX, + .ShaderRegister = 0, + .RegisterSpace = 0, + .ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL, + }, + }; - D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc = { + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc = { .Version = D3D_ROOT_SIGNATURE_VERSION_1_1, .Desc_1_1 = { .NumParameters = ArraySize(parameters), @@ -256,44 +1119,42 @@ namespace Juliet::D3D12 }, }; - // Serialize the root signature - ID3DBlob* serializedRootSignature; - ID3DBlob* errorBlob; - HRESULT res = - d3d12Driver->D3D12SerializeVersionedRootSignatureFct(&rootSignatureDesc, &serializedRootSignature, &errorBlob); - if (FAILED(res)) + // Serialize the root signature + ID3DBlob* serializedRootSignature; + ID3DBlob* errorBlob; + HRESULT res = d3d12Driver->D3D12SerializeVersionedRootSignatureFct(&rootSignatureDesc, &serializedRootSignature, &errorBlob); + if (FAILED(res)) + { + if (errorBlob) { - if (errorBlob) - { - auto errorBuffer = errorBlob->GetBufferPointer(); - LogError(LogCategory::Graphics, "Failed to serialize RootSignature: %s", errorBuffer); + auto errorBuffer = errorBlob->GetBufferPointer(); + LogError(LogCategory::Graphics, "Failed to serialize RootSignature: %s", errorBuffer); - errorBlob->Release(); - } - DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); - return nullptr; + errorBlob->Release(); } - - // Create the root signature - ID3D12RootSignature* rootSignature; - res = d3d12Driver->D3D12Device->CreateRootSignature(0, serializedRootSignature->GetBufferPointer(), - serializedRootSignature->GetBufferSize(), IID_ID3D12RootSignature, - reinterpret_cast(&rootSignature)); - if (FAILED(res)) - { - if (errorBlob) - { - LogError(LogCategory::Graphics, "Failed to create RootSignature: %s", - (const char*)errorBlob->GetBufferPointer()); - errorBlob->Release(); - } - DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); - return nullptr; - } - - d3d12GraphicsRootSignature->Handle = rootSignature; - return d3d12GraphicsRootSignature; + DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); + return nullptr; } + + // Create the root signature + ID3D12RootSignature* rootSignature; + res = d3d12Driver->D3D12Device->CreateRootSignature(0, serializedRootSignature->GetBufferPointer(), + serializedRootSignature->GetBufferSize(), IID_ID3D12RootSignature, + reinterpret_cast(&rootSignature)); + if (FAILED(res)) + { + if (errorBlob) + { + LogError(LogCategory::Graphics, "Failed to create RootSignature: %s", (const char*)errorBlob->GetBufferPointer()); + errorBlob->Release(); + } + DestroyGraphicsRootSignature(d3d12GraphicsRootSignature); + return nullptr; + } + + d3d12GraphicsRootSignature->Handle = rootSignature; + return d3d12GraphicsRootSignature; + } #if JULIET_DEBUG #ifdef IDXGIINFOQUEUE_SUPPORTED @@ -301,796 +1162,3524 @@ namespace Juliet::D3D12 #define DXGIDEBUG_DLL "dxgidebug.dll" #define DXGI_GET_DEBUG_INTERFACE_FUNC "DXGIGetDebugInterface" - void InitializeDXGIDebug(NonNullPtr driver) + void InitializeDXGIDebug(NonNullPtr driver) + { + // See https://github.com/microsoft/DirectX-Graphics-Samples/blob/7aa24663f26e547a5bc437db028dfcfdb4b3c8f3/TechniqueDemos/D3D12MemoryManagement/src/Framework.cpp#L957 + // For win10 only we can just use dxgiGetDebugInterface1 + using LPDXGIGETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID, void**); + + driver->DXGIDebugDLL = LoadDynamicLibrary(DXGIDEBUG_DLL); + if (driver->DXGIDebugDLL) { - // See https://github.com/microsoft/DirectX-Graphics-Samples/blob/7aa24663f26e547a5bc437db028dfcfdb4b3c8f3/TechniqueDemos/D3D12MemoryManagement/src/Framework.cpp#L957 - // For win10 only we can just use dxgiGetDebugInterface1 - using LPDXGIGETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID, void**); + auto dxgiGetDebugInterface = + TOD3D12FuncPtr(LPDXGIGETDEBUGINTERFACE, LoadFunction(driver->DXGIDebugDLL, DXGI_GET_DEBUG_INTERFACE_FUNC)); - driver->DXGIDebugDLL = LoadDynamicLibrary(DXGIDEBUG_DLL); - if (driver->DXGIDebugDLL) + HRESULT result = dxgiGetDebugInterface(IID_IDXGIDebug, (void**)&driver->DXGIDebug); + if (FAILED(result)) { - auto dxgiGetDebugInterface = - TOD3D12FuncPtr(LPDXGIGETDEBUGINTERFACE, LoadFunction(driver->DXGIDebugDLL, DXGI_GET_DEBUG_INTERFACE_FUNC)); + Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIDebug interface"); + } - HRESULT result = dxgiGetDebugInterface(IID_IDXGIDebug, (void**)&driver->DXGIDebug); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIDebug interface"); - } - - result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&driver->DXGIInfoQueue); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIInfoQueue interface"); - } - else - { - driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); - driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); - driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE); - } + result = dxgiGetDebugInterface(IID_IDXGIInfoQueue, (void**)&driver->DXGIInfoQueue); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "Could not get IDXGIInfoQueue interface"); + } + else + { + driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); + driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); + driver->DXGIInfoQueue->SetBreakOnSeverity(DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING, TRUE); } } + } - void ShutdownDXGIDebug(NonNullPtr driver) + void ShutdownDXGIDebug(NonNullPtr driver) + { + if (driver->DXGIDebug) { - if (driver->DXGIDebug) - { - driver->DXGIDebug->ReportLiveObjects(DXGI_DEBUG_ALL, static_cast( - DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_DETAIL)); - driver->DXGIDebug->Release(); - driver->DXGIDebug = nullptr; - } - - if (driver->DXGIDebugDLL) - { - UnloadDynamicLibrary(driver->DXGIDebugDLL); - driver->DXGIDebugDLL = nullptr; - } + driver->DXGIDebug->ReportLiveObjects(DXGI_DEBUG_ALL, static_cast(DXGI_DEBUG_RLO_SUMMARY | + DXGI_DEBUG_RLO_DETAIL)); + driver->DXGIDebug->Release(); + driver->DXGIDebug = nullptr; } + + if (driver->DXGIDebugDLL) + { + UnloadDynamicLibrary(driver->DXGIDebugDLL); + driver->DXGIDebugDLL = nullptr; + } + } #endif #define D3D12_GET_DEBUG_INTERFACE_FUNC "D3D12GetDebugInterface" - void InitializeD3D12DebugLayer(NonNullPtr driver) + void InitializeD3D12DebugLayer(NonNullPtr driver) + { + auto D3D12GetDebugInterfaceFunc = + TOD3D12FuncPtr(PFN_D3D12_GET_DEBUG_INTERFACE, LoadFunction(driver->D3D12DLL, D3D12_GET_DEBUG_INTERFACE_FUNC)); + + if (D3D12GetDebugInterfaceFunc == nullptr) { - auto D3D12GetDebugInterfaceFunc = - TOD3D12FuncPtr(PFN_D3D12_GET_DEBUG_INTERFACE, LoadFunction(driver->D3D12DLL, D3D12_GET_DEBUG_INTERFACE_FUNC)); - - if (D3D12GetDebugInterfaceFunc == nullptr) - { - LogWarning(LogCategory::Graphics, "Could not load function: " D3D12_GET_DEBUG_INTERFACE_FUNC); - return; - } - - HRESULT result = D3D12GetDebugInterfaceFunc(IID_ID3D12Debug1, reinterpret_cast(&driver->D3D12Debug)); - if (FAILED(result)) - { - LogWarning(LogCategory::Graphics, "Could not get ID3D12Debug interface"); - return; - } - - driver->D3D12Debug->EnableDebugLayer(); + LogWarning(LogCategory::Graphics, "Could not load function: " D3D12_GET_DEBUG_INTERFACE_FUNC); + return; } - bool InitializeD3D12DebugInfoQueue(NonNullPtr driver) + HRESULT result = D3D12GetDebugInterfaceFunc(IID_ID3D12Debug1, reinterpret_cast(&driver->D3D12Debug)); + if (FAILED(result)) { - ID3D12InfoQueue* infoQueue = nullptr; - D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; - - HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue, reinterpret_cast(&infoQueue)); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Failed to convert ID3D12Device to ID3D12InfoQueue", result); - return false; - } - - D3D12_INFO_QUEUE_FILTER filter = {}; - filter.DenyList.NumSeverities = 1; - filter.DenyList.pSeverityList = severities; - infoQueue->PushStorageFilter(&filter); - // infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); - infoQueue->Release(); - - return true; + LogWarning(LogCategory::Graphics, "Could not get ID3D12Debug interface"); + return; } - void WINAPI OnD3D12DebugInfoMsg(D3D12_MESSAGE_CATEGORY category, D3D12_MESSAGE_SEVERITY severity, - D3D12_MESSAGE_ID id, LPCSTR description, void* /*context*/) + driver->D3D12Debug->EnableDebugLayer(); + } + + bool InitializeD3D12DebugInfoQueue(NonNullPtr driver) + { + ID3D12InfoQueue* infoQueue = nullptr; + D3D12_MESSAGE_SEVERITY severities[] = { D3D12_MESSAGE_SEVERITY_INFO }; + + HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue, reinterpret_cast(&infoQueue)); + if (FAILED(result)) { - String catStr = WrapString("UNKNOWN"); - switch (category) - { - case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: catStr = WrapString("APPLICATION_DEFINED"); break; - case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: catStr = WrapString("MISCELLANEOUS"); break; - case D3D12_MESSAGE_CATEGORY_INITIALIZATION: catStr = WrapString("INITIALIZATION"); break; - case D3D12_MESSAGE_CATEGORY_CLEANUP: catStr = WrapString("CLEANUP"); break; - case D3D12_MESSAGE_CATEGORY_COMPILATION: catStr = WrapString("COMPILATION"); break; - case D3D12_MESSAGE_CATEGORY_STATE_CREATION: catStr = WrapString("STATE_CREATION"); break; - case D3D12_MESSAGE_CATEGORY_STATE_SETTING: catStr = WrapString("STATE_SETTING"); break; - case D3D12_MESSAGE_CATEGORY_STATE_GETTING: catStr = WrapString("STATE_GETTING"); break; - case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: catStr = WrapString("RESOURCE_MANIPULATION"); break; - case D3D12_MESSAGE_CATEGORY_EXECUTION: catStr = WrapString("EXECUTION"); break; - case D3D12_MESSAGE_CATEGORY_SHADER: catStr = WrapString("SHADER"); break; - } - - String severityStr = WrapString("UNKNOWN"); - switch (severity) - { - case D3D12_MESSAGE_SEVERITY_CORRUPTION: severityStr = WrapString("CORRUPTION"); break; - case D3D12_MESSAGE_SEVERITY_ERROR: severityStr = WrapString("ERROR"); break; - case D3D12_MESSAGE_SEVERITY_WARNING: severityStr = WrapString("WARNING"); break; - case D3D12_MESSAGE_SEVERITY_INFO: severityStr = WrapString("INFO"); break; - case D3D12_MESSAGE_SEVERITY_MESSAGE: severityStr = WrapString("MESSAGE"); break; - } - - if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) - { - LogWarning(LogCategory::Graphics, "D3D12 ERROR: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); - } - else - { - LogWarning(LogCategory::Graphics, "D3D12 WARNING: %s [%s %s #%d]", description, CStr(catStr), - CStr(severityStr), id); - } - } - - void InitializeD3D12DebugInfoLogger(NonNullPtr driver) - { - // Only supported on Win 11 apparently - ID3D12InfoQueue1* infoQueue = nullptr; - HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue1, reinterpret_cast(&infoQueue)); - if (FAILED(result)) - { - return; - } - - infoQueue->RegisterMessageCallback(OnD3D12DebugInfoMsg, D3D12_MESSAGE_CALLBACK_FLAG_NONE, nullptr, nullptr); - infoQueue->Release(); - Log(LogLevel::Message, LogCategory::Graphics, "DX12: Debug Info Logger Initialized"); - } -#endif - - void DestroyDriver_Internal(NonNullPtr driver) - { - // Destroy Descriptor pools - for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) - { - if (driver->StagingDescriptorPools[i]) - { - Internal::DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); - driver->StagingDescriptorPools[i] = nullptr; - } - } - - Internal::DestroyDescriptorHeapPool(driver->SamplerHeapPool); - - // Release command buffers - for (uint32 i = 0; i < driver->AvailableCommandListCount; i += 1) - { - if (driver->AvailableCommandLists[i]) - { - Internal::DestroyCommandList(driver->AvailableCommandLists[i]); - driver->AvailableCommandLists[i] = nullptr; - } - } - - // Release fences - for (uint32 i = 0; i < driver->AvailableFenceCount; i += 1) - { - if (driver->AvailableFences[i]) - { - Internal::DestroyFence(driver->AvailableFences[i]); - driver->AvailableFences[i] = nullptr; - } - } - - DestroyGraphicsRootSignature(driver->BindlessRootSignature); - - Internal::DestroyDescriptorHeap(driver->BindlessDescriptorHeap); - - // Clean allocations - - SafeFree(driver->GraphicsPipelinesToDispose); - // Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now - - if (driver->IndirectDrawCommandSignature) - { - driver->IndirectDrawCommandSignature->Release(); - } - if (driver->IndirectIndexedDrawCommandSignature) - { - driver->IndirectIndexedDrawCommandSignature->Release(); - driver->IndirectIndexedDrawCommandSignature = nullptr; - } - if (driver->IndirectDispatchCommandSignature) - { - driver->IndirectDispatchCommandSignature->Release(); - driver->IndirectDispatchCommandSignature = nullptr; - } - - if (driver->GraphicsQueue) - { - driver->GraphicsQueue->Release(); - driver->GraphicsQueue = nullptr; - } - - if (driver->D3D12Device) - { - driver->D3D12Device->Release(); - driver->D3D12Device = nullptr; - } - - if (driver->DXGIAdapter) - { - driver->DXGIAdapter->Release(); - driver->DXGIAdapter = nullptr; - } - - if (driver->DXGIFactory) - { - driver->DXGIFactory->Release(); - driver->DXGIFactory = nullptr; - } - -#if JULIET_DEBUG - ShutdownDXGIDebug(driver); -#endif - - if (driver->D3D12DLL) - { - UnloadDynamicLibrary(driver->D3D12DLL); - driver->D3D12DLL = nullptr; - } - - driver->D3D12SerializeVersionedRootSignatureFct = nullptr; - - Assert(ArenaPos(driver->DriverArena) == sizeof(D3D12Driver)); // Verify we didnt forget to release something - ArenaRelease(driver->DriverArena); - } - - bool AttachToWindow(NonNullPtr driver, NonNullPtr window) - { - auto* d3d12Driver = static_cast(driver.Get()); - - // TODO : Support more than one window - if (d3d12Driver->WindowData) - { - Assert(false, "D3D12 renderer already attached to the window. Right now we handle only one Window."); - return false; - } - - auto* windowData = static_cast(Calloc(1, sizeof(D3D12WindowData))); - if (!windowData) - { - Log(LogLevel::Error, LogCategory::Graphics, "OOM: D3D12WindowData"); - return false; - } - d3d12Driver->WindowData = windowData; - - windowData->Window = window; - - if (!Internal::CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) - { - Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain."); - Free(windowData); - return false; - } - - d3d12Driver->WindowData = windowData; - - return true; - } - - void DetachFromWindow(NonNullPtr driver, NonNullPtr /*window*/) - { - auto* d3d12Driver = static_cast(driver.Get()); - auto* windowData = d3d12Driver->WindowData; - Assert(windowData && "Trying to destroy a swapchain but no Window Data exists"); - - WaitUntilGPUIsIdle(driver); - - for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1) - { - if (windowData->InFlightFences[idx] != nullptr) - { - ReleaseFence(driver, - windowData->InFlightFences[idx] JULIET_DEBUG_PARAM(ConstString("DeatchFromWindow"))); - windowData->InFlightFences[idx] = nullptr; - } - } - - Internal::DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); - - SafeFree(d3d12Driver->WindowData); - d3d12Driver->WindowData = nullptr; - } - - void DestroyGraphicsDevice(NonNullPtr device) - { - // Note: Its a down cast so clang suggest not to do it but we are totally sure about it. - auto* driver = static_cast(device->Driver); - DestroyDriver_Internal(driver); - Free(device.Get()); - } - - void DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr pipeline) - { - auto* d3d12Driver = static_cast(driver.Get()); - d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = - reinterpret_cast(pipeline.Get()); - d3d12Driver->GraphicsPipelinesToDisposeCount += 1; - if (d3d12Driver->GraphicsPipelinesToDisposeCount >= d3d12Driver->GraphicsPipelinesToDisposeCapacity) - { - Internal::ReleaseGraphicsPipeline(reinterpret_cast(pipeline.Get())); - } - } - - void CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, NonNullPtr src) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto* d3d12TextureContainer = reinterpret_cast(dst.Get()); - auto* d3d12Texture = d3d12TextureContainer->ActiveTexture; - - Internal::TextureTransitionFromDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); - - // Get resource desc using C++ API - D3D12_RESOURCE_DESC desc = d3d12Texture->Resource->GetDesc(); - - D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; - dstLoc.pResource = d3d12Texture->Resource; - dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - dstLoc.SubresourceIndex = 0; - - // Get buffer resource - D3D12Buffer is anonymous, access Handle directly - // The GraphicsTransferBuffer IS a D3D12Buffer internally - struct D3D12TransferBuffer - { - Internal::D3D12Descriptor Descriptor; - ID3D12Resource* Handle; - D3D12_RESOURCE_STATES CurrentState; - }; - auto* d3d12BufferSrc = reinterpret_cast(src.Get()); - - D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; - srcLoc.pResource = d3d12BufferSrc->Handle; - srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - srcLoc.PlacedFootprint.Offset = 0; - srcLoc.PlacedFootprint.Footprint.Format = desc.Format; - srcLoc.PlacedFootprint.Footprint.Width = (UINT)desc.Width; - srcLoc.PlacedFootprint.Footprint.Height = desc.Height; - srcLoc.PlacedFootprint.Footprint.Depth = 1; - - uint32 rowPitch = (uint32)desc.Width * 4; - rowPitch = (rowPitch + 255u) & ~255u; - - srcLoc.PlacedFootprint.Footprint.RowPitch = rowPitch; - - d3d12CommandList->GraphicsCommandList.CommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); - - Internal::TextureTransitionToDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); - } - - uint32 GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer) - { - auto* driver = static_cast(device->Driver); - return D3D12::GetDescriptorIndex(driver, buffer); - } - - uint32 GetDescriptorIndexTexture(NonNullPtr /*device*/, NonNullPtr texture) - { - auto* textureContainer = reinterpret_cast(texture.Get()); - return textureContainer->ActiveTexture->SRVHandle.CpuHandleIndex; - } - -#if ALLOW_SHADER_HOT_RELOAD - bool UpdateGraphicsPipelineShaders(NonNullPtr /*driver*/, NonNullPtr /*graphicsPipeline*/, - Shader* /*optional_vertexShader*/, Shader* /*optional_fragmentShader*/) - { - // Missing implementation, skipping for now + LogError(driver->D3D12Device, "Failed to convert ID3D12Device to ID3D12InfoQueue", result); return false; } -#endif - GraphicsDevice* CreateGraphicsDevice(bool enableDebug) + D3D12_INFO_QUEUE_FILTER filter = {}; + filter.DenyList.NumSeverities = 1; + filter.DenyList.pSeverityList = severities; + infoQueue->PushStorageFilter(&filter); + // infoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true); + infoQueue->Release(); + + return true; + } + + void WINAPI OnD3D12DebugInfoMsg(D3D12_MESSAGE_CATEGORY category, D3D12_MESSAGE_SEVERITY severity, + D3D12_MESSAGE_ID id, LPCSTR description, void* /*context*/) + { + String catStr = WrapString("UNKNOWN"); + switch (category) { - Arena* driverArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "D3D12 Driver Arena")); - D3D12Driver* driver = ArenaPushStruct(driverArena JULIET_DEBUG_PARAM("D3D12Driver struct")); + case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED: catStr = WrapString("APPLICATION_DEFINED"); break; + case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS: catStr = WrapString("MISCELLANEOUS"); break; + case D3D12_MESSAGE_CATEGORY_INITIALIZATION: catStr = WrapString("INITIALIZATION"); break; + case D3D12_MESSAGE_CATEGORY_CLEANUP: catStr = WrapString("CLEANUP"); break; + case D3D12_MESSAGE_CATEGORY_COMPILATION: catStr = WrapString("COMPILATION"); break; + case D3D12_MESSAGE_CATEGORY_STATE_CREATION: catStr = WrapString("STATE_CREATION"); break; + case D3D12_MESSAGE_CATEGORY_STATE_SETTING: catStr = WrapString("STATE_SETTING"); break; + case D3D12_MESSAGE_CATEGORY_STATE_GETTING: catStr = WrapString("STATE_GETTING"); break; + case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION: catStr = WrapString("RESOURCE_MANIPULATION"); break; + case D3D12_MESSAGE_CATEGORY_EXECUTION: catStr = WrapString("EXECUTION"); break; + case D3D12_MESSAGE_CATEGORY_SHADER: catStr = WrapString("SHADER"); break; + } - driver->DriverArena = driverArena; + String severityStr = WrapString("UNKNOWN"); + switch (severity) + { + case D3D12_MESSAGE_SEVERITY_CORRUPTION: severityStr = WrapString("CORRUPTION"); break; + case D3D12_MESSAGE_SEVERITY_ERROR: severityStr = WrapString("ERROR"); break; + case D3D12_MESSAGE_SEVERITY_WARNING: severityStr = WrapString("WARNING"); break; + case D3D12_MESSAGE_SEVERITY_INFO: severityStr = WrapString("INFO"); break; + case D3D12_MESSAGE_SEVERITY_MESSAGE: severityStr = WrapString("MESSAGE"); break; + } -#if JULIET_DEBUG -#ifdef IDXGIINFOQUEUE_SUPPORTED - if (enableDebug) - { - InitializeDXGIDebug(driver); - } + if (severity <= D3D12_MESSAGE_SEVERITY_ERROR) + { + LogWarning(LogCategory::Graphics, "D3D12 ERROR: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); + } + else + { + LogWarning(LogCategory::Graphics, "D3D12 WARNING: %s [%s %s #%d]", description, CStr(catStr), CStr(severityStr), id); + } + } + + void InitializeD3D12DebugInfoLogger(NonNullPtr driver) + { + // Only supported on Win 11 apparently + ID3D12InfoQueue1* infoQueue = nullptr; + HRESULT result = driver->D3D12Device->QueryInterface(IID_ID3D12InfoQueue1, reinterpret_cast(&infoQueue)); + if (FAILED(result)) + { + return; + } + + infoQueue->RegisterMessageCallback(OnD3D12DebugInfoMsg, D3D12_MESSAGE_CALLBACK_FLAG_NONE, nullptr, nullptr); + infoQueue->Release(); + Log(LogLevel::Message, LogCategory::Graphics, "DX12: Debug Info Logger Initialized"); + } #endif -#endif - IDXGIFactory1* factory1 = nullptr; - HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "DX12: Cannot create DXGIFactory1"); - return nullptr; - } - result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&driver->DXGIFactory)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "DX12: Cannot create DXGIFactory4. Need DXGI1.4 support. Weird because it has been " - "checked in CheckDriver"); - return nullptr; - } - factory1->Release(); + // Begin Shaders + Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, + ShaderCreateInfo& /*shaderCreateInfo*/ JULIET_DEBUG_PARAM(String filename)) + { + if (!IsValid(shaderByteCode)) + { + LogError(LogCategory::Graphics, "Invalid shader byte code"); + return nullptr; + } - // Query DXGI1.5 and check for monitor Tearing support - IDXGIFactory5* factory5 = nullptr; - result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory5, reinterpret_cast(&factory5)); - if (SUCCEEDED(result)) + size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size; + auto* shader = static_cast( + ArenaPushSize(driver->DriverArena, allocSize, AlignOf(D3D12Shader), + true JULIET_DEBUG_PARAM("D3D12Shader [{}] | Size [{}]", CStr(filename), shaderByteCode.Size))); + if (!shader) + { + LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory"); + return nullptr; + } + + // Uses the bytes after the struct to store the shader byte code. + shader->ByteCode.Data = reinterpret_cast(shader + 1); + shader->ByteCode.Size = shaderByteCode.Size; + MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size); + + // Make sure the data is correctly copied + if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0) + { + LogError(LogCategory::Graphics, "Memory copy failed"); + Free(shader); + return nullptr; + } + + return reinterpret_cast(shader); + } + + void DestroyShader(NonNullPtr /*driver*/, NonNullPtr /*shader*/) + { + // For now we never destroy the shader, it stays in the arena. + // If we create too many and need to switch dynamically we will need a way to release the slot for other asset + } + // End Shaders + + // Begin Graphics Pipeline + bool ConvertVertexInputState(const VertexInputState& vertexInputState, D3D12_INPUT_ELEMENT_DESC* desc, String semantic) + { + if (desc == nullptr || vertexInputState.NumVertexAttributes == 0) + { + return false; + } + + for (uint32 idx = 0; idx < vertexInputState.NumVertexAttributes; ++idx) + { + VertexAttribute attribute = vertexInputState.VertexAttributes[idx]; + + desc[idx].SemanticName = CStr(semantic); + desc[idx].SemanticIndex = attribute.Location; + desc[idx].Format = JulietToD3D12_VertexFormat[ToUnderlying(attribute.Format)]; + desc[idx].InputSlot = attribute.BufferSlot; + desc[idx].AlignedByteOffset = attribute.Offset; + desc[idx].InputSlotClass = + JulietToD3D12_InputRate[ToUnderlying(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate)]; + desc[idx].InstanceDataStepRate = + (vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate == VertexInputRate::Instance) + ? vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InstanceStepRate + : 0; + } + + return true; + } + + bool ConvertRasterizerState(const RasterizerState& rasterizerState, D3D12_RASTERIZER_DESC& desc) + { + desc.FillMode = JulietToD3D12_FillMode[ToUnderlying(rasterizerState.FillMode)]; + desc.CullMode = JulietToD3D12_CullMode[ToUnderlying(rasterizerState.CullMode)]; + + switch (rasterizerState.FrontFace) + { + case FrontFace::CounterClockwise: desc.FrontCounterClockwise = TRUE; break; + case FrontFace::Clockwise: desc.FrontCounterClockwise = FALSE; break; + default: return false; + } + static_assert(ToUnderlying(FrontFace::Count) == 2); + + if (rasterizerState.EnableDepthBias) + { + desc.DepthBias = LRoundF(rasterizerState.DepthBiasConstantFactor); + desc.DepthBiasClamp = rasterizerState.DepthBiasClamp; + desc.SlopeScaledDepthBias = rasterizerState.DepthBiasSlopeFactor; + } + else + { + desc.DepthBias = 0; + desc.DepthBiasClamp = 0.0f; + desc.SlopeScaledDepthBias = 0.0f; + } + + desc.DepthClipEnable = rasterizerState.EnableDepthClip; + desc.MultisampleEnable = FALSE; + desc.AntialiasedLineEnable = FALSE; + desc.ForcedSampleCount = 0; + desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + return true; + } + + bool ConvertBlendState(const GraphicsPipelineCreateInfo& createInfo, D3D12_BLEND_DESC& blendDesc) + { + ZeroStruct(blendDesc); + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + + for (UINT i = 0; i < GPUDriver::kMaxColorTargetInfo; 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 target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot + if (i < createInfo.TargetInfo.NumColorTargets) { - bool isTearingSupported = false; - result = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &isTearingSupported, - sizeof(isTearingSupported)); - driver->IsTearingSupported = isTearingSupported; - if (FAILED(result)) + ColorTargetBlendState blendState = createInfo.TargetInfo.ColorTargetDescriptions[i].BlendState; + ColorComponentFlags colorWriteMask = + blendState.EnableColorWriteMask ? blendState.ColorWriteMask : static_cast(0xF); + + rtBlendDesc.BlendEnable = blendState.EnableBlend; + rtBlendDesc.SrcBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.SourceColorBlendFactor)]; + rtBlendDesc.DestBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.DestinationColorBlendFactor)]; + rtBlendDesc.BlendOp = JulietToD3D12_BlendOperation[ToUnderlying(blendState.ColorBlendOperation)]; + rtBlendDesc.SrcBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.SourceAlphaBlendFactor)]; + rtBlendDesc.DestBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.DestinationAlphaBlendFactor)]; + rtBlendDesc.BlendOpAlpha = JulietToD3D12_BlendOperation[ToUnderlying(blendState.AlphaBlendOperation)]; + rtBlendDesc.RenderTargetWriteMask = ToUnderlying(colorWriteMask); + + if (i > 0) { - driver->IsTearingSupported = false; + blendDesc.IndependentBlendEnable = TRUE; } - factory5->Release(); } - // If available use DXGI1.6 to fetch the good graphics card. - // 1.6 should be available on most Win10 PC if they didnt their windows update. - // Lets support not having it for now... - IDXGIFactory6* factory6 = nullptr; - result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); - if (SUCCEEDED(result)) + blendDesc.RenderTarget[i] = rtBlendDesc; + } + + return true; + } + + bool ConvertDepthStencilState(DepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC& desc) + { + desc.DepthEnable = depthStencilState.EnableDepthTest == true ? TRUE : FALSE; + desc.DepthWriteMask = depthStencilState.EnableDepthWrite == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; + desc.DepthFunc = JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.CompareOperation)]; + desc.StencilEnable = depthStencilState.EnableStencilTest == true ? TRUE : FALSE; + desc.StencilReadMask = depthStencilState.CompareMask; + desc.StencilWriteMask = depthStencilState.WriteMask; + + desc.FrontFace.StencilFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.FailOperation)]; + desc.FrontFace.StencilDepthFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.DepthFailOperation)]; + desc.FrontFace.StencilPassOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.PassOperation)]; + desc.FrontFace.StencilFunc = + JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.FrontStencilState.CompareOperation)]; + + desc.BackFace.StencilFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.FailOperation)]; + desc.BackFace.StencilDepthFailOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.DepthFailOperation)]; + desc.BackFace.StencilPassOp = + JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.PassOperation)]; + desc.BackFace.StencilFunc = + JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.BackStencilState.CompareOperation)]; + + return true; + } + +#if ALLOW_SHADER_HOT_RELOAD + void CopyShader(NonNullPtr destination, NonNullPtr source) + { + D3D12Shader* src = source.Get(); + D3D12Shader* dst = destination.Get(); + + ByteBuffer dstBuffer = dst->ByteCode; + + if (src->ByteCode.Size != dstBuffer.Size) + { + dstBuffer.Data = static_cast(Realloc(dstBuffer.Data, src->ByteCode.Size)); + dstBuffer.Size = src->ByteCode.Size; + } + // Copy the shader data. Infortunately this will overwrite the bytecode if it exists so we patch it back just after + MemCopy(dst, src, sizeof(D3D12Shader)); + dst->ByteCode = dstBuffer; + + MemCopy(dst->ByteCode.Data, src->ByteCode.Data, src->ByteCode.Size); + } +#endif + + void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline) + { + if (d3d12GraphicsPipeline->PipelineState) + { + d3d12GraphicsPipeline->PipelineState->Release(); + } + +#if ALLOW_SHADER_HOT_RELOAD + SafeFree(d3d12GraphicsPipeline->VertexShaderCache); + SafeFree(d3d12GraphicsPipeline->FragmentShaderCache); +#endif + + Free(d3d12GraphicsPipeline.Get()); + } + + GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo) + { + auto d3d12Driver = static_cast(driver.Get()); + auto vertexShader = reinterpret_cast(createInfo.VertexShader); + auto fragmentShader = reinterpret_cast(createInfo.FragmentShader); + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; + psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; + psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; // PS == Pixel Shader == Fragment Shader + psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; + + if (createInfo.VertexInputState.NumVertexAttributes > 0) + { + D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; + psoDesc.InputLayout.pInputElementDescs = inputElementDescs; + psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes; + ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic); + } + + psoDesc.PrimitiveTopologyType = JulietToD3D12_PrimitiveTopologyType[ToUnderlying(createInfo.PrimitiveType)]; + + if (!ConvertRasterizerState(createInfo.RasterizerState, psoDesc.RasterizerState)) + { + return nullptr; + } + if (!ConvertBlendState(createInfo, psoDesc.BlendState)) + { + return nullptr; + } + if (!ConvertDepthStencilState(createInfo.DepthStencilState, psoDesc.DepthStencilState)) + { + return nullptr; + } + + auto pipeline = static_cast(Calloc(1, sizeof(D3D12GraphicsPipeline))); + if (!pipeline) + { + return nullptr; + } + + uint32 sampleMask = createInfo.MultisampleState.EnableMask ? createInfo.MultisampleState.SampleMask : 0xFFFFFFFF; + + psoDesc.SampleMask = sampleMask; + psoDesc.SampleDesc.Count = JulietToD3D12_SampleCount[ToUnderlying(createInfo.MultisampleState.SampleCount)]; + psoDesc.SampleDesc.Quality = + (createInfo.MultisampleState.SampleCount > TextureSampleCount::One) ? DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN : 0; + + psoDesc.DSVFormat = ConvertToD3D12DepthFormat(createInfo.TargetInfo.DepthStencilFormat); + psoDesc.NumRenderTargets = static_cast(createInfo.TargetInfo.NumColorTargets); + for (uint32_t idx = 0; idx < createInfo.TargetInfo.NumColorTargets; ++idx) + { + psoDesc.RTVFormats[idx] = ConvertToD3D12TextureFormat(createInfo.TargetInfo.ColorTargetDescriptions[idx].Format); + } + + // Assuming some default values or further initialization + psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; + psoDesc.CachedPSO.pCachedBlob = nullptr; + + psoDesc.NodeMask = 0; + + pipeline->RootSignature = d3d12Driver->BindlessRootSignature; + psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; + + ID3D12PipelineState* pipelineState; + HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, + reinterpret_cast(&pipelineState)); + if (FAILED(res)) + { + LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); + ReleaseGraphicsPipeline(pipeline); + return nullptr; + } + + pipeline->PipelineState = pipelineState; + + for (uint32 i = 0; i < createInfo.VertexInputState.NumVertexBufferDescriptions; i += 1) + { + pipeline->VertexStrides[createInfo.VertexInputState.VertexBufferDescriptions[i].Slot] = + createInfo.VertexInputState.VertexBufferDescriptions[i].PitchInBytes; + } + + pipeline->PrimitiveType = createInfo.PrimitiveType; + + pipeline->VertexSamplerCount = vertexShader->NumSamplers; + pipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; + pipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; + pipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; + + pipeline->FragmentSamplerCount = fragmentShader->NumSamplers; + pipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; + pipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; + pipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; + + pipeline->ReferenceCount = 0; + +#if ALLOW_SHADER_HOT_RELOAD + // Save the PSODesc and shaders to be able to recreate the graphics pipeline when needed + pipeline->PSODescTemplate = psoDesc; + + pipeline->VertexShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); + pipeline->FragmentShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); + CopyShader(pipeline->VertexShaderCache, vertexShader); + CopyShader(pipeline->FragmentShaderCache, fragmentShader); +#endif + + return reinterpret_cast(pipeline); + } + + void DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr graphicsPipeline) + { + auto d3d12Driver = static_cast(driver.Get()); + auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get()); + + if (d3d12Driver->GraphicsPipelinesToDisposeCount + 1 >= d3d12Driver->GraphicsPipelinesToDisposeCapacity) + { + d3d12Driver->GraphicsPipelinesToDisposeCapacity = d3d12Driver->GraphicsPipelinesToDisposeCapacity * 2; + d3d12Driver->GraphicsPipelinesToDispose = static_cast( + Realloc(d3d12Driver->GraphicsPipelinesToDispose, + sizeof(D3D12GraphicsPipeline*) * d3d12Driver->GraphicsPipelinesToDisposeCapacity)); + } + d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = d3d12GraphicsPipeline; + d3d12Driver->GraphicsPipelinesToDisposeCount += 1; + } + +#if ALLOW_SHADER_HOT_RELOAD + bool UpdateGraphicsPipelineShaders(NonNullPtr driver, NonNullPtr graphicsPipeline, + Shader* optional_vertexShader, Shader* optional_fragmentShader) + { + auto d3d12Driver = static_cast(driver.Get()); + auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get()); + + Assert(d3d12GraphicsPipeline->ReferenceCount == 0 && + "Trying to update a d3d12 graphics pipeline that is currently being used! Call WaitUntilGPUIsIdle " + "before updating!"); + + auto vertexShader = reinterpret_cast(optional_vertexShader); + auto fragmentShader = reinterpret_cast(optional_fragmentShader); + + if (!vertexShader) + { + vertexShader = d3d12GraphicsPipeline->VertexShaderCache; + } + + if (!fragmentShader) + { + fragmentShader = d3d12GraphicsPipeline->FragmentShaderCache; + } + + auto psoDesc = d3d12GraphicsPipeline->PSODescTemplate; + psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; + psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; + psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; + psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; + + psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; + + ID3D12PipelineState* pipelineState; + HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, + reinterpret_cast(&pipelineState)); + if (FAILED(res)) + { + LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); + return false; + } + + d3d12GraphicsPipeline->VertexSamplerCount = vertexShader->NumSamplers; + d3d12GraphicsPipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; + d3d12GraphicsPipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; + d3d12GraphicsPipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; + + d3d12GraphicsPipeline->FragmentSamplerCount = fragmentShader->NumSamplers; + d3d12GraphicsPipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; + d3d12GraphicsPipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; + d3d12GraphicsPipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; + + // If everything worked, we patch the graphics pipeline and destroy everything irrelevant + if (d3d12GraphicsPipeline->PipelineState) + { + d3d12GraphicsPipeline->PipelineState->Release(); + } + d3d12GraphicsPipeline->PipelineState = pipelineState; + + if (vertexShader != d3d12GraphicsPipeline->VertexShaderCache) + { + CopyShader(d3d12GraphicsPipeline->VertexShaderCache, vertexShader); + } + if (fragmentShader != d3d12GraphicsPipeline->FragmentShaderCache) + { + CopyShader(d3d12GraphicsPipeline->FragmentShaderCache, fragmentShader); + } + + return true; + } +#endif + + // End Graphics Pipeline + + // Begin Descriptor Heap + void DestroyDescriptorHeap(NonNullPtr heap) + { + heap->FreeIndices.Destroy(); + if (heap->Handle) + { + heap->Handle->Release(); + } + } + + D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging) + { + D3D12DescriptorHeap* heap = ArenaPushStruct( + driver->DriverArena JULIET_DEBUG_PARAM("Descriptor Heap Type {}", CStr(GetDescriptorTypeNane(type)))); + Assert(heap); + + heap->CurrentDescriptorIndex = 0; + + heap->FreeIndices.Create(driver->DriverArena JULIET_DEBUG_PARAM("DescriptorHeap Free Indices")); + heap->FreeIndices.Resize(16); + heap->CurrentFreeIndex = 0; + + D3D12_DESCRIPTOR_HEAP_DESC heapDesc; + heapDesc.NumDescriptors = count; + heapDesc.Type = type; + heapDesc.Flags = isStaging ? D3D12_DESCRIPTOR_HEAP_FLAG_NONE : D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + heapDesc.NodeMask = 0; + + ID3D12DescriptorHeap* handle; + HRESULT result = + driver->D3D12Device->CreateDescriptorHeap(&heapDesc, IID_ID3D12DescriptorHeap, reinterpret_cast(&handle)); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Failed to create descriptor heap!", result); + DestroyDescriptorHeap(heap); + return nullptr; + } + + heap->Handle = handle; + heap->HeapType = type; + heap->MaxDescriptors = count; + heap->Staging = isStaging; + heap->DescriptorSize = driver->D3D12Device->GetDescriptorHandleIncrementSize(type); + heap->DescriptorHeapCPUStart = handle->GetCPUDescriptorHandleForHeapStart(); + if (!isStaging) + { + heap->DescriptorHeapGPUStart = handle->GetGPUDescriptorHandleForHeapStart(); + } + + return heap; + } + + void CreateDescriptorHeapPool(NonNullPtr driver, D3D12DescriptorHeapPool& heapPool, + D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count) + { + // Heap pool is just single linked list of free elements + constexpr size_t kInitialCapacity = 4; + heapPool.FirstFreeDescriptorHeap = nullptr; + + // Pre allocate 4 + for (uint32 i = 0; i < kInitialCapacity; ++i) + { + D3D12DescriptorHeap* descriptorHeap = CreateDescriptorHeap(driver, type, count, false); + descriptorHeap->Next = heapPool.FirstFreeDescriptorHeap; + heapPool.FirstFreeDescriptorHeap = descriptorHeap; + } + } + + void D3D12_DestroyDescriptorHeapPool(D3D12DescriptorHeapPool& heapPool) + { + D3D12DescriptorHeap* current = heapPool.FirstFreeDescriptorHeap; + while (current != nullptr) + { + D3D12DescriptorHeap* next = current->Next; + DestroyDescriptorHeap(current); + current = next; + } + } + + bool AssignDescriptor(D3D12DescriptorHeap* heap, D3D12Descriptor& outDescriptor) + { + uint32 index = UINT32_MAX; + + if (heap->CurrentFreeIndex > 0) + { + heap->CurrentFreeIndex -= 1; + index = heap->FreeIndices[heap->CurrentFreeIndex]; + } + else if (heap->CurrentDescriptorIndex < heap->MaxDescriptors) + { + index = heap->CurrentDescriptorIndex; + heap->CurrentDescriptorIndex++; + } + else + { + Assert(false, "Descriptor Heap Full!"); + return false; + } + + outDescriptor.Heap = heap; + outDescriptor.Index = index; + outDescriptor.CpuHandle = heap->DescriptorHeapCPUStart; + outDescriptor.CpuHandle.ptr += heap->DescriptorSize * index; + outDescriptor.GpuHandle = heap->DescriptorHeapGPUStart; + outDescriptor.GpuHandle.ptr += heap->DescriptorSize * index; + + return true; + } + + void ReleaseDescriptor(const D3D12Descriptor& descriptor) + { + if (descriptor.Index == UINT32_MAX || descriptor.Heap == nullptr) + { + return; + } + + D3D12DescriptorHeap* heap = descriptor.Heap; + + if (heap->CurrentFreeIndex >= heap->FreeIndices.Count) + { + heap->FreeIndices.PushBack(descriptor.Index); + } + else + { + heap->FreeIndices[heap->CurrentFreeIndex] = descriptor.Index; + heap->CurrentFreeIndex++; + } + } + + D3D12DescriptorHeap* AcquireSamplerHeapFromPool(NonNullPtr d3d12Driver) + { + D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; + + D3D12DescriptorHeap* result = pool.FirstFreeDescriptorHeap; + if (result) + { + pool.FirstFreeDescriptorHeap = pool.FirstFreeDescriptorHeap->Next; + } + else + { + result = CreateDescriptorHeap(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + GPUDriver::kSampler_HeapDescriptorCount, false); + } + + return result; + } + + void ReturnSamplerHeapToPool(NonNullPtr d3d12Driver, NonNullPtr heap) + { + D3D12DescriptorHeapPool& pool = d3d12Driver->SamplerHeapPool; + + heap->CurrentDescriptorIndex = 0; + + heap->Next = pool.FirstFreeDescriptorHeap; + pool.FirstFreeDescriptorHeap = heap; + } + // End Descriptor Heap + + // Begin Staging Descriptors + void InitStagingDescriptorPool(NonNullPtr heap, NonNullPtr pool) + { + for (uint32 idx = 0; idx < kStagingHeapDescriptorExpectedCount; ++idx) + { + pool->FreeDescriptors[idx].Pool = pool; + pool->FreeDescriptors[idx].Heap = heap.Get(); + pool->FreeDescriptors[idx].CpuHandleIndex = idx; + pool->FreeDescriptors[idx].CpuHandle.ptr = heap->DescriptorHeapCPUStart.ptr + (idx * heap->DescriptorSize); + } + } + + bool ExtendStagingDescriptorPool(NonNullPtr driver, D3D12StagingDescriptorPool& pool) + { + D3D12DescriptorHeap* heap = + CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); + if (!heap) + { + return false; + } + + pool.HeapCount += 1; + pool.Heaps = static_cast(Realloc(pool.Heaps, pool.HeapCount * sizeof(D3D12DescriptorHeap*))); + pool.Heaps[pool.HeapCount - 1] = heap; + + pool.FreeDescriptorCapacity += kStagingHeapDescriptorExpectedCount; + pool.FreeDescriptorCount += kStagingHeapDescriptorExpectedCount; + pool.FreeDescriptors = static_cast( + Realloc(pool.FreeDescriptors, pool.FreeDescriptorCapacity * sizeof(D3D12StagingDescriptor))); + + InitStagingDescriptorPool(heap, &pool); + + return true; + } + + D3D12StagingDescriptorPool* CreateStagingDescriptorPool(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type) + { + D3D12DescriptorHeap* heap = CreateDescriptorHeap(driver, type, kStagingHeapDescriptorExpectedCount, true); + if (!heap) + { + return nullptr; + } + + auto pool = static_cast(Calloc(1, sizeof(D3D12StagingDescriptorPool))); + + // First create the heaps + pool->HeapCount = 1; + pool->Heaps = static_cast(Malloc(sizeof(D3D12DescriptorHeap*))); + pool->Heaps[0] = heap; + + pool->FreeDescriptorCapacity = kStagingHeapDescriptorExpectedCount; + pool->FreeDescriptorCount = kStagingHeapDescriptorExpectedCount; + pool->FreeDescriptors = + static_cast(Malloc(kStagingHeapDescriptorExpectedCount * sizeof(D3D12StagingDescriptor))); + + InitStagingDescriptorPool(heap, pool); + + return pool; + } + + bool AssignStagingDescriptor(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, D3D12StagingDescriptor& outDescriptor) + { + // TODO: Make it thread safe + D3D12StagingDescriptor* descriptor = nullptr; + D3D12StagingDescriptorPool* pool = driver->StagingDescriptorPools[type]; + + if (pool->FreeDescriptorCount == 0) + { + if (!ExtendStagingDescriptorPool(driver, *pool)) { - // TODO: Put into the config - static constexpr bool useLowPower = false; - result = factory6->EnumAdapterByGpuPreference(0, useLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, - IID_IDXGIAdapter1, reinterpret_cast(&driver->DXGIAdapter)); - factory6->Release(); + return false; + } + } + + descriptor = &pool->FreeDescriptors[pool->FreeDescriptorCount - 1]; + MemCopy(&outDescriptor, descriptor, sizeof(D3D12StagingDescriptor)); + pool->FreeDescriptorCount -= 1; + + return true; + } + + void ReleaseStagingDescriptor(NonNullPtr /*driver*/, D3D12StagingDescriptor& cpuDescriptor) + { + D3D12StagingDescriptorPool* pool = cpuDescriptor.Pool; + + if (pool != nullptr) + { + MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor)); + pool->FreeDescriptorCount += 1; + } + } + + void DestroyStagingDescriptorPool(NonNullPtr pool) + { + for (uint32 i = 0; i < pool->HeapCount; i += 1) + { + DestroyDescriptorHeap(pool->Heaps[i]); + } + + Free(pool->Heaps); + Free(pool->FreeDescriptors); + + Free(pool.Get()); + } + // End Staging Descriptors + + // Begin Buffers + // Linked List of free buffers + D3D12Buffer* FreeBuffers = nullptr; + + enum class D3D12BufferType : uint8 + { + Base, + TransferDownload, + TransferUpload, + }; + + [[nodiscard]] const char* D3D12BufferTypeToString(D3D12BufferType type) + { + switch (type) + { + case D3D12BufferType::Base: return "Base"; + case D3D12BufferType::TransferDownload: return "TransferDownload"; + case D3D12BufferType::TransferUpload: return "TransferUpload"; + } + return "Unknown"; + } + + [[nodiscard]] const char* BufferUsageToString(BufferUsage usage) + { + switch (usage) + { + case BufferUsage::None: return "None"; + case BufferUsage::ConstantBuffer: return "ConstantBuffer"; + case BufferUsage::StructuredBuffer: return "StructuredBuffer"; + case BufferUsage::IndexBuffer: return "IndexBuffer"; + } + return "Unknown"; + } + + void DestroyBuffer(D3D12Buffer* buffer) + { + if (!buffer) + { + return; + } + + if (buffer->Descriptor.Index != UINT32_MAX) + { + ReleaseDescriptor(buffer->Descriptor); + } + buffer->Descriptor = {}; + + if (buffer->Handle) + { + buffer->Handle->Release(); + buffer->Handle = nullptr; + } + buffer->CurrentState = D3D12_RESOURCE_STATE_COMMON; + buffer->Size = 0; + + buffer->Next = FreeBuffers; + FreeBuffers = buffer; + } + + D3D12Buffer* CreateBuffer(NonNullPtr d3d12Driver, size_t size, size_t stride, BufferUsage usage, + D3D12BufferType type, bool isDynamic) + { + D3D12Buffer* buffer = nullptr; + if (FreeBuffers) + { + buffer = FreeBuffers; + FreeBuffers = buffer->Next; + buffer->Next = nullptr; + } + + if (!buffer) + { + buffer = ArenaPushStruct(d3d12Driver->DriverArena JULIET_DEBUG_PARAM("D3D12Buffer")); + } + + if (!buffer) + { + return nullptr; + } + + if (type == D3D12BufferType::Base && usage == BufferUsage::None) + { + Assert(false, "Creating Base buffer with BufferUsage::None is invalid"); + DestroyBuffer(buffer); + return nullptr; + } + + // Align size for Constant Buffers + if (usage == BufferUsage::ConstantBuffer) + { + size = (size + 255U) & ~255U; + } + + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON; + D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE; + + // Constant buffers or Dynamic buffers generally need to be uploaded every frame + const bool isUpload = isDynamic || (type == D3D12BufferType::TransferUpload) || (usage == BufferUsage::ConstantBuffer); + + if (type == D3D12BufferType::TransferDownload) + { + heapProperties.Type = D3D12_HEAP_TYPE_READBACK; + initialState = D3D12_RESOURCE_STATE_COPY_DEST; + } + else if (isUpload) + { + if (d3d12Driver->GPUUploadHeapSupported) + { + heapProperties.Type = D3D12_HEAP_TYPE_GPU_UPLOAD; + initialState = D3D12_RESOURCE_STATE_COMMON; } else { - result = driver->DXGIFactory->EnumAdapters1(0, &driver->DXGIAdapter); + heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; + initialState = D3D12_RESOURCE_STATE_GENERIC_READ; } - - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "Could not find adapter for D3D12Device"); - return nullptr; - } - - // Adapter is setup, get all the relevant info in the descriptor - DXGI_ADAPTER_DESC1 adapterDesc; - result = driver->DXGIAdapter->GetDesc1(&adapterDesc); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "Could not get DXGIAdapter description"); - return nullptr; - } - - // Driver version - LARGE_INTEGER umdVersion; - result = driver->DXGIAdapter->CheckInterfaceSupport(IID_IDXGIDevice, &umdVersion); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Assert(false, "Could not get DXGIAdapter driver version"); - return nullptr; - } - - Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Infos:"); - Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Adapter: %S", adapterDesc.Description); - Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Version: %d.%d.%d.%d", HIWORD(umdVersion.HighPart), - LOWORD(umdVersion.HighPart), HIWORD(umdVersion.LowPart), LOWORD(umdVersion.LowPart)); - - driver->D3D12DLL = LoadDynamicLibrary(D3D12_DLL); - if (driver->D3D12DLL == nullptr) - { - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); - return nullptr; - } - - auto* D3D12CreateDeviceFuncPtr = - TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(driver->D3D12DLL, D3D12_CREATEDEVICE_FUNC)); - if (D3D12CreateDeviceFuncPtr == nullptr) - { - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't Load function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); - DestroyDriver_Internal(driver); - return nullptr; - } - - driver->D3D12SerializeVersionedRootSignatureFct = - TOD3D12FuncPtr(PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE, - LoadFunction(driver->D3D12DLL, D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC)); - if (driver->D3D12SerializeVersionedRootSignatureFct == nullptr) - { - Log(LogLevel::Error, LogCategory::Graphics, - "DX12: Couldn't Load function " D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC " in " D3D12_DLL); - DestroyDriver_Internal(driver); - return nullptr; - } - -#if JULIET_DEBUG - if (enableDebug) - { - InitializeD3D12DebugLayer(driver); - } -#endif - - result = D3D12CreateDeviceFuncPtr(static_cast(driver->DXGIAdapter), kD3DFeatureLevel, - IID_ID3D12Device5, reinterpret_cast(&driver->D3D12Device)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12Device5"); - return nullptr; - } - - Log(LogLevel::Message, LogCategory::Graphics, "DX12: D3D12Device Created: %p", (void*)driver->D3D12Device); - -#if JULIET_DEBUG - if (enableDebug) - { - if (!InitializeD3D12DebugInfoQueue(driver)) - { - return nullptr; - } - InitializeD3D12DebugInfoLogger(driver); - } -#endif - - // Check if UMA (unified memory architecture) is available. Used on APU i think ?? - D3D12_FEATURE_DATA_ARCHITECTURE architecture; - architecture.NodeIndex = 0; - result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &architecture, - sizeof(D3D12_FEATURE_DATA_ARCHITECTURE)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not get the device architecture"); - return nullptr; - } - driver->IsUMAAvailable = architecture.UMA; - driver->IsUMACacheCoherent = architecture.CacheCoherentUMA; - - // Check "GPU Upload Heap" support (for fast uniform buffers. Not supported on my 5700xt - D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16; - driver->GPUUploadHeapSupported = false; - result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &options16, sizeof(options16)); - if (SUCCEEDED(result)) - { - driver->GPUUploadHeapSupported = options16.GPUUploadHeapSupported; - } - - // Create bindless root signature - driver->BindlessRootSignature = CreateGraphicsRootSignature(driver); - - // Command Queues - // Graphics Queue only for now - D3D12_COMMAND_QUEUE_DESC queueDesc = {}; - queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - queueDesc.NodeMask = 0; - queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; - result = driver->D3D12Device->CreateCommandQueue(&queueDesc, IID_ID3D12CommandQueue, - reinterpret_cast(&driver->GraphicsQueue)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12CommandQueue: Graphics"); - return nullptr; - } - driver->GraphicsQueue->SetName(L"GRAPHICS_QUEUE"); - driver->QueueDesc[ToUnderlying(QueueType::Graphics)] = queueDesc; - - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; - driver->QueueDesc[ToUnderlying(QueueType::Compute)] = queueDesc; - - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; - driver->QueueDesc[ToUnderlying(QueueType::Copy)] = queueDesc; - - // Indirect Commands - D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc; - D3D12_INDIRECT_ARGUMENT_DESC indirectArgumentDesc; - ZeroStruct(indirectArgumentDesc); - - indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; - commandSignatureDesc.NodeMask = 0; - commandSignatureDesc.ByteStride = sizeof(IndirectDrawCommand); - commandSignatureDesc.NumArgumentDescs = 1; - commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; - result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, - reinterpret_cast(&driver->IndirectDrawCommandSignature)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create indirect draw command signature"); - return nullptr; - } - - indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; - commandSignatureDesc.ByteStride = sizeof(IndexedIndirectDrawCommand); - commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; - - result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, - reinterpret_cast(&driver->IndirectIndexedDrawCommandSignature)); - if (FAILED(result)) - { - - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create INDEXED Indirect draw command signature"); - return nullptr; - } - - indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; - commandSignatureDesc.ByteStride = sizeof(IndirectDispatchCommand); - commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; - - result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, - reinterpret_cast(&driver->IndirectDispatchCommandSignature)); - if (FAILED(result)) - { - DestroyDriver_Internal(driver); - Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create Indirect dispatch command signature"); - return nullptr; - } - - // Create Pools - constexpr static size_t kMaxCommandListNumber = 16; - driver->SubmittedCommandListCapacity = kMaxCommandListNumber; - driver->SubmittedCommandListCount = 0; - driver->SubmittedCommandLists = ArenaPushArray( - driver->DriverArena, - kMaxCommandListNumber JULIET_DEBUG_PARAM("Command list Ptr Array Count: {}", kMaxCommandListNumber)); - if (!driver->SubmittedCommandLists) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - constexpr static size_t kMaxFencesNumber = 16; - driver->AvailableFenceCapacity = kMaxFencesNumber; - driver->AvailableFenceCount = 0; - driver->AvailableFences = - ArenaPushArray(driver->DriverArena, - kMaxFencesNumber JULIET_DEBUG_PARAM("Fence Ptr Array Count: {}", kMaxFencesNumber)); - if (!driver->AvailableFences) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - // Staging descriptor pools - for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) - { - driver->StagingDescriptorPools[i] = - Internal::CreateStagingDescriptorPool(driver, static_cast(i)); - - if (driver->StagingDescriptorPools[i] == nullptr) - { - DestroyDriver_Internal(driver); - return nullptr; - } - } - - CreateDescriptorHeapPool(driver, driver->SamplerHeapPool, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, - GPUDriver::kSampler_HeapDescriptorCount); - - // Deferred dispose vectors - driver->GraphicsPipelinesToDisposeCapacity = 4; - driver->GraphicsPipelinesToDisposeCount = 0; - driver->GraphicsPipelinesToDispose = static_cast( - Calloc(driver->GraphicsPipelinesToDisposeCapacity, sizeof(D3D12GraphicsPipeline*))); - if (!driver->GraphicsPipelinesToDispose) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - driver->Semantic = WrapString("TEXCOORD"); - driver->FramesInFlight = 2; - - auto device = static_cast(Calloc(1, sizeof(GraphicsDevice))); - if (!device) - { - DestroyDriver_Internal(driver); - return nullptr; - } - - // Assign Functions to the device - device->DestroyDevice = DestroyGraphicsDevice; - device->AttachToWindow = AttachToWindow; - device->DetachFromWindow = DetachFromWindow; - device->AcquireSwapChainTexture = AcquireSwapChainTexture; - device->WaitAndAcquireSwapChainTexture = WaitAndAcquireSwapChainTexture; - device->GetSwapChainTextureFormat = GetSwapChainTextureFormat; - device->AcquireCommandList = AcquireCommandList; - device->SubmitCommandLists = SubmitCommandLists; - device->BeginRenderPass = BeginRenderPass; - device->EndRenderPass = EndRenderPass; - device->SetViewPort = SetViewPort; - device->SetScissorRect = SetScissorRect; - device->SetBlendConstants = SetBlendConstants; - device->SetStencilReference = SetStencilReference; - device->BindGraphicsPipeline = BindGraphicsPipeline; - device->DrawPrimitives = DrawPrimitives; - device->DrawIndexedPrimitives = DrawIndexedPrimitives; - device->SetIndexBuffer = SetIndexBuffer; - device->WaitUntilGPUIsIdle = WaitUntilGPUIsIdle; - device->SetPushConstants = SetPushConstants; - device->QueryFence = QueryFence; - device->ReleaseFence = ReleaseFence; - device->CreateShader = CreateShader; - device->DestroyShader = DestroyShader; - device->CreateGraphicsPipeline = CreateGraphicsPipeline; - device->DestroyGraphicsPipeline = DestroyGraphicsPipeline; - device->CreateGraphicsBuffer = CreateGraphicsBuffer; - device->DestroyGraphicsBuffer = DestroyGraphicsBuffer; - device->MapGraphicsBuffer = MapBuffer; - device->UnmapGraphicsBuffer = UnmapBuffer; - device->CreateGraphicsTransferBuffer = CreateGraphicsTransferBuffer; - device->DestroyGraphicsTransferBuffer = DestroyGraphicsTransferBuffer; - device->MapGraphicsTransferBuffer = MapBuffer; - device->UnmapGraphicsTransferBuffer = UnmapBuffer; - device->CopyBuffer = CopyBuffer; - device->CopyBufferToTexture = CopyBufferToTexture; - device->TransitionBufferToReadable = TransitionBufferToReadable; - device->GetDescriptorIndex = GetDescriptorIndex; - device->GetDescriptorIndexTexture = GetDescriptorIndexTexture; - device->CreateTexture = CreateTexture; - device->DestroyTexture = DestroyTexture; - -#if ALLOW_SHADER_HOT_RELOAD - device->UpdateGraphicsPipelineShaders = UpdateGraphicsPipelineShaders; -#endif - - device->Driver = driver; - device->DebugEnabled = enableDebug; - - driver->GraphicsDevice = device; - - // Create Global Bindless Heap that stays alive for the driver whole lifetime - driver->BindlessDescriptorHeap = Internal::CreateDescriptorHeap(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, - GPUDriver::kCBV_SRV_UAV_HeapDescriptorCount, false); - - return device; } - } // namespace - - namespace Internal - { - void DisposePendingResourcces(NonNullPtr driver) + else { - // TODO Destroy anything (buffer, texture, etc...) - uint32 idx = 0; - while (idx < driver->GraphicsPipelinesToDisposeCount) - { - if (driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0) - { - ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]); + // Must be a static buffer (Base type) + heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT; + initialState = D3D12_RESOURCE_STATE_COMMON; + } - driver->GraphicsPipelinesToDispose[idx] = - driver->GraphicsPipelinesToDispose[driver->GraphicsPipelinesToDisposeCount - 1]; - driver->GraphicsPipelinesToDisposeCount -= 1; + D3D12_RESOURCE_DESC desc = {}; + desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + desc.Alignment = 0; + 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 = D3D12_RESOURCE_FLAG_NONE; + + Log(LogLevel::Message, LogCategory::Graphics, "CreateBuffer: Device=%p, Size=%zu, Type=%s Use=%s", + (void*)d3d12Driver->D3D12Device, size, D3D12BufferTypeToString(type), BufferUsageToString(usage)); + + ID3D12Resource* handle = nullptr; + HRESULT result = + d3d12Driver->D3D12Device->CreateCommittedResource(&heapProperties, heapFlags, &desc, initialState, nullptr, + IID_ID3D12Resource, reinterpret_cast(&handle)); + + if (FAILED(result)) + { + Log(LogLevel::Error, LogCategory::Graphics, "Could not create buffer! HRESULT=0x%08X", static_cast(result)); + Log(LogLevel::Error, LogCategory::Graphics, "Failed Desc: Width=%llu Layout=%d HeapType=%d", + (unsigned long long)desc.Width, (int)desc.Layout, (int)heapProperties.Type); + + HRESULT removeReason = d3d12Driver->D3D12Device->GetDeviceRemovedReason(); + if (FAILED(removeReason)) + { + Log(LogLevel::Error, LogCategory::Graphics, "Device Removed Reason: 0x%08X", static_cast(removeReason)); + } + + DestroyBuffer(buffer); + return nullptr; + } + + buffer->Handle = handle; + buffer->CurrentState = initialState; + buffer->Descriptor.Index = UINT32_MAX; + buffer->Size = size; + + if (usage == BufferUsage::ConstantBuffer || usage == BufferUsage::StructuredBuffer) + { + auto& heap = d3d12Driver->BindlessDescriptorHeap; + + D3D12Descriptor descriptor; + if (AssignDescriptor(heap, descriptor)) + { + buffer->Descriptor = descriptor; + + D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = descriptor.CpuHandle; + + if (usage == BufferUsage::ConstantBuffer) + { + D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {}; + cbvDesc.BufferLocation = handle->GetGPUVirtualAddress(); + cbvDesc.SizeInBytes = static_cast(size); + d3d12Driver->D3D12Device->CreateConstantBufferView(&cbvDesc, cpuHandle); + } + else if (usage == BufferUsage::StructuredBuffer) + { + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.Buffer.FirstElement = 0; + + if (stride > 0) + { + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.NumElements = static_cast(size / stride); + srvDesc.Buffer.StructureByteStride = static_cast(stride); + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + } + else + { + srvDesc.Format = DXGI_FORMAT_R32_TYPELESS; + srvDesc.Buffer.NumElements = static_cast(size / 4); + srvDesc.Buffer.StructureByteStride = 0; + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; + } + + d3d12Driver->D3D12Device->CreateShaderResourceView(handle, &srvDesc, cpuHandle); + Log(LogLevel::Message, LogCategory::Graphics, " -> SRV DescriptorIndex=%u", descriptor.Index); + } + } + else + { + LogError(LogCategory::Graphics, "Bindless Heap Full or Invalid!"); + } + } + + return buffer; + } + + GraphicsBuffer* CreateGraphicsBuffer(NonNullPtr driver, size_t size, size_t stride, BufferUsage usage, bool isDynamic) + { + auto d3d12Driver = static_cast(driver.Get()); + return reinterpret_cast(CreateBuffer(d3d12Driver, size, stride, usage, D3D12BufferType::Base, isDynamic)); + } + + void DestroyGraphicsBuffer(NonNullPtr buffer) + { + DestroyBuffer(reinterpret_cast(buffer.Get())); + } + + GraphicsTransferBuffer* CreateGraphicsTransferBuffer(NonNullPtr driver, size_t size, TransferBufferUsage usage) + { + auto d3d12Driver = static_cast(driver.Get()); + return reinterpret_cast( + CreateBuffer(d3d12Driver, size, 0, BufferUsage::None, + usage == TransferBufferUsage::Upload ? D3D12BufferType::TransferUpload : D3D12BufferType::TransferDownload, + false)); + } + + void DestroyGraphicsTransferBuffer(NonNullPtr buffer) + { + DestroyBuffer(reinterpret_cast(buffer.Get())); + } + + void* MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + void* ptr = nullptr; + + // 0-0 range means we don't intend to read anything. + D3D12_RANGE readRange = { 0, 0 }; + if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) + { + return nullptr; + } + return ptr; + } + + void UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + d3d12Buffer->Handle->Unmap(0, nullptr); + } + + void* MapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + void* ptr = nullptr; + D3D12_RANGE readRange = { 0, 0 }; + if (FAILED(d3d12Buffer->Handle->Map(0, &readRange, &ptr))) + { + return nullptr; + } + return ptr; + } + + void UnmapBuffer(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + d3d12Buffer->Handle->Unmap(0, nullptr); + } + + uint32 GetDescriptorIndex(NonNullPtr /*driver*/, NonNullPtr buffer) + { + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + return d3d12Buffer->Descriptor.Index; + } + + void D3D12_CopyBuffer(NonNullPtr commandList, NonNullPtr dst, + NonNullPtr src, size_t size, size_t dstOffset, size_t srcOffset) + { + auto d3d12CmdList = reinterpret_cast(commandList.Get()); + auto d3d12Dst = reinterpret_cast(dst.Get()); + auto d3d12Src = reinterpret_cast(src.Get()); + + // Transition DST to COPY_DEST if needed + if (d3d12Dst->CurrentState != D3D12_RESOURCE_STATE_COPY_DEST) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = d3d12Dst->Handle; + barrier.Transition.StateBefore = d3d12Dst->CurrentState; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); + d3d12Dst->CurrentState = D3D12_RESOURCE_STATE_COPY_DEST; + } + + // Src is Upload Buffer, usually effectively GenericRead/Common but for Upload heaps it's simpler. + // We assume Upload buffers are always in state GENERIC_READ or similar suitable for CopySrc. + // D3D12 Upload heaps start in GENERIC_READ and cannot transition. + + d3d12CmdList->GraphicsCommandList.CommandList->CopyBufferRegion(d3d12Dst->Handle, dstOffset, d3d12Src->Handle, + srcOffset, size); + } + + void D3D12_TransitionBufferToReadable(NonNullPtr commandList, NonNullPtr buffer) + { + auto d3d12CmdList = reinterpret_cast(commandList.Get()); + auto d3d12Buffer = reinterpret_cast(buffer.Get()); + + D3D12_RESOURCE_STATES neededState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + + if (d3d12Buffer->CurrentState != neededState) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = d3d12Buffer->Handle; + barrier.Transition.StateBefore = d3d12Buffer->CurrentState; + barrier.Transition.StateAfter = neededState; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CmdList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); + d3d12Buffer->CurrentState = neededState; + } + } + // End Buffers + + // Begin Fences + void DisposePendingResourcces(NonNullPtr driver) + { + // TODO Destroy anything (buffer, texture, etc...) + uint32 idx = 0; + while (idx < driver->GraphicsPipelinesToDisposeCount) + { + if (driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0) + { + ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]); + + driver->GraphicsPipelinesToDispose[idx] = + driver->GraphicsPipelinesToDispose[driver->GraphicsPipelinesToDisposeCount - 1]; + driver->GraphicsPipelinesToDisposeCount -= 1; + } + else + { + idx++; + } + } + } + + void ReleaseFenceToPool(NonNullPtr driver, NonNullPtr fence) + { + Assert(driver->AvailableFenceCount + 1 <= driver->AvailableFenceCapacity); + + driver->AvailableFences[driver->AvailableFenceCount] = fence; + driver->AvailableFenceCount += 1; + + LogDebug(LogCategory::Graphics, "ReleaseFenceToPool %x fence. Handle %x | Event %x | Refcount %d", fence.Get(), + fence->Handle, fence->Event, fence->ReferenceCount); + } + + void ReleaseFence(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)) + { + auto d3d12driver = static_cast(driver.Get()); + auto d3d12Fence = reinterpret_cast(fence.Get()); + +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "ReleaseFence | %x fence. Handle %x | Event %x | Refcount %d | Querier %s", + d3d12Fence, d3d12Fence->Handle, d3d12Fence->Event, d3d12Fence->ReferenceCount, CStr(querier)); +#endif + if (--d3d12Fence->ReferenceCount == 0) + { + ReleaseFenceToPool(d3d12driver, d3d12Fence); + } + } + + D3D12Fence* AcquireFence(NonNullPtr driver JULIET_DEBUG_PARAM(String querier)) + { + D3D12Fence* fence; + ID3D12Fence* handle; + + // TODO :Thread safe (lock + atomic) + + if (driver->AvailableFenceCount == 0) + { + HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, + IID_ID3D12Fence, reinterpret_cast(&handle)); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Failed to create fence!", result); + return nullptr; + } + + fence = ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12Fence")); + if (!fence) + { + handle->Release(); + + return nullptr; + } + fence->Handle = handle; + fence->Event = CreateEvent(nullptr, false, false, nullptr); + fence->ReferenceCount = 0; +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0 NEW fence", CStr(querier)); +#endif + } + else + { + fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; + driver->AvailableFenceCount -= 1; + fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE); +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0, RECYCLING", CStr(querier)); +#endif + } + + fence->ReferenceCount += 1; + Assert(fence->ReferenceCount == 1); + +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Acquire Querier %s | %x fence. Handle %x | Event %x | Refcount %d", + CStr(querier), fence, fence->Handle, fence->Event, fence->ReferenceCount); +#endif + + return fence; + } + + bool WaitUntilGPUIsIdle(NonNullPtr driver) + { + auto d3d12driver = static_cast(driver.Get()); + D3D12Fence* fence = AcquireFence(d3d12driver JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); + if (!fence) + { + return false; + } + + if (d3d12driver->GraphicsQueue) + { + // Insert a signal into the end of the command queue... + d3d12driver->GraphicsQueue->Signal(fence->Handle, D3D12_FENCE_SIGNAL_VALUE); + + // ...and then block on it. + if (fence->Handle->GetCompletedValue() != D3D12_FENCE_SIGNAL_VALUE) + { + HRESULT result = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); + if (FAILED(result)) + { + LogError(d3d12driver->D3D12Device, "Setting fence event failed!", result); + return false; + } + + DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE); + if (waitResult == WAIT_FAILED) + { + LogError(d3d12driver->D3D12Device, "Wait failed!", result); + return false; + } + } + } + + ReleaseFence(driver, reinterpret_cast(fence) JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); + + bool result = true; + + // Clean up + { + int32 idx = 0; + while (idx < d3d12driver->SubmittedCommandListCount) + { + result &= CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); + // CleanCommandList swaps [idx] with last and decrements count. + // Don't increment — re-check the swapped-in element. + } + } + + DisposePendingResourcces(d3d12driver); + + return result; + } + + bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, uint32 numFences JULIET_DEBUG_PARAM(String querier)) + { + auto d3d12driver = static_cast(driver.Get()); + + TempArena tempArena = ArenaTempBegin(d3d12driver->DriverArena); + + HANDLE* events = + ArenaPushArray(tempArena.Arena, numFences JULIET_DEBUG_PARAM("Wait() HANDLE - JUST IN CASE")); + MemoryZero(events, sizeof(HANDLE) * numFences); + + for (uint32 i = 0; i < numFences; ++i) + { + D3D12Fence* fence = reinterpret_cast(fences[i]); + + HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); + if (FAILED(res)) + { + LogError(d3d12driver->D3D12Device, "Setting fence event failed!", res); + ArenaTempEnd(tempArena); + return false; + } + + events[i] = fence->Event; + } +#if JULIET_DEBUG + LogDebug(LogCategory::Graphics, "Waiting for %d fences. Querier %s", numFences, CStr(querier)); +#endif + for (uint32 i = 0; i < numFences; ++i) + { + D3D12Fence* d3d12fence = reinterpret_cast(fences[i]); + LogDebug(LogCategory::Graphics, "Waiting for %x fence. Handle %x | Event %x | Refcount %d", d3d12fence, + d3d12fence->Handle, d3d12fence->Event, d3d12fence->ReferenceCount); + } + + DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE); + + ArenaTempEnd(tempArena); + + if (waitResult == WAIT_FAILED) + { + LogError(LogCategory::Graphics, "Wait failed"); + return false; + } + + bool result = true; + + // Clean up + { + int32 idx = 0; + while (idx < d3d12driver->SubmittedCommandListCount) + { + uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue(); + if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) + { + result &= CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); } else { - idx++; + idx += 1; } } } - } // namespace Internal -} // namespace Juliet::D3D12 + + DisposePendingResourcces(d3d12driver); + + return result; + } + + bool QueryFence(NonNullPtr /*driver*/, NonNullPtr /*fence*/) + { + Unimplemented(); + return true; + } + + void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier) + { + D3D12_RESOURCE_BARRIER barrierDesc[2]; + uint32 numBarriers = 0; + + // No transition barrier is needed if the state is not changing. + if (sourceState != destinationState) + { + barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrierDesc[numBarriers].Flags = static_cast(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 = static_cast(0); + barrierDesc[numBarriers].UAV.pResource = resource; + + numBarriers += 1; + } + + if (numBarriers > 0) + { + commandList->GraphicsCommandList.CommandList->ResourceBarrier(numBarriers, barrierDesc); + } + } + + void DestroyFence(NonNullPtr fence) + { + if (fence->Handle) + { + fence->Handle->Release(); + } + + if (fence->Event) + { + CloseHandle(fence->Event); + } + } + // End Fences + + // Begin Swapchain + bool CreateSwapChainTexture(NonNullPtr driver, NonNullPtr swapChain, + SwapChainComposition composition, NonNullPtr textureContainer, uint8 index) + { + ID3D12Resource* swapChainTexture = nullptr; + HRESULT result = swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast(&swapChainTexture)); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Cannot get buffer from SwapChain", result); + return false; + } + + auto texture = static_cast(Calloc(1, sizeof(D3D12Texture))); + if (!texture) + { + LogError(driver->D3D12Device, "Cannot allocate D3D12Texture (out of memory)", result); + swapChainTexture->Release(); + return false; + } + + texture->ReferenceCount += 1; + texture->SubresourceCount = 1; + texture->Subresources = static_cast(Calloc(1, sizeof(D3D12TextureSubresource))); + if (!texture->Subresources) + { + LogError(driver->D3D12Device, "Cannot allocate D3D12TextureSubresource (out of memory)", result); + Free(texture); + swapChainTexture->Release(); + return false; + } + texture->Subresources[0].RTVHandles = static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); + texture->Subresources[0].UAVHandle.Heap = nullptr; + texture->Subresources[0].UAVHandle.Heap = nullptr; + texture->Subresources[0].Parent = texture; + texture->Subresources[0].Index = 0; + texture->Subresources[0].Layer = 0; + texture->Subresources[0].Depth = 1; + texture->Subresources[0].Level = 0; + + D3D12_RESOURCE_DESC textureDesc = swapChainTexture->GetDesc(); + textureContainer->Header.CreateInfo.Width = static_cast(textureDesc.Width); + textureContainer->Header.CreateInfo.Height = static_cast(textureDesc.Height); + textureContainer->Header.CreateInfo.LayerCount = 1; + textureContainer->Header.CreateInfo.MipLevelCount = 1; + textureContainer->Header.CreateInfo.Type = TextureType::Texture_2D; + textureContainer->Header.CreateInfo.Flags = TextureUsageFlag::ColorTarget; + textureContainer->Header.CreateInfo.SampleCount = TextureSampleCount::One; + textureContainer->Header.CreateInfo.Format = SwapchainCompositionToJulietTextureFormat[ToUnderlying(composition)]; + + textureContainer->Textures = static_cast(Calloc(1, sizeof(D3D12Texture*))); + if (!textureContainer->Textures) + { + Free(texture->Subresources); + Free(texture); + swapChainTexture->Release(); + return false; + } + + textureContainer->Capacity = 1; + textureContainer->Count = 1; + textureContainer->Textures[0] = texture; + textureContainer->ActiveTexture = texture; + textureContainer->CanBeCycled = false; + + texture->Container = textureContainer; + texture->IndexInContainer = 0; + + // Assign RTV to the swapchain texture + DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; + AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]); + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; + rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = 0; + rtvDesc.Texture2D.PlaneSlice = 0; + + driver->D3D12Device->CreateRenderTargetView(swapChainTexture, &rtvDesc, texture->Subresources[0].RTVHandles[0].CpuHandle); + + swapChainTexture->Release(); + + return true; + } + + bool D3D12_AcquireSwapChainTexture(bool block, NonNullPtr commandList, NonNullPtr window, Texture** swapchainTexture) + { + auto d3d12CommandList = reinterpret_cast(commandList.Get()); + + auto* driver = d3d12CommandList->Driver; + Assert(driver->WindowData); + + // TODO: Find a way to fetch window data more smoothly from the window ptr + // In the mean time i will just void it or the variable is unused and cause a warning + (void)window; + auto* windowData = driver->WindowData; + Assert(windowData->Window == window.Get()); + + if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) + { + if (block) + { + // Wait until the fence for the frame is signaled. + // In VSYNC this means waiting that the least recent presented frame is done + if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], + 1 JULIET_DEBUG_PARAM(ConstString("AcquireSwapChainTexture")))) + { + return false; + } + } + else + { + // If work is not done, the least recent fence wont be signaled. + // In that case we return true to notify that there is no error, but rendering should be skipped as their will be no swapchainTexture + if (!QueryFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter])) + { + return true; + } + } + + ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter] JULIET_DEBUG_PARAM( + ConstString("AcquireSwapChainTexture"))); + windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr; + } + + uint32 swapchainIndex = windowData->SwapChain->GetCurrentBackBufferIndex(); + HRESULT result = windowData->SwapChain->GetBuffer( + swapchainIndex, IID_ID3D12Resource, + reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource)); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Could not acquire swapchain", result); + return false; + } + + // When the swap chain texture is acquired it's time to present + Assert(d3d12CommandList->PresentDataCount + 1 <= d3d12CommandList->PresentDataCapacity); + d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData; + d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].SwapChainImageIndex = swapchainIndex; + d3d12CommandList->PresentDataCount += 1; + + // Create the presentation barrier. + 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->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource; + barrierDesc.Transition.Subresource = 0; + + d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); + + *swapchainTexture = reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex]); + + return true; + } + + bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, + SwapChainComposition composition, PresentMode presentMode) + { + auto windowWin32State = static_cast(windowData->Window->State); + HWND windowHandle = windowWin32State->Handle; + if (!IsWindow(windowHandle)) + { + Assert(false, "windowWin32State->Handle is not a window handle ???"); + return false; + } + + // TODO: I have no way to test HDR easily except the steamdeck + DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; + + windowData->SwapChainTextureCount = std::clamp(driver->FramesInFlight, 2, 3); + + DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; + swapChainDesc.Width = 0; // Use the whole width + swapChainDesc.Height = 0; // Use the whole height + swapChainDesc.Format = swapChainFormat; + swapChainDesc.Stereo = 0; + swapChainDesc.SampleDesc.Count = 1; + swapChainDesc.SampleDesc.Quality = 0; + swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChainDesc.BufferCount = windowData->SwapChainTextureCount; + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + if (driver->IsTearingSupported) + { + swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } + else + { + swapChainDesc.Flags = 0; + } + + DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {}; + swapChainFullscreenDesc.RefreshRate.Numerator = 0; + swapChainFullscreenDesc.RefreshRate.Denominator = 0; + swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; + swapChainFullscreenDesc.Windowed = true; + + IDXGISwapChain1* swapChain = nullptr; + HRESULT result = + driver->DXGIFactory->CreateSwapChainForHwnd(static_cast(driver->GraphicsQueue), windowHandle, + &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Failed to create SwapChain", result); + return false; + } + + IDXGISwapChain3* swapChain3 = nullptr; + result = swapChain->QueryInterface(IID_IDXGISwapChain3, reinterpret_cast(&swapChain3)); + swapChain->Release(); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Could not query IDXGISwapChain3 interface", result); + return false; + } + + if (composition != SwapChainComposition::SDR) + { + swapChain3->SetColorSpace1(SwapchainCompositionToColorSpace[ToUnderlying(composition)]); + } + + IDXGIFactory1* parentFactory = nullptr; + result = swapChain3->GetParent(IID_IDXGIFactory1, reinterpret_cast(&parentFactory)); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result); + } + else + { + // Disable DXGI window crap + result = parentFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result); + } + parentFactory->Release(); + } + + swapChain3->GetDesc1(&swapChainDesc); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Failed to retrieve SwapChain descriptor", result); + return false; + } + windowData->SwapChain = swapChain3; + windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)]; + windowData->SwapChainComposition = composition; + windowData->WindowFrameCounter = 0; + windowData->Width = swapChainDesc.Width; + windowData->Height = swapChainDesc.Height; + windowData->PresentMode = presentMode; + + for (uint8 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) + { + if (!CreateSwapChainTexture(driver, swapChain3, composition, &windowData->SwapChainTextureContainers[idx], idx)) + { + swapChain3->Release(); + return false; + } + } + + return true; + } + + void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData) + { + for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) + { + ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]); + + Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles); + Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources); + Free(windowData->SwapChainTextureContainers[idx].ActiveTexture); + Free(windowData->SwapChainTextureContainers[idx].Textures); + } + + windowData->SwapChain->Release(); + windowData->SwapChain = nullptr; + } + + bool D3D12_AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) + { + return D3D12_AcquireSwapChainTexture(false, commandList, window, swapChainTexture); + } + + bool D3D12_WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) + { + return D3D12_AcquireSwapChainTexture(true, commandList, window, swapChainTexture); + } + + bool WaitForSwapchain(NonNullPtr driver, NonNullPtr /*window*/) + { + auto* d3d12Driver = static_cast(driver.Get()); + auto* windowData = d3d12Driver->WindowData; + if (!windowData) + { + LogError(LogCategory::Graphics, "Cannot wait for swapchain. Window has no Swapchain"); + return false; + } + + if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) + { + if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], + 1 JULIET_DEBUG_PARAM(ConstString("WaitForSwapchain")))) + { + return false; + } + } + + return true; + } + + TextureFormat GetSwapChainTextureFormat(NonNullPtr driver, [[maybe_unused]] NonNullPtr window) + { + auto* d3d12Driver = static_cast(driver.Get()); + + auto* windowData = d3d12Driver->WindowData; + if (!windowData) + { + LogError(LogCategory::Graphics, "Cannot get swapchain format. Window has no Swapchain"); + return TextureFormat::Invalid; + } + + Assert(windowData->Window == window.Get()); + return windowData->SwapChainTextureContainers[windowData->WindowFrameCounter].Header.CreateInfo.Format; + } + // End Swapchain + + // Begin Texture + + uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels) + { + return mipLevel + (layer * numLevels); + } + + D3D12_RESOURCE_STATES GetDefaultTextureResourceState(TextureUsageFlag usageFlags) + { + if ((usageFlags & TextureUsageFlag::Sampler) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + if ((usageFlags & TextureUsageFlag::GraphicsStorageRead) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + if ((usageFlags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_RENDER_TARGET; + } + if ((usageFlags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_DEPTH_WRITE; + } + if ((usageFlags & TextureUsageFlag::ComputeStorageRead) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; + } + if ((usageFlags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + if ((usageFlags & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None) + { + return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + } + Log(LogLevel::Error, LogCategory::Graphics, "Texture has no default usage mode!"); + return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; + } + + D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, uint32 layer, uint32 level) + { + uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount); + return &container->ActiveTexture->Subresources[index]; + } + + void TextureSubresourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, NonNullPtr textureSubresource) + { + TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags; + bool needsUAVBarrier = ((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) || + ((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None); + ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource, + textureSubresource->Index, needsUAVBarrier); + } + + void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr commandList, + NonNullPtr subresource, + D3D12_RESOURCE_STATES toTextureUsage) + { + D3D12_RESOURCE_STATES defaultUsage = + GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); + TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource); + } + + void TextureTransitionFromDefaultUsage(NonNullPtr commandList, NonNullPtr texture, + D3D12_RESOURCE_STATES toTextureUsage) + { + for (uint32 i = 0; i < texture->SubresourceCount; ++i) + { + TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage); + } + } + + void TextureSubresourceTransitionToDefaultUsage(NonNullPtr commandList, + NonNullPtr subresource, D3D12_RESOURCE_STATES fromTextureUsage) + { + D3D12_RESOURCE_STATES defaultUsage = + GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); + TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource); + } + + void TextureTransitionToDefaultUsage(NonNullPtr commandList, NonNullPtr texture, + D3D12_RESOURCE_STATES fromTextureUsage) + { + for (uint32 i = 0; i < texture->SubresourceCount; ++i) + { + TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage); + } + } + + D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr commandList, + NonNullPtr container, uint32 layer, + uint32 level, bool shouldCycle, D3D12_RESOURCE_STATES newTextureUsage) + { + D3D12TextureSubresource* subresource = FetchTextureSubresource(container, layer, level); + if (shouldCycle and container->CanBeCycled and subresource->Parent->ReferenceCount > 0) + { + // TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective) + // CycleActiveTexture(commandList->Driver, container); + + subresource = FetchTextureSubresource(container, layer, level); + } + + TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage); + + return subresource; + } + + Texture* CreateTexture(NonNullPtr driver, const TextureCreateInfo& createInfo) + { + auto* d3d12Driver = static_cast(driver.Get()); + + D3D12_RESOURCE_DESC desc = {}; + switch (createInfo.Type) + { + case TextureType::Texture_2D: + case TextureType::Texture_2DArray: + case TextureType::Texture_Cube: + case TextureType::Texture_CubeArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break; + case TextureType::Texture_3D: + case TextureType::Texture_3DArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break; + } + + desc.Alignment = 0; + desc.Width = createInfo.Width; + desc.Height = createInfo.Height; + desc.DepthOrArraySize = static_cast(createInfo.LayerCount); + desc.MipLevels = static_cast(createInfo.MipLevelCount); + desc.Format = ConvertToD3D12TextureFormat(createInfo.Format); + desc.SampleDesc.Count = JulietToD3D12_SampleCount[ToUnderlying(createInfo.SampleCount)]; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + desc.Flags = D3D12_RESOURCE_FLAG_NONE; + + if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) + { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + } + if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) + { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + } + if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) + { + desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + } + + D3D12_HEAP_PROPERTIES heapProps = {}; + heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; + heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + heapProps.CreationNodeMask = 0; // We don't do multi-adapter operation + heapProps.VisibleNodeMask = 0; // We don't do multi-adapter operation + + ID3D12Resource* resource = nullptr; + D3D12_CLEAR_VALUE clearValue = {}; + D3D12_CLEAR_VALUE* pClearValue = nullptr; + + if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) + { + clearValue.Format = ConvertToD3D12DepthFormat(createInfo.Format); + clearValue.DepthStencil.Depth = 1.0f; + clearValue.DepthStencil.Stencil = 0; + pClearValue = &clearValue; + } + else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) + { + clearValue.Format = desc.Format; + clearValue.Color[0] = 0.0f; + clearValue.Color[1] = 0.0f; + clearValue.Color[2] = 0.0f; + clearValue.Color[3] = 0.0f; + pClearValue = &clearValue; + } + + D3D12_RESOURCE_STATES initialState = GetDefaultTextureResourceState(createInfo.Flags); + HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, + initialState, pClearValue, IID_ID3D12Resource, + reinterpret_cast(&resource)); + + if (FAILED(hr)) + { + LogError(d3d12Driver->D3D12Device, "Failed to create D3D12 committed resource for texture", hr); + return nullptr; + } + + auto* textureContainer = static_cast(Calloc(1, sizeof(D3D12TextureContainer))); + auto* texture = static_cast(Calloc(1, sizeof(D3D12Texture))); + + textureContainer->Header.CreateInfo = createInfo; + textureContainer->ActiveTexture = texture; + textureContainer->Textures = static_cast(Malloc(sizeof(D3D12Texture*))); + textureContainer->Textures[0] = texture; + textureContainer->Capacity = 1; + textureContainer->Count = 1; + textureContainer->CanBeCycled = true; + + texture->Container = textureContainer; + texture->Resource = resource; + texture->ReferenceCount = 1; + + uint32 numLayers = std::max(1, createInfo.LayerCount); + uint32 numMips = std::max(1, createInfo.MipLevelCount); + texture->SubresourceCount = numLayers * numMips; + texture->Subresources = + static_cast(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource))); + + for (uint32 layer = 0; layer < numLayers; ++layer) + { + for (uint32 mip = 0; mip < numMips; ++mip) + { + uint32 index = mip + (layer * numMips); + auto& sub = texture->Subresources[index]; + sub.Parent = texture; + sub.Layer = layer; + sub.Level = mip; + sub.Index = index; + sub.Depth = 1; // 3D texture depth handling would go here + + if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) + { + sub.RTVHandles = static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); + AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, sub.RTVHandles[0]); + + D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; + rtvDesc.Format = desc.Format; + rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rtvDesc.Texture2D.MipSlice = mip; + d3d12Driver->D3D12Device->CreateRenderTargetView(resource, &rtvDesc, sub.RTVHandles[0].CpuHandle); + } + + if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) + { + AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, sub.DSVHandle); + + D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; + dsvDesc.Format = ConvertToD3D12DepthFormat(createInfo.Format); + dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + dsvDesc.Texture2D.MipSlice = mip; + d3d12Driver->D3D12Device->CreateDepthStencilView(resource, &dsvDesc, sub.DSVHandle.CpuHandle); + } + } + } + + // Create SRV for sampled/readable textures (bindless access) + // Assign to the bindless CBV_SRV_UAV heap + { + D3D12Descriptor descriptor; + if (AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor)) + { + texture->SRVHandle = D3D12StagingDescriptor{}; + texture->SRVHandle.CpuHandleIndex = descriptor.Index; + texture->SRVHandle.CpuHandle = descriptor.CpuHandle; + texture->SRVHandle.Heap = descriptor.Heap; + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.Format = desc.Format; + + // Fix SRV format for Depth Buffers (TypeLess -> Typed) + if (createInfo.Format == TextureFormat::D32_FLOAT) + { + srvDesc.Format = DXGI_FORMAT_R32_FLOAT; + } + else if (createInfo.Format == TextureFormat::D16_UNORM) + { + srvDesc.Format = DXGI_FORMAT_R16_UNORM; + } + else if (createInfo.Format == TextureFormat::D24_UNORM_S8_UINT) + { + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + } + else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT) + { + srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; + } + + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MostDetailedMip = 0; + srvDesc.Texture2D.MipLevels = numMips; + srvDesc.Texture2D.PlaneSlice = 0; + srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; + + d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle); + } + } + + return reinterpret_cast(textureContainer); + } + + void DestroyTexture(NonNullPtr driver, NonNullPtr texture) + { + auto* d3d12Driver = static_cast(driver.Get()); + auto* textureContainer = reinterpret_cast(texture.Get()); + + for (uint32 i = 0; i < textureContainer->Count; ++i) + { + D3D12Texture* d3d12Texture = textureContainer->Textures[i]; + for (uint32 j = 0; j < d3d12Texture->SubresourceCount; ++j) + { + D3D12TextureSubresource& sub = d3d12Texture->Subresources[j]; + if (sub.RTVHandles) + { + ReleaseStagingDescriptor(d3d12Driver, sub.RTVHandles[0]); + Free(sub.RTVHandles); + } + if (sub.DSVHandle.Heap) + { + ReleaseStagingDescriptor(d3d12Driver, sub.DSVHandle); + } + } + d3d12Texture->Resource->Release(); + Free(d3d12Texture->Subresources); + Free(d3d12Texture); + } + + Free(textureContainer->Textures); + Free(textureContainer); + } + // End Texture + + // Begin Command list + index_t GetNewCommandListID() + { + return CommandListID++; + } + + bool HasD3D12CommandListForQueueType(NonNullPtr commandList, QueueType queueType) + { + switch (queueType) + { + case QueueType::Graphics: return commandList->GraphicsCommandList.CommandList != nullptr; + case QueueType::Compute: return commandList->ComputeCommandList.CommandList != nullptr; + case QueueType::Copy: return commandList->CopyCommandList.CommandList != nullptr; + default: return false; + } + } + + void DestroyCommandList(NonNullPtr commandList) + { + // TODO : Handle other kind of command list (copy compute) + if (commandList->GraphicsCommandList.CommandList) + { + commandList->GraphicsCommandList.CommandList->Release(); + } + + commandList->GraphicsCommandList.Allocator->Release(); + } + + bool CreateAllocator(NonNullPtr driver, NonNullPtr baseData, D3D12_COMMAND_QUEUE_DESC queueDesc) + { + HRESULT result = driver->D3D12Device->CreateCommandAllocator(queueDesc.Type, IID_ID3D12CommandAllocator, + reinterpret_cast(&baseData->Allocator)); + if (FAILED(result)) + { + AssertHR(result, "Cannot create ID3D12CommandAllocator"); + return false; + } + + baseData->Allocator->Reset(); + return true; + } + + bool CreateD3D12CommandListForQueueType(NonNullPtr driver, NonNullPtr commandList, QueueType queueType) + { + // TODO: String library + std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID); + + // TODO: Factorize this. Flemme + + // Get Proper allocator for the frame. Reset all allocators and the command list with current frame allocator + auto& queueDesc = driver->QueueDesc[ToUnderlying(queueType)]; + switch (queueType) + { + case QueueType::Graphics: + { + CreateAllocator(driver, &commandList->GraphicsCommandList, queueDesc); + ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; + HRESULT result = + driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, + D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, + reinterpret_cast(&d3d12GraphicsCommandList)); + if (FAILED(result)) + { + Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " + "compute command list"); + return false; + } + + commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList; + d3d12GraphicsCommandList->SetName(wide_str.c_str()); + d3d12GraphicsCommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); + + return true; + } + case QueueType::Compute: + { + CreateAllocator(driver, &commandList->ComputeCommandList, queueDesc); + ID3D12GraphicsCommandList6* d3d12GraphicsCommandList = nullptr; + HRESULT result = + driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, + D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList6, + reinterpret_cast(&d3d12GraphicsCommandList)); + if (FAILED(result)) + { + Assert(false, "Error not implemented: cannot create ID3D12GraphicsCommandList6 (graphics or " + "compute command list"); + return false; + } + + commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList; + d3d12GraphicsCommandList->SetName(wide_str.c_str()); + d3d12GraphicsCommandList->Reset(commandList->ComputeCommandList.Allocator, nullptr); + + return true; + } + case QueueType::Copy: + { + CreateAllocator(driver, &commandList->CopyCommandList, queueDesc); + ID3D12GraphicsCommandList* d3d12CopyCommandList = nullptr; + HRESULT result = driver->D3D12Device->CreateCommandList1(queueDesc.NodeMask, queueDesc.Type, + D3D12_COMMAND_LIST_FLAG_NONE, IID_ID3D12GraphicsCommandList, + reinterpret_cast(&d3d12CopyCommandList)); + + if (FAILED(result)) + { + AssertHR(result, "cannot create ID3D12GraphicsCommandList (copy command list)"); + return false; + } + commandList->CopyCommandList.CommandList = d3d12CopyCommandList; + d3d12CopyCommandList->SetName(wide_str.c_str()); + d3d12CopyCommandList->Reset(commandList->CopyCommandList.Allocator, nullptr); + + return true; + } + default: return false; + } + } + + bool AllocateCommandList(NonNullPtr driver, QueueType queueType) + { + if (driver->AvailableCommandLists == nullptr) + { + driver->AvailableCommandLists = + ArenaPushArray(driver->DriverArena, + kMaxCommandListCount JULIET_DEBUG_PARAM("Command list count {}", kMaxCommandListCount)); + driver->AvailableCommandListCapacity = kMaxCommandListCount; + } + const index_t id = GetNewCommandListID(); + + auto* commandList = + ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12CommandList [{}]", id)); + if (!commandList) + { + Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); + DestroyCommandList(commandList); + return false; + } + + driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; + driver->AvailableCommandListCount += 1; + + commandList->ID = id; + commandList->Driver = driver; + + // Window Handling + commandList->PresentDataCapacity = kMaxPresentDataPerCommandList; + commandList->PresentDataCount = 0; + commandList->PresentDatas = ArenaPushArray( + driver->DriverArena, + kMaxPresentDataPerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12PresentData ptr array count " + "{}", + id, kMaxPresentDataPerCommandList)); + + // Resource tracking + commandList->UsedTextureCapacity = kMaxTexturePerCommandList; + commandList->UsedTextureCount = 0; + commandList->UsedTextures = + ArenaPushArray(driver->DriverArena, + kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12Texture " + "ptr array count " + "{}", + id, kMaxTexturePerCommandList)); + + commandList->UsedGraphicsPipelineCapacity = kMaxGraphicsPipelinePerCommandList; + commandList->UsedGraphicsPipelineCount = 0; + commandList->UsedGraphicsPipelines = ArenaPushArray( + driver->DriverArena, + kMaxTexturePerCommandList JULIET_DEBUG_PARAM("Command list [{}] D3D12GraphicsPipeline ptr array count " + "{}", + id, kMaxTexturePerCommandList)); + + // TODO : Simplify this + if (!HasD3D12CommandListForQueueType(commandList, queueType)) + { + if (!CreateD3D12CommandListForQueueType(driver, commandList, queueType)) + { + Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list"); + DestroyCommandList(commandList); + return false; + } + } + + return true; + } + + D3D12CommandList* AcquireCommandListFromPool(NonNullPtr driver, QueueType queueType) + { + if (driver->AvailableCommandListCount == 0) + { + if (!AllocateCommandList(driver, queueType)) + { + return nullptr; + } + } + + D3D12CommandList* commandList = driver->AvailableCommandLists[driver->AvailableCommandListCount - 1]; + driver->AvailableCommandListCount -= 1; + + return commandList; + } + + CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType) + { + auto* d3d12Driver = static_cast(driver.Get()); + + D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType); + + commandList->AutoReleaseFence = true; + + return reinterpret_cast(commandList); + } + + void SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + + D3D12_VIEWPORT d3d12Viewport; + d3d12Viewport.TopLeftX = viewPort.X; + d3d12Viewport.TopLeftY = viewPort.Y; + d3d12Viewport.Width = viewPort.Width; + d3d12Viewport.Height = viewPort.Height; + d3d12Viewport.MinDepth = viewPort.MinDepth; + d3d12Viewport.MaxDepth = viewPort.MaxDepth; + d3d12CommandList->GraphicsCommandList.CommandList->RSSetViewports(1, &d3d12Viewport); + } + + void SetScissorRect(NonNullPtr commandList, const Rectangle& rectangle) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + D3D12_RECT scissorRect; + scissorRect.left = rectangle.X; + scissorRect.top = rectangle.Y; + scissorRect.right = rectangle.X + rectangle.Width; + scissorRect.bottom = rectangle.Y + rectangle.Height; + d3d12CommandList->GraphicsCommandList.CommandList->RSSetScissorRects(1, &scissorRect); + } + + void SetBlendConstants(NonNullPtr commandList, FColor blendConstants) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + FLOAT blendFactor[4] = { blendConstants.R, blendConstants.G, blendConstants.B, blendConstants.A }; + d3d12CommandList->GraphicsCommandList.CommandList->OMSetBlendFactor(blendFactor); + } + + void SetStencilReference(NonNullPtr commandList, uint8 reference) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + d3d12CommandList->GraphicsCommandList.CommandList->OMSetStencilRef(reference); + } + + void D3D12_SetIndexBuffer(NonNullPtr commandList, NonNullPtr buffer, + IndexFormat format, size_t indexCount, index_t offset) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12Buffer = reinterpret_cast(buffer.Get()); + + // Transition to INDEX_BUFFER state if needed + if (d3d12Buffer->CurrentState != D3D12_RESOURCE_STATE_GENERIC_READ) + { + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrier.Transition.pResource = d3d12Buffer->Handle; + barrier.Transition.StateBefore = d3d12Buffer->CurrentState; + barrier.Transition.StateAfter = + D3D12_RESOURCE_STATE_GENERIC_READ; // Since we use a mega buffer we use the generic read that includes D3D12_RESOURCE_STATE_INDEX_BUFFER + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + + d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrier); + d3d12Buffer->CurrentState = D3D12_RESOURCE_STATE_GENERIC_READ; + } + + D3D12_INDEX_BUFFER_VIEW ibView; + ibView.BufferLocation = d3d12Buffer->Handle->GetGPUVirtualAddress() + offset; + if (format == IndexFormat::UInt16) + { + ibView.SizeInBytes = static_cast(indexCount * sizeof(uint16)); + ibView.Format = DXGI_FORMAT_R16_UINT; + } + else + { + ibView.SizeInBytes = static_cast(indexCount * sizeof(uint32)); + ibView.Format = DXGI_FORMAT_R32_UINT; + } + + d3d12CommandList->GraphicsCommandList.CommandList->IASetIndexBuffer(&ibView); + } + + void D3D12_SetPushConstants(NonNullPtr commandList, ShaderStage /*stage*/, uint32 rootParameterIndex, + uint32 numConstants, const void* constants) + { + auto d3d12CommandList = reinterpret_cast(commandList.Get()); + // For now we assume Graphics Root Signature. Compute support would need a check or separate function. + d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRoot32BitConstants(rootParameterIndex, + numConstants, constants, 0); + } + + void SetDescriptorHeaps(NonNullPtr commandList) + { + ID3D12DescriptorHeap* heaps[2]; + D3D12DescriptorHeap* viewHeap = nullptr; + D3D12DescriptorHeap* samplerHeap = nullptr; + + viewHeap = commandList->Driver->BindlessDescriptorHeap; + + samplerHeap = AcquireSamplerHeapFromPool(commandList->Driver); + + commandList->CRB_SRV_UAV_Heap = viewHeap; + commandList->Sampler_Heap = samplerHeap; + + heaps[0] = viewHeap->Handle; + heaps[1] = samplerHeap->Handle; + + commandList->GraphicsCommandList.CommandList->SetDescriptorHeaps(2, heaps); + } + + bool CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel) + { + // No more presentation data + commandList->PresentDataCount = 0; + + HRESULT result = commandList->GraphicsCommandList.Allocator->Reset(); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Could not reset command allocator", result); + return false; + } + + result = commandList->GraphicsCommandList.CommandList->Reset(commandList->GraphicsCommandList.Allocator, nullptr); + if (FAILED(result)) + { + LogError(driver->D3D12Device, "Could not reset command list", result); + return false; + } + + if (commandList->Sampler_Heap) [[likely]] + { + ReturnSamplerHeapToPool(driver, commandList->Sampler_Heap); + commandList->Sampler_Heap = nullptr; + } + commandList->CRB_SRV_UAV_Heap = nullptr; + + // Clean up resource tracking + for (uint32 idx = 0; idx < commandList->UsedTextureCount; ++idx) + { + --commandList->UsedTextures[idx]->ReferenceCount; + } + commandList->UsedTextureCount = 0; + + for (uint32 idx = 0; idx < commandList->UsedGraphicsPipelineCount; ++idx) + { + --commandList->UsedGraphicsPipelines[idx]->ReferenceCount; + } + commandList->UsedGraphicsPipelineCount = 0; + + // Release Fence if needed + if (commandList->AutoReleaseFence) + { + ReleaseFence(driver.Get(), reinterpret_cast(commandList->InFlightFence) + JULIET_DEBUG_PARAM(ConstString("CleanCommandList"))); + commandList->InFlightFence = nullptr; + } + + // Return the command list to the pool + Assert(driver->AvailableCommandListCount + 1 <= driver->AvailableCommandListCapacity); + driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; + driver->AvailableCommandListCount += 1; + + // Remove this command list from the submitted list + if (!cancel) + { + for (uint32 idx = 0; idx < driver->SubmittedCommandListCount; idx += 1) + { + if (driver->SubmittedCommandLists[idx] == commandList) + { + driver->SubmittedCommandLists[idx] = driver->SubmittedCommandLists[driver->SubmittedCommandListCount - 1]; + driver->SubmittedCommandListCount -= 1; + break; + } + } + } + + return true; + } + +#define TRACK_RESOURCE(resource, type, array, count, capacity) \ + uint32 i; \ + \ + for (i = 0; i < commandList->count; i += 1) \ + { \ + if (commandList->array[i] == (resource)) \ + { \ + return; \ + } \ + } \ + \ + Assert(commandList->count + 1 <= commandList->capacity); \ + commandList->array[commandList->count] = resource; \ + commandList->count += 1; \ + ++(resource)->ReferenceCount; + + void TrackGraphicsPipeline(NonNullPtr commandList, NonNullPtr pipeline) + { + TRACK_RESOURCE(pipeline, D3D12GraphicsPipeline*, UsedGraphicsPipelines, UsedGraphicsPipelineCount, UsedGraphicsPipelineCapacity) + } + + void TrackTexture(NonNullPtr commandList, NonNullPtr texture) + { + TRACK_RESOURCE(texture, D3D12Texture*, UsedTextures, UsedTextureCount, UsedTextureCapacity) + } + + bool D3D12_SubmitCommandLists(NonNullPtr commandList) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12Driver = d3d12CommandList->Driver; + // TODO : Use QueueType to choose the correct CommandList and Command Queue + // Only use graphics for now + + // Transition present textures to present mode + for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) + { + uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; + D3D12TextureContainer* container = + &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; + D3D12TextureSubresource* subresource = 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; + + d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); + } + + // Notify the command buffer that we have completed recording + HRESULT result = d3d12CommandList->GraphicsCommandList.CommandList->Close(); + if (FAILED(result)) + { + LogError(d3d12Driver->D3D12Device, "Failed to close command list!", result); + return false; + } + + ID3D12CommandList* ppCommandLists[] = { d3d12CommandList->GraphicsCommandList.CommandList }; + + // Submit the command list to the queue + d3d12Driver->GraphicsQueue->ExecuteCommandLists(1, ppCommandLists); + + // Acquire a fence and set it to the in-flight fence + d3d12CommandList->InFlightFence = + AcquireFence(d3d12Driver JULIET_DEBUG_PARAM(ConstString("SubmitCommandLists"))); + if (!d3d12CommandList->InFlightFence) + { + return false; + } + + // Mark that a fence should be signaled after command list execution + result = d3d12Driver->GraphicsQueue->Signal(d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE); + if (FAILED(result)) + { + LogError(d3d12Driver->D3D12Device, "Failed to enqueue fence signal!", result); + return false; + } + + // Mark the command list as submitted + [[maybe_unused]] const uint32 newValue = static_cast(d3d12Driver->SubmittedCommandListCount) + 1U; + Assert(newValue <= 0xFF && "Command List count exceeded uint8 capacity!"); + Assert(newValue <= d3d12Driver->SubmittedCommandListCapacity); + + d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList; + d3d12Driver->SubmittedCommandListCount += 1; + + bool success = true; + for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) + { + D3D12PresentData* presentData = &d3d12CommandList->PresentDatas[i]; + auto* windowData = presentData->WindowData; + + // NOTE: flip discard always supported since DXGI 1.4 is required + uint32 syncInterval = 1; + if (windowData->PresentMode == PresentMode::Immediate || windowData->PresentMode == PresentMode::Mailbox) + { + syncInterval = 0; + } + + uint32 presentFlags = 0; + if (d3d12Driver->IsTearingSupported && windowData->PresentMode == PresentMode::Immediate) + { + presentFlags = DXGI_PRESENT_ALLOW_TEARING; + } + + result = windowData->SwapChain->Present(syncInterval, presentFlags); + if (FAILED(result)) + { + success = false; + } + + windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource->Release(); + + windowData->InFlightFences[windowData->WindowFrameCounter] = reinterpret_cast(d3d12CommandList->InFlightFence); + d3d12CommandList->InFlightFence->ReferenceCount += 1; + windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight; + } + + // Check for cleanups + { + int32 i = 0; + while (i < d3d12Driver->SubmittedCommandListCount) + { + uint64 fenceValue = d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle->GetCompletedValue(); + if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) + { + success &= CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false); + // CleanCommandList swaps [i] with last and decrements count. + // Don't increment — re-check the swapped-in element. + } + else + { + i += 1; + } + } + } + + DisposePendingResourcces(d3d12Driver); + + ++d3d12Driver->FrameCounter; + + return success; + } + // End Command List + + // Begin Render Pass + void BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, + uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + + uint32 frameBufferWidth = uint32Max; + uint32 frameBufferHeight = uint32Max; + + for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) + { + auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); + uint32 width = container->Header.CreateInfo.Width >> colorTargetInfos[idx].MipLevel; + uint32 height = container->Header.CreateInfo.Height >> colorTargetInfos[idx].MipLevel; + + // Scale the framebuffer to fit the smallest target. + frameBufferWidth = Min(width, frameBufferWidth); + frameBufferHeight = Min(height, frameBufferHeight); + } + + // Depth Stencil and DSV + D3D12_CPU_DESCRIPTOR_HANDLE DSV; + bool hasDSV = false; + if (depthStencilTargetInfo && depthStencilTargetInfo->TargetTexture) + { + auto* container = reinterpret_cast(depthStencilTargetInfo->TargetTexture); + uint32 width = container->Header.CreateInfo.Width; + uint32 height = container->Header.CreateInfo.Height; + + frameBufferWidth = Min(width, frameBufferWidth); + frameBufferHeight = Min(height, frameBufferHeight); + + D3D12TextureSubresource* subresource = + PrepareTextureSubresourceForWrite(d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE); + + DSV = subresource->DSVHandle.CpuHandle; + hasDSV = true; + d3d12CommandList->DepthStencilSubresource = subresource; + + TrackTexture(d3d12CommandList, subresource->Parent); + + if (depthStencilTargetInfo->LoadOperation == LoadOperation::Clear) + { + D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH; + // TODO: Check if texture has stencil + // if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL; + + d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV, clearFlags, + depthStencilTargetInfo->ClearDepth, + depthStencilTargetInfo->ClearStencil, + 0, nullptr); + } + } + + D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo]; + for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) + { + auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); + D3D12TextureSubresource* subresource = PrepareTextureSubresourceForWrite( + d3d12CommandList, container, + container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerIndex, + colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].CycleTexture, D3D12_RESOURCE_STATE_RENDER_TARGET); + + uint32 RTVIndex = container->Header.CreateInfo.Type == TextureType::Texture_3D ? colorTargetInfos[idx].DepthPlane : 0; + D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->RTVHandles[RTVIndex].CpuHandle; + + if (colorTargetInfos[idx].LoadOperation == LoadOperation::Clear) + { + float clearColor[4]; + clearColor[0] = colorTargetInfos[idx].ClearColor.R; + clearColor[1] = colorTargetInfos[idx].ClearColor.G; + clearColor[2] = colorTargetInfos[idx].ClearColor.B; + clearColor[3] = colorTargetInfos[idx].ClearColor.A; + + d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr); + } + + RTVs[idx] = rtv; + d3d12CommandList->ColorTargetSubresources[idx] = subresource; + + TrackTexture(d3d12CommandList, subresource->Parent); + + if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve || + colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore) + { + auto resolveContainer = reinterpret_cast(colorTargetInfos[idx].ResolveTexture); + D3D12TextureSubresource* resolveSubresource = + PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer, colorTargetInfos[idx].ResolveLayerIndex, + colorTargetInfos[idx].ResolveMipLevel, colorTargetInfos[idx].CycleResolveTexture, + D3D12_RESOURCE_STATE_RESOLVE_DEST); + + d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; + + TrackTexture(d3d12CommandList, resolveSubresource->Parent); + } + } + + d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(colorTargetInfoCount, RTVs, false, + hasDSV ? &DSV : nullptr); + + // Set defaults graphics states + GraphicsViewPort defaultViewport; + defaultViewport.X = 0.f; + defaultViewport.Y = 0.f; + defaultViewport.Width = static_cast(frameBufferWidth); + defaultViewport.Height = static_cast(frameBufferHeight); + defaultViewport.MinDepth = 0.f; + defaultViewport.MaxDepth = 1.f; + SetViewPort(commandList, defaultViewport); + + Rectangle defaultScissor; + defaultScissor.X = 0; + defaultScissor.Y = 0; + defaultScissor.Width = static_cast(frameBufferWidth); + defaultScissor.Height = static_cast(frameBufferHeight); + SetScissorRect(commandList, defaultScissor); + + SetStencilReference(commandList, 0); + + FColor blendConstants; + blendConstants.R = 1.0f; + blendConstants.G = 1.0f; + blendConstants.B = 1.0f; + blendConstants.A = 1.0f; + SetBlendConstants(commandList, blendConstants); + } + + void EndRenderPass(NonNullPtr commandList) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + + // Reset Color Target state and optionally resolve color texture + for (uint32 idx = 0; idx < GPUDriver::kMaxColorTargetInfo; ++idx) + { + if (d3d12CommandList->ColorTargetSubresources[idx]) + { + if (d3d12CommandList->ColorResolveSubresources[idx]) + { + TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, + d3d12CommandList->ColorTargetSubresources[idx]); + d3d12CommandList->GraphicsCommandList.CommandList->ResolveSubresource( + d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource, + d3d12CommandList->ColorResolveSubresources[idx]->Index, + d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource, + d3d12CommandList->ColorTargetSubresources[idx]->Index, + ConvertToD3D12TextureFormat( + d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format)); + + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], + D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorResolveSubresources[idx], + D3D12_RESOURCE_STATE_RESOLVE_DEST); + } + else + { + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], + D3D12_RESOURCE_STATE_RENDER_TARGET); + } + } + } + + // Reset Depth Stencil state + if (d3d12CommandList->DepthStencilSubresource) + { + TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->DepthStencilSubresource, + D3D12_RESOURCE_STATE_DEPTH_WRITE); + d3d12CommandList->DepthStencilSubresource = nullptr; + } + d3d12CommandList->CurrentGraphicsPipeline = nullptr; + + d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(0, nullptr, false, nullptr); + + // Reset bind states + ZeroArray(d3d12CommandList->ColorTargetSubresources); + ZeroArray(d3d12CommandList->ColorResolveSubresources); + // TODO : reset depth stencil subresources + // d3d12CommandList->DepthStencilTextureSubresource = NULL; + + // TODO : vertex buffer + // TODO :Vertex sampler and fragment sampler + + // ZeroArray(d3d12CommandList->VertexBuffers); + // ZeroArray(d3d12CommandList->VertexBufferOffsets); + // d3d12CommandList->VertexBufferCount = 0; + // + // ZeroArray(d3d12CommandList->VertexSamplerTextures); + // ZeroArray(d3d12CommandList->VertexSamplers); + // ZeroArray(d3d12CommandList->VertexStorageTextures); + // ZeroArray(d3d12CommandList->VertexStorageBuffers); + // + // ZeroArray(d3d12CommandList->FragmentSamplerTextures); + // ZeroArray(d3d12CommandList->FragmentSamplers); + // ZeroArray(d3d12CommandList->FragmentStorageTextures); + // ZeroArray(d3d12CommandList->FragmentStorageBuffers); + } + + void BindGraphicsPipeline(NonNullPtr commandList, NonNullPtr graphicsPipeline) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto pipeline = reinterpret_cast(graphicsPipeline.Get()); + + d3d12CommandList->CurrentGraphicsPipeline = pipeline; + + // Set the Descriptor heap + if (d3d12CommandList->CRB_SRV_UAV_Heap == nullptr) + { + SetDescriptorHeaps(d3d12CommandList); + } + + // Set the pipeline state + d3d12CommandList->GraphicsCommandList.CommandList->SetPipelineState(pipeline->PipelineState); + d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(pipeline->RootSignature->Handle); + d3d12CommandList->GraphicsCommandList.CommandList->IASetPrimitiveTopology( + JulietToD3D12_PrimitiveType[ToUnderlying(pipeline->PrimitiveType)]); + + // Mark that bindings are needed + d3d12CommandList->NeedVertexSamplerBind = true; + d3d12CommandList->NeedVertexStorageTextureBind = true; + d3d12CommandList->NeedVertexStorageBufferBind = true; + d3d12CommandList->NeedFragmentSamplerBind = true; + d3d12CommandList->NeedFragmentStorageTextureBind = true; + d3d12CommandList->NeedFragmentStorageBufferBind = true; + + for (uint32 idx = 0; idx < GPUDriver::kMaxUniformBuffersPerStage; ++idx) + { + d3d12CommandList->NeedVertexUniformBufferBind[idx] = true; + d3d12CommandList->NeedFragmentUniformBufferBind[idx] = true; + } + + for (uint32 idx = 0; idx < pipeline->VertexUniformBufferCount; ++idx) + { + // if (d3d12CommandList->VertexUniformBuffers[i] == NULL) + // { + // d3d12CommandList->VertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); + // } + } + + for (uint32 idx = 0; idx < pipeline->FragmentUniformBufferCount; ++idx) + { + // if (d3d12CommandList->FragmentUniformBuffers[i] == NULL) + // { + // d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); + // } + } + + TrackGraphicsPipeline(d3d12CommandList, pipeline); + } + + void DrawPrimitives(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + // TODO : Last missing piece + // D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); + + d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance); + } + + void DrawIndexedPrimitives(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, + uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex, + static_cast(vertexOffset), firstInstance); + } + // End Render Pass + + bool AttachToWindow(NonNullPtr driver, NonNullPtr window) + { + auto* d3d12Driver = static_cast(driver.Get()); + + // TODO : Support more than one window + if (d3d12Driver->WindowData) + { + Assert(false, "D3D12 renderer already attached to the window. Right now we handle only one Window."); + return false; + } + + auto* windowData = static_cast(Calloc(1, sizeof(D3D12WindowData))); + if (!windowData) + { + Log(LogLevel::Error, LogCategory::Graphics, "OOM: D3D12WindowData"); + return false; + } + d3d12Driver->WindowData = windowData; + + windowData->Window = window; + + if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) + { + Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain."); + Free(windowData); + return false; + } + + d3d12Driver->WindowData = windowData; + + return true; + } + + void DetachFromWindow(NonNullPtr driver, NonNullPtr /*window*/) + { + auto* d3d12Driver = static_cast(driver.Get()); + auto* windowData = d3d12Driver->WindowData; + Assert(windowData && "Trying to destroy a swapchain but no Window Data exists"); + + WaitUntilGPUIsIdle(driver); + + for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1) + { + if (windowData->InFlightFences[idx] != nullptr) + { + ReleaseFence(driver, + windowData->InFlightFences[idx] JULIET_DEBUG_PARAM(ConstString("DeatchFromWindow"))); + windowData->InFlightFences[idx] = nullptr; + } + } + + DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); + + SafeFree(d3d12Driver->WindowData); + d3d12Driver->WindowData = nullptr; + } + + void DestroyDriver_Internal(NonNullPtr driver) + { + // Destroy Descriptor pools + for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) + { + if (driver->StagingDescriptorPools[i]) + { + DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); + driver->StagingDescriptorPools[i] = nullptr; + } + } + + D3D12_DestroyDescriptorHeapPool(driver->SamplerHeapPool); + + // Release command buffers + for (uint32 i = 0; i < driver->AvailableCommandListCount; i += 1) + { + if (driver->AvailableCommandLists[i]) + { + DestroyCommandList(driver->AvailableCommandLists[i]); + driver->AvailableCommandLists[i] = nullptr; + } + } + + // Release fences + for (uint32 i = 0; i < driver->AvailableFenceCount; i += 1) + { + if (driver->AvailableFences[i]) + { + DestroyFence(driver->AvailableFences[i]); + driver->AvailableFences[i] = nullptr; + } + } + + DestroyGraphicsRootSignature(driver->BindlessRootSignature); + + DestroyDescriptorHeap(driver->BindlessDescriptorHeap); + + // Clean allocations + + SafeFree(driver->GraphicsPipelinesToDispose); + // Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now + + if (driver->IndirectDrawCommandSignature) + { + driver->IndirectDrawCommandSignature->Release(); + } + if (driver->IndirectIndexedDrawCommandSignature) + { + driver->IndirectIndexedDrawCommandSignature->Release(); + driver->IndirectIndexedDrawCommandSignature = nullptr; + } + if (driver->IndirectDispatchCommandSignature) + { + driver->IndirectDispatchCommandSignature->Release(); + driver->IndirectDispatchCommandSignature = nullptr; + } + + if (driver->GraphicsQueue) + { + driver->GraphicsQueue->Release(); + driver->GraphicsQueue = nullptr; + } + + if (driver->D3D12Device) + { + driver->D3D12Device->Release(); + driver->D3D12Device = nullptr; + } + + if (driver->DXGIAdapter) + { + driver->DXGIAdapter->Release(); + driver->DXGIAdapter = nullptr; + } + + if (driver->DXGIFactory) + { + driver->DXGIFactory->Release(); + driver->DXGIFactory = nullptr; + } + +#if JULIET_DEBUG + ShutdownDXGIDebug(driver); +#endif + + if (driver->D3D12DLL) + { + UnloadDynamicLibrary(driver->D3D12DLL); + driver->D3D12DLL = nullptr; + } + + driver->D3D12SerializeVersionedRootSignatureFct = nullptr; + + Assert(ArenaPos(driver->DriverArena) == sizeof(D3D12Driver)); // Verify we didnt forget to release something + ArenaRelease(driver->DriverArena); + } + + void D3D12_DestroyGraphicsDevice(NonNullPtr device) + { + // Note: Its a down cast so clang suggest not to do it but we are totally sure about it. + auto* driver = static_cast(device->Driver); + DestroyDriver_Internal(driver); + Free(device.Get()); + } + + void D3D12_DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr pipeline) + { + auto* d3d12Driver = static_cast(driver.Get()); + d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = + reinterpret_cast(pipeline.Get()); + d3d12Driver->GraphicsPipelinesToDisposeCount += 1; + if (d3d12Driver->GraphicsPipelinesToDisposeCount >= d3d12Driver->GraphicsPipelinesToDisposeCapacity) + { + ReleaseGraphicsPipeline(reinterpret_cast(pipeline.Get())); + } + } + + void D3D12_CopyBufferToTexture(NonNullPtr commandList, NonNullPtr dst, NonNullPtr src) + { + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12TextureContainer = reinterpret_cast(dst.Get()); + auto* d3d12Texture = d3d12TextureContainer->ActiveTexture; + + TextureTransitionFromDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); + + // Get resource desc using C++ API + D3D12_RESOURCE_DESC desc = d3d12Texture->Resource->GetDesc(); + + D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; + dstLoc.pResource = d3d12Texture->Resource; + dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dstLoc.SubresourceIndex = 0; + + // Get buffer resource - D3D12Buffer is anonymous, access Handle directly + // The GraphicsTransferBuffer IS a D3D12Buffer internally + struct D3D12TransferBuffer + { + D3D12Descriptor Descriptor; + ID3D12Resource* Handle; + D3D12_RESOURCE_STATES CurrentState; + }; + auto* d3d12BufferSrc = reinterpret_cast(src.Get()); + + D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; + srcLoc.pResource = d3d12BufferSrc->Handle; + srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + srcLoc.PlacedFootprint.Offset = 0; + srcLoc.PlacedFootprint.Footprint.Format = desc.Format; + srcLoc.PlacedFootprint.Footprint.Width = (UINT)desc.Width; + srcLoc.PlacedFootprint.Footprint.Height = desc.Height; + srcLoc.PlacedFootprint.Footprint.Depth = 1; + + uint32 rowPitch = (uint32)desc.Width * 4; + rowPitch = (rowPitch + 255u) & ~255u; + + srcLoc.PlacedFootprint.Footprint.RowPitch = rowPitch; + + d3d12CommandList->GraphicsCommandList.CommandList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr); + + TextureTransitionToDefaultUsage(d3d12CommandList, d3d12Texture, D3D12_RESOURCE_STATE_COPY_DEST); + } + + uint32 D3D12_GetDescriptorIndex(NonNullPtr device, NonNullPtr buffer) + { + auto* driver = static_cast(device->Driver); + return GetDescriptorIndex(driver, buffer); + } + + uint32 GetDescriptorIndexTexture(NonNullPtr /*device*/, NonNullPtr texture) + { + auto* textureContainer = reinterpret_cast(texture.Get()); + return textureContainer->ActiveTexture->SRVHandle.CpuHandleIndex; + } + +#if ALLOW_SHADER_HOT_RELOAD + bool D3D12_UpdateGraphicsPipelineShaders(NonNullPtr /*driver*/, NonNullPtr /*graphicsPipeline*/, + Shader* /*optional_vertexShader*/, Shader* /*optional_fragmentShader*/) + { + // Missing implementation, skipping for now + return false; + } +#endif + + GraphicsDevice* CreateGraphicsDevice(bool enableDebug) + { + Arena* driverArena = ArenaAllocate({} JULIET_DEBUG_ONLY(, "D3D12 Driver Arena")); + D3D12Driver* driver = ArenaPushStruct(driverArena JULIET_DEBUG_PARAM("D3D12Driver struct")); + + driver->DriverArena = driverArena; + +#if JULIET_DEBUG +#ifdef IDXGIINFOQUEUE_SUPPORTED + if (enableDebug) + { + InitializeDXGIDebug(driver); + } +#endif +#endif + IDXGIFactory1* factory1 = nullptr; + HRESULT result = CreateDXGIFactory1(IID_IDXGIFactory1, reinterpret_cast(&factory1)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "DX12: Cannot create DXGIFactory1"); + return nullptr; + } + + result = factory1->QueryInterface(IID_IDXGIFactory4, reinterpret_cast(&driver->DXGIFactory)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "DX12: Cannot create DXGIFactory4. Need DXGI1.4 support. Weird because it has been " + "checked in CheckDriver"); + return nullptr; + } + factory1->Release(); + + // Query DXGI1.5 and check for monitor Tearing support + IDXGIFactory5* factory5 = nullptr; + result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory5, reinterpret_cast(&factory5)); + if (SUCCEEDED(result)) + { + bool isTearingSupported = false; + result = factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &isTearingSupported, + sizeof(isTearingSupported)); + driver->IsTearingSupported = isTearingSupported; + if (FAILED(result)) + { + driver->IsTearingSupported = false; + } + factory5->Release(); + } + + // If available use DXGI1.6 to fetch the good graphics card. + // 1.6 should be available on most Win10 PC if they didnt their windows update. + // Lets support not having it for now... + IDXGIFactory6* factory6 = nullptr; + result = driver->DXGIFactory->QueryInterface(IID_IDXGIFactory6, reinterpret_cast(&factory6)); + if (SUCCEEDED(result)) + { + // TODO: Put into the config + static constexpr bool useLowPower = false; + result = factory6->EnumAdapterByGpuPreference(0, useLowPower ? DXGI_GPU_PREFERENCE_MINIMUM_POWER : DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, + IID_IDXGIAdapter1, reinterpret_cast(&driver->DXGIAdapter)); + factory6->Release(); + } + else + { + result = driver->DXGIFactory->EnumAdapters1(0, &driver->DXGIAdapter); + } + + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "Could not find adapter for D3D12Device"); + return nullptr; + } + + // Adapter is setup, get all the relevant info in the descriptor + DXGI_ADAPTER_DESC1 adapterDesc; + result = driver->DXGIAdapter->GetDesc1(&adapterDesc); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "Could not get DXGIAdapter description"); + return nullptr; + } + + // Driver version + LARGE_INTEGER umdVersion; + result = driver->DXGIAdapter->CheckInterfaceSupport(IID_IDXGIDevice, &umdVersion); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Assert(false, "Could not get DXGIAdapter driver version"); + return nullptr; + } + + Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Infos:"); + Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Adapter: %S", adapterDesc.Description); + Log(LogLevel::Message, LogCategory::Graphics, "D3D12 Driver Version: %d.%d.%d.%d", HIWORD(umdVersion.HighPart), + LOWORD(umdVersion.HighPart), HIWORD(umdVersion.LowPart), LOWORD(umdVersion.LowPart)); + + driver->D3D12DLL = LoadDynamicLibrary(D3D12_DLL); + if (driver->D3D12DLL == nullptr) + { + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't find " D3D12_DLL); + return nullptr; + } + + auto* D3D12CreateDeviceFuncPtr = + TOD3D12FuncPtr(PFN_D3D12_CREATE_DEVICE, LoadFunction(driver->D3D12DLL, D3D12_CREATEDEVICE_FUNC)); + if (D3D12CreateDeviceFuncPtr == nullptr) + { + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Couldn't Load function " D3D12_CREATEDEVICE_FUNC " in " D3D12_DLL); + DestroyDriver_Internal(driver); + return nullptr; + } + + driver->D3D12SerializeVersionedRootSignatureFct = + TOD3D12FuncPtr(PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE, + LoadFunction(driver->D3D12DLL, D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC)); + if (driver->D3D12SerializeVersionedRootSignatureFct == nullptr) + { + Log(LogLevel::Error, LogCategory::Graphics, + "DX12: Couldn't Load function " D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE_FUNC " in " D3D12_DLL); + DestroyDriver_Internal(driver); + return nullptr; + } + +#if JULIET_DEBUG + if (enableDebug) + { + InitializeD3D12DebugLayer(driver); + } +#endif + + result = D3D12CreateDeviceFuncPtr(static_cast(driver->DXGIAdapter), kD3DFeatureLevel, + IID_ID3D12Device5, reinterpret_cast(&driver->D3D12Device)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12Device5"); + return nullptr; + } + + Log(LogLevel::Message, LogCategory::Graphics, "DX12: D3D12Device Created: %p", (void*)driver->D3D12Device); + +#if JULIET_DEBUG + if (enableDebug) + { + if (!InitializeD3D12DebugInfoQueue(driver)) + { + return nullptr; + } + InitializeD3D12DebugInfoLogger(driver); + } +#endif + + // Check if UMA (unified memory architecture) is available. Used on APU i think ?? + D3D12_FEATURE_DATA_ARCHITECTURE architecture; + architecture.NodeIndex = 0; + result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_ARCHITECTURE, &architecture, + sizeof(D3D12_FEATURE_DATA_ARCHITECTURE)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not get the device architecture"); + return nullptr; + } + driver->IsUMAAvailable = architecture.UMA; + driver->IsUMACacheCoherent = architecture.CacheCoherentUMA; + + // Check "GPU Upload Heap" support (for fast uniform buffers. Not supported on my 5700xt + D3D12_FEATURE_DATA_D3D12_OPTIONS16 options16; + driver->GPUUploadHeapSupported = false; + result = driver->D3D12Device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &options16, sizeof(options16)); + if (SUCCEEDED(result)) + { + driver->GPUUploadHeapSupported = options16.GPUUploadHeapSupported; + } + + // Create bindless root signature + driver->BindlessRootSignature = CreateGraphicsRootSignature(driver); + + // Command Queues + // Graphics Queue only for now + D3D12_COMMAND_QUEUE_DESC queueDesc = {}; + queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queueDesc.NodeMask = 0; + queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL; + result = driver->D3D12Device->CreateCommandQueue(&queueDesc, IID_ID3D12CommandQueue, + reinterpret_cast(&driver->GraphicsQueue)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create D3D12CommandQueue: Graphics"); + return nullptr; + } + driver->GraphicsQueue->SetName(L"GRAPHICS_QUEUE"); + driver->QueueDesc[ToUnderlying(QueueType::Graphics)] = queueDesc; + + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE; + driver->QueueDesc[ToUnderlying(QueueType::Compute)] = queueDesc; + + queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + driver->QueueDesc[ToUnderlying(QueueType::Copy)] = queueDesc; + + // Indirect Commands + D3D12_COMMAND_SIGNATURE_DESC commandSignatureDesc; + D3D12_INDIRECT_ARGUMENT_DESC indirectArgumentDesc; + ZeroStruct(indirectArgumentDesc); + + indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW; + commandSignatureDesc.NodeMask = 0; + commandSignatureDesc.ByteStride = sizeof(IndirectDrawCommand); + commandSignatureDesc.NumArgumentDescs = 1; + commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; + result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, + reinterpret_cast(&driver->IndirectDrawCommandSignature)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create indirect draw command signature"); + return nullptr; + } + + indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED; + commandSignatureDesc.ByteStride = sizeof(IndexedIndirectDrawCommand); + commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; + + result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, + reinterpret_cast(&driver->IndirectIndexedDrawCommandSignature)); + if (FAILED(result)) + { + + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create INDEXED Indirect draw command signature"); + return nullptr; + } + + indirectArgumentDesc.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH; + commandSignatureDesc.ByteStride = sizeof(IndirectDispatchCommand); + commandSignatureDesc.pArgumentDescs = &indirectArgumentDesc; + + result = driver->D3D12Device->CreateCommandSignature(&commandSignatureDesc, nullptr, IID_ID3D12CommandSignature, + reinterpret_cast(&driver->IndirectDispatchCommandSignature)); + if (FAILED(result)) + { + DestroyDriver_Internal(driver); + Log(LogLevel::Error, LogCategory::Graphics, "DX12: Could not create Indirect dispatch command signature"); + return nullptr; + } + + // Create Pools + constexpr static size_t kMaxCommandListNumber = 16; + driver->SubmittedCommandListCapacity = kMaxCommandListNumber; + driver->SubmittedCommandListCount = 0; + driver->SubmittedCommandLists = ArenaPushArray( + driver->DriverArena, kMaxCommandListNumber JULIET_DEBUG_PARAM("Command list Ptr Array Count: {}", kMaxCommandListNumber)); + if (!driver->SubmittedCommandLists) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + constexpr static size_t kMaxFencesNumber = 16; + driver->AvailableFenceCapacity = kMaxFencesNumber; + driver->AvailableFenceCount = 0; + driver->AvailableFences = + ArenaPushArray(driver->DriverArena, + kMaxFencesNumber JULIET_DEBUG_PARAM("Fence Ptr Array Count: {}", kMaxFencesNumber)); + if (!driver->AvailableFences) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + // Staging descriptor pools + for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) + { + driver->StagingDescriptorPools[i] = CreateStagingDescriptorPool(driver, static_cast(i)); + + if (driver->StagingDescriptorPools[i] == nullptr) + { + DestroyDriver_Internal(driver); + return nullptr; + } + } + + CreateDescriptorHeapPool(driver, driver->SamplerHeapPool, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, + GPUDriver::kSampler_HeapDescriptorCount); + + // Deferred dispose vectors + driver->GraphicsPipelinesToDisposeCapacity = 4; + driver->GraphicsPipelinesToDisposeCount = 0; + driver->GraphicsPipelinesToDispose = static_cast( + Calloc(driver->GraphicsPipelinesToDisposeCapacity, sizeof(D3D12GraphicsPipeline*))); + if (!driver->GraphicsPipelinesToDispose) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + driver->Semantic = WrapString("TEXCOORD"); + driver->FramesInFlight = 2; + + auto device = static_cast(Calloc(1, sizeof(GraphicsDevice))); + if (!device) + { + DestroyDriver_Internal(driver); + return nullptr; + } + + // Assign Functions to the device + device->DestroyDevice = D3D12_DestroyGraphicsDevice; + device->AttachToWindow = AttachToWindow; + device->DetachFromWindow = DetachFromWindow; + device->AcquireSwapChainTexture = D3D12_AcquireSwapChainTexture; + device->WaitAndAcquireSwapChainTexture = D3D12_WaitAndAcquireSwapChainTexture; + device->GetSwapChainTextureFormat = GetSwapChainTextureFormat; + device->AcquireCommandList = AcquireCommandList; + device->SubmitCommandLists = D3D12_SubmitCommandLists; + device->BeginRenderPass = BeginRenderPass; + device->EndRenderPass = EndRenderPass; + device->SetViewPort = SetViewPort; + device->SetScissorRect = SetScissorRect; + device->SetBlendConstants = SetBlendConstants; + device->SetStencilReference = SetStencilReference; + device->BindGraphicsPipeline = BindGraphicsPipeline; + device->DrawPrimitives = DrawPrimitives; + device->DrawIndexedPrimitives = DrawIndexedPrimitives; + device->SetIndexBuffer = D3D12_SetIndexBuffer; + device->WaitUntilGPUIsIdle = WaitUntilGPUIsIdle; + device->SetPushConstants = D3D12_SetPushConstants; + device->QueryFence = QueryFence; + device->ReleaseFence = ReleaseFence; + device->CreateShader = CreateShader; + device->DestroyShader = DestroyShader; + device->CreateGraphicsPipeline = CreateGraphicsPipeline; + device->DestroyGraphicsPipeline = D3D12_DestroyGraphicsPipeline; + device->CreateGraphicsBuffer = CreateGraphicsBuffer; + device->DestroyGraphicsBuffer = DestroyGraphicsBuffer; + device->MapGraphicsBuffer = MapBuffer; + device->UnmapGraphicsBuffer = UnmapBuffer; + device->CreateGraphicsTransferBuffer = CreateGraphicsTransferBuffer; + device->DestroyGraphicsTransferBuffer = DestroyGraphicsTransferBuffer; + device->MapGraphicsTransferBuffer = MapBuffer; + device->UnmapGraphicsTransferBuffer = UnmapBuffer; + device->CopyBuffer = D3D12_CopyBuffer; + device->CopyBufferToTexture = D3D12_CopyBufferToTexture; + device->TransitionBufferToReadable = D3D12_TransitionBufferToReadable; + device->GetDescriptorIndex = D3D12_GetDescriptorIndex; + device->GetDescriptorIndexTexture = GetDescriptorIndexTexture; + device->CreateTexture = CreateTexture; + device->DestroyTexture = DestroyTexture; + +#if ALLOW_SHADER_HOT_RELOAD + device->UpdateGraphicsPipelineShaders = D3D12_UpdateGraphicsPipelineShaders; +#endif + + device->Driver = driver; + device->DebugEnabled = enableDebug; + + driver->GraphicsDevice = device; + + // Create Global Bindless Heap that stays alive for the driver whole lifetime + driver->BindlessDescriptorHeap = CreateDescriptorHeap(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, + GPUDriver::kCBV_SRV_UAV_HeapDescriptorCount, false); + + return device; + } + +} // namespace Juliet namespace Juliet { @@ -1098,7 +4687,7 @@ namespace Juliet GraphicsDeviceFactory DX12DeviceFactory = { .Name="DirectX12", .Type=DriverType::DX12, - .CheckDriver = D3D12::CheckDriver, - .CreateGraphicsDevice = D3D12::CreateGraphicsDevice }; + .CheckDriver = D3D12_CheckDriver, + .CreateGraphicsDevice = CreateGraphicsDevice }; // clang-format on } // namespace Juliet diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h deleted file mode 100644 index 6882af4..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.h +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Juliet -{ - struct DynamicLibrary; -} - -namespace Juliet::D3D12 -{ - struct D3D12StagingDescriptorPool; - // Forward Declare - struct D3D12CommandList; - struct D3D12Fence; - - enum class RootParameters : uint8 - { - Constants32Bits, - Count, - }; - - struct D3D12WindowData - { - Window* Window; - - IDXGISwapChain3* SwapChain; - D3D12TextureContainer SwapChainTextureContainers[GPUDriver::kMaxFramesInFlight]; - DXGI_COLOR_SPACE_TYPE SwapChainColorSpace; - SwapChainComposition SwapChainComposition; - uint8 SwapChainTextureCount; - - PresentMode PresentMode; - - Fence* InFlightFences[GPUDriver::kMaxFramesInFlight]; - - uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter - uint32 Width; - uint32 Height; - }; - - struct D3D12Driver : GPUDriver - { - GraphicsDevice* GraphicsDevice; - - // D3D12 - DynamicLibrary* D3D12DLL; - ID3D12Device5* D3D12Device; - PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE D3D12SerializeVersionedRootSignatureFct; - ID3D12CommandQueue* GraphicsQueue; - D3D12_COMMAND_QUEUE_DESC QueueDesc[ToUnderlying(QueueType::Count)]; -#if JULIET_DEBUG - ID3D12Debug1* D3D12Debug; -#endif - - // Indirect commands signature - ID3D12CommandSignature* IndirectDrawCommandSignature; - ID3D12CommandSignature* IndirectIndexedDrawCommandSignature; - ID3D12CommandSignature* IndirectDispatchCommandSignature; - - // DXGI - IDXGIFactory4* DXGIFactory; - IDXGIAdapter1* DXGIAdapter; -#if JULIET_DEBUG - DynamicLibrary* DXGIDebugDLL; - IDXGIDebug* DXGIDebug; -#ifdef IDXGIINFOQUEUE_SUPPORTED - IDXGIInfoQueue* DXGIInfoQueue; -#endif -#endif - - // Windows - // TODO: Support more than one window - D3D12WindowData* WindowData; - - // Resources - D3D12CommandList** AvailableCommandLists; - uint8 AvailableCommandListCapacity; - uint8 AvailableCommandListCount; - - D3D12CommandList** SubmittedCommandLists; - uint8 SubmittedCommandListCapacity; - uint8 SubmittedCommandListCount; - - D3D12Fence** AvailableFences; - uint32 AvailableFenceCount; - uint32 AvailableFenceCapacity; - - D3D12GraphicsPipeline** GraphicsPipelinesToDispose; - uint32 GraphicsPipelinesToDisposeCount; - uint32 GraphicsPipelinesToDisposeCapacity; - - D3D12GraphicsRootSignature* BindlessRootSignature; - - D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; - Internal::D3D12DescriptorHeap* BindlessDescriptorHeap; - Internal::D3D12DescriptorHeapPool SamplerHeapPool; - - String Semantic; - - uint8 FramesInFlight; - uint64 FrameCounter = 0; // Number of frame since inception - - bool IsTearingSupported : 1; - bool IsUMAAvailable : 1; - bool IsUMACacheCoherent : 1; - bool GPUUploadHeapSupported : 1; - }; - - namespace Internal - { - void DisposePendingResourcces(NonNullPtr driver); - } -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp deleted file mode 100644 index 53bd778..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.cpp +++ /dev/null @@ -1,557 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - // clang-format off - D3D12_INPUT_CLASSIFICATION JulietToD3D12_InputRate[] = - { - D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, // VERTEX - D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA // INSTANCE - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_InputRate) / sizeof(JulietToD3D12_InputRate[0]) == ToUnderlying(VertexInputRate::Count)); - - // clang-format off - D3D12_CULL_MODE JulietToD3D12_CullMode[] = - { - D3D12_CULL_MODE_NONE, - D3D12_CULL_MODE_FRONT, - D3D12_CULL_MODE_BACK - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_CullMode) / sizeof(JulietToD3D12_CullMode[0]) == ToUnderlying(CullMode::Count)); - - // clang-format off - D3D12_FILL_MODE JulietToD3D12_FillMode[] = - { - D3D12_FILL_MODE_SOLID, - D3D12_FILL_MODE_WIREFRAME - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_FillMode) / sizeof(JulietToD3D12_FillMode[0]) == ToUnderlying(FillMode::Count)); - - DXGI_FORMAT JulietToD3D12_VertexFormat[] = { - DXGI_FORMAT_UNKNOWN, // Unknown - DXGI_FORMAT_R32_SINT, // Int - DXGI_FORMAT_R32G32_SINT, // Int2 - DXGI_FORMAT_R32G32B32_SINT, // Int3 - DXGI_FORMAT_R32G32B32A32_SINT, // Int4 - DXGI_FORMAT_R32_UINT, // UInt - DXGI_FORMAT_R32G32_UINT, // UInt2 - DXGI_FORMAT_R32G32B32_UINT, // UInt3 - DXGI_FORMAT_R32G32B32A32_UINT, // UInt4 - DXGI_FORMAT_R32_FLOAT, // Float - DXGI_FORMAT_R32G32_FLOAT, // Float2 - DXGI_FORMAT_R32G32B32_FLOAT, // Float3 - DXGI_FORMAT_R32G32B32A32_FLOAT, // Float4 - DXGI_FORMAT_R8G8_SINT, // Byte2 - DXGI_FORMAT_R8G8B8A8_SINT, // Byte4 - DXGI_FORMAT_R8G8_UINT, // UByte2 - DXGI_FORMAT_R8G8B8A8_UINT, // UByte4 - DXGI_FORMAT_R8G8_SNORM, // Byte2_Norm - DXGI_FORMAT_R8G8B8A8_SNORM, // Byte4_Norm - DXGI_FORMAT_R8G8_UNORM, // UByte2_Norm - DXGI_FORMAT_R8G8B8A8_UNORM, // UByte4_Norm - DXGI_FORMAT_R16G16_SINT, // Short2 - DXGI_FORMAT_R16G16B16A16_SINT, // Short4 - DXGI_FORMAT_R16G16_UINT, // UShort2 - DXGI_FORMAT_R16G16B16A16_UINT, // UShort4 - DXGI_FORMAT_R16G16_SNORM, // Short2_Norm - DXGI_FORMAT_R16G16B16A16_SNORM, // Short4_Norm - DXGI_FORMAT_R16G16_UNORM, // UShort2_Norm - DXGI_FORMAT_R16G16B16A16_UNORM, // UShort4_Norm - DXGI_FORMAT_R16G16_FLOAT, // Half2 - DXGI_FORMAT_R16G16B16A16_FLOAT // Half4 - }; - static_assert(sizeof(JulietToD3D12_VertexFormat) / sizeof(JulietToD3D12_VertexFormat[0]) == - ToUnderlying(VertexElementFormat::Count)); - - // clang-format off - D3D12_PRIMITIVE_TOPOLOGY_TYPE JulietToD3D12_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 - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_PrimitiveTopologyType) / sizeof(JulietToD3D12_PrimitiveTopologyType[0]) == - ToUnderlying(PrimitiveType::Count)); - - // clang-format off - D3D12_BLEND JulietToD3D12_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, - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_BlendFactor) / sizeof(JulietToD3D12_BlendFactor[0]) == ToUnderlying(BlendFactor::Count)); - - // clang-format off - D3D12_BLEND JulietToD3D12_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, - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_BlendFactorAlpha) / sizeof(JulietToD3D12_BlendFactorAlpha[0]) == - ToUnderlying(BlendFactor::Count)); - - // clang-format off - D3D12_BLEND_OP JulietToD3D12_BlendOperation[] = - { - 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 - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_BlendOperation) / sizeof(JulietToD3D12_BlendOperation[0]) == - ToUnderlying(BlendOperation::Count)); - - // clang-format off - D3D12_COMPARISON_FUNC JulietToD3D12_CompareOperation[] = - { - 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 - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_CompareOperation) / sizeof(JulietToD3D12_CompareOperation[0]) == - ToUnderlying(CompareOperation::Count)); - - // clang-format off - D3D12_STENCIL_OP JulietToD3D12_StencilOperation[] = - { - 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 - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_StencilOperation) / sizeof(JulietToD3D12_StencilOperation[0]) == - ToUnderlying(StencilOperation::Count)); - - bool ConvertVertexInputState(const VertexInputState& vertexInputState, D3D12_INPUT_ELEMENT_DESC* desc, String semantic) - { - if (desc == nullptr || vertexInputState.NumVertexAttributes == 0) - { - return false; - } - - for (uint32 idx = 0; idx < vertexInputState.NumVertexAttributes; ++idx) - { - VertexAttribute attribute = vertexInputState.VertexAttributes[idx]; - - desc[idx].SemanticName = CStr(semantic); - desc[idx].SemanticIndex = attribute.Location; - desc[idx].Format = JulietToD3D12_VertexFormat[ToUnderlying(attribute.Format)]; - desc[idx].InputSlot = attribute.BufferSlot; - desc[idx].AlignedByteOffset = attribute.Offset; - desc[idx].InputSlotClass = - JulietToD3D12_InputRate[ToUnderlying(vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate)]; - desc[idx].InstanceDataStepRate = - (vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InputRate == VertexInputRate::Instance) - ? vertexInputState.VertexBufferDescriptions[attribute.BufferSlot].InstanceStepRate - : 0; - } - - return true; - } - - bool ConvertRasterizerState(const RasterizerState& rasterizerState, D3D12_RASTERIZER_DESC& desc) - { - desc.FillMode = JulietToD3D12_FillMode[ToUnderlying(rasterizerState.FillMode)]; - desc.CullMode = JulietToD3D12_CullMode[ToUnderlying(rasterizerState.CullMode)]; - - switch (rasterizerState.FrontFace) - { - case FrontFace::CounterClockwise: desc.FrontCounterClockwise = TRUE; break; - case FrontFace::Clockwise: desc.FrontCounterClockwise = FALSE; break; - default: return false; - } - static_assert(ToUnderlying(FrontFace::Count) == 2); - - if (rasterizerState.EnableDepthBias) - { - desc.DepthBias = LRoundF(rasterizerState.DepthBiasConstantFactor); - desc.DepthBiasClamp = rasterizerState.DepthBiasClamp; - desc.SlopeScaledDepthBias = rasterizerState.DepthBiasSlopeFactor; - } - else - { - desc.DepthBias = 0; - desc.DepthBiasClamp = 0.0f; - desc.SlopeScaledDepthBias = 0.0f; - } - - desc.DepthClipEnable = rasterizerState.EnableDepthClip; - desc.MultisampleEnable = FALSE; - desc.AntialiasedLineEnable = FALSE; - desc.ForcedSampleCount = 0; - desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; - return true; - } - - bool ConvertBlendState(const GraphicsPipelineCreateInfo& createInfo, D3D12_BLEND_DESC& blendDesc) - { - ZeroStruct(blendDesc); - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = FALSE; - - for (UINT i = 0; i < GPUDriver::kMaxColorTargetInfo; 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 target_info has more blend states, you can set IndependentBlendEnable to TRUE and assign different blend states to each render target slot - if (i < createInfo.TargetInfo.NumColorTargets) - { - ColorTargetBlendState blendState = createInfo.TargetInfo.ColorTargetDescriptions[i].BlendState; - ColorComponentFlags colorWriteMask = - blendState.EnableColorWriteMask ? blendState.ColorWriteMask : static_cast(0xF); - - rtBlendDesc.BlendEnable = blendState.EnableBlend; - rtBlendDesc.SrcBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.SourceColorBlendFactor)]; - rtBlendDesc.DestBlend = JulietToD3D12_BlendFactor[ToUnderlying(blendState.DestinationColorBlendFactor)]; - rtBlendDesc.BlendOp = JulietToD3D12_BlendOperation[ToUnderlying(blendState.ColorBlendOperation)]; - rtBlendDesc.SrcBlendAlpha = JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.SourceAlphaBlendFactor)]; - rtBlendDesc.DestBlendAlpha = - JulietToD3D12_BlendFactorAlpha[ToUnderlying(blendState.DestinationAlphaBlendFactor)]; - rtBlendDesc.BlendOpAlpha = JulietToD3D12_BlendOperation[ToUnderlying(blendState.AlphaBlendOperation)]; - rtBlendDesc.RenderTargetWriteMask = ToUnderlying(colorWriteMask); - - if (i > 0) - { - blendDesc.IndependentBlendEnable = TRUE; - } - } - - blendDesc.RenderTarget[i] = rtBlendDesc; - } - - return true; - } - - bool ConvertDepthStencilState(DepthStencilState depthStencilState, D3D12_DEPTH_STENCIL_DESC& desc) - { - desc.DepthEnable = depthStencilState.EnableDepthTest == true ? TRUE : FALSE; - desc.DepthWriteMask = depthStencilState.EnableDepthWrite == true ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; - desc.DepthFunc = JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.CompareOperation)]; - desc.StencilEnable = depthStencilState.EnableStencilTest == true ? TRUE : FALSE; - desc.StencilReadMask = depthStencilState.CompareMask; - desc.StencilWriteMask = depthStencilState.WriteMask; - - desc.FrontFace.StencilFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.FailOperation)]; - desc.FrontFace.StencilDepthFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.DepthFailOperation)]; - desc.FrontFace.StencilPassOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.FrontStencilState.PassOperation)]; - desc.FrontFace.StencilFunc = - JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.FrontStencilState.CompareOperation)]; - - desc.BackFace.StencilFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.FailOperation)]; - desc.BackFace.StencilDepthFailOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.DepthFailOperation)]; - desc.BackFace.StencilPassOp = - JulietToD3D12_StencilOperation[ToUnderlying(depthStencilState.BackStencilState.PassOperation)]; - desc.BackFace.StencilFunc = - JulietToD3D12_CompareOperation[ToUnderlying(depthStencilState.BackStencilState.CompareOperation)]; - - return true; - } - -#if ALLOW_SHADER_HOT_RELOAD - void CopyShader(NonNullPtr destination, NonNullPtr source) - { - D3D12Shader* src = source.Get(); - D3D12Shader* dst = destination.Get(); - - ByteBuffer dstBuffer = dst->ByteCode; - - if (src->ByteCode.Size != dstBuffer.Size) - { - dstBuffer.Data = static_cast(Realloc(dstBuffer.Data, src->ByteCode.Size)); - dstBuffer.Size = src->ByteCode.Size; - } - // Copy the shader data. Infortunately this will overwrite the bytecode if it exists so we patch it back just after - MemCopy(dst, src, sizeof(D3D12Shader)); - dst->ByteCode = dstBuffer; - - MemCopy(dst->ByteCode.Data, src->ByteCode.Data, src->ByteCode.Size); - } -#endif - } // namespace - - GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo) - { - auto d3d12Driver = static_cast(driver.Get()); - auto vertexShader = reinterpret_cast(createInfo.VertexShader); - auto fragmentShader = reinterpret_cast(createInfo.FragmentShader); - - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; - psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; - psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; - psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; // PS == Pixel Shader == Fragment Shader - psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; - - if (createInfo.VertexInputState.NumVertexAttributes > 0) - { - D3D12_INPUT_ELEMENT_DESC inputElementDescs[D3D12_IA_VERTEX_INPUT_STRUCTURE_ELEMENT_COUNT]; - psoDesc.InputLayout.pInputElementDescs = inputElementDescs; - psoDesc.InputLayout.NumElements = createInfo.VertexInputState.NumVertexAttributes; - ConvertVertexInputState(createInfo.VertexInputState, inputElementDescs, d3d12Driver->Semantic); - } - - psoDesc.PrimitiveTopologyType = JulietToD3D12_PrimitiveTopologyType[ToUnderlying(createInfo.PrimitiveType)]; - - if (!ConvertRasterizerState(createInfo.RasterizerState, psoDesc.RasterizerState)) - { - return nullptr; - } - if (!ConvertBlendState(createInfo, psoDesc.BlendState)) - { - return nullptr; - } - if (!ConvertDepthStencilState(createInfo.DepthStencilState, psoDesc.DepthStencilState)) - { - return nullptr; - } - - auto pipeline = static_cast(Calloc(1, sizeof(D3D12GraphicsPipeline))); - if (!pipeline) - { - return nullptr; - } - - uint32 sampleMask = createInfo.MultisampleState.EnableMask ? createInfo.MultisampleState.SampleMask : 0xFFFFFFFF; - - psoDesc.SampleMask = sampleMask; - psoDesc.SampleDesc.Count = Internal::JulietToD3D12_SampleCount[ToUnderlying(createInfo.MultisampleState.SampleCount)]; - psoDesc.SampleDesc.Quality = - (createInfo.MultisampleState.SampleCount > TextureSampleCount::One) ? DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN : 0; - - psoDesc.DSVFormat = Internal::ConvertToD3D12DepthFormat(createInfo.TargetInfo.DepthStencilFormat); - psoDesc.NumRenderTargets = static_cast(createInfo.TargetInfo.NumColorTargets); - for (uint32_t idx = 0; idx < createInfo.TargetInfo.NumColorTargets; ++idx) - { - psoDesc.RTVFormats[idx] = - Internal::ConvertToD3D12TextureFormat(createInfo.TargetInfo.ColorTargetDescriptions[idx].Format); - } - - // Assuming some default values or further initialization - psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - psoDesc.CachedPSO.CachedBlobSizeInBytes = 0; - psoDesc.CachedPSO.pCachedBlob = nullptr; - - psoDesc.NodeMask = 0; - - pipeline->RootSignature = d3d12Driver->BindlessRootSignature; - psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; - - ID3D12PipelineState* pipelineState; - HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, - reinterpret_cast(&pipelineState)); - if (FAILED(res)) - { - LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); - Internal::ReleaseGraphicsPipeline(pipeline); - return nullptr; - } - - pipeline->PipelineState = pipelineState; - - for (uint32 i = 0; i < createInfo.VertexInputState.NumVertexBufferDescriptions; i += 1) - { - pipeline->VertexStrides[createInfo.VertexInputState.VertexBufferDescriptions[i].Slot] = - createInfo.VertexInputState.VertexBufferDescriptions[i].PitchInBytes; - } - - pipeline->PrimitiveType = createInfo.PrimitiveType; - - pipeline->VertexSamplerCount = vertexShader->NumSamplers; - pipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; - pipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; - pipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; - - pipeline->FragmentSamplerCount = fragmentShader->NumSamplers; - pipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; - pipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; - pipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; - - pipeline->ReferenceCount = 0; - -#if ALLOW_SHADER_HOT_RELOAD - // Save the PSODesc and shaders to be able to recreate the graphics pipeline when needed - pipeline->PSODescTemplate = psoDesc; - - pipeline->VertexShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); - pipeline->FragmentShaderCache = static_cast(Calloc(1, sizeof(D3D12Shader))); - CopyShader(pipeline->VertexShaderCache, vertexShader); - CopyShader(pipeline->FragmentShaderCache, fragmentShader); -#endif - - return reinterpret_cast(pipeline); - } - - void DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr graphicsPipeline) - { - auto d3d12Driver = static_cast(driver.Get()); - auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get()); - - if (d3d12Driver->GraphicsPipelinesToDisposeCount + 1 >= d3d12Driver->GraphicsPipelinesToDisposeCapacity) - { - d3d12Driver->GraphicsPipelinesToDisposeCapacity = d3d12Driver->GraphicsPipelinesToDisposeCapacity * 2; - d3d12Driver->GraphicsPipelinesToDispose = static_cast( - Realloc(d3d12Driver->GraphicsPipelinesToDispose, - sizeof(D3D12GraphicsPipeline*) * d3d12Driver->GraphicsPipelinesToDisposeCapacity)); - } - d3d12Driver->GraphicsPipelinesToDispose[d3d12Driver->GraphicsPipelinesToDisposeCount] = d3d12GraphicsPipeline; - d3d12Driver->GraphicsPipelinesToDisposeCount += 1; - } - -#if ALLOW_SHADER_HOT_RELOAD - bool UpdateGraphicsPipelineShaders(NonNullPtr driver, NonNullPtr graphicsPipeline, - Shader* optional_vertexShader, Shader* optional_fragmentShader) - { - auto d3d12Driver = static_cast(driver.Get()); - auto d3d12GraphicsPipeline = reinterpret_cast(graphicsPipeline.Get()); - - Assert(d3d12GraphicsPipeline->ReferenceCount == 0 && - "Trying to update a d3d12 graphics pipeline that is currently being used! Call WaitUntilGPUIsIdle " - "before updating!"); - - auto vertexShader = reinterpret_cast(optional_vertexShader); - auto fragmentShader = reinterpret_cast(optional_fragmentShader); - - if (!vertexShader) - { - vertexShader = d3d12GraphicsPipeline->VertexShaderCache; - } - - if (!fragmentShader) - { - fragmentShader = d3d12GraphicsPipeline->FragmentShaderCache; - } - - auto psoDesc = d3d12GraphicsPipeline->PSODescTemplate; - psoDesc.VS.pShaderBytecode = vertexShader->ByteCode.Data; - psoDesc.VS.BytecodeLength = vertexShader->ByteCode.Size; - psoDesc.PS.pShaderBytecode = fragmentShader->ByteCode.Data; - psoDesc.PS.BytecodeLength = fragmentShader->ByteCode.Size; - - psoDesc.pRootSignature = d3d12Driver->BindlessRootSignature->Handle; - - ID3D12PipelineState* pipelineState; - HRESULT res = d3d12Driver->D3D12Device->CreateGraphicsPipelineState(&psoDesc, IID_ID3D12PipelineState, - reinterpret_cast(&pipelineState)); - if (FAILED(res)) - { - LogError(d3d12Driver->D3D12Device, "Could not create graphics pipeline state", res); - return false; - } - - d3d12GraphicsPipeline->VertexSamplerCount = vertexShader->NumSamplers; - d3d12GraphicsPipeline->VertexStorageTextureCount = vertexShader->NumStorageTextures; - d3d12GraphicsPipeline->VertexStorageBufferCount = vertexShader->NumStorageBuffers; - d3d12GraphicsPipeline->VertexUniformBufferCount = vertexShader->NumUniformBuffers; - - d3d12GraphicsPipeline->FragmentSamplerCount = fragmentShader->NumSamplers; - d3d12GraphicsPipeline->FragmentStorageTextureCount = fragmentShader->NumStorageTextures; - d3d12GraphicsPipeline->FragmentStorageBufferCount = fragmentShader->NumStorageBuffers; - d3d12GraphicsPipeline->FragmentUniformBufferCount = fragmentShader->NumUniformBuffers; - - // If everything worked, we patch the graphics pipeline and destroy everything irrelevant - if (d3d12GraphicsPipeline->PipelineState) - { - d3d12GraphicsPipeline->PipelineState->Release(); - } - d3d12GraphicsPipeline->PipelineState = pipelineState; - - if (vertexShader != d3d12GraphicsPipeline->VertexShaderCache) - { - CopyShader(d3d12GraphicsPipeline->VertexShaderCache, vertexShader); - } - if (fragmentShader != d3d12GraphicsPipeline->FragmentShaderCache) - { - CopyShader(d3d12GraphicsPipeline->FragmentShaderCache, fragmentShader); - } - - return true; - } -#endif - - namespace Internal - { - void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline) - { - if (d3d12GraphicsPipeline->PipelineState) - { - d3d12GraphicsPipeline->PipelineState->Release(); - } - -#if ALLOW_SHADER_HOT_RELOAD - SafeFree(d3d12GraphicsPipeline->VertexShaderCache); - SafeFree(d3d12GraphicsPipeline->FragmentShaderCache); -#endif - - Free(d3d12GraphicsPipeline.Get()); - } - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h b/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h deleted file mode 100644 index 7ef7c43..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsPipeline.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace Juliet -{ - struct GraphicsPipelineCreateInfo; - struct GPUDriver; - struct GraphicsPipeline; -} // namespace Juliet - -namespace Juliet::D3D12 -{ - struct D3D12Shader; - - struct D3D12GraphicsRootSignature - { - ID3D12RootSignature* Handle; - }; - - struct D3D12GraphicsPipeline - { -#if ALLOW_SHADER_HOT_RELOAD - // Template to recreate an ID3D12PipelineState when shader are hot reloaded - // Stripped out in shipping build as the struct is huge - D3D12_GRAPHICS_PIPELINE_STATE_DESC PSODescTemplate; - - // Keeping shaders byte code to make it easier to recreate the ID3D12PipelineState - // Those will be freed when the pipeline is destroyed or updated - D3D12Shader* VertexShaderCache; - D3D12Shader* FragmentShaderCache; -#endif - - ID3D12PipelineState* PipelineState; - D3D12GraphicsRootSignature* RootSignature; - PrimitiveType PrimitiveType; - - uint32 VertexStrides[GPUDriver::kMaxVertexBuffers]; - - uint32 VertexSamplerCount; - uint32 VertexUniformBufferCount; - uint32 VertexStorageBufferCount; - uint32 VertexStorageTextureCount; - - uint32 FragmentSamplerCount; - uint32 FragmentUniformBufferCount; - uint32 FragmentStorageBufferCount; - uint32 FragmentStorageTextureCount; - - int ReferenceCount; - }; - - extern GraphicsPipeline* CreateGraphicsPipeline(NonNullPtr driver, const GraphicsPipelineCreateInfo& createInfo); - extern void DestroyGraphicsPipeline(NonNullPtr driver, NonNullPtr graphicsPipeline); - extern bool UpdateGraphicsPipelineShaders(NonNullPtr driver, NonNullPtr graphicsPipeline, - Shader* optional_vertexShader, Shader* optional_fragmentShader); - namespace Internal - { - extern void ReleaseGraphicsPipeline(NonNullPtr d3d12GraphicsPipeline); - } -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12InternalTests.cpp b/Juliet/src/Graphics/D3D12/D3D12InternalTests.cpp deleted file mode 100644 index 4bcbbe4..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12InternalTests.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include -#include - -#if JULIET_DEBUG - -namespace Juliet::D3D12::UnitTest -{ - using namespace Juliet::D3D12; - using namespace Juliet::D3D12::Internal; -} // namespace Juliet::D3D12::UnitTest -#endif diff --git a/Juliet/src/Graphics/D3D12/D3D12InternalTests.h b/Juliet/src/Graphics/D3D12/D3D12InternalTests.h deleted file mode 100644 index cc7ee8d..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12InternalTests.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include - -#if JULIET_DEBUG -namespace Juliet::D3D12::UnitTest -{ -} -#endif diff --git a/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp deleted file mode 100644 index 3a0810a..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp +++ /dev/null @@ -1,294 +0,0 @@ -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - // clang-format off - D3D12_PRIMITIVE_TOPOLOGY JulietToD3D12_PrimitiveType[] = - { - D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - D3D_PRIMITIVE_TOPOLOGY_LINELIST, - D3D_PRIMITIVE_TOPOLOGY_LINESTRIP, - D3D_PRIMITIVE_TOPOLOGY_POINTLIST - }; - // clang-format on - static_assert(sizeof(JulietToD3D12_PrimitiveType) / sizeof(JulietToD3D12_PrimitiveType[0]) == - ToUnderlying(PrimitiveType::Count)); - } // namespace - - void BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, - uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - - uint32 frameBufferWidth = uint32Max; - uint32 frameBufferHeight = uint32Max; - - for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) - { - auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); - uint32 width = container->Header.CreateInfo.Width >> colorTargetInfos[idx].MipLevel; - uint32 height = container->Header.CreateInfo.Height >> colorTargetInfos[idx].MipLevel; - - // Scale the framebuffer to fit the smallest target. - frameBufferWidth = Min(width, frameBufferWidth); - frameBufferHeight = Min(height, frameBufferHeight); - } - - // Depth Stencil and DSV - D3D12_CPU_DESCRIPTOR_HANDLE DSV; - bool hasDSV = false; - if (depthStencilTargetInfo && depthStencilTargetInfo->TargetTexture) - { - auto* container = reinterpret_cast(depthStencilTargetInfo->TargetTexture); - uint32 width = container->Header.CreateInfo.Width; - uint32 height = container->Header.CreateInfo.Height; - - frameBufferWidth = Min(width, frameBufferWidth); - frameBufferHeight = Min(height, frameBufferHeight); - - D3D12TextureSubresource* subresource = - Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, container, 0, 0, false, D3D12_RESOURCE_STATE_DEPTH_WRITE); - - DSV = subresource->DSVHandle.CpuHandle; - hasDSV = true; - d3d12CommandList->DepthStencilSubresource = subresource; - - Internal::TrackTexture(d3d12CommandList, subresource->Parent); - - if (depthStencilTargetInfo->LoadOperation == LoadOperation::Clear) - { - D3D12_CLEAR_FLAGS clearFlags = D3D12_CLEAR_FLAG_DEPTH; - // TODO: Check if texture has stencil - // if (HasStencil(container->Header.CreateInfo.Format)) clearFlags |= D3D12_CLEAR_FLAG_STENCIL; - - d3d12CommandList->GraphicsCommandList.CommandList->ClearDepthStencilView(DSV, clearFlags, - depthStencilTargetInfo->ClearDepth, - depthStencilTargetInfo->ClearStencil, - 0, nullptr); - } - } - - D3D12_CPU_DESCRIPTOR_HANDLE RTVs[GPUDriver::kMaxColorTargetInfo]; - for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) - { - auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); - D3D12TextureSubresource* subresource = Internal::PrepareTextureSubresourceForWrite( - d3d12CommandList, container, - container->Header.CreateInfo.Type == TextureType::Texture_3D ? 0 : colorTargetInfos[idx].LayerIndex, - colorTargetInfos[idx].MipLevel, colorTargetInfos[idx].CycleTexture, D3D12_RESOURCE_STATE_RENDER_TARGET); - - uint32 RTVIndex = container->Header.CreateInfo.Type == TextureType::Texture_3D ? colorTargetInfos[idx].DepthPlane : 0; - D3D12_CPU_DESCRIPTOR_HANDLE rtv = subresource->RTVHandles[RTVIndex].CpuHandle; - - if (colorTargetInfos[idx].LoadOperation == LoadOperation::Clear) - { - float clearColor[4]; - clearColor[0] = colorTargetInfos[idx].ClearColor.R; - clearColor[1] = colorTargetInfos[idx].ClearColor.G; - clearColor[2] = colorTargetInfos[idx].ClearColor.B; - clearColor[3] = colorTargetInfos[idx].ClearColor.A; - - d3d12CommandList->GraphicsCommandList.CommandList->ClearRenderTargetView(rtv, clearColor, 0, nullptr); - } - - RTVs[idx] = rtv; - d3d12CommandList->ColorTargetSubresources[idx] = subresource; - - Internal::TrackTexture(d3d12CommandList, subresource->Parent); - - if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve || - colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore) - { - auto resolveContainer = reinterpret_cast(colorTargetInfos[idx].ResolveTexture); - D3D12TextureSubresource* resolveSubresource = - Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer, - colorTargetInfos[idx].ResolveLayerIndex, - colorTargetInfos[idx].ResolveMipLevel, - colorTargetInfos[idx].CycleResolveTexture, - D3D12_RESOURCE_STATE_RESOLVE_DEST); - - d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; - - Internal::TrackTexture(d3d12CommandList, resolveSubresource->Parent); - } - } - - d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(colorTargetInfoCount, RTVs, false, - hasDSV ? &DSV : nullptr); - - // Set defaults graphics states - GraphicsViewPort defaultViewport; - defaultViewport.X = 0.f; - defaultViewport.Y = 0.f; - defaultViewport.Width = static_cast(frameBufferWidth); - defaultViewport.Height = static_cast(frameBufferHeight); - defaultViewport.MinDepth = 0.f; - defaultViewport.MaxDepth = 1.f; - SetViewPort(commandList, defaultViewport); - - Rectangle defaultScissor; - defaultScissor.X = 0; - defaultScissor.Y = 0; - defaultScissor.Width = static_cast(frameBufferWidth); - defaultScissor.Height = static_cast(frameBufferHeight); - SetScissorRect(commandList, defaultScissor); - - SetStencilReference(commandList, 0); - - FColor blendConstants; - blendConstants.R = 1.0f; - blendConstants.G = 1.0f; - blendConstants.B = 1.0f; - blendConstants.A = 1.0f; - SetBlendConstants(commandList, blendConstants); - } - - void EndRenderPass(NonNullPtr commandList) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - - // Reset Color Target state and optionally resolve color texture - for (uint32 idx = 0; idx < GPUDriver::kMaxColorTargetInfo; ++idx) - { - if (d3d12CommandList->ColorTargetSubresources[idx]) - { - if (d3d12CommandList->ColorResolveSubresources[idx]) - { - Internal::TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, - D3D12_RESOURCE_STATE_RESOLVE_SOURCE, - d3d12CommandList->ColorTargetSubresources[idx]); - d3d12CommandList->GraphicsCommandList.CommandList->ResolveSubresource( - d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource, - d3d12CommandList->ColorResolveSubresources[idx]->Index, - d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource, - d3d12CommandList->ColorTargetSubresources[idx]->Index, - Internal::ConvertToD3D12TextureFormat( - d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format)); - - Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, - d3d12CommandList->ColorTargetSubresources[idx], - D3D12_RESOURCE_STATE_RESOLVE_SOURCE); - - Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, - d3d12CommandList->ColorResolveSubresources[idx], - D3D12_RESOURCE_STATE_RESOLVE_DEST); - } - else - { - Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, - d3d12CommandList->ColorTargetSubresources[idx], - D3D12_RESOURCE_STATE_RENDER_TARGET); - } - } - } - - // Reset Depth Stencil state - if (d3d12CommandList->DepthStencilSubresource) - { - Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->DepthStencilSubresource, - D3D12_RESOURCE_STATE_DEPTH_WRITE); - d3d12CommandList->DepthStencilSubresource = nullptr; - } - d3d12CommandList->CurrentGraphicsPipeline = nullptr; - - d3d12CommandList->GraphicsCommandList.CommandList->OMSetRenderTargets(0, nullptr, false, nullptr); - - // Reset bind states - ZeroArray(d3d12CommandList->ColorTargetSubresources); - ZeroArray(d3d12CommandList->ColorResolveSubresources); - // TODO : reset depth stencil subresources - // d3d12CommandList->DepthStencilTextureSubresource = NULL; - - // TODO : vertex buffer - // TODO :Vertex sampler and fragment sampler - - // ZeroArray(d3d12CommandList->VertexBuffers); - // ZeroArray(d3d12CommandList->VertexBufferOffsets); - // d3d12CommandList->VertexBufferCount = 0; - // - // ZeroArray(d3d12CommandList->VertexSamplerTextures); - // ZeroArray(d3d12CommandList->VertexSamplers); - // ZeroArray(d3d12CommandList->VertexStorageTextures); - // ZeroArray(d3d12CommandList->VertexStorageBuffers); - // - // ZeroArray(d3d12CommandList->FragmentSamplerTextures); - // ZeroArray(d3d12CommandList->FragmentSamplers); - // ZeroArray(d3d12CommandList->FragmentStorageTextures); - // ZeroArray(d3d12CommandList->FragmentStorageBuffers); - } - - void BindGraphicsPipeline(NonNullPtr commandList, NonNullPtr graphicsPipeline) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - auto pipeline = reinterpret_cast(graphicsPipeline.Get()); - - d3d12CommandList->CurrentGraphicsPipeline = pipeline; - - // Set the Descriptor heap - if (d3d12CommandList->CRB_SRV_UAV_Heap == nullptr) - { - Internal::SetDescriptorHeaps(d3d12CommandList); - } - - // Set the pipeline state - d3d12CommandList->GraphicsCommandList.CommandList->SetPipelineState(pipeline->PipelineState); - d3d12CommandList->GraphicsCommandList.CommandList->SetGraphicsRootSignature(pipeline->RootSignature->Handle); - d3d12CommandList->GraphicsCommandList.CommandList->IASetPrimitiveTopology( - JulietToD3D12_PrimitiveType[ToUnderlying(pipeline->PrimitiveType)]); - - // Mark that bindings are needed - d3d12CommandList->NeedVertexSamplerBind = true; - d3d12CommandList->NeedVertexStorageTextureBind = true; - d3d12CommandList->NeedVertexStorageBufferBind = true; - d3d12CommandList->NeedFragmentSamplerBind = true; - d3d12CommandList->NeedFragmentStorageTextureBind = true; - d3d12CommandList->NeedFragmentStorageBufferBind = true; - - for (uint32 idx = 0; idx < GPUDriver::kMaxUniformBuffersPerStage; ++idx) - { - d3d12CommandList->NeedVertexUniformBufferBind[idx] = true; - d3d12CommandList->NeedFragmentUniformBufferBind[idx] = true; - } - - for (uint32 idx = 0; idx < pipeline->VertexUniformBufferCount; ++idx) - { - // if (d3d12CommandList->VertexUniformBuffers[i] == NULL) - // { - // d3d12CommandList->VertexUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); - // } - } - - for (uint32 idx = 0; idx < pipeline->FragmentUniformBufferCount; ++idx) - { - // if (d3d12CommandList->FragmentUniformBuffers[i] == NULL) - // { - // d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); - // } - } - - Internal::TrackGraphicsPipeline(d3d12CommandList, pipeline); - } - - void DrawPrimitives(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - // TODO : Last missing piece - // D3D12_INTERNAL_BindGraphicsResources(d3d12CommandBuffer); - - d3d12CommandList->GraphicsCommandList.CommandList->DrawInstanced(numVertices, numInstances, firstVertex, firstInstance); - } - - void DrawIndexedPrimitives(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, - uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance) - { - auto* d3d12CommandList = reinterpret_cast(commandList.Get()); - d3d12CommandList->GraphicsCommandList.CommandList->DrawIndexedInstanced(numIndices, numInstances, firstIndex, - static_cast(vertexOffset), firstInstance); - } -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12RenderPass.h b/Juliet/src/Graphics/D3D12/D3D12RenderPass.h deleted file mode 100644 index cf5f2f5..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12RenderPass.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Juliet::D3D12 -{ - extern void BeginRenderPass(NonNullPtr commandList, NonNullPtr colorTargetInfos, - uint32 colorTargetInfoCount, const DepthStencilTargetInfo* depthStencilTargetInfo); - extern void EndRenderPass(NonNullPtr commandList); - - extern void BindGraphicsPipeline(NonNullPtr commandList, NonNullPtr graphicsPipeline); - extern void DrawPrimitives(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, - uint32 firstVertex, uint32 firstInstance); - void DrawIndexedPrimitives(NonNullPtr commandList, uint32 numIndices, uint32 numInstances, - uint32 firstIndex, uint32 vertexOffset, uint32 firstInstance); -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp b/Juliet/src/Graphics/D3D12/D3D12Shader.cpp deleted file mode 100644 index d071e49..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Shader.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, - ShaderCreateInfo& /*shaderCreateInfo*/ JULIET_DEBUG_PARAM(String filename)) - { - if (!IsValid(shaderByteCode)) - { - LogError(LogCategory::Graphics, "Invalid shader byte code"); - return nullptr; - } - - size_t allocSize = sizeof(D3D12Shader) + shaderByteCode.Size; - auto* shader = static_cast( - ArenaPushSize(driver->DriverArena, allocSize, AlignOf(D3D12Shader), - true JULIET_DEBUG_PARAM("D3D12Shader [{}] | Size [{}]", CStr(filename), shaderByteCode.Size))); - if (!shader) - { - LogError(LogCategory::Graphics, "Cannot allocate a new D3D12Shader: Out of memory"); - return nullptr; - } - - // Uses the bytes after the struct to store the shader byte code. - shader->ByteCode.Data = reinterpret_cast(shader + 1); - shader->ByteCode.Size = shaderByteCode.Size; - MemCopy(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size); - - // Make sure the data is correctly copied - if (MemCompare(shader->ByteCode.Data, shaderByteCode.Data, shaderByteCode.Size) != 0) - { - LogError(LogCategory::Graphics, "Memory copy failed"); - Free(shader); - return nullptr; - } - - return reinterpret_cast(shader); - } - - void DestroyShader(NonNullPtr /*driver*/, NonNullPtr /*shader*/) - { - // For now we never destroy the shader, it stays in the arena. - // If we create too many and need to switch dynamically we will need a way to release the slot for other asset - } -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Shader.h b/Juliet/src/Graphics/D3D12/D3D12Shader.h deleted file mode 100644 index 63c097f..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Shader.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Juliet::D3D12 -{ - struct D3D12Shader - { - ByteBuffer ByteCode; - - uint32 NumSamplers; - uint32 NumUniformBuffers; - uint32 NumStorageBuffers; - uint32 NumStorageTextures; - }; - - extern Shader* CreateShader(NonNullPtr driver, ByteBuffer shaderByteCode, - ShaderCreateInfo& shaderCreateInfo JULIET_DEBUG_PARAM(String filename)); - extern void DestroyShader(NonNullPtr driver, NonNullPtr shader); -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp b/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp deleted file mode 100644 index 3ad09ab..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp +++ /dev/null @@ -1,372 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - DXGI_COLOR_SPACE_TYPE SwapchainCompositionToColorSpace[] = { - DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR - DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, // SDR_LINEAR - DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, // HDR_EXTENDED_LINEAR - DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 // HDR10_ST2084 - }; - - DXGI_FORMAT SwapchainCompositionToTextureFormat[] = { - DXGI_FORMAT_B8G8R8A8_UNORM, // SDR - DXGI_FORMAT_B8G8R8A8_UNORM, // SDR_LINEAR (NOTE: The RTV uses the sRGB format) - DXGI_FORMAT_R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR - DXGI_FORMAT_R10G10B10A2_UNORM, // HDR10_ST2084 - }; - - TextureFormat SwapchainCompositionToJulietTextureFormat[] = { - TextureFormat::B8G8R8A8_UNORM, // SDR - TextureFormat::B8G8R8A8_UNORM_SRGB, // SDR_LINEAR - TextureFormat::R16G16B16A16_FLOAT, // HDR_EXTENDED_LINEAR - TextureFormat::R10G10B10A2_UNORM, // HDR10_ST2084 - }; - - bool CreateSwapChainTexture(NonNullPtr driver, NonNullPtr swapChain, - SwapChainComposition composition, NonNullPtr textureContainer, uint8 index) - { - ID3D12Resource* swapChainTexture = nullptr; - HRESULT result = swapChain->GetBuffer(index, IID_ID3D12Resource, reinterpret_cast(&swapChainTexture)); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Cannot get buffer from SwapChain", result); - return false; - } - - auto texture = static_cast(Calloc(1, sizeof(D3D12Texture))); - if (!texture) - { - LogError(driver->D3D12Device, "Cannot allocate D3D12Texture (out of memory)", result); - swapChainTexture->Release(); - return false; - } - - texture->ReferenceCount += 1; - texture->SubresourceCount = 1; - texture->Subresources = static_cast(Calloc(1, sizeof(D3D12TextureSubresource))); - if (!texture->Subresources) - { - LogError(driver->D3D12Device, "Cannot allocate D3D12TextureSubresource (out of memory)", result); - Free(texture); - swapChainTexture->Release(); - return false; - } - texture->Subresources[0].RTVHandles = - static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); - texture->Subresources[0].UAVHandle.Heap = nullptr; - texture->Subresources[0].UAVHandle.Heap = nullptr; - texture->Subresources[0].Parent = texture; - texture->Subresources[0].Index = 0; - texture->Subresources[0].Layer = 0; - texture->Subresources[0].Depth = 1; - texture->Subresources[0].Level = 0; - - D3D12_RESOURCE_DESC textureDesc = swapChainTexture->GetDesc(); - textureContainer->Header.CreateInfo.Width = static_cast(textureDesc.Width); - textureContainer->Header.CreateInfo.Height = static_cast(textureDesc.Height); - textureContainer->Header.CreateInfo.LayerCount = 1; - textureContainer->Header.CreateInfo.MipLevelCount = 1; - textureContainer->Header.CreateInfo.Type = TextureType::Texture_2D; - textureContainer->Header.CreateInfo.Flags = TextureUsageFlag::ColorTarget; - textureContainer->Header.CreateInfo.SampleCount = TextureSampleCount::One; - textureContainer->Header.CreateInfo.Format = SwapchainCompositionToJulietTextureFormat[ToUnderlying(composition)]; - - textureContainer->Textures = static_cast(Calloc(1, sizeof(D3D12Texture*))); - if (!textureContainer->Textures) - { - Free(texture->Subresources); - Free(texture); - swapChainTexture->Release(); - return false; - } - - textureContainer->Capacity = 1; - textureContainer->Count = 1; - textureContainer->Textures[0] = texture; - textureContainer->ActiveTexture = texture; - textureContainer->CanBeCycled = false; - - texture->Container = textureContainer; - texture->IndexInContainer = 0; - - // Assign RTV to the swapchain texture - DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; - Internal::AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]); - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc; - rtvDesc.Format = (composition == SwapChainComposition::SDR_LINEAR) ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : swapchainFormat; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = 0; - rtvDesc.Texture2D.PlaneSlice = 0; - - driver->D3D12Device->CreateRenderTargetView(swapChainTexture, &rtvDesc, - texture->Subresources[0].RTVHandles[0].CpuHandle); - - swapChainTexture->Release(); - - return true; - } - - bool AcquireSwapChainTexture(bool block, NonNullPtr commandList, NonNullPtr window, Texture** swapchainTexture) - { - auto d3d12CommandList = reinterpret_cast(commandList.Get()); - - auto* driver = d3d12CommandList->Driver; - Assert(driver->WindowData); - - // TODO: Find a way to fetch window data more smoothly from the window ptr - // In the mean time i will just void it or the variable is unused and cause a warning - (void)window; - auto* windowData = driver->WindowData; - Assert(windowData->Window == window.Get()); - - if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) - { - if (block) - { - // Wait until the fence for the frame is signaled. - // In VSYNC this means waiting that the least recent presented frame is done - if (!Wait(driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], - 1 JULIET_DEBUG_PARAM(ConstString("AcquireSwapChainTexture")))) - { - return false; - } - } - else - { - // If work is not done, the least recent fence wont be signaled. - // In that case we return true to notify that there is no error, but rendering should be skipped as their will be no swapchainTexture - if (!QueryFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter])) - { - return true; - } - } - - ReleaseFence(driver, windowData->InFlightFences[windowData->WindowFrameCounter] JULIET_DEBUG_PARAM( - ConstString("AcquireSwapChainTexture"))); - windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr; - } - - uint32 swapchainIndex = windowData->SwapChain->GetCurrentBackBufferIndex(); - HRESULT result = windowData->SwapChain->GetBuffer( - swapchainIndex, IID_ID3D12Resource, - reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource)); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Could not acquire swapchain", result); - return false; - } - - // When the swap chain texture is acquired it's time to present - Assert(d3d12CommandList->PresentDataCount + 1 <= d3d12CommandList->PresentDataCapacity); - d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].WindowData = windowData; - d3d12CommandList->PresentDatas[d3d12CommandList->PresentDataCount].SwapChainImageIndex = swapchainIndex; - d3d12CommandList->PresentDataCount += 1; - - // Create the presentation barrier. - 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->SwapChainTextureContainers[swapchainIndex].ActiveTexture->Resource; - barrierDesc.Transition.Subresource = 0; - - d3d12CommandList->GraphicsCommandList.CommandList->ResourceBarrier(1, &barrierDesc); - - *swapchainTexture = reinterpret_cast(&windowData->SwapChainTextureContainers[swapchainIndex]); - - return true; - } - } // namespace - - bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) - { - return AcquireSwapChainTexture(false, commandList, window, swapChainTexture); - } - - bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) - { - return AcquireSwapChainTexture(true, commandList, window, swapChainTexture); - } - - bool WaitForSwapchain(NonNullPtr driver, NonNullPtr /*window*/) - { - auto* d3d12Driver = static_cast(driver.Get()); - auto* windowData = d3d12Driver->WindowData; - if (!windowData) - { - LogError(LogCategory::Graphics, "Cannot wait for swapchain. Window has no Swapchain"); - return false; - } - - if (windowData->InFlightFences[windowData->WindowFrameCounter] != nullptr) - { - if (!Wait(d3d12Driver, true, &windowData->InFlightFences[windowData->WindowFrameCounter], - 1 JULIET_DEBUG_PARAM(ConstString("WaitForSwapchain")))) - { - return false; - } - } - - return true; - } - - TextureFormat GetSwapChainTextureFormat(NonNullPtr driver, [[maybe_unused]] NonNullPtr window) - { - auto* d3d12Driver = static_cast(driver.Get()); - - auto* windowData = d3d12Driver->WindowData; - if (!windowData) - { - LogError(LogCategory::Graphics, "Cannot get swapchain format. Window has no Swapchain"); - return TextureFormat::Invalid; - } - - Assert(windowData->Window == window.Get()); - return windowData->SwapChainTextureContainers[windowData->WindowFrameCounter].Header.CreateInfo.Format; - } - - namespace Internal - { - bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, - SwapChainComposition composition, PresentMode presentMode) - { - auto windowWin32State = static_cast(windowData->Window->State); - HWND windowHandle = windowWin32State->Handle; - if (!IsWindow(windowHandle)) - { - Assert(false, "windowWin32State->Handle is not a window handle ???"); - return false; - } - - // TODO: I have no way to test HDR easily except the steamdeck - DXGI_FORMAT swapChainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; - - windowData->SwapChainTextureCount = std::clamp(driver->FramesInFlight, 2, 3); - - DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {}; - swapChainDesc.Width = 0; // Use the whole width - swapChainDesc.Height = 0; // Use the whole height - swapChainDesc.Format = swapChainFormat; - swapChainDesc.Stereo = 0; - swapChainDesc.SampleDesc.Count = 1; - swapChainDesc.SampleDesc.Quality = 0; - swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; - swapChainDesc.BufferCount = windowData->SwapChainTextureCount; - swapChainDesc.Scaling = DXGI_SCALING_STRETCH; - swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; - swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; - if (driver->IsTearingSupported) - { - swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - } - else - { - swapChainDesc.Flags = 0; - } - - DXGI_SWAP_CHAIN_FULLSCREEN_DESC swapChainFullscreenDesc = {}; - swapChainFullscreenDesc.RefreshRate.Numerator = 0; - swapChainFullscreenDesc.RefreshRate.Denominator = 0; - swapChainFullscreenDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; - swapChainFullscreenDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; - swapChainFullscreenDesc.Windowed = true; - - IDXGISwapChain1* swapChain = nullptr; - HRESULT result = driver->DXGIFactory->CreateSwapChainForHwnd(static_cast(driver->GraphicsQueue), - windowHandle, &swapChainDesc, - &swapChainFullscreenDesc, nullptr, &swapChain); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Failed to create SwapChain", result); - return false; - } - - IDXGISwapChain3* swapChain3 = nullptr; - result = swapChain->QueryInterface(IID_IDXGISwapChain3, reinterpret_cast(&swapChain3)); - swapChain->Release(); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Could not query IDXGISwapChain3 interface", result); - return false; - } - - if (composition != SwapChainComposition::SDR) - { - swapChain3->SetColorSpace1(SwapchainCompositionToColorSpace[ToUnderlying(composition)]); - } - - IDXGIFactory1* parentFactory = nullptr; - result = swapChain3->GetParent(IID_IDXGIFactory1, reinterpret_cast(&parentFactory)); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "Cannot get SwapChain Parent! Error Code: " HRESULT_FMT, result); - } - else - { - // Disable DXGI window crap - result = parentFactory->MakeWindowAssociation(windowHandle, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result); - } - parentFactory->Release(); - } - - swapChain3->GetDesc1(&swapChainDesc); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Failed to retrieve SwapChain descriptor", result); - return false; - } - windowData->SwapChain = swapChain3; - windowData->SwapChainColorSpace = SwapchainCompositionToColorSpace[ToUnderlying(composition)]; - windowData->SwapChainComposition = composition; - windowData->WindowFrameCounter = 0; - windowData->Width = swapChainDesc.Width; - windowData->Height = swapChainDesc.Height; - windowData->PresentMode = presentMode; - - for (uint8 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) - { - if (!CreateSwapChainTexture(driver, swapChain3, composition, &windowData->SwapChainTextureContainers[idx], idx)) - { - swapChain3->Release(); - return false; - } - } - - return true; - } - - void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData) - { - for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) - { - ReleaseStagingDescriptor(driver, - windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]); - - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles); - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources); - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture); - Free(windowData->SwapChainTextureContainers[idx].Textures); - } - - windowData->SwapChain->Release(); - windowData->SwapChain = nullptr; - } - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12SwapChain.h b/Juliet/src/Graphics/D3D12/D3D12SwapChain.h deleted file mode 100644 index 5c5da43..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12SwapChain.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include - -namespace Juliet::D3D12 -{ - // Forward Declare - struct D3D12Driver; - struct D3D12WindowData; - - extern bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); - extern bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); - extern bool WaitForSwapchain(NonNullPtr driver, NonNullPtr window); - extern TextureFormat GetSwapChainTextureFormat(NonNullPtr driver, NonNullPtr window); - - namespace Internal - { - extern bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, - SwapChainComposition composition, PresentMode presentMode); - extern void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData); - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp deleted file mode 100644 index 240f5ce..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp +++ /dev/null @@ -1,268 +0,0 @@ -#include -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - void ReleaseFenceToPool(NonNullPtr driver, NonNullPtr fence) - { - Assert(driver->AvailableFenceCount + 1 <= driver->AvailableFenceCapacity); - - driver->AvailableFences[driver->AvailableFenceCount] = fence; - driver->AvailableFenceCount += 1; - - LogDebug(LogCategory::Graphics, "ReleaseFenceToPool %x fence. Handle %x | Event %x | Refcount %d", - fence.Get(), fence->Handle, fence->Event, fence->ReferenceCount); - } - } // namespace - - bool WaitUntilGPUIsIdle(NonNullPtr driver) - { - auto d3d12driver = static_cast(driver.Get()); - D3D12Fence* fence = Internal::AcquireFence(d3d12driver JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); - if (!fence) - { - return false; - } - - if (d3d12driver->GraphicsQueue) - { - // Insert a signal into the end of the command queue... - d3d12driver->GraphicsQueue->Signal(fence->Handle, D3D12_FENCE_SIGNAL_VALUE); - - // ...and then block on it. - if (fence->Handle->GetCompletedValue() != D3D12_FENCE_SIGNAL_VALUE) - { - HRESULT result = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); - if (FAILED(result)) - { - LogError(d3d12driver->D3D12Device, "Setting fence event failed!", result); - return false; - } - - DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE); - if (waitResult == WAIT_FAILED) - { - LogError(d3d12driver->D3D12Device, "Wait failed!", result); - return false; - } - } - } - - ReleaseFence(driver, reinterpret_cast(fence) JULIET_DEBUG_PARAM(ConstString("WaitUntilGPUIsIdle"))); - - bool result = true; - - // Clean up - { - int32 idx = 0; - while (idx < d3d12driver->SubmittedCommandListCount) - { - result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); - // CleanCommandList swaps [idx] with last and decrements count. - // Don't increment — re-check the swapped-in element. - } - } - - Internal::DisposePendingResourcces(d3d12driver); - - return result; - } - - bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, uint32 numFences JULIET_DEBUG_PARAM(String querier)) - { - auto d3d12driver = static_cast(driver.Get()); - - TempArena tempArena = ArenaTempBegin(d3d12driver->DriverArena); - - HANDLE* events = - ArenaPushArray(tempArena.Arena, numFences JULIET_DEBUG_PARAM("Wait() HANDLE - JUST IN CASE")); - MemoryZero(events, sizeof(HANDLE) * numFences); - - for (uint32 i = 0; i < numFences; ++i) - { - D3D12Fence* fence = reinterpret_cast(fences[i]); - - HRESULT res = fence->Handle->SetEventOnCompletion(D3D12_FENCE_SIGNAL_VALUE, fence->Event); - if (FAILED(res)) - { - LogError(d3d12driver->D3D12Device, "Setting fence event failed!", res); - ArenaTempEnd(tempArena); - return false; - } - - events[i] = fence->Event; - } -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Waiting for %d fences. Querier %s", numFences, CStr(querier)); -#endif - for (uint32 i = 0; i < numFences; ++i) - { - D3D12Fence* d3d12fence = reinterpret_cast(fences[i]); - LogDebug(LogCategory::Graphics, "Waiting for %x fence. Handle %x | Event %x | Refcount %d", d3d12fence, - d3d12fence->Handle, d3d12fence->Event, d3d12fence->ReferenceCount); - } - - DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE); - - ArenaTempEnd(tempArena); - - if (waitResult == WAIT_FAILED) - { - LogError(LogCategory::Graphics, "Wait failed"); - return false; - } - - bool result = true; - - // Clean up - { - int32 idx = 0; - while (idx < d3d12driver->SubmittedCommandListCount) - { - uint64 fenceValue = d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle->GetCompletedValue(); - if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) - { - result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); - } - else - { - idx += 1; - } - } - } - - Internal::DisposePendingResourcces(d3d12driver); - - return result; - } - - bool QueryFence(NonNullPtr /*driver*/, NonNullPtr /*fence*/) - { - Unimplemented(); - return true; - } - - void ReleaseFence(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)) - { - auto d3d12driver = static_cast(driver.Get()); - auto d3d12Fence = reinterpret_cast(fence.Get()); - -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "ReleaseFence | %x fence. Handle %x | Event %x | Refcount %d | Querier %s", - d3d12Fence, d3d12Fence->Handle, d3d12Fence->Event, d3d12Fence->ReferenceCount, CStr(querier)); -#endif - if (--d3d12Fence->ReferenceCount == 0) - { - ReleaseFenceToPool(d3d12driver, d3d12Fence); - } - } - - namespace Internal - { - void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, - bool needsUavBarrier) - { - D3D12_RESOURCE_BARRIER barrierDesc[2]; - uint32 numBarriers = 0; - - // No transition barrier is needed if the state is not changing. - if (sourceState != destinationState) - { - barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrierDesc[numBarriers].Flags = static_cast(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 = static_cast(0); - barrierDesc[numBarriers].UAV.pResource = resource; - - numBarriers += 1; - } - - if (numBarriers > 0) - { - commandList->GraphicsCommandList.CommandList->ResourceBarrier(numBarriers, barrierDesc); - } - } - - D3D12Fence* AcquireFence(NonNullPtr driver JULIET_DEBUG_PARAM(String querier)) - { - D3D12Fence* fence; - ID3D12Fence* handle; - - // TODO :Thread safe (lock + atomic) - - if (driver->AvailableFenceCount == 0) - { - HRESULT result = driver->D3D12Device->CreateFence(D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, - IID_ID3D12Fence, reinterpret_cast(&handle)); - if (FAILED(result)) - { - LogError(driver->D3D12Device, "Failed to create fence!", result); - return nullptr; - } - - fence = ArenaPushStruct(driver->DriverArena JULIET_DEBUG_PARAM("D3D12Fence")); - if (!fence) - { - handle->Release(); - - return nullptr; - } - fence->Handle = handle; - fence->Event = CreateEvent(nullptr, false, false, nullptr); - fence->ReferenceCount = 0; -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0 NEW fence", CStr(querier)); -#endif - } - else - { - fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; - driver->AvailableFenceCount -= 1; - fence->Handle->Signal(D3D12_FENCE_UNSIGNALED_VALUE); -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Acquire Querier %s | Setting Signal to 0, RECYCLING", CStr(querier)); -#endif - } - - fence->ReferenceCount += 1; - Assert(fence->ReferenceCount == 1); - -#if JULIET_DEBUG - LogDebug(LogCategory::Graphics, "Acquire Querier %s | %x fence. Handle %x | Event %x | Refcount %d", - CStr(querier), fence, fence->Handle, fence->Event, fence->ReferenceCount); -#endif - - return fence; - } - - void DestroyFence(NonNullPtr fence) - { - if (fence->Handle) - { - fence->Handle->Release(); - } - - if (fence->Event) - { - CloseHandle(fence->Event); - } - } - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h deleted file mode 100644 index 746966e..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Juliet -{ - struct Fence; - struct GPUDriver; -} // namespace Juliet - -namespace Juliet::D3D12 -{ -#define D3D12_FENCE_UNSIGNALED_VALUE 0 -#define D3D12_FENCE_SIGNAL_VALUE 1 - - // Forward Declare - struct D3D12CommandList; - - struct D3D12Fence - { - ID3D12Fence* Handle; - HANDLE Event; // used for blocking - int32 ReferenceCount; // TODO : Atomic - }; - - extern bool WaitUntilGPUIsIdle(NonNullPtr driver); - extern bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, - uint32 numFences JULIET_DEBUG_PARAM(String querier)); - extern bool QueryFence(NonNullPtr driver, NonNullPtr fence); - extern void ReleaseFence(NonNullPtr driver, NonNullPtr fence JULIET_DEBUG_PARAM(String querier)); - - namespace Internal - { - extern void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, - uint32 subresourceIndex, bool needsUavBarrier); - - extern D3D12Fence* AcquireFence(NonNullPtr driver JULIET_DEBUG_PARAM(String querier)); - extern void DestroyFence(NonNullPtr fence); - } // namespace Internal -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp deleted file mode 100644 index 3dcc19e..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp +++ /dev/null @@ -1,579 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - namespace - { - DXGI_FORMAT JulietToD3D12_TextureFormat[] = { - DXGI_FORMAT_UNKNOWN, // INVALID - DXGI_FORMAT_A8_UNORM, // A8_UNORM - DXGI_FORMAT_R8_UNORM, // R8_UNORM - DXGI_FORMAT_R8G8_UNORM, // R8G8_UNORM - DXGI_FORMAT_R8G8B8A8_UNORM, // R8G8B8A8_UNORM - DXGI_FORMAT_R16_UNORM, // R16_UNORM - DXGI_FORMAT_R16G16_UNORM, // R16G16_UNORM - DXGI_FORMAT_R16G16B16A16_UNORM, // R16G16B16A16_UNORM - DXGI_FORMAT_R10G10B10A2_UNORM, // R10G10B10A2_UNORM - DXGI_FORMAT_B5G6R5_UNORM, // B5G6R5_UNORM - DXGI_FORMAT_B5G5R5A1_UNORM, // B5G5R5A1_UNORM - DXGI_FORMAT_B4G4R4A4_UNORM, // B4G4R4A4_UNORM - DXGI_FORMAT_B8G8R8A8_UNORM, // B8G8R8A8_UNORM - DXGI_FORMAT_BC1_UNORM, // BC1_UNORM - DXGI_FORMAT_BC2_UNORM, // BC2_UNORM - DXGI_FORMAT_BC3_UNORM, // BC3_UNORM - DXGI_FORMAT_BC4_UNORM, // BC4_UNORM - DXGI_FORMAT_BC5_UNORM, // BC5_UNORM - DXGI_FORMAT_BC7_UNORM, // BC7_UNORM - DXGI_FORMAT_BC6H_SF16, // BC6H_FLOAT - DXGI_FORMAT_BC6H_UF16, // BC6H_UFLOAT - DXGI_FORMAT_R8_SNORM, // R8_SNORM - DXGI_FORMAT_R8G8_SNORM, // R8G8_SNORM - DXGI_FORMAT_R8G8B8A8_SNORM, // R8G8B8A8_SNORM - DXGI_FORMAT_R16_SNORM, // R16_SNORM - DXGI_FORMAT_R16G16_SNORM, // R16G16_SNORM - DXGI_FORMAT_R16G16B16A16_SNORM, // R16G16B16A16_SNORM - DXGI_FORMAT_R16_FLOAT, // R16_FLOAT - DXGI_FORMAT_R16G16_FLOAT, // R16G16_FLOAT - DXGI_FORMAT_R16G16B16A16_FLOAT, // R16G16B16A16_FLOAT - DXGI_FORMAT_R32_FLOAT, // R32_FLOAT - DXGI_FORMAT_R32G32_FLOAT, // R32G32_FLOAT - DXGI_FORMAT_R32G32B32A32_FLOAT, // R32G32B32A32_FLOAT - DXGI_FORMAT_R11G11B10_FLOAT, // R11G11B10_UFLOAT - DXGI_FORMAT_R8_UINT, // R8_UINT - DXGI_FORMAT_R8G8_UINT, // R8G8_UINT - DXGI_FORMAT_R8G8B8A8_UINT, // R8G8B8A8_UINT - DXGI_FORMAT_R16_UINT, // R16_UINT - DXGI_FORMAT_R16G16_UINT, // R16G16_UINT - DXGI_FORMAT_R16G16B16A16_UINT, // R16G16B16A16_UINT - DXGI_FORMAT_R32_UINT, // R32_UINT - DXGI_FORMAT_R32G32_UINT, // R32G32_UINT - DXGI_FORMAT_R32G32B32A32_UINT, // R32G32B32A32_UINT - DXGI_FORMAT_R8_SINT, // R8_INT - DXGI_FORMAT_R8G8_SINT, // R8G8_INT - DXGI_FORMAT_R8G8B8A8_SINT, // R8G8B8A8_INT - DXGI_FORMAT_R16_SINT, // R16_INT - DXGI_FORMAT_R16G16_SINT, // R16G16_INT - DXGI_FORMAT_R16G16B16A16_SINT, // R16G16B16A16_INT - DXGI_FORMAT_R32_SINT, // R32_INT - DXGI_FORMAT_R32G32_SINT, // R32G32_INT - DXGI_FORMAT_R32G32B32A32_SINT, // R32G32B32A32_INT - DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, // R8G8B8A8_UNORM_SRGB - DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, // B8G8R8A8_UNORM_SRGB - DXGI_FORMAT_BC1_UNORM_SRGB, // BC1_UNORM_SRGB - DXGI_FORMAT_BC2_UNORM_SRGB, // BC2_UNORM_SRGB - DXGI_FORMAT_BC3_UNORM_SRGB, // BC3_UNORM_SRGB - DXGI_FORMAT_BC7_UNORM_SRGB, // BC7_UNORM_SRGB - DXGI_FORMAT_R16_TYPELESS, // D16_UNORM - DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM - DXGI_FORMAT_R32_TYPELESS, // D32_FLOAT - DXGI_FORMAT_R24G8_TYPELESS, // D24_UNORM_S8_UINT - DXGI_FORMAT_R32G8X24_TYPELESS, // D32_FLOAT_S8_UINT - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT - }; - static_assert(sizeof(JulietToD3D12_TextureFormat) / sizeof(JulietToD3D12_TextureFormat[0]) == - ToUnderlying(TextureFormat::Count)); - - DXGI_FORMAT JulietToD3D12_DepthFormat[] = { - DXGI_FORMAT_UNKNOWN, // INVALID - DXGI_FORMAT_UNKNOWN, // A8_UNORM - DXGI_FORMAT_UNKNOWN, // R8_UNORM - DXGI_FORMAT_UNKNOWN, // R8G8_UNORM - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM - DXGI_FORMAT_UNKNOWN, // R16_UNORM - DXGI_FORMAT_UNKNOWN, // R16G16_UNORM - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UNORM - DXGI_FORMAT_UNKNOWN, // R10G10B10A2_UNORM - DXGI_FORMAT_UNKNOWN, // B5G6R5_UNORM - DXGI_FORMAT_UNKNOWN, // B5G5R5A1_UNORM - DXGI_FORMAT_UNKNOWN, // B4G4R4A4_UNORM - DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM - DXGI_FORMAT_UNKNOWN, // BC1_UNORM - DXGI_FORMAT_UNKNOWN, // BC2_UNORM - DXGI_FORMAT_UNKNOWN, // BC3_UNORM - DXGI_FORMAT_UNKNOWN, // BC4_UNORM - DXGI_FORMAT_UNKNOWN, // BC5_UNORM - DXGI_FORMAT_UNKNOWN, // BC7_UNORM - DXGI_FORMAT_UNKNOWN, // BC6H_FLOAT - DXGI_FORMAT_UNKNOWN, // BC6H_UFLOAT - DXGI_FORMAT_UNKNOWN, // R8_SNORM - DXGI_FORMAT_UNKNOWN, // R8G8_SNORM - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_SNORM - DXGI_FORMAT_UNKNOWN, // R16_SNORM - DXGI_FORMAT_UNKNOWN, // R16G16_SNORM - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_SNORM - DXGI_FORMAT_UNKNOWN, // R16_FLOAT - DXGI_FORMAT_UNKNOWN, // R16G16_FLOAT - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_FLOAT - DXGI_FORMAT_UNKNOWN, // R32_FLOAT - DXGI_FORMAT_UNKNOWN, // R32G32_FLOAT - DXGI_FORMAT_UNKNOWN, // R32G32B32A32_FLOAT - DXGI_FORMAT_UNKNOWN, // R11G11B10_UFLOAT - DXGI_FORMAT_UNKNOWN, // R8_UINT - DXGI_FORMAT_UNKNOWN, // R8G8_UINT - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UINT - DXGI_FORMAT_UNKNOWN, // R16_UINT - DXGI_FORMAT_UNKNOWN, // R16G16_UINT - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_UINT - DXGI_FORMAT_UNKNOWN, // R32_UINT - DXGI_FORMAT_UNKNOWN, // R32G32_UINT - DXGI_FORMAT_UNKNOWN, // R32G32B32A32_UINT - DXGI_FORMAT_UNKNOWN, // R8_INT - DXGI_FORMAT_UNKNOWN, // R8G8_INT - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_INT - DXGI_FORMAT_UNKNOWN, // R16_INT - DXGI_FORMAT_UNKNOWN, // R16G16_INT - DXGI_FORMAT_UNKNOWN, // R16G16B16A16_INT - DXGI_FORMAT_UNKNOWN, // R32_INT - DXGI_FORMAT_UNKNOWN, // R32G32_INT - DXGI_FORMAT_UNKNOWN, // R32G32B32A32_INT - DXGI_FORMAT_UNKNOWN, // R8G8B8A8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // B8G8R8A8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC1_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC2_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC3_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // BC7_UNORM_SRGB - DXGI_FORMAT_D16_UNORM, // D16_UNORM - DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM - DXGI_FORMAT_D32_FLOAT, // D32_FLOAT - DXGI_FORMAT_D24_UNORM_S8_UINT, // D24_UNORM_S8_UINT - DXGI_FORMAT_D32_FLOAT_S8X24_UINT, // D32_FLOAT_S8_UINT - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_UNORM_SRGB - DXGI_FORMAT_UNKNOWN, // ASTC_4x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x4_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_5x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_6x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_8x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x5_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x6_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x8_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_10x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x10_FLOAT - DXGI_FORMAT_UNKNOWN, // ASTC_12x12_FLOAT - }; - static_assert(sizeof(JulietToD3D12_DepthFormat) / sizeof(JulietToD3D12_DepthFormat[0]) == ToUnderlying(TextureFormat::Count)); - - uint32 ComputeSubresourceIndex(uint32 mipLevel, uint32 layer, uint32 numLevels) - { - return mipLevel + (layer * numLevels); - } - - D3D12_RESOURCE_STATES GetDefaultTextureResourceState(TextureUsageFlag usageFlags) - { - if ((usageFlags & TextureUsageFlag::Sampler) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - if ((usageFlags & TextureUsageFlag::GraphicsStorageRead) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - if ((usageFlags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_RENDER_TARGET; - } - if ((usageFlags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_DEPTH_WRITE; - } - if ((usageFlags & TextureUsageFlag::ComputeStorageRead) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE; - } - if ((usageFlags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - if ((usageFlags & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None) - { - return D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - } - Log(LogLevel::Error, LogCategory::Graphics, "Texture has no default usage mode!"); - return D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE; - } - } // namespace - - namespace Internal - { - D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr commandList, - NonNullPtr container, - uint32 layer, uint32 level, bool shouldCycle, - D3D12_RESOURCE_STATES newTextureUsage) - { - D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level); - if (shouldCycle and container->CanBeCycled and subresource->Parent->ReferenceCount > 0) - { - // TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective) - // CycleActiveTexture(commandList->Driver, container); - - subresource = Internal::FetchTextureSubresource(container, layer, level); - } - - Internal::TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage); - - return subresource; - } - - D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, uint32 layer, uint32 level) - { - uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount); - return &container->ActiveTexture->Subresources[index]; - } - - void TextureSubresourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, NonNullPtr textureSubresource) - { - TextureUsageFlag currentFlag = textureSubresource->Parent->Container->Header.CreateInfo.Flags; - bool needsUAVBarrier = - ((currentFlag & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) || - ((currentFlag & TextureUsageFlag::ComputeStorageSimultaneousReadWrite) != TextureUsageFlag::None); - Internal::ResourceBarrier(commandList, sourceState, destinationState, textureSubresource->Parent->Resource, - textureSubresource->Index, needsUAVBarrier); - } - - void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr commandList, - NonNullPtr subresource, - D3D12_RESOURCE_STATES toTextureUsage) - { - D3D12_RESOURCE_STATES defaultUsage = - GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); - TextureSubresourceBarrier(commandList, defaultUsage, toTextureUsage, subresource); - } - - void TextureTransitionFromDefaultUsage(NonNullPtr commandList, - NonNullPtr texture, D3D12_RESOURCE_STATES toTextureUsage) - { - for (uint32 i = 0; i < texture->SubresourceCount; ++i) - { - TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage); - } - } - - void TextureSubresourceTransitionToDefaultUsage(NonNullPtr commandList, - NonNullPtr subresource, - D3D12_RESOURCE_STATES fromTextureUsage) - { - D3D12_RESOURCE_STATES defaultUsage = - GetDefaultTextureResourceState(subresource->Parent->Container->Header.CreateInfo.Flags); - TextureSubresourceBarrier(commandList, fromTextureUsage, defaultUsage, subresource); - } - - void TextureTransitionToDefaultUsage(NonNullPtr commandList, NonNullPtr texture, - D3D12_RESOURCE_STATES fromTextureUsage) - { - for (uint32 i = 0; i < texture->SubresourceCount; ++i) - { - TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage); - } - } - - // Utils - DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format) - { - return JulietToD3D12_TextureFormat[ToUnderlying(format)]; - } - - DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format) - { - return JulietToD3D12_DepthFormat[ToUnderlying(format)]; - } - - uint32 JulietToD3D12_SampleCount[] = { - 1, // MSAA 1x - 2, // MSAA 2x - 4, // MSAA 4x - 8, // MSAA 8x - }; - } // namespace Internal - - Texture* CreateTexture(NonNullPtr driver, const TextureCreateInfo& createInfo) - { - auto* d3d12Driver = static_cast(driver.Get()); - - D3D12_RESOURCE_DESC desc = {}; - switch (createInfo.Type) - { - case TextureType::Texture_2D: - case TextureType::Texture_2DArray: - case TextureType::Texture_Cube: - case TextureType::Texture_CubeArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; break; - case TextureType::Texture_3D: - case TextureType::Texture_3DArray: desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE3D; break; - } - - desc.Alignment = 0; - desc.Width = createInfo.Width; - desc.Height = createInfo.Height; - desc.DepthOrArraySize = static_cast(createInfo.LayerCount); - desc.MipLevels = static_cast(createInfo.MipLevelCount); - desc.Format = Internal::ConvertToD3D12TextureFormat(createInfo.Format); - desc.SampleDesc.Count = Internal::JulietToD3D12_SampleCount[ToUnderlying(createInfo.SampleCount)]; - desc.SampleDesc.Quality = 0; - desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; - desc.Flags = D3D12_RESOURCE_FLAG_NONE; - - if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) - { - desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - } - if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) - { - desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; - } - if ((createInfo.Flags & TextureUsageFlag::ComputeStorageWrite) != TextureUsageFlag::None) - { - desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; - } - - D3D12_HEAP_PROPERTIES heapProps = {}; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 0; // We don't do multi-adapter operation - heapProps.VisibleNodeMask = 0; // We don't do multi-adapter operation - - ID3D12Resource* resource = nullptr; - D3D12_CLEAR_VALUE clearValue = {}; - D3D12_CLEAR_VALUE* pClearValue = nullptr; - - if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) - { - clearValue.Format = Internal::ConvertToD3D12DepthFormat(createInfo.Format); - clearValue.DepthStencil.Depth = 1.0f; - clearValue.DepthStencil.Stencil = 0; - pClearValue = &clearValue; - } - else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) - { - clearValue.Format = desc.Format; - clearValue.Color[0] = 0.0f; - clearValue.Color[1] = 0.0f; - clearValue.Color[2] = 0.0f; - clearValue.Color[3] = 0.0f; - pClearValue = &clearValue; - } - - D3D12_RESOURCE_STATES initialState = GetDefaultTextureResourceState(createInfo.Flags); - HRESULT hr = d3d12Driver->D3D12Device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, - initialState, pClearValue, IID_ID3D12Resource, - reinterpret_cast(&resource)); - - if (FAILED(hr)) - { - LogError(d3d12Driver->D3D12Device, "Failed to create D3D12 committed resource for texture", hr); - return nullptr; - } - - auto* textureContainer = static_cast(Calloc(1, sizeof(D3D12TextureContainer))); - auto* texture = static_cast(Calloc(1, sizeof(D3D12Texture))); - - textureContainer->Header.CreateInfo = createInfo; - textureContainer->ActiveTexture = texture; - textureContainer->Textures = static_cast(Malloc(sizeof(D3D12Texture*))); - textureContainer->Textures[0] = texture; - textureContainer->Capacity = 1; - textureContainer->Count = 1; - textureContainer->CanBeCycled = true; - - texture->Container = textureContainer; - texture->Resource = resource; - texture->ReferenceCount = 1; - - uint32 numLayers = std::max(1, createInfo.LayerCount); - uint32 numMips = std::max(1, createInfo.MipLevelCount); - texture->SubresourceCount = numLayers * numMips; - texture->Subresources = - static_cast(Calloc(texture->SubresourceCount, sizeof(D3D12TextureSubresource))); - - for (uint32 layer = 0; layer < numLayers; ++layer) - { - for (uint32 mip = 0; mip < numMips; ++mip) - { - uint32 index = mip + (layer * numMips); - auto& sub = texture->Subresources[index]; - sub.Parent = texture; - sub.Layer = layer; - sub.Level = mip; - sub.Index = index; - sub.Depth = 1; // 3D texture depth handling would go here - - if ((createInfo.Flags & TextureUsageFlag::ColorTarget) != TextureUsageFlag::None) - { - sub.RTVHandles = static_cast(Calloc(1, sizeof(D3D12StagingDescriptor))); - Internal::AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, sub.RTVHandles[0]); - - D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {}; - rtvDesc.Format = desc.Format; - rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; - rtvDesc.Texture2D.MipSlice = mip; - d3d12Driver->D3D12Device->CreateRenderTargetView(resource, &rtvDesc, sub.RTVHandles[0].CpuHandle); - } - - if ((createInfo.Flags & TextureUsageFlag::DepthStencilTarget) != TextureUsageFlag::None) - { - Internal::AssignStagingDescriptor(d3d12Driver, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, sub.DSVHandle); - - D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {}; - dsvDesc.Format = Internal::ConvertToD3D12DepthFormat(createInfo.Format); - dsvDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; - dsvDesc.Texture2D.MipSlice = mip; - d3d12Driver->D3D12Device->CreateDepthStencilView(resource, &dsvDesc, sub.DSVHandle.CpuHandle); - } - } - } - - // Create SRV for sampled/readable textures (bindless access) - // Assign to the bindless CBV_SRV_UAV heap - { - Internal::D3D12Descriptor descriptor; - if (Internal::AssignDescriptor(d3d12Driver->BindlessDescriptorHeap, descriptor)) - { - texture->SRVHandle = D3D12StagingDescriptor{}; - texture->SRVHandle.CpuHandleIndex = descriptor.Index; - texture->SRVHandle.CpuHandle = descriptor.CpuHandle; - texture->SRVHandle.Heap = descriptor.Heap; - - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.Format = desc.Format; - - // Fix SRV format for Depth Buffers (TypeLess -> Typed) - if (createInfo.Format == TextureFormat::D32_FLOAT) - { - srvDesc.Format = DXGI_FORMAT_R32_FLOAT; - } - else if (createInfo.Format == TextureFormat::D16_UNORM) - { - srvDesc.Format = DXGI_FORMAT_R16_UNORM; - } - else if (createInfo.Format == TextureFormat::D24_UNORM_S8_UINT) - { - srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; - } - else if (createInfo.Format == TextureFormat::D32_FLOAT_S8_UINT) - { - srvDesc.Format = DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; - } - - srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; - srvDesc.Texture2D.MostDetailedMip = 0; - srvDesc.Texture2D.MipLevels = numMips; - srvDesc.Texture2D.PlaneSlice = 0; - srvDesc.Texture2D.ResourceMinLODClamp = 0.0f; - - d3d12Driver->D3D12Device->CreateShaderResourceView(resource, &srvDesc, descriptor.CpuHandle); - } - } - - return reinterpret_cast(textureContainer); - } - - void DestroyTexture(NonNullPtr driver, NonNullPtr texture) - { - auto* d3d12Driver = static_cast(driver.Get()); - auto* textureContainer = reinterpret_cast(texture.Get()); - - for (uint32 i = 0; i < textureContainer->Count; ++i) - { - D3D12Texture* d3d12Texture = textureContainer->Textures[i]; - for (uint32 j = 0; j < d3d12Texture->SubresourceCount; ++j) - { - D3D12TextureSubresource& sub = d3d12Texture->Subresources[j]; - if (sub.RTVHandles) - { - Internal::ReleaseStagingDescriptor(d3d12Driver, sub.RTVHandles[0]); - Free(sub.RTVHandles); - } - if (sub.DSVHandle.Heap) - { - Internal::ReleaseStagingDescriptor(d3d12Driver, sub.DSVHandle); - } - } - d3d12Texture->Resource->Release(); - Free(d3d12Texture->Subresources); - Free(d3d12Texture); - } - - Free(textureContainer->Textures); - Free(textureContainer); - } -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.h b/Juliet/src/Graphics/D3D12/D3D12Texture.h deleted file mode 100644 index 5c12ded..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Texture.h +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include -#include -#include - -struct ID3D12Resource; - -namespace Juliet::D3D12 -{ - // Forward Declare - struct D3D12Texture; - struct D3D12ResourceHeap; - struct D3D12CommandList; - - struct D3D12TextureContainer - { - TextureHeader Header; - - D3D12Texture* ActiveTexture; - D3D12Texture** Textures; - uint32 Capacity; - uint32 Count; - - // Note: Swapchain images cannot be cycled - bool CanBeCycled; - -#if JULIET_DEBUG - char* DebugName; -#endif - }; - - // D3D12 subresourcces: https://learn.microsoft.com/en-us/windows/win32/direct3d12/subresources (mipmaps, etc..) - struct D3D12TextureSubresource - { - D3D12Texture* Parent; - uint32 Layer; - uint32 Level; - uint32 Depth; - uint32 Index; - - // One per depth slice - D3D12StagingDescriptor* RTVHandles; // NULL if not a color target - - D3D12StagingDescriptor UAVHandle; // NULL if not a compute storage write texture - D3D12StagingDescriptor DSVHandle; // NULL if not a depth stencil target - }; - - struct D3D12Texture - { - D3D12TextureContainer* Container; - uint32 IndexInContainer; - - ID3D12Resource* Resource; - - D3D12TextureSubresource* Subresources; - uint32 SubresourceCount; // Layer Count * number of Levels - - D3D12StagingDescriptor SRVHandle; - - // TODO: Should be atomic to support multithreading - int32 ReferenceCount; - }; - - namespace Internal - { - extern D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr, - NonNullPtr container, - uint32 layer, uint32 level, bool shouldCycle, - D3D12_RESOURCE_STATES newTextureUsage); - extern D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, - uint32 layer, uint32 level); - extern void TextureSubresourceBarrier(NonNullPtr commandList, - D3D12_RESOURCE_STATES sourceState, D3D12_RESOURCE_STATES destinationState, - NonNullPtr textureSubresource); - - // Texture usage transition - extern void TextureSubresourceTransitionFromDefaultUsage(NonNullPtr commandList, - NonNullPtr subresource, - D3D12_RESOURCE_STATES toTextureUsage); - extern void TextureTransitionFromDefaultUsage(NonNullPtr commandList, - NonNullPtr texture, D3D12_RESOURCE_STATES toTextureUsage); - extern void TextureSubresourceTransitionToDefaultUsage(NonNullPtr commandList, - NonNullPtr subresource, - D3D12_RESOURCE_STATES fromTextureUsage); - extern void TextureTransitionToDefaultUsage(NonNullPtr commandList, NonNullPtr texture, - D3D12_RESOURCE_STATES fromTextureUsage); - - // Utils - extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format); - extern DXGI_FORMAT ConvertToD3D12DepthFormat(TextureFormat format); - extern uint32 JulietToD3D12_SampleCount[]; - } // namespace Internal - - extern Texture* CreateTexture(NonNullPtr driver, const TextureCreateInfo& createInfo); - extern void DestroyTexture(NonNullPtr driver, NonNullPtr texture); -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Utils.cpp b/Juliet/src/Graphics/D3D12/D3D12Utils.cpp deleted file mode 100644 index c9f2cf5..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Utils.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include - -namespace Juliet::D3D12 -{ - // From SDLGPU - // TODO Do my own version. - extern void LogError(NonNullPtr D3D12Device, const char* errorMessage, HRESULT result) - { -#define MAX_ERROR_LEN 1024 // FIXME: Arbitrary! - - // Buffer for text, ensure space for \0 terminator after buffer - char wszMsgBuff[MAX_ERROR_LEN + 1]; - // Number of chars returned. - - if (result == DXGI_ERROR_DEVICE_REMOVED) - { - result = D3D12Device->GetDeviceRemovedReason(); - } - - // Try to get the message from the system errors. - DWORD dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, - static_cast(result), 0, wszMsgBuff, MAX_ERROR_LEN, nullptr); - - // No message? Screw it, just post the code. - if (dwChars == 0) - { - Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: " HRESULT_FMT, errorMessage, result); - return; - } - - // Ensure valid range - dwChars = Min(dwChars, MAX_ERROR_LEN); - - // Trim whitespace from tail of message - while (dwChars > 0) - { - if (wszMsgBuff[dwChars - 1] <= ' ') - { - dwChars--; - } - else - { - break; - } - } - - // Ensure null-terminated string - wszMsgBuff[dwChars] = '\0'; - - Log(LogLevel::Error, LogCategory::Graphics, "%s! Error: %s" HRESULT_FMT, errorMessage, wszMsgBuff, result); - } - -#if JULIET_DEBUG - String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type) - { - switch (type) - { - case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV"); - case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER"); - case D3D12_DESCRIPTOR_HEAP_TYPE_RTV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_RTV"); - case D3D12_DESCRIPTOR_HEAP_TYPE_DSV: return WrapString("D3D12_DESCRIPTOR_HEAP_TYPE_DSV"); - case D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES: return WrapString("Invalid"); - } - return WrapString("Invalid"); - } -#endif -} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Utils.h b/Juliet/src/Graphics/D3D12/D3D12Utils.h deleted file mode 100644 index ec33703..0000000 --- a/Juliet/src/Graphics/D3D12/D3D12Utils.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -#ifdef _WIN32 -#define HRESULT_FMT "(0x%08lX)" -#else -#define HRESULT_FMT "(0x%08X)" -#endif - -#define TOD3D12FuncPtr(type, ptr) reinterpret_cast(reinterpret_cast(ptr)) - -namespace Juliet::D3D12 -{ - struct D3D12Driver; - - extern void LogError(NonNullPtr D3D12Device, const char* errorMessage, HRESULT result); - -#if JULIET_DEBUG - String GetDescriptorTypeNane(D3D12_DESCRIPTOR_HEAP_TYPE type); -#endif -} // namespace Juliet::D3D12