Bug 106646

Summary: Support VK_IMAGE_USAGE_STORAGE_BIT for WSI swapchain surfaces
Product: Mesa Reporter: Niklas Haas <bugs.freedesktop>
Component: Drivers/Vulkan/CommonAssignee: Jason Ekstrand <jason>
Status: RESOLVED MOVED QA Contact:
Severity: enhancement    
Priority: medium CC: airlied, chadversary, daniel, jason, lemody
Version: git   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:

Description Niklas Haas 2018-05-25 04:19:54 UTC
It would appear as though RADV (and ANV, judging by the code) on both X11 and Wayland only support the following hard-coded list of VkImageUsageFlags:

   caps->supportedUsageFlags =
      VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
      VK_IMAGE_USAGE_SAMPLED_BIT |
      VK_IMAGE_USAGE_TRANSFER_DST_BIT |
      VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;

Could we get VK_IMAGE_USAGE_STORAGE_BIT added to this list? Other Vulkan implementations I looked at (NVIDIA and AMDVLK) both support it, and simply adding it to the list seems to work just fine for me. (on RADV+X11, not sure about ANV or Wayland)

Use case: I have a rendering pipeline (mpv/vlc/libplacebo) that may involve the use of a compute shader during the final output step, in order to do HDR peak detection. If the swapchain image supports STORAGE_BIT then I can directly paint to screen without needing to allocate an intermediate texture and roundtrip through a fragment shader unnecessarily.
Comment 1 Tapani Pälli 2018-05-25 05:05:49 UTC
FYI, VK_IMAGE_USAGE_STORAGE_BIT bit is required to pass dEQP-VK.wsi.android.*  tests.
Comment 2 Jason Ekstrand 2018-05-25 05:19:40 UTC
I'd really like to support this in anv but it isn't as trivial as it looks.  The only 32-bit image format supported by X11 is B8G8R8A8_UNORM which is not one of the standard storage image formats.  I think Wayland is basically the same.  Since anv requires a format to be specified in the shader for storage image reads, it's a bit tricky to support B8G8R8A8_UNORM because there is no SPIR-V enum for it.  I've actually been looking into how to best support it for the last couple of weeks and have a few ideas but nothing solid yet.
Comment 3 Niklas Haas 2018-05-25 06:42:38 UTC
> I'd really like to support this in anv but it isn't as trivial as it looks.  The only 32-bit image format supported by X11 is B8G8R8A8_UNORM which is not one of the standard storage image formats. 

Actually, the same is true for RADV. I'm pretty sure that the relevant storage format here is “rgba8”, although I'm not too sure on the specifics of how the various standards interact here. One the one hand, the vulkan spec makes the claim that the OpTypeImage's Image Format must be “compatible” with the VkImageView's format. (This claim is made under the section governing texel input operations, specifically 15.3.1)

It links to the following compatibility table:
https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#spirvenv-image-formats

This table makes the claim that the rgba8 storage format is only compatible with exactly VK_FORMAT_R8G8B8A8_UNORM. So going by this, apart from using the “ωrite without layout” feature, you could still make it work by creating an rgba8 VkImageView of the bgra8 texture, and then using that as your VkDescriptorImageView.imageView. This should be possible with ANV as well.

However, confusingly, https://www.khronos.org/opengl/wiki/Image_Load_Store#Format_conversion makes the claim that image formats as used in the shader can differ from the actual texture under a given set of circumstances, which include such normalizations as allowing rgba8 instead of bgra8, and this is treated as a concept that is distinct from the opengl concept of a texture view. So perhaps the vulkan spec either needs to be updated here to match reality, or it was deliberately changed in vulkan and it's just working by accident for me?

Because in practice, I found that using "rgba8" for B8G8R8A8_UNORM works just fine on all three implementations I tested (NVIDIA, RADV, AMDVLK), and none of the shader validation layers seem to complain about it either. The channel order is the correct way around (the shader samples as rgba). So maybe I am misinterpreting the vulkan standard here, and a VkImageView is not actually required? Either way, it seems that it should be possible via one of these methods.
Comment 4 Jason Ekstrand 2018-05-26 05:44:30 UTC
(In reply to Niklas Haas from comment #3)
> However, confusingly,
> https://www.khronos.org/opengl/wiki/Image_Load_Store#Format_conversion makes
> the claim that image formats as used in the shader can differ from the
> actual texture under a given set of circumstances, which include such
> normalizations as allowing rgba8 instead of bgra8, and this is treated as a
> concept that is distinct from the opengl concept of a texture view. So
> perhaps the vulkan spec either needs to be updated here to match reality, or
> it was deliberately changed in vulkan and it's just working by accident for
> me?

First off, the wiki is not the spec. :-)  The GL_ARB_image_load_store spec says, very clearly,

> Any image variable used for shader loads or atomic memory operations must
> be declared with a format layout qualifier matching the format of its
> associated image unit, as enumerated in Table X.2.

And Table X.2 is identical to the Vulkan table.  The mismatch they're talking about is between the the image unit and the underlying texture.  This is exactly the texture view scenario though it goes by a bit of a different name.

> Because in practice, I found that using "rgba8" for B8G8R8A8_UNORM works
> just fine on all three implementations I tested (NVIDIA, RADV, AMDVLK), and
> none of the shader validation layers seem to complain about it either. The
> channel order is the correct way around (the shader samples as rgba). So
> maybe I am misinterpreting the vulkan standard here, and a VkImageView is
> not actually required? Either way, it seems that it should be possible via
> one of these methods.

I've considered going down this path.  It would work on our implementation for something like bgra8 but it would fall flat on our implementation if, for instance, we tried to support B10G10R10A2_UINT that way.  The shader badly needs to know the channel order if it has to do any real unpacking of the data.

Another option for supporting this that I've considered is to simply expose the VK_IMAGE_USAGE_STORAGE_BIT for it and only allow BGRA8 to be used if the shader variable has an Unknown format and is NonReadable.  We support shaderStorageImageWriteWithoutFormat and we can support BGRA8 without a shader format.  This would allow for writing to WSI images from compute shaders but wouldn't allow reading.  Maybe that's enough?
Comment 5 Bas Nieuwenhuizen 2018-05-27 01:26:20 UTC
FWIW, in radv we completely ignore the shader specified formats, so we could just enable this for radv?
Comment 6 Jason Ekstrand 2018-05-27 01:34:35 UTC
(In reply to Bas Nieuwenhuizen from comment #5)
> FWIW, in radv we completely ignore the shader specified formats, so we could
> just enable this for radv?

I think so.  The spec is all a bit weird but I think that, if you support both shaderStorageImageReadWithoutFormat and shaderStorageImageWriteWithoutFormat, you should be able to turn on any storage formats you'd like.
Comment 7 GitLab Migration User 2019-09-18 18:13:08 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/mesa/mesa/issues/178.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.