Reputation: 900
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:
vkCmdPipelineBarrier
vkCmdClearColorImage
vkEndCommandBuffer
vkQueuePresentKHR
The 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_OPTIMAL
orVK_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_GENERAL
orVK_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
Upvotes: 4
Views: 2025
Reputation: 900
I found a solution which works but seems kinda gross. Basically I modify step (2) to the following:
vkCmdPipelineBarrier
vkCmdClearColorImage
vkCmdPipelineBarrier
vkEndCommandBuffer
Essentially the logical flow of this pipeline is:
VK_IMAGE_LAYOUT_UNDEFINED
to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
vkCmdClearColorImage
VK_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_KHR
Since 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);
Upvotes: 2