summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpdeayton-nv <205388607+pdeayton-nv@users.noreply.github.com>2025-05-01 14:51:34 -0700
committerGitHub <noreply@github.com>2025-05-01 14:51:34 -0700
commit7d7027853a94c83e9b90b8a11877e91cdaa3e81b (patch)
tree6ed96ae4fc5b2cbfaa0abfd44769eaab2ef6b981
parentdde654c8605ea65f959fcadaa6618337ab1f20c0 (diff)
Add fwidth_coarse and fwidth_fine functions (#6941)
Fixes #6940. Add new Slang fwidth_coarse and fwidth_fine functions, similar to GLSL's fwidthCoarse and fwidthFine. Move the implementation of the GLSL functions from glsl.meta.slang to hlsl.meta.slang. Update the existing spirv/fwidth.slang test with the new functions, and add a new hlsl-intrinsic/fragment-derivative.slang test to test HLSL, SPIR-V, and GLSL targets for the new functions.
-rw-r--r--source/slang/glsl.meta.slang72
-rw-r--r--source/slang/hlsl.meta.slang124
-rw-r--r--tests/hlsl-intrinsic/fragment-derivative.slang105
-rw-r--r--tests/spirv/fwidth.slang54
4 files changed, 268 insertions, 87 deletions
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index 85c8b174c..0ea7d1c89 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -8898,23 +8898,7 @@ public vector<float, N> dFdyCoarse(vector<float, N> p)
[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
public float fwidthFine(float p)
{
- __requireComputeDerivative();
- __target_switch
- {
- case hlsl:
- {
- return abs(ddx_fine(p)) + abs(ddy_fine(p));
- }
- case glsl: __intrinsic_asm "fwidthFine($0)";
- case spirv:
- {
- return spirv_asm
- {
- OpCapability DerivativeControl;
- OpFwidthFine $$float result $p;
- };
- }
- }
+ return fwidth_fine(p);
}
__generic<let N : int>
[__NoSideEffect]
@@ -8922,23 +8906,7 @@ __generic<let N : int>
[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
public vector<float, N> fwidthFine(vector<float, N> p)
{
- __requireComputeDerivative();
- __target_switch
- {
- case hlsl:
- {
- return abs(ddx_fine(p)) + abs(ddy_fine(p));
- }
- case glsl: __intrinsic_asm "fwidthFine($0)";
- case spirv:
- {
- return spirv_asm
- {
- OpCapability DerivativeControl;
- OpFwidthFine $$vector<float, N> result $p;
- };
- }
- }
+ return fwidth_fine(p);
}
[__NoSideEffect]
@@ -8946,23 +8914,7 @@ public vector<float, N> fwidthFine(vector<float, N> p)
[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
public float fwidthCoarse(float p)
{
- __requireComputeDerivative();
- __target_switch
- {
- case hlsl:
- {
- return abs(ddx_coarse(p)) + abs(ddy_coarse(p));
- }
- case glsl: __intrinsic_asm "fwidthCoarse($0)";
- case spirv:
- {
- return spirv_asm
- {
- OpCapability DerivativeControl;
- OpFwidthCoarse $$float result $p;
- };
- }
- }
+ return fwidth_coarse(p);
}
__generic<let N : int>
[__NoSideEffect]
@@ -8970,23 +8922,7 @@ __generic<let N : int>
[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
public vector<float, N> fwidthCoarse(vector<float, N> p)
{
- __requireComputeDerivative();
- __target_switch
- {
- case hlsl:
- {
- return abs(ddx_coarse(p)) + abs(ddy_coarse(p));
- }
- case glsl: __intrinsic_asm "fwidthCoarse($0)";
- case spirv:
- {
- return spirv_asm
- {
- OpCapability DerivativeControl;
- OpFwidthCoarse $$vector<float, N> result $p;
- };
- }
- }
+ return fwidth_coarse(p);
}
[__NoSideEffect]
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 3d83e33c1..0f04006e5 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -9940,6 +9940,130 @@ matrix<T, N, M> fwidth(matrix<T, N, M> x)
}
}
+/// Texture filter width (coarse).
+/// Calculates the sum abs(ddx_coarse(`p`)) + abs(ddy_coarse(`p`)).
+/// @param p The value to sum x and y partial derivative magnitudes for.
+/// @return The sum of abs(ddx_coarse(`p`)) and abs(ddy_coarse(`p`)).
+/// @remarks For SPIR-V, this function maps to `OpFwidthCoarse`.
+/// @category derivative
+__generic<T : __BuiltinFloatingPointType>
+[__readNone]
+[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
+T fwidth_coarse(T p)
+{
+ __requireComputeDerivative();
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "abs(ddx_coarse($0)) + abs(ddy_coarse($0))";
+ case glsl:
+ __intrinsic_asm "fwidthCoarse($0)";
+ case spirv:
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthCoarse $$T result $p;
+ };
+ }
+}
+
+__generic<T : __BuiltinFloatingPointType, let N : int>
+[__readNone]
+[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
+vector<T, N> fwidth_coarse(vector<T, N> x)
+{
+ __requireComputeDerivative();
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "abs(ddx_coarse($0)) + abs(ddy_coarse($0))";
+ case glsl:
+ __intrinsic_asm "fwidthCoarse($0)";
+ case spirv:
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthCoarse $$vector<T, N> result $x;
+ };
+ }
+}
+
+__generic<T : __BuiltinFloatingPointType, let N : int, let M : int>
+[__readNone]
+[require(glsl_hlsl_spirv, fragmentprocessing)]
+matrix<T, N, M> fwidth_coarse(matrix<T, N, M> x)
+{
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "abs(ddx_coarse($0)) + abs(ddy_coarse($0))";
+ default:
+ MATRIX_MAP_UNARY(T, N, M, fwidth_coarse, x);
+ }
+}
+
+/// Texture filter width (fine).
+/// Calculates the sum abs(ddx_fine(`p`)) + abs(ddy_fine(`p`)).
+/// @param p The value to sum x and y partial derivative magnitudes for.
+/// @return The sum of abs(ddx_fine(`p`)) and abs(ddy_fine(`p`)).
+/// @remarks For SPIR-V, this function maps to `OpFwidthFine`.
+/// @category derivative
+__generic<T : __BuiltinFloatingPointType>
+[__readNone]
+[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
+T fwidth_fine(T p)
+{
+ __requireComputeDerivative();
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "abs(ddx_fine($0)) + abs(ddy_fine($0))";
+ case glsl:
+ __intrinsic_asm "fwidthFine($0)";
+ case spirv:
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthFine $$T result $p;
+ };
+ }
+}
+
+__generic<T : __BuiltinFloatingPointType, let N : int>
+[__readNone]
+[require(glsl_hlsl_spirv, fragmentprocessing_derivativecontrol)]
+vector<T, N> fwidth_fine(vector<T, N> x)
+{
+ __requireComputeDerivative();
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "abs(ddx_fine($0)) + abs(ddy_fine($0))";
+ case glsl:
+ __intrinsic_asm "fwidthFine($0)";
+ case spirv:
+ return spirv_asm
+ {
+ OpCapability DerivativeControl;
+ OpFwidthFine $$vector<T, N> result $x;
+ };
+ }
+}
+
+__generic<T : __BuiltinFloatingPointType, let N : int, let M : int>
+[__readNone]
+[require(glsl_hlsl_spirv, fragmentprocessing)]
+matrix<T, N, M> fwidth_fine(matrix<T, N, M> x)
+{
+ __target_switch
+ {
+ case hlsl:
+ __intrinsic_asm "abs(ddx_fine($0)) + abs(ddy_fine($0))";
+ default:
+ MATRIX_MAP_UNARY(T, N, M, fwidth_fine, x);
+ }
+}
+
__intrinsic_op($(kIROp_ResolveVaryingInputRef))
Ref<T> __ResolveVaryingInputRef<T>(__constref T attribute);
diff --git a/tests/hlsl-intrinsic/fragment-derivative.slang b/tests/hlsl-intrinsic/fragment-derivative.slang
new file mode 100644
index 000000000..ff605aae6
--- /dev/null
+++ b/tests/hlsl-intrinsic/fragment-derivative.slang
@@ -0,0 +1,105 @@
+//TEST:SIMPLE(filecheck=CHECK_HLSL): -target hlsl -stage fragment -entry main
+//TEST:SIMPLE(filecheck=CHECK_SPV): -target spirv -emit-spirv-directly -stage fragment -entry main
+//TEST:SIMPLE(filecheck=CHECK_GLSL): -target glsl -stage fragment -entry main
+
+bool testFragmentProcessingDerivativeFunctionsScalar()
+{
+// CHECK_HLSL: ddx
+// CHECK_SPV: OpDPdx
+// CHECK_GLSL: dFdx
+// CHECK_HLSL: ddy
+// CHECK_SPV: OpDPdy
+// CHECK_GLSL: dFdy
+// CHECK_HLSL: ddx_fine
+// CHECK_SPV: OpDPdxFine
+// CHECK_GLSL: dFdxFine
+// CHECK_HLSL: ddy_fine
+// CHECK_SPV: OpDPdyFine
+// CHECK_GLSL: dFdyFine
+// CHECK_HLSL: ddx_coarse
+// CHECK_SPV: OpDPdxCoarse
+// CHECK_GLSL: dFdxCoarse
+// CHECK_HLSL: ddy_coarse
+// CHECK_SPV: OpDPdyCoarse
+// CHECK_GLSL: dFdyCoarse
+// CHECK_HLSL: fwidth
+// CHECK_SPV: OpFwidth
+// CHECK_GLSL: fwidth
+// CHECK_HLSL: abs(ddx_fine({{.*}})) + abs(ddy_fine({{.*}}))
+// CHECK_SPV: OpFwidthFine
+// CHECK_GLSL: fwidthFine
+// CHECK_HLSL: abs(ddx_coarse({{.*}})) + abs(ddy_coarse({{.*}}))
+// CHECK_SPV: OpFwidthCoarse
+// CHECK_GLSL: fwidthCoarse
+ return true
+ && ddx(1.0f) != -1.0f
+ && ddy(1.0f) != -1.0f
+ && ddx_fine(1.0f) != -1.0f
+ && ddy_fine(1.0f) != -1.0f
+ && ddx_coarse(1.0f) != -1.0f
+ && ddy_coarse(1.0f) != -1.0f
+ && fwidth(1.0f) != -1.0f
+ && fwidth_fine(1.0f) != -1.0f
+ && fwidth_coarse(1.0f) != -1.0f
+ ;
+}
+__generic<let N:int>
+bool testFragmentProcessingDerivativeFunctionsVector()
+{
+// CHECK_HLSL: ddx
+// CHECK_SPV: OpDPdx
+// CHECK_GLSL: dFdx
+// CHECK_HLSL: ddy
+// CHECK_SPV: OpDPdy
+// CHECK_GLSL: dFdy
+// CHECK_HLSL: ddx_fine
+// CHECK_SPV: OpDPdxFine
+// CHECK_GLSL: dFdxFine
+// CHECK_HLSL: ddy_fine
+// CHECK_SPV: OpDPdyFine
+// CHECK_GLSL: dFdyFine
+// CHECK_HLSL: ddx_coarse
+// CHECK_SPV: OpDPdxCoarse
+// CHECK_GLSL: dFdxCoarse
+// CHECK_HLSL: ddy_coarse
+// CHECK_SPV: OpDPdyCoarse
+// CHECK_GLSL: dFdyCoarse
+// CHECK_HLSL: fwidth
+// CHECK_SPV: OpFwidth
+// CHECK_GLSL: fwidth
+// CHECK_HLSL: abs(ddx_fine({{.*}})) + abs(ddy_fine({{.*}}))
+// CHECK_SPV: OpFwidthFine
+// CHECK_GLSL: fwidthFine
+// CHECK_HLSL: abs(ddx_coarse({{.*}})) + abs(ddy_coarse({{.*}}))
+// CHECK_SPV: OpFwidthCoarse
+// CHECK_GLSL: fwidthCoarse
+ return true
+ && all(ddx(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(ddy(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(ddx_fine(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(ddy_fine(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(ddx_coarse(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(ddy_coarse(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(fwidth(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(fwidth_fine(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ && all(fwidth_coarse(vector<float,N>(1.0f)) != vector<float,N>(-1.0f))
+ ;
+}
+
+bool testFragmentProcessingFunctions()
+{
+ return true
+ && testFragmentProcessingDerivativeFunctionsScalar()
+ && testFragmentProcessingDerivativeFunctionsVector<2>()
+ && testFragmentProcessingDerivativeFunctionsVector<3>()
+ && testFragmentProcessingDerivativeFunctionsVector<4>()
+ ;
+ ;
+}
+
+[shader("pixel")]
+int4 main() : SV_Target {
+ return int4(true
+ && testFragmentProcessingFunctions()
+ );
+}
diff --git a/tests/spirv/fwidth.slang b/tests/spirv/fwidth.slang
index a55dfa3b0..a65e799f5 100644
--- a/tests/spirv/fwidth.slang
+++ b/tests/spirv/fwidth.slang
@@ -17,50 +17,66 @@ void main()
float b2 = ddy(w);
output[2] = b2;
- // CHECK: OpDPdxCoarse
- float b3 = ddx_coarse(w);
+ // CHECK: OpFwidthCoarse
+ float b3 = fwidth_coarse(w);
output[3] = b3;
- // CHECK: OpDPdyCoarse
- float b4 = ddy_coarse(w);
+ // CHECK: OpDPdxCoarse
+ float b4 = ddx_coarse(w);
output[4] = b4;
- // CHECK: OpDPdxFine
- float b5 = ddx_fine(w);
+ // CHECK: OpDPdyCoarse
+ float b5 = ddy_coarse(w);
output[5] = b5;
- // CHECK: OpDPdyFine
- float b6 = ddy_fine(w);
+ // CHECK: OpFwidthFine
+ float b6 = fwidth_fine(w);
output[6] = b6;
+
+ // CHECK: OpDPdxFine
+ float b7 = ddx_fine(w);
+ output[7] = b7;
+
+ // CHECK: OpDPdyFine
+ float b8 = ddy_fine(w);
+ output[8] = b8;
}
{
// CHECK: OpFwidth
float3 w = 1.0;
float3 b = fwidth(w);
- output[7] = b.x;
+ output[9] = b.x;
// CHECK: OpDPdx
float3 b1 = ddx(w);
- output[8] = b1.x;
+ output[10] = b1.x;
// CHECK: OpDPdy
float3 b2 = ddy(w);
- output[9] = b2.x;
+ output[11] = b2.x;
+
+ // CHECK: OpFwidthCoarse
+ float3 b3 = fwidth_coarse(w);
+ output[12] = b3.x;
// CHECK: OpDPdxCoarse
- float3 b3 = ddx_coarse(w);
- output[10] = b3.x;
+ float3 b4 = ddx_coarse(w);
+ output[13] = b4.x;
// CHECK: OpDPdyCoarse
- float3 b4 = ddy_coarse(w);
- output[11] = b4.x;
+ float3 b5 = ddy_coarse(w);
+ output[14] = b5.x;
+
+ // CHECK: OpFwidthFine
+ float3 b6 = fwidth_fine(w);
+ output[15] = b6.x;
// CHECK: OpDPdxFine
- float3 b5 = ddx_fine(w);
- output[12] = b5.x;
+ float3 b7 = ddx_fine(w);
+ output[16] = b7.x;
// CHECK: OpDPdyFine
- float3 b6 = ddy_fine(w);
- output[13] = b6.x;
+ float3 b8 = ddy_fine(w);
+ output[17] = b8.x;
}
}