Usando una pasada de render encima de otra

Sep 08 2020

Estoy tratando de implementar imGUI en mi aplicación que ya tiene un pase de renderizado para renderizar mallas. Su búfer de comando se actualiza solo cuando se agregan nuevas mallas a la escena, mientras que el búfer de comando imGUI debe actualizarse en cada cuadro. El búfer de comando secundario no me queda porque siempre tengo que hacer referencia a él desde el cb primario, que no se actualiza con tanta frecuencia.

También quiero mencionar que mi código se basa en este tutorial.

Llegué a la conclusión de que debería tener dos pases de renderizado con dos búferes de comando primarios. El único problema ahora es que no puedo combinar estos dos pases de renderizado.

Existe el código para main 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);

Existe el código para 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);

Y está el código de mi función 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;

Y el resultado es:

Como puede ver, el color claro se usa para sobrescribir los resultados de mi primer pase de renderizado, lo que no es lo que quiero.

Tenga en cuenta que loady storeoperaciones que ya están en uso y que sigue sin trabajo.


ACTUALIZAR

Hay un código de mi segundo 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();

Respuestas

1 SaschaWillems Sep 08 2020 at 02:56

Si desea renderizar la interfaz de usuario utilizando una segunda pasada, simplemente configure el storeOpdel adjunto de color en la primera pasada de renderizado en VK_ATTACHMENT_STORE_OP_STOREy el loadOpde en la segunda pasada de renderizado VK_ATTACHMENT_LOAD_OP_LOADpara mantener el contenido.

Otra opción sería hacer esto en una sola pasada de render, como hago en mis muestras. Simplemente renderice su escena y coloque las llamadas de dibujo para la interfaz de usuario en la misma pasada de renderizado.