0

I have a minimalistic Vulkan pipeline set up and all it does is clearing the backbuffer before presenting it. However, if I set .commandBufferCount = 0 I get the following validation error:

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)

The application still clears the image and seems to keep working, but why do I need to supply a command buffer for the backbuffer image transition into the expected layout? Doesn't the render pass take care of the transition?

Here is the code used for rendering; I'm using 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++;
Semicolon
  • 163
  • 2
  • 16
  • 1
    Do not use `assert` with `VkResult`s. `VkResult` errors are mostly runtime errors, not logical errors. – krOoze Apr 20 '22 at 17:05
  • Can you demonstrate to me that your `renderFinishedSemaphores[currentFrame % BACKBUFFER_COUNT]` semaphore cannot still be in use when passed to `graphicsQueue.submit()`? – krOoze Apr 20 '22 at 17:16
  • @krOoze I know, but it works for a lab environment/quick example. With resizing disabled I haven't yet to run into any issues. – Semicolon May 24 '22 at 09:39

1 Answers1

1

First of all, you start and end the render pass in the command buffer. So if you don't submit the command buffer, then the render pass will not run and won't transition the image from one layout to another.

Anyway, it doesn't really make sense to submit 0 command buffers. Also, not sure how the synchronization would work in this case, because according to 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
csisy
  • 471
  • 3
  • 15
  • 1
    Super obvious now that you point it out. I was looking for some obscure paragraph in the spec all this time when the answer was right in front of me. – Semicolon May 24 '22 at 09:37