Descriptor aliasing with sampler2D and sampler2DArray on the same binding triggers VUID-vkCmdDraw-viewType-07752 error (Validation Layers 1.4.304+)
Environment:
- OS: Arch Linux x86-64
- GPU: NVIDIA GeForce RTX 4090
- GPU driver: 570.124.04
- Vulkan SDK Version: 1.4.304
- Vulkan Validation Layers:
- 1.4.304 (self-built; note that the Arch Linux vulkan-validation-layers package currently fails with a
VK_ERROR_LAYER_NOT_PRESENTerror — I'll report this on Arch Linux GitLab soon) - 1.4.309 (Git head trunk)
- 1.4.304 (self-built; note that the Arch Linux vulkan-validation-layers package currently fails with a
- Previous Validation Layers: 1.3.296 (did not trigger this error)
Description:
I'm encountering an issue with descriptor aliasing in my Vulkan project PasVulkan. I use the same binding for both a sampler2D and a sampler2DArray, which according to the spec should be allowed as long as the types are compatible. However, when running with validation layers 1.4.304 and 1.4.309 (Git head trunk), I get a VUID-vkCmdDraw-viewType-07752 error stating that a VK_IMAGE_VIEW_TYPE_2D_ARRAY is bound to a sampler2D (non-arrayed) image type. This error did not occur with validation layers 1.3.296.
Below is one of the error messages I receive:
[Debug] ERROR: VALIDATION - Message ID number: 1944932341 - Message ID name: VUID-vkCmdDraw-viewType-07752
Validation Error: [ VUID-vkCmdDraw-viewType-07752 ] Object 0: handle = 0xd7acbf000000058b, type = VK_OBJECT_TYPE_DESCRIPTOR_SET; Object 1: handle = 0x4db5e000000004b4, name = TpvScene3DPlanet.TData[-1].fBlendMapImage.ArrayImageView, type = VK_OBJECT_TYPE_IMAGE_VIEW; | MessageID = 0x73ed4ff5 | vkCmdDraw(): the descriptor VkDescriptorSet 0xd7acbf000000058b[] [Set 2, Binding 0, Index 2, variable "uPlanetTextures"] ImageView type is VK_IMAGE_VIEW_TYPE_2D_ARRAY but the OpTypeImage has (Dim = 2D) and (Arrayed = 0).
And another similar error:
[Debug] ERROR: VALIDATION - Message ID number: 1944932341 - Message ID name: VUID-vkCmdDraw-viewType-07752
Validation Error: [ VUID-vkCmdDraw-viewType-07752 ] Object 0: handle = 0x4b1c0000000058c, type = VK_OBJECT_TYPE_DESCRIPTOR_SET; Object 1: handle = 0x350f8f000000048a, name = TpvScene3DPlanet.fBrushesTexture.ImageView, type = VK_OBJECT_TYPE_IMAGE_VIEW; | MessageID = 0x73ed4ff5 | vkCmdDraw(): the descriptor VkDescriptorSet 0x4b1c0000000058c[] [Set 2, Binding 0, Index 5, variable "uPlanetTextures"] ImageView type is VK_IMAGE_VIEW_TYPE_2D_ARRAY but the OpTypeImage has (Dim = 2D) and (Arrayed = 0).
Additional Information:
-
The shader snippet causing the issue is:
layout(set = 2, binding = 0) uniform sampler2D uPlanetTextures[]; layout(set = 2, binding = 0) uniform sampler2DArray uPlanetArrayTextures[]; -
This usage worked without error using validation layers 1.3.296.
-
For further context, additional shader files from my project are available, in preprocessed form through a C preprocessor so that there are no ifdefs, includes, comments, etc.: planet_shaders.zip
planet_grass_preprocessed.fragplanet_renderpass_preprocessed.fragplanet_water_preprocessed.fragplanet_grass_preprocessed.meshplanet_grass_preprocessed.taskplanet_grass_preprocessed.vert
These files provide more context on how descriptor aliasing is used in a complete rendering pipeline.
Steps to Reproduce:
- Use the shader code provided below to create a minimal test case.
- Compile and run an application that uses these shaders with Vulkan validation layers 1.4.304 or later.
- Observe the validation error regarding the mismatched image view type.
Expected Behavior:
Descriptor aliasing should be allowed provided the types are compatible, and the validation layers should not report an error if the usage conforms to the spec.
Actual Behavior:
Validation layers report a VUID-vkCmdDraw-viewType-07752 error, indicating that a VK_IMAGE_VIEW_TYPE_2D_ARRAY is bound to a sampler2D (non-arrayed) image type.
Minimal Test Case:
Vertex Shader (minimal.vert):
#version 450
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inUV;
layout(location = 0) out vec2 uv;
void main() {
uv = inUV;
gl_Position = vec4(inPos, 0.0, 1.0);
}
Fragment Shader (minimal.frag):
#version 450
// Using descriptor aliasing: same binding for sampler2D and sampler2DArray.
layout(set = 2, binding = 0) uniform sampler2D uPlanetTextures[];
layout(set = 2, binding = 0) uniform sampler2DArray uPlanetArrayTextures[];
layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 fragColor;
void main() {
// Sample from the first element of each texture array.
vec4 color1 = texture(uPlanetTextures[0], uv);
vec4 color2 = texture(uPlanetArrayTextures[1], vec3(uv, 0.0));
fragColor = mix(color1, color2, 0.5);
}
Further Shader Files (for completeness):
Further Vertex Shader (further_minimal.vert):
#version 450
// Input vertex attributes.
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inUV;
// Pass UV coordinates to the fragment shader.
layout(location = 0) out vec2 uv;
void main() {
uv = inUV;
gl_Position = vec4(inPos, 0.0, 1.0);
}
Further Fragment Shader (further_minimal.frag):
#version 450
// Descriptor aliasing: binding 0 of set 2 is used for both sampler2D and sampler2DArray.
layout(set = 2, binding = 0) uniform sampler2D uPlanetTextures[];
layout(set = 2, binding = 0) uniform sampler2DArray uPlanetArrayTextures[];
// UV coordinates received from the vertex shader.
layout(location = 0) in vec2 uv;
// Output color.
layout(location = 0) out vec4 fragColor;
void main() {
// Sample from index 0 of each texture array.
vec4 texColor1 = texture(uPlanetTextures[0], uv);
vec4 texColor2 = texture(uPlanetArrayTextures[1], vec3(uv, 0.0));
// Mix the two sampled colors.
fragColor = mix(texColor1, texColor2, 0.5);
}
Important Clarification:
Although the shader snippet shows both sampler2D and sampler2DArray sharing the same binding, they are used with different descriptor array indices in practice. Even after ensuring each sampler references its own index (i.e., there is no overlap in the actual runtime usage), the validation layers still trigger the VUID-vkCmdDraw-viewType-07752 error. Thus, the underlying issue remains unresolved despite correcting any “typo” in the sample code.
I suspect this may be a bug in the new validation layers. Any insights or suggestions are welcome.
Thanks for your attention!
So looked at right now, tl;dr we defer a lot of descriptor indexing related things to GPU-AV (because it is hard to statically prove things are correct)
Alias bindings have caused an issue in the past, wrote a test, can reproduce. Just need to decide if something we can properly detect or if I also need to kick this off to GPU-AV
(This example is simple, but once people start passing things through functions and other clever stuff, can be hard to know for sure)
@BeRo1985 sorry, after trying to make my PR I found this test failing
// This should be an GLSL error, if both of these are accessed (without PARTIALLY_BOUND), you need to satisfy both, which is impossible
layout(set = 0, binding = 0) uniform texture2D float_textures[2];
layout(set = 0, binding = 0) uniform utexture2D uint_textures[2];
This has been discussed (at great lengths) and without VK_EXT_descriptor_indexing this is not valid to go
layout(set = 2, binding = 0) uniform sampler2D uPlanetTextures[];
layout(set = 2, binding = 0) uniform sampler2DArray uPlanetArrayTextures[];
Because while it works for most devices, there are known drivers/hw that can't handle this and that is why VK_EXT_descriptor_indexing was created in the first place
I use the same binding for both a sampler2D and a sampler2DArray, which according to the spec should be allowed as long as the types are compatible.
Where did you find this, that might be a spec oversight
I use the same binding for both a sampler2D and a sampler2DArray, which according to the spec should be allowed as long as the types are compatible.
Where did you find this, that might be a spec oversight
Good question. I still had that in my head from a long time ago, when I read up on descriptor aliasing, what's legal and what's not. I'll see if I can find it again.
closing - confirmed with working group that this is not allowed without VK_EXT_descriptor_indexing (which is widely supported now)