@plasius/gpu-renderer 0.1.4 → 0.1.7
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 +46 -0
- package/README.md +55 -0
- package/dist/index.cjs +621 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +612 -6
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/src/index.d.ts +143 -1
- package/src/index.js +644 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,457 @@
|
|
|
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
|
+
function buildRendererWorkerBudgetLevels(jobType, queueClass, levels) {
|
|
8
|
+
return Object.freeze(
|
|
9
|
+
levels.map(
|
|
10
|
+
(level) => Object.freeze({
|
|
11
|
+
id: level.id,
|
|
12
|
+
estimatedCostMs: level.estimatedCostMs,
|
|
13
|
+
config: Object.freeze({
|
|
14
|
+
maxDispatchesPerFrame: level.config.maxDispatchesPerFrame,
|
|
15
|
+
maxJobsPerDispatch: level.config.maxJobsPerDispatch,
|
|
16
|
+
cadenceDivisor: level.config.cadenceDivisor,
|
|
17
|
+
workgroupScale: level.config.workgroupScale,
|
|
18
|
+
maxQueueDepth: level.config.maxQueueDepth,
|
|
19
|
+
metadata: Object.freeze({
|
|
20
|
+
owner: rendererDebugOwner,
|
|
21
|
+
queueClass,
|
|
22
|
+
jobType,
|
|
23
|
+
quality: level.id
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
var rendererWorkerProfileSpecs = {
|
|
31
|
+
realtime: {
|
|
32
|
+
description: "Frame-stage DAG for flat rendering with visibility, main encode, post-processing, and submit.",
|
|
33
|
+
suggestedAllocationIds: [
|
|
34
|
+
"renderer.surface.current",
|
|
35
|
+
"renderer.visibility.worklist",
|
|
36
|
+
"renderer.post-process.history"
|
|
37
|
+
],
|
|
38
|
+
jobs: {
|
|
39
|
+
acquire: {
|
|
40
|
+
priority: 5,
|
|
41
|
+
dependencies: [],
|
|
42
|
+
domain: "resolution",
|
|
43
|
+
importance: "critical",
|
|
44
|
+
levels: [
|
|
45
|
+
{
|
|
46
|
+
id: "fixed",
|
|
47
|
+
estimatedCostMs: 0.2,
|
|
48
|
+
config: {
|
|
49
|
+
maxDispatchesPerFrame: 1,
|
|
50
|
+
maxJobsPerDispatch: 1,
|
|
51
|
+
cadenceDivisor: 1,
|
|
52
|
+
workgroupScale: 1,
|
|
53
|
+
maxQueueDepth: 1
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
suggestedAllocationIds: ["renderer.surface.current"]
|
|
58
|
+
},
|
|
59
|
+
visibility: {
|
|
60
|
+
priority: 4,
|
|
61
|
+
dependencies: [],
|
|
62
|
+
domain: "geometry",
|
|
63
|
+
importance: "high",
|
|
64
|
+
levels: [
|
|
65
|
+
{
|
|
66
|
+
id: "low",
|
|
67
|
+
estimatedCostMs: 0.4,
|
|
68
|
+
config: {
|
|
69
|
+
maxDispatchesPerFrame: 1,
|
|
70
|
+
maxJobsPerDispatch: 128,
|
|
71
|
+
cadenceDivisor: 2,
|
|
72
|
+
workgroupScale: 0.5,
|
|
73
|
+
maxQueueDepth: 256
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "medium",
|
|
78
|
+
estimatedCostMs: 0.8,
|
|
79
|
+
config: {
|
|
80
|
+
maxDispatchesPerFrame: 1,
|
|
81
|
+
maxJobsPerDispatch: 256,
|
|
82
|
+
cadenceDivisor: 1,
|
|
83
|
+
workgroupScale: 0.75,
|
|
84
|
+
maxQueueDepth: 384
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: "high",
|
|
89
|
+
estimatedCostMs: 1.2,
|
|
90
|
+
config: {
|
|
91
|
+
maxDispatchesPerFrame: 2,
|
|
92
|
+
maxJobsPerDispatch: 512,
|
|
93
|
+
cadenceDivisor: 1,
|
|
94
|
+
workgroupScale: 1,
|
|
95
|
+
maxQueueDepth: 512
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
suggestedAllocationIds: ["renderer.visibility.worklist"]
|
|
100
|
+
},
|
|
101
|
+
mainEncode: {
|
|
102
|
+
priority: 4,
|
|
103
|
+
dependencies: ["acquire", "visibility"],
|
|
104
|
+
domain: "geometry",
|
|
105
|
+
importance: "critical",
|
|
106
|
+
levels: [
|
|
107
|
+
{
|
|
108
|
+
id: "low",
|
|
109
|
+
estimatedCostMs: 1.2,
|
|
110
|
+
config: {
|
|
111
|
+
maxDispatchesPerFrame: 1,
|
|
112
|
+
maxJobsPerDispatch: 128,
|
|
113
|
+
cadenceDivisor: 1,
|
|
114
|
+
workgroupScale: 0.6,
|
|
115
|
+
maxQueueDepth: 192
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
id: "medium",
|
|
120
|
+
estimatedCostMs: 2.1,
|
|
121
|
+
config: {
|
|
122
|
+
maxDispatchesPerFrame: 1,
|
|
123
|
+
maxJobsPerDispatch: 256,
|
|
124
|
+
cadenceDivisor: 1,
|
|
125
|
+
workgroupScale: 0.8,
|
|
126
|
+
maxQueueDepth: 256
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
id: "high",
|
|
131
|
+
estimatedCostMs: 3,
|
|
132
|
+
config: {
|
|
133
|
+
maxDispatchesPerFrame: 1,
|
|
134
|
+
maxJobsPerDispatch: 384,
|
|
135
|
+
cadenceDivisor: 1,
|
|
136
|
+
workgroupScale: 1,
|
|
137
|
+
maxQueueDepth: 384
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
suggestedAllocationIds: ["renderer.surface.current"]
|
|
142
|
+
},
|
|
143
|
+
postProcess: {
|
|
144
|
+
priority: 3,
|
|
145
|
+
dependencies: ["mainEncode"],
|
|
146
|
+
domain: "post-processing",
|
|
147
|
+
importance: "high",
|
|
148
|
+
levels: [
|
|
149
|
+
{
|
|
150
|
+
id: "low",
|
|
151
|
+
estimatedCostMs: 0.5,
|
|
152
|
+
config: {
|
|
153
|
+
maxDispatchesPerFrame: 1,
|
|
154
|
+
maxJobsPerDispatch: 64,
|
|
155
|
+
cadenceDivisor: 2,
|
|
156
|
+
workgroupScale: 0.5,
|
|
157
|
+
maxQueueDepth: 96
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "medium",
|
|
162
|
+
estimatedCostMs: 0.9,
|
|
163
|
+
config: {
|
|
164
|
+
maxDispatchesPerFrame: 1,
|
|
165
|
+
maxJobsPerDispatch: 128,
|
|
166
|
+
cadenceDivisor: 1,
|
|
167
|
+
workgroupScale: 0.75,
|
|
168
|
+
maxQueueDepth: 128
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
id: "high",
|
|
173
|
+
estimatedCostMs: 1.4,
|
|
174
|
+
config: {
|
|
175
|
+
maxDispatchesPerFrame: 2,
|
|
176
|
+
maxJobsPerDispatch: 192,
|
|
177
|
+
cadenceDivisor: 1,
|
|
178
|
+
workgroupScale: 1,
|
|
179
|
+
maxQueueDepth: 192
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
],
|
|
183
|
+
suggestedAllocationIds: ["renderer.post-process.history"]
|
|
184
|
+
},
|
|
185
|
+
submit: {
|
|
186
|
+
priority: 2,
|
|
187
|
+
dependencies: ["postProcess"],
|
|
188
|
+
domain: "resolution",
|
|
189
|
+
importance: "critical",
|
|
190
|
+
levels: [
|
|
191
|
+
{
|
|
192
|
+
id: "fixed",
|
|
193
|
+
estimatedCostMs: 0.2,
|
|
194
|
+
config: {
|
|
195
|
+
maxDispatchesPerFrame: 1,
|
|
196
|
+
maxJobsPerDispatch: 1,
|
|
197
|
+
cadenceDivisor: 1,
|
|
198
|
+
workgroupScale: 1,
|
|
199
|
+
maxQueueDepth: 1
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
],
|
|
203
|
+
suggestedAllocationIds: ["renderer.surface.current"]
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
xr: {
|
|
208
|
+
description: "Frame-stage DAG for XR rendering with late-latch coordination before main encode and submit.",
|
|
209
|
+
suggestedAllocationIds: [
|
|
210
|
+
"renderer.xr.surface.current",
|
|
211
|
+
"renderer.xr.visibility.worklist"
|
|
212
|
+
],
|
|
213
|
+
jobs: {
|
|
214
|
+
acquire: {
|
|
215
|
+
priority: 5,
|
|
216
|
+
dependencies: [],
|
|
217
|
+
domain: "xr",
|
|
218
|
+
importance: "critical",
|
|
219
|
+
levels: [
|
|
220
|
+
{
|
|
221
|
+
id: "fixed",
|
|
222
|
+
estimatedCostMs: 0.2,
|
|
223
|
+
config: {
|
|
224
|
+
maxDispatchesPerFrame: 1,
|
|
225
|
+
maxJobsPerDispatch: 1,
|
|
226
|
+
cadenceDivisor: 1,
|
|
227
|
+
workgroupScale: 1,
|
|
228
|
+
maxQueueDepth: 1
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
],
|
|
232
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
233
|
+
},
|
|
234
|
+
visibility: {
|
|
235
|
+
priority: 4,
|
|
236
|
+
dependencies: [],
|
|
237
|
+
domain: "geometry",
|
|
238
|
+
importance: "high",
|
|
239
|
+
levels: [
|
|
240
|
+
{
|
|
241
|
+
id: "low",
|
|
242
|
+
estimatedCostMs: 0.5,
|
|
243
|
+
config: {
|
|
244
|
+
maxDispatchesPerFrame: 1,
|
|
245
|
+
maxJobsPerDispatch: 96,
|
|
246
|
+
cadenceDivisor: 2,
|
|
247
|
+
workgroupScale: 0.5,
|
|
248
|
+
maxQueueDepth: 192
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
id: "medium",
|
|
253
|
+
estimatedCostMs: 0.9,
|
|
254
|
+
config: {
|
|
255
|
+
maxDispatchesPerFrame: 1,
|
|
256
|
+
maxJobsPerDispatch: 192,
|
|
257
|
+
cadenceDivisor: 1,
|
|
258
|
+
workgroupScale: 0.75,
|
|
259
|
+
maxQueueDepth: 256
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: "high",
|
|
264
|
+
estimatedCostMs: 1.3,
|
|
265
|
+
config: {
|
|
266
|
+
maxDispatchesPerFrame: 2,
|
|
267
|
+
maxJobsPerDispatch: 320,
|
|
268
|
+
cadenceDivisor: 1,
|
|
269
|
+
workgroupScale: 1,
|
|
270
|
+
maxQueueDepth: 320
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
],
|
|
274
|
+
suggestedAllocationIds: ["renderer.xr.visibility.worklist"]
|
|
275
|
+
},
|
|
276
|
+
lateLatch: {
|
|
277
|
+
priority: 5,
|
|
278
|
+
dependencies: ["acquire"],
|
|
279
|
+
domain: "xr",
|
|
280
|
+
importance: "critical",
|
|
281
|
+
levels: [
|
|
282
|
+
{
|
|
283
|
+
id: "fixed",
|
|
284
|
+
estimatedCostMs: 0.15,
|
|
285
|
+
config: {
|
|
286
|
+
maxDispatchesPerFrame: 1,
|
|
287
|
+
maxJobsPerDispatch: 1,
|
|
288
|
+
cadenceDivisor: 1,
|
|
289
|
+
workgroupScale: 1,
|
|
290
|
+
maxQueueDepth: 1
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
],
|
|
294
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
295
|
+
},
|
|
296
|
+
mainEncode: {
|
|
297
|
+
priority: 4,
|
|
298
|
+
dependencies: ["visibility", "lateLatch"],
|
|
299
|
+
domain: "xr",
|
|
300
|
+
importance: "critical",
|
|
301
|
+
levels: [
|
|
302
|
+
{
|
|
303
|
+
id: "low",
|
|
304
|
+
estimatedCostMs: 1.1,
|
|
305
|
+
config: {
|
|
306
|
+
maxDispatchesPerFrame: 1,
|
|
307
|
+
maxJobsPerDispatch: 96,
|
|
308
|
+
cadenceDivisor: 1,
|
|
309
|
+
workgroupScale: 0.6,
|
|
310
|
+
maxQueueDepth: 128
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: "medium",
|
|
315
|
+
estimatedCostMs: 1.8,
|
|
316
|
+
config: {
|
|
317
|
+
maxDispatchesPerFrame: 1,
|
|
318
|
+
maxJobsPerDispatch: 192,
|
|
319
|
+
cadenceDivisor: 1,
|
|
320
|
+
workgroupScale: 0.8,
|
|
321
|
+
maxQueueDepth: 192
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
id: "high",
|
|
326
|
+
estimatedCostMs: 2.6,
|
|
327
|
+
config: {
|
|
328
|
+
maxDispatchesPerFrame: 1,
|
|
329
|
+
maxJobsPerDispatch: 256,
|
|
330
|
+
cadenceDivisor: 1,
|
|
331
|
+
workgroupScale: 1,
|
|
332
|
+
maxQueueDepth: 256
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
],
|
|
336
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
337
|
+
},
|
|
338
|
+
submit: {
|
|
339
|
+
priority: 2,
|
|
340
|
+
dependencies: ["mainEncode"],
|
|
341
|
+
domain: "xr",
|
|
342
|
+
importance: "critical",
|
|
343
|
+
levels: [
|
|
344
|
+
{
|
|
345
|
+
id: "fixed",
|
|
346
|
+
estimatedCostMs: 0.2,
|
|
347
|
+
config: {
|
|
348
|
+
maxDispatchesPerFrame: 1,
|
|
349
|
+
maxJobsPerDispatch: 1,
|
|
350
|
+
cadenceDivisor: 1,
|
|
351
|
+
workgroupScale: 1,
|
|
352
|
+
maxQueueDepth: 1
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
],
|
|
356
|
+
suggestedAllocationIds: ["renderer.xr.surface.current"]
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
function buildRendererWorkerProfile(name, spec) {
|
|
362
|
+
return Object.freeze({
|
|
363
|
+
name,
|
|
364
|
+
description: spec.description,
|
|
365
|
+
jobs: Object.freeze(Object.keys(spec.jobs))
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
function buildRendererWorkerManifestJob(profileName, jobName, spec) {
|
|
369
|
+
const label = `renderer.${profileName}.${jobName}`;
|
|
370
|
+
return Object.freeze({
|
|
371
|
+
key: jobName,
|
|
372
|
+
label,
|
|
373
|
+
worker: Object.freeze({
|
|
374
|
+
jobType: label,
|
|
375
|
+
queueClass: rendererWorkerQueueClass,
|
|
376
|
+
priority: spec.priority,
|
|
377
|
+
dependencies: Object.freeze(
|
|
378
|
+
spec.dependencies.map((dependency) => `renderer.${profileName}.${dependency}`)
|
|
379
|
+
),
|
|
380
|
+
schedulerMode: "dag"
|
|
381
|
+
}),
|
|
382
|
+
performance: Object.freeze({
|
|
383
|
+
id: label,
|
|
384
|
+
jobType: label,
|
|
385
|
+
queueClass: rendererWorkerQueueClass,
|
|
386
|
+
domain: spec.domain,
|
|
387
|
+
authority: "visual",
|
|
388
|
+
importance: spec.importance,
|
|
389
|
+
levels: buildRendererWorkerBudgetLevels(
|
|
390
|
+
label,
|
|
391
|
+
rendererWorkerQueueClass,
|
|
392
|
+
spec.levels
|
|
393
|
+
)
|
|
394
|
+
}),
|
|
395
|
+
debug: Object.freeze({
|
|
396
|
+
owner: rendererDebugOwner,
|
|
397
|
+
queueClass: rendererWorkerQueueClass,
|
|
398
|
+
jobType: label,
|
|
399
|
+
tags: Object.freeze(["renderer", profileName, jobName, spec.domain]),
|
|
400
|
+
suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds])
|
|
401
|
+
})
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
function buildRendererWorkerManifest(name, spec) {
|
|
405
|
+
return Object.freeze({
|
|
406
|
+
schemaVersion: 1,
|
|
407
|
+
owner: rendererDebugOwner,
|
|
408
|
+
profile: name,
|
|
409
|
+
description: spec.description,
|
|
410
|
+
queueClass: rendererWorkerQueueClass,
|
|
411
|
+
schedulerMode: "dag",
|
|
412
|
+
suggestedAllocationIds: Object.freeze([...spec.suggestedAllocationIds]),
|
|
413
|
+
jobs: Object.freeze(
|
|
414
|
+
Object.entries(spec.jobs).map(
|
|
415
|
+
([jobName, jobSpec]) => buildRendererWorkerManifestJob(name, jobName, jobSpec)
|
|
416
|
+
)
|
|
417
|
+
)
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
var rendererWorkerProfiles = Object.freeze(
|
|
421
|
+
Object.fromEntries(
|
|
422
|
+
Object.entries(rendererWorkerProfileSpecs).map(([name, spec]) => [
|
|
423
|
+
name,
|
|
424
|
+
buildRendererWorkerProfile(name, spec)
|
|
425
|
+
])
|
|
426
|
+
)
|
|
427
|
+
);
|
|
428
|
+
var rendererWorkerProfileNames = Object.freeze(
|
|
429
|
+
Object.keys(rendererWorkerProfiles)
|
|
430
|
+
);
|
|
431
|
+
var rendererWorkerManifests = Object.freeze(
|
|
432
|
+
Object.fromEntries(
|
|
433
|
+
Object.entries(rendererWorkerProfileSpecs).map(([name, spec]) => [
|
|
434
|
+
name,
|
|
435
|
+
buildRendererWorkerManifest(name, spec)
|
|
436
|
+
])
|
|
437
|
+
)
|
|
438
|
+
);
|
|
439
|
+
function getRendererWorkerProfile(name = defaultRendererWorkerProfile) {
|
|
440
|
+
const profile = rendererWorkerProfiles[name];
|
|
441
|
+
if (!profile) {
|
|
442
|
+
const available = rendererWorkerProfileNames.join(", ");
|
|
443
|
+
throw new Error(`Unknown renderer worker profile "${name}". Available: ${available}.`);
|
|
444
|
+
}
|
|
445
|
+
return profile;
|
|
446
|
+
}
|
|
447
|
+
function getRendererWorkerManifest(name = defaultRendererWorkerProfile) {
|
|
448
|
+
const manifest = rendererWorkerManifests[name];
|
|
449
|
+
if (!manifest) {
|
|
450
|
+
const available = rendererWorkerProfileNames.join(", ");
|
|
451
|
+
throw new Error(`Unknown renderer worker profile "${name}". Available: ${available}.`);
|
|
452
|
+
}
|
|
453
|
+
return manifest;
|
|
454
|
+
}
|
|
4
455
|
function clamp01(value) {
|
|
5
456
|
return Math.min(1, Math.max(0, value));
|
|
6
457
|
}
|
|
@@ -36,12 +487,111 @@ function normalizeColor(value) {
|
|
|
36
487
|
}
|
|
37
488
|
return [...DEFAULT_CLEAR_COLOR];
|
|
38
489
|
}
|
|
490
|
+
function readPositiveNumber(name, value) {
|
|
491
|
+
if (value === void 0) {
|
|
492
|
+
return void 0;
|
|
493
|
+
}
|
|
494
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
495
|
+
throw new Error(`${name} must be a finite number greater than zero.`);
|
|
496
|
+
}
|
|
497
|
+
return value;
|
|
498
|
+
}
|
|
39
499
|
function now() {
|
|
40
500
|
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
41
501
|
return performance.now();
|
|
42
502
|
}
|
|
43
503
|
return Date.now();
|
|
44
504
|
}
|
|
505
|
+
function normalizeFrameId(value) {
|
|
506
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
507
|
+
throw new Error("frameIdFactory must return a non-empty string.");
|
|
508
|
+
}
|
|
509
|
+
return value.trim();
|
|
510
|
+
}
|
|
511
|
+
function resolveTargetFrameTimeMs(options, event) {
|
|
512
|
+
const {
|
|
513
|
+
targetFrameTimeMs: fixedTargetFrameTimeMs,
|
|
514
|
+
targetFrameRate,
|
|
515
|
+
getTargetFrameTimeMs
|
|
516
|
+
} = options;
|
|
517
|
+
if (typeof getTargetFrameTimeMs === "function") {
|
|
518
|
+
const resolved = getTargetFrameTimeMs(event);
|
|
519
|
+
return readPositiveNumber("getTargetFrameTimeMs()", resolved);
|
|
520
|
+
}
|
|
521
|
+
if (fixedTargetFrameTimeMs !== void 0) {
|
|
522
|
+
return fixedTargetFrameTimeMs;
|
|
523
|
+
}
|
|
524
|
+
if (targetFrameRate !== void 0) {
|
|
525
|
+
return 1e3 / targetFrameRate;
|
|
526
|
+
}
|
|
527
|
+
return void 0;
|
|
528
|
+
}
|
|
529
|
+
function createRendererDebugHooks(options = {}) {
|
|
530
|
+
const {
|
|
531
|
+
debugSession,
|
|
532
|
+
targetFrameTimeMs,
|
|
533
|
+
targetFrameRate,
|
|
534
|
+
getTargetFrameTimeMs,
|
|
535
|
+
onFrameStart,
|
|
536
|
+
onFrameComplete
|
|
537
|
+
} = options;
|
|
538
|
+
if (!debugSession || typeof debugSession.recordFrame !== "function") {
|
|
539
|
+
throw new Error(
|
|
540
|
+
"debugSession must expose recordFrame(sample). Use @plasius/gpu-debug createGpuDebugSession()."
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
const fixedTargetFrameTimeMs = readPositiveNumber(
|
|
544
|
+
"targetFrameTimeMs",
|
|
545
|
+
targetFrameTimeMs
|
|
546
|
+
);
|
|
547
|
+
const fixedTargetFrameRate = readPositiveNumber(
|
|
548
|
+
"targetFrameRate",
|
|
549
|
+
targetFrameRate
|
|
550
|
+
);
|
|
551
|
+
if (fixedTargetFrameTimeMs !== void 0 && fixedTargetFrameRate !== void 0) {
|
|
552
|
+
throw new Error(
|
|
553
|
+
"Provide either targetFrameTimeMs or targetFrameRate, not both."
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
if (getTargetFrameTimeMs !== void 0 && typeof getTargetFrameTimeMs !== "function") {
|
|
557
|
+
throw new Error("getTargetFrameTimeMs must be a function when provided.");
|
|
558
|
+
}
|
|
559
|
+
const resolvedOptions = {
|
|
560
|
+
targetFrameTimeMs: fixedTargetFrameTimeMs,
|
|
561
|
+
targetFrameRate: fixedTargetFrameRate,
|
|
562
|
+
getTargetFrameTimeMs
|
|
563
|
+
};
|
|
564
|
+
return {
|
|
565
|
+
onFrameStart(event) {
|
|
566
|
+
if (typeof onFrameStart === "function") {
|
|
567
|
+
onFrameStart({
|
|
568
|
+
...event,
|
|
569
|
+
owner: rendererDebugOwner
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
onFrameComplete(event) {
|
|
574
|
+
const resolvedTargetFrameTimeMs = resolveTargetFrameTimeMs(
|
|
575
|
+
resolvedOptions,
|
|
576
|
+
event
|
|
577
|
+
);
|
|
578
|
+
if (typeof event.frameTimeMs === "number" && Number.isFinite(event.frameTimeMs) && event.frameTimeMs > 0) {
|
|
579
|
+
debugSession.recordFrame({
|
|
580
|
+
frameId: event.frameId,
|
|
581
|
+
frameTimeMs: event.frameTimeMs,
|
|
582
|
+
targetFrameTimeMs: resolvedTargetFrameTimeMs
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
if (typeof onFrameComplete === "function") {
|
|
586
|
+
onFrameComplete({
|
|
587
|
+
...event,
|
|
588
|
+
owner: rendererDebugOwner,
|
|
589
|
+
targetFrameTimeMs: resolvedTargetFrameTimeMs
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
}
|
|
45
595
|
function readNavigator(navigatorOverride) {
|
|
46
596
|
const currentNavigator = navigatorOverride ?? globalThis.navigator;
|
|
47
597
|
if (!currentNavigator || typeof currentNavigator !== "object") {
|
|
@@ -122,8 +672,11 @@ async function createGpuRenderer(options = {}) {
|
|
|
122
672
|
clearColor = DEFAULT_CLEAR_COLOR,
|
|
123
673
|
requestAnimationFrame = globalThis.requestAnimationFrame?.bind(globalThis),
|
|
124
674
|
cancelAnimationFrame = globalThis.cancelAnimationFrame?.bind(globalThis),
|
|
675
|
+
frameIdFactory,
|
|
676
|
+
onFrameStart,
|
|
125
677
|
onBeforeEncode,
|
|
126
|
-
onAfterSubmit
|
|
678
|
+
onAfterSubmit,
|
|
679
|
+
onFrameComplete
|
|
127
680
|
} = options;
|
|
128
681
|
const gpu = readGpu(navigatorOverride);
|
|
129
682
|
const adapter = await gpu.requestAdapter({ powerPreference });
|
|
@@ -150,6 +703,28 @@ async function createGpuRenderer(options = {}) {
|
|
|
150
703
|
if (destroyed) {
|
|
151
704
|
throw new Error("Renderer was destroyed.");
|
|
152
705
|
}
|
|
706
|
+
const frameNumber = frame + 1;
|
|
707
|
+
const frameId = normalizeFrameId(
|
|
708
|
+
typeof frameIdFactory === "function" ? frameIdFactory({
|
|
709
|
+
frame: frameNumber,
|
|
710
|
+
timestamp,
|
|
711
|
+
canvas: targetCanvas,
|
|
712
|
+
xrActive
|
|
713
|
+
}) : `renderer.frame.${frameNumber}`
|
|
714
|
+
);
|
|
715
|
+
const frameTimeMs = lastTimestamp > 0 ? Math.max(0, timestamp - lastTimestamp) : void 0;
|
|
716
|
+
if (typeof onFrameStart === "function") {
|
|
717
|
+
onFrameStart({
|
|
718
|
+
frame: frameNumber,
|
|
719
|
+
frameId,
|
|
720
|
+
frameTimeMs,
|
|
721
|
+
timestamp,
|
|
722
|
+
device,
|
|
723
|
+
context,
|
|
724
|
+
canvas: targetCanvas,
|
|
725
|
+
xrActive
|
|
726
|
+
});
|
|
727
|
+
}
|
|
153
728
|
const texture = context.getCurrentTexture?.();
|
|
154
729
|
if (!texture || typeof texture.createView !== "function") {
|
|
155
730
|
throw new Error("WebGPU context returned an invalid current texture.");
|
|
@@ -162,12 +737,16 @@ async function createGpuRenderer(options = {}) {
|
|
|
162
737
|
if (typeof onBeforeEncode === "function") {
|
|
163
738
|
onBeforeEncode({
|
|
164
739
|
frame,
|
|
740
|
+
frameNumber,
|
|
741
|
+
frameId,
|
|
742
|
+
frameTimeMs,
|
|
165
743
|
timestamp,
|
|
166
744
|
device,
|
|
167
745
|
context,
|
|
168
746
|
encoder,
|
|
169
747
|
pass,
|
|
170
|
-
canvas: targetCanvas
|
|
748
|
+
canvas: targetCanvas,
|
|
749
|
+
xrActive
|
|
171
750
|
});
|
|
172
751
|
}
|
|
173
752
|
if (typeof pass.end === "function") {
|
|
@@ -175,19 +754,37 @@ async function createGpuRenderer(options = {}) {
|
|
|
175
754
|
}
|
|
176
755
|
const commandBuffer = encoder.finish();
|
|
177
756
|
device.queue.submit([commandBuffer]);
|
|
178
|
-
frame
|
|
757
|
+
frame = frameNumber;
|
|
179
758
|
lastTimestamp = timestamp;
|
|
180
759
|
if (typeof onAfterSubmit === "function") {
|
|
181
760
|
onAfterSubmit({
|
|
182
|
-
frame,
|
|
761
|
+
frame: frameNumber,
|
|
762
|
+
frameNumber,
|
|
763
|
+
frameId,
|
|
764
|
+
frameTimeMs,
|
|
183
765
|
timestamp,
|
|
184
766
|
device,
|
|
185
767
|
context,
|
|
186
|
-
canvas: targetCanvas
|
|
768
|
+
canvas: targetCanvas,
|
|
769
|
+
xrActive
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
if (typeof onFrameComplete === "function") {
|
|
773
|
+
onFrameComplete({
|
|
774
|
+
frame: frameNumber,
|
|
775
|
+
frameId,
|
|
776
|
+
frameTimeMs,
|
|
777
|
+
timestamp,
|
|
778
|
+
device,
|
|
779
|
+
context,
|
|
780
|
+
canvas: targetCanvas,
|
|
781
|
+
xrActive
|
|
187
782
|
});
|
|
188
783
|
}
|
|
189
784
|
return {
|
|
190
|
-
frame,
|
|
785
|
+
frame: frameNumber,
|
|
786
|
+
frameId,
|
|
787
|
+
frameTimeMs,
|
|
191
788
|
timestamp
|
|
192
789
|
};
|
|
193
790
|
};
|
|
@@ -328,7 +925,16 @@ var defaultRendererClearColor = DEFAULT_CLEAR_COLOR;
|
|
|
328
925
|
export {
|
|
329
926
|
bindRendererToXrManager,
|
|
330
927
|
createGpuRenderer,
|
|
928
|
+
createRendererDebugHooks,
|
|
331
929
|
defaultRendererClearColor,
|
|
930
|
+
defaultRendererWorkerProfile,
|
|
931
|
+
getRendererWorkerManifest,
|
|
932
|
+
getRendererWorkerProfile,
|
|
933
|
+
rendererDebugOwner,
|
|
934
|
+
rendererWorkerManifests,
|
|
935
|
+
rendererWorkerProfileNames,
|
|
936
|
+
rendererWorkerProfiles,
|
|
937
|
+
rendererWorkerQueueClass,
|
|
332
938
|
supportsWebGpu
|
|
333
939
|
};
|
|
334
940
|
//# sourceMappingURL=index.js.map
|