diff --git a/Juliet/include/Core/Common/CoreUtils.h b/Juliet/include/Core/Common/CoreUtils.h index a2afa97..dbc78ab 100644 --- a/Juliet/include/Core/Common/CoreUtils.h +++ b/Juliet/include/Core/Common/CoreUtils.h @@ -19,8 +19,16 @@ namespace Juliet } \ while (0) +#define Unimplemented() \ + do \ + { \ + Juliet::JulietAssert("Unimplemented!"); \ + } \ + while (0) + #else #define Assert(Expression) +#define Unimplemented() #endif extern void JULIET_API JulietAssert(const char* expression); diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h index f04cf8a..d804f75 100644 --- a/Juliet/include/Graphics/Graphics.h +++ b/Juliet/include/Graphics/Graphics.h @@ -93,6 +93,9 @@ namespace Juliet // SwapChain extern JULIET_API bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); + extern JULIET_API bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, + NonNullPtr window, Texture** swapChainTexture); + extern JULIET_API bool WaitForSwapchain(NonNullPtr device, NonNullPtr window); extern JULIET_API TextureFormat GetSwapChainTextureFormat(NonNullPtr device, NonNullPtr window); // Command List diff --git a/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp b/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp index 9514fe2..7193c73 100644 --- a/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12CommandList.cpp @@ -24,16 +24,15 @@ namespace Juliet::D3D12 bool CreateAllocator(NonNullPtr driver, NonNullPtr baseData, D3D12_COMMAND_QUEUE_DESC queueDesc) { - for (auto& buffer : baseData->Allocator) + HRESULT result = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator, + reinterpret_cast(&baseData->Allocator)); + if (FAILED(result)) { - HRESULT result = ID3D12Device5_CreateCommandAllocator(driver->D3D12Device, queueDesc.Type, IID_ID3D12CommandAllocator, - reinterpret_cast(&buffer)); - if (FAILED(result)) - { - Assert(false && "Error not implemented: cannot create ID3D12CommandAllocator"); - return false; - } + Assert(false && "Error not implemented: cannot create ID3D12CommandAllocator"); + return false; } + + ID3D12CommandAllocator_Reset(baseData->Allocator); return true; } @@ -43,6 +42,8 @@ namespace Juliet::D3D12 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) { @@ -63,6 +64,8 @@ namespace Juliet::D3D12 commandList->GraphicsCommandList.CommandList = d3d12GraphicsCommandList; ID3D12GraphicsCommandList6_SetName(d3d12GraphicsCommandList, wide_str.c_str()); + ID3D12GraphicsCommandList6_Reset(d3d12GraphicsCommandList, commandList->GraphicsCommandList.Allocator, nullptr); + return true; } case QueueType::Compute: @@ -82,6 +85,8 @@ namespace Juliet::D3D12 commandList->ComputeCommandList.CommandList = d3d12GraphicsCommandList; ID3D12GraphicsCommandList6_SetName(d3d12GraphicsCommandList, wide_str.c_str()); + ID3D12GraphicsCommandList6_Reset(d3d12GraphicsCommandList, commandList->ComputeCommandList.Allocator, nullptr); + return true; } case QueueType::Copy: @@ -99,6 +104,8 @@ namespace Juliet::D3D12 } commandList->CopyCommandList.CommandList = d3d12CopyCommandList; ID3D12GraphicsCommandList_SetName(d3d12CopyCommandList, wide_str.c_str()); + ID3D12GraphicsCommandList_Reset(d3d12CopyCommandList, commandList->CopyCommandList.Allocator, nullptr); + return true; } default: return false; @@ -136,11 +143,23 @@ namespace Juliet::D3D12 commandList->ID = id; commandList->Driver = driver; + // Window Handling commandList->PresentDataCapacity = 1; commandList->PresentDataCount = 0; commandList->PresentDatas = static_cast(Calloc(commandList->PresentDataCapacity, sizeof(D3D12PresentData))); + // Resource tracking + commandList->UsedTextureCapacity = 4; + commandList->UsedTextureCount = 0; + commandList->UsedTextures = + static_cast(Calloc(commandList->UsedTextureCapacity, sizeof(D3D12Texture*))); + + commandList->UsedGraphicsPipelineCapacity = 4; + commandList->UsedGraphicsPipelineCount = 0; + commandList->UsedGraphicsPipelines = static_cast( + Calloc(commandList->UsedGraphicsPipelineCapacity, sizeof(D3D12GraphicsPipeline*))); + // TODO : Simplify this if (!HasD3D12CommandListForQueueType(commandList, queueType)) { @@ -178,34 +197,6 @@ namespace Juliet::D3D12 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; - switch (queueType) - { - case QueueType::Graphics: - { - auto* allocator = commandList->GraphicsCommandList.Allocator[bufferIndex]; - ID3D12CommandAllocator_Reset(allocator); - ID3D12GraphicsCommandList6_Reset(commandList->GraphicsCommandList.CommandList, allocator, nullptr); - break; - } - case QueueType::Compute: - { - auto* allocator = commandList->ComputeCommandList.Allocator[bufferIndex]; - ID3D12CommandAllocator_Reset(allocator); - ID3D12GraphicsCommandList6_Reset(commandList->ComputeCommandList.CommandList, allocator, nullptr); - break; - } - case QueueType::Copy: - { - auto* allocator = commandList->CopyCommandList.Allocator[bufferIndex]; - ID3D12CommandAllocator_Reset(allocator); - ID3D12GraphicsCommandList6_Reset(commandList->CopyCommandList.CommandList, allocator, nullptr); - break; - } - default: Assert(false && "Unsupported QueueType"); return nullptr; - } - commandList->AutoReleaseFence = true; return reinterpret_cast(commandList); @@ -384,15 +375,11 @@ namespace Juliet::D3D12 ID3D12GraphicsCommandList_Release(commandList->GraphicsCommandList.CommandList); } - for (auto* allocator : commandList->GraphicsCommandList.Allocator) - { - if (allocator) - { - ID3D12CommandAllocator_Release(allocator); - } - } + ID3D12CommandAllocator_Release(commandList->GraphicsCommandList.Allocator); SafeFree(commandList->PresentDatas); + SafeFree(commandList->UsedTextures); + SafeFree(commandList->UsedGraphicsPipelines); Free(commandList.Get()); } @@ -401,6 +388,34 @@ namespace Juliet::D3D12 // No more presentation data commandList->PresentDataCount = 0; + HRESULT result = ID3D12CommandAllocator_Reset(commandList->GraphicsCommandList.Allocator); + if (FAILED(result)) + { + LogError(driver, "Could not reset command allocator", result); + return false; + } + + result = ID3D12GraphicsCommandList_Reset(commandList->GraphicsCommandList.CommandList, + commandList->GraphicsCommandList.Allocator, NULL); + if (FAILED(result)) + { + LogError(driver, "Could not reset command list", result); + return false; + } + + // 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) { @@ -434,5 +449,35 @@ namespace Juliet::D3D12 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; \ + } \ + } \ + \ + if (commandList->count == commandList->capacity) \ + { \ + commandList->capacity += 1; \ + commandList->array = (type*)Realloc(commandList->array, commandList->capacity * sizeof(type)); \ + } \ + 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 index 12b5d07..06dfd71 100644 --- a/Juliet/src/Graphics/D3D12/D3D12CommandList.h +++ b/Juliet/src/Graphics/D3D12/D3D12CommandList.h @@ -11,12 +11,13 @@ namespace Juliet::D3D12 // Forward Declare struct D3D12Driver; struct D3D12Fence; + struct D3D12Texture; struct D3D12TextureSubresource; struct D3D12WindowData; struct D3D12CommandListBaseData { - ID3D12CommandAllocator* Allocator[GPUDriver::kResourceBufferCount]; + ID3D12CommandAllocator* Allocator; }; struct D3D12CopyCommandListData : D3D12CommandListBaseData @@ -70,8 +71,17 @@ namespace Juliet::D3D12 bool NeedVertexUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; bool NeedFragmentUniformBufferBind[GPUDriver::kMaxUniformBuffersPerStage]; - //D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; - //D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + // D3D12UniformBuffer *vertexUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + // D3D12UniformBuffer *fragmentUniformBuffers[GPUDriver::kMaxUniformBuffersPerStage]; + + // Resource Tracking + D3D12Texture** UsedTextures; + uint32 UsedTextureCount; + uint32 UsedTextureCapacity; + + D3D12GraphicsPipeline** UsedGraphicsPipelines; + uint32 UsedGraphicsPipelineCount; + uint32 UsedGraphicsPipelineCapacity; }; extern CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType); @@ -85,5 +95,8 @@ namespace Juliet::D3D12 { 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/D3D12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp index 268b9e9..2d893f8 100644 --- a/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12GraphicsDevice.cpp @@ -310,6 +310,7 @@ namespace Juliet::D3D12 // Clean allocations SafeFree(driver->AvailableCommandLists); SafeFree(driver->SubmittedCommandLists); + SafeFree(driver->GraphicsPipelinesToDispose); // Free(driver->WindowData); // TODO Should free the vector of WindowData, but we have only one for now SafeFree(driver->AvailableFences); @@ -709,6 +710,20 @@ namespace Juliet::D3D12 } } + // 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) { @@ -717,36 +732,35 @@ namespace Juliet::D3D12 } // Assign Functions to the device - device->DestroyDevice = DestroyGraphicsDevice; - device->AttachToWindow = AttachToWindow; - device->DetachFromWindow = DetachFromWindow; - device->AcquireSwapChainTexture = AcquireSwapChainTexture; - 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->Wait = Wait; - device->QueryFence = QueryFence; - device->ReleaseFence = ReleaseFence; - device->CreateShader = CreateShader; - device->DestroyShader = DestroyShader; - device->CreateGraphicsPipeline = CreateGraphicsPipeline; - device->DestroyGraphicsPipeline = DestroyGraphicsPipeline; + 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->Wait = Wait; + device->QueryFence = QueryFence; + device->ReleaseFence = ReleaseFence; + device->CreateShader = CreateShader; + device->DestroyShader = DestroyShader; + device->CreateGraphicsPipeline = CreateGraphicsPipeline; + device->DestroyGraphicsPipeline = DestroyGraphicsPipeline; + + device->Driver = driver; + device->DebugEnabled = enableDebug; - device->Driver = driver; driver->GraphicsDevice = device; - driver->Semantic = WrapString("TEXCOORD"); - - driver->FramesInFlight = 2; - return device; } } // namespace @@ -758,7 +772,7 @@ namespace Juliet::D3D12 // TODO Destroy anything (buffer, texture, etc...) for (int32 idx = driver->GraphicsPipelinesToDisposeCount - 1; idx >= 0; --idx) { - if ((--(driver->GraphicsPipelinesToDispose[idx]->ReferenceCount)) == 0) + if (driver->GraphicsPipelinesToDispose[idx]->ReferenceCount == 0) { ReleaseGraphicsPipeline(driver->GraphicsPipelinesToDispose[idx]); diff --git a/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp index 450b726..26bc840 100644 --- a/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12RenderPass.cpp @@ -70,7 +70,7 @@ namespace Juliet::D3D12 RTVs[idx] = rtv; d3d12CommandList->ColorTargetSubresources[idx] = subresource; - // TODO: TrackTexture + Internal::TrackTexture(d3d12CommandList, subresource->Parent); if (colorTargetInfos[idx].StoreOperation == StoreOperation::Resolve || colorTargetInfos[idx].StoreOperation == StoreOperation::ResolveAndStore) @@ -85,7 +85,7 @@ namespace Juliet::D3D12 d3d12CommandList->ColorResolveSubresources[idx] = resolveSubresource; - // TODO: TrackTexture Resolve + Internal::TrackTexture(d3d12CommandList, resolveSubresource->Parent); } } @@ -233,6 +233,8 @@ namespace Juliet::D3D12 // d3d12CommandList->FragmentUniformBuffers[i] = D3D12_INTERNAL_AcquireUniformBufferFromPool(d3d12CommandBuffer); // } } + + Internal::TrackGraphicsPipeline(d3d12CommandList, pipeline); } void DrawPrimitives(NonNullPtr commandList, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance) diff --git a/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp b/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp index 84a168a..2c9a1af 100644 --- a/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12SwapChain.cpp @@ -10,6 +10,7 @@ #include #include +#include namespace Juliet::D3D12 { @@ -56,7 +57,7 @@ namespace Juliet::D3D12 return false; } - texture->RefCount += 1; + texture->ReferenceCount += 1; texture->SubresourceCount = 1; texture->Subresources = static_cast(Calloc(1, sizeof(D3D12TextureSubresource))); if (!texture->Subresources) @@ -145,8 +146,30 @@ namespace Juliet::D3D12 auto* windowData = driver->WindowData; Assert(windowData->Window == window.Get()); - // TODO : FENCES - Assert(!block); + 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)) + { + 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]); + windowData->InFlightFences[windowData->WindowFrameCounter] = nullptr; + } uint32 swapchainIndex = IDXGISwapChain3_GetCurrentBackBufferIndex(windowData->SwapChain); HRESULT result = @@ -192,6 +215,32 @@ namespace Juliet::D3D12 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)) + { + return false; + } + } + + return true; + } + TextureFormat GetSwapChainTextureFormat(NonNullPtr driver, NonNullPtr window) { auto* d3d12Driver = static_cast(driver.Get()); diff --git a/Juliet/src/Graphics/D3D12/D3D12SwapChain.h b/Juliet/src/Graphics/D3D12/D3D12SwapChain.h index c9f95e4..5c5da43 100644 --- a/Juliet/src/Graphics/D3D12/D3D12SwapChain.h +++ b/Juliet/src/Graphics/D3D12/D3D12SwapChain.h @@ -8,7 +8,9 @@ namespace Juliet::D3D12 struct D3D12WindowData; extern bool AcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); -extern TextureFormat GetSwapChainTextureFormat(NonNullPtr driver, NonNullPtr window); + 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 { diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp index e10b389..345e8cf 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.cpp @@ -61,7 +61,7 @@ namespace Juliet::D3D12 bool result = true; // Clean up - for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; idx -= 1) + for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx) { result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); } @@ -71,8 +71,54 @@ namespace Juliet::D3D12 return result; } + bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, uint32 numFences) + { + auto d3d12driver = static_cast(driver.Get()); + + // TODO: use scratch allocator for alloca (stack alloc) + auto events = static_cast(alloca(sizeof(HANDLE) * numFences)); + + for (uint32 i = 0; i < numFences; ++i) + { + auto fence = reinterpret_cast(fences[i]); + + HRESULT res = ID3D12Fence_SetEventOnCompletion(fence->Handle, D3D12_FENCE_SIGNAL_VALUE, fence->Event); + if (FAILED(res)) + { + LogError(d3d12driver, "Setting fence event failed!", res); + return false; + } + + events[i] = fence->Event; + } + + DWORD waitResult = WaitForMultipleObjects(numFences, events, waitForAll, INFINITE); + if (waitResult == WAIT_FAILED) + { + LogError(LogCategory::Graphics, "Wait failed"); + return false; + } + + bool result = true; + + // Clean up + for (int32 idx = d3d12driver->SubmittedCommandListCount - 1; idx >= 0; --idx -= 1) + { + uint64 fenceValue = ID3D12Fence_GetCompletedValue(d3d12driver->SubmittedCommandLists[idx]->InFlightFence->Handle); + if (fenceValue == D3D12_FENCE_SIGNAL_VALUE) + { + result &= Internal::CleanCommandList(d3d12driver, d3d12driver->SubmittedCommandLists[idx], false); + } + } + + Internal::DisposePendingResourcces(d3d12driver); + + return result; + } + bool QueryFence(NonNullPtr driver, NonNullPtr fence) { + Unimplemented(); return true; } diff --git a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h index 443734b..ab23f61 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Synchronization.h +++ b/Juliet/src/Graphics/D3D12/D3D12Synchronization.h @@ -26,6 +26,7 @@ namespace Juliet::D3D12 }; extern bool Wait(NonNullPtr driver); + extern bool Wait(NonNullPtr driver, bool waitForAll, Fence* const* fences, uint32 numFences); extern bool QueryFence(NonNullPtr driver, NonNullPtr fence); extern void ReleaseFence(NonNullPtr driver, NonNullPtr fence); diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp index 1fcc016..1f228ff 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Texture.cpp +++ b/Juliet/src/Graphics/D3D12/D3D12Texture.cpp @@ -276,7 +276,7 @@ namespace Juliet::D3D12 D3D12_RESOURCE_STATES newTextureUsage) { D3D12TextureSubresource* subresource = Internal::FetchTextureSubresource(container, layer, level); - if (shouldCycle and container->CanBeCycled and subresource->Parent->RefCount > 0) + 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); diff --git a/Juliet/src/Graphics/D3D12/D3D12Texture.h b/Juliet/src/Graphics/D3D12/D3D12Texture.h index f936163..2da1673 100644 --- a/Juliet/src/Graphics/D3D12/D3D12Texture.h +++ b/Juliet/src/Graphics/D3D12/D3D12Texture.h @@ -59,7 +59,7 @@ namespace Juliet::D3D12 D3D12StagingDescriptor SRVHandle; // TODO: Should be atomic to support multithreading - int32 RefCount; + int32 ReferenceCount; }; namespace Internal diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp index 2ef00b4..8d439e2 100644 --- a/Juliet/src/Graphics/Graphics.cpp +++ b/Juliet/src/Graphics/Graphics.cpp @@ -79,6 +79,27 @@ namespace Juliet { auto header = reinterpret_cast(commandList.Get()); + if (header->Device->DebugEnabled) + { + bool error = false; + if (header->Submitted) + { + error = true; + Assert(false && "Cannot submit command list twice"); + } + + if (header->RenderPass.IsInProgress) + { + error = true; + Assert(false && "Cannot submit command list twice"); + } + + if (error) + { + return false; + } + } + header->Device->AcquireSwapChainTexture(commandList, window, swapChainTexture); if (swapChainTexture) { @@ -88,6 +109,45 @@ namespace Juliet return true; } + bool WaitAndAcquireSwapChainTexture(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture) + { + auto header = reinterpret_cast(commandList.Get()); + + if (header->Device->DebugEnabled) + { + bool error = false; + if (header->Submitted) + { + error = true; + Assert(false && "Cannot submit command list twice"); + } + + if (header->RenderPass.IsInProgress) + { + error = true; + Assert(false && "Cannot submit command list twice"); + } + + if (error) + { + return false; + } + } + + header->Device->WaitAndAcquireSwapChainTexture(commandList, window, swapChainTexture); + if (swapChainTexture) + { + header->AcquiredSwapChain = true; + } + + return true; + } + + bool WaitForSwapchain(NonNullPtr device, NonNullPtr window) + { + return device->WaitForSwapchain(device->Driver, window); + } + TextureFormat GetSwapChainTextureFormat(NonNullPtr device, NonNullPtr window) { return device->GetSwapChainTextureFormat(device->Driver, window); @@ -105,6 +165,7 @@ namespace Juliet auto header = reinterpret_cast(cmdList); header->Device = device.Get(); header->RenderPass.CommandList = cmdList; + header->Submitted = false; return cmdList; } @@ -181,7 +242,7 @@ namespace Juliet commandListHeader->Device->SetStencilReference(commandList, reference); } - void BindGraphicsPipeline(NonNullPtr renderPass, NonNullPtr graphicsPipeline) + void BindGraphicsPipeline(NonNullPtr renderPass, NonNullPtr graphicsPipeline) { auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; auto* commandListHeader = reinterpret_cast(commandList); @@ -189,8 +250,7 @@ namespace Juliet commandListHeader->Device->BindGraphicsPipeline(commandList, graphicsPipeline); } - void DrawPrimitives(NonNullPtr renderPass, uint32 numVertices, uint32 numInstances, - uint32 firstVertex, uint32 firstInstance) + void DrawPrimitives(NonNullPtr renderPass, uint32 numVertices, uint32 numInstances, uint32 firstVertex, uint32 firstInstance) { auto* commandList = reinterpret_cast(renderPass.Get())->CommandList; auto* commandListHeader = reinterpret_cast(commandList); diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h index e1b08fe..abed932 100644 --- a/Juliet/src/Graphics/GraphicsDevice.h +++ b/Juliet/src/Graphics/GraphicsDevice.h @@ -30,7 +30,6 @@ namespace Juliet struct GPUDriver { - static constexpr uint8 kResourceBufferCount = 2; static constexpr uint8 kMaxFramesInFlight = 3; static constexpr uint8 kMaxColorTargetInfo = 4; static constexpr uint8 kMaxUniformBuffersPerStage = 4; @@ -47,6 +46,8 @@ namespace Juliet // SwapChain bool (*AcquireSwapChainTexture)(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); + bool (*WaitAndAcquireSwapChainTexture)(NonNullPtr commandList, NonNullPtr window, Texture** swapChainTexture); + bool (*WaitForSwapchain)(NonNullPtr driver, NonNullPtr window); TextureFormat (*GetSwapChainTextureFormat)(NonNullPtr driver, NonNullPtr window); // CommandLists @@ -82,6 +83,7 @@ namespace Juliet const char* Name = "Unknown"; GPUDriver* Driver = nullptr; + bool DebugEnabled : 1; }; struct GraphicsDeviceFactory diff --git a/JulietApp/main.cpp b/JulietApp/main.cpp index 0b75973..0086a4c 100644 --- a/JulietApp/main.cpp +++ b/JulietApp/main.cpp @@ -188,7 +188,7 @@ void JulietApplication::Update() } Texture* swapChainTexture = nullptr; - if (!AcquireSwapChainTexture(cmdList, MainWindow, &swapChainTexture)) + if (!WaitAndAcquireSwapChainTexture(cmdList, MainWindow, &swapChainTexture)) { Log(LogLevel::Error, LogCategory::Tool, "Failed to acquire swapchain texture."); Running = false;