@gnsx/three 0.184.11 → 0.184.13
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 +509 -0
- package/build/three.core.js +507 -1
- package/build/three.core.min.js +1 -1
- package/build/three.module.js +1 -1
- package/build/three.module.min.js +1 -1
- package/build/three.webgpu.js +104 -3
- package/build/three.webgpu.min.js +1 -1
- package/build/three.webgpu.nodes.js +104 -3
- package/build/three.webgpu.nodes.min.js +1 -1
- package/package.json +1 -1
- package/src/Three.Core.js +5 -0
- package/src/nodes/core/NodeFrame.js +22 -0
- package/src/nodes/lighting/ShadowNode.js +20 -0
- package/src/profiler/ProfilerService.js +504 -0
- package/src/renderers/common/Renderer.js +64 -0
package/build/three.cjs
CHANGED
|
@@ -59687,6 +59687,512 @@ class TextureUtils {
|
|
|
59687
59687
|
|
|
59688
59688
|
}
|
|
59689
59689
|
|
|
59690
|
+
// WITH_GENESYS
|
|
59691
|
+
/**
|
|
59692
|
+
* ProfilerService — per-label CPU timing with ring-buffer aggregation and DevTools integration.
|
|
59693
|
+
*
|
|
59694
|
+
* Activate via environment variable:
|
|
59695
|
+
* PROFILING=1 stats + trace (full profile)
|
|
59696
|
+
* PROFILING=stats stats only, no trace accumulation (lower overhead)
|
|
59697
|
+
*
|
|
59698
|
+
* Quick start (browser console):
|
|
59699
|
+
* __gnsx_profiler.enable()
|
|
59700
|
+
* // play for a few seconds
|
|
59701
|
+
* __gnsx_profiler.report() // sorted console.table (aggregated stats)
|
|
59702
|
+
* __gnsx_profiler.downloadTrace() // download gnsx-trace.json for Speedscope / Perfetto
|
|
59703
|
+
* __gnsx_profiler.reset() // clear samples and trace
|
|
59704
|
+
* __gnsx_profiler.disable()
|
|
59705
|
+
*/
|
|
59706
|
+
|
|
59707
|
+
const RING_SIZE = 120;
|
|
59708
|
+
const FRAME_BUDGET_MS = 1000 / 60;
|
|
59709
|
+
/** Max events in the trace log (~50s at 60fps with 8 labels). */
|
|
59710
|
+
const MAX_TRACE_EVENTS = 50_000;
|
|
59711
|
+
const NOOP = () => {};
|
|
59712
|
+
|
|
59713
|
+
function _readProfilingEnv() {
|
|
59714
|
+
|
|
59715
|
+
const raw =
|
|
59716
|
+
( typeof process !== 'undefined' ? process.env?.[ 'PROFILING' ] : undefined ) ??
|
|
59717
|
+
( typeof globalThis !== 'undefined' ? globalThis[ '__gnsx_env__' ]?.[ 'PROFILING' ] : undefined ) ??
|
|
59718
|
+
( typeof globalThis !== 'undefined' ? globalThis[ '__GNSX_PROFILING__' ] : undefined );
|
|
59719
|
+
|
|
59720
|
+
if ( ! raw || raw === '0' || raw === 'false' ) return false;
|
|
59721
|
+
if ( raw === 'stats' ) return 'stats';
|
|
59722
|
+
return 'full';
|
|
59723
|
+
|
|
59724
|
+
}
|
|
59725
|
+
|
|
59726
|
+
class ProfilerServiceClass {
|
|
59727
|
+
|
|
59728
|
+
constructor() {
|
|
59729
|
+
|
|
59730
|
+
const envProfile = _readProfilingEnv();
|
|
59731
|
+
this._profile = envProfile !== false ? envProfile : 'full';
|
|
59732
|
+
this._enabled = envProfile !== false;
|
|
59733
|
+
|
|
59734
|
+
/** @type {Map<string, Float64Array>} */
|
|
59735
|
+
this.buffers = new Map();
|
|
59736
|
+
/** @type {Map<string, number>} */
|
|
59737
|
+
this.cursors = new Map();
|
|
59738
|
+
/** @type {Map<string, number>} */
|
|
59739
|
+
this.counts = new Map();
|
|
59740
|
+
/** @type {Map<string, Array<{ startTime: number, startMark: string, traced: boolean }>>} */
|
|
59741
|
+
this.marks = new Map();
|
|
59742
|
+
/** @type {ChromeTraceEvent[]} */
|
|
59743
|
+
this.traceEvents = [];
|
|
59744
|
+
this.traceStartTime = 0;
|
|
59745
|
+
this._markId = 0;
|
|
59746
|
+
|
|
59747
|
+
if ( this._enabled ) {
|
|
59748
|
+
|
|
59749
|
+
this.traceStartTime = performance.now();
|
|
59750
|
+
this.begin = this._beginImpl.bind( this );
|
|
59751
|
+
this.end = this._endImpl.bind( this );
|
|
59752
|
+
this._exposeGlobal();
|
|
59753
|
+
console.log( `[ProfilerService] auto-started from env (profile: ${this._profile})` );
|
|
59754
|
+
|
|
59755
|
+
} else {
|
|
59756
|
+
|
|
59757
|
+
this.begin = NOOP;
|
|
59758
|
+
this.end = NOOP;
|
|
59759
|
+
|
|
59760
|
+
}
|
|
59761
|
+
|
|
59762
|
+
}
|
|
59763
|
+
|
|
59764
|
+
/**
|
|
59765
|
+
* Set the active profile. Must be called before enable() to take effect on the current session.
|
|
59766
|
+
*
|
|
59767
|
+
* @param {'full'|'stats'} profile
|
|
59768
|
+
*/
|
|
59769
|
+
setProfile( profile ) {
|
|
59770
|
+
|
|
59771
|
+
this._profile = profile;
|
|
59772
|
+
|
|
59773
|
+
}
|
|
59774
|
+
|
|
59775
|
+
/**
|
|
59776
|
+
* @return {'full'|'stats'}
|
|
59777
|
+
*/
|
|
59778
|
+
getProfile() {
|
|
59779
|
+
|
|
59780
|
+
return this._profile;
|
|
59781
|
+
|
|
59782
|
+
}
|
|
59783
|
+
|
|
59784
|
+
enable() {
|
|
59785
|
+
|
|
59786
|
+
this._clearState();
|
|
59787
|
+
this._enabled = true;
|
|
59788
|
+
this.begin = this._beginImpl.bind( this );
|
|
59789
|
+
this.end = this._endImpl.bind( this );
|
|
59790
|
+
this._exposeGlobal();
|
|
59791
|
+
console.log( `[ProfilerService] enabled (profile: ${this._profile}) — call __gnsx_profiler.report() or downloadTrace() from the console` );
|
|
59792
|
+
|
|
59793
|
+
}
|
|
59794
|
+
|
|
59795
|
+
disable() {
|
|
59796
|
+
|
|
59797
|
+
this._clearState();
|
|
59798
|
+
this._enabled = false;
|
|
59799
|
+
this.begin = NOOP;
|
|
59800
|
+
this.end = NOOP;
|
|
59801
|
+
console.log( '[ProfilerService] disabled' );
|
|
59802
|
+
|
|
59803
|
+
}
|
|
59804
|
+
|
|
59805
|
+
isEnabled() {
|
|
59806
|
+
|
|
59807
|
+
return this._enabled;
|
|
59808
|
+
|
|
59809
|
+
}
|
|
59810
|
+
|
|
59811
|
+
_exposeGlobal() {
|
|
59812
|
+
|
|
59813
|
+
if ( typeof window !== 'undefined' ) {
|
|
59814
|
+
|
|
59815
|
+
window.__gnsx_profiler = this;
|
|
59816
|
+
|
|
59817
|
+
}
|
|
59818
|
+
|
|
59819
|
+
}
|
|
59820
|
+
|
|
59821
|
+
/**
|
|
59822
|
+
* @param {string} label
|
|
59823
|
+
*/
|
|
59824
|
+
_beginImpl( label ) {
|
|
59825
|
+
|
|
59826
|
+
const startTime = performance.now();
|
|
59827
|
+
const startMark = `gnsx:${label}:start:${++ this._markId}`;
|
|
59828
|
+
let stack = this.marks.get( label );
|
|
59829
|
+
if ( stack === undefined ) {
|
|
59830
|
+
|
|
59831
|
+
stack = [];
|
|
59832
|
+
this.marks.set( label, stack );
|
|
59833
|
+
|
|
59834
|
+
}
|
|
59835
|
+
|
|
59836
|
+
const traced = this._profile === 'full' && this.traceEvents.length < MAX_TRACE_EVENTS;
|
|
59837
|
+
if ( traced ) {
|
|
59838
|
+
|
|
59839
|
+
this.traceEvents.push( {
|
|
59840
|
+
name: label,
|
|
59841
|
+
ph: 'B',
|
|
59842
|
+
ts: this._getTraceTimestamp( startTime ),
|
|
59843
|
+
pid: 1,
|
|
59844
|
+
tid: 1,
|
|
59845
|
+
cat: 'gnsx',
|
|
59846
|
+
} );
|
|
59847
|
+
|
|
59848
|
+
}
|
|
59849
|
+
|
|
59850
|
+
performance.mark( startMark );
|
|
59851
|
+
stack.push( { startTime, startMark, traced } );
|
|
59852
|
+
|
|
59853
|
+
}
|
|
59854
|
+
|
|
59855
|
+
/**
|
|
59856
|
+
* @param {string} label
|
|
59857
|
+
*/
|
|
59858
|
+
_endImpl( label ) {
|
|
59859
|
+
|
|
59860
|
+
const stack = this.marks.get( label );
|
|
59861
|
+
const mark = stack?.pop();
|
|
59862
|
+
if ( mark === undefined ) return;
|
|
59863
|
+
if ( stack.length === 0 ) this.marks.delete( label );
|
|
59864
|
+
|
|
59865
|
+
const now = performance.now();
|
|
59866
|
+
const { startTime, startMark, traced } = mark;
|
|
59867
|
+
const duration = now - startTime;
|
|
59868
|
+
const endMark = `gnsx:${label}:end:${++ this._markId}`;
|
|
59869
|
+
|
|
59870
|
+
performance.mark( endMark );
|
|
59871
|
+
performance.measure( `gnsx:${label}`, startMark, endMark );
|
|
59872
|
+
|
|
59873
|
+
let buffer = this.buffers.get( label );
|
|
59874
|
+
if ( ! buffer ) {
|
|
59875
|
+
|
|
59876
|
+
buffer = new Float64Array( RING_SIZE );
|
|
59877
|
+
this.buffers.set( label, buffer );
|
|
59878
|
+
this.cursors.set( label, 0 );
|
|
59879
|
+
this.counts.set( label, 0 );
|
|
59880
|
+
|
|
59881
|
+
}
|
|
59882
|
+
|
|
59883
|
+
const cursor = this.cursors.get( label );
|
|
59884
|
+
buffer[ cursor ] = duration;
|
|
59885
|
+
this.cursors.set( label, ( cursor + 1 ) % RING_SIZE );
|
|
59886
|
+
this.counts.set( label, Math.min( ( this.counts.get( label ) + 1 ), RING_SIZE ) );
|
|
59887
|
+
|
|
59888
|
+
if ( traced ) {
|
|
59889
|
+
|
|
59890
|
+
this.traceEvents.push( {
|
|
59891
|
+
name: label,
|
|
59892
|
+
ph: 'E',
|
|
59893
|
+
ts: this._getTraceTimestamp( now ),
|
|
59894
|
+
pid: 1,
|
|
59895
|
+
tid: 1,
|
|
59896
|
+
cat: 'gnsx',
|
|
59897
|
+
} );
|
|
59898
|
+
|
|
59899
|
+
}
|
|
59900
|
+
|
|
59901
|
+
}
|
|
59902
|
+
|
|
59903
|
+
/**
|
|
59904
|
+
* @param {string} label
|
|
59905
|
+
* @return {number[]}
|
|
59906
|
+
*/
|
|
59907
|
+
getValidSamples( label ) {
|
|
59908
|
+
|
|
59909
|
+
const buffer = this.buffers.get( label );
|
|
59910
|
+
const count = this.counts.get( label ) ?? 0;
|
|
59911
|
+
if ( ! buffer || count === 0 ) return [];
|
|
59912
|
+
return count < RING_SIZE
|
|
59913
|
+
? Array.from( buffer.subarray( 0, count ) )
|
|
59914
|
+
: Array.from( buffer );
|
|
59915
|
+
|
|
59916
|
+
}
|
|
59917
|
+
|
|
59918
|
+
/**
|
|
59919
|
+
* @param {string} label
|
|
59920
|
+
* @return {import('./ProfilerService.js').ProfilerStats|null}
|
|
59921
|
+
*/
|
|
59922
|
+
getStats( label ) {
|
|
59923
|
+
|
|
59924
|
+
const samples = this.getValidSamples( label );
|
|
59925
|
+
if ( samples.length === 0 ) return null;
|
|
59926
|
+
|
|
59927
|
+
const sorted = [ ...samples ].sort( ( a, b ) => a - b );
|
|
59928
|
+
const avg = sorted.reduce( ( a, b ) => a + b, 0 ) / sorted.length;
|
|
59929
|
+
|
|
59930
|
+
return {
|
|
59931
|
+
label,
|
|
59932
|
+
samples: samples.length,
|
|
59933
|
+
avg,
|
|
59934
|
+
min: sorted[ 0 ],
|
|
59935
|
+
max: sorted[ sorted.length - 1 ],
|
|
59936
|
+
p95: sorted[ Math.floor( sorted.length * 0.95 ) ],
|
|
59937
|
+
frameBudget: ( avg / FRAME_BUDGET_MS ) * 100,
|
|
59938
|
+
};
|
|
59939
|
+
|
|
59940
|
+
}
|
|
59941
|
+
|
|
59942
|
+
/**
|
|
59943
|
+
* @return {import('./ProfilerService.js').ProfilerStats[]}
|
|
59944
|
+
*/
|
|
59945
|
+
getAllStats() {
|
|
59946
|
+
|
|
59947
|
+
return [ ...this.buffers.keys() ]
|
|
59948
|
+
.map( label => this.getStats( label ) )
|
|
59949
|
+
.filter( s => s !== null );
|
|
59950
|
+
|
|
59951
|
+
}
|
|
59952
|
+
|
|
59953
|
+
report() {
|
|
59954
|
+
|
|
59955
|
+
const stats = this.getAllStats();
|
|
59956
|
+
if ( stats.length === 0 ) {
|
|
59957
|
+
|
|
59958
|
+
console.log( '[ProfilerService] No data. Enable profiling first and wait a few frames.' );
|
|
59959
|
+
return;
|
|
59960
|
+
|
|
59961
|
+
}
|
|
59962
|
+
|
|
59963
|
+
stats.sort( ( a, b ) => b.avg - a.avg );
|
|
59964
|
+
console.table(
|
|
59965
|
+
stats.map( s => ( {
|
|
59966
|
+
label: s.label,
|
|
59967
|
+
'avg ms': s.avg.toFixed( 3 ),
|
|
59968
|
+
'min ms': s.min.toFixed( 3 ),
|
|
59969
|
+
'max ms': s.max.toFixed( 3 ),
|
|
59970
|
+
'p95 ms': s.p95.toFixed( 3 ),
|
|
59971
|
+
'budget %': s.frameBudget.toFixed( 1 ) + '%',
|
|
59972
|
+
samples: s.samples,
|
|
59973
|
+
} ) )
|
|
59974
|
+
);
|
|
59975
|
+
|
|
59976
|
+
}
|
|
59977
|
+
|
|
59978
|
+
/**
|
|
59979
|
+
* @return {import('./ProfilerService.js').ChromeTrace}
|
|
59980
|
+
*/
|
|
59981
|
+
exportChromeTrace() {
|
|
59982
|
+
|
|
59983
|
+
return {
|
|
59984
|
+
displayTimeUnit: 'ms',
|
|
59985
|
+
traceEvents: [
|
|
59986
|
+
{ name: 'process_name', ph: 'M', pid: 1, args: { name: 'Genesys Profiler' } },
|
|
59987
|
+
{ name: 'thread_name', ph: 'M', pid: 1, tid: 1, args: { name: 'Main Thread' } },
|
|
59988
|
+
...this.traceEvents,
|
|
59989
|
+
],
|
|
59990
|
+
};
|
|
59991
|
+
|
|
59992
|
+
}
|
|
59993
|
+
|
|
59994
|
+
/**
|
|
59995
|
+
* @param {number} time
|
|
59996
|
+
* @return {number}
|
|
59997
|
+
*/
|
|
59998
|
+
_getTraceTimestamp( time ) {
|
|
59999
|
+
|
|
60000
|
+
return ( time - this.traceStartTime ) * 1000;
|
|
60001
|
+
|
|
60002
|
+
}
|
|
60003
|
+
|
|
60004
|
+
/**
|
|
60005
|
+
* @param {string} [filename='gnsx-trace.json']
|
|
60006
|
+
*/
|
|
60007
|
+
downloadTrace( filename = 'gnsx-trace.json' ) {
|
|
60008
|
+
|
|
60009
|
+
if ( typeof document === 'undefined' ) {
|
|
60010
|
+
|
|
60011
|
+
console.log( '[ProfilerService] downloadTrace() only works in the browser. Use exportChromeTrace() in Node.js.' );
|
|
60012
|
+
return;
|
|
60013
|
+
|
|
60014
|
+
}
|
|
60015
|
+
|
|
60016
|
+
if ( this._profile !== 'full' ) {
|
|
60017
|
+
|
|
60018
|
+
console.log( `[ProfilerService] No trace — current profile is '${this._profile}'. Use setProfile('full') before enabling.` );
|
|
60019
|
+
return;
|
|
60020
|
+
|
|
60021
|
+
}
|
|
60022
|
+
|
|
60023
|
+
if ( this.traceEvents.length === 0 ) {
|
|
60024
|
+
|
|
60025
|
+
console.log( '[ProfilerService] No trace events. Enable the profiler and play for a few seconds first.' );
|
|
60026
|
+
return;
|
|
60027
|
+
|
|
60028
|
+
}
|
|
60029
|
+
|
|
60030
|
+
const json = JSON.stringify( this.exportChromeTrace() );
|
|
60031
|
+
const blob = new Blob( [ json ], { type: 'application/json' } );
|
|
60032
|
+
const url = URL.createObjectURL( blob );
|
|
60033
|
+
const a = document.createElement( 'a' );
|
|
60034
|
+
a.href = url;
|
|
60035
|
+
a.download = filename;
|
|
60036
|
+
a.click();
|
|
60037
|
+
URL.revokeObjectURL( url );
|
|
60038
|
+
console.log( `[ProfilerService] Trace downloaded: ${filename} (${this.traceEvents.length} events)` );
|
|
60039
|
+
|
|
60040
|
+
}
|
|
60041
|
+
|
|
60042
|
+
/**
|
|
60043
|
+
* @return {import('./ProfilerService.js').ProfilerStats[]}
|
|
60044
|
+
*/
|
|
60045
|
+
exportJSON() {
|
|
60046
|
+
|
|
60047
|
+
return this.getAllStats();
|
|
60048
|
+
|
|
60049
|
+
}
|
|
60050
|
+
|
|
60051
|
+
_clearState() {
|
|
60052
|
+
|
|
60053
|
+
this.buffers.clear();
|
|
60054
|
+
this.cursors.clear();
|
|
60055
|
+
this.counts.clear();
|
|
60056
|
+
this.marks.clear();
|
|
60057
|
+
this.traceEvents = [];
|
|
60058
|
+
this.traceStartTime = performance.now();
|
|
60059
|
+
this._markId = 0;
|
|
60060
|
+
|
|
60061
|
+
}
|
|
60062
|
+
|
|
60063
|
+
reset() {
|
|
60064
|
+
|
|
60065
|
+
this._clearState();
|
|
60066
|
+
console.log( '[ProfilerService] data reset' );
|
|
60067
|
+
|
|
60068
|
+
}
|
|
60069
|
+
|
|
60070
|
+
}
|
|
60071
|
+
|
|
60072
|
+
/**
|
|
60073
|
+
* @typedef {Object} ProfilerStats
|
|
60074
|
+
* @property {string} label
|
|
60075
|
+
* @property {number} samples
|
|
60076
|
+
* @property {number} avg
|
|
60077
|
+
* @property {number} min
|
|
60078
|
+
* @property {number} max
|
|
60079
|
+
* @property {number} p95
|
|
60080
|
+
* @property {number} frameBudget Percentage of a 60 fps frame budget (16.67 ms)
|
|
60081
|
+
*/
|
|
60082
|
+
|
|
60083
|
+
/**
|
|
60084
|
+
* @typedef {Object} ChromeTraceEvent
|
|
60085
|
+
* @property {string} name
|
|
60086
|
+
* @property {'B'|'E'} ph
|
|
60087
|
+
* @property {number} ts
|
|
60088
|
+
* @property {1} pid
|
|
60089
|
+
* @property {1} tid
|
|
60090
|
+
* @property {'gnsx'} cat
|
|
60091
|
+
*/
|
|
60092
|
+
|
|
60093
|
+
/**
|
|
60094
|
+
* @typedef {Object} ChromeTraceMetadataEvent
|
|
60095
|
+
* @property {'process_name'|'thread_name'} name
|
|
60096
|
+
* @property {'M'} ph
|
|
60097
|
+
* @property {1} pid
|
|
60098
|
+
* @property {1} [tid]
|
|
60099
|
+
* @property {{ name: string }} args
|
|
60100
|
+
*/
|
|
60101
|
+
|
|
60102
|
+
/**
|
|
60103
|
+
* @typedef {Object} ChromeTrace
|
|
60104
|
+
* @property {'ms'} displayTimeUnit
|
|
60105
|
+
* @property {Array<ChromeTraceEvent|ChromeTraceMetadataEvent>} traceEvents
|
|
60106
|
+
*/
|
|
60107
|
+
|
|
60108
|
+
/**
|
|
60109
|
+
* @typedef {'full'|'stats'} ProfilingProfile
|
|
60110
|
+
*/
|
|
60111
|
+
|
|
60112
|
+
const ProfilerService = new ProfilerServiceClass();
|
|
60113
|
+
|
|
60114
|
+
function applyProfileToMethod( label, descriptor ) {
|
|
60115
|
+
|
|
60116
|
+
if ( _readProfilingEnv() === false ) return descriptor;
|
|
60117
|
+
|
|
60118
|
+
const original = descriptor.value;
|
|
60119
|
+
|
|
60120
|
+
function profiled( ...args ) {
|
|
60121
|
+
|
|
60122
|
+
ProfilerService.begin( label );
|
|
60123
|
+
try {
|
|
60124
|
+
|
|
60125
|
+
const result = original.apply( this, args );
|
|
60126
|
+
if ( result instanceof Promise ) {
|
|
60127
|
+
|
|
60128
|
+
return result.finally( () => ProfilerService.end( label ) );
|
|
60129
|
+
|
|
60130
|
+
}
|
|
60131
|
+
|
|
60132
|
+
ProfilerService.end( label );
|
|
60133
|
+
return result;
|
|
60134
|
+
|
|
60135
|
+
} catch ( error ) {
|
|
60136
|
+
|
|
60137
|
+
ProfilerService.end( label );
|
|
60138
|
+
throw error;
|
|
60139
|
+
|
|
60140
|
+
}
|
|
60141
|
+
|
|
60142
|
+
}
|
|
60143
|
+
|
|
60144
|
+
descriptor.value = profiled;
|
|
60145
|
+
return descriptor;
|
|
60146
|
+
|
|
60147
|
+
}
|
|
60148
|
+
|
|
60149
|
+
/**
|
|
60150
|
+
* Method decorator that profiles the decorated method.
|
|
60151
|
+
* The label is automatically set to `ClassName.methodName`.
|
|
60152
|
+
*
|
|
60153
|
+
* @param {Object} target
|
|
60154
|
+
* @param {string|symbol} propertyKey
|
|
60155
|
+
* @param {PropertyDescriptor} descriptor
|
|
60156
|
+
* @return {PropertyDescriptor}
|
|
60157
|
+
*/
|
|
60158
|
+
function profile( target, propertyKey, descriptor ) {
|
|
60159
|
+
|
|
60160
|
+
const className = target.constructor?.name ?? 'Unknown';
|
|
60161
|
+
return applyProfileToMethod( `${className}.${String( propertyKey )}`, descriptor );
|
|
60162
|
+
|
|
60163
|
+
}
|
|
60164
|
+
|
|
60165
|
+
/**
|
|
60166
|
+
* Class decorator that profiles every method of the decorated class.
|
|
60167
|
+
*
|
|
60168
|
+
* @template T
|
|
60169
|
+
* @param {T} constructor
|
|
60170
|
+
* @return {T}
|
|
60171
|
+
*/
|
|
60172
|
+
function profileClass( constructor ) {
|
|
60173
|
+
|
|
60174
|
+
const proto = constructor.prototype;
|
|
60175
|
+
for ( const key of Object.getOwnPropertyNames( proto ) ) {
|
|
60176
|
+
|
|
60177
|
+
if ( key === 'constructor' ) continue;
|
|
60178
|
+
const descriptor = Object.getOwnPropertyDescriptor( proto, key );
|
|
60179
|
+
if ( ! descriptor || typeof descriptor.value !== 'function' ) continue;
|
|
60180
|
+
Object.defineProperty(
|
|
60181
|
+
proto,
|
|
60182
|
+
key,
|
|
60183
|
+
applyProfileToMethod( `${constructor.name}.${key}`, { ...descriptor } )
|
|
60184
|
+
);
|
|
60185
|
+
|
|
60186
|
+
}
|
|
60187
|
+
|
|
60188
|
+
return constructor;
|
|
60189
|
+
|
|
60190
|
+
}
|
|
60191
|
+
// !WITH_GENESYS
|
|
60192
|
+
|
|
60193
|
+
// !WITH_GENESYS
|
|
60194
|
+
|
|
60195
|
+
|
|
59690
60196
|
if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {
|
|
59691
60197
|
|
|
59692
60198
|
__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {
|
|
@@ -79528,6 +80034,7 @@ exports.PointsMaterial = PointsMaterial;
|
|
|
79528
80034
|
exports.PolarGridHelper = PolarGridHelper;
|
|
79529
80035
|
exports.PolyhedronGeometry = PolyhedronGeometry;
|
|
79530
80036
|
exports.PositionalAudio = PositionalAudio;
|
|
80037
|
+
exports.ProfilerService = ProfilerService;
|
|
79531
80038
|
exports.PropertyBinding = PropertyBinding;
|
|
79532
80039
|
exports.PropertyMixer = PropertyMixer;
|
|
79533
80040
|
exports.QuadraticBezierCurve = QuadraticBezierCurve;
|
|
@@ -79690,6 +80197,8 @@ exports.createCanvasElement = createCanvasElement;
|
|
|
79690
80197
|
exports.error = error;
|
|
79691
80198
|
exports.getConsoleFunction = getConsoleFunction;
|
|
79692
80199
|
exports.log = log;
|
|
80200
|
+
exports.profile = profile;
|
|
80201
|
+
exports.profileClass = profileClass;
|
|
79693
80202
|
exports.setConsoleFunction = setConsoleFunction;
|
|
79694
80203
|
exports.warn = warn;
|
|
79695
80204
|
exports.warnOnce = warnOnce;
|