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 = ¤tSwapchainImageIndex,
.pResults = nullptr,
};
// This will _not_ return success if the window is resized
assert(graphicsQueue.presentKHR(presentInfo) == vk::Result::eSuccess);
currentFrame++;