在另一个渲染通道上使用一个渲染通道

问题描述

我正在尝试在我的应用中实现imGUI,该应用已经具有一些渲染网格物体的渲染通道。它的命令缓冲区仅在将新网格物体添加到场景时才更新,而imGUI命令缓冲区应每帧更新一次。辅助命令缓冲区不适合我,因为我总是必须从主cb引用它,该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,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],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;

结果是:

Bad result >:(

如您所见,透明色用于覆盖我的第一次渲染过程的结果,不是我想要的。

请注意,loadstore操作已在使用中,并且仍然无法运行。


更新

第二个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,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的绘制调用放在同一渲染过程中即可。