@aardworx/wombat.rendering 0.9.17 → 0.9.19
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.
- package/dist/core/renderObject.d.ts +19 -0
- package/dist/core/renderObject.d.ts.map +1 -1
- package/dist/runtime/derivedModes/gpuDispatcher.d.ts +46 -0
- package/dist/runtime/derivedModes/gpuDispatcher.d.ts.map +1 -0
- package/dist/runtime/derivedModes/gpuDispatcher.js +170 -0
- package/dist/runtime/derivedModes/gpuDispatcher.js.map +1 -0
- package/dist/runtime/derivedModes/gpuKernel.d.ts +9 -0
- package/dist/runtime/derivedModes/gpuKernel.d.ts.map +1 -0
- package/dist/runtime/derivedModes/gpuKernel.js +97 -0
- package/dist/runtime/derivedModes/gpuKernel.js.map +1 -0
- package/dist/runtime/derivedModes/rule.d.ts +33 -0
- package/dist/runtime/derivedModes/rule.d.ts.map +1 -1
- package/dist/runtime/derivedModes/rule.js +39 -0
- package/dist/runtime/derivedModes/rule.js.map +1 -1
- package/dist/runtime/heapAdapter.d.ts.map +1 -1
- package/dist/runtime/heapAdapter.js +1 -0
- package/dist/runtime/heapAdapter.js.map +1 -1
- package/dist/runtime/heapScene.d.ts.map +1 -1
- package/dist/runtime/heapScene.js +78 -0
- package/dist/runtime/heapScene.js.map +1 -1
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +3 -1
- package/dist/runtime/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/renderObject.ts +19 -0
- package/src/runtime/derivedModes/gpuDispatcher.ts +190 -0
- package/src/runtime/derivedModes/gpuKernel.ts +98 -0
- package/src/runtime/derivedModes/rule.ts +62 -0
- package/src/runtime/heapAdapter.ts +1 -0
- package/src/runtime/heapScene.ts +76 -0
- package/src/runtime/index.ts +9 -0
|
@@ -55,6 +55,8 @@ import { GrowBuffer, MIN_BUFFER_BYTES, POW2, ALIGN16, } from "./heapScene/growBu
|
|
|
55
55
|
import { UniformPool, IndexPool, DrawHeap, AttributeArena, IndexAllocator, insertSortedFreeBlock, buildArenaState, arenaBytes, writeAttribute, asAval, isBufferView, asFloat32, ALLOC_HEADER_BYTES, ALLOC_HEADER_PAD_TO, ENC_V3F_TIGHT, SEM_POSITIONS, SEM_NORMALS, } from "./heapScene/pools.js";
|
|
56
56
|
import { encodeModeKey } from "./pipelineCache/index.js";
|
|
57
57
|
import { snapshotDescriptor, ModeKeyTracker } from "./derivedModes/modeKeyCpu.js";
|
|
58
|
+
import { GpuDerivedModesScene } from "./derivedModes/gpuDispatcher.js";
|
|
59
|
+
import { U32_TO_CULL } from "./derivedModes/gpuKernel.js";
|
|
58
60
|
import { addMarkingCallback } from "@aardworx/wombat.adaptive";
|
|
59
61
|
export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
60
62
|
const atlasPool = opts.atlasPool;
|
|
@@ -335,6 +337,13 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
335
337
|
/** Per-RO §7 registration handles, keyed by global drawId.
|
|
336
338
|
* Drained on removeDraw to release slots + records. */
|
|
337
339
|
const derivedByDrawId = new Map();
|
|
340
|
+
// ─── GPU-eval mode rules (Task 2 Phase 5, narrow) ─────────────────
|
|
341
|
+
// Lazily allocated on first registration; one dispatcher per scene.
|
|
342
|
+
let gpuModesScene;
|
|
343
|
+
/** Last per-RO GPU output we routed to a bucket. Diff against
|
|
344
|
+
* newly-readback values to decide rebuckets without re-bucketing
|
|
345
|
+
* un-changed ROs. */
|
|
346
|
+
const gpuModesLastKey = new Map();
|
|
338
347
|
/** The derived-uniform rule for a uniform binding on this RO, if any: an explicit
|
|
339
348
|
* `derivedUniform(...)` value in `spec.inputs`, or a standard trafo recipe by name
|
|
340
349
|
* (recipes apply only when their base-trafo leaves are actually bound on this RO —
|
|
@@ -1410,6 +1419,21 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
1410
1419
|
});
|
|
1411
1420
|
drawIdToModeTracker[drawId] = tracker;
|
|
1412
1421
|
tracker.forEachLeaf((av) => subscribeModeLeaf(av, drawId));
|
|
1422
|
+
// ─── GPU-eval mode rule registration (Task 2 Phase 5) ────────────
|
|
1423
|
+
// If spec.modeRules.cull is GPU-flavoured, register the RO with
|
|
1424
|
+
// the scene-wide dispatcher. Provide the arena byte offset of the
|
|
1425
|
+
// RO's input uniform so the kernel reads from the right slot.
|
|
1426
|
+
{
|
|
1427
|
+
const gpuRule = spec.modeRules?.cull?.gpu;
|
|
1428
|
+
if (gpuRule !== undefined && gpuRule.kernel === "flipCullByDeterminant") {
|
|
1429
|
+
const inputRef = perDrawRefs.get(gpuRule.inputUniform);
|
|
1430
|
+
if (inputRef !== undefined) {
|
|
1431
|
+
if (gpuModesScene === undefined)
|
|
1432
|
+
gpuModesScene = new GpuDerivedModesScene(device);
|
|
1433
|
+
gpuModesScene.registerRo(drawId, inputRef, gpuRule.declared);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1413
1437
|
// ─── §7 derived-uniforms registration ────────────────────────────
|
|
1414
1438
|
// A uniform binding on this RO is either a value (aval/constant) or a rule —
|
|
1415
1439
|
// collect the rules (explicit `derivedUniform(...)` values + standard trafo
|
|
@@ -1578,6 +1602,10 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
1578
1602
|
}
|
|
1579
1603
|
drawIdToModeTracker[drawId] = undefined;
|
|
1580
1604
|
dirtyModeKeyDrawIds.delete(drawId);
|
|
1605
|
+
if (gpuModesScene !== undefined) {
|
|
1606
|
+
gpuModesScene.deregisterRo(drawId);
|
|
1607
|
+
gpuModesLastKey.delete(drawId);
|
|
1608
|
+
}
|
|
1581
1609
|
stats.totalDraws--;
|
|
1582
1610
|
stats.geometryBytes = arenaBytes(arena);
|
|
1583
1611
|
// GC the bucket if it just emptied (common after reactive
|
|
@@ -1912,6 +1940,55 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
1912
1940
|
* we just swap the bind group + dispatch shape per bucket.
|
|
1913
1941
|
*/
|
|
1914
1942
|
function encodeComputePrep(enc, token) {
|
|
1943
|
+
// GPU-eval derived-mode rules (Task 2 Phase 5): dispatch the
|
|
1944
|
+
// hardcoded determinant-flip-cull kernel + start readback.
|
|
1945
|
+
// Resolved on the next frame's update() — one-frame lag for the
|
|
1946
|
+
// first appearance of a state transition. CPU fallback runs at
|
|
1947
|
+
// addDraw time so the initial bucket assignment is still correct.
|
|
1948
|
+
if (gpuModesScene !== undefined && gpuModesScene.registered > 0) {
|
|
1949
|
+
const numROs = nextDrawId; // upper bound; sparse entries are skipped via 0xFFFFFFFF sentinel
|
|
1950
|
+
gpuModesScene.dispatch(arena.attrs.buffer, numROs, enc);
|
|
1951
|
+
// mapAsync the staging buffer in the background. When it
|
|
1952
|
+
// resolves, diff against gpuModesLastKey to schedule rebuckets.
|
|
1953
|
+
gpuModesScene.finish(numROs).then(() => {
|
|
1954
|
+
const out = gpuModesScene.lastOutput;
|
|
1955
|
+
for (let i = 0; i < numROs; i++) {
|
|
1956
|
+
const cur = out[i] ?? 0xFFFFFFFF;
|
|
1957
|
+
const prev = gpuModesLastKey.get(i);
|
|
1958
|
+
if (cur === 0xFFFFFFFF)
|
|
1959
|
+
continue; // no rule on this RO
|
|
1960
|
+
if (prev === cur)
|
|
1961
|
+
continue;
|
|
1962
|
+
gpuModesLastKey.set(i, cur);
|
|
1963
|
+
// Project the kernel's u32 enum back to a CullMode value,
|
|
1964
|
+
// store on the tracker's modeRules so the next snapshot
|
|
1965
|
+
// picks it up, then schedule a rebucket.
|
|
1966
|
+
const tracker = drawIdToModeTracker[i];
|
|
1967
|
+
const spec = drawIdToSpec[i];
|
|
1968
|
+
if (tracker === undefined || spec === undefined)
|
|
1969
|
+
continue;
|
|
1970
|
+
const cull = U32_TO_CULL[cur];
|
|
1971
|
+
if (cull === undefined)
|
|
1972
|
+
continue;
|
|
1973
|
+
// Inject the GPU result by patching the spec's CPU rule to
|
|
1974
|
+
// return a constant. Slightly hacky but contained: the next
|
|
1975
|
+
// recompute() will read this and route to the right bucket.
|
|
1976
|
+
const patched = {
|
|
1977
|
+
...spec.modeRules,
|
|
1978
|
+
cull: {
|
|
1979
|
+
__derivedModeRule: true, axis: "cull",
|
|
1980
|
+
evaluate: () => cull,
|
|
1981
|
+
},
|
|
1982
|
+
};
|
|
1983
|
+
spec.modeRules = patched;
|
|
1984
|
+
dirtyModeKeyDrawIds.add(i);
|
|
1985
|
+
}
|
|
1986
|
+
}).catch((e) => {
|
|
1987
|
+
// mapAsync can reject if the device was lost or the scene was
|
|
1988
|
+
// disposed mid-readback. Log but don't crash the frame.
|
|
1989
|
+
console.warn("gpuModesScene readback failed:", e);
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1915
1992
|
// §7: derived-uniforms dispatch first — writes into per-bucket
|
|
1916
1993
|
// drawHeap regions before the scan reads anything. One dispatcher
|
|
1917
1994
|
// per bucket; constituents are shared so dirty state propagates
|
|
@@ -2043,6 +2120,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2043
2120
|
arena.indices.destroy();
|
|
2044
2121
|
for (const b of buckets)
|
|
2045
2122
|
destroyBucketResources(b);
|
|
2123
|
+
gpuModesScene?.dispose();
|
|
2046
2124
|
}
|
|
2047
2125
|
// Test-only escape hatch for inspecting megacall bucket state. Not
|
|
2048
2126
|
// part of the public API surface — keep cast at use-site.
|