فهرست منبع

[spirv] Add support for texture .GatherCmp() method (#697)

Lei Zhang 8 سال پیش
والد
کامیت
52372b1186

+ 11 - 0
docs/SPIR-V.rst

@@ -1429,6 +1429,17 @@ There are a few overloads for these functions:
   instruction. So those offset parameters must all be constant values.
   instruction. So those offset parameters must all be constant values.
 - Those overloads with the status parameter are not supported.
 - Those overloads with the status parameter are not supported.
 
 
+``.GatherCmp()``
+++++++++++++++++
+
+Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
+``TextureCubeArray``.
+
+The translation is similar to ``.Sample()``, but the ``OpImageDrefGather``
+instruction is used.
+
+The overload with the status parameter are not supported.
+
 ``.Load(location[, sampleIndex][, offset])``
 ``.Load(location[, sampleIndex][, offset])``
 ++++++++++++++++++++++++++++++++++++++++++++
 ++++++++++++++++++++++++++++++++++++++++++++
 
 

+ 3 - 2
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -193,8 +193,9 @@ public:
   uint32_t createImageGather(uint32_t texelType, uint32_t imageType,
   uint32_t createImageGather(uint32_t texelType, uint32_t imageType,
                              uint32_t image, uint32_t sampler,
                              uint32_t image, uint32_t sampler,
                              uint32_t coordinate, uint32_t component,
                              uint32_t coordinate, uint32_t component,
-                             uint32_t constOffset, uint32_t varOffset,
-                             uint32_t constOffsets, uint32_t sample);
+                             uint32_t compareVal, uint32_t constOffset,
+                             uint32_t varOffset, uint32_t constOffsets,
+                             uint32_t sample);
 
 
   /// \brief Creates a select operation with the given values for true and false
   /// \brief Creates a select operation with the given values for true and false
   /// cases and returns the <result-id> for the result.
   /// cases and returns the <result-id> for the result.

+ 13 - 4
tools/clang/lib/SPIRV/ModuleBuilder.cpp

@@ -418,8 +418,9 @@ uint32_t ModuleBuilder::createImageFetchOrRead(
 
 
 uint32_t ModuleBuilder::createImageGather(
 uint32_t ModuleBuilder::createImageGather(
     uint32_t texelType, uint32_t imageType, uint32_t image, uint32_t sampler,
     uint32_t texelType, uint32_t imageType, uint32_t image, uint32_t sampler,
-    uint32_t coordinate, uint32_t component, uint32_t constOffset,
-    uint32_t varOffset, uint32_t constOffsets, uint32_t sample) {
+    uint32_t coordinate, uint32_t component, uint32_t compareVal,
+    uint32_t constOffset, uint32_t varOffset, uint32_t constOffsets,
+    uint32_t sample) {
   assert(insertPoint && "null insert point");
   assert(insertPoint && "null insert point");
 
 
   // An OpSampledImage is required to do the image sampling.
   // An OpSampledImage is required to do the image sampling.
@@ -435,8 +436,16 @@ uint32_t ModuleBuilder::createImageGather(
           /*bias*/ 0, /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
           /*bias*/ 0, /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
           constOffsets, sample, &params));
           constOffsets, sample, &params));
   const uint32_t texelId = theContext.takeNextId();
   const uint32_t texelId = theContext.takeNextId();
-  instBuilder.opImageGather(texelType, texelId, sampledImgId, coordinate,
-                            component, mask);
+
+  if (compareVal) {
+    // Note: OpImageDrefGather does not take the component parameter.
+    instBuilder.opImageDrefGather(texelType, texelId, sampledImgId, coordinate,
+                                  compareVal, mask);
+  } else {
+    instBuilder.opImageGather(texelType, texelId, sampledImgId, coordinate,
+                              component, mask);
+  }
+
   for (const auto param : params)
   for (const auto param : params)
     instBuilder.idRef(param);
     instBuilder.idRef(param);
   instBuilder.x();
   instBuilder.x();

+ 44 - 8
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -1720,11 +1720,7 @@ uint32_t SPIRVEmitter::processTextureGatherRGBA(const CXXMemberCallExpr *expr,
   uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
   uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
   if (numArgs == 3) {
   if (numArgs == 3) {
     // One offset parameter
     // One offset parameter
-    const uint32_t offset = tryToEvaluateAsConst(expr->getArg(2));
-    if (offset)
-      constOffset = offset;
-    else
-      varOffset = offset;
+    handleOptionalOffsetInMethodCall(expr, 2, &constOffset, &varOffset);
   } else {
   } else {
     // Four offset parameters
     // Four offset parameters
     const auto offset0 = tryToEvaluateAsConst(expr->getArg(2));
     const auto offset0 = tryToEvaluateAsConst(expr->getArg(2));
@@ -1751,8 +1747,45 @@ uint32_t SPIRVEmitter::processTextureGatherRGBA(const CXXMemberCallExpr *expr,
 
 
   return theBuilder.createImageGather(
   return theBuilder.createImageGather(
       retType, imageType, image, sampler, coordinate,
       retType, imageType, image, sampler, coordinate,
-      theBuilder.getConstantInt32(component), constOffset, varOffset,
-      constOffsets, /*sampleNumber=*/0);
+      theBuilder.getConstantInt32(component), /*compareVal*/ 0, constOffset,
+      varOffset, constOffsets, /*sampleNumber*/ 0);
+}
+
+uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
+  // Signature:
+  //
+  // float4 GatherCmp(
+  //   in SamplerComparisonState s,
+  //   in float2 location,
+  //   in float compare_value
+  //   [,in int2 offset]
+  // );
+  const FunctionDecl *callee = expr->getDirectCallee();
+  const auto numArgs = expr->getNumArgs();
+
+  if (expr->getNumArgs() > 4) {
+    emitError("unsupported '%0' method call with status parameter",
+              expr->getExprLoc())
+        << callee->getName() << expr->getSourceRange();
+    return 0;
+  }
+
+  const auto *imageExpr = expr->getImplicitObjectArgument();
+
+  const uint32_t image = loadIfGLValue(imageExpr);
+  const uint32_t sampler = doExpr(expr->getArg(0));
+  const uint32_t coordinate = doExpr(expr->getArg(1));
+  const uint32_t comparator = doExpr(expr->getArg(2));
+  uint32_t constOffset = 0, varOffset = 0;
+  handleOptionalOffsetInMethodCall(expr, 3, &constOffset, &varOffset);
+
+  const auto retType = typeTranslator.translateType(callee->getReturnType());
+  const auto imageType = typeTranslator.translateType(imageExpr->getType());
+
+  return theBuilder.createImageGather(
+      retType, imageType, image, sampler, coordinate,
+      /*component*/ 0, comparator, constOffset, varOffset, /*constOffsets*/ 0,
+      /*sampleNumber*/ 0);
 }
 }
 
 
 uint32_t SPIRVEmitter::processBufferTextureLoad(const Expr *object,
 uint32_t SPIRVEmitter::processBufferTextureLoad(const Expr *object,
@@ -2051,6 +2084,8 @@ SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
     return processTextureGatherRGBA(expr, 2);
     return processTextureGatherRGBA(expr, 2);
   case IntrinsicOp::MOP_GatherAlpha:
   case IntrinsicOp::MOP_GatherAlpha:
     return processTextureGatherRGBA(expr, 3);
     return processTextureGatherRGBA(expr, 3);
+  case IntrinsicOp::MOP_GatherCmp:
+    return processTextureGatherCmp(expr);
   case IntrinsicOp::MOP_Load:
   case IntrinsicOp::MOP_Load:
     return processBufferTextureLoad(expr);
     return processBufferTextureLoad(expr);
   case IntrinsicOp::MOP_Load2:
   case IntrinsicOp::MOP_Load2:
@@ -2128,7 +2163,8 @@ uint32_t SPIRVEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
     return theBuilder.createImageGather(
     return theBuilder.createImageGather(
         retType, imageType, image, sampler, coordinate,
         retType, imageType, image, sampler, coordinate,
         // .Gather() doc says we return four components of red data.
         // .Gather() doc says we return four components of red data.
-        theBuilder.getConstantInt32(0), constOffset, varOffset,
+        theBuilder.getConstantInt32(0), /*compareVal*/ 0, constOffset,
+        varOffset,
         /*constOffsets*/ 0, /*sampleNumber*/ 0);
         /*constOffsets*/ 0, /*sampleNumber*/ 0);
   }
   }
 }
 }

+ 3 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.h

@@ -507,6 +507,9 @@ private:
   uint32_t processTextureGatherRGBA(const CXXMemberCallExpr *expr,
   uint32_t processTextureGatherRGBA(const CXXMemberCallExpr *expr,
                                     uint32_t component);
                                     uint32_t component);
 
 
+  /// \brief Handles .GatherCmp() calls on texture types.
+  uint32_t processTextureGatherCmp(const CXXMemberCallExpr *expr);
+
   /// \brief Returns the calculated level-of-detail (a single float value) for
   /// \brief Returns the calculated level-of-detail (a single float value) for
   /// the given texture. Handles intrinsic HLSL CalculateLevelOfDetail function.
   /// the given texture. Handles intrinsic HLSL CalculateLevelOfDetail function.
   uint32_t processTextureLevelOfDetail(const CXXMemberCallExpr *expr);
   uint32_t processTextureLevelOfDetail(const CXXMemberCallExpr *expr);

+ 40 - 0
tools/clang/test/CodeGenSPIRV/texture.array.gather-cmp.hlsl

@@ -0,0 +1,40 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture2DArray<float4> t1 : register(t1);
+Texture2DArray<float2> t2 : register(t2);
+Texture2DArray<float>  t3 : register(t3);
+// .GatherCmp() does not support Texture1DArray.
+// .GatherCmp() for TextureCubeArray requires the status parameter.
+
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
+
+float4 main(float3 location: A, float comparator: B, int2 offset: C) : SV_Target {
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[v2ic]]
+    float4 val1 = t1.GatherCmp(gSampler, location, comparator, int2(1, 2));
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[v3fc]] [[comparator]]
+    float4 val2 = t2.GatherCmp(gSampler, float3(0.1, 0.2, 0.3), comparator);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_2d_image_array %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v3float %location
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:     [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
+    float4 val3 = t3.GatherCmp(gSampler, location, comparator, offset);
+
+    return 1.0;
+}

+ 40 - 0
tools/clang/test/CodeGenSPIRV/texture.gather-cmp.hlsl

@@ -0,0 +1,40 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture2D<float4> t1 : register(t1);
+Texture2D<float2> t2 : register(t2);
+Texture2D<float>  t3 : register(t3);
+// .GatherCmp() does not support Texture1D and Texture3D.
+// .GatherCmp() for TextureCube requires the status parameter.
+
+// CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
+
+float4 main(float2 location: A, float comparator: B, int2 offset: C) : SV_Target {
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t1
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[v2ic]]
+    float4 val1 = t1.GatherCmp(gSampler, location, comparator, int2(1, 2));
+
+// CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t2
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t2]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[v2fc]] [[comparator]]
+    float4 val2 = t2.GatherCmp(gSampler, float2(0.1, 0.2), comparator);
+
+// CHECK:              [[t3:%\d+]] = OpLoad %type_2d_image %t3
+// CHECK-NEXT:   [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:        [[loc:%\d+]] = OpLoad %v2float %location
+// CHECK-NEXT: [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:     [[offset:%\d+]] = OpLoad %v2int %offset
+// CHECK-NEXT: [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image [[t3]] [[gSampler]]
+// CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
+    float4 val3 = t3.GatherCmp(gSampler, location, comparator, offset);
+
+    return 1.0;
+}

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

@@ -410,6 +410,10 @@ TEST_F(FileTest, TextureGatherAlpha) {
 TEST_F(FileTest, TextureArrayGatherAlpha) {
 TEST_F(FileTest, TextureArrayGatherAlpha) {
   runFileTest("texture.array.gather-alpha.hlsl");
   runFileTest("texture.array.gather-alpha.hlsl");
 }
 }
+TEST_F(FileTest, TextureGatherCmp) { runFileTest("texture.gather-cmp.hlsl"); }
+TEST_F(FileTest, TextureArrayGatherCmp) {
+  runFileTest("texture.array.gather-cmp.hlsl");
+}
 TEST_F(FileTest, TextureSampleLevel) {
 TEST_F(FileTest, TextureSampleLevel) {
   runFileTest("texture.sample-level.hlsl");
   runFileTest("texture.sample-level.hlsl");
 }
 }