[SPIR-V] Sampled image type requires an image type with "Sampled" operand set to 0 or 1
This issue is compute shader only in my case. In pixel (fragment) shader code, I wrote: const float4 baseColor = BaseColor[input.Pos.xy]; It's OK.
But in compute shader code, I wrote: const float4 baseColor = BaseColor[DTid]; It reports a compilation error:
fatal error: generated SPIR-V is invalid: [VUID-StandaloneSpirv-OpTypeImage-04657] Sampled image type requires an image type with "Sampled" operand set to 0 or 1
%31 = OpTypeSampledImage %type_2d_image_0
Full reproducible code:
[[vk::combinedImageSampler]] SamplerState Sampler : register (s0);
[[vk::combinedImageSampler]] Texture2D BaseColor : register (t0);
[[vk::combinedImageSampler]] SamplerState Sampler1 : register (s1);
[[vk::combinedImageSampler]] Texture2D BaseColor1 : register (t1);
RWTexture2D<float4> OutBuffer : register (u0);
[numthreads(8, 8, 1)]
void main(uint2 DTid : SV_DispatchThreadID)
{
float2 texSize;
BaseColor.GetDimensions(texSize.x, texSize.y);
const float2 uv = (DTid + 0.5) / texSize;
const float4 baseColor = BaseColor1[DTid];
OutBuffer[DTid] = baseColor.w > 0.0 ? baseColor : 0.0;
}
fatal error: generated SPIR-V is invalid: [VUID-StandaloneSpirv-OpTypeImage-04657] Sampled image type requires an image type with "Sampled" operand set to 0 or 1
%22 = OpTypeSampledImage %type_2d_image_0
Another trial:
[[vk::combinedImageSampler]] SamplerState Sampler : register (s0);
[[vk::combinedImageSampler]] Texture2D BaseColor : register (t0);
RWTexture2D<float4> OutBuffer : register (u0);
[numthreads(8, 8, 1)]
void main(uint2 DTid : SV_DispatchThreadID)
{
float2 texSize;
BaseColor.GetDimensions(texSize.x, texSize.y);
const float2 uv = (DTid + 0.5) / texSize;
const float4 baseColor = BaseColor.SampleLevel(Sampler, uv, 0.0);
OutBuffer[DTid] = baseColor.w > 0.0 ? baseColor : 0.0;
}
fatal error: failed to legalize SPIR-V:
note: please file a bug report on https://github.com/Microsoft/DirectXShaderCompiler/issues with source code if possible
It seems that the cause is the confliction of u0 and (t0, s0). DXC regards OutBuffer in u0 as the sampled image by mistake. Besides, glslang is good for the similar use cases, but I use DX9-style Sampler2D instead of [[vk::combinedImageSampler]] with glslang. However, glslang does not support [[vk::combinedImageSampler]], so it has no way to realize a texture combined with SamplerComparisonState by DX9 style.
Completed the reproducible code and root-cause analysis.
The spirv-opt pass that combines the sampler and the image into a combined image sampler, is modifying the RWTexture2D as well.
The source
[[vk::combinedImageSampler]] SamplerState Sampler : register (s0);
[[vk::combinedImageSampler]] Texture2D BaseColor : register (t0);
RWTexture2D<float4> OutBuffer : register (u0);
[numthreads(8, 8, 1)]
void main(uint2 DTid : SV_DispatchThreadID)
{
OutBuffer[DTid] = float4(0.0, 1.0, 2.0, 3.0);
}
The spir-v that does the type of %OutBuffer is
%type_2d_image_0 = OpTypeImage %float 2D 2 0 0 2 Rgba32f
%_ptr_UniformConstant_type_2d_image_0 = OpTypePointer UniformConstant %type_2d_image_0
%OutBuffer = OpVariable %_ptr_UniformConstant_type_2d_image_0 UniformConstant
After legalization
%type_2d_image = OpTypeImage %float 2D 2 0 0 2 Rgba32f
%19 = OpTypeSampledImage %type_2d_image ; <---- This causes the validation error
%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19
%OutBuffer = OpVariable %_ptr_UniformConstant_19 UniformConstant
Note that is the vk::combinedImageSampler attribute is removed, this change does not happen.