瀏覽代碼

[spirv] Intrinsic ddx and ddy. (#707)

Also:
* ddx_coarse, ddx_fine
* ddy_coarse, ddy_fine
Ehsan 8 年之前
父節點
當前提交
8afee2994c

+ 6 - 0
docs/SPIR-V.rst

@@ -1086,6 +1086,12 @@ The following intrinsic HLSL functions are currently supported:
 - ``reversebits``: Reverses the order of the bits, per component. Uses SPIR-V ``OpBitReverse``.
 - ``clip``: Discards the current pixel if the specified value is less than zero. Uses conditional
   control flow as well as SPIR-V ``OpKill``.
+- ``ddx``: Partial derivative with respect to the screen-space x-coordinate. Uses SIR-V ``OpDPdx``.
+- ``ddy``: Partial derivative with respect to the screen-space y-coordinate. Uses SIR-V ``OpDPdy``.
+- ``ddx_coarse``: Low precision partial derivative with respect to the screen-space x-coordinate. Uses SIR-V ``OpDPdxCoarse``.
+- ``ddy_coarse``: Low precision partial derivative with respect to the screen-space y-coordinate. Uses SIR-V ``OpDPdyCoarse``.
+- ``ddx_fine``: High precision partial derivative with respect to the screen-space x-coordinate. Uses SIR-V ``OpDPdxFine``.
+- ``ddy_fine``: High precision partial derivative with respect to the screen-space y-coordinate. Uses SIR-V ``OpDPdyFine``.
 
 Using GLSL extended instructions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ 17 - 0
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -3674,6 +3674,13 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
 
   GLSLstd450 glslOpcode = GLSLstd450Bad;
 
+#define INTRINSIC_SPIRV_OP_WITH_CAP_CASE(intrinsicOp, spirvOp, doEachVec, cap) \
+  case hlsl::IntrinsicOp::IOP_##intrinsicOp: {                                 \
+    theBuilder.requireCapability(cap);                                         \
+    return processIntrinsicUsingSpirvInst(callExpr, spv::Op::Op##spirvOp,      \
+                                          doEachVec);                          \
+  } break
+
 #define INTRINSIC_SPIRV_OP_CASE(intrinsicOp, spirvOp, doEachVec)               \
   case hlsl::IntrinsicOp::IOP_##intrinsicOp: {                                 \
     return processIntrinsicUsingSpirvInst(callExpr, spv::Op::Op##spirvOp,      \
@@ -3756,6 +3763,16 @@ uint32_t SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
     return processIntrinsicLog10(callExpr);
   }
     INTRINSIC_SPIRV_OP_CASE(transpose, Transpose, false);
+    INTRINSIC_SPIRV_OP_CASE(ddx, DPdx, true);
+    INTRINSIC_SPIRV_OP_WITH_CAP_CASE(ddx_coarse, DPdxCoarse, false,
+                                     spv::Capability::DerivativeControl);
+    INTRINSIC_SPIRV_OP_WITH_CAP_CASE(ddx_fine, DPdxFine, false,
+                                     spv::Capability::DerivativeControl);
+    INTRINSIC_SPIRV_OP_CASE(ddy, DPdy, true);
+    INTRINSIC_SPIRV_OP_WITH_CAP_CASE(ddy_coarse, DPdyCoarse, false,
+                                     spv::Capability::DerivativeControl);
+    INTRINSIC_SPIRV_OP_WITH_CAP_CASE(ddy_fine, DPdyFine, false,
+                                     spv::Capability::DerivativeControl);
     INTRINSIC_SPIRV_OP_CASE(countbits, BitCount, false);
     INTRINSIC_SPIRV_OP_CASE(isinf, IsInf, true);
     INTRINSIC_SPIRV_OP_CASE(isnan, IsNan, true);

+ 17 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ddx-coarse.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: OpCapability DerivativeControl
+
+void main() {
+
+  float  a;
+  float4 b;
+
+// CHECK:      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:   {{%\d+}} = OpDPdxCoarse %float [[a]]
+  float    da = ddx_coarse(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT:   {{%\d+}} = OpDPdxCoarse %v4float [[b]]
+  float4   db = ddx_coarse(b);
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ddx-fine.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: OpCapability DerivativeControl
+
+void main() {
+
+  float  a;
+  float4 b;
+
+// CHECK:      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:   {{%\d+}} = OpDPdxFine %float [[a]]
+  float    da = ddx_fine(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT:   {{%\d+}} = OpDPdxFine %v4float [[b]]
+  float4   db = ddx_fine(b);
+}

+ 24 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ddx.hlsl

@@ -0,0 +1,24 @@
+// Run: %dxc -T ps_6_0 -E main
+
+void main() {
+
+  float    a;
+  float2   b;
+  float2x3 c;
+
+// CHECK:      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:   {{%\d+}} = OpDPdx %float [[a]]
+  float    da = ddx(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v2float %b
+// CHECK-NEXT:   {{%\d+}} = OpDPdx %v2float [[b]]
+  float2   db = ddx(b);
+
+// CHECK:        [[c:%\d+]] = OpLoad %mat2v3float %c
+// CHECK-NEXT:  [[c0:%\d+]] = OpCompositeExtract %v3float [[c]] 0
+// CHECK-NEXT: [[dc0:%\d+]] = OpDPdx %v3float [[c0]]
+// CHECK-NEXT:  [[c1:%\d+]] = OpCompositeExtract %v3float [[c]] 1
+// CHECK-NEXT: [[dc1:%\d+]] = OpDPdx %v3float [[c1]]
+// CHECK-NEXT:     {{%\d+}} = OpCompositeConstruct %mat2v3float [[dc0]] [[dc1]]
+  float2x3 dc = ddx(c);
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ddy-coarse.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: OpCapability DerivativeControl
+
+void main() {
+
+  float  a;
+  float4 b;
+
+// CHECK:      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:   {{%\d+}} = OpDPdyCoarse %float [[a]]
+  float    da = ddy_coarse(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT:   {{%\d+}} = OpDPdyCoarse %v4float [[b]]
+  float4   db = ddy_coarse(b);
+}

+ 17 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ddy-fine.hlsl

@@ -0,0 +1,17 @@
+// Run: %dxc -T ps_6_0 -E main
+
+// CHECK: OpCapability DerivativeControl
+
+void main() {
+
+  float  a;
+  float4 b;
+
+// CHECK:      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:   {{%\d+}} = OpDPdyFine %float [[a]]
+  float    da = ddy_fine(a);
+
+// CHECK:      [[b:%\d+]] = OpLoad %v4float %b
+// CHECK-NEXT:   {{%\d+}} = OpDPdyFine %v4float [[b]]
+  float4   db = ddy_fine(b);
+}

+ 25 - 0
tools/clang/test/CodeGenSPIRV/intrinsics.ddy.hlsl

@@ -0,0 +1,25 @@
+// Run: %dxc -T ps_6_0 -E main
+
+void main() {
+
+  float    a;
+  float2   b;
+  float2x3 c;
+
+// CHECK:      [[a:%\d+]] = OpLoad %float %a
+// CHECK-NEXT:   {{%\d+}} = OpDPdy %float [[a]]
+  float    da = ddy(a);
+
+
+// CHECK:      [[b:%\d+]] = OpLoad %v2float %b
+// CHECK-NEXT:   {{%\d+}} = OpDPdy %v2float [[b]]
+  float2   db = ddy(b);
+
+// CHECK:        [[c:%\d+]] = OpLoad %mat2v3float %c
+// CHECK-NEXT:  [[c0:%\d+]] = OpCompositeExtract %v3float [[c]] 0
+// CHECK-NEXT: [[dc0:%\d+]] = OpDPdy %v3float [[c0]]
+// CHECK-NEXT:  [[c1:%\d+]] = OpCompositeExtract %v3float [[c]] 1
+// CHECK-NEXT: [[dc1:%\d+]] = OpDPdy %v3float [[c1]]
+// CHECK-NEXT:     {{%\d+}} = OpCompositeConstruct %mat2v3float [[dc0]] [[dc1]]
+  float2x3 dc = ddy(c);
+}

+ 1 - 1
tools/clang/test/CodeGenSPIRV/intrinsics.isfinite.hlsl

@@ -1,7 +1,7 @@
 // Run: %dxc -T ps_6_0 -E main
 
 // Since OpIsFinite needs the Kernel capability, translation is done using OpIsNan and OpIsInf.
-// isFinite = !isNan && !isInf.
+// isFinite = !(isNan || isInf)
 
 void main() {
   float    a;

+ 11 - 3
tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp

@@ -518,6 +518,16 @@ TEST_F(FileTest, IntrinsicsDistance) {
   runFileTest("intrinsics.distance.hlsl");
 }
 TEST_F(FileTest, IntrinsicsRadians) { runFileTest("intrinsics.radians.hlsl"); }
+TEST_F(FileTest, IntrinsicsDdx) { runFileTest("intrinsics.ddx.hlsl"); }
+TEST_F(FileTest, IntrinsicsDdy) { runFileTest("intrinsics.ddy.hlsl"); }
+TEST_F(FileTest, IntrinsicsDdxCoarse) {
+  runFileTest("intrinsics.ddx-coarse.hlsl");
+}
+TEST_F(FileTest, IntrinsicsDdyCoarse) {
+  runFileTest("intrinsics.ddy-coarse.hlsl");
+}
+TEST_F(FileTest, IntrinsicsDdxFine) { runFileTest("intrinsics.ddx-fine.hlsl"); }
+TEST_F(FileTest, IntrinsicsDdyFine) { runFileTest("intrinsics.ddy-fine.hlsl"); }
 TEST_F(FileTest, IntrinsicsDeterminant) {
   runFileTest("intrinsics.determinant.hlsl");
 }
@@ -696,9 +706,7 @@ TEST_F(FileTest, VulkanLayoutConsumeSBufferStd430) {
 }
 
 // For different Patch Constant Functions (for Hull shaders)
-TEST_F(FileTest, HullShaderPCFVoid) {
-  runFileTest("hull.pcf.void.hlsl");
-}
+TEST_F(FileTest, HullShaderPCFVoid) { runFileTest("hull.pcf.void.hlsl"); }
 TEST_F(FileTest, HullShaderPCFTakesInputPatch) {
   runFileTest("hull.pcf.input-patch.hlsl");
 }