如果没有提交命令缓冲区,vkQueuePresentKHR 图像的布局无效

vkQueuePresentKHR image has invalid layout if no command buffers are submitted

我设置了一个简约的 Vulkan 管道,它所做的只是在呈现之前清除后台缓冲区。但是,如果我设置 .commandBufferCount = 0 我会收到以下验证错误:

vkQueuePresentKHR(): pSwapchains[0] images passed to present must be in layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHR or VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but is in VK_IMAGE_LAYOUT_UNDEFINED. The Vulkan spec states: Each element of pImageIndices must be the index of a presentable image acquired from the swapchain specified by the corresponding element of the pSwapchains array, and the presented image subresource must be in the VK_IMAGE_LAYOUT_PRESENT_SRC_KHR layout at the time the operation is executed on a VkDevice (https://github.com/KhronosGroup/Vulkan-Docs/search?q=)VUID-VkPresentInfoKHR-pImageIndices-01296)

应用程序仍然清除图像并且似乎继续工作,但为什么我需要提供命令缓冲区以将后缓冲区图像转换为预期的布局?渲染通道不会处理过渡吗?

这里是用于渲染的代码;我正在使用 vulkan_raii.hpp:

device->waitForFences(*queueDoneFences[currentFrame % BACKBUFFER_COUNT], true, UINT64_MAX);

vk::Result res;
std::tie(res, currentSwapchainImageIndex) = device->acquireNextImageKHR(
    *swapchain,
    UINT64_MAX,
    *imageAvailableSemaphores[currentFrame % BACKBUFFER_COUNT],
    VK_NULL_HANDLE);
device->resetFences(*queueDoneFences[currentFrame % BACKBUFFER_COUNT]);
assert(res == vk::Result::eSuccess);

commandBuffers[currentFrame % BACKBUFFER_COUNT]->reset();
commandBuffers[currentFrame % BACKBUFFER_COUNT]->begin(
    {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit});

vk::ClearColorValue clearColor = {std::array<float, 4>{0.0f, 0.0f, 0.0f, 0.0f}};
vk::RenderPassBeginInfo info = {
    .renderPass = *renderPass,
    .framebuffer = *framebuffers[currentSwapchainImageIndex],
    .renderArea =
        {
            .offset = {0, 0},
            .extent = {1280, 720} // TODO
        },
    .clearValueCount = 1,
    .pClearValues = (vk::ClearValue*)&clearColor,
};
commandBuffers[currentFrame % BACKBUFFER_COUNT]->bindPipeline(
    vk::PipelineBindPoint::eGraphics,
    *pipeline);
commandBuffers[currentFrame % BACKBUFFER_COUNT]->beginRenderPass(
    info,
    vk::SubpassContents::eInline);

commandBuffers[currentFrame % BACKBUFFER_COUNT]->endRenderPass();
commandBuffers[currentFrame % BACKBUFFER_COUNT]->end();

vk::PipelineStageFlags waitFlags = vk::PipelineStageFlagBits::eColorAttachmentOutput;
vk::SubmitInfo submitInfo = {
    .waitSemaphoreCount = 1,
    .pWaitSemaphores = &*imageAvailableSemaphores[currentFrame % BACKBUFFER_COUNT],
    .pWaitDstStageMask = &waitFlags,
    .commandBufferCount = 1,
    .pCommandBuffers = &*commandBuffers[currentFrame % BACKBUFFER_COUNT],
    .signalSemaphoreCount = 1,
    .pSignalSemaphores = &*renderFinishedSemaphores[currentFrame % BACKBUFFER_COUNT],
};
graphicsQueue.submit({submitInfo}, *queueDoneFences[currentFrame % BACKBUFFER_COUNT]);

vk::PresentInfoKHR presentInfo = {
    .waitSemaphoreCount = 1,
    .pWaitSemaphores = &*renderFinishedSemaphores[currentFrame % BACKBUFFER_COUNT],
    .swapchainCount = 1,
    .pSwapchains = &*swapchain,
    .pImageIndices = &currentSwapchainImageIndex,
    .pResults = nullptr,
};
// This will _not_ return success if the window is resized
assert(graphicsQueue.presentKHR(presentInfo) == vk::Result::eSuccess);

currentFrame++;

首先,您在命令缓冲区中开始和结束渲染过程。因此,如果您不提交命令缓冲区,则渲染通道将不会 运行 并且不会将图像从一种布局过渡到另一种布局。

无论如何,提交0个命令缓冲区真的没有意义。此外,不确定在这种情况下同步将如何工作,因为根据 the docs:

pSignalSemaphores is a pointer to an array of VkSemaphore handles which will be signaled when the command buffers for this batch have completed execution