Переглянути джерело

[spirv] Hack OpSampledImage for depth-comparison sampling (#1191)

Drivers are expecting to see the Dpeth hint to be 1 in OpTypeImage
for OpImageSample*Dref* instructions. Hack to get the OpTypeImage
have the expected hint for OpSampledImage.
Lei Zhang 7 роки тому
батько
коміт
0f165c6483

+ 10 - 1
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -4072,7 +4072,16 @@ SPIRVEmitter::processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
   const uint32_t lod = isCmp ? 0 : theBuilder.getConstantFloat32(0);
 
   const auto retType = expr->getDirectCallee()->getReturnType();
-  const auto imageType = typeTranslator.translateType(imageExpr->getType());
+  // TODO: Hack. Drivers are expecting the Depth value in OpTypeImage to match
+  // the OpImageSample* instruction: Depth=0 for normal sampling, and Depth=1
+  // for depth-comparison sampling. That behavior is not what the spec says;
+  // Vulkan spec reads "The 'Depth' operand of OpTypeImage is ignored."
+  // We always generate OpTypeImage variables with Depth=0. Hack this only
+  // depth-comparison sampling code path to use Depth=1 for the OpTypeImage
+  // used by OpSampledImage. This causes inconsistent types in SPIR-V, but
+  // pleases drivers. Whatever.
+  const auto imageType = typeTranslator.translateResourceType(
+      imageExpr->getType(), LayoutRule::Void, /*isDepthCmp=*/true);
 
   return createImageSample(retType, imageType, image, sampler, coordinate,
                            compareVal, /*bias*/ 0, lod, std::make_pair(0, 0),

+ 3 - 2
tools/clang/lib/SPIRV/TypeTranslator.cpp

@@ -1261,7 +1261,8 @@ TypeTranslator::getLayoutDecorations(const DeclContext *decl, LayoutRule rule) {
   return decorations;
 }
 
-uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule) {
+uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule,
+                                               bool isDepthCmp) {
   // Resource types are either represented like C struct or C++ class in the
   // AST. Samplers are represented like C struct, so isStructureType() will
   // return true for it; textures are represented like C++ class, so
@@ -1291,7 +1292,7 @@ uint32_t TypeTranslator::translateResourceType(QualType type, LayoutRule rule) {
       const auto isMS = (name == "Texture2DMS" || name == "Texture2DMSArray");
       const auto sampledType = hlsl::GetHLSLResourceResultType(type);
       return theBuilder.getImageType(translateType(getElementType(sampledType)),
-                                     dim, /*depth*/ 0, isArray, isMS);
+                                     dim, isDepthCmp, isArray, isMS);
     }
 
     // There is no RWTexture3DArray

+ 5 - 4
tools/clang/lib/SPIRV/TypeTranslator.h

@@ -55,6 +55,11 @@ public:
   uint32_t translateType(QualType type,
                          LayoutRule layoutRule = LayoutRule::Void);
 
+  /// \brief Translates the given HLSL resource type into its SPIR-V
+  /// instructions and returns the <result-id>. Returns 0 on failure.
+  uint32_t translateResourceType(QualType type, LayoutRule rule,
+                                 bool isDepthCmp = false);
+
   /// \brief Generates the SPIR-V type for the counter associated with a
   /// {Append|Consume}StructuredBuffer: an OpTypeStruct with a single 32-bit
   /// integer value. This type will be decorated with BufferBlock.
@@ -280,10 +285,6 @@ private:
   /// constnesss and literalness.
   static bool canTreatAsSameScalarType(QualType type1, QualType type2);
 
-  /// \brief Translates the given HLSL resource type into its SPIR-V
-  /// instructions and returns the <result-id>. Returns 0 on failure.
-  uint32_t translateResourceType(QualType type, LayoutRule rule);
-
   /// \brief For the given sampled type, returns the corresponding image format
   /// that can be used to create an image object.
   spv::ImageFormat translateSampledTypeToImageFormat(QualType type);

+ 33 - 0
tools/clang/test/CodeGenSPIRV/texture.sample.sample-cmp.hlsl

@@ -0,0 +1,33 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK:        %type_2d_image = OpTypeImage %float 2D 0 0 0 1 Unknown
+// CHECK:   %type_sampled_image = OpTypeSampledImage %type_2d_image
+// CHECK:      %type_2d_image_0 = OpTypeImage %float 2D 1 0 0 1 Unknown
+// CHECK: %type_sampled_image_0 = OpTypeSampledImage %type_2d_image_0
+
+// CHECK: %gTexture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant
+Texture2D              gTexture;
+SamplerState           gSampler;
+SamplerComparisonState gCmpSampler;
+
+float4 main(float3 input : A) : SV_Target {
+  // Use OpSampledImage with Depth=0 OpTypeImage for normal sampling
+// CHECK: [[tex:%\d+]] = OpLoad %type_2d_image %gTexture
+// CHECK:  [[si:%\d+]] = OpSampledImage %type_sampled_image [[tex]]
+// CHECK:                OpImageSampleImplicitLod %v4float [[si]]
+
+  // Use OpSampledImage with Depth=1 OpTypeImage for depth-comparison sampling
+    float4 a = gTexture.Sample(gSampler, input.xy);
+// CHECK: [[tex:%\d+]] = OpLoad %type_2d_image %gTexture
+// CHECK:  [[si:%\d+]] = OpSampledImage %type_sampled_image_0 [[tex]]
+// CHECK:                OpImageSampleDrefImplicitLod %float [[si]]
+    float4 b = gTexture.SampleCmp(gCmpSampler, input.xy, input.z);
+
+  // Use OpSampledImage with Depth=1 OpTypeImage for depth-comparison sampling
+// CHECK: [[tex:%\d+]] = OpLoad %type_2d_image %gTexture
+// CHECK:  [[si:%\d+]] = OpSampledImage %type_sampled_image_0 [[tex]]
+// CHECK:                OpImageSampleDrefExplicitLod %float [[si]]
+    float4 c = gTexture.SampleCmpLevelZero(gCmpSampler, input.xy, input.z);
+
+    return a + b + c;
+}

+ 6 - 0
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -740,6 +740,12 @@ TEST_F(FileTest, TextureSampleCmpLevelZero) {
 TEST_F(FileTest, TextureArraySampleCmpLevelZero) {
   runFileTest("texture.array.sample-cmp-level-zero.hlsl");
 }
+TEST_F(FileTest, TextureNormalAndComparisonSample) {
+  // Check that we generate OpSampledImage derived from the appropriate
+  // OpTypeImage having the matching Depth value with the OpImageSample*
+  // instruction
+  runFileTest("texture.sample.sample-cmp.hlsl");
+}
 
 // For structured buffer methods
 TEST_F(FileTest, StructuredBufferLoad) {