From 83267725585be5c2e6084e8738e29d9b3dd02563 Mon Sep 17 00:00:00 2001 From: Patedam Date: Wed, 19 Feb 2025 22:01:39 -0500 Subject: [PATCH] Finishing fences + moved some functions to an internal namespace to tidy stuff a bit --- Juliet/src/Graphics/D3D12/D3D12Common.cpp | 222 +++++++-------- Juliet/src/Graphics/D3D12/D3D12Common.h | 19 +- Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp | 32 ++- .../Graphics/D3D12/D3D12Synchronization.cpp | 198 ++++++++++---- .../src/Graphics/D3D12/D3D12Synchronization.h | 24 +- Juliet/src/Graphics/D3D12/D3D12Texture.cpp | 131 ++++----- Juliet/src/Graphics/D3D12/D3D12Texture.h | 46 ++-- Juliet/src/Graphics/D3D12/DX12CommandList.cpp | 183 ++++++++----- Juliet/src/Graphics/D3D12/DX12CommandList.h | 8 +- .../src/Graphics/D3D12/DX12GraphicsDevice.cpp | 33 ++- .../src/Graphics/D3D12/DX12GraphicsDevice.h | 2 +- Juliet/src/Graphics/D3D12/DX12SwapChain.cpp | 255 +++++++++--------- Juliet/src/Graphics/D3D12/DX12SwapChain.h | 10 +- Juliet/src/Graphics/GraphicsDevice.h | 5 + 14 files changed, 683 insertions(+), 485 deletions(-) diff --git a/Juliet/src/Graphics/D3D12/D3D12Common.cpp b/Juliet/src/Graphics/D3D12/D3D12Common.cpp index ea5aa58..9e8ddd2 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Common.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Common.cpp @@ -26,7 +26,7 @@ namespace Juliet::D3D12 bool ExtendStagingDescriptorPool(NonNullPtr driver, D3D12StagingDescriptorPool& pool) { D3D12DescriptorHeap* heap = - CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); + Internal::CreateDescriptorHeap(driver, pool.Heaps[0]->HeapType, kStagingHeapDescriptorExpectedCount, true); if (!heap) { return false; @@ -47,122 +47,126 @@ namespace Juliet::D3D12 } } // namespace - D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging) + namespace Internal { - ID3D12DescriptorHeap* handle; - - auto heap = static_cast(Calloc(1, sizeof(D3D12DescriptorHeap))); - if (!heap) + D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, + uint32 count, bool isStaging) { - return nullptr; - } + ID3D12DescriptorHeap* handle; - heap->CurrentDescriptorIndex = 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; - - HRESULT result = - ID3D12Device_CreateDescriptorHeap(driver->D3D12Device, &heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle); - if (FAILED(result)) - { - LogError(driver, "Failed to create descriptor heap!", result); - DestroyDescriptorHeap(heap); - return nullptr; - } - - heap->Handle = handle; - heap->HeapType = type; - heap->MaxDescriptors = count; - heap->Staging = isStaging; - heap->DescriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(driver->D3D12Device, type); - ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapCPUStart); - if (!isStaging) - { - ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapGPUStart); - } - - return heap; - } - - void DestroyDescriptorHeap(NonNullPtr heap) - { - if (heap->Handle) - { - ID3D12DescriptorHeap_Release(heap->Handle); - } - Free(heap.Get()); - } - - 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)) + auto heap = static_cast(Calloc(1, sizeof(D3D12DescriptorHeap))); + if (!heap) { - return false; + return nullptr; + } + + heap->CurrentDescriptorIndex = 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; + + HRESULT result = + ID3D12Device_CreateDescriptorHeap(driver->D3D12Device, &heapDesc, IID_ID3D12DescriptorHeap, (void**)&handle); + if (FAILED(result)) + { + LogError(driver, "Failed to create descriptor heap!", result); + DestroyDescriptorHeap(heap); + return nullptr; + } + + heap->Handle = handle; + heap->HeapType = type; + heap->MaxDescriptors = count; + heap->Staging = isStaging; + heap->DescriptorSize = ID3D12Device_GetDescriptorHandleIncrementSize(driver->D3D12Device, type); + ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapCPUStart); + if (!isStaging) + { + ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(handle, &heap->DescriptorHeapGPUStart); + } + + return heap; + } + + void DestroyDescriptorHeap(NonNullPtr heap) + { + if (heap->Handle) + { + ID3D12DescriptorHeap_Release(heap->Handle); + } + Free(heap.Get()); + } + + 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; } } - 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) + void DestroyStagingDescriptorPool(NonNullPtr pool) { - MemCopy(&pool->FreeDescriptors[pool->FreeDescriptorCount], &cpuDescriptor, sizeof(D3D12StagingDescriptor)); - pool->FreeDescriptorCount += 1; - } - } + for (uint32 i = 0; i < pool->HeapCount; i += 1) + { + DestroyDescriptorHeap(pool->Heaps[i]); + } - 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()); } - - Free(pool->Heaps); - Free(pool->FreeDescriptors); - Free(pool.Get()); - } + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Common.h b/Juliet/src/Graphics/D3D12/D3D12Common.h index c04feff..1f5b817 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Common.h +++ b/Juliet/src/Graphics/D3D12/D3D12Common.h @@ -51,13 +51,16 @@ namespace Juliet::D3D12 uint32 CpuHandleIndex; }; - extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, D3D12_DESCRIPTOR_HEAP_TYPE type, - uint32 count, bool isStaging); - extern void DestroyDescriptorHeap(NonNullPtr heap); + namespace Internal + { + extern D3D12DescriptorHeap* CreateDescriptorHeap(NonNullPtr driver, + D3D12_DESCRIPTOR_HEAP_TYPE type, uint32 count, bool isStaging); + extern void DestroyDescriptorHeap(NonNullPtr heap); - 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); + 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/D3D12RenderPass.cpp b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp index 455d387..719ae62 100644 --- a/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp @@ -31,7 +31,7 @@ namespace Juliet::D3D12 for (uint32 idx = 0; idx < colorTargetInfoCount; ++idx) { auto* container = reinterpret_cast(colorTargetInfos[idx].TargetTexture); - D3D12TextureSubresource* subresource = PrepareTextureSubresourceForWrite( + 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); @@ -61,9 +61,11 @@ namespace Juliet::D3D12 { 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); + Internal::PrepareTextureSubresourceForWrite(d3d12CommandList, resolveContainer, + colorTargetInfos[idx].ResolveLayerIndex, + colorTargetInfos[idx].ResolveMipLevel, + colorTargetInfos[idx].CycleResolveTexture, + D3D12_RESOURCE_STATE_RESOLVE_DEST); d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; @@ -114,27 +116,31 @@ namespace Juliet::D3D12 { if (d3d12CommandList->ColorResolveSubresources[idx]) { - TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE, - d3d12CommandList->ColorTargetSubresources[idx]); + Internal::TextureSubresourceBarrier(d3d12CommandList, D3D12_RESOURCE_STATE_RENDER_TARGET, + D3D12_RESOURCE_STATE_RESOLVE_SOURCE, + d3d12CommandList->ColorTargetSubresources[idx]); ID3D12GraphicsCommandList_ResolveSubresource( d3d12CommandList->GraphicsCommandList.CommandList, d3d12CommandList->ColorResolveSubresources[idx]->Parent->Resource, d3d12CommandList->ColorResolveSubresources[idx]->Index, d3d12CommandList->ColorTargetSubresources[idx]->Parent->Resource, d3d12CommandList->ColorTargetSubresources[idx]->Index, - ConvertToD3D12TextureFormat( + Internal::ConvertToD3D12TextureFormat( d3d12CommandList->ColorTargetSubresources[idx]->Parent->Container->Header.CreateInfo.Format)); - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], - D3D12_RESOURCE_STATE_RESOLVE_SOURCE); + Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, + d3d12CommandList->ColorTargetSubresources[idx], + D3D12_RESOURCE_STATE_RESOLVE_SOURCE); - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorResolveSubresources[idx], - D3D12_RESOURCE_STATE_RESOLVE_DEST); + Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, + d3d12CommandList->ColorResolveSubresources[idx], + D3D12_RESOURCE_STATE_RESOLVE_DEST); } else { - TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, d3d12CommandList->ColorTargetSubresources[idx], - D3D12_RESOURCE_STATE_RENDER_TARGET); + Internal::TextureSubresourceTransitionToDefaultUsage(d3d12CommandList, + d3d12CommandList->ColorTargetSubresources[idx], + D3D12_RESOURCE_STATE_RENDER_TARGET); } } } diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp index 1b7bef2..0e4ff45 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp @@ -8,91 +8,171 @@ namespace Juliet::D3D12 { - void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, bool needsUavBarrier) + namespace { - D3D12_RESOURCE_BARRIER barrierDesc[2]; - uint32 numBarriers = 0; - - // No transition barrier is needed if the state is not changing. - if (sourceState != destinationState) + void ReleaseFenceToPool(NonNullPtr driver, NonNullPtr fence) { - 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; + if (driver->AvailableFenceCount + 1 >= driver->AvailableFenceCapacity) + { + driver->AvailableFenceCapacity = driver->AvailableFenceCapacity * 2; + driver->AvailableFences = static_cast( + Realloc(driver->AvailableFences, sizeof(D3D12Fence*) * driver->AvailableFenceCapacity)); + } + driver->AvailableFences[driver->AvailableFenceCount] = fence; + driver->AvailableFenceCount += 1; + } + } // namespace - numBarriers += 1; + bool Wait(NonNullPtr driver) + { + auto d3d12driver = static_cast(driver.Get()); + D3D12Fence* fence = Internal::AcquireFence(d3d12driver); + if (!fence) + { + return false; } - if (needsUavBarrier) + if (d3d12driver->GraphicsQueue) { - barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; - barrierDesc[numBarriers].Flags = static_cast(0); - barrierDesc[numBarriers].UAV.pResource = resource; + // Insert a signal into the end of the command queue... + ID3D12CommandQueue_Signal(d3d12driver->GraphicsQueue, fence->Handle, D3D12_FENCE_SIGNAL_VALUE); - numBarriers += 1; + // ...and then block on it. + if (ID3D12Fence_GetCompletedValue(fence->Handle) != D3D12_FENCE_SIGNAL_VALUE) + { + HRESULT result = ID3D12Fence_SetEventOnCompletion(fence->Handle, D3D12_FENCE_SIGNAL_VALUE, fence->Event); + if (FAILED(result)) + { + LogError(d3d12driver, "Setting fence event failed!", result); + return false; + } + + DWORD waitResult = WaitForSingleObject(fence->Event, INFINITE); + if (waitResult == WAIT_FAILED) + { + LogError(d3d12driver, "Wait failed!", result); + return false; + } + } } - if (numBarriers > 0) + ReleaseFence(driver, reinterpret_cast(fence)); + + bool result = true; + + // Clean up + for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; idx -= 1) { - ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc); + result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); + } + + return result; + } + + bool QueryFence(NonNullPtr driver, NonNullPtr fence) + { + return true; + } + + void ReleaseFence(NonNullPtr driver, NonNullPtr fence) + { + auto d3d12driver = static_cast(driver.Get()); + auto d3d12Fence = reinterpret_cast(fence.Get()); + + if (--d3d12Fence->ReferenceCount == 0) + { + ReleaseFenceToPool(d3d12driver, d3d12Fence); } } - D3D12Fence* AcquireFence(NonNullPtr driver) + namespace Internal { - D3D12Fence* fence; - ID3D12Fence* handle; - - // TODO :Thread safe (lock + atomic) - - if (driver->AvailableFenceCount == 0) + void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, uint32 subresourceIndex, + bool needsUavBarrier) { - HRESULT result = ID3D12Device_CreateFence(driver->D3D12Device, D3D12_FENCE_UNSIGNALED_VALUE, D3D12_FENCE_FLAG_NONE, - IID_ID3D12Fence, reinterpret_cast(&handle)); - if (FAILED(result)) + D3D12_RESOURCE_BARRIER barrierDesc[2]; + uint32 numBarriers = 0; + + // No transition barrier is needed if the state is not changing. + if (sourceState != destinationState) { - LogError(driver, "Failed to create fence!", result); - return nullptr; + 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; } - fence = static_cast(Calloc(1, sizeof(D3D12Fence))); - if (!fence) + if (needsUavBarrier) { - ID3D12Fence_Release(handle); + barrierDesc[numBarriers].Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + barrierDesc[numBarriers].Flags = static_cast(0); + barrierDesc[numBarriers].UAV.pResource = resource; - return nullptr; + numBarriers += 1; + } + + if (numBarriers > 0) + { + ID3D12GraphicsCommandList_ResourceBarrier(commandList->GraphicsCommandList.CommandList, numBarriers, barrierDesc); } - fence->Handle = handle; - fence->Event = CreateEvent(nullptr, false, false, nullptr); - fence->ReferenceCount = 0; } - else + + D3D12Fence* AcquireFence(NonNullPtr driver) { - fence = driver->AvailableFences[driver->AvailableFenceCount - 1]; - driver->AvailableFenceCount -= 1; - ID3D12Fence_Signal(fence->Handle, D3D12_FENCE_UNSIGNALED_VALUE); + 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; } - fence->ReferenceCount += 1; - return fence; - } - - void DestroyFence(NonNullPtr fence) - { - if (fence->Handle) + void DestroyFence(NonNullPtr fence) { - ID3D12Fence_Release(fence->Handle); - } + if (fence->Handle) + { + ID3D12Fence_Release(fence->Handle); + } - if (fence->Event) - { - CloseHandle(fence->Event); + if (fence->Event) + { + CloseHandle(fence->Event); + } + Free(fence.Get()); } - Free(fence.Get()); - } - + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h index 0d48620..443734b 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h +++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h @@ -2,6 +2,13 @@ #include #include +#include + +namespace Juliet +{ + struct Fence; + struct GPUDriver; +} // namespace Juliet namespace Juliet::D3D12 { @@ -18,10 +25,17 @@ namespace Juliet::D3D12 int32 ReferenceCount; // TODO : Atomic }; - extern void ResourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, - D3D12_RESOURCE_STATES destinationState, ID3D12Resource* resource, - uint32 subresourceIndex, bool needsUavBarrier); + extern bool Wait(NonNullPtr driver); + extern bool QueryFence(NonNullPtr driver, NonNullPtr fence); + extern void ReleaseFence(NonNullPtr driver, NonNullPtr fence); - extern D3D12Fence* AcquireFence(NonNullPtr driver); - extern void DestroyFence(NonNullPtr fence); + 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); + 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 index c16b727..ac94ca8 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp @@ -157,79 +157,84 @@ namespace Juliet::D3D12 } } // namespace - D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr commandList, - NonNullPtr container, uint32 layer, - uint32 level, bool shouldCycle, D3D12_RESOURCE_STATES newTextureUsage) + namespace Internal { - D3D12TextureSubresource* subresource = FetchTextureSubresource(container, layer, level); - if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 0) + D3D12TextureSubresource* PrepareTextureSubresourceForWrite(NonNullPtr commandList, + NonNullPtr container, + uint32 layer, uint32 level, bool shouldCycle, + D3D12_RESOURCE_STATES newTextureUsage) { - // TODO: Cycle the active texture to an available one. Not needed for swap chain (current objective) - // CycleActiveTexture(commandList->Driver, container); + D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level); + if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 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); + subresource = Internal::FetchTextureSubresource(container, layer, level); + } + + Internal::TextureSubresourceTransitionFromDefaultUsage(commandList, subresource, newTextureUsage); + + return subresource; } - 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); - 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) + D3D12TextureSubresource* FetchTextureSubresource(NonNullPtr container, uint32 layer, uint32 level) { - TextureSubresourceTransitionFromDefaultUsage(commandList, &texture->Subresources[i], toTextureUsage); + uint32 index = ComputeSubresourceIndex(level, layer, container->Header.CreateInfo.MipLevelCount); + return &container->ActiveTexture->Subresources[index]; } - } - 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) + void TextureSubresourceBarrier(NonNullPtr commandList, D3D12_RESOURCE_STATES sourceState, + D3D12_RESOURCE_STATES destinationState, NonNullPtr textureSubresource) { - TextureSubresourceTransitionToDefaultUsage(commandList, &texture->Subresources[i], fromTextureUsage); + 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); } - } - // Utils - DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format) - { - return JulietToD3D12_TextureFormat[ToUnderlying(format)]; - } + 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)]; + } + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.h b/Juliet/src/Graphics/D3D12/D3D12Texture.h index a106cfc..eca7cd6 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Texture.h +++ b/Juliet/src/Graphics/D3D12/D3D12Texture.h @@ -62,27 +62,31 @@ namespace Juliet::D3D12 int32 RefCount; }; - 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); + 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); + // 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); + // Utils + extern DXGI_FORMAT ConvertToD3D12TextureFormat(TextureFormat format); + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp index c7d03e2..685f57f 100644 --- a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp +++ b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp @@ -10,7 +10,7 @@ namespace Juliet::D3D12 { namespace { - bool HasD3D12CommandList(NonNullPtr commandList, QueueType queueType) + bool HasD3D12CommandListForQueueType(NonNullPtr commandList, QueueType queueType) { switch (queueType) { @@ -37,7 +37,7 @@ namespace Juliet::D3D12 return true; } - bool CreateD3D12CommandList(NonNullPtr driver, NonNullPtr commandList, QueueType queueType) + bool CreateD3D12CommandListForQueueType(NonNullPtr driver, NonNullPtr commandList, QueueType queueType) { // TODO: String library std::wstring wide_str = L"CommandList ID:" + std::to_wstring(commandList->ID); @@ -111,7 +111,7 @@ namespace Juliet::D3D12 if (!commandList) { Log(LogLevel::Error, LogCategory::Graphics, "Cannot allocate D3D12CommandList: Out of memory"); - DestroyCommandList(commandList); + Internal::DestroyCommandList(commandList); return false; } @@ -122,14 +122,18 @@ namespace Juliet::D3D12 { Log(LogLevel::Error, LogCategory::Graphics, "Error not implemented, out of memory, handle that by deallocating stuff and returning false"); - DestroyCommandList(commandList); + Internal::DestroyCommandList(commandList); return false; } - driver->AvailableCommandLists = resizedArray; - driver->AvailableCommandLists[driver->AvailableCommandListCapacity] = commandList; + uint32 id = driver->AvailableCommandListCapacity; + driver->AvailableCommandListCapacity += 1; + driver->AvailableCommandLists = resizedArray; - commandList->ID = driver->AvailableCommandListCapacity; + driver->AvailableCommandLists[driver->AvailableCommandListCount] = commandList; + driver->AvailableCommandListCount += 1; + + commandList->ID = id; commandList->Driver = driver; commandList->PresentDataCapacity = 1; @@ -137,35 +141,42 @@ namespace Juliet::D3D12 commandList->PresentDatas = static_cast(Calloc(commandList->PresentDataCapacity, sizeof(D3D12PresentData))); - driver->AvailableCommandListCapacity += 1; + // 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()); - uint8 currentCommandListIndex = d3d12Driver->AvailableCommandListCount; - if (currentCommandListIndex >= d3d12Driver->AvailableCommandListCapacity) - { - if (!AllocateCommandList(d3d12Driver, queueType)) - { - return nullptr; - } - } - - D3D12CommandList* commandList = d3d12Driver->AvailableCommandLists[currentCommandListIndex]; - if (!HasD3D12CommandList(commandList, queueType)) - { - if (!CreateD3D12CommandList(d3d12Driver, commandList, queueType)) - { - Log(LogLevel::Error, LogCategory::Graphics, "Cannot Create D3D12 command list"); - DestroyCommandList(commandList); - return nullptr; - } - } + D3D12CommandList* commandList = AcquireCommandListFromPool(d3d12Driver, queueType); // Get Proper allocator for the frame and reset both it and the requested queue uint8 bufferIndex = d3d12Driver->FrameCounter % GPUDriver::kResourceBufferCount; @@ -195,7 +206,8 @@ namespace Juliet::D3D12 default: Assert(false && "Unsupported QueueType"); return nullptr; } - d3d12Driver->AvailableCommandListCount += 1; + commandList->AutoReleaseFence = true; + return reinterpret_cast(commandList); } @@ -212,7 +224,7 @@ namespace Juliet::D3D12 uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; D3D12TextureContainer* container = &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; - D3D12TextureSubresource* subresource = FetchTextureSubresource(container, 0, 0); + D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, 0, 0); D3D12_RESOURCE_BARRIER barrierDesc; barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; @@ -248,7 +260,7 @@ namespace Juliet::D3D12 ID3D12CommandList_Release(commandLists[0]); // Acquire a fence and set it to the in-flight fence - d3d12CommandList->InFlightFence = AcquireFence(d3d12Driver); + d3d12CommandList->InFlightFence = Internal::AcquireFence(d3d12Driver); if (!d3d12CommandList->InFlightFence) { return false; @@ -263,16 +275,15 @@ namespace Juliet::D3D12 } // Mark the command list as submitted - if (d3d12Driver->SubmittedCommandBufferCount + 1 >= d3d12Driver->SubmittedCommandListCapacity) + if (d3d12Driver->SubmittedCommandListCount + 1 >= d3d12Driver->SubmittedCommandListCapacity) { - d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandBufferCount + 1; + d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandListCount + 1; d3d12Driver->SubmittedCommandLists = static_cast( Realloc(d3d12Driver->SubmittedCommandLists, sizeof(D3D12CommandList*) * d3d12Driver->SubmittedCommandListCapacity)); } - - d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandBufferCount] = d3d12CommandList; - d3d12Driver->SubmittedCommandBufferCount += 1; + d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandListCount] = d3d12CommandList; + d3d12Driver->SubmittedCommandListCount += 1; bool success = true; for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) @@ -308,19 +319,15 @@ namespace Juliet::D3D12 } // TODO : Correctly clean up and destroy - d3d12Driver->AvailableCommandListCount = 0; // Check for cleanups - // for (Sint32 i = renderer->submittedCommandBufferCount - 1; i >= 0; i -= 1) { - // Uint64 fenceValue = ID3D12Fence_GetCompletedValue( - // renderer->submittedCommandBuffers[i]->inFlightFence->handle); - // - // if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) { - // result &= D3D12_INTERNAL_CleanCommandBuffer( - // renderer, - // renderer->submittedCommandBuffers[i], - // false); - // } - // } + for (int32 i = d3d12Driver->SubmittedCommandListCount - 1; i >= 0; i -= 1) + { + uint64 fenceValue = ID3D12Fence_GetCompletedValue(d3d12Driver->SubmittedCommandLists[i]->InFlightFence->Handle); + if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) + { + result &= Internal::CleanCommandList(d3d12Driver, d3d12Driver->SubmittedCommandLists[i], false); + } + } // TODO Destroy anything (buffer, texture, etc...) @@ -329,26 +336,6 @@ 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()); @@ -386,4 +373,66 @@ namespace Juliet::D3D12 auto* d3d12CommandList = reinterpret_cast(commandList.Get()); ID3D12GraphicsCommandList_OMSetStencilRef(d3d12CommandList->GraphicsCommandList.CommandList, reference); } + + namespace Internal + { + 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()); + } + + bool CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel) + { + // No more presentation data + commandList->PresentDataCount = 0; + + // Release Fence if needed + if (commandList->AutoReleaseFence) + { + ReleaseFence(driver.Get(), reinterpret_cast(commandList->InFlightFence)); + commandList->InFlightFence = nullptr; + } + + // Return the command list to the pool + if (driver->AvailableCommandListCount == driver->AvailableCommandListCapacity) + { + driver->AvailableCommandListCapacity += 1; + driver->AvailableCommandLists = static_cast( + Realloc(driver->AvailableCommandLists, driver->AvailableCommandListCapacity * sizeof(D3D12CommandList*))); + } + 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; + } + } + } + + return true; + } + + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.h b/Juliet/src/Graphics/D3D12/DX12CommandList.h index 1c2faff..e07b7d0 100644 --- a/Juliet/src/Graphics/D3D12/DX12CommandList.h +++ b/Juliet/src/Graphics/D3D12/DX12CommandList.h @@ -46,6 +46,7 @@ namespace Juliet::D3D12 uint32 PresentDataCount; D3D12Fence* InFlightFence; + bool AutoReleaseFence; D3D12GraphicsCommandListData GraphicsCommandList; D3D12GraphicsCommandListData ComputeCommandList; @@ -57,9 +58,14 @@ 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); extern void SetStencilReference(NonNullPtr commandList, uint8 reference); + + namespace Internal + { + extern void DestroyCommandList(NonNullPtr commandList); + extern bool CleanCommandList(NonNullPtr driver, NonNullPtr commandList, bool cancel); + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp index 7088a46..b76106a 100644 --- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp @@ -174,7 +174,7 @@ namespace Juliet::D3D12 { if (driver->StagingDescriptorPools[i]) { - DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); + Internal::DestroyStagingDescriptorPool(driver->StagingDescriptorPools[i]); driver->StagingDescriptorPools[i] = nullptr; } } @@ -184,7 +184,7 @@ namespace Juliet::D3D12 { if (driver->AvailableCommandLists[i]) { - DestroyCommandList(driver->AvailableCommandLists[i]); + Internal::DestroyCommandList(driver->AvailableCommandLists[i]); driver->AvailableCommandLists[i] = nullptr; } } @@ -194,7 +194,7 @@ namespace Juliet::D3D12 { if (driver->AvailableFences[i]) { - DestroyFence(driver->AvailableFences[i]); + Internal::DestroyFence(driver->AvailableFences[i]); driver->AvailableFences[i] = nullptr; } } @@ -202,7 +202,7 @@ namespace Juliet::D3D12 // Clean allocations Free(driver->AvailableCommandLists); Free(driver->SubmittedCommandLists); - Free(driver->WindowData); + //Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now Free(driver->AvailableFences); if (driver->IndirectDrawCommandSignature) @@ -278,7 +278,7 @@ namespace Juliet::D3D12 windowData->Window = window; - if (!CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) + if (!Internal::CreateSwapChain(d3d12Driver, windowData, SwapChainComposition::SDR, PresentMode::VSync)) { Log(LogLevel::Error, LogCategory::Graphics, "AttachToWindow failure: Cannot create Swap Chain."); Free(windowData); @@ -294,12 +294,21 @@ namespace Juliet::D3D12 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"); - Assert(d3d12Driver->WindowData && "Trying to destroy a swapchain but no Window Data exists"); + Wait(driver); - // TODO : Wait for any remaining work and release the fences. + for (uint32 idx = 0; idx < GPUDriver::kMaxFramesInFlight; idx += 1) + { + if (windowData->InFlightFences[idx] != nullptr) + { + ReleaseFence(driver, windowData->InFlightFences[idx]); + windowData->InFlightFences[idx] = nullptr; + } + } - DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); + Internal::DestroySwapChain(d3d12Driver, d3d12Driver->WindowData); Free(d3d12Driver->WindowData); d3d12Driver->WindowData = nullptr; @@ -548,7 +557,7 @@ namespace Juliet::D3D12 // Create Pools driver->SubmittedCommandListCapacity = 4; - driver->SubmittedCommandBufferCount = 0; + driver->SubmittedCommandListCount = 0; driver->SubmittedCommandLists = static_cast(Calloc(driver->SubmittedCommandListCapacity, sizeof(D3D12CommandList*))); if (!driver->SubmittedCommandLists) @@ -570,7 +579,7 @@ namespace Juliet::D3D12 for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { driver->StagingDescriptorPools[i] = - CreateStagingDescriptorPool(driver, static_cast(i)); + Internal::CreateStagingDescriptorPool(driver, static_cast(i)); if (driver->StagingDescriptorPools[i] == nullptr) { @@ -605,6 +614,10 @@ namespace Juliet::D3D12 device->SetBlendConstants = SetBlendConstants; device->SetStencilReference = SetStencilReference; + device->Wait = Wait; + device->QueryFence = QueryFence; + device->ReleaseFence = ReleaseFence; + device->Driver = driver; driver->GraphicsDevice = device; diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h index 735ea03..776b0d8 100644 --- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h +++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h @@ -71,7 +71,7 @@ namespace Juliet::D3D12 D3D12CommandList** SubmittedCommandLists; uint8 SubmittedCommandListCapacity; - uint8 SubmittedCommandBufferCount; + uint8 SubmittedCommandListCount; D3D12Fence** AvailableFences; uint32 AvailableFenceCount; diff --git a/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp b/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp index 4172d73..08f2792 100644 --- a/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp +++ b/Juliet/src/Graphics/D3D12/DX12SwapChain.cpp @@ -3,13 +3,14 @@ #include #include #include +#include #include #include #include #include #include -#include + namespace Juliet::D3D12 { namespace @@ -105,7 +106,7 @@ namespace Juliet::D3D12 texture->IndexInContainer = 0; // Assign SRV to the swapchain texture - AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, texture->SRVHandle); + Internal::AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, texture->SRVHandle); D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc; srvDesc.Format = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; @@ -118,7 +119,7 @@ namespace Juliet::D3D12 // Assign RTV to the swapchain texture DXGI_FORMAT swapchainFormat = SwapchainCompositionToTextureFormat[ToUnderlying(composition)]; - AssignStagingDescriptor(driver, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, texture->Subresources[0].RTVHandles[0]); + 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; @@ -186,136 +187,140 @@ namespace Juliet::D3D12 } } // namespace - 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 = - IDXGIFactory4_CreateSwapChainForHwnd(driver->DXGIFactory, reinterpret_cast(driver->GraphicsQueue), - windowHandle, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain); - if (FAILED(result)) - { - LogError(driver, "Failed to create SwapChain", result); - return false; - } - - IDXGISwapChain3* swapChain3 = nullptr; - result = IDXGISwapChain1_QueryInterface(swapChain, IID_IDXGISwapChain3, reinterpret_cast(&swapChain3)); - IDXGISwapChain1_Release(swapChain); - if (FAILED(result)) - { - LogError(driver, "Could not query IDXGISwapChain3 interface", result); - return false; - } - - if (composition != SwapChainComposition::SDR) - { - IDXGISwapChain3_SetColorSpace1(swapChain3, SwapchainCompositionToColorSpace[ToUnderlying(composition)]); - } - - IDXGIFactory1* parentFactory = nullptr; - result = IDXGISwapChain3_GetParent(swapChain3, 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 = IDXGIFactory1_MakeWindowAssociation(parentFactory, windowHandle, DXGI_MWA_NO_WINDOW_CHANGES); - if (FAILED(result)) - { - Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result); - } - IDXGIFactory1_Release(parentFactory); - } - - IDXGISwapChain3_GetDesc1(swapChain3, &swapChainDesc); - if (FAILED(result)) - { - LogError(driver, "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)) - { - IDXGISwapChain3_Release(swapChain3); - return false; - } - } - - return true; - } - bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) { return AcquireSwapChainTexture(false, commandList, window, swapChainTexture); } - void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData) + namespace Internal { - for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) + bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, + SwapChainComposition composition, PresentMode presentMode) { - ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->SRVHandle); - ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles[0]); + 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; + } - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources[0].RTVHandles); - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture->Subresources); - Free(windowData->SwapChainTextureContainers[idx].ActiveTexture); - Free(windowData->SwapChainTextureContainers[idx].Textures); + // 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 = + IDXGIFactory4_CreateSwapChainForHwnd(driver->DXGIFactory, reinterpret_cast(driver->GraphicsQueue), + windowHandle, &swapChainDesc, &swapChainFullscreenDesc, nullptr, &swapChain); + if (FAILED(result)) + { + LogError(driver, "Failed to create SwapChain", result); + return false; + } + + IDXGISwapChain3* swapChain3 = nullptr; + result = IDXGISwapChain1_QueryInterface(swapChain, IID_IDXGISwapChain3, reinterpret_cast(&swapChain3)); + IDXGISwapChain1_Release(swapChain); + if (FAILED(result)) + { + LogError(driver, "Could not query IDXGISwapChain3 interface", result); + return false; + } + + if (composition != SwapChainComposition::SDR) + { + IDXGISwapChain3_SetColorSpace1(swapChain3, SwapchainCompositionToColorSpace[ToUnderlying(composition)]); + } + + IDXGIFactory1* parentFactory = nullptr; + result = IDXGISwapChain3_GetParent(swapChain3, 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 = IDXGIFactory1_MakeWindowAssociation(parentFactory, windowHandle, DXGI_MWA_NO_WINDOW_CHANGES); + if (FAILED(result)) + { + Log(LogLevel::Warning, LogCategory::Graphics, "MakeWindowAssociation failed! Error Code: " HRESULT_FMT, result); + } + IDXGIFactory1_Release(parentFactory); + } + + IDXGISwapChain3_GetDesc1(swapChain3, &swapChainDesc); + if (FAILED(result)) + { + LogError(driver, "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)) + { + IDXGISwapChain3_Release(swapChain3); + return false; + } + } + + return true; } - IDXGISwapChain_Release(windowData->SwapChain); - windowData->SwapChain = nullptr; - } + void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData) + { + for (uint32 idx = 0; idx < windowData->SwapChainTextureCount; ++idx) + { + ReleaseStagingDescriptor(driver, windowData->SwapChainTextureContainers[idx].ActiveTexture->SRVHandle); + 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); + } + + IDXGISwapChain_Release(windowData->SwapChain); + windowData->SwapChain = nullptr; + } + } // namespace Internal } // namespace Juliet::D3D12 diff --git a/Juliet/src/Graphics/D3D12/DX12SwapChain.h b/Juliet/src/Graphics/D3D12/DX12SwapChain.h index b7a7aef..fc12aec 100644 --- a/Juliet/src/Graphics/D3D12/DX12SwapChain.h +++ b/Juliet/src/Graphics/D3D12/DX12SwapChain.h @@ -7,8 +7,12 @@ namespace Juliet::D3D12 struct D3D12Driver; struct D3D12WindowData; - extern bool CreateSwapChain(NonNullPtr driver, NonNullPtr windowData, - SwapChainComposition composition, PresentMode presentMode); extern bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); - extern void DestroySwapChain(NonNullPtr driver, NonNullPtr windowData); + + 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/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h index d80ceaf..0311c7a 100644 --- a/Juliet/src/Graphics/GraphicsDevice.h +++ b/Juliet/src/Graphics/GraphicsDevice.h @@ -59,6 +59,11 @@ namespace Juliet void (*SetBlendConstants)(NonNullPtr commandList, FColor blendConstants); void (*SetStencilReference)(NonNullPtr commandList, uint8 reference); + // Fences + bool (*Wait)(NonNullPtr driver); + bool (*QueryFence)(NonNullPtr driver, NonNullPtr fence); + void (*ReleaseFence)(NonNullPtr driver, NonNullPtr fence); + const char* Name = "Unknown"; GPUDriver* Driver = nullptr; };