Ver código fonte

[spirv] Add support for texture .GatherCmpRed() method (#700)

Lei Zhang 8 anos atrás
pai
commit
2e1ea68d6c

+ 10 - 0
docs/SPIR-V.rst

@@ -1440,6 +1440,16 @@ instruction is used.
 
 The overload with the status parameter are not supported.
 
+``.GatherCmpRed()``
++++++++++++++++++++
+
+Available to ``Texture2D``, ``Texture2DArray``, ``TextureCube``, and
+``TextureCubeArray``.
+
+The translation is the same as ``.GatherCmp()``.
+
+The overload with the status parameter are not supported.
+
 ``.Load(location[, sampleIndex][, offset])``
 ++++++++++++++++++++++++++++++++++++++++++++
 

+ 4 - 1
tools/clang/include/clang/SPIRV/ModuleBuilder.h

@@ -189,7 +189,10 @@ public:
   /// \brief Creates SPIR-V instructions for writing to the given image.
   void createImageWrite(uint32_t imageId, uint32_t coordId, uint32_t texelId);
 
-  /// \brief Creates SPIR-V instructions for sampling the given image.
+  /// \brief Creates SPIR-V instructions for gathering the given image.
+  ///
+  /// If compareVal is given a non-zero value, OpImageDrefGather will be
+  /// generated; otherwise, OpImageGather will be generated.
   uint32_t createImageGather(uint32_t texelType, uint32_t imageType,
                              uint32_t image, uint32_t sampler,
                              uint32_t coordinate, uint32_t component,

+ 32 - 20
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -1722,20 +1722,31 @@ SPIRVEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr) {
                                            {0});
 }
 
-uint32_t SPIRVEmitter::processTextureGatherRGBA(const CXXMemberCallExpr *expr,
-                                                const uint32_t component) {
-  // Parameters for .Gather{Red|Green|Blue|Alpha}() are one of the following two
-  // sets:
+uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
+    const CXXMemberCallExpr *expr, const bool isCmp, const uint32_t component) {
+  // Parameters for .Gather{Red|Green|Blue|Alpha}() are one of the following
+  // two sets:
   // * SamplerState s, float2 location, int2 offset
   // * SamplerState s, float2 location, int2 offset0, int2 offset1,
   //   int offset2, int2 offset3
+  //
+  // An additional out uint status parameter can appear in both of the above,
+  // which we does not support yet.
+  //
+  // Parameters for .GatherCmp{Red|Green|Blue|Alpha}() are one of the following
+  // two sets:
+  // * SamplerState s, float2 location, int2 offset
+  // * SamplerState s, float2 location, int2 offset0, int2 offset1,
+  //   int offset2, int2 offset3
+  //
   // An additional out uint status parameter can appear in both of the above,
   // which we does not support yet.
+  //
   // Return type is always a 4-component vector.
   const FunctionDecl *callee = expr->getDirectCallee();
   const auto numArgs = expr->getNumArgs();
 
-  if (numArgs != 3 && numArgs != 6) {
+  if (numArgs != 3 + isCmp && numArgs != 6 + isCmp) {
     emitError("unsupported '%0' method call with status parameter",
               expr->getExprLoc())
         << callee->getName() << expr->getSourceRange();
@@ -1747,17 +1758,18 @@ uint32_t SPIRVEmitter::processTextureGatherRGBA(const CXXMemberCallExpr *expr,
   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 compareVal = isCmp ? doExpr(expr->getArg(2)) : 0;
 
   uint32_t constOffset = 0, varOffset = 0, constOffsets = 0;
-  if (numArgs == 3) {
+  if (numArgs == 3 + isCmp) {
     // One offset parameter
-    handleOptionalOffsetInMethodCall(expr, 2, &constOffset, &varOffset);
+    handleOptionalOffsetInMethodCall(expr, 2 + isCmp, &constOffset, &varOffset);
   } else {
     // Four offset parameters
-    const auto offset0 = tryToEvaluateAsConst(expr->getArg(2));
-    const auto offset1 = tryToEvaluateAsConst(expr->getArg(3));
-    const auto offset2 = tryToEvaluateAsConst(expr->getArg(4));
-    const auto offset3 = tryToEvaluateAsConst(expr->getArg(5));
+    const auto offset0 = tryToEvaluateAsConst(expr->getArg(2 + isCmp));
+    const auto offset1 = tryToEvaluateAsConst(expr->getArg(3 + isCmp));
+    const auto offset2 = tryToEvaluateAsConst(expr->getArg(4 + isCmp));
+    const auto offset3 = tryToEvaluateAsConst(expr->getArg(5 + isCmp));
 
     // Make sure we can generate the ConstOffsets image operands in SPIR-V.
     if (!offset0 || !offset1 || !offset2 || !offset3) {
@@ -1778,7 +1790,7 @@ uint32_t SPIRVEmitter::processTextureGatherRGBA(const CXXMemberCallExpr *expr,
 
   return theBuilder.createImageGather(
       retType, imageType, image, sampler, coordinate,
-      theBuilder.getConstantInt32(component), /*compareVal*/ 0, constOffset,
+      theBuilder.getConstantInt32(component), compareVal, constOffset,
       varOffset, constOffsets, /*sampleNumber*/ 0);
 }
 
@@ -2108,15 +2120,17 @@ SPIRVEmitter::processIntrinsicMemberCall(const CXXMemberCallExpr *expr,
   case IntrinsicOp::MOP_SampleCmpLevelZero:
     return processTextureSampleCmpCmpLevelZero(expr, /*isCmp=*/false);
   case IntrinsicOp::MOP_GatherRed:
-    return processTextureGatherRGBA(expr, 0);
+    return processTextureGatherRGBACmpRGBA(expr, /*isCmp=*/false, 0);
   case IntrinsicOp::MOP_GatherGreen:
-    return processTextureGatherRGBA(expr, 1);
+    return processTextureGatherRGBACmpRGBA(expr, /*isCmp=*/false, 1);
   case IntrinsicOp::MOP_GatherBlue:
-    return processTextureGatherRGBA(expr, 2);
+    return processTextureGatherRGBACmpRGBA(expr, /*isCmp=*/false, 2);
   case IntrinsicOp::MOP_GatherAlpha:
-    return processTextureGatherRGBA(expr, 3);
+    return processTextureGatherRGBACmpRGBA(expr, /*isCmp=*/false, 3);
   case IntrinsicOp::MOP_GatherCmp:
     return processTextureGatherCmp(expr);
+  case IntrinsicOp::MOP_GatherCmpRed:
+    return processTextureGatherRGBACmpRGBA(expr, /*isCmp=*/true, 0);
   case IntrinsicOp::MOP_Load:
     return processBufferTextureLoad(expr);
   case IntrinsicOp::MOP_Load2:
@@ -2187,16 +2201,14 @@ uint32_t SPIRVEmitter::processTextureSampleGather(const CXXMemberCallExpr *expr,
   if (isSample) {
     return theBuilder.createImageSample(
         retType, imageType, image, sampler, coordinate, /*compareVal*/ 0,
-        /*bias*/ 0,
-        /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
+        /*bias*/ 0, /*lod*/ 0, std::make_pair(0, 0), constOffset, varOffset,
         /*constOffsets*/ 0, /*sampleNumber*/ 0);
   } else {
     return theBuilder.createImageGather(
         retType, imageType, image, sampler, coordinate,
         // .Gather() doc says we return four components of red data.
         theBuilder.getConstantInt32(0), /*compareVal*/ 0, constOffset,
-        varOffset,
-        /*constOffsets*/ 0, /*sampleNumber*/ 0);
+        varOffset, /*constOffsets*/ 0, /*sampleNumber*/ 0);
   }
 }
 

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

@@ -537,9 +537,10 @@ private:
   uint32_t processTextureSampleCmpCmpLevelZero(const CXXMemberCallExpr *expr,
                                                bool isCmp);
 
-  /// \brief Handles .Gather{Red|Green|Blue|Alpha}() calls on texture types.
-  uint32_t processTextureGatherRGBA(const CXXMemberCallExpr *expr,
-                                    uint32_t component);
+  /// \brief Handles .Gather{|Cmp}{Red|Green|Blue|Alpha}() calls on texture
+  /// types.
+  uint32_t processTextureGatherRGBACmpRGBA(const CXXMemberCallExpr *expr,
+                                           bool isCmp, uint32_t component);
 
   /// \brief Handles .GatherCmp() calls on texture types.
   uint32_t processTextureGatherCmp(const CXXMemberCallExpr *expr);

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

@@ -0,0 +1,52 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture2DArray<float4> t2f4 : register(t1);
+Texture2DArray<uint>   t2u1 : register(t2);
+// .GatherCmpRed() does not support Texture1DArray.
+// .GatherCmpRed() for TextureCubeArray only has one signature that takes the status parameter.
+
+// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+
+float4 main(float3 location: A, float comparator: B) : SV_Target {
+// CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
+// 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 [[t2f4]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[c12]]
+// CHECK-NEXT:                       OpStore %a [[res]]
+    float4 a = t2f4.GatherCmpRed(gSampler, location, comparator, int2(1, 2));
+// CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image_array %t2f4
+// 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 [[t2f4]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] ConstOffsets [[c1to8]]
+// CHECK-NEXT:                       OpStore %b [[res]]
+    float4 b = t2f4.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
+
+// CHECK:            [[t2u1:%\d+]] = OpLoad %type_2d_image_array_0 %t2u1
+// 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_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4uint [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[c12]]
+// CHECK-NEXT:                       OpStore %c [[res]]
+    uint4 c = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2));
+// CHECK:            [[t2u1:%\d+]] = OpLoad %type_2d_image_array_0 %t2u1
+// 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_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4uint [[sampledImg]] [[loc]] [[comparator]] ConstOffsets [[c1to8]]
+// CHECK-NEXT:                       OpStore %d [[res]]
+    uint4 d = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
+
+    return 1.0;
+}

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

@@ -0,0 +1,52 @@
+// Run: %dxc -T ps_6_0 -E main
+
+SamplerComparisonState gSampler : register(s1);
+
+Texture2D<float4> t2f4 : register(t1);
+Texture2D<uint>   t2u1 : register(t2);
+// .GatherCmpRed() does not support Texture1D and Texture3D.
+// .GatherCmpRed() for TextureCube only has one signature that takes the status parameter.
+
+// CHECK: [[c12:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
+// CHECK: [[c34:%\d+]] = OpConstantComposite %v2int %int_3 %int_4
+// CHECK: [[c56:%\d+]] = OpConstantComposite %v2int %int_5 %int_6
+// CHECK: [[c78:%\d+]] = OpConstantComposite %v2int %int_7 %int_8
+// CHECK: [[c1to8:%\d+]] = OpConstantComposite %_arr_v2int_uint_4 [[c12]] [[c34]] [[c56]] [[c78]]
+
+float4 main(float2 location: A, float comparator: B) : SV_Target {
+// CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
+// 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 [[t2f4]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[c12]]
+// CHECK-NEXT:                       OpStore %a [[res]]
+    float4 a = t2f4.GatherCmpRed(gSampler, location, comparator, int2(1, 2));
+// CHECK:            [[t2f4:%\d+]] = OpLoad %type_2d_image %t2f4
+// 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 [[t2f4]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] ConstOffsets [[c1to8]]
+// CHECK-NEXT:                       OpStore %b [[res]]
+    float4 b = t2f4.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
+
+// CHECK:            [[t2u1:%\d+]] = OpLoad %type_2d_image_0 %t2u1
+// 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_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4uint [[sampledImg]] [[loc]] [[comparator]] ConstOffset [[c12]]
+// CHECK-NEXT:                       OpStore %c [[res]]
+    uint4 c = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2));
+// CHECK:            [[t2u1:%\d+]] = OpLoad %type_2d_image_0 %t2u1
+// 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_0 [[t2u1]] [[gSampler]]
+// CHECK-NEXT:        [[res:%\d+]] = OpImageDrefGather %v4uint [[sampledImg]] [[loc]] [[comparator]] ConstOffsets [[c1to8]]
+// CHECK-NEXT:                       OpStore %d [[res]]
+    uint4 d = t2u1.GatherCmpRed(gSampler, location, comparator, int2(1, 2), int2(3, 4), int2(5, 6), int2(7, 8));
+
+    return 1.0;
+}

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

@@ -418,6 +418,12 @@ TEST_F(FileTest, TextureGatherCmp) { runFileTest("texture.gather-cmp.hlsl"); }
 TEST_F(FileTest, TextureArrayGatherCmp) {
   runFileTest("texture.array.gather-cmp.hlsl");
 }
+TEST_F(FileTest, TextureGatherCmpRed) {
+  runFileTest("texture.gather-cmp-red.hlsl");
+}
+TEST_F(FileTest, TextureArrayGatherCmpRed) {
+  runFileTest("texture.array.gather-cmp-red.hlsl");
+}
 TEST_F(FileTest, TextureSampleLevel) {
   runFileTest("texture.sample-level.hlsl");
 }