Match step's NaN result to what dxc emits
dxc 1.9.0.5402 (dxc_2026_07_29, lib_6_3, -HV 2021, -Od) lowers step(e, x) to fcmp olt x, e; select 0 : 1, so NaN on either side gives 1. The previous x >= e ? 1 : 0 rule came from prose, not the compiler. math.step and cultmath_step now use x < e ? 0 : 1 for every overload; the mirror's cultmath_step compiles to the same fcmp/select as the intrinsic. Unity shader copy synced; DLL rebuilt and byte-checked by build-unity-package.ps1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
10b2c15fb8
commit
e0a054a7b4
7 changed files with 8 additions and 8 deletions
|
|
@ -40,8 +40,8 @@ That makes these HLSL rules, not options:
|
|||
- Scalar/vector arithmetic and comparisons have explicit overloads on both
|
||||
sides rather than leaning on implicit scalar splat.
|
||||
- Intrinsics return HLSL's types and edge cases: `sign` returns `int`/`intN`
|
||||
(NaN gives 0); `step(y, x)` is `x >= y ? 1 : 0` (NaN gives 0), in C# and in the
|
||||
HLSL mirror; `any`/`all` accept numeric vectors (a component is true when it is
|
||||
(NaN gives 0); `step(y, x)` is `x < y ? 0 : 1` (NaN gives 1), which is how dxc
|
||||
lowers it, in C# and in the HLSL mirror; `any`/`all` accept numeric vectors (a component is true when it is
|
||||
not 0); `min`, `max`, and `abs` on int vectors return int vectors.
|
||||
|
||||
Deferred until a consumer needs them: `float4x4`, `transpose`, `determinant`,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ float2 cultmath_lerp(float2 start, float2 end, float2 amount) { return start + (
|
|||
float3 cultmath_lerp(float3 start, float3 end, float3 amount) { return start + (end - start) * amount; }
|
||||
float4 cultmath_lerp(float4 start, float4 end, float4 amount) { return start + (end - start) * amount; }
|
||||
|
||||
float cultmath_step(float edge, float value) { return value >= edge ? 1.0 : 0.0; }
|
||||
float cultmath_step(float edge, float value) { return value < edge ? 0.0 : 1.0; }
|
||||
float2 cultmath_step(float2 edge, float2 value) { return float2(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y)); }
|
||||
float3 cultmath_step(float3 edge, float3 value) { return float3(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z)); }
|
||||
float4 cultmath_step(float4 edge, float4 value) { return float4(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z), cultmath_step(edge.w, value.w)); }
|
||||
|
|
|
|||
|
|
@ -150,8 +150,8 @@ public static partial class math
|
|||
public static double2 unlerp(double2 start, double2 end, double2 value) => (value - start) / (end - start);
|
||||
public static double3 unlerp(double3 start, double3 end, double3 value) => (value - start) / (end - start);
|
||||
|
||||
// HLSL: step(y, x) = x >= y ? 1 : 0, so a NaN on either side yields 0.
|
||||
public static float step(float edge, float value) => value >= edge ? 1.0f : 0.0f;
|
||||
// dxc lowers step(y, x) to x < y ? 0 : 1 (fcmp olt, then select), so a NaN on either side yields 1.
|
||||
public static float step(float edge, float value) => value < edge ? 0.0f : 1.0f;
|
||||
public static float2 step(float2 edge, float2 value) => new(step(edge.x, value.x), step(edge.y, value.y));
|
||||
public static float3 step(float3 edge, float3 value) => new(step(edge.x, value.x), step(edge.y, value.y), step(edge.z, value.z));
|
||||
public static float4 step(float4 edge, float4 value) => new(step(edge.x, value.x), step(edge.y, value.y), step(edge.z, value.z), step(edge.w, value.w));
|
||||
|
|
|
|||
|
|
@ -161,8 +161,8 @@ public sealed class HlslSemanticsTests
|
|||
Assert.Equal(new int4(1, 2, 0, 3), math.abs(new int4(-1, 2, 0, -3)));
|
||||
Assert.Equal(7, math.abs(-7));
|
||||
|
||||
Assert.Equal(0.0f, math.step(1.0f, float.NaN));
|
||||
Assert.Equal(0.0f, math.step(float.NaN, 1.0f));
|
||||
Assert.Equal(1.0f, math.step(1.0f, float.NaN));
|
||||
Assert.Equal(1.0f, math.step(float.NaN, 1.0f));
|
||||
Assert.Equal(1.0f, math.step(1.0f, 1.0f));
|
||||
|
||||
Assert.Equal(0, math.sign(float.NaN));
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -36,7 +36,7 @@ float2 cultmath_lerp(float2 start, float2 end, float2 amount) { return start + (
|
|||
float3 cultmath_lerp(float3 start, float3 end, float3 amount) { return start + (end - start) * amount; }
|
||||
float4 cultmath_lerp(float4 start, float4 end, float4 amount) { return start + (end - start) * amount; }
|
||||
|
||||
float cultmath_step(float edge, float value) { return value >= edge ? 1.0 : 0.0; }
|
||||
float cultmath_step(float edge, float value) { return value < edge ? 0.0 : 1.0; }
|
||||
float2 cultmath_step(float2 edge, float2 value) { return float2(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y)); }
|
||||
float3 cultmath_step(float3 edge, float3 value) { return float3(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z)); }
|
||||
float4 cultmath_step(float4 edge, float4 value) { return float4(cultmath_step(edge.x, value.x), cultmath_step(edge.y, value.y), cultmath_step(edge.z, value.z), cultmath_step(edge.w, value.w)); }
|
||||
|
|
|
|||
Loading…
Reference in a new issue