diff --git a/Juliet/include/Graphics/Graphics.h b/Juliet/include/Graphics/Graphics.h index b3d121c..2f48680 100644 --- a/Juliet/include/Graphics/Graphics.h +++ b/Juliet/include/Graphics/Graphics.h @@ -13,6 +13,7 @@ namespace Juliet // Opaque types struct CommandList; struct GraphicsDevice; + struct Fence; // Parameters of an indirect draw command struct IndirectDrawCommand @@ -91,7 +92,7 @@ namespace Juliet // Command List extern JULIET_API CommandList* AcquireCommandList(NonNullPtr device, QueueType queueType = QueueType::Graphics); - extern JULIET_API void SubmitCommandLists(NonNullPtr device); + extern JULIET_API void SubmitCommandLists(NonNullPtr commandList); // RenderPass extern JULIET_API RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo); diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp index dfd389b..ce59400 100644 --- a/Juliet/src/Graphics/D3D12/DX12CommandList.cpp +++ b/Juliet/src/Graphics/D3D12/DX12CommandList.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace Juliet::D3D12 { @@ -194,21 +195,116 @@ namespace Juliet::D3D12 return reinterpret_cast(commandList); } - bool SubmitCommandLists(NonNullPtr driver) + bool SubmitCommandLists(NonNullPtr commandList) { - auto* d3d12Driver = static_cast(driver.Get()); - bool success = true; + auto* d3d12CommandList = reinterpret_cast(commandList.Get()); + auto* d3d12Driver = d3d12CommandList->Driver; + // TODO : Use QueueType to choose the correct CommandList and Command Queue + // Only use graphics for now - uint8 commandLastIndex = d3d12Driver->AvailableCommandListCount; - - // TODO : Get window data from the command list: We associate the swapchain texture to a window with a missing function - HRESULT result = IDXGISwapChain_Present(d3d12Driver->WindowData->SwapChain, 0, 1); - if (FAILED(result)) + // Transition present textures to present mode + for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) { - success = false; + uint32 swapchainIndex = d3d12CommandList->PresentDatas[i].SwapChainImageIndex; + D3D12TextureContainer* container = + &d3d12CommandList->PresentDatas[i].WindowData->SwapChainTextureContainers[swapchainIndex]; + D3D12TextureSubresource* subresource = FetchTextureSubresource(container, 0, 0); + + D3D12_RESOURCE_BARRIER barrierDesc; + barrierDesc.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrierDesc.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; + barrierDesc.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; + barrierDesc.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + barrierDesc.Transition.pResource = subresource->Parent->Resource; + barrierDesc.Transition.Subresource = subresource->Index; + + ID3D12GraphicsCommandList_ResourceBarrier(d3d12CommandList->GraphicsCommandList.CommandList, 1, &barrierDesc); } + // Notify the command buffer that we have completed recording + HRESULT result = ID3D12GraphicsCommandList_Close(d3d12CommandList->GraphicsCommandList.CommandList); + if (FAILED(result)) + { + LogError(d3d12Driver, "Failed to close command list!", result); + return false; + } + + ID3D12CommandList* commandLists[1]; + result = ID3D12GraphicsCommandList_QueryInterface(d3d12CommandList->GraphicsCommandList.CommandList, + IID_ID3D12CommandList, reinterpret_cast(&commandLists[0])); + if (FAILED(result)) + { + LogError(d3d12Driver, "Failed to convert command list!", result); + return false; + } + + // Submit the command list to the queue + ID3D12CommandQueue_ExecuteCommandLists(d3d12Driver->GraphicsQueue, 1, commandLists); + + ID3D12CommandList_Release(commandLists[0]); + + // TODO Fences + + // Mark the command list as submitted + if (d3d12Driver->SubmittedCommandBufferCount + 1 >= d3d12Driver->SubmittedCommandListCapacity) { + d3d12Driver->SubmittedCommandListCapacity = d3d12Driver->SubmittedCommandBufferCount + 1; + + d3d12Driver->SubmittedCommandLists = static_cast( + Realloc(d3d12Driver->SubmittedCommandLists, sizeof(D3D12CommandList*) * d3d12Driver->SubmittedCommandListCapacity)); + } + + d3d12Driver->SubmittedCommandLists[d3d12Driver->SubmittedCommandBufferCount] = d3d12CommandList; + d3d12Driver->SubmittedCommandBufferCount += 1; + + bool success = true; + for (uint32 i = 0; i < d3d12CommandList->PresentDataCount; i += 1) + { + D3D12PresentData* presentData = &d3d12CommandList->PresentDatas[i]; + auto* windowData = presentData->WindowData; + + // NOTE: flip discard always supported since DXGI 1.4 is required + uint32 syncInterval = 1; + if (windowData->PresentMode == PresentMode::Immediate || windowData->PresentMode == PresentMode::Mailbox) + { + syncInterval = 0; + } + + uint32 presentFlags = 0; + if (d3d12Driver->IsTearingSupported && windowData->PresentMode == PresentMode::Immediate) + { + presentFlags = DXGI_PRESENT_ALLOW_TEARING; + } + + result = IDXGISwapChain_Present(windowData->SwapChain, syncInterval, presentFlags); + if (FAILED(result)) + { + result = false; + } + + ID3D12Resource_Release(windowData->SwapChainTextureContainers[presentData->SwapChainImageIndex].ActiveTexture->Resource); + + //windowData->inFlightFences[windowData->frameCounter] = (SDL_GPUFence*)d3d12CommandBuffer->inFlightFence; + //(void)SDL_AtomicIncRef(&d3d12CommandBuffer->inFlightFence->referenceCount); + windowData->WindowFrameCounter = (windowData->WindowFrameCounter + 1) % d3d12Driver->FramesInFlight; + } + + // 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); + // } + // } + + // TODO Destroy anything (buffer, texture, etc...) + ++d3d12Driver->FrameCounter; return success; diff --git a/Juliet/src/Graphics/D3D12/DX12CommandList.h b/Juliet/src/Graphics/D3D12/DX12CommandList.h index 97609a3..ca1b1c3 100644 --- a/Juliet/src/Graphics/D3D12/DX12CommandList.h +++ b/Juliet/src/Graphics/D3D12/DX12CommandList.h @@ -53,7 +53,7 @@ namespace Juliet::D3D12 }; extern CommandList* AcquireCommandList(NonNullPtr driver, QueueType queueType); - extern bool SubmitCommandLists(NonNullPtr driver); + extern bool SubmitCommandLists(NonNullPtr commandList); extern void SetViewPort(NonNullPtr commandList, const GraphicsViewPort& viewPort); extern void SetScissorRect(NonNullPtr commandList, const Rectangle& rectangle); extern void SetBlendConstants(NonNullPtr commandList, FColor blendConstants); diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp index 42e8d85..182048f 100644 --- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp +++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.cpp @@ -518,15 +518,18 @@ namespace Juliet::D3D12 return nullptr; } - auto device = static_cast(Calloc(1, sizeof(GraphicsDevice))); - if (!device) + // Create Pools + driver->SubmittedCommandListCapacity = 4; + driver->SubmittedCommandBufferCount = 0; + driver->SubmittedCommandLists = + static_cast(Calloc(driver->SubmittedCommandListCapacity, sizeof(D3D12CommandList*))); + if (!driver->SubmittedCommandLists) { DestroyDriver_Internal(driver); return nullptr; } - // Create Pools - + // Staging descriptor pools for (uint32 i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; i += 1) { driver->StagingDescriptorPools[i] = @@ -535,10 +538,17 @@ namespace Juliet::D3D12 if (driver->StagingDescriptorPools[i] == nullptr) { DestroyDriver_Internal(driver); - return NULL; + return nullptr; } } + auto device = static_cast(Calloc(1, sizeof(GraphicsDevice))); + if (!device) + { + DestroyDriver_Internal(driver); + return nullptr; + } + // Assign Functions to the device device->DestroyDevice = DestroyGraphicsDevice; @@ -551,11 +561,11 @@ namespace Juliet::D3D12 device->SubmitCommandLists = SubmitCommandLists; device->BeginRenderPass = BeginRenderPass; - device->EndRenderPass = EndRenderPass; + device->EndRenderPass = EndRenderPass; - device->SetViewPort = SetViewPort; - device->SetScissorRect = SetScissorRect; - device->SetBlendConstants = SetBlendConstants; + device->SetViewPort = SetViewPort; + device->SetScissorRect = SetScissorRect; + device->SetBlendConstants = SetBlendConstants; device->SetStencilReference = SetStencilReference; device->Driver = driver; diff --git a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h index 8a2b3d2..20f4e89 100644 --- a/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h +++ b/Juliet/src/Graphics/D3D12/DX12GraphicsDevice.h @@ -27,6 +27,8 @@ namespace Juliet::D3D12 PresentMode PresentMode; + Fence* InFlightFences[GPUDriver::kMaxFramesInFlight]; + uint32 WindowFrameCounter; // Specific to that window. See GraphicsDevice for global counter uint32 Width; uint32 Height; @@ -66,9 +68,13 @@ namespace Juliet::D3D12 uint8 AvailableCommandListCapacity; uint8 AvailableCommandListCount; + D3D12CommandList** SubmittedCommandLists; + uint8 SubmittedCommandListCapacity; + uint8 SubmittedCommandBufferCount; + D3D12StagingDescriptorPool* StagingDescriptorPools[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES]; - uint8 FramesInFlight; + uint8 FramesInFlight; uint64 FrameCounter = 0; // Number of frame since inception bool IsTearingSupported : 1; diff --git a/Juliet/src/Graphics/Graphics.cpp b/Juliet/src/Graphics/Graphics.cpp index 9bd5b39..ad65e68 100644 --- a/Juliet/src/Graphics/Graphics.cpp +++ b/Juliet/src/Graphics/Graphics.cpp @@ -103,10 +103,13 @@ namespace Juliet return cmdList; } - void SubmitCommandLists(NonNullPtr device) + void SubmitCommandLists(NonNullPtr commandList) { - GPUDriver* driver = device->Driver; - device->SubmitCommandLists(driver); + auto* commandListHeader = reinterpret_cast(commandList.Get()); + + commandListHeader->Submitted = true; + + commandListHeader->Device->SubmitCommandLists(commandList); } RenderPass* BeginRenderPass(NonNullPtr commandList, ColorTargetInfo& colorTargetInfo) diff --git a/Juliet/src/Graphics/GraphicsDevice.h b/Juliet/src/Graphics/GraphicsDevice.h index 0475ec2..d80ceaf 100644 --- a/Juliet/src/Graphics/GraphicsDevice.h +++ b/Juliet/src/Graphics/GraphicsDevice.h @@ -22,6 +22,7 @@ namespace Juliet { GraphicsDevice* Device = nullptr; bool AcquiredSwapChain = false; + bool Submitted = false; GPUPass RenderPass; }; @@ -46,7 +47,7 @@ namespace Juliet // CommandLists CommandList* (*AcquireCommandList)(NonNullPtr driver, QueueType queueType); - bool (*SubmitCommandLists)(NonNullPtr driver); + bool (*SubmitCommandLists)(NonNullPtr commandList); // RenderPass void (*BeginRenderPass)(NonNullPtr commandList, NonNullPtr colorTargetInfos, diff --git a/JulietApp/Editor/EditorMain_win32.cpp b/JulietApp/Editor/EditorMain_win32.cpp index 024c760..6b5c458 100644 --- a/JulietApp/Editor/EditorMain_win32.cpp +++ b/JulietApp/Editor/EditorMain_win32.cpp @@ -111,7 +111,7 @@ void Win32EditorApplication::Update() } // Submit Commands - SubmitCommandLists(GraphicsDevice); + SubmitCommandLists(cmdList); } bool Win32EditorApplication::IsRunning()