GPUOpen-Drivers / AMDVLK

AMD Open Source Driver For Vulkan
MIT License
1.69k stars 160 forks source link

CS rejected: descriptor with destroyed VkImageView despite VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT #329

Closed xatian closed 1 month ago

xatian commented 1 year ago

I got a shader that uses a texture array. layout(set = 0, binding = 1) uniform texture2D textures[count]; I am also using the feature descriptorBindingPartiallyBound since I don't have all textures available when the application starts. At some point I got a descriptor set with some of the texture-slots written to and used by the shader. All is fine.

Then I would like to destroy on of the used textures and free it's memory. So I destroy the VkImageView, the VkImage and free the VkMemory. I do this in between frames where nothing is accessing the descriptor set and all command buffers are reset. For the next frame I bind the descriptor set and want to draw again --> but the VkImageView is still written to the "slot" in the descriptor set.

When I call vkCmdBindDescriptorSets valgrind shows an error in the driver-code:

==60360== Invalid read of size 4
==60360==    at 0x12A71D76: ??? (in /usr/lib/x86_64-linux-gnu/libvulkan_radeon.so)
==60360==    by 0x129F219F: ??? (in /usr/lib/x86_64-linux-gnu/libvulkan_radeon.so)
==60360==    by 0x14F1590C: ??? (in /usr/lib/x86_64-linux-gnu/libVkLayer_khronos_validation.so)
==60360==    by 0x14E48052: ??? (in /usr/lib/x86_64-linux-gnu/libVkLayer_khronos_validation.so)

When I then want to submit the command buffer by calling vkQueueSubmit this error message is printed: radv/amdgpu: The CS has been rejected, see dmesg for more information (-2). There is nothing written to dmesg.

Two additional points:

My question is --> is this a bug in the driver or is my behavior invalid according to the vulkan spec? I am not sure if it is valid to have a destroyed image still referenced by the descriptor set ... vulkan spec says that with descriptorBindingPartiallyBound enabled all not used slots are allowed to be invalid. I don't know if invalid just means empty or also destroyed?!

I am sorry if I misinterpreted the spec and this is a bug in my design. If this behavior should work I could provide a minimal example to replicate this issue. Thank you!

ravi688 commented 1 year ago

I think it is not valid to reference a destroyed image by a descriptor. Also I've tried descriptor sets in which none of the descriptors in it were written/updated, that was working just fine no validation errors.

xatian commented 12 months ago

https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkDescriptorBindingFlagBits.html It says in part:

VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT indicates that descriptors in this binding that are not dynamically used need not contain valid descriptors at the time the descriptors are consumed. A descriptor is dynamically used if any shader invocation executes an instruction that performs any memory access using the descriptor. If a descriptor is not dynamically used, any resource referenced by the descriptor is not considered to be referenced during command execution.

To me that sounds as if destroyed ImageViews referenced by descriptors is fine, as long as they are not dynamically used by the shader. Empty descriptors work without issue. My issue is about destroyed ones.

xatian commented 12 months ago

With help I found some more language in the spec that sounds like this should work: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/vkAllocateDescriptorSets.html

When a descriptor set is allocated, the initial state is largely uninitialized and all descriptors are undefined, with the exception that samplers with a non-null pImmutableSamplers are initialized on allocation. Descriptors also become undefined if the underlying resource or view object is destroyed. Descriptor sets containing undefined descriptors can still be bound and used, subject to the following conditions:

For descriptor set bindings created with the VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT bit set, all descriptors in that binding that are dynamically used must have been populated before the descriptor set is consumed.

xatian commented 12 months ago

I made a test application with these basic steps:

  1. create all needed VulkanHandles
  2. activate descriptorBindingPartiallyBound
  3. create a basic pipeline with a texture2DArray[2] as the only binding
  4. set VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT when creating the vkCreateDescriptorSetLayout
  5. create 2 VkImages + VkImageViews and wrote both to a vkDescriptorSet
  6. destroyed the second one (VkImage, VkImageView and freed VkMemory)
  7. recording into command buffer -> vkBeginCommandBuffer, vkCmdBeginRenderPass, vkCmdBindPipeline, vkCmdBindDescriptorSets, vkCmdEndRenderPass, vkEndCommandBuffer, vkQueueSubmit.

This would draw a frame containing nothing yet it does what I stated in the initial post --> it gets rejected. If I skip 6.) all works fine (--> the crucial part in 6. is the vkFreeMemory) Including with the relevant parts from the spec I strongly believe this should work and it is in fact a bug in the driver.

nythrix commented 2 weeks ago

@xatian Do you still have the code that demonstrates this issue? I think, I am seeing the same thing and I would like to verify.

jinjianrong commented 2 weeks ago

The test is run with RADV. Please try with amdvlk.

nythrix commented 1 week ago

@jinjianrong Oh, thanks for the clarification! Will do.