@aardworx/wombat.rendering 0.9.33 → 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/derivedModes/kernelCodegen.d.ts +90 -0
- package/dist/runtime/derivedModes/kernelCodegen.d.ts.map +1 -0
- package/dist/runtime/derivedModes/kernelCodegen.js +623 -0
- package/dist/runtime/derivedModes/kernelCodegen.js.map +1 -0
- package/dist/runtime/derivedModes/modeKeyCpu.d.ts.map +1 -1
- package/dist/runtime/derivedModes/modeKeyCpu.js +23 -67
- package/dist/runtime/derivedModes/modeKeyCpu.js.map +1 -1
- package/dist/runtime/derivedModes/partitionDispatcher.d.ts +79 -0
- package/dist/runtime/derivedModes/partitionDispatcher.d.ts.map +1 -0
- package/dist/runtime/derivedModes/partitionDispatcher.js +303 -0
- package/dist/runtime/derivedModes/partitionDispatcher.js.map +1 -0
- package/dist/runtime/derivedModes/partitionKernel.d.ts +12 -0
- package/dist/runtime/derivedModes/partitionKernel.d.ts.map +1 -0
- package/dist/runtime/derivedModes/partitionKernel.js +127 -0
- package/dist/runtime/derivedModes/partitionKernel.js.map +1 -0
- package/dist/runtime/derivedModes/partitionKernelLayout.d.ts +4 -0
- package/dist/runtime/derivedModes/partitionKernelLayout.d.ts.map +1 -0
- package/dist/runtime/derivedModes/partitionKernelLayout.js +24 -0
- package/dist/runtime/derivedModes/partitionKernelLayout.js.map +1 -0
- package/dist/runtime/derivedModes/rule.d.ts +38 -86
- package/dist/runtime/derivedModes/rule.d.ts.map +1 -1
- package/dist/runtime/derivedModes/rule.js +34 -74
- package/dist/runtime/derivedModes/rule.js.map +1 -1
- package/dist/runtime/derivedUniforms/dispatch.d.ts +10 -8
- package/dist/runtime/derivedUniforms/dispatch.d.ts.map +1 -1
- package/dist/runtime/derivedUniforms/dispatch.js +31 -18
- package/dist/runtime/derivedUniforms/dispatch.js.map +1 -1
- package/dist/runtime/derivedUniforms/marker.d.ts +90 -11
- package/dist/runtime/derivedUniforms/marker.d.ts.map +1 -1
- package/dist/runtime/derivedUniforms/marker.js +161 -15
- package/dist/runtime/derivedUniforms/marker.js.map +1 -1
- package/dist/runtime/derivedUniforms/sceneIntegration.d.ts +25 -6
- package/dist/runtime/derivedUniforms/sceneIntegration.d.ts.map +1 -1
- package/dist/runtime/derivedUniforms/sceneIntegration.js +61 -20
- package/dist/runtime/derivedUniforms/sceneIntegration.js.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/heapEligibility.d.ts.map +1 -1
- package/dist/runtime/heapEligibility.js +22 -2
- package/dist/runtime/heapEligibility.js.map +1 -1
- package/dist/runtime/heapScene/chunkedArena.d.ts +76 -0
- package/dist/runtime/heapScene/chunkedArena.d.ts.map +1 -0
- package/dist/runtime/heapScene/chunkedArena.js +223 -0
- package/dist/runtime/heapScene/chunkedArena.js.map +1 -0
- package/dist/runtime/heapScene/freelist.d.ts +55 -0
- package/dist/runtime/heapScene/freelist.d.ts.map +1 -0
- package/dist/runtime/heapScene/freelist.js +188 -0
- package/dist/runtime/heapScene/freelist.js.map +1 -0
- package/dist/runtime/heapScene/growBuffer.d.ts +23 -2
- package/dist/runtime/heapScene/growBuffer.d.ts.map +1 -1
- package/dist/runtime/heapScene/growBuffer.js +35 -3
- package/dist/runtime/heapScene/growBuffer.js.map +1 -1
- package/dist/runtime/heapScene/pools.d.ts +84 -42
- package/dist/runtime/heapScene/pools.d.ts.map +1 -1
- package/dist/runtime/heapScene/pools.js +309 -134
- package/dist/runtime/heapScene/pools.js.map +1 -1
- package/dist/runtime/heapScene.d.ts +24 -0
- package/dist/runtime/heapScene.d.ts.map +1 -1
- package/dist/runtime/heapScene.js +1158 -92
- package/dist/runtime/heapScene.js.map +1 -1
- package/dist/runtime/hybridScene.d.ts +15 -0
- package/dist/runtime/hybridScene.d.ts.map +1 -1
- package/dist/runtime/hybridScene.js +16 -0
- package/dist/runtime/hybridScene.js.map +1 -1
- package/dist/runtime/index.d.ts +4 -3
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/renderTask.d.ts +5 -0
- package/dist/runtime/renderTask.d.ts.map +1 -1
- package/dist/runtime/renderTask.js +1 -0
- package/dist/runtime/renderTask.js.map +1 -1
- package/dist/runtime/runtime.d.ts +6 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +1 -0
- package/dist/runtime/runtime.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/derivedModes/kernelCodegen.ts +673 -0
- package/src/runtime/derivedModes/modeKeyCpu.ts +22 -60
- package/src/runtime/derivedModes/partitionDispatcher.ts +349 -0
- package/src/runtime/derivedModes/partitionKernelLayout.ts +25 -0
- package/src/runtime/derivedModes/rule.ts +66 -145
- package/src/runtime/derivedUniforms/dispatch.ts +48 -21
- package/src/runtime/derivedUniforms/marker.ts +210 -16
- package/src/runtime/derivedUniforms/sceneIntegration.ts +67 -20
- package/src/runtime/heapAdapter.ts +17 -0
- package/src/runtime/heapEligibility.ts +22 -1
- package/src/runtime/heapScene/chunkedArena.ts +238 -0
- package/src/runtime/heapScene/freelist.ts +196 -0
- package/src/runtime/heapScene/growBuffer.ts +39 -2
- package/src/runtime/heapScene/pools.ts +350 -143
- package/src/runtime/heapScene.ts +1350 -88
- package/src/runtime/hybridScene.ts +31 -0
- package/src/runtime/index.ts +12 -9
- package/src/runtime/renderTask.ts +6 -0
- package/src/runtime/runtime.ts +7 -0
- package/src/runtime/textureAtlas/atlasPool.ts +19 -0
- package/src/runtime/derivedModes/gpuDispatcher.ts +0 -226
- package/src/runtime/derivedModes/gpuKernel.ts +0 -98
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Phase 5c.3 partition kernel — GPU-driven record routing.
|
|
2
|
+
//
|
|
3
|
+
// Each frame the kernel runs over a bucket's master record pool. For
|
|
4
|
+
// each record, it evaluates the rule (currently hard-coded: flip
|
|
5
|
+
// cullMode by sign of det(upperLeft3x3) of the record's ModelTrafo),
|
|
6
|
+
// picks the destination slot index (0 = declared, 1 = flipped),
|
|
7
|
+
// atomically reserves a write offset in that slot, and copies the
|
|
8
|
+
// record into `slotDrawTable[slotIdx][offset]`.
|
|
9
|
+
//
|
|
10
|
+
// Buffer layout (one bucket):
|
|
11
|
+
//
|
|
12
|
+
// masterRecords: array<Record> // CPU populates at addRO
|
|
13
|
+
// numRecords: u32 (uniform)
|
|
14
|
+
// slot0Indirect: array<u32, 4> // (indexCount, instanceCount=1, 0, 0)
|
|
15
|
+
// slot1Indirect: array<u32, 4> // ditto
|
|
16
|
+
// slot0DrawTable: array<Record> // partition output
|
|
17
|
+
// slot1DrawTable: array<Record> // partition output
|
|
18
|
+
// slot0ScanParams: { numRecords: u32 ... }
|
|
19
|
+
// slot1ScanParams: { numRecords: u32 ... }
|
|
20
|
+
//
|
|
21
|
+
// The existing scan (HEAP_SCAN_WGSL in heapScene/scanKernel.ts) runs
|
|
22
|
+
// per slot AFTER partition: it reads the slot's drawTable, computes
|
|
23
|
+
// firstEmit prefix sums, and writes the final indirect[0] = totalEmit.
|
|
24
|
+
//
|
|
25
|
+
// What this kernel does NOT do:
|
|
26
|
+
// - Generalize beyond the determinant-flip-cull rule (v1 only).
|
|
27
|
+
// - Handle >2 slots per bucket. (For multi-output rules, future
|
|
28
|
+
// work: dynamic slot count, modeKey-table lookup.)
|
|
29
|
+
// - Manage record removal — that's CPU at removeDraw time (swap-pop
|
|
30
|
+
// the master pool).
|
|
31
|
+
import { CULL_TO_U32 } from "./gpuKernel.js";
|
|
32
|
+
/** Record layout: 6 × u32 = 24 bytes per record. Matches the heap
|
|
33
|
+
* scan's record format (5 × u32) plus a `modelRef` byte offset. */
|
|
34
|
+
export const PARTITION_RECORD_U32 = 6;
|
|
35
|
+
export const PARTITION_RECORD_BYTES = PARTITION_RECORD_U32 * 4;
|
|
36
|
+
/** Per-bucket partition kernel WGSL. Two output slots: declared
|
|
37
|
+
* + flipped. */
|
|
38
|
+
export const PARTITION_FLIP_CULL_BY_DET_WGSL = /* wgsl */ `
|
|
39
|
+
struct Record {
|
|
40
|
+
// firstEmit is GPU-written by the scan; leave as 0 here.
|
|
41
|
+
firstEmit: u32,
|
|
42
|
+
drawIdx: u32,
|
|
43
|
+
indexStart: u32,
|
|
44
|
+
indexCount: u32,
|
|
45
|
+
instanceCount: u32,
|
|
46
|
+
modelRef: u32,
|
|
47
|
+
};
|
|
48
|
+
struct PartitionParams {
|
|
49
|
+
numRecords: u32,
|
|
50
|
+
declaredCull: u32, // 0=none, 1=front, 2=back
|
|
51
|
+
_pad0: u32,
|
|
52
|
+
_pad1: u32,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
@group(0) @binding(0) var<storage, read> arena: array<u32>;
|
|
56
|
+
@group(0) @binding(1) var<storage, read> masterRecords: array<Record>;
|
|
57
|
+
@group(0) @binding(2) var<uniform> params: PartitionParams;
|
|
58
|
+
// Slot 0 = declared cull mode. Slot 1 = flipped cull mode.
|
|
59
|
+
@group(0) @binding(3) var<storage, read_write> slot0Count: array<atomic<u32>>; // length 1
|
|
60
|
+
@group(0) @binding(4) var<storage, read_write> slot1Count: array<atomic<u32>>;
|
|
61
|
+
// Slot draw tables hold scan-format records (5 × u32 per record:
|
|
62
|
+
// firstEmit, drawIdx, indexStart, indexCount, instanceCount). We
|
|
63
|
+
// drop modelRef on scatter — only the partition kernel needs it,
|
|
64
|
+
// and including it would force the scan to read a 6-u32 stride.
|
|
65
|
+
@group(0) @binding(5) var<storage, read_write> slot0DrawTable: array<u32>;
|
|
66
|
+
@group(0) @binding(6) var<storage, read_write> slot1DrawTable: array<u32>;
|
|
67
|
+
|
|
68
|
+
const SCAN_REC_U32: u32 = 5u;
|
|
69
|
+
|
|
70
|
+
fn loadUpper3x3(refBytes: u32) -> array<f32, 9> {
|
|
71
|
+
let baseU32 = (refBytes + 16u) >> 2u;
|
|
72
|
+
return array<f32, 9>(
|
|
73
|
+
bitcast<f32>(arena[baseU32 + 0u]), bitcast<f32>(arena[baseU32 + 1u]), bitcast<f32>(arena[baseU32 + 2u]),
|
|
74
|
+
bitcast<f32>(arena[baseU32 + 4u]), bitcast<f32>(arena[baseU32 + 5u]), bitcast<f32>(arena[baseU32 + 6u]),
|
|
75
|
+
bitcast<f32>(arena[baseU32 + 8u]), bitcast<f32>(arena[baseU32 + 9u]), bitcast<f32>(arena[baseU32 + 10u]),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fn det3x3(m: array<f32, 9>) -> f32 {
|
|
80
|
+
return m[0] * (m[4] * m[8] - m[5] * m[7])
|
|
81
|
+
- m[1] * (m[3] * m[8] - m[5] * m[6])
|
|
82
|
+
+ m[2] * (m[3] * m[7] - m[4] * m[6]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@compute @workgroup_size(64)
|
|
86
|
+
fn clear(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
87
|
+
// One thread total clears both atomics. Cheap pass.
|
|
88
|
+
if (gid.x != 0u) { return; }
|
|
89
|
+
atomicStore(&slot0Count[0], 0u);
|
|
90
|
+
atomicStore(&slot1Count[0], 0u);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@compute @workgroup_size(64)
|
|
94
|
+
fn partition(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
95
|
+
let i = gid.x;
|
|
96
|
+
if (i >= params.numRecords) { return; }
|
|
97
|
+
let r = masterRecords[i];
|
|
98
|
+
let m = loadUpper3x3(r.modelRef);
|
|
99
|
+
let flipped = det3x3(m) < 0.0;
|
|
100
|
+
// slotIdx 0 = declared (not flipped), 1 = flipped.
|
|
101
|
+
// Atomic-add into the appropriate slot's count, then scatter the
|
|
102
|
+
// record into the slot's drawTable at the reserved offset.
|
|
103
|
+
if (flipped) {
|
|
104
|
+
let off = atomicAdd(&slot1Count[0], 1u);
|
|
105
|
+
let base = off * SCAN_REC_U32;
|
|
106
|
+
slot1DrawTable[base + 0u] = 0u; // firstEmit (scan rewrites)
|
|
107
|
+
slot1DrawTable[base + 1u] = r.drawIdx;
|
|
108
|
+
slot1DrawTable[base + 2u] = r.indexStart;
|
|
109
|
+
slot1DrawTable[base + 3u] = r.indexCount;
|
|
110
|
+
slot1DrawTable[base + 4u] = r.instanceCount;
|
|
111
|
+
} else {
|
|
112
|
+
let off = atomicAdd(&slot0Count[0], 1u);
|
|
113
|
+
let base = off * SCAN_REC_U32;
|
|
114
|
+
slot0DrawTable[base + 0u] = 0u;
|
|
115
|
+
slot0DrawTable[base + 1u] = r.drawIdx;
|
|
116
|
+
slot0DrawTable[base + 2u] = r.indexStart;
|
|
117
|
+
slot0DrawTable[base + 3u] = r.indexCount;
|
|
118
|
+
slot0DrawTable[base + 4u] = r.instanceCount;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
/** WGSL helper: pack a Trafo3d's upper-left 3×3 + a CullMode enum
|
|
123
|
+
* into the partition kernel's expected uniform layout. */
|
|
124
|
+
export function cullModeToU32(c) {
|
|
125
|
+
return CULL_TO_U32[c];
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=partitionKernel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partitionKernel.js","sourceRoot":"","sources":["../../../src/runtime/derivedModes/partitionKernel.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,EAAE;AACF,qEAAqE;AACrE,iEAAiE;AACjE,qEAAqE;AACrE,gEAAgE;AAChE,kEAAkE;AAClE,gDAAgD;AAChD,EAAE;AACF,8BAA8B;AAC9B,EAAE;AACF,sEAAsE;AACtE,iCAAiC;AACjC,mFAAmF;AACnF,qDAAqD;AACrD,gEAAgE;AAChE,gEAAgE;AAChE,6CAA6C;AAC7C,6CAA6C;AAC7C,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,uEAAuE;AACvE,EAAE;AACF,gCAAgC;AAChC,kEAAkE;AAClE,kEAAkE;AAClE,uDAAuD;AACvD,sEAAsE;AACtE,wBAAwB;AAGxB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C;oEACoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAK,CAAC,CAAC;AACxC,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,GAAG,CAAC,CAAC;AAE/D;iBACiB;AACjB,MAAM,CAAC,MAAM,+BAA+B,GAAG,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmFzD,CAAC;AAEF;2DAC2D;AAC3D,MAAM,UAAU,aAAa,CAAC,CAAW;IACvC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partitionKernelLayout.d.ts","sourceRoot":"","sources":["../../../src/runtime/derivedModes/partitionKernelLayout.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE9D;AACD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEhE"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Partition kernel record layout — shared by the codegen + dispatcher.
|
|
2
|
+
//
|
|
3
|
+
// Each record in the master buffer has a FIXED 6-u32 prefix and a
|
|
4
|
+
// per-bucket variable tail of K uniform refs:
|
|
5
|
+
//
|
|
6
|
+
// [firstEmit, drawIdx, indexStart, indexCount, instanceCount, comboId,
|
|
7
|
+
// ref0, ref1, …, ref{K-1}]
|
|
8
|
+
//
|
|
9
|
+
// `firstEmit` is reserved (GPU-written by the downstream scan); CPU
|
|
10
|
+
// writes 0. `comboId` selects which combo of axis-rules the partition
|
|
11
|
+
// kernel evaluates — a combo is a per-RO choice of (at most one) rule
|
|
12
|
+
// per mode axis. Each `refI` is the per-RO arena byte offset of the
|
|
13
|
+
// I-th uniform appearing across all rules in the bucket
|
|
14
|
+
// (`bucket.uniformOrder`). The kernel reads `r.refI` for whichever
|
|
15
|
+
// uniform a given rule body declares via `ReadInput("Uniform", name)`
|
|
16
|
+
// — the codegen translates name → refI lookup.
|
|
17
|
+
export const PARTITION_RECORD_PREFIX_U32 = 6;
|
|
18
|
+
export function partitionRecordU32(numUniforms) {
|
|
19
|
+
return PARTITION_RECORD_PREFIX_U32 + numUniforms;
|
|
20
|
+
}
|
|
21
|
+
export function partitionRecordBytes(numUniforms) {
|
|
22
|
+
return partitionRecordU32(numUniforms) * 4;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=partitionKernelLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partitionKernelLayout.js","sourceRoot":"","sources":["../../../src/runtime/derivedModes/partitionKernelLayout.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,EAAE;AACF,kEAAkE;AAClE,8CAA8C;AAC9C,EAAE;AACF,yEAAyE;AACzE,8BAA8B;AAC9B,EAAE;AACF,oEAAoE;AACpE,sEAAsE;AACtE,sEAAsE;AACtE,oEAAoE;AACpE,wDAAwD;AACxD,mEAAmE;AACnE,sEAAsE;AACtE,+CAA+C;AAE/C,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAE7C,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO,2BAA2B,GAAG,WAAW,CAAC;AACnD,CAAC;AACD,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,OAAO,kBAAkB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -1,98 +1,50 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* uniforms you'll read via `UniformScope` augmentation on the
|
|
14
|
-
* wombat.shader side for compile-time safety, or annotate locally.
|
|
15
|
-
* - `declared`: the SG-declared value for this axis at this leaf.
|
|
16
|
-
* Identity rules `(u, d) => d` are valid and useful for axes that
|
|
17
|
-
* want to pass declared through unchanged.
|
|
18
|
-
*/
|
|
19
|
-
export type DerivedModeBuilder<A extends ModeAxis> = (u: Record<string, unknown>, declared: ModeValue<A>) => ModeValue<A>;
|
|
20
|
-
/**
|
|
21
|
-
* Opt-in GPU evaluation marker. When present on a rule, the heap
|
|
22
|
-
* scene runs a hard-coded WGSL kernel (see `./gpuKernel.ts`) instead
|
|
23
|
-
* of the CPU closure. The closure is retained for fallback (e.g.
|
|
24
|
-
* MockGPU tests, devices without compute, or before frame 0).
|
|
25
|
-
*
|
|
26
|
-
* v1 supports one kernel: `"flipCullByDeterminant"`. v2 generalizes
|
|
27
|
-
* via a traced IR builder.
|
|
28
|
-
*/
|
|
29
|
-
export interface GpuRuleSpec<A extends ModeAxis = ModeAxis> {
|
|
30
|
-
readonly kernel: "flipCullByDeterminant";
|
|
31
|
-
/** Name of the input uniform the kernel reads (e.g. "ModelTrafo"). */
|
|
32
|
-
readonly inputUniform: string;
|
|
33
|
-
/**
|
|
34
|
-
* Declared (SG-scope) value the kernel mutates by. Either a plain
|
|
35
|
-
* mode value (baked at scene-build) or an `aval` for reactive
|
|
36
|
-
* declared — the dispatcher re-uploads the kernel uniform on each
|
|
37
|
-
* dispatch from the aval's current value, so flipping it via a UI
|
|
38
|
-
* cval re-runs the rule with the new declared.
|
|
39
|
-
*/
|
|
40
|
-
readonly declared: ModeValue<A> | import("@aardworx/wombat.adaptive").aval<ModeValue<A>>;
|
|
41
|
-
}
|
|
1
|
+
import type { RuleExpr } from "@aardworx/wombat.shader";
|
|
2
|
+
import type { aval } from "@aardworx/wombat.adaptive";
|
|
3
|
+
import type { CullMode, FrontFace, Topology, AttachmentBlend } from "../pipelineCache/index.js";
|
|
4
|
+
export type ModeAxis = "cull" | "frontFace" | "topology" | "depthCompare" | "depthWrite" | "alphaToCoverage"
|
|
5
|
+
/** Per-attachment blend state. The rule's u32 output indexes into
|
|
6
|
+
* the `values` array on `DerivedModeOptions` (or the `resolve`
|
|
7
|
+
* callback); each entry is a full {@link AttachmentBlend} struct
|
|
8
|
+
* with srcFactor / dstFactor / operation / writeMask / enabled
|
|
9
|
+
* fields — letting blend rules specify the entire mode object,
|
|
10
|
+
* not just an enum index. */
|
|
11
|
+
| "blend";
|
|
12
|
+
export type ModeValue<A extends ModeAxis> = A extends "cull" ? CullMode : A extends "frontFace" ? FrontFace : A extends "topology" ? Topology : A extends "depthCompare" ? GPUCompareFunction : A extends "depthWrite" ? boolean : A extends "alphaToCoverage" ? boolean : A extends "blend" ? AttachmentBlend : never;
|
|
42
13
|
export interface DerivedModeRule<A extends ModeAxis = ModeAxis> {
|
|
43
14
|
readonly __derivedModeRule: true;
|
|
44
15
|
readonly axis: A;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
16
|
+
/** Shader-IR rule body — the entry's return Expr is the rule. For
|
|
17
|
+
* axes whose `ModeValue<A>` is a struct (e.g. blend's
|
|
18
|
+
* `AttachmentBlend`) the body returns object literals directly;
|
|
19
|
+
* the renderer fingerprints distinct returns and auto-assigns
|
|
20
|
+
* slot indices. For enum axes (cull etc.) the body returns u32
|
|
21
|
+
* enum indices that the renderer maps via the canonical table. */
|
|
22
|
+
readonly expr: RuleExpr<ModeValue<A> | number>;
|
|
48
23
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
24
|
+
* SG-context value for this axis. Filled in by `<Sg CullMode>` /
|
|
25
|
+
* `<Sg DepthTest>` / etc. at traversal time — users never write
|
|
26
|
+
* it. The rule body's `declared` ambient leaf resolves to this;
|
|
27
|
+
* when the underlying aval marks, heapScene re-specialises +
|
|
28
|
+
* swaps the cached kernel + pipeline set.
|
|
29
|
+
*
|
|
30
|
+
* `undefined` is the initial state right after `derivedMode(...)`;
|
|
31
|
+
* the SG fills it in before the rule reaches the renderer.
|
|
53
32
|
*/
|
|
54
|
-
readonly
|
|
33
|
+
readonly declared: aval<ModeValue<A>> | ModeValue<A> | undefined;
|
|
55
34
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Author a derived mode rule.
|
|
58
|
-
*
|
|
59
|
-
* derivedMode("cull", (u, declared) =>
|
|
60
|
-
* u.WindingFlipped ? flipCull(declared) : declared);
|
|
61
|
-
*
|
|
62
|
-
* derivedMode("blend", (u) => u.Premultiplied ? "premul" : "straight");
|
|
63
|
-
*
|
|
64
|
-
* // Determinant-flip-cull (the motivating case):
|
|
65
|
-
* derivedMode("cull", (u, declared) => {
|
|
66
|
-
* const m = u.ModelTrafo as M44d;
|
|
67
|
-
* const det =
|
|
68
|
-
* m.M00 * (m.M11 * m.M22 - m.M12 * m.M21) -
|
|
69
|
-
* m.M01 * (m.M10 * m.M22 - m.M12 * m.M20) +
|
|
70
|
-
* m.M02 * (m.M10 * m.M21 - m.M11 * m.M20);
|
|
71
|
-
* return det < 0 ? flipCull(declared) : declared;
|
|
72
|
-
* });
|
|
73
|
-
*/
|
|
74
|
-
export declare function derivedMode<A extends ModeAxis>(axis: A, evaluate: DerivedModeBuilder<A>, options?: {
|
|
75
|
-
readonly domain?: ReadonlyArray<ModeValue<A>>;
|
|
76
|
-
}): DerivedModeRule<A>;
|
|
77
|
-
/** Brand check — distinguishes a DerivedModeRule from an aval/raw value
|
|
78
|
-
* at runtime so PipelineState consumers can route accordingly. */
|
|
79
35
|
export declare function isDerivedModeRule(x: unknown): x is DerivedModeRule;
|
|
80
|
-
/** Convenience: flip 'back' ↔ 'front' (and pass through 'none').
|
|
81
|
-
* Useful in `(u, declared) => mirrored ? flipCull(declared) : declared`. */
|
|
82
|
-
export declare function flipCull(c: CullMode): CullMode;
|
|
83
36
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* heapScene's compute path is available; the same logic is mirrored
|
|
87
|
-
* in the CPU closure for tests and fallback.
|
|
37
|
+
* Brand a `RuleExpr` (the shader-IR artefact emitted by the
|
|
38
|
+
* `rule(...)` build-time marker) as a derived-mode rule for `axis`.
|
|
88
39
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
40
|
+
* The `declared` option carries the SG-context value the rule reads
|
|
41
|
+
* via `declare const declared: number` in its body. heapScene
|
|
42
|
+
* substitutes it (as a Const) before codegen — when `declared` is a
|
|
43
|
+
* cval, every mark triggers a re-specialise + cached-kernel swap.
|
|
91
44
|
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* carry this rule.
|
|
45
|
+
* `domain` is NOT a parameter: the renderer infers the per-declared
|
|
46
|
+
* set of possible outputs from the rule's IR via
|
|
47
|
+
* `analyseOutputSet` + `evaluateSet`.
|
|
96
48
|
*/
|
|
97
|
-
export declare function
|
|
49
|
+
export declare function derivedMode<A extends ModeAxis>(axis: A, expr: RuleExpr<ModeValue<A> | number>): DerivedModeRule<A>;
|
|
98
50
|
//# sourceMappingURL=rule.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/runtime/derivedModes/rule.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../../src/runtime/derivedModes/rule.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEhG,MAAM,MAAM,QAAQ,GAChB,MAAM,GAAG,WAAW,GAAG,UAAU,GACjC,cAAc,GAAG,YAAY,GAC7B,iBAAiB;AACnB;;;;;8BAK8B;GAC5B,OAAO,CAAC;AAEZ,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,QAAQ,IACtC,CAAC,SAAS,MAAM,GAAa,QAAQ,GACrC,CAAC,SAAS,WAAW,GAAQ,SAAS,GACtC,CAAC,SAAS,UAAU,GAAS,QAAQ,GACrC,CAAC,SAAS,cAAc,GAAK,kBAAkB,GAC/C,CAAC,SAAS,YAAY,GAAO,OAAO,GACpC,CAAC,SAAS,iBAAiB,GAAG,OAAO,GACrC,CAAC,SAAS,OAAO,GAAY,eAAe,GAC5C,KAAK,CAAC;AAER,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,QAAQ,GAAG,QAAQ;IAC5D,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB;;;;;uEAKmE;IACnE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;IAC/C;;;;;;;;;OASG;IACH,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;CAClE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,eAAe,CAGlE;AAGD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAC5C,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,GACpC,eAAe,CAAC,CAAC,CAAC,CAOpB"}
|
|
@@ -1,90 +1,50 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Derived-mode rule — branded combination of a shader-IR rule
|
|
2
|
+
// expression (from `rule(...)` in wombat.shader) + an axis + the
|
|
3
|
+
// SG-declared aval. The IR is what gets compiled into the partition
|
|
4
|
+
// kernel; the declared aval drives per-frame re-specialisation.
|
|
4
5
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
// shapes (a uniform-driven enum flip, a determinant-sign cull flip,
|
|
8
|
-
// etc.) and pairs naturally with the bucket-level rebuild fast path
|
|
9
|
-
// shipped in 0.9.16 — only ROs whose inputs actually changed get
|
|
10
|
-
// re-evaluated, and same-key buckets re-bind their pipeline once
|
|
11
|
-
// rather than per-RO.
|
|
6
|
+
// Authoring flow (with `@boperators/plugin-vite` + the shader-vite
|
|
7
|
+
// plugin both installed):
|
|
12
8
|
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
// CPU-side bottleneck. See docs/derived-mode-rules-plan.md.
|
|
9
|
+
// declare const u: { ModelTrafo: M44f };
|
|
10
|
+
// declare const declared: number;
|
|
16
11
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
* const m = u.ModelTrafo as M44d;
|
|
31
|
-
* const det =
|
|
32
|
-
* m.M00 * (m.M11 * m.M22 - m.M12 * m.M21) -
|
|
33
|
-
* m.M01 * (m.M10 * m.M22 - m.M12 * m.M20) +
|
|
34
|
-
* m.M02 * (m.M10 * m.M21 - m.M11 * m.M20);
|
|
35
|
-
* return det < 0 ? flipCull(declared) : declared;
|
|
36
|
-
* });
|
|
37
|
-
*/
|
|
38
|
-
export function derivedMode(axis, evaluate, options = {}) {
|
|
39
|
-
const out = options.domain !== undefined
|
|
40
|
-
? { __derivedModeRule: true, axis, evaluate, domain: options.domain }
|
|
41
|
-
: { __derivedModeRule: true, axis, evaluate };
|
|
42
|
-
return out;
|
|
43
|
-
}
|
|
44
|
-
/** Brand check — distinguishes a DerivedModeRule from an aval/raw value
|
|
45
|
-
* at runtime so PipelineState consumers can route accordingly. */
|
|
12
|
+
// const cullExpr = rule(() => {
|
|
13
|
+
// const m: M33f = mat3(u.ModelTrafo);
|
|
14
|
+
// const det = determinant(m);
|
|
15
|
+
// return det < 0 ? flipCull(declared) : declared;
|
|
16
|
+
// });
|
|
17
|
+
//
|
|
18
|
+
// const cullRule = derivedMode("cull", cullExpr, { declared: cullModeC });
|
|
19
|
+
//
|
|
20
|
+
// At runtime, heapScene reads `cullRule.expr.template`, extracts the
|
|
21
|
+
// entry's body Stmt, calls `analyseOutputSet(body)` to obtain the
|
|
22
|
+
// symbolic set, and for each declared-aval value resolves the set
|
|
23
|
+
// via `evaluateSet({"declared": current}, intrinsics)` to size the
|
|
24
|
+
// bucket's slots + codegen the partition kernel.
|
|
46
25
|
export function isDerivedModeRule(x) {
|
|
47
26
|
return typeof x === "object" && x !== null
|
|
48
27
|
&& x.__derivedModeRule === true;
|
|
49
28
|
}
|
|
50
|
-
/** Convenience: flip 'back' ↔ 'front' (and pass through 'none').
|
|
51
|
-
* Useful in `(u, declared) => mirrored ? flipCull(declared) : declared`. */
|
|
52
|
-
export function flipCull(c) {
|
|
53
|
-
return c === "back" ? "front" : c === "front" ? "back" : "none";
|
|
54
|
-
}
|
|
55
29
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* heapScene's compute path is available; the same logic is mirrored
|
|
59
|
-
* in the CPU closure for tests and fallback.
|
|
30
|
+
* Brand a `RuleExpr` (the shader-IR artefact emitted by the
|
|
31
|
+
* `rule(...)` build-time marker) as a derived-mode rule for `axis`.
|
|
60
32
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
33
|
+
* The `declared` option carries the SG-context value the rule reads
|
|
34
|
+
* via `declare const declared: number` in its body. heapScene
|
|
35
|
+
* substitutes it (as a Const) before codegen — when `declared` is a
|
|
36
|
+
* cval, every mark triggers a re-specialise + cached-kernel swap.
|
|
63
37
|
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* carry this rule.
|
|
38
|
+
* `domain` is NOT a parameter: the renderer infers the per-declared
|
|
39
|
+
* set of possible outputs from the rule's IR via
|
|
40
|
+
* `analyseOutputSet` + `evaluateSet`.
|
|
68
41
|
*/
|
|
69
|
-
export function
|
|
42
|
+
export function derivedMode(axis, expr) {
|
|
70
43
|
return {
|
|
71
44
|
__derivedModeRule: true,
|
|
72
|
-
axis
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
evaluate: (u, declaredFromCtx) => {
|
|
76
|
-
// Accept Trafo3d ({forward: M44d}) — the wombat.base shape used
|
|
77
|
-
// by SG ModelTrafo — or any object with M00..M22 accessors.
|
|
78
|
-
const raw = u[inputUniform];
|
|
79
|
-
const m = raw.forward
|
|
80
|
-
?? raw;
|
|
81
|
-
if (m === undefined || typeof m.M00 !== "number")
|
|
82
|
-
return declaredFromCtx;
|
|
83
|
-
const det = m.M00 * (m.M11 * m.M22 - m.M12 * m.M21)
|
|
84
|
-
- m.M01 * (m.M10 * m.M22 - m.M12 * m.M20)
|
|
85
|
-
+ m.M02 * (m.M10 * m.M21 - m.M11 * m.M20);
|
|
86
|
-
return det < 0 ? flipCull(declaredFromCtx) : declaredFromCtx;
|
|
87
|
-
},
|
|
45
|
+
axis,
|
|
46
|
+
expr,
|
|
47
|
+
declared: undefined, // SG fills this in at traversal time
|
|
88
48
|
};
|
|
89
49
|
}
|
|
90
50
|
//# sourceMappingURL=rule.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/runtime/derivedModes/rule.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../../src/runtime/derivedModes/rule.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,iEAAiE;AACjE,oEAAoE;AACpE,gEAAgE;AAChE,EAAE;AACF,mEAAmE;AACnE,0BAA0B;AAC1B,EAAE;AACF,6CAA6C;AAC7C,sCAAsC;AACtC,EAAE;AACF,oCAAoC;AACpC,4CAA4C;AAC5C,oCAAoC;AACpC,wDAAwD;AACxD,UAAU;AACV,EAAE;AACF,+EAA+E;AAC/E,EAAE;AACF,qEAAqE;AACrE,kEAAkE;AAClE,kEAAkE;AAClE,mEAAmE;AACnE,iDAAiD;AAmDjD,MAAM,UAAU,iBAAiB,CAAC,CAAU;IAC1C,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;WAClC,CAAqC,CAAC,iBAAiB,KAAK,IAAI,CAAC;AAC3E,CAAC;AAGD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CACzB,IAAO,EACP,IAAqC;IAErC,OAAO;QACL,iBAAiB,EAAE,IAAI;QACvB,IAAI;QACJ,IAAI;QACJ,QAAQ,EAAE,SAAS,EAAG,qCAAqC;KAC5D,CAAC;AACJ,CAAC"}
|
|
@@ -3,24 +3,26 @@ import type { RecordsBuffer } from "./records.js";
|
|
|
3
3
|
import { type SlotIndex } from "./slots.js";
|
|
4
4
|
/** Upload the changed-constituent value range to the constituents GPU buffer. */
|
|
5
5
|
export declare function uploadConstituentsRange(device: GPUDevice, buf: GPUBuffer, mirror: Float32Array, dirty: ReadonlySet<SlotIndex>): void;
|
|
6
|
-
/** Live getters for the GPU buffers the kernel binds
|
|
6
|
+
/** Live getters for the scene-wide GPU buffers the kernel binds. The
|
|
7
|
+
* main-heap binding is per-dispatch and supplied to `encodeChunk`,
|
|
8
|
+
* since one DerivedUniformsScene now serves multiple arena chunks
|
|
9
|
+
* (§3) and each chunk has its own main-heap GPUBuffer. */
|
|
7
10
|
export interface DerivedUniformsResources {
|
|
8
11
|
/** `array<vec2<f32>>` — df32 trafo halves (the constituents heap). */
|
|
9
12
|
readonly constituentsBuf: () => GPUBuffer;
|
|
10
|
-
/** `array<f32>` — the main heap (drawHeaders); written by the kernel. */
|
|
11
|
-
readonly mainHeapBuf: () => GPUBuffer;
|
|
12
13
|
}
|
|
13
14
|
export declare class DerivedUniformsDispatcher {
|
|
14
15
|
private readonly device;
|
|
15
16
|
private readonly resources;
|
|
16
|
-
private readonly gpu;
|
|
17
17
|
private readonly pipe;
|
|
18
|
-
private
|
|
19
|
-
private bgKey;
|
|
18
|
+
private readonly byChunk;
|
|
20
19
|
constructor(device: GPUDevice, resources: DerivedUniformsResources);
|
|
21
|
-
/**
|
|
22
|
-
|
|
20
|
+
/** Run the uber-kernel for ONE chunk's records, binding
|
|
21
|
+
* `mainHeapGetter()` as the heap target. No-op if the chunk's
|
|
22
|
+
* records buffer is empty or the registry has no rules. */
|
|
23
|
+
encodeChunk(enc: GPUCommandEncoder, registry: DerivedUniformRegistry, records: RecordsBuffer, mainHeapGetter: () => GPUBuffer): boolean;
|
|
23
24
|
dispose(): void;
|
|
25
|
+
private stateFor;
|
|
24
26
|
private bindGroup;
|
|
25
27
|
}
|
|
26
28
|
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/runtime/derivedUniforms/dispatch.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7D,iFAAiF;AACjF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,GAC5B,IAAI,CAWN;AAED
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/runtime/derivedUniforms/dispatch.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE7D,iFAAiF;AACjF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,WAAW,CAAC,SAAS,CAAC,GAC5B,IAAI,CAWN;AAED;;;2DAG2D;AAC3D,MAAM,WAAW,wBAAwB;IACvC,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,MAAM,SAAS,CAAC;CAC3C;AAmHD,qBAAa,yBAAyB;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;gBAEpD,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,wBAAwB;IAMlE;;gEAE4D;IAC5D,WAAW,CACT,GAAG,EAAE,iBAAiB,EACtB,QAAQ,EAAE,sBAAsB,EAChC,OAAO,EAAE,aAAa,EACtB,cAAc,EAAE,MAAM,SAAS,GAC9B,OAAO;IAcV,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,SAAS;CAmBlB"}
|
|
@@ -127,53 +127,66 @@ class UberPipeline {
|
|
|
127
127
|
export class DerivedUniformsDispatcher {
|
|
128
128
|
device;
|
|
129
129
|
resources;
|
|
130
|
-
gpu;
|
|
131
130
|
pipe;
|
|
132
|
-
|
|
133
|
-
bgKey = [undefined, undefined, undefined];
|
|
131
|
+
byChunk = new Map();
|
|
134
132
|
constructor(device, resources) {
|
|
135
133
|
this.device = device;
|
|
136
134
|
this.resources = resources;
|
|
137
|
-
this.gpu = new RecordsGpu(device);
|
|
138
135
|
this.pipe = new UberPipeline(device);
|
|
139
136
|
}
|
|
140
|
-
/**
|
|
141
|
-
|
|
137
|
+
/** Run the uber-kernel for ONE chunk's records, binding
|
|
138
|
+
* `mainHeapGetter()` as the heap target. No-op if the chunk's
|
|
139
|
+
* records buffer is empty or the registry has no rules. */
|
|
140
|
+
encodeChunk(enc, registry, records, mainHeapGetter) {
|
|
142
141
|
if (records.recordCount === 0)
|
|
143
142
|
return false;
|
|
144
143
|
const pipeline = this.pipe.pipeline(registry, records.strideWords);
|
|
145
144
|
if (pipeline === undefined)
|
|
146
145
|
return false;
|
|
147
|
-
this.
|
|
146
|
+
const state = this.stateFor(records);
|
|
147
|
+
state.gpu.sync(records);
|
|
148
148
|
const pass = enc.beginComputePass({ label: "derivedUniforms.uber" });
|
|
149
149
|
pass.setPipeline(pipeline);
|
|
150
|
-
pass.setBindGroup(0, this.bindGroup());
|
|
150
|
+
pass.setBindGroup(0, this.bindGroup(state, mainHeapGetter()));
|
|
151
151
|
pass.dispatchWorkgroups(Math.ceil(records.recordCount / 64));
|
|
152
152
|
pass.end();
|
|
153
153
|
return true;
|
|
154
154
|
}
|
|
155
155
|
dispose() {
|
|
156
|
-
this.
|
|
156
|
+
for (const s of this.byChunk.values())
|
|
157
|
+
s.gpu.dispose();
|
|
158
|
+
this.byChunk.clear();
|
|
157
159
|
}
|
|
158
|
-
|
|
160
|
+
stateFor(records) {
|
|
161
|
+
let s = this.byChunk.get(records);
|
|
162
|
+
if (s === undefined) {
|
|
163
|
+
s = {
|
|
164
|
+
gpu: new RecordsGpu(this.device),
|
|
165
|
+
cachedBg: undefined,
|
|
166
|
+
bgKey: [undefined, undefined, undefined],
|
|
167
|
+
};
|
|
168
|
+
this.byChunk.set(records, s);
|
|
169
|
+
}
|
|
170
|
+
return s;
|
|
171
|
+
}
|
|
172
|
+
bindGroup(state, heap) {
|
|
159
173
|
const consts = this.resources.constituentsBuf();
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return this.cachedBg;
|
|
174
|
+
const recs = state.gpu.buffer();
|
|
175
|
+
if (state.cachedBg !== undefined && state.bgKey[0] === consts && state.bgKey[1] === heap && state.bgKey[2] === recs) {
|
|
176
|
+
return state.cachedBg;
|
|
164
177
|
}
|
|
165
|
-
|
|
178
|
+
state.cachedBg = this.device.createBindGroup({
|
|
166
179
|
label: "derivedUniforms.uber",
|
|
167
180
|
layout: this.pipe.bgl,
|
|
168
181
|
entries: [
|
|
169
182
|
{ binding: 0, resource: { buffer: consts } },
|
|
170
183
|
{ binding: 1, resource: { buffer: heap } },
|
|
171
184
|
{ binding: 2, resource: { buffer: recs } },
|
|
172
|
-
{ binding: 3, resource: { buffer:
|
|
185
|
+
{ binding: 3, resource: { buffer: state.gpu.countBuf } },
|
|
173
186
|
],
|
|
174
187
|
});
|
|
175
|
-
|
|
176
|
-
return
|
|
188
|
+
state.bgKey = [consts, heap, recs];
|
|
189
|
+
return state.cachedBg;
|
|
177
190
|
}
|
|
178
191
|
}
|
|
179
192
|
//# sourceMappingURL=dispatch.js.map
|