فهرست منبع

[spirv] Support GatherCmp methods with Status arg. (#877)

Ehsan 7 سال پیش
والد
کامیت
487a73af30

+ 43 - 14
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -2243,41 +2243,70 @@ uint32_t SPIRVEmitter::processTextureGatherRGBACmpRGBA(
 }
 }
 
 
 uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
 uint32_t SPIRVEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
-  // Signature:
+  // Signature for Texture2D/Texture2DArray:
   //
   //
   // float4 GatherCmp(
   // float4 GatherCmp(
   //   in SamplerComparisonState s,
   //   in SamplerComparisonState s,
   //   in float2 location,
   //   in float2 location,
   //   in float compare_value
   //   in float compare_value
   //   [,in int2 offset]
   //   [,in int2 offset]
+  //   [,out uint Status]
   // );
   // );
+  //
+  // Signature for TextureCube/TextureCubeArray:
+  //
+  // float4 GatherCmp(
+  //   in SamplerComparisonState s,
+  //   in float2 location,
+  //   in float compare_value,
+  //   out uint Status
+  // );
+  //
+  // Other Texture types do not have the GatherCmp method.
+
   const FunctionDecl *callee = expr->getDirectCallee();
   const FunctionDecl *callee = expr->getDirectCallee();
   const auto numArgs = expr->getNumArgs();
   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 bool hasStatusArg =
+      expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
+  const bool hasOffsetArg = (numArgs == 5) || (numArgs == 4 && !hasStatusArg);
 
 
   const auto *imageExpr = expr->getImplicitObjectArgument();
   const auto *imageExpr = expr->getImplicitObjectArgument();
-
   const uint32_t image = loadIfGLValue(imageExpr);
   const uint32_t image = loadIfGLValue(imageExpr);
   const uint32_t sampler = doExpr(expr->getArg(0));
   const uint32_t sampler = doExpr(expr->getArg(0));
   const uint32_t coordinate = doExpr(expr->getArg(1));
   const uint32_t coordinate = doExpr(expr->getArg(1));
   const uint32_t comparator = doExpr(expr->getArg(2));
   const uint32_t comparator = doExpr(expr->getArg(2));
   uint32_t constOffset = 0, varOffset = 0;
   uint32_t constOffset = 0, varOffset = 0;
-  handleOptionalOffsetInMethodCall(expr, 3, &constOffset, &varOffset);
+  if(hasOffsetArg)
+    handleOffsetInMethodCall(expr, 3, &constOffset, &varOffset);
 
 
   const auto retType = typeTranslator.translateType(callee->getReturnType());
   const auto retType = typeTranslator.translateType(callee->getReturnType());
   const auto imageType = typeTranslator.translateType(imageExpr->getType());
   const auto imageType = typeTranslator.translateType(imageExpr->getType());
 
 
-  // TODO: Update this function to include sparse cases.
-  return theBuilder.createImageGather(
-      retType, imageType, image, sampler, coordinate,
+  if(!hasStatusArg)
+    return theBuilder.createImageGather(
+        retType, imageType, image, sampler, coordinate,
+        /*component*/ 0, comparator, constOffset, varOffset, /*constOffsets*/ 0,
+        /*sampleNumber*/ 0, /*isSparse*/ false);
+
+  // If the Status parameter is present, OpImageSparseGather should be used.
+  // The result type of this SPIR-V instruction is a struct in which the first
+  // member is an integer that holds the Residency Code.
+  const auto uintType = theBuilder.getUint32Type();
+  const auto sparseRetType =
+      theBuilder.getStructType({uintType, retType}, "SparseResidencyStruct",
+                               {"Residency.Code", "Result.Type"});
+
+  // Perform ImageSparseGather
+  const auto sparseGather = theBuilder.createImageGather(
+      sparseRetType, imageType, image, sampler, coordinate,
       /*component*/ 0, comparator, constOffset, varOffset, /*constOffsets*/ 0,
       /*component*/ 0, comparator, constOffset, varOffset, /*constOffsets*/ 0,
-      /*sampleNumber*/ 0, /*isSparse*/ false);
+      /*sampleNumber*/ 0, /*isSparse*/ true);
+  // Write the Residency Code
+  const auto status =
+      theBuilder.createCompositeExtract(uintType, sparseGather, {0});
+  theBuilder.createStore(doExpr(expr->getArg(numArgs - 1)), status);
+  // Return the results
+  return theBuilder.createCompositeExtract(retType, sparseGather, {1});
 }
 }
 
 
 SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object,
 SpirvEvalInfo SPIRVEmitter::processBufferTextureLoad(const Expr *object,

+ 30 - 1
tools/clang/test/CodeGenSPIRV/texture.array.gather-cmp.hlsl

@@ -5,11 +5,14 @@ SamplerComparisonState gSampler : register(s5);
 Texture2DArray<float4> t1 : register(t1);
 Texture2DArray<float4> t1 : register(t1);
 Texture2DArray<float2> t2 : register(t2);
 Texture2DArray<float2> t2 : register(t2);
 Texture2DArray<float>  t3 : register(t3);
 Texture2DArray<float>  t3 : register(t3);
+TextureCubeArray<float>t4 : register(t4);
 // .GatherCmp() does not support Texture1DArray.
 // .GatherCmp() does not support Texture1DArray.
-// .GatherCmp() for TextureCubeArray requires the status parameter.
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
 
 
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
 // CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_0_1 %float_0_2 %float_0_3
+// CHECK: [[v4fc:%\d+]] = OpConstantComposite %v4float %float_1_5 %float_1_5 %float_1_5 %float_1_5
 
 
 float4 main(float3 location: A, float comparator: B, int2 offset: C) : SV_Target {
 float4 main(float3 location: A, float comparator: B, int2 offset: C) : SV_Target {
 // CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t1
 // CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image_array %t1
@@ -36,5 +39,31 @@ float4 main(float3 location: A, float comparator: B, int2 offset: C) : SV_Target
 // CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
 // CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
     float4 val3 = t3.GatherCmp(gSampler, location, comparator, offset);
     float4 val3 = t3.GatherCmp(gSampler, location, comparator, offset);
 
 
+    uint status;
+
+// 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: [[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val4 [[result]]
+    float4 val4 = t3.GatherCmp(gSampler, location, comparator, offset, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image_array %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[v4fc]] [[comparator]] None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val5 [[result]]
+    float4 val5 = t4.GatherCmp(gSampler, /*location*/float4(1.5, 1.5, 1.5, 1.5), comparator, status);
+
     return 1.0;
     return 1.0;
 }
 }

+ 30 - 1
tools/clang/test/CodeGenSPIRV/texture.gather-cmp.hlsl

@@ -5,11 +5,14 @@ SamplerComparisonState gSampler : register(s5);
 Texture2D<float4> t1 : register(t1);
 Texture2D<float4> t1 : register(t1);
 Texture2D<float2> t2 : register(t2);
 Texture2D<float2> t2 : register(t2);
 Texture2D<float>  t3 : register(t3);
 Texture2D<float>  t3 : register(t3);
+TextureCube<float>t4 : register(t4);
 // .GatherCmp() does not support Texture1D and Texture3D.
 // .GatherCmp() does not support Texture1D and Texture3D.
-// .GatherCmp() for TextureCube requires the status parameter.
+
+// CHECK: %SparseResidencyStruct = OpTypeStruct %uint %v4float
 
 
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 // CHECK: [[v2ic:%\d+]] = OpConstantComposite %v2int %int_1 %int_2
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
 // CHECK: [[v2fc:%\d+]] = OpConstantComposite %v2float %float_0_1 %float_0_2
+// CHECK: [[v3fc:%\d+]] = OpConstantComposite %v3float %float_1_5 %float_1_5 %float_1_5
 
 
 float4 main(float2 location: A, float comparator: B, int2 offset: C) : SV_Target {
 float4 main(float2 location: A, float comparator: B, int2 offset: C) : SV_Target {
 // CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t1
 // CHECK:              [[t2:%\d+]] = OpLoad %type_2d_image %t1
@@ -36,5 +39,31 @@ float4 main(float2 location: A, float comparator: B, int2 offset: C) : SV_Target
 // CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
 // CHECK-NEXT:            {{%\d+}} = OpImageDrefGather %v4float [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
     float4 val3 = t3.GatherCmp(gSampler, location, comparator, offset);
     float4 val3 = t3.GatherCmp(gSampler, location, comparator, offset);
 
 
+    uint status;
+
+// 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: [[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[loc]] [[comparator]] Offset [[offset]]
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val4 [[result]]
+    float4 val4 = t3.GatherCmp(gSampler, location, comparator, offset, status);
+
+// CHECK:                [[t4:%\d+]] = OpLoad %type_cube_image %t4
+// CHECK-NEXT:     [[gSampler:%\d+]] = OpLoad %type_sampler %gSampler
+// CHECK-NEXT:   [[comparator:%\d+]] = OpLoad %float %comparator
+// CHECK-NEXT:   [[sampledImg:%\d+]] = OpSampledImage %type_sampled_image_0 [[t4]] [[gSampler]]
+// CHECK-NEXT: [[structResult:%\d+]] = OpImageSparseDrefGather %SparseResidencyStruct [[sampledImg]] [[v3fc]] [[comparator]] None
+// CHECK-NEXT:       [[status:%\d+]] = OpCompositeExtract %uint [[structResult]] 0
+// CHECK-NEXT:                         OpStore %status [[status]]
+// CHECK-NEXT:       [[result:%\d+]] = OpCompositeExtract %v4float [[structResult]] 1
+// CHECK-NEXT:                         OpStore %val5 [[result]]
+    float4 val5 = t4.GatherCmp(gSampler, /*location*/float3(1.5, 1.5, 1.5), comparator, status);
+
     return 1.0;
     return 1.0;
 }
 }