@gnsx/three 0.185.9 → 0.185.11
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/build/three.cjs +980 -2
- package/build/three.core.js +980 -2
- package/build/three.core.min.js +1 -1
- package/build/three.webgpu.js +215 -68
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +215 -68
- package/build/three.webgpu.nodes.min.js +1 -1
- package/package.json +1 -1
- package/src/profiler/ProfilerService.js +982 -2
- package/src/renderers/common/Backend.js +60 -0
- package/src/renderers/common/RenderContext.js +10 -0
- package/src/renderers/common/Renderer.js +20 -1
- package/src/renderers/common/TimestampQueryPool.js +23 -0
- package/src/renderers/webgl-fallback/WebGLBackend.js +14 -3
- package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +8 -4
- package/src/renderers/webgpu/WebGPUBackend.js +37 -8
- package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +44 -5
|
@@ -67,6 +67,15 @@ class Backend {
|
|
|
67
67
|
[ TimestampQuery.COMPUTE ]: null
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
// WITH_GENESYS
|
|
71
|
+
/**
|
|
72
|
+
* Listeners notified after a timestamp query is successfully allocated.
|
|
73
|
+
*
|
|
74
|
+
* @type {Set<function(string, string, ?string): void>}
|
|
75
|
+
*/
|
|
76
|
+
this.timestampQueryListeners = new Set();
|
|
77
|
+
// !WITH_GENESYS
|
|
78
|
+
|
|
70
79
|
/**
|
|
71
80
|
* Whether to track timestamps with a Timestamp Query API or not.
|
|
72
81
|
*
|
|
@@ -505,6 +514,41 @@ class Backend {
|
|
|
505
514
|
|
|
506
515
|
}
|
|
507
516
|
|
|
517
|
+
// WITH_GENESYS
|
|
518
|
+
/**
|
|
519
|
+
* @param {function(string, string, ?string): void} listener
|
|
520
|
+
*/
|
|
521
|
+
addTimestampQueryListener( listener ) {
|
|
522
|
+
|
|
523
|
+
this.timestampQueryListeners.add( listener );
|
|
524
|
+
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* @param {function(string, string, ?string): void} listener
|
|
529
|
+
*/
|
|
530
|
+
removeTimestampQueryListener( listener ) {
|
|
531
|
+
|
|
532
|
+
this.timestampQueryListeners.delete( listener );
|
|
533
|
+
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* @param {string} type
|
|
538
|
+
* @param {string} uid
|
|
539
|
+
* @param {?string} [label=null]
|
|
540
|
+
*/
|
|
541
|
+
notifyTimestampQuery( type, uid, label = null ) {
|
|
542
|
+
|
|
543
|
+
for ( const listener of this.timestampQueryListeners ) {
|
|
544
|
+
|
|
545
|
+
listener( type, uid, label );
|
|
546
|
+
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
}
|
|
550
|
+
// !WITH_GENESYS
|
|
551
|
+
|
|
508
552
|
/**
|
|
509
553
|
* Returns all timestamp frames for the given type.
|
|
510
554
|
*
|
|
@@ -548,6 +592,22 @@ class Backend {
|
|
|
548
592
|
|
|
549
593
|
}
|
|
550
594
|
|
|
595
|
+
// WITH_GENESYS
|
|
596
|
+
/**
|
|
597
|
+
* Returns the raw GPU timestamp range for the given uid when supported.
|
|
598
|
+
*
|
|
599
|
+
* @param {string} uid - The unique identifier.
|
|
600
|
+
* @return {?{start: bigint, end: bigint}} The raw timestamp range.
|
|
601
|
+
*/
|
|
602
|
+
getTimestampRange( uid ) {
|
|
603
|
+
|
|
604
|
+
const queryPool = this._getQueryPool( uid );
|
|
605
|
+
|
|
606
|
+
return queryPool.getTimestampRange( uid );
|
|
607
|
+
|
|
608
|
+
}
|
|
609
|
+
// !WITH_GENESYS
|
|
610
|
+
|
|
551
611
|
/**
|
|
552
612
|
* Whether the backend supports query timestamps or not.
|
|
553
613
|
*
|
|
@@ -230,6 +230,16 @@ class RenderContext {
|
|
|
230
230
|
*/
|
|
231
231
|
this.camera = null;
|
|
232
232
|
|
|
233
|
+
// WITH_GENESYS
|
|
234
|
+
/**
|
|
235
|
+
* An optional label used to identify this render pass in GPU profiler output.
|
|
236
|
+
*
|
|
237
|
+
* @type {?string}
|
|
238
|
+
* @default null
|
|
239
|
+
*/
|
|
240
|
+
this.gpuProfilerLabel = null;
|
|
241
|
+
// !WITH_GENESYS
|
|
242
|
+
|
|
233
243
|
/**
|
|
234
244
|
* This flag can be used for type testing.
|
|
235
245
|
*
|
|
@@ -1617,6 +1617,25 @@ class Renderer {
|
|
|
1617
1617
|
|
|
1618
1618
|
const renderContext = this._renderContexts.get( renderTarget, this._mrt, this._callDepth );
|
|
1619
1619
|
|
|
1620
|
+
// WITH_GENESYS
|
|
1621
|
+
// Prefer an explicit scene/pass name; otherwise fall back to the render
|
|
1622
|
+
// target texture name so depth/shadow/RTT work is not an invisible hole.
|
|
1623
|
+
let gpuProfilerLabel = scene.name !== '' ? scene.name : null;
|
|
1624
|
+
if ( gpuProfilerLabel === null && renderTarget !== null ) {
|
|
1625
|
+
|
|
1626
|
+
const textureName = renderTarget.texture?.name;
|
|
1627
|
+
if ( textureName !== undefined && textureName !== null && textureName !== '' ) {
|
|
1628
|
+
|
|
1629
|
+
gpuProfilerLabel = textureName;
|
|
1630
|
+
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
renderContext.gpuProfilerLabel = gpuProfilerLabel;
|
|
1636
|
+
// !WITH_GENESYS
|
|
1637
|
+
// renderContext.gpuProfilerLabel = scene.name !== '' ? scene.name : null;
|
|
1638
|
+
|
|
1620
1639
|
this._currentRenderContext = renderContext;
|
|
1621
1640
|
this._currentRenderObjectFunction = this._renderObjectFunction || this.renderObject;
|
|
1622
1641
|
this._handleObjectFunction = this._renderObjectDirect;
|
|
@@ -2616,7 +2635,7 @@ class Renderer {
|
|
|
2616
2635
|
|
|
2617
2636
|
// WITH_GENESYS
|
|
2618
2637
|
// Drop the strong reference to the active `RenderContext` so module-level
|
|
2619
|
-
// `WeakMap<RenderContext,
|
|
2638
|
+
// `WeakMap<RenderContext, ...>` caches can release entries once
|
|
2620
2639
|
// `_renderContexts.dispose()` has cleared its dictionary.
|
|
2621
2640
|
this._currentRenderContext = null;
|
|
2622
2641
|
// !WITH_GENESYS
|
|
@@ -85,6 +85,15 @@ class TimestampQueryPool {
|
|
|
85
85
|
*/
|
|
86
86
|
this.timestamps = new Map();
|
|
87
87
|
|
|
88
|
+
// WITH_GENESYS
|
|
89
|
+
/**
|
|
90
|
+
* Stores raw GPU timestamp ranges for each render context when supported.
|
|
91
|
+
*
|
|
92
|
+
* @type {Map<string, {start: bigint, end: bigint}>}
|
|
93
|
+
*/
|
|
94
|
+
this.timestampRanges = new Map();
|
|
95
|
+
// !WITH_GENESYS
|
|
96
|
+
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
/**
|
|
@@ -120,6 +129,20 @@ class TimestampQueryPool {
|
|
|
120
129
|
|
|
121
130
|
}
|
|
122
131
|
|
|
132
|
+
// WITH_GENESYS
|
|
133
|
+
/**
|
|
134
|
+
* Returns the raw GPU timestamp range for a render context.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} uid - A unique identifier for the render context.
|
|
137
|
+
* @return {?{start: bigint, end: bigint}} The raw timestamp range, or null when unsupported.
|
|
138
|
+
*/
|
|
139
|
+
getTimestampRange( uid ) {
|
|
140
|
+
|
|
141
|
+
return this.timestampRanges.get( uid ) ?? null;
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
// !WITH_GENESYS
|
|
145
|
+
|
|
123
146
|
/**
|
|
124
147
|
* Returns whether a timestamp is available for a given render context.
|
|
125
148
|
*
|
|
@@ -407,7 +407,11 @@ class WebGLBackend extends Backend {
|
|
|
407
407
|
* @param {string} type - The type of the timestamp query.
|
|
408
408
|
* @param {string} uid - A unique identifier for the timestamp query.
|
|
409
409
|
*/
|
|
410
|
-
|
|
410
|
+
// WITH_GENESYS
|
|
411
|
+
initTimestampQuery( type, uid, label = null ) {
|
|
412
|
+
|
|
413
|
+
// !WITH_GENESYS
|
|
414
|
+
// initTimestampQuery( type, uid ) {
|
|
411
415
|
|
|
412
416
|
if ( ! this.disjoint || ! this.trackTimestamp ) return;
|
|
413
417
|
|
|
@@ -424,7 +428,11 @@ class WebGLBackend extends Backend {
|
|
|
424
428
|
|
|
425
429
|
if ( baseOffset !== null ) {
|
|
426
430
|
|
|
427
|
-
timestampQueryPool.beginQuery( uid );
|
|
431
|
+
const started = timestampQueryPool.beginQuery( uid );
|
|
432
|
+
|
|
433
|
+
// WITH_GENESYS
|
|
434
|
+
if ( started ) this.notifyTimestampQuery( type, uid, label );
|
|
435
|
+
// !WITH_GENESYS
|
|
428
436
|
|
|
429
437
|
}
|
|
430
438
|
|
|
@@ -497,7 +505,10 @@ class WebGLBackend extends Backend {
|
|
|
497
505
|
|
|
498
506
|
//
|
|
499
507
|
|
|
500
|
-
|
|
508
|
+
// WITH_GENESYS
|
|
509
|
+
this.initTimestampQuery( TimestampQuery.RENDER, this.getTimestampUID( renderContext ), renderContext.gpuProfilerLabel );
|
|
510
|
+
// !WITH_GENESYS
|
|
511
|
+
// this.initTimestampQuery( TimestampQuery.RENDER, this.getTimestampUID( renderContext ) );
|
|
501
512
|
|
|
502
513
|
renderContextData.previousContext = this._currentContext;
|
|
503
514
|
this._currentContext = renderContext;
|
|
@@ -81,33 +81,34 @@ class WebGLTimestampQueryPool extends TimestampQueryPool {
|
|
|
81
81
|
* Begins a timestamp query for the specified render context.
|
|
82
82
|
*
|
|
83
83
|
* @param {string} uid - A unique identifier for the render context.
|
|
84
|
+
* @return {boolean} Whether the query was started.
|
|
84
85
|
*/
|
|
85
86
|
beginQuery( uid ) {
|
|
86
87
|
|
|
87
88
|
if ( ! this.trackTimestamp || this.isDisposed ) {
|
|
88
89
|
|
|
89
|
-
return;
|
|
90
|
+
return false;
|
|
90
91
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
const baseOffset = this.queryOffsets.get( uid );
|
|
94
95
|
if ( baseOffset == null ) {
|
|
95
96
|
|
|
96
|
-
return;
|
|
97
|
+
return false;
|
|
97
98
|
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
// Don't start a new query if there's an active one
|
|
101
102
|
if ( this.activeQuery !== null ) {
|
|
102
103
|
|
|
103
|
-
return;
|
|
104
|
+
return false;
|
|
104
105
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
const query = this.queries[ baseOffset ];
|
|
108
109
|
if ( ! query ) {
|
|
109
110
|
|
|
110
|
-
return;
|
|
111
|
+
return false;
|
|
111
112
|
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -119,6 +120,7 @@ class WebGLTimestampQueryPool extends TimestampQueryPool {
|
|
|
119
120
|
this.gl.beginQuery( this.ext.TIME_ELAPSED_EXT, query );
|
|
120
121
|
this.activeQuery = baseOffset;
|
|
121
122
|
this.queryStates.set( baseOffset, 'started' );
|
|
123
|
+
return true;
|
|
122
124
|
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -130,6 +132,8 @@ class WebGLTimestampQueryPool extends TimestampQueryPool {
|
|
|
130
132
|
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
return false;
|
|
136
|
+
|
|
133
137
|
}
|
|
134
138
|
|
|
135
139
|
/**
|
|
@@ -25,7 +25,7 @@ import GPUShaderModuleDescriptor from './descriptors/GPUShaderModuleDescriptor.j
|
|
|
25
25
|
import GPURenderPassColorAttachment from './descriptors/GPURenderPassColorAttachment.js';
|
|
26
26
|
import GPURenderPassDepthStencilAttachment from './descriptors/GPURenderPassDepthStencilAttachment.js';
|
|
27
27
|
import GPURenderPassDescriptor from './descriptors/GPURenderPassDescriptor.js';
|
|
28
|
-
import GPURenderPassTimestampWrites from './descriptors/GPURenderPassTimestampWrites.js';
|
|
28
|
+
// import GPURenderPassTimestampWrites from './descriptors/GPURenderPassTimestampWrites.js';
|
|
29
29
|
import GPUTexelCopyTextureInfo from './descriptors/GPUTexelCopyTextureInfo.js';
|
|
30
30
|
import GPUTextureViewDescriptor from './descriptors/GPUTextureViewDescriptor.js';
|
|
31
31
|
import GPUExtent3D from './descriptors/GPUExtent3D.js';
|
|
@@ -36,7 +36,7 @@ const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor();
|
|
|
36
36
|
const _computePassDescriptor = new GPUComputePassDescriptor();
|
|
37
37
|
const _querySetDescriptor = new GPUQuerySetDescriptor();
|
|
38
38
|
const _shaderModuleDescriptor = new GPUShaderModuleDescriptor();
|
|
39
|
-
const _renderPassTimestampWrites = new GPURenderPassTimestampWrites();
|
|
39
|
+
// const _renderPassTimestampWrites = new GPURenderPassTimestampWrites();
|
|
40
40
|
const _texelCopyTextureInfoSrc = new GPUTexelCopyTextureInfo();
|
|
41
41
|
const _texelCopyTextureInfoDst = new GPUTexelCopyTextureInfo();
|
|
42
42
|
const _viewDescriptor = new GPUTextureViewDescriptor();
|
|
@@ -836,7 +836,10 @@ class WebGPUBackend extends Backend {
|
|
|
836
836
|
|
|
837
837
|
}
|
|
838
838
|
|
|
839
|
-
|
|
839
|
+
// WITH_GENESYS
|
|
840
|
+
this.initTimestampQuery( TimestampQuery.RENDER, this.getTimestampUID( renderContext ), descriptor, renderContext.gpuProfilerLabel );
|
|
841
|
+
// !WITH_GENESYS
|
|
842
|
+
// this.initTimestampQuery( TimestampQuery.RENDER, this.getTimestampUID( renderContext ), descriptor );
|
|
840
843
|
|
|
841
844
|
descriptor.occlusionQuerySet = occlusionQuerySet;
|
|
842
845
|
|
|
@@ -2252,7 +2255,11 @@ class WebGPUBackend extends Backend {
|
|
|
2252
2255
|
* @param {number} uid - Unique id for the context (e.g. render context id).
|
|
2253
2256
|
* @param {Object} descriptor - The query descriptor.
|
|
2254
2257
|
*/
|
|
2255
|
-
|
|
2258
|
+
// WITH_GENESYS
|
|
2259
|
+
initTimestampQuery( type, uid, descriptor, label = null ) {
|
|
2260
|
+
|
|
2261
|
+
// !WITH_GENESYS
|
|
2262
|
+
// initTimestampQuery( type, uid, descriptor ) {
|
|
2256
2263
|
|
|
2257
2264
|
if ( ! this.trackTimestamp ) return;
|
|
2258
2265
|
|
|
@@ -2272,11 +2279,22 @@ class WebGPUBackend extends Backend {
|
|
|
2272
2279
|
if ( baseOffset === null || timestampQueryPool.querySet === null ) return;
|
|
2273
2280
|
// !WITH_GENESYS
|
|
2274
2281
|
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2282
|
+
// WITH_GENESYS
|
|
2283
|
+
// Per-pass object: a shared descriptor is mutated by nested beginRender /
|
|
2284
|
+
// copyFramebuffer restarts and can make unrelated passes write the same
|
|
2285
|
+
// query indices (shadow maps collapsing to ~1µs is the common symptom).
|
|
2286
|
+
descriptor.timestampWrites = {
|
|
2287
|
+
querySet: timestampQueryPool.querySet,
|
|
2288
|
+
beginningOfPassWriteIndex: baseOffset,
|
|
2289
|
+
endOfPassWriteIndex: baseOffset + 1,
|
|
2290
|
+
};
|
|
2278
2291
|
|
|
2279
|
-
|
|
2292
|
+
this.notifyTimestampQuery( type, uid, label );
|
|
2293
|
+
// !WITH_GENESYS
|
|
2294
|
+
// _renderPassTimestampWrites.querySet = timestampQueryPool.querySet;
|
|
2295
|
+
// _renderPassTimestampWrites.beginningOfPassWriteIndex = baseOffset;
|
|
2296
|
+
// _renderPassTimestampWrites.endOfPassWriteIndex = baseOffset + 1;
|
|
2297
|
+
// descriptor.timestampWrites = _renderPassTimestampWrites;
|
|
2280
2298
|
|
|
2281
2299
|
}
|
|
2282
2300
|
|
|
@@ -2837,6 +2855,17 @@ class WebGPUBackend extends Backend {
|
|
|
2837
2855
|
if ( renderContext.depth ) descriptor.depthStencilAttachment.depthLoadOp = GPULoadOp.Load;
|
|
2838
2856
|
if ( renderContext.stencil ) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load;
|
|
2839
2857
|
|
|
2858
|
+
// WITH_GENESYS
|
|
2859
|
+
// Restarted passes need fresh timestamp slots; reusing the previous
|
|
2860
|
+
// timestampWrites overwrites the first segment's query results.
|
|
2861
|
+
this.initTimestampQuery(
|
|
2862
|
+
TimestampQuery.RENDER,
|
|
2863
|
+
this.getTimestampUID( renderContext ),
|
|
2864
|
+
descriptor,
|
|
2865
|
+
renderContext.gpuProfilerLabel
|
|
2866
|
+
);
|
|
2867
|
+
// !WITH_GENESYS
|
|
2868
|
+
|
|
2840
2869
|
renderContextData.currentPass = encoder.beginRenderPass( descriptor );
|
|
2841
2870
|
renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
|
|
2842
2871
|
|
|
@@ -78,7 +78,20 @@ class WebGPUTimestampQueryPool extends TimestampQueryPool {
|
|
|
78
78
|
const baseOffset = this.currentQueryIndex;
|
|
79
79
|
this.currentQueryIndex += 2;
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
// WITH_GENESYS
|
|
82
|
+
// One logical uid can own multiple GPU passes (nested interrupt /
|
|
83
|
+
// copyFramebuffer restart). Keep every offset; resolve sums them.
|
|
84
|
+
let offsets = this.queryOffsets.get( uid );
|
|
85
|
+
if ( offsets === undefined ) {
|
|
86
|
+
|
|
87
|
+
offsets = [];
|
|
88
|
+
this.queryOffsets.set( uid, offsets );
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
offsets.push( baseOffset );
|
|
93
|
+
// !WITH_GENESYS
|
|
94
|
+
// this.queryOffsets.set( uid, baseOffset );
|
|
82
95
|
|
|
83
96
|
return baseOffset;
|
|
84
97
|
|
|
@@ -200,7 +213,7 @@ class WebGPUTimestampQueryPool extends TimestampQueryPool {
|
|
|
200
213
|
|
|
201
214
|
const frames = [];
|
|
202
215
|
|
|
203
|
-
for ( const [ uid,
|
|
216
|
+
for ( const [ uid, offsetOrOffsets ] of currentOffsets ) {
|
|
204
217
|
|
|
205
218
|
const match = uid.match( /^(.*):f(\d+)$/ );
|
|
206
219
|
const frame = parseInt( match[ 2 ] );
|
|
@@ -213,11 +226,34 @@ class WebGPUTimestampQueryPool extends TimestampQueryPool {
|
|
|
213
226
|
|
|
214
227
|
if ( framesDuration[ frame ] === undefined ) framesDuration[ frame ] = 0;
|
|
215
228
|
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
|
|
229
|
+
// WITH_GENESYS
|
|
230
|
+
const offsets = Array.isArray( offsetOrOffsets ) ? offsetOrOffsets : [ offsetOrOffsets ];
|
|
231
|
+
let duration = 0;
|
|
232
|
+
let rangeStart = null;
|
|
233
|
+
let rangeEnd = null;
|
|
234
|
+
|
|
235
|
+
for ( const baseOffset of offsets ) {
|
|
236
|
+
|
|
237
|
+
const startTime = times[ baseOffset ];
|
|
238
|
+
const endTime = times[ baseOffset + 1 ];
|
|
239
|
+
duration += Number( endTime - startTime ) / 1e6;
|
|
240
|
+
|
|
241
|
+
if ( rangeStart === null || startTime < rangeStart ) rangeStart = startTime;
|
|
242
|
+
if ( rangeEnd === null || endTime > rangeEnd ) rangeEnd = endTime;
|
|
243
|
+
|
|
244
|
+
}
|
|
219
245
|
|
|
220
246
|
this.timestamps.set( uid, duration );
|
|
247
|
+
if ( rangeStart !== null && rangeEnd !== null ) {
|
|
248
|
+
|
|
249
|
+
this.timestampRanges.set( uid, { start: rangeStart, end: rangeEnd } );
|
|
250
|
+
|
|
251
|
+
}
|
|
252
|
+
// !WITH_GENESYS
|
|
253
|
+
// const startTime = times[ baseOffset ];
|
|
254
|
+
// const endTime = times[ baseOffset + 1 ];
|
|
255
|
+
// const duration = Number( endTime - startTime ) / 1e6;
|
|
256
|
+
// this.timestamps.set( uid, duration );
|
|
221
257
|
|
|
222
258
|
framesDuration[ frame ] += duration;
|
|
223
259
|
|
|
@@ -316,6 +352,9 @@ class WebGPUTimestampQueryPool extends TimestampQueryPool {
|
|
|
316
352
|
}
|
|
317
353
|
|
|
318
354
|
this.queryOffsets.clear();
|
|
355
|
+
// WITH_GENESYS
|
|
356
|
+
this.timestampRanges.clear();
|
|
357
|
+
// !WITH_GENESYS
|
|
319
358
|
this.pendingResolve = null;
|
|
320
359
|
|
|
321
360
|
}
|