@plasius/gpu-renderer 0.1.6 → 0.1.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/CHANGELOG.md +53 -0
- package/README.md +78 -0
- package/dist/index.cjs +813 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +800 -6
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/src/index.d.ts +239 -1
- package/src/index.js +862 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,641 @@
|
|
|
1
1
|
// src/index.js
|
|
2
2
|
var DEFAULT_CLEAR_COLOR = Object.freeze([0.07, 0.11, 0.18, 1]);
|
|
3
3
|
var DEFAULT_CANVAS_SELECTOR = "canvas[data-plasius-gpu-renderer]";
|
|
4
|
+
var rendererDebugOwner = "renderer";
|
|
5
|
+
var rendererWorkerQueueClass = "render";
|
|
6
|
+
var defaultRendererWorkerProfile = "realtime";
|
|
7
|
+
var rendererRepresentationBands = Object.freeze([
|
|
8
|
+
"near",
|
|
9
|
+
"mid",
|
|
10
|
+
"far",
|
|
11
|
+
"horizon"
|
|
12
|
+
]);
|
|
13
|
+
var rendererAccelerationStructureUpdateClasses = Object.freeze([
|
|
14
|
+
"static",
|
|
15
|
+
"rigid-dynamic",
|
|
16
|
+
"deforming",
|
|
17
|
+
"proxy"
|
|
18
|
+
]);
|
|
19
|
+
var rendererRayTracingStageOrder = Object.freeze([
|
|
20
|
+
"primaryVisibility",
|
|
21
|
+
"shadowAssist",
|
|
22
|
+
"opaqueFoundation",
|
|
23
|
+
"rtDirectLighting",
|
|
24
|
+
"rtReflections",
|
|
25
|
+
"rtGlobalIllumination",
|
|
26
|
+
"denoiseTemporal",
|
|
27
|
+
"transparents",
|
|
28
|
+
"composition",
|
|
29
|
+
"present"
|
|
30
|
+
]);
|
|
31
|
+
var rendererRayTracingStageDefinitions = Object.freeze(
|
|
32
|
+
rendererRayTracingStageOrder.map(
|
|
33
|
+
(key, index) => Object.freeze({
|
|
34
|
+
key,
|
|
35
|
+
order: index + 1,
|
|
36
|
+
required: true,
|
|
37
|
+
description: {
|
|
38
|
+
primaryVisibility: "Primary visibility and depth preparation.",
|
|
39
|
+
shadowAssist: "Shadow assist passes and regional shadow preparation.",
|
|
40
|
+
opaqueFoundation: "Main opaque foundation for shading and tracing inputs.",
|
|
41
|
+
rtDirectLighting: "Ray-traced direct lighting and premium shadows.",
|
|
42
|
+
rtReflections: "Ray-traced reflections for important surfaces.",
|
|
43
|
+
rtGlobalIllumination: "Selective ray-traced indirect lighting and GI.",
|
|
44
|
+
denoiseTemporal: "Required denoise and temporal accumulation stage.",
|
|
45
|
+
transparents: "Transparents, particles, and volumetrics composition.",
|
|
46
|
+
composition: "Final world composition and color resolve.",
|
|
47
|
+
present: "Presentation to the active surface."
|
|
48
|
+
}[key]
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
);
|
|
52
|
+
var rendererRepresentationBandPolicies = Object.freeze({
|
|
53
|
+
near: Object.freeze({
|
|
54
|
+
band: "near",
|
|
55
|
+
rasterMode: "full-live",
|
|
56
|
+
rtParticipation: "premium",
|
|
57
|
+
shadowSource: "ray-traced-primary",
|
|
58
|
+
temporalReuse: "balanced",
|
|
59
|
+
updateCadenceDivisor: 1
|
|
60
|
+
}),
|
|
61
|
+
mid: Object.freeze({
|
|
62
|
+
band: "mid",
|
|
63
|
+
rasterMode: "simplified-live",
|
|
64
|
+
rtParticipation: "selective",
|
|
65
|
+
shadowSource: "regional-raster-and-proxy",
|
|
66
|
+
temporalReuse: "aggressive",
|
|
67
|
+
updateCadenceDivisor: 2
|
|
68
|
+
}),
|
|
69
|
+
far: Object.freeze({
|
|
70
|
+
band: "far",
|
|
71
|
+
rasterMode: "proxy-or-cached",
|
|
72
|
+
rtParticipation: "proxy",
|
|
73
|
+
shadowSource: "merged-proxy-casters",
|
|
74
|
+
temporalReuse: "high",
|
|
75
|
+
updateCadenceDivisor: 8
|
|
76
|
+
}),
|
|
77
|
+
horizon: Object.freeze({
|
|
78
|
+
band: "horizon",
|
|
79
|
+
rasterMode: "horizon-shell",
|
|
80
|
+
rtParticipation: "disabled",
|
|
81
|
+
shadowSource: "baked-impression",
|
|
82
|
+
temporalReuse: "cached",
|
|
83
|
+
updateCadenceDivisor: 60
|
|
84
|
+
})
|
|
85
|
+
});
|
|
86
|
+
var rendererAccelerationStructurePolicies = Object.freeze(
|
|
87
|
+
rendererAccelerationStructureUpdateClasses.map(
|
|
88
|
+
(updateClass) => Object.freeze({
|
|
89
|
+
updateClass,
|
|
90
|
+
description: {
|
|
91
|
+
static: "Stable static world geometry with infrequent rebuilds.",
|
|
92
|
+
"rigid-dynamic": "Rigid transforms that can be refit or relinked without full deformation updates.",
|
|
93
|
+
deforming: "Skinned or vertex-deforming content treated as a managed RT cost center.",
|
|
94
|
+
proxy: "Low-cost RT proxy or distant representation updates."
|
|
95
|
+
}[updateClass]
|
|
96
|
+
})
|
|
97
|
+
)
|
|
98
|
+
);
|
|
99
|
+
function buildRendererWorkerBudgetLevels(jobType, queueClass, levels) {
|
|
100
|
+
return Object.freeze(
|
|
101
|
+
levels.map(
|
|
102
|
+
(level) => Object.freeze({
|
|
103
|
+
id: level.id,
|
|
104
|
+
estimatedCostMs: level.estimatedCostMs,
|
|
105
|
+
config: Object.freeze({
|
|
106
|
+
maxDispatchesPerFrame: level.config.maxDispatchesPerFrame,
|
|
107
|
+
maxJobsPerDispatch: level.config.maxJobsPerDispatch,
|
|
108
|
+
cadenceDivisor: level.config.cadenceDivisor,
|
|
109
|
+
workgroupScale: level.config.workgroupScale,
|
|
110
|
+
maxQueueDepth: level.config.maxQueueDepth,
|
|
111
|
+
metadata: Object.freeze({
|
|
112
|
+
owner: rendererDebugOwner,
|
|
113
|
+
queueClass,
|
|
114
|
+
jobType,
|
|
115
|
+
quality: level.id
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
})
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
var rendererWorkerProfileSpecs = {
|
|
123
|
+
realtime: {
|
|
124
|
+
description: "Frame-stage DAG for flat rendering with visibility, main encode, post-processing, and submit.",
|
|
125
|
+
suggestedAllocationIds: [
|
|
126
|
+
"renderer.surface.current",
|
|
127
|
+
"renderer.visibility.worklist",
|
|
128
|
+
"renderer.post-process.history"
|
|
129
|
+
],
|
|
130
|
+
jobs: {
|
|
131
|
+
acquire: {
|
|
132
|
+
priority: 5,
|
|
133
|
+
dependencies: [],
|
|
134
|
+
domain: "resolution",
|
|
135
|
+
importance: "critical",
|
|
136
|
+
levels: [
|
|
137
|
+
{
|
|
138
|
+
id: "fixed",
|
|
139
|
+
estimatedCostMs: 0.2,
|
|
140
|
+
config: {
|
|
141
|
+
maxDispatchesPerFrame: 1,
|
|
142
|
+
maxJobsPerDispatch: 1,
|
|
143
|
+
cadenceDivisor: 1,
|
|
144
|
+
workgroupScale: 1,
|
|
145
|
+
maxQueueDepth: 1
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
],
|
|
149
|
+
suggestedAllocationIds: ["renderer.surface.current"]
|
|
150
|
+
},
|
|
151
|
+
visibility: {
|
|
152
|
+
priority: 4,
|
|
153
|
+
dependencies: [],
|
|
154
|
+
domain: "geometry",
|
|
155
|
+
importance: "high",
|
|
156
|
+
levels: [
|
|
157
|
+
{
|
|
158
|
+
id: "low",
|
|
159
|
+
estimatedCostMs: 0.4,
|
|
160
|
+
config: {
|
|
161
|
+
maxDispatchesPerFrame: 1,
|
|
162
|
+
maxJobsPerDispatch: 128,
|
|
163
|
+
cadenceDivisor: 2,
|
|
164
|
+
workgroupScale: 0.5,
|
|
165
|
+
maxQueueDepth: 256
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "medium",
|
|
170
|
+
estimatedCostMs: 0.8,
|
|
171
|
+
config: {
|
|
172
|
+
maxDispatchesPerFrame: 1,
|
|
173
|
+
maxJobsPerDispatch: 256,
|
|
174
|
+
cadenceDivisor: 1,
|
|
175
|
+
workgroupScale: 0.75,
|
|
176
|
+
maxQueueDepth: 384
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "high",
|
|
181
|
+
estimatedCostMs: 1.2,
|
|
182
|
+
config: {
|
|
183
|
+
maxDispatchesPerFrame: 2,
|
|
184
|
+
maxJobsPerDispatch: 512,
|
|
185
|
+
cadenceDivisor: 1,
|
|
186
|
+
workgroupScale: 1,
|
|
187
|
+
maxQueueDepth: 512
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
suggestedAllocationIds: ["renderer.visibility.worklist"]
|
|
192
|
+
},
|
|
193
|
+
mainEncode: {
|
|
194
|
+
priority: 4,
|
|
195
|
+
dependencies: ["acquire", "visibility"],
|
|
196
|
+
domain: "geometry",
|
|
197
|
+
importance: "critical",
|
|
198
|
+
levels: [
|
|
199
|
+
{
|
|
200
|
+
id: "low",
|
|
201
|
+
estimatedCostMs: 1.2,
|
|
202
|
+
config: {
|
|
203
|
+
maxDispatchesPerFrame: 1,
|
|
204
|
+
maxJobsPerDispatch: 128,
|
|
205
|
+
cadenceDivisor: 1,
|
|
206
|
+
workgroupScale: 0.6,
|
|
207
|
+
maxQueueDepth: 192
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
id: "medium",
|
|
212
|
+
estimatedCostMs: 2.1,
|
|
213
|
+
config: {
|
|
214
|
+
maxDispatchesPerFrame: 1,
|
|
215
|
+
maxJobsPerDispatch: 256,
|
|
216
|
+
cadenceDivisor: 1,
|
|
217
|
+
workgroupScale: 0.8,
|
|
218
|
+
maxQueueDepth: 256
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
id: "high",
|
|
223
|
+
estimatedCostMs: 3,
|
|
224
|
+
config: {
|
|
225
|
+
maxDispatchesPerFrame: 1,
|
|
226
|
+
maxJobsPerDispatch: 384,
|
|
227
|
+
cadenceDivisor: 1,
|
|
228
|
+
workgroupScale: 1,
|
|
229
|
+
maxQueueDepth: 384
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
],
|
|
233
|
+
suggestedAllocationIds: ["renderer.surface.current"]
|
|
234
|
+
},
|
|
235
|
+
postProcess: {
|
|
236
|
+
priority: 3,
|
|
237
|
+
dependencies: ["mainEncode"],
|
|
238
|
+
domain: "post-processing",
|
|
239
|
+
importance: "high",
|
|
240
|
+
levels: [
|
|
241
|
+
{
|
|
242
|
+
id: "low",
|
|
243
|
+
estimatedCostMs: 0.5,
|
|
244
|
+
config: {
|
|
245
|
+
maxDispatchesPerFrame: 1,
|
|
246
|
+
maxJobsPerDispatch: 64,
|
|
247
|
+
cadenceDivisor: 2,
|
|
248
|
+
workgroupScale: 0.5,
|
|
249
|
+
maxQueueDepth: 96
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
id: "medium",
|
|
254
|
+
estimatedCostMs: 0.9,
|
|
255
|
+
config: {
|
|
256
|
+
maxDispatchesPerFrame: 1,
|
|
257
|
+
maxJobsPerDispatch: 128,
|
|
258
|
+
cadenceDivisor: 1,
|
|
259
|
+
workgroupScale: 0.75,
|
|
260
|
+
maxQueueDepth: 128
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
id: "high",
|
|
265
|
+
estimatedCostMs: 1.4,
|
|
266
|
+
config: {
|
|
267
|
+
maxDispatchesPerFrame: 2,
|
|
268
|
+
maxJobsPerDispatch: 192,
|
|
269
|
+
cadenceDivisor: 1,
|
|
270
|
+
workgroupScale: 1,
|
|
271
|
+
maxQueueDepth: 192
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
],
|
|
275
|
+
suggestedAllocationIds: ["renderer.post-process.history"]
|
|
276
|
+
},
|
|
277
|
+
submit: {
|
|
278
|
+
priority: 2,
|
|
279
|
+
dependencies: ["postProcess"],
|
|
280
|
+
domain: "resolution",
|
|
281
|
+
importance: "critical",
|
|
282
|
+
levels: [
|
|
283
|
+
{
|
|
284
|
+
id: "fixed",
|
|
285
|
+
estimatedCostMs: 0.2,
|
|
286
|
+
config: {
|
|
287
|
+
maxDispatchesPerFrame: 1,
|
|
288
|
+
maxJobsPerDispatch: 1,
|
|
289
|
+
cadenceDivisor: 1,
|
|
290
|
+
workgroupScale: 1,
|
|
291
|
+
maxQueueDepth: 1
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
],
|
|
295
|
+
suggestedAllocationIds: ["renderer.surface.current"]
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
xr: {
|
|
300
|
+
description: "Frame-stage DAG for XR rendering with late-latch coordination before main encode and submit.",
|
|
301
|
+
suggestedAllocationIds: [
|
|
302
|
+
"renderer.xr.surface.current",
|
|
303
|
+
"renderer.xr.visibility.worklist"
|
|
304
|
+
],
|
|
305
|
+
jobs: {
|
|
306
|
+
acquire: {
|
|
307
|
+
priority: 5,
|
|
308
|
+
dependencies: [],
|
|
309
|
+
domain: "xr",
|
|
310
|
+
importance: "critical",
|
|
311
|
+
levels: [
|
|
312
|
+
{
|
|
313
|
+
id: "fixed",
|
|
314
|
+
estimatedCostMs: 0.2,
|
|
315
|
+
config: {
|
|
316
|
+
maxDispatchesPerFrame: 1,
|
|
317
|
+
maxJobsPerDispatch: 1,
|
|
318
|
+
cadenceDivisor: 1,
|
|
319
|
+
workgroupScale: 1,
|
|
320
|
+
maxQueueDepth: 1
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
],
|
|
324
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
325
|
+
},
|
|
326
|
+
visibility: {
|
|
327
|
+
priority: 4,
|
|
328
|
+
dependencies: [],
|
|
329
|
+
domain: "geometry",
|
|
330
|
+
importance: "high",
|
|
331
|
+
levels: [
|
|
332
|
+
{
|
|
333
|
+
id: "low",
|
|
334
|
+
estimatedCostMs: 0.5,
|
|
335
|
+
config: {
|
|
336
|
+
maxDispatchesPerFrame: 1,
|
|
337
|
+
maxJobsPerDispatch: 96,
|
|
338
|
+
cadenceDivisor: 2,
|
|
339
|
+
workgroupScale: 0.5,
|
|
340
|
+
maxQueueDepth: 192
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: "medium",
|
|
345
|
+
estimatedCostMs: 0.9,
|
|
346
|
+
config: {
|
|
347
|
+
maxDispatchesPerFrame: 1,
|
|
348
|
+
maxJobsPerDispatch: 192,
|
|
349
|
+
cadenceDivisor: 1,
|
|
350
|
+
workgroupScale: 0.75,
|
|
351
|
+
maxQueueDepth: 256
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
id: "high",
|
|
356
|
+
estimatedCostMs: 1.3,
|
|
357
|
+
config: {
|
|
358
|
+
maxDispatchesPerFrame: 2,
|
|
359
|
+
maxJobsPerDispatch: 320,
|
|
360
|
+
cadenceDivisor: 1,
|
|
361
|
+
workgroupScale: 1,
|
|
362
|
+
maxQueueDepth: 320
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
],
|
|
366
|
+
suggestedAllocationIds: ["renderer.xr.visibility.worklist"]
|
|
367
|
+
},
|
|
368
|
+
lateLatch: {
|
|
369
|
+
priority: 5,
|
|
370
|
+
dependencies: ["acquire"],
|
|
371
|
+
domain: "xr",
|
|
372
|
+
importance: "critical",
|
|
373
|
+
levels: [
|
|
374
|
+
{
|
|
375
|
+
id: "fixed",
|
|
376
|
+
estimatedCostMs: 0.15,
|
|
377
|
+
config: {
|
|
378
|
+
maxDispatchesPerFrame: 1,
|
|
379
|
+
maxJobsPerDispatch: 1,
|
|
380
|
+
cadenceDivisor: 1,
|
|
381
|
+
workgroupScale: 1,
|
|
382
|
+
maxQueueDepth: 1
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
],
|
|
386
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
387
|
+
},
|
|
388
|
+
mainEncode: {
|
|
389
|
+
priority: 4,
|
|
390
|
+
dependencies: ["visibility", "lateLatch"],
|
|
391
|
+
domain: "xr",
|
|
392
|
+
importance: "critical",
|
|
393
|
+
levels: [
|
|
394
|
+
{
|
|
395
|
+
id: "low",
|
|
396
|
+
estimatedCostMs: 1.1,
|
|
397
|
+
config: {
|
|
398
|
+
maxDispatchesPerFrame: 1,
|
|
399
|
+
maxJobsPerDispatch: 96,
|
|
400
|
+
cadenceDivisor: 1,
|
|
401
|
+
workgroupScale: 0.6,
|
|
402
|
+
maxQueueDepth: 128
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
id: "medium",
|
|
407
|
+
estimatedCostMs: 1.8,
|
|
408
|
+
config: {
|
|
409
|
+
maxDispatchesPerFrame: 1,
|
|
410
|
+
maxJobsPerDispatch: 192,
|
|
411
|
+
cadenceDivisor: 1,
|
|
412
|
+
workgroupScale: 0.8,
|
|
413
|
+
maxQueueDepth: 192
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
id: "high",
|
|
418
|
+
estimatedCostMs: 2.6,
|
|
419
|
+
config: {
|
|
420
|
+
maxDispatchesPerFrame: 1,
|
|
421
|
+
maxJobsPerDispatch: 256,
|
|
422
|
+
cadenceDivisor: 1,
|
|
423
|
+
workgroupScale: 1,
|
|
424
|
+
maxQueueDepth: 256
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
],
|
|
428
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
429
|
+
},
|
|
430
|
+
submit: {
|
|
431
|
+
priority: 2,
|
|
432
|
+
dependencies: ["mainEncode"],
|
|
433
|
+
domain: "xr",
|
|
434
|
+
importance: "critical",
|
|
435
|
+
levels: [
|
|
436
|
+
{
|
|
437
|
+
id: "fixed",
|
|
438
|
+
estimatedCostMs: 0.2,
|
|
439
|
+
config: {
|
|
440
|
+
maxDispatchesPerFrame: 1,
|
|
441
|
+
maxJobsPerDispatch: 1,
|
|
442
|
+
cadenceDivisor: 1,
|
|
443
|
+
workgroupScale: 1,
|
|
444
|
+
maxQueueDepth: 1
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
],
|
|
448
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
function buildRendererInputBoundary(profile) {
|
|
454
|
+
return Object.freeze({
|
|
455
|
+
type: "stable-visual-snapshot",
|
|
456
|
+
owner: rendererDebugOwner,
|
|
457
|
+
profile,
|
|
458
|
+
authority: "visual",
|
|
459
|
+
source: "scene-preparation",
|
|
460
|
+
stable: true
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
function buildRendererRenderStages(profile) {
|
|
464
|
+
return Object.freeze(
|
|
465
|
+
rendererRayTracingStageDefinitions.map(
|
|
466
|
+
(stage) => Object.freeze({
|
|
467
|
+
...stage,
|
|
468
|
+
profile,
|
|
469
|
+
workerJobKeys: profile === "xr" && stage.key === "primaryVisibility" ? Object.freeze(["lateLatch", "visibility"]) : stage.key === "present" ? Object.freeze(["submit"]) : stage.key === "denoiseTemporal" || stage.key === "transparents" || stage.key === "composition" ? Object.freeze(["postProcess"]) : stage.key === "primaryVisibility" ? Object.freeze(["visibility"]) : stage.key === "shadowAssist" || stage.key === "opaqueFoundation" || stage.key === "rtDirectLighting" || stage.key === "rtReflections" || stage.key === "rtGlobalIllumination" ? Object.freeze(["mainEncode"]) : Object.freeze(["mainEncode"])
|
|
470
|
+
})
|
|
471
|
+
)
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
function buildRendererRepresentationBands(profile) {
|
|
475
|
+
return Object.freeze(
|
|
476
|
+
rendererRepresentationBands.map(
|
|
477
|
+
(band) => Object.freeze({
|
|
478
|
+
...rendererRepresentationBandPolicies[band],
|
|
479
|
+
profile
|
|
480
|
+
})
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
function buildRendererAccelerationStructureUpdates(profile) {
|
|
485
|
+
return Object.freeze(
|
|
486
|
+
rendererAccelerationStructurePolicies.map(
|
|
487
|
+
(policy) => Object.freeze({
|
|
488
|
+
...policy,
|
|
489
|
+
profile
|
|
490
|
+
})
|
|
491
|
+
)
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
function assertRendererIdentifier(name, value) {
|
|
495
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
496
|
+
throw new Error(`${name} must be a non-empty string.`);
|
|
497
|
+
}
|
|
498
|
+
return value.trim();
|
|
499
|
+
}
|
|
500
|
+
function buildRendererWorkerProfile(name, spec) {
|
|
501
|
+
return Object.freeze({
|
|
502
|
+
name,
|
|
503
|
+
description: spec.description,
|
|
504
|
+
jobs: Object.freeze(Object.keys(spec.jobs))
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
function buildRendererWorkerManifestJob(profileName, jobName, spec) {
|
|
508
|
+
const label = `renderer.${profileName}.${jobName}`;
|
|
509
|
+
return Object.freeze({
|
|
510
|
+
key: jobName,
|
|
511
|
+
label,
|
|
512
|
+
worker: Object.freeze({
|
|
513
|
+
jobType: label,
|
|
514
|
+
queueClass: rendererWorkerQueueClass,
|
|
515
|
+
priority: spec.priority,
|
|
516
|
+
dependencies: Object.freeze(
|
|
517
|
+
spec.dependencies.map((dependency) => `renderer.${profileName}.${dependency}`)
|
|
518
|
+
),
|
|
519
|
+
schedulerMode: "dag"
|
|
520
|
+
}),
|
|
521
|
+
performance: Object.freeze({
|
|
522
|
+
id: label,
|
|
523
|
+
jobType: label,
|
|
524
|
+
queueClass: rendererWorkerQueueClass,
|
|
525
|
+
domain: spec.domain,
|
|
526
|
+
authority: "visual",
|
|
527
|
+
importance: spec.importance,
|
|
528
|
+
levels: buildRendererWorkerBudgetLevels(
|
|
529
|
+
label,
|
|
530
|
+
rendererWorkerQueueClass,
|
|
531
|
+
spec.levels
|
|
532
|
+
)
|
|
533
|
+
}),
|
|
534
|
+
debug: Object.freeze({
|
|
535
|
+
owner: rendererDebugOwner,
|
|
536
|
+
queueClass: rendererWorkerQueueClass,
|
|
537
|
+
jobType: label,
|
|
538
|
+
tags: Object.freeze(["renderer", profileName, jobName, spec.domain]),
|
|
539
|
+
suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds])
|
|
540
|
+
})
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
function buildRendererWorkerManifest(name, spec) {
|
|
544
|
+
return Object.freeze({
|
|
545
|
+
schemaVersion: 1,
|
|
546
|
+
owner: rendererDebugOwner,
|
|
547
|
+
profile: name,
|
|
548
|
+
description: spec.description,
|
|
549
|
+
queueClass: rendererWorkerQueueClass,
|
|
550
|
+
schedulerMode: "dag",
|
|
551
|
+
inputBoundary: buildRendererInputBoundary(name),
|
|
552
|
+
renderStages: buildRendererRenderStages(name),
|
|
553
|
+
representationBands: buildRendererRepresentationBands(name),
|
|
554
|
+
accelerationStructureUpdates: buildRendererAccelerationStructureUpdates(name),
|
|
555
|
+
suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds]),
|
|
556
|
+
jobs: Object.freeze(
|
|
557
|
+
Object.entries(spec.jobs).map(
|
|
558
|
+
([jobName, jobSpec]) => buildRendererWorkerManifestJob(name, jobName, jobSpec)
|
|
559
|
+
)
|
|
560
|
+
)
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
var rendererWorkerProfiles = Object.freeze(
|
|
564
|
+
Object.fromEntries(
|
|
565
|
+
Object.entries(rendererWorkerProfileSpecs).map(([name, spec]) => [
|
|
566
|
+
name,
|
|
567
|
+
buildRendererWorkerProfile(name, spec)
|
|
568
|
+
])
|
|
569
|
+
)
|
|
570
|
+
);
|
|
571
|
+
var rendererWorkerProfileNames = Object.freeze(
|
|
572
|
+
Object.keys(rendererWorkerProfiles)
|
|
573
|
+
);
|
|
574
|
+
var rendererWorkerManifests = Object.freeze(
|
|
575
|
+
Object.fromEntries(
|
|
576
|
+
Object.entries(rendererWorkerProfileSpecs).map(([name, spec]) => [
|
|
577
|
+
name,
|
|
578
|
+
buildRendererWorkerManifest(name, spec)
|
|
579
|
+
])
|
|
580
|
+
)
|
|
581
|
+
);
|
|
582
|
+
function getRendererWorkerProfile(name = defaultRendererWorkerProfile) {
|
|
583
|
+
const profile = rendererWorkerProfiles[name];
|
|
584
|
+
if (!profile) {
|
|
585
|
+
const available = rendererWorkerProfileNames.join(", ");
|
|
586
|
+
throw new Error(`Unknown renderer worker profile "${name}". Available: ${available}.`);
|
|
587
|
+
}
|
|
588
|
+
return profile;
|
|
589
|
+
}
|
|
590
|
+
function getRendererWorkerManifest(name = defaultRendererWorkerProfile) {
|
|
591
|
+
const manifest = rendererWorkerManifests[name];
|
|
592
|
+
if (!manifest) {
|
|
593
|
+
const available = rendererWorkerProfileNames.join(", ");
|
|
594
|
+
throw new Error(`Unknown renderer worker profile "${name}". Available: ${available}.`);
|
|
595
|
+
}
|
|
596
|
+
return manifest;
|
|
597
|
+
}
|
|
598
|
+
function createRayTracingRenderPlan(options = {}) {
|
|
599
|
+
const profile = options.profile ?? defaultRendererWorkerProfile;
|
|
600
|
+
const snapshotId = assertRendererIdentifier(
|
|
601
|
+
"snapshotId",
|
|
602
|
+
options.snapshotId
|
|
603
|
+
);
|
|
604
|
+
const workerManifest = getRendererWorkerManifest(profile);
|
|
605
|
+
const representations = Array.isArray(options.representations) ? Object.freeze(
|
|
606
|
+
options.representations.map((representation, index) => {
|
|
607
|
+
if (!representation || typeof representation !== "object") {
|
|
608
|
+
throw new Error(`representations[${index}] must be an object.`);
|
|
609
|
+
}
|
|
610
|
+
const band = assertRendererIdentifier(
|
|
611
|
+
`representations[${index}].band`,
|
|
612
|
+
representation.band
|
|
613
|
+
);
|
|
614
|
+
if (!rendererRepresentationBands.includes(band)) {
|
|
615
|
+
throw new Error(
|
|
616
|
+
`representations[${index}].band must be one of: ${rendererRepresentationBands.join(", ")}.`
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
return Object.freeze({
|
|
620
|
+
...representation,
|
|
621
|
+
band
|
|
622
|
+
});
|
|
623
|
+
})
|
|
624
|
+
) : workerManifest.representationBands;
|
|
625
|
+
return Object.freeze({
|
|
626
|
+
schemaVersion: 1,
|
|
627
|
+
owner: rendererDebugOwner,
|
|
628
|
+
profile,
|
|
629
|
+
inputBoundary: Object.freeze({
|
|
630
|
+
...workerManifest.inputBoundary,
|
|
631
|
+
snapshotId
|
|
632
|
+
}),
|
|
633
|
+
renderStages: workerManifest.renderStages,
|
|
634
|
+
representationBands: representations,
|
|
635
|
+
accelerationStructureUpdates: workerManifest.accelerationStructureUpdates,
|
|
636
|
+
workerManifest
|
|
637
|
+
});
|
|
638
|
+
}
|
|
4
639
|
function clamp01(value) {
|
|
5
640
|
return Math.min(1, Math.max(0, value));
|
|
6
641
|
}
|
|
@@ -36,12 +671,111 @@ function normalizeColor(value) {
|
|
|
36
671
|
}
|
|
37
672
|
return [...DEFAULT_CLEAR_COLOR];
|
|
38
673
|
}
|
|
674
|
+
function readPositiveNumber(name, value) {
|
|
675
|
+
if (value === void 0) {
|
|
676
|
+
return void 0;
|
|
677
|
+
}
|
|
678
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
679
|
+
throw new Error(`${name} must be a finite number greater than zero.`);
|
|
680
|
+
}
|
|
681
|
+
return value;
|
|
682
|
+
}
|
|
39
683
|
function now() {
|
|
40
684
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
41
685
|
return performance.now();
|
|
42
686
|
}
|
|
43
687
|
return Date.now();
|
|
44
688
|
}
|
|
689
|
+
function normalizeFrameId(value) {
|
|
690
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
691
|
+
throw new Error("frameIdFactory must return a non-empty string.");
|
|
692
|
+
}
|
|
693
|
+
return value.trim();
|
|
694
|
+
}
|
|
695
|
+
function resolveTargetFrameTimeMs(options, event) {
|
|
696
|
+
const {
|
|
697
|
+
targetFrameTimeMs: fixedTargetFrameTimeMs,
|
|
698
|
+
targetFrameRate,
|
|
699
|
+
getTargetFrameTimeMs
|
|
700
|
+
} = options;
|
|
701
|
+
if (typeof getTargetFrameTimeMs === "function") {
|
|
702
|
+
const resolved = getTargetFrameTimeMs(event);
|
|
703
|
+
return readPositiveNumber("getTargetFrameTimeMs()", resolved);
|
|
704
|
+
}
|
|
705
|
+
if (fixedTargetFrameTimeMs !== void 0) {
|
|
706
|
+
return fixedTargetFrameTimeMs;
|
|
707
|
+
}
|
|
708
|
+
if (targetFrameRate !== void 0) {
|
|
709
|
+
return 1e3 / targetFrameRate;
|
|
710
|
+
}
|
|
711
|
+
return void 0;
|
|
712
|
+
}
|
|
713
|
+
function createRendererDebugHooks(options = {}) {
|
|
714
|
+
const {
|
|
715
|
+
debugSession,
|
|
716
|
+
targetFrameTimeMs,
|
|
717
|
+
targetFrameRate,
|
|
718
|
+
getTargetFrameTimeMs,
|
|
719
|
+
onFrameStart,
|
|
720
|
+
onFrameComplete
|
|
721
|
+
} = options;
|
|
722
|
+
if (!debugSession || typeof debugSession.recordFrame !== "function") {
|
|
723
|
+
throw new Error(
|
|
724
|
+
"debugSession must expose recordFrame(sample). Use @plasius/gpu-debug createGpuDebugSession()."
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
const fixedTargetFrameTimeMs = readPositiveNumber(
|
|
728
|
+
"targetFrameTimeMs",
|
|
729
|
+
targetFrameTimeMs
|
|
730
|
+
);
|
|
731
|
+
const fixedTargetFrameRate = readPositiveNumber(
|
|
732
|
+
"targetFrameRate",
|
|
733
|
+
targetFrameRate
|
|
734
|
+
);
|
|
735
|
+
if (fixedTargetFrameTimeMs !== void 0 && fixedTargetFrameRate !== void 0) {
|
|
736
|
+
throw new Error(
|
|
737
|
+
"Provide either targetFrameTimeMs or targetFrameRate, not both."
|
|
738
|
+
);
|
|
739
|
+
}
|
|
740
|
+
if (getTargetFrameTimeMs !== void 0 && typeof getTargetFrameTimeMs !== "function") {
|
|
741
|
+
throw new Error("getTargetFrameTimeMs must be a function when provided.");
|
|
742
|
+
}
|
|
743
|
+
const resolvedOptions = {
|
|
744
|
+
targetFrameTimeMs: fixedTargetFrameTimeMs,
|
|
745
|
+
targetFrameRate: fixedTargetFrameRate,
|
|
746
|
+
getTargetFrameTimeMs
|
|
747
|
+
};
|
|
748
|
+
return {
|
|
749
|
+
onFrameStart(event) {
|
|
750
|
+
if (typeof onFrameStart === "function") {
|
|
751
|
+
onFrameStart({
|
|
752
|
+
...event,
|
|
753
|
+
owner: rendererDebugOwner
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
},
|
|
757
|
+
onFrameComplete(event) {
|
|
758
|
+
const resolvedTargetFrameTimeMs = resolveTargetFrameTimeMs(
|
|
759
|
+
resolvedOptions,
|
|
760
|
+
event
|
|
761
|
+
);
|
|
762
|
+
if (typeof event.frameTimeMs === "number" && Number.isFinite(event.frameTimeMs) && event.frameTimeMs > 0) {
|
|
763
|
+
debugSession.recordFrame({
|
|
764
|
+
frameId: event.frameId,
|
|
765
|
+
frameTimeMs: event.frameTimeMs,
|
|
766
|
+
targetFrameTimeMs: resolvedTargetFrameTimeMs
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
if (typeof onFrameComplete === "function") {
|
|
770
|
+
onFrameComplete({
|
|
771
|
+
...event,
|
|
772
|
+
owner: rendererDebugOwner,
|
|
773
|
+
targetFrameTimeMs: resolvedTargetFrameTimeMs
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
}
|
|
45
779
|
function readNavigator(navigatorOverride) {
|
|
46
780
|
const currentNavigator = navigatorOverride ?? globalThis.navigator;
|
|
47
781
|
if (!currentNavigator || typeof currentNavigator !== "object") {
|
|
@@ -122,8 +856,11 @@ async function createGpuRenderer(options = {}) {
|
|
|
122
856
|
clearColor = DEFAULT_CLEAR_COLOR,
|
|
123
857
|
requestAnimationFrame = globalThis.requestAnimationFrame?.bind(globalThis),
|
|
124
858
|
cancelAnimationFrame = globalThis.cancelAnimationFrame?.bind(globalThis),
|
|
859
|
+
frameIdFactory,
|
|
860
|
+
onFrameStart,
|
|
125
861
|
onBeforeEncode,
|
|
126
|
-
onAfterSubmit
|
|
862
|
+
onAfterSubmit,
|
|
863
|
+
onFrameComplete
|
|
127
864
|
} = options;
|
|
128
865
|
const gpu = readGpu(navigatorOverride);
|
|
129
866
|
const adapter = await gpu.requestAdapter({ powerPreference });
|
|
@@ -150,6 +887,28 @@ async function createGpuRenderer(options = {}) {
|
|
|
150
887
|
if (destroyed) {
|
|
151
888
|
throw new Error("Renderer was destroyed.");
|
|
152
889
|
}
|
|
890
|
+
const frameNumber = frame + 1;
|
|
891
|
+
const frameId = normalizeFrameId(
|
|
892
|
+
typeof frameIdFactory === "function" ? frameIdFactory({
|
|
893
|
+
frame: frameNumber,
|
|
894
|
+
timestamp,
|
|
895
|
+
canvas: targetCanvas,
|
|
896
|
+
xrActive
|
|
897
|
+
}) : `renderer.frame.${frameNumber}`
|
|
898
|
+
);
|
|
899
|
+
const frameTimeMs = lastTimestamp > 0 ? Math.max(0, timestamp - lastTimestamp) : void 0;
|
|
900
|
+
if (typeof onFrameStart === "function") {
|
|
901
|
+
onFrameStart({
|
|
902
|
+
frame: frameNumber,
|
|
903
|
+
frameId,
|
|
904
|
+
frameTimeMs,
|
|
905
|
+
timestamp,
|
|
906
|
+
device,
|
|
907
|
+
context,
|
|
908
|
+
canvas: targetCanvas,
|
|
909
|
+
xrActive
|
|
910
|
+
});
|
|
911
|
+
}
|
|
153
912
|
const texture = context.getCurrentTexture?.();
|
|
154
913
|
if (!texture || typeof texture.createView !== "function") {
|
|
155
914
|
throw new Error("WebGPU context returned an invalid current texture.");
|
|
@@ -162,12 +921,16 @@ async function createGpuRenderer(options = {}) {
|
|
|
162
921
|
if (typeof onBeforeEncode === "function") {
|
|
163
922
|
onBeforeEncode({
|
|
164
923
|
frame,
|
|
924
|
+
frameNumber,
|
|
925
|
+
frameId,
|
|
926
|
+
frameTimeMs,
|
|
165
927
|
timestamp,
|
|
166
928
|
device,
|
|
167
929
|
context,
|
|
168
930
|
encoder,
|
|
169
931
|
pass,
|
|
170
|
-
canvas: targetCanvas
|
|
932
|
+
canvas: targetCanvas,
|
|
933
|
+
xrActive
|
|
171
934
|
});
|
|
172
935
|
}
|
|
173
936
|
if (typeof pass.end === "function") {
|
|
@@ -175,19 +938,37 @@ async function createGpuRenderer(options = {}) {
|
|
|
175
938
|
}
|
|
176
939
|
const commandBuffer = encoder.finish();
|
|
177
940
|
device.queue.submit([commandBuffer]);
|
|
178
|
-
frame
|
|
941
|
+
frame = frameNumber;
|
|
179
942
|
lastTimestamp = timestamp;
|
|
180
943
|
if (typeof onAfterSubmit === "function") {
|
|
181
944
|
onAfterSubmit({
|
|
182
|
-
frame,
|
|
945
|
+
frame: frameNumber,
|
|
946
|
+
frameNumber,
|
|
947
|
+
frameId,
|
|
948
|
+
frameTimeMs,
|
|
949
|
+
timestamp,
|
|
950
|
+
device,
|
|
951
|
+
context,
|
|
952
|
+
canvas: targetCanvas,
|
|
953
|
+
xrActive
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
if (typeof onFrameComplete === "function") {
|
|
957
|
+
onFrameComplete({
|
|
958
|
+
frame: frameNumber,
|
|
959
|
+
frameId,
|
|
960
|
+
frameTimeMs,
|
|
183
961
|
timestamp,
|
|
184
962
|
device,
|
|
185
963
|
context,
|
|
186
|
-
canvas: targetCanvas
|
|
964
|
+
canvas: targetCanvas,
|
|
965
|
+
xrActive
|
|
187
966
|
});
|
|
188
967
|
}
|
|
189
968
|
return {
|
|
190
|
-
frame,
|
|
969
|
+
frame: frameNumber,
|
|
970
|
+
frameId,
|
|
971
|
+
frameTimeMs,
|
|
191
972
|
timestamp
|
|
192
973
|
};
|
|
193
974
|
};
|
|
@@ -328,7 +1109,20 @@ var defaultRendererClearColor = DEFAULT_CLEAR_COLOR;
|
|
|
328
1109
|
export {
|
|
329
1110
|
bindRendererToXrManager,
|
|
330
1111
|
createGpuRenderer,
|
|
1112
|
+
createRayTracingRenderPlan,
|
|
1113
|
+
createRendererDebugHooks,
|
|
331
1114
|
defaultRendererClearColor,
|
|
1115
|
+
defaultRendererWorkerProfile,
|
|
1116
|
+
getRendererWorkerManifest,
|
|
1117
|
+
getRendererWorkerProfile,
|
|
1118
|
+
rendererAccelerationStructureUpdateClasses,
|
|
1119
|
+
rendererDebugOwner,
|
|
1120
|
+
rendererRayTracingStageOrder,
|
|
1121
|
+
rendererRepresentationBands,
|
|
1122
|
+
rendererWorkerManifests,
|
|
1123
|
+
rendererWorkerProfileNames,
|
|
1124
|
+
rendererWorkerProfiles,
|
|
1125
|
+
rendererWorkerQueueClass,
|
|
332
1126
|
supportsWebGpu
|
|
333
1127
|
};
|
|
334
1128
|
//# sourceMappingURL=index.js.map
|