Verwenden eines Renderpasses über einem anderen

Sep 08 2020

Ich versuche, imGUI in meiner App zu implementieren, die bereits einen Renderpass zum Rendern von Netzen haben. Der Befehlspuffer wird nur aktualisiert, wenn der Szene neue Netze hinzugefügt werden, während der imGUI-Befehlspuffer in jedem Frame aktualisiert werden sollte. Der sekundäre Befehlspuffer passt nicht zu mir, weil ich ihn immer von der primären cb referenzieren muss, die nicht so oft aktualisiert wird.

Ich möchte auch erwähnen, dass mein Code auf diesem Tutorial basiert .

Ich kam zu dem Schluss, dass ich zwei Renderdurchläufe mit zwei primären Befehlspuffern haben sollte. Das einzige Problem ist jetzt, dass ich diese beiden Renderdurchgänge nicht kombinieren kann.

Es gibt den Code für Haupt-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);

Es gibt den Code für 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);

Und da ist der Code meiner DrawFrame-Funktion:

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;

Und das Ergebnis ist:

As you can see, clear color is used to overwrite the results of my first render pass, what is not what I want.

Note that load and store operations already in use and it still doesn't work.


UPDATE

There is a code of my second 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();

Antworten

1 SaschaWillems Sep 08 2020 at 02:56

If you want to render the UI using a second pass, just set the storeOp of the color attachment in the first render pass to VK_ATTACHMENT_STORE_OP_STORE and the loadOp for it in the second render pass to VK_ATTACHMENT_LOAD_OP_LOAD to keep the contents.

Eine andere Möglichkeit wäre, dies in einem einzigen Renderdurchlauf zu tun, wie ich es in meinen Beispielen tue. Rendern Sie einfach Ihre Szene und setzen Sie die Zeichenaufrufe für die Benutzeroberfläche in denselben Renderdurchlauf.