Reputation: 2314
I have a compute shader that reads a signed normalized integer image using imageLoad
.
The image itself (which contains both positive and negative values) is created as a R16G16_SNORM
and is written by a fragment shader in a previous gpass.
The imageview bound to the descriptorsetlayout binding in the compute shader is also created with the same R16G16_SNORM
format.
Everything works as expected.
Yesterday I realized that in the compute shader I used the wrong image format qualifier rg16
.
A bit puzzled (I could not understand how it could work properly reading an unsigned normalized value) I corrected to rg16_snorm
, and.. nothing changed.
I performed several tests (I even specified a rg16f
) and always had the same (correct, [-1,1] signed) result.
It seems like Vulkan (at least my implementation) silently ignores any image format qualifier, and falls back (I guess) to the imageview format bound to the descriptorset.
This seems to be in line with the spec regarding format in imageview creation
format is a VkFormat describing the format and type used to interpret texel blocks in the image
but then in Appendix A (Vulkan Environment for SPIR-V - "Compatibility Between SPIR-V Image Formats And Vulkan Formats") there is a clear distinction between Rg16 and Rg16Snorm.. so:
is it a bug or a feature?
I am working with an Nvidia 2070 Super under ubuntu 20.04
UPDATE
The initial image writing operation happens as the result of a fragment shader color attachment output, and as such, there is no descriptorsetlayout binding declaration. The fragment shader outputs a vec2
to the R16G16_SNORM
color attachment as specified by the active framebuffer and renderpass.
The resulting image (after the relevant barriers) is then read (correctly, despite the wrong layout qualifier) by a compute shader as an image/imageLoad operation.
Note that validation layers are enabled and silent.
Note also that the resulting values are far from random, and exactly match the expected values (both positive and negative), using either rg16
, rg16f
or rg16_snorm
.
Upvotes: 2
Views: 916
Reputation: 473262
What you're getting is undefined behavior.
There is a validation check on Image Write Operations that prevents the OpTypeImage
's format (equivalent to the layout
format specifier in GLSL) from being incompatible with the backing VkImageView
's format:
If the image format of the
OpTypeImage
is not compatible with theVkImageView
’s format, the write causes the contents of the image’s memory to become undefined.
Note that when it says "compatible", it doesn't mean image view compatibility; it means "exactly match". Your OpTypeImage
format did not exactly match that of the shader, so your writes were undefined. And "undefined" can mean "works as if you had specified the correct format".
Upvotes: 1