@aardworx/wombat.rendering 0.19.7 → 0.19.8
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/runtime/heapAdapter.d.ts.map +1 -1
- package/dist/runtime/heapAdapter.js +14 -7
- package/dist/runtime/heapAdapter.js.map +1 -1
- package/dist/runtime/heapEffect.js +1 -1
- package/dist/runtime/heapEffect.js.map +1 -1
- package/dist/runtime/heapEligibility.d.ts.map +1 -1
- package/dist/runtime/heapEligibility.js +26 -19
- package/dist/runtime/heapEligibility.js.map +1 -1
- package/dist/runtime/heapIrBuilders.d.ts.map +1 -1
- package/dist/runtime/heapIrBuilders.js +7 -2
- package/dist/runtime/heapIrBuilders.js.map +1 -1
- package/dist/runtime/heapScene.d.ts +10 -1
- package/dist/runtime/heapScene.d.ts.map +1 -1
- package/dist/runtime/heapScene.js +55 -12
- package/dist/runtime/heapScene.js.map +1 -1
- package/package.json +1 -1
- package/src/runtime/heapAdapter.ts +15 -7
- package/src/runtime/heapEffect.ts +1 -1
- package/src/runtime/heapEligibility.ts +20 -16
- package/src/runtime/heapIrBuilders.ts +12 -2
- package/src/runtime/heapScene.ts +33 -13
|
@@ -60,6 +60,39 @@ import { emitPartitionKernel, substituteReadInputInStmt, collectUniformReadsInSt
|
|
|
60
60
|
import {} from "./derivedModes/rule.js";
|
|
61
61
|
import { addMarkingCallback } from "@aardworx/wombat.adaptive";
|
|
62
62
|
import { analyseOutputSet, evaluateStructural, evaluateStructuralSet, stableStringify, } from "@aardworx/wombat.shader/ir";
|
|
63
|
+
// GrowBuffer + ALIGN16 + MIN_BUFFER_BYTES + POW2 live in ./heapScene/growBuffer.
|
|
64
|
+
// Packers (WGSL-type → JS-value → arena bytes) live in ./heapScene/packers.
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Shared WGSL prelude (struct + bindings + VS)
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Common decls — struct + bindings + helpers. Always concatenated
|
|
69
|
+
// into every group's shader, before its custom VS+FS bodies.
|
|
70
|
+
//
|
|
71
|
+
// One arena GPUBuffer is bound through multiple typed views. Today
|
|
72
|
+
// only `array<DrawHeader>` and `array<f32>` are wired; later we add
|
|
73
|
+
// `array<u32>`, `array<vec2<f32>>`, `array<vec4<f32>>`, etc. (skip
|
|
74
|
+
// `vec3` — its storage stride is 16, doesn't match tight packing).
|
|
75
|
+
//
|
|
76
|
+
// `attrRef` style: each attribute reference in DrawHeader is a byte
|
|
77
|
+
// offset into the arena pointing at the allocation's header. The
|
|
78
|
+
// header is `(u32 typeId, u32 length)`; data follows 16 bytes after
|
|
79
|
+
// the ref. Today every attribute is V3F_TIGHT-encoded so the shader
|
|
80
|
+
// reads 3 consecutive f32s from the f32 view; once we add more
|
|
81
|
+
// encodings, `loadVec3Attr` grows a branch on `typeId & 0xFFFFu`.
|
|
82
|
+
// (Per-bucket WGSL preludes are now generated by `buildBucketLayout`
|
|
83
|
+
// in heapEffect.ts; this module just glues the bucket layout, the
|
|
84
|
+
// shared arena, and the per-bucket DrawHeap together.)
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
// Geometry packing
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
/**
|
|
89
|
+
* Geometry triple. Tightly-packed Float32 positions / normals (3
|
|
90
|
+
* floats per vertex) plus Uint32 indices.
|
|
91
|
+
*/
|
|
92
|
+
/** drawTable `firstIndex` sentinel marking a non-indexed record: the megacall
|
|
93
|
+
* prelude then uses the local vertex index directly (no indexStorage lookup).
|
|
94
|
+
* Must match the literal in heapEffect.ts's `megacallSearchPrelude`. */
|
|
95
|
+
export const HEAP_NONINDEXED = 0xffffffff;
|
|
63
96
|
export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
64
97
|
const atlasPool = opts.atlasPool;
|
|
65
98
|
const colorAttachmentName = sig.colorNames[0];
|
|
@@ -2133,10 +2166,18 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2133
2166
|
const effectFields = fam.fieldsForEffect.get(spec.effect.id);
|
|
2134
2167
|
// Indices live in their own INDEX-usage buffer (WebGPU constraint).
|
|
2135
2168
|
// Aval-keyed: 19K instanced clones of the same mesh share one
|
|
2136
|
-
// index allocation + one upload.
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2169
|
+
// index allocation + one upload. NON-INDEXED draws (spec.indices
|
|
2170
|
+
// omitted) skip the index pool entirely: the drawTable record stores
|
|
2171
|
+
// firstIndex = HEAP_NONINDEXED (sentinel) and indexCount = vertexCount,
|
|
2172
|
+
// and the megacall prelude uses the local vertex index directly.
|
|
2173
|
+
const hasIndices = spec.indices !== undefined;
|
|
2174
|
+
const indicesAval = hasIndices ? asAval(spec.indices) : undefined;
|
|
2175
|
+
const idxAlloc = hasIndices
|
|
2176
|
+
? indexPool.acquire(device, arena.indices, indicesAval, bucket.chunkIdx, readPlain(spec.indices))
|
|
2177
|
+
: undefined;
|
|
2178
|
+
// Emit count per instance + the firstIndex field written to the record.
|
|
2179
|
+
const emitCount = hasIndices ? idxAlloc.count : (spec.vertexCount ?? 0);
|
|
2180
|
+
const firstIndexField = hasIndices ? idxAlloc.firstIndex : HEAP_NONINDEXED;
|
|
2140
2181
|
const localSlot = bucket.drawHeap.alloc();
|
|
2141
2182
|
// Per-RO instancing: read `spec.instanceCount` (defaults to 1).
|
|
2142
2183
|
const instanceCount = spec.instanceCount !== undefined
|
|
@@ -2219,7 +2260,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2219
2260
|
bucket.localPosRefs[localSlot] = perDrawRefs.get("Positions");
|
|
2220
2261
|
bucket.localNorRefs[localSlot] = perDrawRefs.get("Normals");
|
|
2221
2262
|
bucket.localEntries[localSlot] = {
|
|
2222
|
-
indexCount:
|
|
2263
|
+
indexCount: emitCount, firstIndex: firstIndexField, instanceCount,
|
|
2223
2264
|
};
|
|
2224
2265
|
bucket.localToDrawId[localSlot] = drawId;
|
|
2225
2266
|
bucket.drawSlots.add(localSlot);
|
|
@@ -2327,7 +2368,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2327
2368
|
// it) get 0 — the kernel only reads refs through combo fns that
|
|
2328
2369
|
// gate on `r.comboId`, so an unread 0 is harmless.
|
|
2329
2370
|
const uniformRefs = (bucket.uniformOrder ?? []).map(name => perDrawRefs.get(name) ?? 0);
|
|
2330
|
-
partition.appendRecord(localSlot,
|
|
2371
|
+
partition.appendRecord(localSlot, firstIndexField, emitCount, instanceCount, roComboId, uniformRefs);
|
|
2331
2372
|
bucket.drawIdToRecord.set(drawId, recIdx);
|
|
2332
2373
|
bucket.recordToDrawId[recIdx] = drawId;
|
|
2333
2374
|
bucket.drawIdToComboId.set(drawId, roComboId);
|
|
@@ -2338,7 +2379,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2338
2379
|
const numRecords = recIdx + 1;
|
|
2339
2380
|
const recBytes = numRecords * RECORD_BYTES;
|
|
2340
2381
|
const needBlocks = Math.max(1, Math.ceil(numRecords / SCAN_TILE_SIZE));
|
|
2341
|
-
const emitDelta =
|
|
2382
|
+
const emitDelta = emitCount * instanceCount;
|
|
2342
2383
|
for (const s of bucket.slots) {
|
|
2343
2384
|
s.drawTableBuf.ensureCapacity(recBytes);
|
|
2344
2385
|
s.drawTableBuf.setUsed(Math.max(s.drawTableBuf.usedBytes, recBytes));
|
|
@@ -2370,8 +2411,8 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2370
2411
|
// firstEmit is GPU-overwritten by the prefix-sum pass; 0 is fine.
|
|
2371
2412
|
shadow[recIdx * RECORD_U32 + 0] = 0;
|
|
2372
2413
|
shadow[recIdx * RECORD_U32 + 1] = localSlot;
|
|
2373
|
-
shadow[recIdx * RECORD_U32 + 2] =
|
|
2374
|
-
shadow[recIdx * RECORD_U32 + 3] =
|
|
2414
|
+
shadow[recIdx * RECORD_U32 + 2] = firstIndexField;
|
|
2415
|
+
shadow[recIdx * RECORD_U32 + 3] = emitCount;
|
|
2375
2416
|
shadow[recIdx * RECORD_U32 + 4] = instanceCount;
|
|
2376
2417
|
roSlot.recordCount = recIdx + 1;
|
|
2377
2418
|
roSlot.slotToRecord[localSlot] = recIdx;
|
|
@@ -2380,7 +2421,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2380
2421
|
roSlot.drawTableDirtyMin = byteOff;
|
|
2381
2422
|
if (byteOff + RECORD_BYTES > roSlot.drawTableDirtyMax)
|
|
2382
2423
|
roSlot.drawTableDirtyMax = byteOff + RECORD_BYTES;
|
|
2383
|
-
roSlot.totalEmitEstimate +=
|
|
2424
|
+
roSlot.totalEmitEstimate += emitCount * instanceCount;
|
|
2384
2425
|
const newNumTiles = Math.max(1, Math.ceil(roSlot.totalEmitEstimate / TILE_K));
|
|
2385
2426
|
roSlot.firstDrawInTileBuf.ensureCapacity((newNumTiles + 1) * 4);
|
|
2386
2427
|
roSlot.scanDirty = true;
|
|
@@ -2395,7 +2436,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2395
2436
|
// `subscribeActive` → `activeDirty` and drained in `update()`.
|
|
2396
2437
|
if (spec.active !== undefined) {
|
|
2397
2438
|
drawIdToActiveAval.set(drawId, spec.active);
|
|
2398
|
-
drawIdToOrigIndexCount.set(drawId,
|
|
2439
|
+
drawIdToOrigIndexCount.set(drawId, emitCount);
|
|
2399
2440
|
const initial = spec.active.getValue(outerTok);
|
|
2400
2441
|
subscribeActive(spec.active, drawId);
|
|
2401
2442
|
if (initial === false) {
|
|
@@ -4224,7 +4265,9 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
4224
4265
|
let _instCount = drawTable[_slot * 5u + 4u];
|
|
4225
4266
|
let _local = emitIdx - _firstEmit;
|
|
4226
4267
|
let _instId = _local / _indexCount;
|
|
4227
|
-
let
|
|
4268
|
+
let _li = _local % _indexCount;
|
|
4269
|
+
var _vid: u32 = _li;
|
|
4270
|
+
if (_indexStart != 0xffffffffu) { _vid = indexStorage[_indexStart + _li]; }
|
|
4228
4271
|
let base = i * 8u;
|
|
4229
4272
|
outRows[base + 0u] = _slot;
|
|
4230
4273
|
outRows[base + 1u] = _drawIdx;
|