diff --git a/docs/SPIR-V.rst b/docs/SPIR-V.rst index a1140bcca..970091710 100644 --- a/docs/SPIR-V.rst +++ b/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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tools/clang/lib/SPIRV/SPIRVEmitter.cpp b/tools/clang/lib/SPIRV/SPIRVEmitter.cpp index 9c3aec5d7..83bc8caf3 100644 --- a/tools/clang/lib/SPIRV/SPIRVEmitter.cpp +++ b/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); diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.ddx-coarse.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.ddx-coarse.hlsl new file mode 100644 index 000000000..5ae71786a --- /dev/null +++ b/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); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.ddx-fine.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.ddx-fine.hlsl new file mode 100644 index 000000000..cb423aec1 --- /dev/null +++ b/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); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.ddx.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.ddx.hlsl new file mode 100644 index 000000000..2a1284e97 --- /dev/null +++ b/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); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.ddy-coarse.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.ddy-coarse.hlsl new file mode 100644 index 000000000..7a8ddf0fb --- /dev/null +++ b/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); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.ddy-fine.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.ddy-fine.hlsl new file mode 100644 index 000000000..95f6b631c --- /dev/null +++ b/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); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.ddy.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.ddy.hlsl new file mode 100644 index 000000000..7b24bd84f --- /dev/null +++ b/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); +} diff --git a/tools/clang/test/CodeGenSPIRV/intrinsics.isfinite.hlsl b/tools/clang/test/CodeGenSPIRV/intrinsics.isfinite.hlsl index 1b9d836bc..595333498 100644 --- a/tools/clang/test/CodeGenSPIRV/intrinsics.isfinite.hlsl +++ b/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; diff --git a/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp b/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp index 8eefa61f0..1b6314288 100644 --- a/tools/clang/unittests/SPIRV/CodeGenSPIRVTest.cpp +++ b/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"); }