From 169822c2216efcd89ad27d72df8ddc9a06828338 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Thu, 15 Sep 2022 09:16:13 +0800 Subject: [PATCH] Render graph execution fixed GetVkQueue function deleted. More specific function implemented (Present). --- .../src/Application/SBApplication.cpp | 1 + .../Graphics/Commands/SHVkCommandBuffer.cpp | 22 +++++- .../src/Graphics/Commands/SHVkCommandBuffer.h | 2 + .../src/Graphics/Commands/SHVkCommandPool.cpp | 15 ++-- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 26 ++++--- .../MiddleEnd/Interface/SHGraphicsSystem.h | 4 +- .../src/Graphics/Queues/SHVkQueue.cpp | 73 +++++++++++++++---- SHADE_Engine/src/Graphics/Queues/SHVkQueue.h | 5 +- .../Graphics/RenderGraph/SHRenderGraph.cpp | 23 ++++-- .../src/Graphics/RenderGraph/SHRenderGraph.h | 3 +- 10 files changed, 127 insertions(+), 47 deletions(-) diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index a30237dc..c47b8016 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -48,6 +48,7 @@ namespace Sandbox //SHADE::SHEditor::PreRender(); //#endif graphicsSystem->BeginRender(); + graphicsSystem->Run(1.0f); //#ifdef SHEDITOR //SHADE::SHEditor::PreRender(); //SHADE::SHEditor::Update(); diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp index 5b2d15fe..f83087dd 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.cpp @@ -76,7 +76,10 @@ namespace SHADE // Check if command buffer is ready to record. if (cmdBufferState != SH_CMD_BUFFER_STATE::INITIAL) { - SHLOG_ERROR("Command buffer not in initial state, cannot begin recording. "); + SHLOG_ERROR("Command buffer not in initial state, cannot begin recording. Command buffer could be: \n" + "- corrupted and in invalid state\n" + "- in executable state\n" + "- in pending state\n"); return; } @@ -182,7 +185,9 @@ namespace SHADE // Check if render area is optimal if (!IsRenderAreaOptimal(renderpassHdl, framebufferExtent, renderPassInfo.renderArea)) + { SHLOG_ERROR("Render area in renderpass begin info is not optimal. See Vulkan vkGetRenderAreaGranularity for details."); + } // Begin the render pass vkCommandBuffer.beginRenderPass (&renderPassInfo, vk::SubpassContents::eInline); @@ -431,6 +436,16 @@ namespace SHADE ); } + bool SHVkCommandBuffer::IsReadyToSubmit(void) const noexcept + { + return cmdBufferState == SH_CMD_BUFFER_STATE::EXECUTABLE; + } + + void SHVkCommandBuffer::HandlePostSubmit(void) noexcept + { + SetState(SH_CMD_BUFFER_STATE::PENDING); + } + //void SHVkCommandBuffer::PipelineBarrier(vk::PipelineStageFlags ) const noexcept //{ // //vkCommandBuffer.pipelineBarrier() @@ -493,9 +508,7 @@ namespace SHADE { vk::Extent2D granularity = parentPool->GetLogicalDevice()->GetVkLogicalDevice().getRenderAreaGranularity(renderpassHdl->GetVkRenderpass()); - return (renderArea.offset.x % granularity.width == 0 && renderArea.offset.y % granularity.height == 0 && - (renderArea.extent.width % granularity.width || renderArea.offset.x + renderArea.extent.width == framebufferExtent.width) && - (renderArea.extent.height % granularity.height || renderArea.offset.y + renderArea.extent.height == framebufferExtent.height)); + return (renderArea.offset.x % granularity.width == 0 && renderArea.offset.y % granularity.height == 0 && (renderArea.extent.width % granularity.width || renderArea.offset.x + renderArea.extent.width == framebufferExtent.width) && (renderArea.extent.height % granularity.height || renderArea.offset.y + renderArea.extent.height == framebufferExtent.height)); } /***************************************************************************/ @@ -559,6 +572,7 @@ namespace SHADE , usageFlags{} , commandBufferCount{ 0 } , parentPool{commandPool} + , pushConstantData{} { vk::CommandBufferAllocateInfo allocateInfo{}; diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h index d2171c25..948092bf 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandBuffer.h @@ -125,6 +125,8 @@ namespace SHADE std::vector const& imageMemoryBarriers ) const noexcept; + bool IsReadyToSubmit (void) const noexcept; + void HandlePostSubmit (void) noexcept; // Push Constant variable setting template diff --git a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp index 5cf4bea4..881ee998 100644 --- a/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp +++ b/SHADE_Engine/src/Graphics/Commands/SHVkCommandPool.cpp @@ -150,20 +150,19 @@ namespace SHADE logicalDeviceHdl->GetVkLogicalDevice().resetCommandPool(vkCommandPool, vk::CommandPoolResetFlagBits::eReleaseResources); for (auto& primary : primaries) { - if (primary->GetState() != SH_CMD_BUFFER_STATE::PENDING) - primary->SetState(SH_CMD_BUFFER_STATE::INITIAL); - else - SHLOG_ERROR("Primary command buffer in pending state, could not reset. "); + // #NoteToSelf: Since there is no way to set the state of a command buffer back to initial, we just hard set it to initial. Ditto for secondaries. + //if (primary->GetState() != SH_CMD_BUFFER_STATE::PENDING) + primary->SetState(SH_CMD_BUFFER_STATE::INITIAL); + + // From the spec: Any primary command buffer allocated from another VkCommandPool that is in the recording or // executable state and has a secondary command buffer allocated from commandPool recorded into it, // becomes invalid. TODO: Might want to check and throw exception for these conditions after making sure this actually happens using validation layers. } for (auto& secondary : secondaries) { - if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING) - secondary->SetState(SH_CMD_BUFFER_STATE::INITIAL); - else - SHLOG_ERROR("Secondary command buffer in pending state, could not reset. "); + //if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING) + secondary->SetState(SH_CMD_BUFFER_STATE::INITIAL); // TODO: Ditto from TODO in primary check } diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 4d4ca4f4..63fd7466 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -54,7 +54,7 @@ namespace SHADE }); // Create graphics queue - queue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0); + graphicsQueue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0); // Create Render Context @@ -101,7 +101,7 @@ namespace SHADE auto node = renderGraph.AddNode("G-Buffer", { "Position", "Normals", "Composite" }, {}); // no predecessors // First subpass to write to G-Buffer - auto writeSubpass = node->AddSubpass("G-Buffer Write"); + auto writeSubpass = node->AddSubpass("G-Buffer Write"); writeSubpass->AddColorOutput("Position"); writeSubpass->AddColorOutput("Normals"); @@ -111,11 +111,11 @@ namespace SHADE compositeSubpass->AddInput("Normals"); compositeSubpass->AddInput("Position"); - auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present"}, {"G-Buffer"}); - auto bloomSubpass = compositeNode->AddSubpass("Downsample"); - bloomSubpass->AddInput("Composite"); - bloomSubpass->AddColorOutput("Downscale"); - bloomSubpass->AddColorOutput("Present"); + //auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present"}, {"G-Buffer"}); + //auto bloomSubpass = compositeNode->AddSubpass("Downsample"); + //bloomSubpass->AddInput("Composite"); + // bloomSubpass->AddColorOutput("Downscale"); + // bloomSubpass->AddColorOutput("Present"); renderGraph.Generate(); @@ -127,6 +127,14 @@ namespace SHADE void SHGraphicsSystem::Run(float dt) { + auto const& frameData = renderContext.GetCurrentFrameData(); + + renderGraph.Execute(renderContext.GetCurrentFrame()); + + graphicsQueue->SubmitCommandBuffer({ renderGraph.GetCommandBuffer(renderContext.GetCurrentFrame()) }, + { frameData.semRenderFinishHdl }, + { frameData.semImgAvailableHdl }, + vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests); } @@ -134,7 +142,7 @@ namespace SHADE { //renderPass.Free(); renderContext.Destroy(); - queue.Free(); + graphicsQueue.Free(); swapchain.Free(); surface.Free(); device.Free(); @@ -208,7 +216,7 @@ namespace SHADE presentInfo.pImageIndices = &CURR_FRAME_IDX; // #BackEndTest: queues an image for presentation - if (auto result = device->GetQueue(SH_Q_FAM::GRAPHICS, 0)->GetVkQueue().presentKHR(&presentInfo); result != vk::Result::eSuccess) + if (auto result = graphicsQueue->Present(swapchain, {currFrameData.semRenderFinishHdl}, CURR_FRAME_IDX); result != vk::Result::eSuccess) { // If swapchain is incompatible/outdated if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR) diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 27d03fd3..8c803e1d 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -114,7 +114,7 @@ namespace SHADE Handle GetSwapchain() const { return swapchain; } Handle GetSurface() const { return surface; } Handle GetPhysicalDevice() const {return physicalDevice;} - Handle GetQueue() const { return queue; } + Handle GetQueue() const { return graphicsQueue; } Handle GetDescriptorPool() const { return descPool; } SHRenderGraph const& GetRenderGraph (void) const noexcept; @@ -130,7 +130,7 @@ namespace SHADE Handle device; Handle surface; Handle swapchain; - Handle queue; + Handle graphicsQueue; Handle descPool; //Handle renderPass; // Potentially bring out? std::vector screenSegments; diff --git a/SHADE_Engine/src/Graphics/Queues/SHVkQueue.cpp b/SHADE_Engine/src/Graphics/Queues/SHVkQueue.cpp index 9f8c529c..6ed6def6 100644 --- a/SHADE_Engine/src/Graphics/Queues/SHVkQueue.cpp +++ b/SHADE_Engine/src/Graphics/Queues/SHVkQueue.cpp @@ -5,6 +5,7 @@ #include "Graphics/Synchronization/SHVkSemaphore.h" #include "Graphics/Synchronization/SHVkFence.h" #include "Graphics/Commands/SHVkCommandBuffer.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" namespace SHADE @@ -31,14 +32,10 @@ namespace SHADE } - vk::Queue SHVkQueue::GetVkQueue(void) const noexcept + void SHVkQueue::SubmitCommandBuffer(std::initializer_list> cmdBuffers, std::initializer_list> signalSems /*= {}*/, std::initializer_list> waitSems /*= {}*/, vk::PipelineStageFlags waitDstStageMask /*= {}*/, Handle const& optionalFence /*= {}*/) noexcept { - return vkQueue; - } - - void SHVkQueue::SubmitCommandBuffer(std::initializer_list> cmdBuffers, std::initializer_list> signalSems /*= {}*/, std::initializer_list> waitSems /*= {}*/, vk::PipelineStageFlagBits waitDstStageMask /*= {}*/, Handle const& optionalFence /*= {}*/) noexcept - { - std::vector vkWaitSems{ waitSems.size() }; + // prepare wait sems + std::array vkWaitSems{ }; uint32_t i = 0; for (auto& sem : waitSems) { @@ -46,7 +43,8 @@ namespace SHADE ++i; } - std::vector vkSignalSems{ signalSems.size() }; + // prepare signal sems + std::array vkSignalSems{ }; i = 0; for (auto& sem : signalSems) { @@ -54,33 +52,76 @@ namespace SHADE ++i; } - std::vector vkCmdBuffers{ cmdBuffers.size() }; + // prepare cmd buffers + std::array vkCmdBuffers{ }; i = 0; for (auto& cmdBuffer : cmdBuffers) { + // Check if command buffer is in executable state + if (!cmdBuffer->IsReadyToSubmit()) + { + SHLOG_ERROR("Command buffer is not in executable state. Cannot submit command buffer. "); + return; + } + vkCmdBuffers[i] = cmdBuffer->GetVkCommandBuffer(); ++i; } - vk::PipelineStageFlags mask = waitDstStageMask; - + // Prepare submit info vk::SubmitInfo submitInfo { - .waitSemaphoreCount = static_cast(vkWaitSems.size()), + .waitSemaphoreCount = static_cast(waitSems.size()), .pWaitSemaphores = vkWaitSems.data(), - .pWaitDstStageMask = &mask, - .commandBufferCount = static_cast(vkCmdBuffers.size()), + .pWaitDstStageMask = &waitDstStageMask, + .commandBufferCount = static_cast(cmdBuffers.size()), .pCommandBuffers = vkCmdBuffers.data(), - .signalSemaphoreCount = static_cast(vkSignalSems.size()), + .signalSemaphoreCount = static_cast(signalSems.size()), .pSignalSemaphores = vkSignalSems.data(), }; - // #BackEndTest: Submit the queue + // Submit the queue if (auto result = vkQueue.submit(1, &submitInfo, (optionalFence) ? optionalFence->GetVkFence() : nullptr); result != vk::Result::eSuccess) { SHVulkanDebugUtil::ReportVkError(result, "Failed to submit command buffer. "); } + else // if success + { + // Change all command buffers to pending state + for (Handle cmdBuffer : cmdBuffers) + { + cmdBuffer->HandlePostSubmit(); + } + } + } + vk::Result SHVkQueue::Present(Handle const& swapchain, std::initializer_list> waitSems, uint32_t frameIndex) noexcept + { + vk::PresentInfoKHR presentInfo{}; + + // prepare wait sems + std::array vkWaitSems{ }; + uint32_t i = 0; + for (auto& sem : waitSems) + { + vkWaitSems[i] = sem->GetVkSem(); + ++i; + } + + // prepare presentation information + presentInfo.waitSemaphoreCount = static_cast(waitSems.size()); + presentInfo.pWaitSemaphores = vkWaitSems.data(); + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapchain->GetVkSwapchain(); + presentInfo.pImageIndices = &frameIndex; + + // Present swapchain image. + auto result = vkQueue.presentKHR(&presentInfo); + if (result != vk::Result::eSuccess) + { + SHLOGV_ERROR ("Failed to present swapchain image. "); + } + return result; } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h b/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h index 203ae59e..042bc4bb 100644 --- a/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h +++ b/SHADE_Engine/src/Graphics/Queues/SHVkQueue.h @@ -11,6 +11,7 @@ namespace SHADE class SHVkCommandBuffer; class SHVkFence; class SHVkSemaphore; + class SHVkSwapchain; enum class SH_QUEUE_FAMILY_ARRAY_INDEX : std::size_t { @@ -45,9 +46,9 @@ namespace SHADE public: SHVkQueue(vk::Queue inVkQueue, SHQueueFamilyIndex parent, Handle const& inLogicalDeviceHdl) noexcept; - vk::Queue GetVkQueue(void) const noexcept; - void SubmitCommandBuffer(std::initializer_list> cmdBuffers, std::initializer_list> signalSems = {}, std::initializer_list> waitSems = {}, vk::PipelineStageFlagBits waitDstStageMask = {}, Handle const& fence = {}) noexcept; + void SubmitCommandBuffer (std::initializer_list> cmdBuffers, std::initializer_list> signalSems = {}, std::initializer_list> waitSems = {}, vk::PipelineStageFlags waitDstStageMask = {}, Handle const& fence = {}) noexcept; + vk::Result Present (Handle const& swapchain, std::initializer_list> waitSems, uint32_t frameIndex) noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 71bac1e6..76106d67 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -552,14 +552,16 @@ namespace SHADE void SHRenderGraphNode::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept { + frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); - for (auto& subpass : subpasses) + for (uint32_t i = 0; i < subpasses.size(); ++i) { - subpass->Execute(commandBuffer); + subpasses[i]->Execute(commandBuffer); - // Go to next subpass - commandBuffer->NextSubpass(); + // Go to next subpass if not last subpass + if (i != subpasses.size() - 1) + commandBuffer->NextSubpass(); } commandBuffer->EndRenderpass(); @@ -892,6 +894,10 @@ namespace SHADE { commandPool = logicalDeviceHdl->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); commandBuffers.resize(static_cast(swapchainHdl->GetNumImages())); + for (auto& cmdBuffer : commandBuffers) + { + cmdBuffer = commandPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY); + } } /***************************************************************************/ @@ -1019,6 +1025,8 @@ namespace SHADE void SHRenderGraph::Execute(uint32_t frameIndex) noexcept { + commandPool->Reset(); + auto& cmdBuffer = commandBuffers[frameIndex]; cmdBuffer->BeginRecording(); @@ -1027,7 +1035,7 @@ namespace SHADE node->Execute(commandBuffers[frameIndex], frameIndex); } - cmdBuffer->EndRenderpass(); + cmdBuffer->EndRecording(); } Handle SHRenderGraph::GetNode(std::string const& nodeName) const noexcept @@ -1038,4 +1046,9 @@ namespace SHADE return {}; } + Handle const& SHRenderGraph::GetCommandBuffer(uint32_t frameIndex) const noexcept + { + return commandBuffers[frameIndex]; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index ea913baa..91f3f2ca 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -275,7 +275,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - Handle GetNode (std::string const& nodeName) const noexcept; + Handle GetNode (std::string const& nodeName) const noexcept; + Handle const& GetCommandBuffer (uint32_t frameIndex) const noexcept; }; }