I'm learning vulkan, and as a (very) simple project I want to simply clear a single swapchain image to a single color (red). My code works, but I get two validation errors. I would like to know:
Regarding (2): I specifically don't want to use a graphics pipeline: in the future I would like to use a compute shader to draw directly to the screen.
My project uses vk-bootstrap to set up, and then I try to render a single frame as follows:
vkCmdPipelineBarriervkCmdClearColorImagevkEndCommandBuffervkQueuePresentKHRThe relevant code can be found below, but it seems that the validation errors arise from the calls to vkCmdClearColorImage and vkQueuePresentKHR.
The first validation error is from the vkCmdClearColorImage call, and seems to be triggered by my choice of layout:
VkImageLayout layout = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
// (... snip ...)
vkCmdClearColorImage(commandBuffer, swapChainImages[nextImageIndex], layout, &color, 1, &imageSubresourceRange);
The error message says:
[ERROR: Validation]
Validation Error: [ VUID-vkCmdClearColorImage-imageLayout-00005 ] Object 0: handle = 0xf56c9b0000000004, type = VK_OBJECT_TYPE_IMAGE; | MessageID = 0x9740ed23 | vkCmdClearColorImage(): Layout for cleared image is VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR but can only be TRANSFER_DST_OPTIMAL or GENERAL. The Vulkan spec states: imageLayout must be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL or VK_IMAGE_LAYOUT_GENERAL (https://www.khronos.org/registry/vulkan/specs/1.2/html/vkspec.html#VUID-vkCmdClearColorImage-imageLayout-00005)
I'm confused by this message, because although the link in this error message indeed says that
imageLayout must be
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMALorVK_IMAGE_LAYOUT_GENERAL
I also found this page in the spec that says
imageLayout specifies the current layout of the image subresource ranges to be cleared, and must be
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,VK_IMAGE_LAYOUT_GENERALorVK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
The second error is triggered by the call to vkQueuePresentKHR and is especially weird...
[ERROR: Validation]
Validation Error: [ VUID-VkPresentInfoKHR-pImageIndices-01296 ] Object 0: handle = 0x55a3c6b9e408, type = VK_OBJECT_TYPE_QUEUE; | MessageID = 0xc7aabc16 | 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_SHARED_PRESENT_KHR. 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)
... because the message seems to contradict itself (linebreaks added):
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_SHARED_PRESENT_KHR
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = 0;
beginInfo.pInheritanceInfo = nullptr;
if(vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("failed vkBeginCommandBuffer");
}
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = swapChainImages[nextImageIndex];
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier);
VkImageLayout layout = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
VkClearColorValue color = { .float32 = {1.0, 0.0, 0.0} };
VkImageSubresourceRange imageSubresourceRange { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdClearColorImage(commandBuffer, swapChainImages[nextImageIndex], layout, &color, 1, &imageSubresourceRange);
vkEndCommandBuffer(commandBuffer);
So to repeat: I would like to know:
The vulkaninfo command reports Vulkan Instance Version 1.2.194
I found a solution which works but seems kinda gross. Basically I modify step (2) to the following:
vkCmdPipelineBarriervkCmdClearColorImagevkCmdPipelineBarriervkEndCommandBufferEssentially the logical flow of this pipeline is:
VK_IMAGE_LAYOUT_UNDEFINED to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMALvkCmdClearColorImageVK_IMAGE_LAYOUT_PRESENT_SRC_KHR so it can be presentedThis works because:
vkCmdClearColorImage requires the image to have layout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, butvkQueuePresent requires the image to have layout VK_IMAGE_LAYOUT_PRESENT_SRC_KHRSince this seems a little hacky / gross, I will leave this question open for a while to see if anyone has a better solution. For completeness, here is the new code for step (2)
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = 0;
beginInfo.pInheritanceInfo = nullptr;
if(vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
throw std::runtime_error("failed vkBeginCommandBuffer");
}
//VkImageLayout clearLayout = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR;
VkImageLayout clearLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = clearLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = swapChainImages[nextImageIndex];
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
1, &barrier);
VkImageLayout layout = clearLayout;
VkClearColorValue color = { .float32 = {1.0, 0.0, 0.0} };
VkImageSubresourceRange imageSubresourceRange { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdClearColorImage(commandBuffer, swapChainImages[nextImageIndex], layout, &color, 1, &imageSubresourceRange);
// Add another barrier and put the image in VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
VkImageLayout finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkImageMemoryBarrier finalBarrier{};
finalBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
finalBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
finalBarrier.newLayout = finalLayout;
finalBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
finalBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
finalBarrier.image = swapChainImages[nextImageIndex];
finalBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
finalBarrier.subresourceRange.baseMipLevel = 0;
finalBarrier.subresourceRange.levelCount = 1;
finalBarrier.subresourceRange.baseArrayLayer = 0;
finalBarrier.subresourceRange.layerCount = 1;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, nullptr,
0, nullptr,
1, &finalBarrier);
vkEndCommandBuffer(commandBuffer);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With