@aardworx/wombat.rendering 0.18.1 → 0.19.0
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 +16 -0
- package/dist/core/renderObject.d.ts.map +1 -1
- package/dist/runtime/heapAdapter.d.ts.map +1 -1
- package/dist/runtime/heapAdapter.js +17 -0
- package/dist/runtime/heapAdapter.js.map +1 -1
- package/dist/runtime/heapScene/freelist.d.ts +5 -0
- package/dist/runtime/heapScene/freelist.d.ts.map +1 -1
- package/dist/runtime/heapScene/freelist.js +28 -0
- package/dist/runtime/heapScene/freelist.js.map +1 -1
- package/dist/runtime/heapScene/pools.d.ts +19 -0
- package/dist/runtime/heapScene/pools.d.ts.map +1 -1
- package/dist/runtime/heapScene/pools.js +115 -12
- package/dist/runtime/heapScene/pools.js.map +1 -1
- package/dist/runtime/heapScene.d.ts +12 -0
- package/dist/runtime/heapScene.d.ts.map +1 -1
- package/dist/runtime/heapScene.js +223 -10
- package/dist/runtime/heapScene.js.map +1 -1
- package/dist/runtime/hybridScene.d.ts +8 -0
- package/dist/runtime/hybridScene.d.ts.map +1 -1
- package/dist/runtime/hybridScene.js +15 -0
- package/dist/runtime/hybridScene.js.map +1 -1
- package/dist/runtime/textureAtlas/atlasPool.d.ts +12 -0
- package/dist/runtime/textureAtlas/atlasPool.d.ts.map +1 -1
- package/dist/runtime/textureAtlas/atlasPool.js +20 -0
- package/dist/runtime/textureAtlas/atlasPool.js.map +1 -1
- package/package.json +1 -1
- package/src/core/renderObject.ts +16 -0
- package/src/runtime/heapAdapter.ts +17 -0
- package/src/runtime/heapScene/freelist.ts +35 -0
- package/src/runtime/heapScene/pools.ts +131 -12
- package/src/runtime/heapScene.ts +234 -10
- package/src/runtime/hybridScene.ts +23 -0
- package/src/runtime/textureAtlas/atlasPool.ts +19 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heapScene.d.ts","sourceRoot":"","sources":["../../src/runtime/heapScene.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"heapScene.d.ts","sourceRoot":"","sources":["../../src/runtime/heapScene.ts"],"names":[],"mappings":"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"}
|
|
@@ -119,6 +119,96 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
119
119
|
*/
|
|
120
120
|
const modeAvalToDrawIds = new Map();
|
|
121
121
|
const modeAvalCallbacks = new Map();
|
|
122
|
+
// ─── HeapDrawSpec.active subscription ────────────────────────────────
|
|
123
|
+
// Per-drawId state for the "skip without re-allocating" path. When a
|
|
124
|
+
// tile (or any RO) flips visibility many times per second (e.g. an
|
|
125
|
+
// LOD walker culling/uncrossing the frustum), pool churn would be
|
|
126
|
+
// prohibitive. Instead we keep the RO in the bucket and flip its
|
|
127
|
+
// drawTable record's `indexCount` field between the original count
|
|
128
|
+
// (visible) and 0 (hidden). The scan kernel's prefix sum naturally
|
|
129
|
+
// skips a record with 0 emit count, so this costs one drawTable
|
|
130
|
+
// write + a re-scan dispatch — no arena/freelist activity.
|
|
131
|
+
const drawIdToActiveAval = new Map();
|
|
132
|
+
const drawIdToOrigIndexCount = new Map();
|
|
133
|
+
const drawIdToActiveCallback = new Map();
|
|
134
|
+
const activeAvalToDrawIds = new Map();
|
|
135
|
+
const activeDirty = new Set();
|
|
136
|
+
function subscribeActive(av, drawId) {
|
|
137
|
+
let set = activeAvalToDrawIds.get(av);
|
|
138
|
+
if (set === undefined) {
|
|
139
|
+
set = new Set();
|
|
140
|
+
activeAvalToDrawIds.set(av, set);
|
|
141
|
+
}
|
|
142
|
+
set.add(drawId);
|
|
143
|
+
const cb = addMarkingCallback(av, () => { activeDirty.add(drawId); });
|
|
144
|
+
drawIdToActiveCallback.set(drawId, cb);
|
|
145
|
+
}
|
|
146
|
+
function unsubscribeActive(drawId) {
|
|
147
|
+
const av = drawIdToActiveAval.get(drawId);
|
|
148
|
+
if (av === undefined)
|
|
149
|
+
return;
|
|
150
|
+
const cb = drawIdToActiveCallback.get(drawId);
|
|
151
|
+
cb?.dispose();
|
|
152
|
+
drawIdToActiveCallback.delete(drawId);
|
|
153
|
+
const set = activeAvalToDrawIds.get(av);
|
|
154
|
+
if (set !== undefined) {
|
|
155
|
+
set.delete(drawId);
|
|
156
|
+
if (set.size === 0)
|
|
157
|
+
activeAvalToDrawIds.delete(av);
|
|
158
|
+
}
|
|
159
|
+
drawIdToActiveAval.delete(drawId);
|
|
160
|
+
drawIdToOrigIndexCount.delete(drawId);
|
|
161
|
+
activeDirty.delete(drawId);
|
|
162
|
+
}
|
|
163
|
+
/** Update the drawTable record's effective indexCount in place
|
|
164
|
+
* (GPU-routed: masterShadow + partition re-dispatch; legacy:
|
|
165
|
+
* drawTableShadow + scan re-dispatch). Common helper used by the
|
|
166
|
+
* active-aval drain in `update()`. */
|
|
167
|
+
function setEffectiveIndexCount(drawId, newIndexCount) {
|
|
168
|
+
const bucket = drawIdToBucket[drawId];
|
|
169
|
+
if (bucket === undefined)
|
|
170
|
+
return;
|
|
171
|
+
if (bucket.gpuRouted) {
|
|
172
|
+
const partition = bucket.partitionScene;
|
|
173
|
+
const recIdx = bucket.drawIdToRecord.get(drawId);
|
|
174
|
+
if (recIdx === undefined)
|
|
175
|
+
return;
|
|
176
|
+
const ru32 = partition.recordU32;
|
|
177
|
+
const oldIndexCount = partition.masterShadow[recIdx * ru32 + 3];
|
|
178
|
+
const instanceCount = partition.masterShadow[recIdx * ru32 + 4];
|
|
179
|
+
partition.masterShadow[recIdx * ru32 + 3] = newIndexCount >>> 0;
|
|
180
|
+
const delta = (newIndexCount - oldIndexCount) * instanceCount;
|
|
181
|
+
bucket.partitionDirty = true;
|
|
182
|
+
for (const s of bucket.slots) {
|
|
183
|
+
s.totalEmitEstimate = Math.max(0, s.totalEmitEstimate + delta);
|
|
184
|
+
s.scanDirty = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const slotIdx = drawIdToSlotIdx[drawId];
|
|
189
|
+
const slot = slotIdx !== undefined ? bucket.slots[slotIdx] : bucket.slots[0];
|
|
190
|
+
if (slot === undefined)
|
|
191
|
+
return;
|
|
192
|
+
const localSlot = drawIdToLocalSlot[drawId];
|
|
193
|
+
if (localSlot === undefined)
|
|
194
|
+
return;
|
|
195
|
+
const recIdx = slot.slotToRecord[localSlot];
|
|
196
|
+
if (recIdx === undefined || recIdx < 0)
|
|
197
|
+
return;
|
|
198
|
+
const shadow = slot.drawTableShadow;
|
|
199
|
+
const oldIndexCount = shadow[recIdx * RECORD_U32 + 3];
|
|
200
|
+
const instanceCount = shadow[recIdx * RECORD_U32 + 4];
|
|
201
|
+
shadow[recIdx * RECORD_U32 + 3] = newIndexCount >>> 0;
|
|
202
|
+
const byteOff = recIdx * RECORD_BYTES + 3 * 4;
|
|
203
|
+
if (byteOff < slot.drawTableDirtyMin)
|
|
204
|
+
slot.drawTableDirtyMin = byteOff;
|
|
205
|
+
if (byteOff + 4 > slot.drawTableDirtyMax)
|
|
206
|
+
slot.drawTableDirtyMax = byteOff + 4;
|
|
207
|
+
const delta = (newIndexCount - oldIndexCount) * instanceCount;
|
|
208
|
+
slot.totalEmitEstimate = Math.max(0, slot.totalEmitEstimate + delta);
|
|
209
|
+
slot.scanDirty = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
122
212
|
function subscribeModeLeaf(av, drawId) {
|
|
123
213
|
let set = modeAvalToDrawIds.get(av);
|
|
124
214
|
if (set === undefined) {
|
|
@@ -1924,6 +2014,11 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
1924
2014
|
// inside a single outer evaluateAlways and invoke addDrawImpl
|
|
1925
2015
|
// directly with their token — collapsing 1000× nested
|
|
1926
2016
|
// evaluateAlways into 1× outer.
|
|
2017
|
+
// DEBUG counters.
|
|
2018
|
+
let __addDrawCalls = 0;
|
|
2019
|
+
let __removeDrawCalls = 0;
|
|
2020
|
+
sceneObj.__addDrawCalls = () => __addDrawCalls;
|
|
2021
|
+
sceneObj.__removeDrawCalls = () => __removeDrawCalls;
|
|
1927
2022
|
function addDraw(spec) {
|
|
1928
2023
|
let id = -1;
|
|
1929
2024
|
sceneObj.evaluateAlways(AdaptiveToken.top, (tok) => {
|
|
@@ -1932,6 +2027,7 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
1932
2027
|
return id;
|
|
1933
2028
|
}
|
|
1934
2029
|
function addDrawImpl(spec, outerTok) {
|
|
2030
|
+
__addDrawCalls++;
|
|
1935
2031
|
const drawId = nextDrawId++;
|
|
1936
2032
|
// Family-merge (slice 3c): build the family lazily from this
|
|
1937
2033
|
// single spec when no batched lazy-build occurred earlier (e.g.
|
|
@@ -2122,6 +2218,47 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2122
2218
|
packBucketHeader(bucket, localSlot, perDrawRefs, layoutId);
|
|
2123
2219
|
if (bucket.isAtlasBucket && spec.textures !== undefined && spec.textures.kind === "atlas") {
|
|
2124
2220
|
packAtlasTextureFields(bucket, localSlot, spec.textures);
|
|
2221
|
+
// Pair this addDraw with one atlas refcount bump. The spec's
|
|
2222
|
+
// release closure (stored below, fired in removeDraw) decrements
|
|
2223
|
+
// exactly once per add/remove cycle; without this incRef the
|
|
2224
|
+
// refcount underflows when the same cached spec is re-introduced
|
|
2225
|
+
// across multiple aset add/remove cycles (e.g., a tile flipping
|
|
2226
|
+
// in and out of the heap-eligible subset).
|
|
2227
|
+
//
|
|
2228
|
+
// Falls back to a full re-acquire if the entry was already
|
|
2229
|
+
// evicted (incRef returns false): in that case the spec's stored
|
|
2230
|
+
// (pageId, origin, size) are stale and the new acquire's values
|
|
2231
|
+
// overwrite them before packAtlasTextureFields is re-called.
|
|
2232
|
+
if (atlasPool !== undefined) {
|
|
2233
|
+
const ok = atlasPool.incRef(spec.textures.poolRef);
|
|
2234
|
+
if (!ok) {
|
|
2235
|
+
// Entry was evicted while the cached spec was idle in heap-
|
|
2236
|
+
// remove state. Acquire a fresh sub-rect, redirect the spec
|
|
2237
|
+
// (and the per-aval cell behind its release closure) to the
|
|
2238
|
+
// new ref, and re-emit the drawHeader fields.
|
|
2239
|
+
const acq = atlasPool.acquire(spec.textures.page.format, spec.textures.sourceAval, spec.textures.size.x, spec.textures.size.y, { wantsMips: spec.textures.numMips > 1 });
|
|
2240
|
+
spec.textures.pageId = acq.pageId;
|
|
2241
|
+
spec.textures.origin = acq.origin;
|
|
2242
|
+
spec.textures.size = acq.size;
|
|
2243
|
+
spec.textures.numMips = acq.numMips;
|
|
2244
|
+
spec.textures.page = acq.page;
|
|
2245
|
+
spec.textures.poolRef = acq.ref;
|
|
2246
|
+
// The release closure captures a per-aval cell whose `ref`
|
|
2247
|
+
// must track the LATEST acquired sub-rect; otherwise the
|
|
2248
|
+
// closure releases a long-evicted ref (no-op leak).
|
|
2249
|
+
if (spec.textures.repack !== undefined) {
|
|
2250
|
+
// repack updates the per-aval cell to the new ref as a
|
|
2251
|
+
// side effect of its own atlas-mark drain path. Re-using
|
|
2252
|
+
// it here would free the entry we just acquired; instead
|
|
2253
|
+
// mirror the same effect with a tiny helper attached to
|
|
2254
|
+
// the spec at adapter time (`__retarget`).
|
|
2255
|
+
}
|
|
2256
|
+
const retarget = spec.textures.__retarget;
|
|
2257
|
+
if (retarget !== undefined)
|
|
2258
|
+
retarget(acq.ref);
|
|
2259
|
+
packAtlasTextureFields(bucket, localSlot, spec.textures);
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2125
2262
|
bucket.localAtlasReleases[localSlot] = spec.textures.release;
|
|
2126
2263
|
bucket.localAtlasTextures[localSlot] = spec.textures;
|
|
2127
2264
|
// Reactivity wire-up: subscribe to `sourceAval` (so sceneObj.inputChanged
|
|
@@ -2226,6 +2363,22 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2226
2363
|
drawIdToLocalSlot[drawId] = localSlot;
|
|
2227
2364
|
drawIdToSlotIdx[drawId] = roSlotIdx;
|
|
2228
2365
|
drawIdToIndexAval[drawId] = indicesAval;
|
|
2366
|
+
// ─── HeapDrawSpec.active wire-up ──────────────────────────────────
|
|
2367
|
+
// Track the visibility aval (if any) and apply its initial value
|
|
2368
|
+
// immediately. After this point, ticks on the aval are routed via
|
|
2369
|
+
// `subscribeActive` → `activeDirty` and drained in `update()`.
|
|
2370
|
+
if (spec.active !== undefined) {
|
|
2371
|
+
drawIdToActiveAval.set(drawId, spec.active);
|
|
2372
|
+
drawIdToOrigIndexCount.set(drawId, idxAlloc.count);
|
|
2373
|
+
const initial = spec.active.getValue(outerTok);
|
|
2374
|
+
subscribeActive(spec.active, drawId);
|
|
2375
|
+
if (initial === false) {
|
|
2376
|
+
// Apply the off state synchronously so the very first frame
|
|
2377
|
+
// already skips this RO (no flash of un-gated geometry while
|
|
2378
|
+
// we wait for the next update tick).
|
|
2379
|
+
setEffectiveIndexCount(drawId, 0);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2229
2382
|
// ─── Reactive rebucket: track PS-modeKey changes ────────────────
|
|
2230
2383
|
// When any mode-axis aval marks (e.g. cullCval.value = 'front'),
|
|
2231
2384
|
// schedule this RO for rebucket on the next update(). Today's
|
|
@@ -2329,10 +2482,14 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2329
2482
|
return drawId;
|
|
2330
2483
|
}
|
|
2331
2484
|
function removeDraw(drawId) {
|
|
2485
|
+
__removeDrawCalls++;
|
|
2332
2486
|
const bucket = drawIdToBucket[drawId];
|
|
2333
2487
|
const localSlot = drawIdToLocalSlot[drawId];
|
|
2334
2488
|
if (bucket === undefined || localSlot === undefined)
|
|
2335
2489
|
return;
|
|
2490
|
+
// Tear down `active` subscription (if any) so its callback won't
|
|
2491
|
+
// fire after the underlying drawTable record is gone.
|
|
2492
|
+
unsubscribeActive(drawId);
|
|
2336
2493
|
// §7: deregister this RO's derivation records and release slots.
|
|
2337
2494
|
if (derivedScene !== undefined) {
|
|
2338
2495
|
const reg = derivedByDrawId.get(drawId);
|
|
@@ -2345,9 +2502,15 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2345
2502
|
const partition = bucket.partitionScene;
|
|
2346
2503
|
const recIdx = bucket.drawIdToRecord.get(drawId);
|
|
2347
2504
|
const removedEntry = bucket.localEntries[localSlot];
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2505
|
+
// Read the EFFECTIVE indexCount from masterShadow (already 0 for
|
|
2506
|
+
// an inactive draw via setEffectiveIndexCount). Using the original
|
|
2507
|
+
// count from localEntries would double-subtract for inactive draws
|
|
2508
|
+
// (whose contribution was already removed when active flipped false).
|
|
2509
|
+
const effectiveIndexCount = recIdx !== undefined
|
|
2510
|
+
? partition.masterShadow[recIdx * partition.recordU32 + 3]
|
|
2511
|
+
: (removedEntry?.indexCount ?? 0);
|
|
2512
|
+
const instanceCount = removedEntry?.instanceCount ?? 0;
|
|
2513
|
+
const removedCount = effectiveIndexCount * instanceCount;
|
|
2351
2514
|
if (recIdx !== undefined) {
|
|
2352
2515
|
const moved = partition.removeRecord(recIdx);
|
|
2353
2516
|
if (moved >= 0) {
|
|
@@ -2376,9 +2539,15 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2376
2539
|
const slotIdx = drawIdToSlotIdx[drawId];
|
|
2377
2540
|
const slot = slotIdx !== undefined ? bucket.slots[slotIdx] : bucket.slots[0];
|
|
2378
2541
|
const removedEntry = bucket.localEntries[localSlot];
|
|
2379
|
-
const
|
|
2380
|
-
|
|
2381
|
-
|
|
2542
|
+
const localSlotRec = slot.slotToRecord[localSlot];
|
|
2543
|
+
// Effective (post-active) indexCount, read from shadow so that
|
|
2544
|
+
// inactive draws contribute 0 here (their contribution was
|
|
2545
|
+
// already removed when active flipped false).
|
|
2546
|
+
const effectiveIndexCount = localSlotRec !== undefined && localSlotRec >= 0
|
|
2547
|
+
? slot.drawTableShadow[localSlotRec * RECORD_U32 + 3]
|
|
2548
|
+
: (removedEntry?.indexCount ?? 0);
|
|
2549
|
+
const instanceCount = removedEntry?.instanceCount ?? 0;
|
|
2550
|
+
const removedCount = effectiveIndexCount * instanceCount;
|
|
2382
2551
|
slot.totalEmitEstimate = Math.max(0, slot.totalEmitEstimate - removedCount);
|
|
2383
2552
|
// Swap-pop: move the last record into the freed slot, decrement
|
|
2384
2553
|
// recordCount. firstEmit is GPU-rewritten by the next scan, so
|
|
@@ -2680,6 +2849,22 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
2680
2849
|
}
|
|
2681
2850
|
allocDirty.clear();
|
|
2682
2851
|
}
|
|
2852
|
+
// 1c. HeapDrawSpec.active drain — flip drawTable.indexCount
|
|
2853
|
+
// between origIndexCount (visible) and 0 (hidden) for any RO
|
|
2854
|
+
// whose active aval ticked since last frame. Set is small in
|
|
2855
|
+
// steady state (only the ROs whose visibility actually
|
|
2856
|
+
// changed). No pool / arena / freelist activity.
|
|
2857
|
+
if (activeDirty.size > 0) {
|
|
2858
|
+
for (const did of activeDirty) {
|
|
2859
|
+
const av = drawIdToActiveAval.get(did);
|
|
2860
|
+
if (av === undefined)
|
|
2861
|
+
continue;
|
|
2862
|
+
const a = av.getValue(tok);
|
|
2863
|
+
const orig = drawIdToOrigIndexCount.get(did) ?? 0;
|
|
2864
|
+
setEffectiveIndexCount(did, a ? orig : 0);
|
|
2865
|
+
}
|
|
2866
|
+
activeDirty.clear();
|
|
2867
|
+
}
|
|
2683
2868
|
// 1b. Atlas-texture aval reactivity: an `aval<ITexture>` that
|
|
2684
2869
|
// drives an atlas placement was marked. Repack the pool entry
|
|
2685
2870
|
// and rewrite the drawHeader fields of every (bucket, slot)
|
|
@@ -3101,7 +3286,26 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
3101
3286
|
const typeId = arenaU32[refU32];
|
|
3102
3287
|
const length = arenaU32[refU32 + 1];
|
|
3103
3288
|
if (!KNOWN_TYPE_IDS.has(typeId)) {
|
|
3104
|
-
|
|
3289
|
+
// Dump the first 8 u32s of the alloc to help diagnose
|
|
3290
|
+
// what wrote garbage onto the header. Also peek the
|
|
3291
|
+
// FOUR u32s BEFORE the alloc to see if a neighbour
|
|
3292
|
+
// overran into us.
|
|
3293
|
+
const before = refU32 >= 4
|
|
3294
|
+
? `prev=[${arenaU32[refU32 - 4]},${arenaU32[refU32 - 3]},${arenaU32[refU32 - 2]},${arenaU32[refU32 - 1]}] `
|
|
3295
|
+
: "";
|
|
3296
|
+
const here = `here=[${arenaU32[refU32]},${arenaU32[refU32 + 1]},${arenaU32[refU32 + 2]},${arenaU32[refU32 + 3]},${arenaU32[refU32 + 4]},${arenaU32[refU32 + 5]},${arenaU32[refU32 + 6]},${arenaU32[refU32 + 7]}]`;
|
|
3297
|
+
// Compare CPU shadow vs GPU read-back. Differ → GPU
|
|
3298
|
+
// write corrupted; match → bug is in CPU-side write path
|
|
3299
|
+
// OR the alloc never went through pool.acquire.
|
|
3300
|
+
const shadowChunk = arena.attrs.chunk(0);
|
|
3301
|
+
const shadowU32 = shadowChunk.peekShadowU32(ref, 8);
|
|
3302
|
+
const shadowStr = `shadow=[${shadowU32[0]},${shadowU32[1]},${shadowU32[2]},${shadowU32[3]},${shadowU32[4]},${shadowU32[5]},${shadowU32[6]},${shadowU32[7]}]`;
|
|
3303
|
+
const cpuMatches = shadowU32[0] === arenaU32[refU32]
|
|
3304
|
+
&& shadowU32[1] === arenaU32[refU32 + 1]
|
|
3305
|
+
&& shadowU32[2] === arenaU32[refU32 + 2]
|
|
3306
|
+
&& shadowU32[3] === arenaU32[refU32 + 3];
|
|
3307
|
+
const verdict = cpuMatches ? "GPU=CPU (likely CPU-write bug)" : "GPU≠CPU (likely GPU-write corruption)";
|
|
3308
|
+
push(`bucket#${bucketIdx} slot=${slot} field='${f.name}' alloc@0x${ref.toString(16)} typeId=${typeId} unknown ${verdict} ${before}${here} ${shadowStr}`);
|
|
3105
3309
|
attrAllocsBad++;
|
|
3106
3310
|
continue;
|
|
3107
3311
|
}
|
|
@@ -3205,11 +3409,18 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
3205
3409
|
tilesBad++;
|
|
3206
3410
|
}
|
|
3207
3411
|
}
|
|
3412
|
+
// The scan kernel intentionally writes `numRecords - 1` as the
|
|
3413
|
+
// sentinel (not `numRecords`) — the render VS's binary search
|
|
3414
|
+
// uses `hi = firstDrawInTile[_tileIdx + 1u]` as an *inclusive*
|
|
3415
|
+
// upper bound, so the sentinel must point at the last valid
|
|
3416
|
+
// record slot. See scanKernel.ts `buildTileIndex` for the
|
|
3417
|
+
// full rationale.
|
|
3418
|
+
const expectedSentinel = recordCount === 0 ? 0 : recordCount - 1;
|
|
3208
3419
|
const sentinel = fdt[dc.numTiles];
|
|
3209
3420
|
tilesChecked++;
|
|
3210
|
-
if (sentinel !==
|
|
3421
|
+
if (sentinel !== expectedSentinel) {
|
|
3211
3422
|
push(`bucket#${bucketIdx} firstDrawInTile[${dc.numTiles}] sentinel ` +
|
|
3212
|
-
`got=${sentinel} expected=${
|
|
3423
|
+
`got=${sentinel} expected=${expectedSentinel}`);
|
|
3213
3424
|
tilesBad++;
|
|
3214
3425
|
}
|
|
3215
3426
|
dc.firstDrawInTile.unmap();
|
|
@@ -4098,6 +4309,8 @@ export function buildHeapScene(device, sig, initialDraws, opts = {}) {
|
|
|
4098
4309
|
return { emitsChecked: sampleCount, gpuMismatches, issues };
|
|
4099
4310
|
},
|
|
4100
4311
|
};
|
|
4101
|
-
|
|
4312
|
+
const __addDrawCallsGetter = () => __addDrawCalls;
|
|
4313
|
+
const __removeDrawCallsGetter = () => __removeDrawCalls;
|
|
4314
|
+
return { frame, update, encodeIntoPass, encodeComputePrep, addDraw, removeDraw, stats, dispose, _debug, __addDrawCalls: __addDrawCallsGetter, __removeDrawCalls: __removeDrawCallsGetter };
|
|
4102
4315
|
}
|
|
4103
4316
|
//# sourceMappingURL=heapScene.js.map
|