From cc9bbf0ef580a4284aec6b778bb066b361390af8 Mon Sep 17 00:00:00 2001 From: Patedam Date: Tue, 18 Feb 2025 22:26:50 -0500 Subject: [PATCH] Fences first pass --- .../Graphics/D3D12/D3D12Synchronization.cpp | 57 +++++++++++++++++++ .../src/Graphics/D3D12/D3D12Synchronization.h | 19 ++++++- Juliet/src/Graphics/D3D12/DX12CommandList.cpp | 56 +++++++++++++++--- Juliet/src/Graphics/D3D12/DX12CommandList.h | 6 +- .../src/Graphics/D3D12/DX12GraphicsDevice.cpp | 37 ++++++++++++ .../src/Graphics/D3D12/DX12GraphicsDevice.h | 5 ++ 6 files changed, 167 insertions(+), 13 deletions(-) diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp index b8778a5..1b7bef2 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp @@ -1,7 +1,10 @@ #include +#include #include #include +#include +#include namespace Juliet::D3D12 { @@ -38,4 +41,58 @@ namespace Juliet::D3D12 ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc); } } + + D3D12Fence* AcquireFence(NonNullPtr driver) + { + D3D12Fence* fence; + ID3D12Fence* handle; + + // TODO :Thread safe (lock + atomic) + + if (driver->AvailableFenceCount == 0) + { + HRESULT result = ID3D12Device_CreateFence(driver->D3D12Device, D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, + IID_ID3D12Fence, reinterpret_cast(&handle)); + if (FAILED(result)) + { + LogError(driver, "Failed to create fence!", result); + return nullptr; + } + + fence = static_cast(Calloc(1, sizeof(D3D12Fence))); + if (!fence) + { + ID3D12Fence_Release(handle); + + return nullptr; + } + fence->Handle = handle; + fence->Event = CreateEvent(nullptr, false, false, nullptr); + fence->ReferenceCount = 0; + } + else + { + fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; + driver->AvailableFenceCount -= 1; + ID3D12Fence_Signal(fence->Handle, D3D12_FENCE_UNSIGNALED_VALUE); + } + + fence->ReferenceCount += 1; + return fence; + } + + void DestroyFence(NonNullPtr fence) + { + if (fence->Handle) + { + ID3D12Fence_Release(fence->Handle); + } + + if (fence->Event) + { + CloseHandle(fence->Event); + } + Free(fence.Get()); + } + } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h index c10b56d..0d48620 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h +++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h @@ -5,10 +5,23 @@ namespace Juliet::D3D12 { +#define D3D12_FENCE_UNSIGNALED_VALUE 0 +#define D3D12_FENCE_SIGNAL_VALUE 1 + // Forward Declare struct D3D12CommandList; - extern void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, D3D12_RESOURCE_STATES destinationState, - ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier); -} + struct D3D12Fence + { + ID3D12Fence* Handle; + HANDLE Event; // used for blocking + int32 ReferenceCount; // TODO : Atomic + }; + extern void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, + uint32 subresourceIndex, bool needsUavBarrier); + + extern D3D12Fence* AcquireFence(NonNullPtr driver); + extern void DestroyFence(NonNullPtr fence); +} // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp index ce59400..c7d03e2 100644 --- a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp +++ b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -110,6 +111,7 @@ namespace Juliet::D3D12 if (!commandList) { Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); + DestroyCommandList(commandList); return false; } @@ -118,8 +120,9 @@ namespace Juliet::D3D12 if (!resizedArray) { - Assert(false && - "Error not implemented, out of memory, handle that by deallocating stuff and returning false"); + Log(LogLevel::Error, LogCategory::Graphics, + "Error not implemented, out of memory, handle that by deallocating stuff and returning false"); + DestroyCommandList(commandList); return false; } @@ -158,7 +161,8 @@ namespace Juliet::D3D12 { if (!CreateD3D12CommandList(d3d12Driver, commandList, queueType)) { - // TODO Shoud destroy the command list here + Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list"); + DestroyCommandList(commandList); return nullptr; } } @@ -243,10 +247,24 @@ namespace Juliet::D3D12 ID3D12CommandList_Release(commandLists[0]); - // TODO Fences + // Acquire a fence and set it to the in-flight fence + d3d12CommandList->InFlightFence = AcquireFence(d3d12Driver); + if (!d3d12CommandList->InFlightFence) + { + return false; + } + + // Mark that a fence should be signaled after command list execution + result = ID3D12CommandQueue_Signal(d3d12Driver->GraphicsQueue, d3d12CommandList->InFlightFence->Handle, D3D12_FENCE_SIGNAL_VALUE); + if (FAILED(result)) + { + LogError(d3d12Driver, "Failed to enqueue fence signal!", result); + return false; + } // Mark the command list as submitted - if (d3d12Driver->SubmittedCommandBufferCount + 1 >= d3d12Driver->SubmittedCommandListCapacity) { + if (d3d12Driver->SubmittedCommandBufferCount + 1 >= d3d12Driver->SubmittedCommandListCapacity) + { d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandBufferCount + 1; d3d12Driver->SubmittedCommandLists = static_cast( @@ -281,10 +299,11 @@ namespace Juliet::D3D12 result = false; } - ID3D12Resource_Release(windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource); + ID3D12Resource_Release( + windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource); - //windowData->inFlightFences[windowData->frameCounter] = (SDL_GPUFence*)d3d12CommandBuffer->inFlightFence; - //(void)SDL_AtomicIncRef(&d3d12CommandBuffer->inFlightFence->referenceCount); + windowData->InFlightFences[windowData->WindowFrameCounter] = reinterpret_cast(d3d12CommandList->InFlightFence); + d3d12CommandList->InFlightFence->ReferenceCount += 1; windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight; } @@ -310,6 +329,26 @@ namespace Juliet::D3D12 return success; } + void DestroyCommandList(NonNullPtr commandList) + { + // TODO : Handle other kind of command list (copy compute) + if (commandList->GraphicsCommandList.CommandList) + { + ID3D12GraphicsCommandList_Release(commandList->GraphicsCommandList.CommandList); + } + + for (auto* allocator : commandList->GraphicsCommandList.Allocator) + { + if (allocator) + { + ID3D12CommandAllocator_Release(allocator); + } + } + + Free(commandList->PresentDatas); + Free(commandList.Get()); + } + void SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort) { auto* d3d12CommandList = reinterpret_cast(commandList.Get()); @@ -347,5 +386,4 @@ namespace Juliet::D3D12 auto* d3d12CommandList = reinterpret_cast(commandList.Get()); ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandList->GraphicsCommandList.CommandList, reference); } - } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.h b/Juliet/src/Graphics/D3D12/DX12CommandList.h index ca1b1c3..1c2faff 100644 --- a/Juliet/src/Graphics/D3D12/DX12CommandList.h +++ b/Juliet/src/Graphics/D3D12/DX12CommandList.h @@ -9,8 +9,9 @@ namespace Juliet::D3D12 { // Forward Declare struct D3D12Driver; - struct D3D12WindowData; + struct D3D12Fence; struct D3D12TextureSubresource; + struct D3D12WindowData; struct D3D12CommandListBaseData { @@ -44,6 +45,8 @@ namespace Juliet::D3D12 uint32 PresentDataCapacity; uint32 PresentDataCount; + D3D12Fence* InFlightFence; + D3D12GraphicsCommandListData GraphicsCommandList; D3D12GraphicsCommandListData ComputeCommandList; D3D12CopyCommandListData CopyCommandList; @@ -54,6 +57,7 @@ namespace Juliet::D3D12 extern CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType); extern bool SubmitCommandLists(NonNullPtr commandList); + extern void DestroyCommandList(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); diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp index 182048f..7088a46 100644 --- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -168,6 +169,7 @@ namespace Juliet::D3D12 void DestroyDriver_Internal(NonNullPtr driver) { + // Destroy pools for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { if (driver->StagingDescriptorPools[i]) @@ -177,6 +179,32 @@ namespace Juliet::D3D12 } } + // 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; + } + } + + // Clean allocations + Free(driver->AvailableCommandLists); + Free(driver->SubmittedCommandLists); + Free(driver->WindowData); + Free(driver->AvailableFences); + if (driver->IndirectDrawCommandSignature) { ID3D12CommandSignature_Release(driver->IndirectDrawCommandSignature); @@ -529,6 +557,15 @@ namespace Juliet::D3D12 return nullptr; } + driver->AvailableFenceCapacity = 4; + driver->AvailableFenceCount = 0; + driver->AvailableFences = static_cast(Calloc(driver->AvailableFenceCapacity, sizeof(D3D12Fence*))); + if (!driver->AvailableFences) + { + DestroyDriver_Internal(driver); + return nullptr; + } + // Staging descriptor pools for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h index 20f4e89..735ea03 100644 --- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h +++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h @@ -14,6 +14,7 @@ namespace Juliet::D3D12 { // Forward Declare struct D3D12CommandList; + struct D3D12Fence; struct D3D12WindowData { @@ -72,6 +73,10 @@ namespace Juliet::D3D12 uint8 SubmittedCommandListCapacity; uint8 SubmittedCommandBufferCount; + D3D12Fence** AvailableFences; + uint32 AvailableFenceCount; + uint32 AvailableFenceCapacity; + D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; uint8 FramesInFlight;