1

I'm using the transfer queue to upload data to GPU local memory to be used by the graphics queue. I believe I need 3 barriers, one to release the texture object from the transfer queue, one to acquire it on the graphics queue, and one transition it from TRANSFER_DST_OPTIMAL to SHADER_READ_ONLY_OPTIMAL. I think my barriers are what's incorrect as this is the error I get and also, I see the correct rendered output as I'm on Nvidia hardware. Is there any synchronization missing?

UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout(ERROR / SPEC): msgNum: 1303270965 - 
Validation Error: [ UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout ] Object 0: 
handle = 0x562696461ca0, type = VK_OBJECT_TYPE_COMMAND_BUFFER; | MessageID = 0x4dae5635 | 
Submitted command buffer expects VkImage 0x1c000000001c[] (subresource: aspectMask 0x1 array 
layer 0, mip level 0) to be in layout VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL--instead, 
current layout is VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.

I believe what I'm doing wrong is not properly specifying stageMasks

    VkImageMemoryBarrier tex_barrier = {0};
    /* layout transition - UNDEFINED -> TRANSFER_DST */
    tex_barrier.srcAccessMask = 0;
    tex_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
    tex_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    tex_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    tex_barrier.srcQueueFamilyIndex = -1; 
    tex_barrier.dstQueueFamilyIndex = -1;
    tex_barrier.subresourceRange = (VkImageSubresourceRange) { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };

    vkCmdPipelineBarrier(transfer_cmdbuffs[0], 
                         VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
                         VK_PIPELINE_STAGE_TRANSFER_BIT,
                         0,
                         0, NULL, 0, NULL, 1, &tex_barrier);

    /* queue ownership transfer */
    tex_barrier.srcAccessMask = 0;
    tex_barrier.dstAccessMask = 0;
    tex_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    tex_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    tex_barrier.srcQueueFamilyIndex = device.transfer_queue_family_index;
    tex_barrier.dstQueueFamilyIndex = device.graphics_queue_family_index;
    
    vkCmdPipelineBarrier(transfer_cmdbuffs[0],
                         VK_PIPELINE_STAGE_TRANSFER_BIT,
                         VK_PIPELINE_STAGE_TRANSFER_BIT,
                         0,
                         0, NULL, 0, NULL, 1, &tex_barrier);
                         
    tex_barrier.srcAccessMask = 0;
    tex_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
    tex_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
    tex_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
    tex_barrier.srcQueueFamilyIndex = device.transfer_queue_family_index;
    tex_barrier.dstQueueFamilyIndex = device.graphics_queue_family_index;
    
    vkCmdPipelineBarrier(transfer_cmdbuffs[0],
                         VK_PIPELINE_STAGE_TRANSFER_BIT,
                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
                         0,
                         0, NULL, 0, NULL, 1, &tex_barrier);
    
2
  • 1
    Are you issuing these commands to the same command buffer, like your pseudo-code suggests? Because I'm pretty sure that doesn't work. Commented Oct 11, 2020 at 22:13
  • Same command buffer, same queue for submission. Do I need a semaphore sync op between submits? Commented Oct 12, 2020 at 0:14

1 Answer 1

2

Doing an ownership transfer is a 2-way process: the source of the transfer has to release the resource, and the receiver has to acquire it. And by "the source" and "the receiver", I mean the queues themselves. You can't merely give a queue take ownership of a resource; that queue must issue a command to claim ownership of it.

You need to submit a release barrier operation on the source queue. It must specify the source queue family as well as the destination queue family. Then, you have to submit an acquire barrier operation on the receiving queue, using the same source and destination. And you must ensure the order of these operations via a semaphore. So the vkQueueSubmit call for the acquire has to wait on the semaphore from the submission of the release operation (a timeline semaphore would work too).

Now, since these are pipeline/memory barriers, you are free to also specify a layout transition. You don't need a third barrier to change the layout, but both barriers have to specify the same source/destination layouts for the acquire/release operation.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.