handles: indirect draw buckets for opaque and mask meshes

Opaque/mask draws sharing a pipeline and bind set become rows of one
persistent `draws.<id>` indirect array (32-byte indexed commands,
geometric capacity, inactive tail zeroed) drawn by a single graph pass,
so the graph holds one pass per bucket instead of one per mesh.
Transmission and blend draws stay direct and ordered after the buckets.
Scene requires the indirect-first-instance feature. Compiles re-assert
the bundle block when they start, since an earlier switch in the queue
clears the one set at enqueue time.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0b2dd-db32-712d-99ce-12ce4a86d979
Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-09-18 07:14:37 +00:00
co-authored by heaust
parent a4f3eeddd6
commit bc957cf40d
4 changed files with 300 additions and 81 deletions
+26
View File
@@ -53,3 +53,29 @@ export function detailedMesh(
) {
return new Mesh(scene, { material, vertexData });
}
/** Decodes the active indirect rows of every forward bucket pass, in pass order. */
export function bucketDraws(scene: Scene, graph: any) {
return forwardPasses(graph)
.filter((pass: any) => pass.indirect)
.flatMap((pass: any) => {
const buffer = graph.resources.buffers.find(
(buffer: any) => buffer.id === pass.indirect.resource,
);
const view = scene.core.array(buffer.array).view;
const draws = [];
for (let row = 0; row * 8 < view.length; row++) {
const [indices, instances, firstIndex, baseVertex, firstInstance] =
view.subarray(row * 8, row * 8 + 5);
if (instances)
draws.push({
pass: pass.id,
indices,
firstIndex,
baseVertex,
firstInstance,
});
}
return draws;
});
}