From 6d0a0c147d09b198ae948cd2817962cbfff16b41 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 3 Oct 2026 13:40:16 +0200 Subject: [PATCH] CultMath design.md and README: the two GLSL files, the concatenation order, the fixture's platform tolerance Co-Authored-By: Claude Opus 5.5 --- packages/cultmath/README.md | 11 ++++--- packages/cultmath/docs/design.md | 49 +++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/packages/cultmath/README.md b/packages/cultmath/README.md index b9ca6e0b..0b12819e 100644 --- a/packages/cultmath/README.md +++ b/packages/cultmath/README.md @@ -47,12 +47,15 @@ shader semantics. carved sphere): its interval over the segment proves empty space in one probe, and the noise ball is consulted only near the surface. See `docs/design.md`, "Intervals". -- `shaders/CultMath.glsl`, the same `cultmath_*` library in GLSL ES 3.00 for - WebGL2, generated from `CultMath.hlsl` (never edited by hand). GLSL has no - `#include`: a WebGL consumer concatenates the file's text after its own +- `shaders/CultMath.glsl` (MIT), the same `cultmath_*` library in GLSL ES 3.00 + for WebGL2, generated from `CultMath.hlsl` (never edited by hand), and + `shaders/CultMath.Phacelle.glsl` (MPL-2.0), generated from + `CultMath.Phacelle.hlsl`, which holds `cultmath_phacelle` alone. GLSL has no + `#include`: a WebGL consumer concatenates `CultMath.glsl` after its own `#version 300 es` line and `precision highp float; precision highp int;` (the library declares no precision, and its hashes need 32-bit integers), - then appends its own shader source. + then `CultMath.Phacelle.glsl` only if it calls `cultmath_phacelle`, then its + own shader source. - `Voronoi.SampleTones`, a C# batch surface that calls the Rust `cultmath-core` native kernel when `cultmath_core` is available and falls back to the managed parity path otherwise. diff --git a/packages/cultmath/docs/design.md b/packages/cultmath/docs/design.md index 73793212..4d9558d7 100644 --- a/packages/cultmath/docs/design.md +++ b/packages/cultmath/docs/design.md @@ -136,20 +136,28 @@ it fails the same walk that already handles a bare vector return. ### GLSL Target: Source Transformations `shaders/CultMath.glsl` is a GLSL ES 3.00 (WebGL2) library generated from -`shaders/CultMath.hlsl` by `GlslLowering` (in the test project). It is a derived -file: never edit it by hand. Regenerate it, and the golden fixture +`shaders/CultMath.hlsl` by `GlslLowering` (in the test project), and +`shaders/CultMath.Phacelle.glsl` is generated beside it from +`shaders/CultMath.Phacelle.hlsl`. Both are derived files: never edit them by +hand. Regenerate them, and the golden fixture `tests/CultMath.Tests/fixtures/glsl-parity.json`, with: ```powershell $env:CULTMATH_WRITE_GLSL = "1"; dotnet test packages/cultmath/tests/CultMath.Tests --filter GlslMirrorTests ``` -`GlslMirrorTests.CommittedGlslEqualsLowering` fails on any difference between the -committed file and the lowering of the committed HLSL. These transformations, -in order, are the complete list: +`GlslMirrorTests.CommittedGlslEqualsLowering` fails on any difference between +either committed file and the lowering of the committed HLSL. These +transformations, in order, are the complete list: 1. Each `#include "name"` is replaced in place by the included file, by the - same resolver the C# mirror uses; GLSL has no `#include`. + same resolver the C# mirror uses; GLSL has no `#include`. The exception is + an include under a file-level licence of its own, listed in one table, + `GlslLowering.SeparateFiles`: its line is dropped and the file is lowered on + its own, by the same steps, into its own output. The table has one entry, + `CultMath.Phacelle.hlsl` to `CultMath.Phacelle.glsl`, because Phacelle is + MPL-2.0 and MPL-2.0 is file-level: kept separate, it leaves + `CultMath.glsl` MIT. Nothing else in the lowering is keyed by name. 2. Include guards are dropped, and so are the functions taking `Texture2D`/`SamplerState`; the host shader samples its own textures. 3. Type names: `floatN`, `intN`, `uintN` and `boolN` become `vecN`, `ivecN`, @@ -162,8 +170,11 @@ in order, are the complete list: `inversesqrt`, `asuint` to `floatBitsToUint`, `asfloat` to `uintBitsToFloat`, and `saturate(x)` becomes `clamp(x, 0.0, 1.0)`. 7. Float literals pass through unchanged. -8. The library is wrapped in a `CULTMATH_GLSL` guard. -9. The first line names the file as generated and says how to regenerate it. +8. Each output is wrapped in a guard named for its file: `CULTMATH_GLSL`, + `CULTMATH_PHACELLE_GLSL`. +9. The first line names the file as generated, its sources and its licence, + and says how to regenerate it; `CultMath.glsl`'s also says which + functions live in the separate file. GLSL ES 3.00 is stricter than HLSL: no implicit conversions between int, uint and float, no C-style casts, and no `step(genType, float)` overload. Those gaps @@ -180,16 +191,26 @@ The library declares no precision. The host shader does, and it must be integers. `tools/compile-glsl.ps1` writes such a wrapper (its own `#version 300 es` line, the precision, the library by string concatenation, and one call of every public function) and compiles it with glslang, which -`tools/get-glslang.ps1` fetches pinned. The Unity package does not ship the -GLSL file. +`tools/get-glslang.ps1` fetches pinned. It runs twice: over `CultMath.glsl` +alone, and with `-Phacelle` over `CultMath.glsl` followed by +`CultMath.Phacelle.glsl`, the order a consumer that calls `cultmath_phacelle` +concatenates them in. Two negative controls must fail: `-Body` with an HLSL +token (`float x = lerp(0.0, 1.0, 0.5);`), and `-Body` calling +`cultmath_phacelle` without `-Phacelle`, which proves the MIT file does not +carry it. The Unity package ships neither GLSL file. Parity runs in two legs, each with one owner: HLSL against C# by the mirror test, bit for bit; GLSL against C# by the golden fixture, which records 256 seeded cases per function family as float32 bit patterns, evaluated by the -consumer on WebGL2 and read back. Integer-only families (`pcg3d`, `pcg4d`) must -match exactly; float families are ulp-bounded, the bound measured on the device. -`iv_exp` is not in the fixture, because its C# bits come from the platform's -`exp`. +consumer on WebGL2 and read back. The families `pcg3d`, `pcg4d` and +`iv_frustum_ball` are marked exact; the other float families are ulp-bounded, +the bound measured on the device. `iv_exp` is in the fixture so the site can +measure WebGL2's `exp`, but its C# bits come from the platform's `exp` and +differ by OS: its tolerance is "ulp-bounded, platform exp", its entry names the +platform that generated it, and `GoldenFixtureMatchesCSharp` compares it case +by case within one ulp of the running platform, printing the largest distance. +Every other family is compared as text. Every fixture family is in +`CultMath.glsl`, so the parity run needs no `CultMath.Phacelle.glsl`. ## Invariant 8: Value-and-Gradient Primitives