vulkano icon indicating copy to clipboard operation
vulkano copied to clipboard

Can't execute command on swapchain image

Open realitix opened this issue 7 years ago • 7 comments

Hello,

When I try to execute a command directly on a swapchain image, I got a layout error:

thread '<unnamed>' panicked at 'Can't execute clear command buffer: AccessError { error: ImageNotInitialized { requested: PresentSrc }, command_name: "vkCmdCopyImageToBuffer", command_param: "source", command_offset: 0 }', libcore/result.rs:945:5

With a command like this one:

let cb = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family(),).unwrap()
            .copy_image_to_buffer(
                swapchain_images[image_num].clone(),
                buffer.clone()
            )
            .unwrap()
            .build()
            .unwrap();

I got the same error with the clear_color_image command. I searched in the API but I can't find a way to manually update the layout. Why the AutoCommandBufferBuilder doesn't expose the vkCmdPipelineBarrier function ?

Thanks, JS

realitix avatar Jun 21 '18 07:06 realitix

Why the AutoCommandBufferBuilder doesn't expose the vkCmdPipelineBarrier function ?

Per design, the AutoCommandBufferBuilder is supposed to automatically handle pipeline barriers for you.

tomaka avatar Jul 08 '18 07:07 tomaka

Any updates on this?

dvc94ch avatar Oct 27 '18 10:10 dvc94ch

Or put differently: How can I initialize a swapchain image? I'd like to render a stream from my webcam after processing it with a compute shader straight to a window. Missing the straight to a window part, but I guess I can copy it back to ram and then push it through a graphics pipeline with the framebuffer/renderpass stuff

dvc94ch avatar Oct 27 '18 14:10 dvc94ch

Just want to add that I'm running into this exact issue - specifically, using an AutoCommandBufferBuilder with only the clear_color_image command on a swapchain image.

I can verify that something to do with .clear_color_image is definitely causing the issue as the AccessError no longer occurs when I remove the call.

#974 seems very similar, though runs into the issue with a StorageImage rather than a SwapchainImage. That said, it's definitely a helpful read for digging into this.

Both the initial_layout_requirement and final_layout_requirement are expected to be PresentSrc, however vkCmdClearColorImage requires either TransferDstOptimal or General. Seeing as it seems it is the role of SyncCommandBufferBuilder::prev_cmd_resource to handle these layout transitions, I'm going to look into this here first.

@realitix did you ever work out a solution? I noticed you mentioned you were going to try the solution mentioned in #974, any luck?

mitchmindtree avatar Nov 20 '18 16:11 mitchmindtree

Memory barrier image layouts seem OK

Memory barriers are inserted via the add_image_memory_barrier method. In the simple clear_color_image command buffer I describe in my previous comment, add_image_memory_barrier gets called twice:

  1. When calling the clear_color_image builder.
  2. When calling build.

The first call is a barrier with layout transition from PresentSrc -> TransferDstOptimal so that the image may be cleared. The second is a transition from TransferDstOptimal -> PresentSrc so that it is ready for present. If I print out the current_layout and new_layout within the add_image_memory_barrier it seems to be called correctly with both layout transitions, so it seems my incorrect-image-layout-theory is a dead-end.

Actual Err result trace

The exact place from which the error is returned is via the following trace:

  • GpuFuture::then_execute
  • CommandBuffer::execute_after
  • SyncCommandBuffer::lock_submit (via CommandBuffer::lock_submit impl)
  • SwapchainAcquireFuture::check_image_access (via Future::check_image_access)

The SwapchainAcquireFuture::check_image_access impl looks like this:

#[inline]
fn check_image_access(&self, image: &ImageAccess, layout: ImageLayout, _: bool, _: &Queue)
                      -> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
    let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
    if swapchain_image.image.internal_object() != image.inner().image.internal_object() {
        return Err(AccessCheckError::Unknown);
    }

    if self.swapchain.images[self.image_id]
        .undefined_layout
        .load(Ordering::Relaxed) && layout != ImageLayout::Undefined
    {
        println!("err a");
        return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
                                                requested: layout,
                                            }));
    }

    if layout != ImageLayout::Undefined && layout != ImageLayout::PresentSrc {
        println!("err b");
        return Err(AccessCheckError::Denied(AccessError::UnexpectedImageLayout {
                                                allowed: ImageLayout::PresentSrc,
                                                requested: layout,
                                            }));
    }

    Ok(None)
}

Specifically, it's the first condition that is met and that is that branch which returns the error.

The thing I find strange about the first condition is that:

self.swapchain.images[self.image_id]
        .undefined_layout
        .load(Ordering::Relaxed)

is returning true in order to get into this branch, however from my understanding the swapchain image does have a defined layout (PresentSrc) so I would have expected this to return false. If I comment out that first error condition, my program seems to run correctly downstream (the window clears with the correct colour) which supports the possibility that undefined_layout might be incorrect.

I will see if I can investigate further into this undefined_layout field.

mitchmindtree avatar Nov 20 '18 18:11 mitchmindtree

It looks like undefined_layout is initialised to true within Swapchain::new_inner, but a quick

grep -nr undefined_layout ./vulkano/src/

shows that it can never be changed from this. The only other time the field seems to get read is within the SwapchainAcquireImage::check_image_access which I mentioned is the source of the Err in my previous comment.

This leads me to believe that the source of the problem is either:

  1. Swapchain images do initially start with ImageLayout::Undefined but are eventually changed to ImageLayout::PresentSrc and undefined_layout should be changed to false when this happens but currently is not or

  2. Swapchain images always initialise with ImageLayout::PresentSrc and this field is unnecessary, meaning that the error branch I'm currently hitting is unnecessary.

Will do some investigating into this.

mitchmindtree avatar Nov 20 '18 18:11 mitchmindtree

@mitchmindtree Thanks for your investigation. I use Ash now, that let me more liberty.

realitix avatar Nov 21 '18 15:11 realitix