@aardworx/wombat.rendering 0.19.9 → 0.19.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,293 @@
1
+ // CPU interpreter for derived-uniform rule IR (a wombat.shader `Expr`).
2
+ //
3
+ // Evaluates a `derivedUniform(u => …)` rule in DOUBLE precision (M44d / V3d /
4
+ // …) — no df32 dual-float trick, no GPU constituent slots. The heap path
5
+ // compiles rules into a §7 GPU compute pass (f32, df32 for the inverse trick);
6
+ // here we just interpret the IR with f64 host math (`M44d.inverse()` is exact
7
+ // enough that the backward-storage trick is unnecessary), and `writeField`
8
+ // narrows the result to f32 at pack time.
9
+ //
10
+ // Used by the legacy per-RO uniform path so derived uniforms work on ROs that
11
+ // aren't heap-eligible (a storage buffer, 2+ textures, …). The evaluator is a
12
+ // standalone `Expr → value` function so other CPU rule paths can reuse it.
13
+ import { V2d, V3d, V4d, M22d, M33d, M44d } from "@aardworx/wombat.base";
14
+ // ── runtime classification ───────────────────────────────────────────────
15
+ function isVec(v) {
16
+ return v instanceof V2d || v instanceof V3d || v instanceof V4d;
17
+ }
18
+ function isMat(v) {
19
+ return v instanceof M22d || v instanceof M33d || v instanceof M44d;
20
+ }
21
+ function data(v) { return v._data; }
22
+ function num(v) {
23
+ if (typeof v === "number")
24
+ return v;
25
+ if (typeof v === "boolean")
26
+ return v ? 1 : 0;
27
+ throw new Error("derived eval: expected scalar, got " + describe(v));
28
+ }
29
+ function describe(v) {
30
+ if (isVec(v))
31
+ return "vec" + data(v).length;
32
+ if (isMat(v))
33
+ return "mat";
34
+ return typeof v;
35
+ }
36
+ function vecOf(d) {
37
+ switch (d.length) {
38
+ case 2: return new V2d(d[0], d[1]);
39
+ case 3: return new V3d(d[0], d[1], d[2]);
40
+ case 4: return new V4d(d[0], d[1], d[2], d[3]);
41
+ default: throw new Error("derived eval: bad vector arity " + d.length);
42
+ }
43
+ }
44
+ // ── leaf coercion (by the IR leaf type) ──────────────────────────────────
45
+ function toM44(raw) {
46
+ if (raw instanceof M44d)
47
+ return raw;
48
+ const o = raw;
49
+ if (o && o.forward !== undefined)
50
+ return toM44(o.forward); // Trafo3d → forward
51
+ if (o && o._data !== undefined && o._data.length >= 16)
52
+ return M44d.fromArray(o._data); // M44f
53
+ throw new Error("derived eval: leaf is not a mat4: " + describe(raw));
54
+ }
55
+ function upperLeft3(m) {
56
+ const d = data(m); // row-major r*4+c
57
+ return M33d.fromArray([d[0], d[1], d[2], d[4], d[5], d[6], d[8], d[9], d[10]]);
58
+ }
59
+ function toM33(raw) {
60
+ if (raw instanceof M33d)
61
+ return raw;
62
+ const o = raw;
63
+ if (raw instanceof M44d)
64
+ return upperLeft3(raw);
65
+ if (o && o.forward !== undefined)
66
+ return upperLeft3(toM44(o.forward));
67
+ if (o && o._data !== undefined && o._data.length === 9)
68
+ return M33d.fromArray(o._data);
69
+ if (o && o._data !== undefined && o._data.length >= 16)
70
+ return upperLeft3(toM44(raw));
71
+ throw new Error("derived eval: leaf is not a mat3: " + describe(raw));
72
+ }
73
+ function toM22(raw) {
74
+ if (raw instanceof M22d)
75
+ return raw;
76
+ const o = raw;
77
+ if (o && o._data !== undefined && o._data.length === 4)
78
+ return M22d.fromArray(o._data);
79
+ throw new Error("derived eval: leaf is not a mat2: " + describe(raw));
80
+ }
81
+ function toVec(raw, n) {
82
+ if (isVec(raw))
83
+ return raw;
84
+ const o = raw;
85
+ if (o && o._data !== undefined) {
86
+ const d = o._data;
87
+ return vecOf(n === 2 ? [d[0], d[1]] : n === 3 ? [d[0], d[1], d[2]] : [d[0], d[1], d[2], d[3]]);
88
+ }
89
+ throw new Error("derived eval: leaf is not a vec" + n + ": " + describe(raw));
90
+ }
91
+ function coerce(raw, t) {
92
+ switch (t.kind) {
93
+ case "Matrix": return t.rows === 4 ? toM44(raw) : t.rows === 3 ? toM33(raw) : toM22(raw);
94
+ case "Vector": return toVec(raw, t.dim);
95
+ case "Float": return Number(raw);
96
+ case "Int": return Math.trunc(Number(raw));
97
+ case "Bool": return Boolean(raw);
98
+ default: throw new Error("derived eval: unsupported leaf type " + t.kind);
99
+ }
100
+ }
101
+ // ── arithmetic over scalar / vector / matrix ─────────────────────────────
102
+ function negate(x) {
103
+ if (typeof x === "number")
104
+ return -x;
105
+ if (isVec(x) || isMat(x))
106
+ return remap(x, (a) => -a);
107
+ throw new Error("derived eval: cannot negate " + describe(x));
108
+ }
109
+ /** Map a vector/matrix's components through `f`, returning the same shape. */
110
+ function remap(v, f) {
111
+ const d = data(v);
112
+ const out = new Array(d.length);
113
+ for (let i = 0; i < d.length; i++)
114
+ out[i] = f(d[i]);
115
+ return isMat(v) ? matOf(out) : vecOf(out);
116
+ }
117
+ function matOf(d) {
118
+ switch (d.length) {
119
+ case 4: return M22d.fromArray(d);
120
+ case 9: return M33d.fromArray(d);
121
+ case 16: return M44d.fromArray(d);
122
+ default: throw new Error("derived eval: bad matrix arity " + d.length);
123
+ }
124
+ }
125
+ /** Element-wise binary op, broadcasting a scalar against a vector/matrix. */
126
+ function elementwise(a, b, f) {
127
+ if (typeof a === "number" && typeof b === "number")
128
+ return f(a, b);
129
+ if (isVec(a) || isMat(a)) {
130
+ const da = data(a);
131
+ const out = new Array(da.length);
132
+ if (typeof b === "number") {
133
+ for (let i = 0; i < da.length; i++)
134
+ out[i] = f(da[i], b);
135
+ }
136
+ else {
137
+ const db = data(b);
138
+ for (let i = 0; i < da.length; i++)
139
+ out[i] = f(da[i], db[i]);
140
+ }
141
+ return isMat(a) ? matOf(out) : vecOf(out);
142
+ }
143
+ if (typeof a === "number" && (isVec(b) || isMat(b))) {
144
+ const db = data(b);
145
+ const out = new Array(db.length);
146
+ for (let i = 0; i < db.length; i++)
147
+ out[i] = f(a, db[i]);
148
+ return isMat(b) ? matOf(out) : vecOf(out);
149
+ }
150
+ throw new Error(`derived eval: cannot combine ${describe(a)} and ${describe(b)}`);
151
+ }
152
+ /** `Mul` node — scalar·scalar, scalar·(vec|mat) broadcast, or component-wise
153
+ * vec·vec (mat·mat / mat·vec / vec·mat have their own node kinds). */
154
+ function mulNode(a, b) {
155
+ if (typeof a === "number" && isMat(b))
156
+ return b.mul(a);
157
+ if (typeof b === "number" && isMat(a))
158
+ return a.mul(b);
159
+ return elementwise(a, b, (x, y) => x * y);
160
+ }
161
+ function vlen(v) {
162
+ if (typeof v === "number")
163
+ return Math.abs(v);
164
+ const d = data(v);
165
+ let s = 0;
166
+ for (let i = 0; i < d.length; i++)
167
+ s += d[i] * d[i];
168
+ return Math.sqrt(s);
169
+ }
170
+ function dot(a, b) {
171
+ const da = data(a), db = data(b);
172
+ let s = 0;
173
+ for (let i = 0; i < da.length; i++)
174
+ s += da[i] * db[i];
175
+ return s;
176
+ }
177
+ function normalize(v) {
178
+ const len = vlen(v);
179
+ return len === 0 ? v : remap(v, (x) => x / len);
180
+ }
181
+ function swizzle(v, comps) {
182
+ const d = data(v);
183
+ const idx = (c) => ({ x: 0, y: 1, z: 2, w: 3 }[c] ?? 0);
184
+ if (comps.length === 1)
185
+ return d[idx(comps[0])];
186
+ return vecOf(comps.map((c) => d[idx(c)]));
187
+ }
188
+ function convertMatrix(v, t) {
189
+ if (t.kind === "Matrix" && t.rows === 3 && v instanceof M44d)
190
+ return upperLeft3(v);
191
+ if (isMat(v))
192
+ return v; // identity-ish convert
193
+ throw new Error("derived eval: ConvertMatrix on " + describe(v));
194
+ }
195
+ // ── intrinsics (vec-componentwise where natural) ─────────────────────────
196
+ const UNARY = {
197
+ sin: Math.sin, cos: Math.cos, tan: Math.tan, abs: Math.abs, floor: Math.floor,
198
+ ceil: Math.ceil, sqrt: Math.sqrt, exp: Math.exp, log: Math.log,
199
+ exp2: (x) => 2 ** x, log2: Math.log2, sign: Math.sign, fract: (x) => x - Math.floor(x),
200
+ };
201
+ const BINARY = {
202
+ min: Math.min, max: Math.max, pow: (x, y) => x ** y, atan2: Math.atan2,
203
+ };
204
+ function intrinsic(name, a) {
205
+ if (UNARY[name])
206
+ return typeof a[0] === "number" ? UNARY[name](a[0]) : remap(a[0], UNARY[name]);
207
+ if (BINARY[name])
208
+ return elementwise(a[0], a[1], BINARY[name]);
209
+ switch (name) {
210
+ case "normalize": return normalize(a[0]);
211
+ case "length": return vlen(a[0]);
212
+ case "dot": return dot(a[0], a[1]);
213
+ case "cross": return a[0].cross(a[1]);
214
+ case "distance": return vlen(elementwise(a[0], a[1], (x, y) => x - y));
215
+ case "step": return elementwise(a[1], a[0], (x, edge) => (x < edge ? 0 : 1));
216
+ case "clamp": return elementwise(elementwise(a[0], a[1], Math.max), a[2], Math.min);
217
+ case "mix": { // a + (b - a) * t
218
+ const diff = elementwise(a[1], a[0], (y, x) => y - x);
219
+ const scaled = elementwise(diff, a[2], (d, t) => d * t);
220
+ return elementwise(a[0], scaled, (x, s) => x + s);
221
+ }
222
+ case "reflect": {
223
+ const d = dot(a[0], a[1]);
224
+ return elementwise(a[0], elementwise(a[1], 2 * d, (n, k) => n * k), (i, s) => i - s);
225
+ }
226
+ default: throw new Error("derived eval: unsupported intrinsic '" + name + "'");
227
+ }
228
+ }
229
+ export function interpretExpr(ir, readLeaf, opts = {}) {
230
+ const ev = (e) => {
231
+ switch (e.kind) {
232
+ case "Const": {
233
+ const v = e.value;
234
+ if (v.kind === "Bool")
235
+ return v.value;
236
+ if (v.kind === "Int" || v.kind === "Float")
237
+ return v.value;
238
+ throw new Error("derived eval: null const");
239
+ }
240
+ case "ReadInput": {
241
+ // Scope-agnostic: the readLeaf decides what a name resolves to
242
+ // (uniforms for derived uniforms; uniforms + `declared` for modes).
243
+ const raw = readLeaf(e.name);
244
+ if (raw === undefined)
245
+ throw new Error("derived eval: missing leaf '" + e.name + "'");
246
+ return coerce(raw, e.type);
247
+ }
248
+ case "Var": {
249
+ const v = opts.locals?.get(e.var.name);
250
+ if (v === undefined)
251
+ throw new Error("derived eval: unbound local '" + e.var.name + "'");
252
+ return v;
253
+ }
254
+ case "Call": {
255
+ if (opts.callFn === undefined)
256
+ throw new Error("derived eval: Call '" + e.fn.signature.name + "' but no callFn provided");
257
+ return opts.callFn(e.fn.signature.name, e.args.map(ev));
258
+ }
259
+ case "Neg": return negate(ev(e.value));
260
+ case "Not": return !ev(e.value);
261
+ case "Add": return elementwise(ev(e.lhs), ev(e.rhs), (x, y) => x + y);
262
+ case "Sub": return elementwise(ev(e.lhs), ev(e.rhs), (x, y) => x - y);
263
+ case "Div": return elementwise(ev(e.lhs), ev(e.rhs), (x, y) => x / y);
264
+ case "Mod": return elementwise(ev(e.lhs), ev(e.rhs), (x, y) => x % y);
265
+ case "Mul": return mulNode(ev(e.lhs), ev(e.rhs));
266
+ case "MulMatMat": return ev(e.lhs).mul(ev(e.rhs));
267
+ case "MulMatVec": return ev(e.lhs).mul(ev(e.rhs));
268
+ case "MulVecMat": return ev(e.rhs).transpose().mul(ev(e.lhs));
269
+ case "Transpose": return ev(e.value).transpose();
270
+ case "Inverse": return ev(e.value).inverse();
271
+ case "Determinant": return ev(e.value).determinant();
272
+ case "Dot": return dot(ev(e.lhs), ev(e.rhs));
273
+ case "Cross": return ev(e.lhs).cross(ev(e.rhs));
274
+ case "Length": return vlen(ev(e.value));
275
+ case "ConvertMatrix": return convertMatrix(ev(e.value), e.type);
276
+ case "VecSwizzle": return swizzle(ev(e.value), e.comps);
277
+ case "NewVector": return vecOf(e.components.map((c) => num(ev(c))));
278
+ case "And": return ev(e.lhs) && ev(e.rhs);
279
+ case "Or": return ev(e.lhs) || ev(e.rhs);
280
+ case "Eq": return num(ev(e.lhs)) === num(ev(e.rhs));
281
+ case "Neq": return num(ev(e.lhs)) !== num(ev(e.rhs));
282
+ case "Lt": return num(ev(e.lhs)) < num(ev(e.rhs));
283
+ case "Le": return num(ev(e.lhs)) <= num(ev(e.rhs));
284
+ case "Gt": return num(ev(e.lhs)) > num(ev(e.rhs));
285
+ case "Ge": return num(ev(e.lhs)) >= num(ev(e.rhs));
286
+ case "Conditional": return ev(e.cond) ? ev(e.ifTrue) : ev(e.ifFalse);
287
+ case "CallIntrinsic": return intrinsic(e.op.name, e.args.map(ev));
288
+ default: throw new Error("derived eval: unsupported IR node '" + e.kind + "'");
289
+ }
290
+ };
291
+ return ev(ir);
292
+ }
293
+ //# sourceMappingURL=cpuEval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpuEval.js","sourceRoot":"","sources":["../../../src/runtime/derivedUniforms/cpuEval.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aardworx/wombat.rendering",
3
- "version": "0.19.9",
3
+ "version": "0.19.11",
4
4
  "description": "WebGPU rendering layer for the Wombat TypeScript stack — RenderObject/RenderTask/runtime + window glue, port of Aardvark.Rendering's lower layers on top of WebGPU and wombat.shader.",
5
5
  "license": "MIT",
6
6
  "author": "krauthaufen",
@@ -29,8 +29,13 @@ import {
29
29
  type aval,
30
30
  HashMap,
31
31
  cval,
32
+ AVal,
32
33
  } from "@aardworx/wombat.adaptive";
33
34
  import type { Type } from "@aardworx/wombat.shader/ir";
35
+ import { isDerivedRule } from "../runtime/derivedUniforms/rule.js";
36
+ import { STANDARD_DERIVED_RULES, STANDARD_TRAFO_LEAVES } from "../runtime/derivedUniforms/recipes.js";
37
+ import { interpretExpr } from "../runtime/derivedUniforms/cpuEval.js";
38
+ import { evaluateModeRule } from "../runtime/derivedModes/cpuEval.js";
34
39
  import { prepareAdaptiveBuffer } from "./adaptiveBuffer.js";
35
40
  import { prepareAdaptiveTexture } from "./adaptiveTexture.js";
36
41
  import { prepareAdaptiveSampler } from "./adaptiveSampler.js";
@@ -365,6 +370,8 @@ export class PreparedRenderObject {
365
370
  pipelineCtx: PipelineBuildContext,
366
371
  pipelineState: import("../core/index.js").PipelineState,
367
372
  private readonly active: aval<boolean> | undefined = undefined,
373
+ private readonly modeRules: import("../core/renderObject.js").RenderObject["modeRules"] = undefined,
374
+ private readonly modeUniformReader: ((name: string, token: AdaptiveToken) => unknown) | undefined = undefined,
368
375
  ) {
369
376
  this.groups = groups;
370
377
  this._pipelineCtx = pipelineCtx;
@@ -377,6 +384,28 @@ export class PreparedRenderObject {
377
384
  /** Internal — exposed for tests. The PipelineState the RO is reading. */
378
385
  get pipelineState(): import("../core/index.js").PipelineState { return this._pipelineState; }
379
386
 
387
+ /**
388
+ * Override pipeline-axis values with CPU-evaluated derived-mode rules.
389
+ * Each rule reads per-RO uniforms + the SG-declared default; evaluating
390
+ * under `token` registers the dependency so a uniform/declared change
391
+ * re-keys the pipeline (recompile via the snapshot cache). The heap path
392
+ * does this on a GPU partition kernel — this is the legacy per-RO answer.
393
+ */
394
+ private applyModeRules(snap: PipelineSnap, token: AdaptiveToken): PipelineSnap {
395
+ const mr = this.modeRules;
396
+ const ru = this.modeUniformReader;
397
+ if (mr === undefined || ru === undefined) return snap;
398
+ const read = (name: string): unknown => ru(name, token);
399
+ const ov: Record<string, unknown> = {};
400
+ if (mr.cull !== undefined) ov.cullMode = evaluateModeRule(mr.cull, read, token);
401
+ if (mr.frontFace !== undefined) ov.frontFace = evaluateModeRule(mr.frontFace, read, token);
402
+ if (mr.topology !== undefined) ov.topology = evaluateModeRule(mr.topology, read, token);
403
+ if (mr.depthWrite !== undefined) ov.depthWrite = evaluateModeRule(mr.depthWrite, read, token);
404
+ if (mr.depthCompare !== undefined) ov.depthCompare = evaluateModeRule(mr.depthCompare, read, token);
405
+ if (mr.alphaToCoverage !== undefined) ov.alphaToCoverage = evaluateModeRule(mr.alphaToCoverage, read, token);
406
+ return { ...snap, ...ov };
407
+ }
408
+
380
409
  acquire(): void {
381
410
  for (const r of this.vertexBuffers.values()) r.acquire();
382
411
  if (this.indexBuffer !== undefined) this.indexBuffer.acquire();
@@ -395,7 +424,7 @@ export class PreparedRenderObject {
395
424
  * surrounding sort / record path can read it without forcing.
396
425
  */
397
426
  update(token: AdaptiveToken): void {
398
- const snap = snapshotPipeline(this._pipelineState, token);
427
+ const snap = this.applyModeRules(snapshotPipeline(this._pipelineState, token), token);
399
428
  const key = pipelineKeyOf(snap);
400
429
  let pipeline = this._pipelineCache.get(key);
401
430
  if (pipeline === undefined) {
@@ -747,6 +776,20 @@ export function prepareRenderObject(
747
776
  ...(opts.effectId !== undefined ? { effectId: opts.effectId } : {}),
748
777
  };
749
778
 
779
+ // Derived-mode rules (cull/frontFace/… as a function of per-RO uniforms)
780
+ // are evaluated CPU-side in the legacy path. Build a uniform reader over
781
+ // the RO's provider (resolving nested derived-uniform rules too).
782
+ let modeUniformReader: ((name: string, token: AdaptiveToken) => unknown) | undefined;
783
+ if (obj.modeRules !== undefined) {
784
+ const uniProv = asUniformProvider(obj.uniforms);
785
+ modeUniformReader = (name: string, token: AdaptiveToken): unknown => {
786
+ const v = uniProv.tryGet(name);
787
+ if (v === undefined) return undefined;
788
+ if (isDerivedRule(v)) return interpretExpr(v.ir, (n) => readLeaf(n, uniProv, effect.avalBindings, token));
789
+ return (v as aval<unknown>).getValue(token);
790
+ };
791
+ }
792
+
750
793
  return new PreparedRenderObject(
751
794
  device,
752
795
  vertexBindings, vertexBuffers, vertexViews,
@@ -756,6 +799,8 @@ export function prepareRenderObject(
756
799
  pipelineCtx,
757
800
  obj.pipelineState,
758
801
  obj.active,
802
+ obj.modeRules,
803
+ modeUniformReader,
759
804
  );
760
805
  }
761
806
 
@@ -785,11 +830,14 @@ function mergeUniformInputs(
785
830
  let merged = HashMap.empty<string, aval<unknown>>();
786
831
  for (const f of block.fields) {
787
832
  const u = user.tryGet(f.name);
788
- if (u !== undefined) { merged = merged.add(f.name, u); continue; }
833
+ if (u !== undefined) { merged = merged.add(f.name, resolveUniform(u, user, bindings)); continue; }
789
834
  const getter = bindings?.[f.name];
790
- if (getter === undefined) continue;
791
- const v = getter();
792
- merged = merged.add(f.name, isAval(v) ? (v as aval<unknown>) : cval(v));
835
+ if (getter !== undefined) { merged = merged.add(f.name, resolveUniform(getter(), user, bindings)); continue; }
836
+ // Standard derived recipe by name (ModelViewTrafo, …) — derive it CPU-side
837
+ // here just as the heap path derives it on the GPU, so the legacy path
838
+ // serves the same declared uniforms.
839
+ const recipe = STANDARD_DERIVED_RULES.get(f.name);
840
+ if (recipe !== undefined) merged = merged.add(f.name, ruleToAval(recipe, user, bindings));
793
841
  }
794
842
  return merged;
795
843
  }
@@ -798,6 +846,46 @@ function isAval(v: unknown): boolean {
798
846
  return typeof v === "object" && v !== null && typeof (v as { getValue?: unknown }).getValue === "function";
799
847
  }
800
848
 
849
+ // A uniform binding value is either an aval/constant or a derivedUniform RULE.
850
+ // Rules are evaluated on CPU (cpuEval) in double precision and exposed as a
851
+ // derived aval — the legacy per-RO path's answer to the heap's §7 compute pass.
852
+ type UProvider = import("../core/index.js").IUniformProvider;
853
+ type Bindings = Readonly<Record<string, () => unknown>> | undefined;
854
+
855
+ function resolveUniform(v: unknown, user: UProvider, bindings: Bindings): aval<unknown> {
856
+ if (isDerivedRule(v)) return ruleToAval(v, user, bindings);
857
+ return isAval(v) ? (v as aval<unknown>) : cval(v);
858
+ }
859
+
860
+ function ruleToAval(rule: import("../runtime/derivedUniforms/rule.js").DerivedRule, user: UProvider, bindings: Bindings): aval<unknown> {
861
+ return AVal.custom((token: AdaptiveToken) =>
862
+ interpretExpr(rule.ir, (leaf) => readLeaf(leaf, user, bindings, token)),
863
+ ) as aval<unknown>;
864
+ }
865
+
866
+ // Resolve a `u.<name>` leaf to its current value, recursing through nested
867
+ // rules / standard recipes. Reading the leaf aval's value under `token`
868
+ // registers the dependency, so the derived aval re-evaluates reactively.
869
+ function readLeaf(name: string, user: UProvider, bindings: Bindings, token: AdaptiveToken): unknown {
870
+ const evalRule = (r: unknown): unknown =>
871
+ interpretExpr((r as import("../runtime/derivedUniforms/rule.js").DerivedRule).ir, (n) => readLeaf(n, user, bindings, token));
872
+ const lookup = (n: string): unknown => {
873
+ const u = user.tryGet(n);
874
+ if (u !== undefined) return isDerivedRule(u) ? evalRule(u) : isAval(u) ? (u as aval<unknown>).getValue(token) : u;
875
+ const getter = bindings?.[n];
876
+ if (getter !== undefined) { const v = getter(); return isDerivedRule(v) ? evalRule(v) : isAval(v) ? (v as aval<unknown>).getValue(token) : v; }
877
+ const recipe = STANDARD_DERIVED_RULES.get(n);
878
+ if (recipe !== undefined) return evalRule(recipe);
879
+ return undefined;
880
+ };
881
+ const direct = lookup(name);
882
+ if (direct !== undefined) return direct;
883
+ // Standard recipes read short trafo leaves (Model / View / Proj) that the RO
884
+ // binds under ModelTrafo / ViewTrafo / ProjTrafo — alias them like the heap.
885
+ const alias = STANDARD_TRAFO_LEAVES.get(name);
886
+ return alias !== undefined ? lookup(alias) : undefined;
887
+ }
888
+
801
889
  function ubAsBlock(ub: import("../core/index.js").UniformBlockInfo): import("../core/index.js").UniformBlockInfo {
802
890
  return ub;
803
891
  }
@@ -0,0 +1,65 @@
1
+ // Canonical per-axis enum tables + value mapping for derived modes.
2
+ //
3
+ // Used by the legacy CPU-eval path (derivedModes/cpuEval). heapScene's
4
+ // GPU-routing path keeps a parallel inline copy of this table + helpers
5
+ // (heapScene.ts ~AXIS_ENUM_TABLE / resolveAxisValue / resolveDeclaredU32);
6
+ // they must stay in sync — fold both onto this module when convenient.
7
+ // The index↔value mapping is the WebGPU enum order; a rule body returns a
8
+ // u32 index and the renderer maps it to the concrete mode value here.
9
+
10
+ import type { aval, AdaptiveToken } from "@aardworx/wombat.adaptive";
11
+ import type { DerivedModeRule, ModeAxis } from "./rule.js";
12
+
13
+ /** u32 index → mode value, per axis. `blend` has no canonical table —
14
+ * blend rules return object literals directly (see resolveAxisValue). */
15
+ export const AXIS_ENUM_TABLE: { readonly [A in ModeAxis]: ReadonlyArray<unknown> } = {
16
+ cull: ["none", "front", "back"],
17
+ frontFace: ["ccw", "cw"],
18
+ topology: ["point-list", "line-list", "line-strip", "triangle-list", "triangle-strip"],
19
+ depthCompare: ["never", "less", "equal", "less-equal", "greater", "not-equal", "greater-equal", "always"],
20
+ depthWrite: [false, true],
21
+ alphaToCoverage: [false, true],
22
+ blend: [],
23
+ };
24
+
25
+ /**
26
+ * Map a rule's resolved output to its axis-shape value:
27
+ * - object → already the full axis value (e.g. a blend AttachmentBlend).
28
+ * - number → enum-table lookup for enum axes; pass-through otherwise.
29
+ */
30
+ export function resolveAxisValue<A extends ModeAxis>(rule: DerivedModeRule<A>, value: unknown): unknown {
31
+ if (typeof value === "object" && value !== null) return value;
32
+ if (typeof value === "number") {
33
+ const table = AXIS_ENUM_TABLE[rule.axis];
34
+ if (table.length > 0) {
35
+ const v = table[value];
36
+ if (v !== undefined) return v;
37
+ }
38
+ return value;
39
+ }
40
+ return value;
41
+ }
42
+
43
+ /**
44
+ * Resolve a rule's `declared` SG-context value to its u32 index:
45
+ * - omitted → 0 (axis canonical zero).
46
+ * - number → passed through.
47
+ * - aval / string / boolean → looked up in the canonical enum table.
48
+ */
49
+ export function declaredToU32<A extends ModeAxis>(rule: DerivedModeRule<A>, tok: AdaptiveToken): number {
50
+ const d = rule.declared;
51
+ if (d === undefined) return 0;
52
+ const v = (typeof d === "object" && d !== null && "getValue" in (d as object))
53
+ ? (d as aval<unknown>).getValue(tok)
54
+ : d;
55
+ if (typeof v === "number") return v >>> 0;
56
+ const table = AXIS_ENUM_TABLE[rule.axis];
57
+ if (table.length === 0) {
58
+ throw new Error(`derivedModes: axis '${rule.axis}' has no canonical enum table; pass \`declared\` as a u32 index or omit it`);
59
+ }
60
+ const i = table.indexOf(v);
61
+ if (i < 0) {
62
+ throw new Error(`derivedModes: declared value '${String(v)}' for axis '${rule.axis}' not in canonical enum table ${JSON.stringify(table)}`);
63
+ }
64
+ return i;
65
+ }
@@ -0,0 +1,104 @@
1
+ // CPU evaluation of a derived-MODE rule for the legacy per-RO path.
2
+ //
3
+ // A `derivedMode(...)` rule is a RuleExpr whose body computes a pipeline-axis
4
+ // value (cull / frontFace / …) from per-RO uniforms (e.g. determinant of the
5
+ // model matrix) and the SG-declared default. The heap path lowers this to a
6
+ // GPU partition kernel; the legacy per-RO path has no kernel, so we evaluate
7
+ // the rule body on the CPU here — the "v1 evaluates rules CPU-side" design in
8
+ // core/renderObject.ts.
9
+ //
10
+ // Reuses the matrix-aware expression interpreter (derivedUniforms/cpuEval) and
11
+ // adds a small Stmt walker (locals + control flow) plus user-function `Call`
12
+ // resolution against the rule's own Module (helpers like `flipCull` are NOT
13
+ // inlined — they're separate Function items in template.values).
14
+
15
+ import type { Expr, Stmt, ValueDef } from "@aardworx/wombat.shader/ir";
16
+ import type { AdaptiveToken } from "@aardworx/wombat.adaptive";
17
+ import { interpretExpr, type EvalValue } from "../derivedUniforms/cpuEval.js";
18
+ import type { DerivedModeRule, ModeAxis, ModeValue } from "./rule.js";
19
+ import { declaredToU32, resolveAxisValue } from "./axisEnum.js";
20
+
21
+ const NO_RETURN = Symbol("no-return");
22
+ type RunResult = EvalValue | typeof NO_RETURN;
23
+
24
+ interface FnDef { readonly params: readonly string[]; readonly body: Stmt; }
25
+
26
+ function truthy(v: EvalValue): boolean {
27
+ return typeof v === "boolean" ? v : typeof v === "number" ? v !== 0 : true;
28
+ }
29
+
30
+ /**
31
+ * Evaluate a derived-mode rule to its concrete axis value for one RO.
32
+ * `readUniform(name)` returns the RO's current value for a `u.<name>` leaf
33
+ * (Trafo3d / M44f / number / …); reading it under `token` registers the
34
+ * dependency so the pipeline re-keys when it changes. Returns the mapped
35
+ * mode value (e.g. "back", or `true` for depthWrite).
36
+ */
37
+ export function evaluateModeRule<A extends ModeAxis>(
38
+ rule: DerivedModeRule<A>,
39
+ readUniform: (name: string) => unknown,
40
+ token: AdaptiveToken,
41
+ ): ModeValue<A> {
42
+ // Collect helper functions + the entry body from the rule's Module.
43
+ const fns = new Map<string, FnDef>();
44
+ let body: Stmt | undefined;
45
+ for (const v of rule.expr.template.values as readonly ValueDef[]) {
46
+ if (v.kind === "Function") fns.set(v.signature.name, { params: v.signature.parameters.map((p) => p.name), body: v.body });
47
+ else if (v.kind === "Entry") body = v.entry.body;
48
+ }
49
+ if (body === undefined) {
50
+ throw new Error(`derivedModes: rule for axis '${rule.axis}' has no Entry in its template`);
51
+ }
52
+
53
+ const declaredU32 = declaredToU32(rule, token);
54
+ const readLeaf = (name: string): unknown => (name === "declared" ? declaredU32 : readUniform(name));
55
+
56
+ // Mutually-recursive: an expr `Call` runs a function body; a function body
57
+ // evaluates exprs via interpretExpr with `callFn` wired back here.
58
+ const callFn = (name: string, args: EvalValue[]): EvalValue => {
59
+ const fn = fns.get(name);
60
+ if (fn === undefined) throw new Error(`derivedModes: rule calls unknown function '${name}'`);
61
+ const locals = new Map<string, EvalValue>();
62
+ fn.params.forEach((p, i) => { if (args[i] !== undefined) locals.set(p, args[i]!); });
63
+ return evalBody(fn.body, locals);
64
+ };
65
+ const evalExpr = (e: Expr, locals: Map<string, EvalValue>): EvalValue =>
66
+ interpretExpr(e, readLeaf, { locals, callFn });
67
+
68
+ const run = (s: Stmt, locals: Map<string, EvalValue>): RunResult => {
69
+ switch (s.kind) {
70
+ case "Sequential":
71
+ case "Isolated": {
72
+ for (const c of s.body) { const r = run(c, locals); if (r !== NO_RETURN) return r; }
73
+ return NO_RETURN;
74
+ }
75
+ case "Declare": {
76
+ if (s.init !== undefined && s.init.kind === "Expr") locals.set(s.var.name, evalExpr(s.init.value, locals));
77
+ return NO_RETURN;
78
+ }
79
+ case "Write": {
80
+ if (s.target.kind === "LVar") locals.set(s.target.var.name, evalExpr(s.value, locals));
81
+ return NO_RETURN;
82
+ }
83
+ case "If": {
84
+ if (truthy(evalExpr(s.cond, locals))) return run(s.then, locals);
85
+ return s.else !== undefined ? run(s.else, locals) : NO_RETURN;
86
+ }
87
+ case "ReturnValue": return evalExpr(s.value, locals);
88
+ case "Expression":
89
+ case "Nop":
90
+ case "Return":
91
+ return NO_RETURN;
92
+ default:
93
+ throw new Error(`derivedModes: unsupported statement '${s.kind}' in rule body`);
94
+ }
95
+ };
96
+ const evalBody = (b: Stmt, locals: Map<string, EvalValue>): EvalValue => {
97
+ const r = run(b, locals);
98
+ if (r === NO_RETURN) throw new Error(`derivedModes: rule body for axis '${rule.axis}' produced no return value`);
99
+ return r;
100
+ };
101
+
102
+ const raw = evalBody(body, new Map());
103
+ return resolveAxisValue(rule, raw) as ModeValue<A>;
104
+ }