Render graph execution fixed

GetVkQueue function deleted. More specific function implemented (Present).
This commit is contained in:
Brandon Mak 2022-09-15 09:16:13 +08:00
parent 44e529f06f
commit 169822c221
10 changed files with 127 additions and 47 deletions

View File

@ -48,6 +48,7 @@ namespace Sandbox
//SHADE::SHEditor::PreRender(); //SHADE::SHEditor::PreRender();
//#endif //#endif
graphicsSystem->BeginRender(); graphicsSystem->BeginRender();
graphicsSystem->Run(1.0f);
//#ifdef SHEDITOR //#ifdef SHEDITOR
//SHADE::SHEditor::PreRender(); //SHADE::SHEditor::PreRender();
//SHADE::SHEditor::Update(); //SHADE::SHEditor::Update();

View File

@ -76,7 +76,10 @@ namespace SHADE
// Check if command buffer is ready to record. // Check if command buffer is ready to record.
if (cmdBufferState != SH_CMD_BUFFER_STATE::INITIAL) 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; return;
} }
@ -182,7 +185,9 @@ namespace SHADE
// Check if render area is optimal // Check if render area is optimal
if (!IsRenderAreaOptimal(renderpassHdl, framebufferExtent, renderPassInfo.renderArea)) if (!IsRenderAreaOptimal(renderpassHdl, framebufferExtent, renderPassInfo.renderArea))
{
SHLOG_ERROR("Render area in renderpass begin info is not optimal. See Vulkan vkGetRenderAreaGranularity for details."); SHLOG_ERROR("Render area in renderpass begin info is not optimal. See Vulkan vkGetRenderAreaGranularity for details.");
}
// Begin the render pass // Begin the render pass
vkCommandBuffer.beginRenderPass (&renderPassInfo, vk::SubpassContents::eInline); 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 //void SHVkCommandBuffer::PipelineBarrier(vk::PipelineStageFlags ) const noexcept
//{ //{
// //vkCommandBuffer.pipelineBarrier() // //vkCommandBuffer.pipelineBarrier()
@ -493,9 +508,7 @@ namespace SHADE
{ {
vk::Extent2D granularity = parentPool->GetLogicalDevice()->GetVkLogicalDevice().getRenderAreaGranularity(renderpassHdl->GetVkRenderpass()); vk::Extent2D granularity = parentPool->GetLogicalDevice()->GetVkLogicalDevice().getRenderAreaGranularity(renderpassHdl->GetVkRenderpass());
return (renderArea.offset.x % granularity.width == 0 && renderArea.offset.y % granularity.height == 0 && 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));
(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{} , usageFlags{}
, commandBufferCount{ 0 } , commandBufferCount{ 0 }
, parentPool{commandPool} , parentPool{commandPool}
, pushConstantData{}
{ {
vk::CommandBufferAllocateInfo allocateInfo{}; vk::CommandBufferAllocateInfo allocateInfo{};

View File

@ -125,6 +125,8 @@ namespace SHADE
std::vector<vk::ImageMemoryBarrier> const& imageMemoryBarriers std::vector<vk::ImageMemoryBarrier> const& imageMemoryBarriers
) const noexcept; ) const noexcept;
bool IsReadyToSubmit (void) const noexcept;
void HandlePostSubmit (void) noexcept;
// Push Constant variable setting // Push Constant variable setting
template <typename T> template <typename T>

View File

@ -150,20 +150,19 @@ namespace SHADE
logicalDeviceHdl->GetVkLogicalDevice().resetCommandPool(vkCommandPool, vk::CommandPoolResetFlagBits::eReleaseResources); logicalDeviceHdl->GetVkLogicalDevice().resetCommandPool(vkCommandPool, vk::CommandPoolResetFlagBits::eReleaseResources);
for (auto& primary : primaries) for (auto& primary : primaries)
{ {
if (primary->GetState() != SH_CMD_BUFFER_STATE::PENDING) // #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); primary->SetState(SH_CMD_BUFFER_STATE::INITIAL);
else
SHLOG_ERROR("Primary command buffer in pending state, could not reset. ");
// From the spec: Any primary command buffer allocated from another VkCommandPool that is in the recording or // 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, // 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. // 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) for (auto& secondary : secondaries)
{ {
if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING) //if (secondary->GetState() != SH_CMD_BUFFER_STATE::PENDING)
secondary->SetState(SH_CMD_BUFFER_STATE::INITIAL); secondary->SetState(SH_CMD_BUFFER_STATE::INITIAL);
else
SHLOG_ERROR("Secondary command buffer in pending state, could not reset. ");
// TODO: Ditto from TODO in primary check // TODO: Ditto from TODO in primary check
} }

View File

@ -54,7 +54,7 @@ namespace SHADE
}); });
// Create graphics queue // Create graphics queue
queue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0); graphicsQueue = device->GetQueue(SH_Q_FAM::GRAPHICS, 0);
// Create Render Context // Create Render Context
@ -111,11 +111,11 @@ namespace SHADE
compositeSubpass->AddInput("Normals"); compositeSubpass->AddInput("Normals");
compositeSubpass->AddInput("Position"); compositeSubpass->AddInput("Position");
auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present"}, {"G-Buffer"}); //auto compositeNode = renderGraph.AddNode("Bloom", { "Composite", "Downscale", "Present"}, {"G-Buffer"});
auto bloomSubpass = compositeNode->AddSubpass("Downsample"); //auto bloomSubpass = compositeNode->AddSubpass("Downsample");
bloomSubpass->AddInput("Composite"); //bloomSubpass->AddInput("Composite");
bloomSubpass->AddColorOutput("Downscale"); // bloomSubpass->AddColorOutput("Downscale");
bloomSubpass->AddColorOutput("Present"); // bloomSubpass->AddColorOutput("Present");
renderGraph.Generate(); renderGraph.Generate();
@ -127,6 +127,14 @@ namespace SHADE
void SHGraphicsSystem::Run(float dt) 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(); //renderPass.Free();
renderContext.Destroy(); renderContext.Destroy();
queue.Free(); graphicsQueue.Free();
swapchain.Free(); swapchain.Free();
surface.Free(); surface.Free();
device.Free(); device.Free();
@ -208,7 +216,7 @@ namespace SHADE
presentInfo.pImageIndices = &CURR_FRAME_IDX; presentInfo.pImageIndices = &CURR_FRAME_IDX;
// #BackEndTest: queues an image for presentation // #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 swapchain is incompatible/outdated
if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR) if (result == vk::Result::eErrorOutOfDateKHR || result == vk::Result::eSuboptimalKHR)

View File

@ -114,7 +114,7 @@ namespace SHADE
Handle<SHVkSwapchain> GetSwapchain() const { return swapchain; } Handle<SHVkSwapchain> GetSwapchain() const { return swapchain; }
Handle<SHVkSurface> GetSurface() const { return surface; } Handle<SHVkSurface> GetSurface() const { return surface; }
Handle<SHVkPhysicalDevice> GetPhysicalDevice() const {return physicalDevice;} Handle<SHVkPhysicalDevice> GetPhysicalDevice() const {return physicalDevice;}
Handle<SHVkQueue> GetQueue() const { return queue; } Handle<SHVkQueue> GetQueue() const { return graphicsQueue; }
Handle<SHVkDescriptorPool> GetDescriptorPool() const { return descPool; } Handle<SHVkDescriptorPool> GetDescriptorPool() const { return descPool; }
SHRenderGraph const& GetRenderGraph (void) const noexcept; SHRenderGraph const& GetRenderGraph (void) const noexcept;
@ -130,7 +130,7 @@ namespace SHADE
Handle<SHVkLogicalDevice> device; Handle<SHVkLogicalDevice> device;
Handle<SHVkSurface> surface; Handle<SHVkSurface> surface;
Handle<SHVkSwapchain> swapchain; Handle<SHVkSwapchain> swapchain;
Handle<SHVkQueue> queue; Handle<SHVkQueue> graphicsQueue;
Handle<SHVkDescriptorPool> descPool; Handle<SHVkDescriptorPool> descPool;
//Handle<SHVkRenderpass> renderPass; // Potentially bring out? //Handle<SHVkRenderpass> renderPass; // Potentially bring out?
std::vector<SHScreenSegment> screenSegments; std::vector<SHScreenSegment> screenSegments;

View File

@ -5,6 +5,7 @@
#include "Graphics/Synchronization/SHVkSemaphore.h" #include "Graphics/Synchronization/SHVkSemaphore.h"
#include "Graphics/Synchronization/SHVkFence.h" #include "Graphics/Synchronization/SHVkFence.h"
#include "Graphics/Commands/SHVkCommandBuffer.h" #include "Graphics/Commands/SHVkCommandBuffer.h"
#include "Graphics/Swapchain/SHVkSwapchain.h"
namespace SHADE namespace SHADE
@ -31,14 +32,10 @@ namespace SHADE
} }
vk::Queue SHVkQueue::GetVkQueue(void) const noexcept void SHVkQueue::SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems /*= {}*/, std::initializer_list<Handle<SHVkSemaphore>> waitSems /*= {}*/, vk::PipelineStageFlags waitDstStageMask /*= {}*/, Handle<SHVkFence> const& optionalFence /*= {}*/) noexcept
{ {
return vkQueue; // prepare wait sems
} std::array<vk::Semaphore, 5> vkWaitSems{ };
void SHVkQueue::SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems /*= {}*/, std::initializer_list<Handle<SHVkSemaphore>> waitSems /*= {}*/, vk::PipelineStageFlagBits waitDstStageMask /*= {}*/, Handle<SHVkFence> const& optionalFence /*= {}*/) noexcept
{
std::vector<vk::Semaphore> vkWaitSems{ waitSems.size() };
uint32_t i = 0; uint32_t i = 0;
for (auto& sem : waitSems) for (auto& sem : waitSems)
{ {
@ -46,7 +43,8 @@ namespace SHADE
++i; ++i;
} }
std::vector<vk::Semaphore> vkSignalSems{ signalSems.size() }; // prepare signal sems
std::array<vk::Semaphore, 5> vkSignalSems{ };
i = 0; i = 0;
for (auto& sem : signalSems) for (auto& sem : signalSems)
{ {
@ -54,33 +52,76 @@ namespace SHADE
++i; ++i;
} }
std::vector<vk::CommandBuffer> vkCmdBuffers{ cmdBuffers.size() }; // prepare cmd buffers
std::array<vk::CommandBuffer, 5> vkCmdBuffers{ };
i = 0; i = 0;
for (auto& cmdBuffer : cmdBuffers) 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(); vkCmdBuffers[i] = cmdBuffer->GetVkCommandBuffer();
++i; ++i;
} }
vk::PipelineStageFlags mask = waitDstStageMask; // Prepare submit info
vk::SubmitInfo submitInfo vk::SubmitInfo submitInfo
{ {
.waitSemaphoreCount = static_cast<uint32_t>(vkWaitSems.size()), .waitSemaphoreCount = static_cast<uint32_t>(waitSems.size()),
.pWaitSemaphores = vkWaitSems.data(), .pWaitSemaphores = vkWaitSems.data(),
.pWaitDstStageMask = &mask, .pWaitDstStageMask = &waitDstStageMask,
.commandBufferCount = static_cast<uint32_t>(vkCmdBuffers.size()), .commandBufferCount = static_cast<uint32_t>(cmdBuffers.size()),
.pCommandBuffers = vkCmdBuffers.data(), .pCommandBuffers = vkCmdBuffers.data(),
.signalSemaphoreCount = static_cast<uint32_t>(vkSignalSems.size()), .signalSemaphoreCount = static_cast<uint32_t>(signalSems.size()),
.pSignalSemaphores = vkSignalSems.data(), .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) if (auto result = vkQueue.submit(1, &submitInfo, (optionalFence) ? optionalFence->GetVkFence() : nullptr); result != vk::Result::eSuccess)
{ {
SHVulkanDebugUtil::ReportVkError(result, "Failed to submit command buffer. "); SHVulkanDebugUtil::ReportVkError(result, "Failed to submit command buffer. ");
} }
else // if success
{
// Change all command buffers to pending state
for (Handle<SHVkCommandBuffer> cmdBuffer : cmdBuffers)
{
cmdBuffer->HandlePostSubmit();
}
}
}
vk::Result SHVkQueue::Present(Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept
{
vk::PresentInfoKHR presentInfo{};
// prepare wait sems
std::array<vk::Semaphore, 5> vkWaitSems{ };
uint32_t i = 0;
for (auto& sem : waitSems)
{
vkWaitSems[i] = sem->GetVkSem();
++i;
}
// prepare presentation information
presentInfo.waitSemaphoreCount = static_cast<uint32_t>(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;
} }
} }

View File

@ -11,6 +11,7 @@ namespace SHADE
class SHVkCommandBuffer; class SHVkCommandBuffer;
class SHVkFence; class SHVkFence;
class SHVkSemaphore; class SHVkSemaphore;
class SHVkSwapchain;
enum class SH_QUEUE_FAMILY_ARRAY_INDEX : std::size_t enum class SH_QUEUE_FAMILY_ARRAY_INDEX : std::size_t
{ {
@ -45,9 +46,9 @@ namespace SHADE
public: public:
SHVkQueue(vk::Queue inVkQueue, SHQueueFamilyIndex parent, Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl) noexcept; SHVkQueue(vk::Queue inVkQueue, SHQueueFamilyIndex parent, Handle<SHVkLogicalDevice> const& inLogicalDeviceHdl) noexcept;
vk::Queue GetVkQueue(void) const noexcept;
void SubmitCommandBuffer(std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlagBits waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept; void SubmitCommandBuffer (std::initializer_list<Handle<SHVkCommandBuffer>> cmdBuffers, std::initializer_list<Handle<SHVkSemaphore>> signalSems = {}, std::initializer_list<Handle<SHVkSemaphore>> waitSems = {}, vk::PipelineStageFlags waitDstStageMask = {}, Handle<SHVkFence> const& fence = {}) noexcept;
vk::Result Present (Handle<SHVkSwapchain> const& swapchain, std::initializer_list<Handle<SHVkSemaphore>> waitSems, uint32_t frameIndex) noexcept;
}; };
} }

View File

@ -552,13 +552,15 @@ namespace SHADE
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept
{ {
frameIndex = (framebuffers.size() > 1) ? frameIndex : 0;
commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); 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 // Go to next subpass if not last subpass
if (i != subpasses.size() - 1)
commandBuffer->NextSubpass(); commandBuffer->NextSubpass();
} }
@ -892,6 +894,10 @@ namespace SHADE
{ {
commandPool = logicalDeviceHdl->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true); commandPool = logicalDeviceHdl->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
commandBuffers.resize(static_cast<std::size_t>(swapchainHdl->GetNumImages())); commandBuffers.resize(static_cast<std::size_t>(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 void SHRenderGraph::Execute(uint32_t frameIndex) noexcept
{ {
commandPool->Reset();
auto& cmdBuffer = commandBuffers[frameIndex]; auto& cmdBuffer = commandBuffers[frameIndex];
cmdBuffer->BeginRecording(); cmdBuffer->BeginRecording();
@ -1027,7 +1035,7 @@ namespace SHADE
node->Execute(commandBuffers[frameIndex], frameIndex); node->Execute(commandBuffers[frameIndex], frameIndex);
} }
cmdBuffer->EndRenderpass(); cmdBuffer->EndRecording();
} }
Handle<SHRenderGraphNode> SHRenderGraph::GetNode(std::string const& nodeName) const noexcept Handle<SHRenderGraphNode> SHRenderGraph::GetNode(std::string const& nodeName) const noexcept
@ -1038,4 +1046,9 @@ namespace SHADE
return {}; return {};
} }
Handle<SHVkCommandBuffer> const& SHRenderGraph::GetCommandBuffer(uint32_t frameIndex) const noexcept
{
return commandBuffers[frameIndex];
}
} }

View File

@ -276,6 +276,7 @@ namespace SHADE
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
Handle<SHRenderGraphNode> GetNode (std::string const& nodeName) const noexcept; Handle<SHRenderGraphNode> GetNode (std::string const& nodeName) const noexcept;
Handle<SHVkCommandBuffer> const& GetCommandBuffer (uint32_t frameIndex) const noexcept;
}; };
} }