在另一个渲染通道之上使用一个渲染通道
Using one render pass on top of another
我正在尝试在我的应用程序中实现 imGUI,它已经有一些用于渲染网格的渲染通道。它的命令缓冲区仅在新网格添加到场景时更新,而 imGUI 命令缓冲区应每帧更新。辅助命令缓冲区不适合我,因为我总是必须从主 cb 引用它,它不经常更新。
我还想提一下,我的代码是基于 this 教程。
我得出结论,我应该有两个渲染通道和两个主要命令缓冲区。现在唯一的问题是我无法合并这两个渲染通道。
有主要rp的代码:
vk::AttachmentDescription colorAttachment;
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = vk::SampleCountFlagBits::e1;
colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
colorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eNoneQCOM;
colorAttachment.initialLayout = vk::ImageLayout::eUndefined;
colorAttachment.finalLayout = vk::ImageLayout::ePresentSrcKHR;
vk::AttachmentDescription depthAttachment;
depthAttachment.format = FindDepthFormat();
depthAttachment.samples = vk::SampleCountFlagBits::e1;
depthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.initialLayout = vk::ImageLayout::eUndefined;
depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
std::array<vk::AttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
vk::AttachmentReference colorAttachmentRef;
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;
vk::AttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
vk::SubpassDescription subpass;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
vk::SubpassDependency dependency;
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.srcAccessMask = vk::AccessFlagBits();
dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite;
vk::RenderPassCreateInfo renderPassInfo;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
gameRenderPass = device.createRenderPass(renderPassInfo);
有 ui 的代码 rp:
vk::AttachmentDescription colorAttachment;
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = vk::SampleCountFlagBits::e1;
colorAttachment.loadOp = vk::AttachmentLoadOp::eLoad;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
colorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
colorAttachment.initialLayout = vk::ImageLayout::ePresentSrcKHR;
colorAttachment.finalLayout = vk::ImageLayout::ePresentSrcKHR;
vk::AttachmentDescription depthAttachment;
depthAttachment.format = FindDepthFormat();
depthAttachment.samples = vk::SampleCountFlagBits::e1;
depthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.initialLayout = vk::ImageLayout::eUndefined;
depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
std::array<vk::AttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
vk::AttachmentReference colorAttachmentRef;
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;
vk::AttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
vk::SubpassDescription subpass;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
vk::SubpassDependency dependency;
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.srcAccessMask = vk::AccessFlagBits();
dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite;
vk::RenderPassCreateInfo renderPassInfo;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
uiRenderPass = device.createRenderPass(renderPassInfo);
还有我的 DrawFrame 函数的代码:
device.waitForFences(1, &inFlightFences[currentFrame], true, UINT64_MAX);
uint32_t imageIndex;
device.acquireNextImageKHR(swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], nullptr, &imageIndex);
if (imagesInFlight[imageIndex].operator!=(nullptr))
{
device.waitForFences(1, &imagesInFlight[imageIndex], true, UINT64_MAX);
}
imagesInFlight[imageIndex] = inFlightFences[currentFrame];
vk::SubmitInfo submitInfo;
vk::Semaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
vk::PipelineStageFlags waitStages[] = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
vk::Semaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
device.resetFences(1, &inFlightFences[currentFrame]);
UpdateUniformBuffer(imageIndex);
UpdateUiCommandBuffer(imageIndex);
if (comandUpdateRequired[imageIndex])
{
UpdateGameCommandBuffer(imageIndex);
comandUpdateRequired[imageIndex] = false;
}
std::vector<vk::CommandBuffer> commands = { gameCommandBuffers[imageIndex], uiCommandBuffers[imageIndex] };
submitInfo.commandBufferCount = static_cast<uint32_t>(commands.size());
submitInfo.pCommandBuffers = commands.data();
graphicsQueue.submit(1, &submitInfo, inFlightFences[currentFrame]);
vk::PresentInfoKHR presentInfo;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
vk::SwapchainKHR swapChains[] = { swapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentQueue.presentKHR(presentInfo);
presentQueue.waitIdle();
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
结果是:
如您所见,清晰的颜色用于覆盖我第一次渲染过程的结果,这不是我想要的。
请注意,load
和 store
操作已经在使用,但它仍然没有 工作。
更新
有我的第二个cb的代码:
device.freeCommandBuffers(commandPool, 1, &uiCommandBuffers[index]);
vk::CommandBufferAllocateInfo allocInfo;
allocInfo.commandPool = commandPool;
allocInfo.level = vk::CommandBufferLevel::ePrimary;
allocInfo.commandBufferCount = 1;
device.allocateCommandBuffers(&allocInfo, &uiCommandBuffers[index]);
vk::CommandBufferBeginInfo beginInfo;
uiCommandBuffers[index].begin(beginInfo);
std::array<vk::ClearValue, 2> clearValues;
clearValues[0].color = vk::ClearColorValue(std::array<float, 4>{ 1.0f, 0.0f, 0.0f, 1.0f });
clearValues[1].depthStencil = { 1.0f, 0 };
vk::RenderPassBeginInfo renderPassInfo;
renderPassInfo.renderPass = gameRenderPass;
renderPassInfo.framebuffer = uiSwapChainFramebuffers[index];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = swapChainExtent;
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size()); // It doesn't work at all if I set clear values count to 0
renderPassInfo.pClearValues = clearValues.data();
//renderPassInfo.clearValueCount = 0;
//renderPassInfo.pClearValues = nullptr;
uiCommandBuffers[index].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline);
auto drawData = ImGui::GetDrawData();
if (drawData)
{
ImGui_ImplVulkan_RenderDrawData(drawData, uiCommandBuffers[index]);
}
uiCommandBuffers[index].endRenderPass();
uiCommandBuffers[index].end();
如果要使用第二遍渲染 UI,只需将第一遍渲染中的颜色附件的 storeOp
设置为 VK_ATTACHMENT_STORE_OP_STORE
并将 loadOp
在第二次渲染传递给 VK_ATTACHMENT_LOAD_OP_LOAD
以保留内容。
另一种选择是在单个渲染过程中执行此操作,就像我在示例中所做的那样。只需渲染您的场景,然后将 UI 的绘制调用放在同一个渲染通道中。
我正在尝试在我的应用程序中实现 imGUI,它已经有一些用于渲染网格的渲染通道。它的命令缓冲区仅在新网格添加到场景时更新,而 imGUI 命令缓冲区应每帧更新。辅助命令缓冲区不适合我,因为我总是必须从主 cb 引用它,它不经常更新。
我还想提一下,我的代码是基于 this 教程。
我得出结论,我应该有两个渲染通道和两个主要命令缓冲区。现在唯一的问题是我无法合并这两个渲染通道。
有主要rp的代码:
vk::AttachmentDescription colorAttachment;
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = vk::SampleCountFlagBits::e1;
colorAttachment.loadOp = vk::AttachmentLoadOp::eClear;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
colorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eNoneQCOM;
colorAttachment.initialLayout = vk::ImageLayout::eUndefined;
colorAttachment.finalLayout = vk::ImageLayout::ePresentSrcKHR;
vk::AttachmentDescription depthAttachment;
depthAttachment.format = FindDepthFormat();
depthAttachment.samples = vk::SampleCountFlagBits::e1;
depthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.initialLayout = vk::ImageLayout::eUndefined;
depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
std::array<vk::AttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
vk::AttachmentReference colorAttachmentRef;
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;
vk::AttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
vk::SubpassDescription subpass;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
vk::SubpassDependency dependency;
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.srcAccessMask = vk::AccessFlagBits();
dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite;
vk::RenderPassCreateInfo renderPassInfo;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
gameRenderPass = device.createRenderPass(renderPassInfo);
有 ui 的代码 rp:
vk::AttachmentDescription colorAttachment;
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = vk::SampleCountFlagBits::e1;
colorAttachment.loadOp = vk::AttachmentLoadOp::eLoad;
colorAttachment.storeOp = vk::AttachmentStoreOp::eStore;
colorAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
colorAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
colorAttachment.initialLayout = vk::ImageLayout::ePresentSrcKHR;
colorAttachment.finalLayout = vk::ImageLayout::ePresentSrcKHR;
vk::AttachmentDescription depthAttachment;
depthAttachment.format = FindDepthFormat();
depthAttachment.samples = vk::SampleCountFlagBits::e1;
depthAttachment.loadOp = vk::AttachmentLoadOp::eClear;
depthAttachment.storeOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.stencilLoadOp = vk::AttachmentLoadOp::eDontCare;
depthAttachment.stencilStoreOp = vk::AttachmentStoreOp::eDontCare;
depthAttachment.initialLayout = vk::ImageLayout::eUndefined;
depthAttachment.finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
std::array<vk::AttachmentDescription, 2> attachments = { colorAttachment, depthAttachment };
vk::AttachmentReference colorAttachmentRef;
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = vk::ImageLayout::eColorAttachmentOptimal;
vk::AttachmentReference depthAttachmentRef;
depthAttachmentRef.attachment = 1;
depthAttachmentRef.layout = vk::ImageLayout::eDepthStencilAttachmentOptimal;
vk::SubpassDescription subpass;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
subpass.pDepthStencilAttachment = &depthAttachmentRef;
vk::SubpassDependency dependency;
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.srcAccessMask = vk::AccessFlagBits();
dependency.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput;
dependency.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite;
vk::RenderPassCreateInfo renderPassInfo;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
uiRenderPass = device.createRenderPass(renderPassInfo);
还有我的 DrawFrame 函数的代码:
device.waitForFences(1, &inFlightFences[currentFrame], true, UINT64_MAX);
uint32_t imageIndex;
device.acquireNextImageKHR(swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], nullptr, &imageIndex);
if (imagesInFlight[imageIndex].operator!=(nullptr))
{
device.waitForFences(1, &imagesInFlight[imageIndex], true, UINT64_MAX);
}
imagesInFlight[imageIndex] = inFlightFences[currentFrame];
vk::SubmitInfo submitInfo;
vk::Semaphore waitSemaphores[] = { imageAvailableSemaphores[currentFrame] };
vk::PipelineStageFlags waitStages[] = { vk::PipelineStageFlagBits::eColorAttachmentOutput };
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages;
vk::Semaphore signalSemaphores[] = { renderFinishedSemaphores[currentFrame] };
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores;
device.resetFences(1, &inFlightFences[currentFrame]);
UpdateUniformBuffer(imageIndex);
UpdateUiCommandBuffer(imageIndex);
if (comandUpdateRequired[imageIndex])
{
UpdateGameCommandBuffer(imageIndex);
comandUpdateRequired[imageIndex] = false;
}
std::vector<vk::CommandBuffer> commands = { gameCommandBuffers[imageIndex], uiCommandBuffers[imageIndex] };
submitInfo.commandBufferCount = static_cast<uint32_t>(commands.size());
submitInfo.pCommandBuffers = commands.data();
graphicsQueue.submit(1, &submitInfo, inFlightFences[currentFrame]);
vk::PresentInfoKHR presentInfo;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = signalSemaphores;
vk::SwapchainKHR swapChains[] = { swapChain };
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = swapChains;
presentInfo.pImageIndices = &imageIndex;
presentQueue.presentKHR(presentInfo);
presentQueue.waitIdle();
currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
结果是:
如您所见,清晰的颜色用于覆盖我第一次渲染过程的结果,这不是我想要的。
请注意,load
和 store
操作已经在使用,但它仍然没有 工作。
更新
有我的第二个cb的代码:
device.freeCommandBuffers(commandPool, 1, &uiCommandBuffers[index]);
vk::CommandBufferAllocateInfo allocInfo;
allocInfo.commandPool = commandPool;
allocInfo.level = vk::CommandBufferLevel::ePrimary;
allocInfo.commandBufferCount = 1;
device.allocateCommandBuffers(&allocInfo, &uiCommandBuffers[index]);
vk::CommandBufferBeginInfo beginInfo;
uiCommandBuffers[index].begin(beginInfo);
std::array<vk::ClearValue, 2> clearValues;
clearValues[0].color = vk::ClearColorValue(std::array<float, 4>{ 1.0f, 0.0f, 0.0f, 1.0f });
clearValues[1].depthStencil = { 1.0f, 0 };
vk::RenderPassBeginInfo renderPassInfo;
renderPassInfo.renderPass = gameRenderPass;
renderPassInfo.framebuffer = uiSwapChainFramebuffers[index];
renderPassInfo.renderArea.offset = { 0, 0 };
renderPassInfo.renderArea.extent = swapChainExtent;
renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size()); // It doesn't work at all if I set clear values count to 0
renderPassInfo.pClearValues = clearValues.data();
//renderPassInfo.clearValueCount = 0;
//renderPassInfo.pClearValues = nullptr;
uiCommandBuffers[index].beginRenderPass(renderPassInfo, vk::SubpassContents::eInline);
auto drawData = ImGui::GetDrawData();
if (drawData)
{
ImGui_ImplVulkan_RenderDrawData(drawData, uiCommandBuffers[index]);
}
uiCommandBuffers[index].endRenderPass();
uiCommandBuffers[index].end();
如果要使用第二遍渲染 UI,只需将第一遍渲染中的颜色附件的 storeOp
设置为 VK_ATTACHMENT_STORE_OP_STORE
并将 loadOp
在第二次渲染传递给 VK_ATTACHMENT_LOAD_OP_LOAD
以保留内容。
另一种选择是在单个渲染过程中执行此操作,就像我在示例中所做的那样。只需渲染您的场景,然后将 UI 的绘制调用放在同一个渲染通道中。