stats-gl 3.8.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.cjs CHANGED
@@ -1,7 +1,13 @@
1
1
  "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const core = require("./core.cjs");
2
4
  const panel = require("./panel.cjs");
3
5
  const panelVsync = require("./panelVsync.cjs");
4
- const _Stats = class _Stats2 {
6
+ const panelTexture = require("./panelTexture.cjs");
7
+ const textureCapture = require("./textureCapture.cjs");
8
+ const profiler = require("./profiler.cjs");
9
+ const statsGLNode = require("./statsGLNode.cjs");
10
+ const _Stats = class _Stats2 extends core.StatsCore {
5
11
  constructor({
6
12
  trackGPU = false,
7
13
  trackCPT = false,
@@ -16,25 +22,34 @@ const _Stats = class _Stats2 {
16
22
  horizontal = true,
17
23
  mode = 0
18
24
  } = {}) {
19
- this.gl = null;
20
- this.ext = null;
21
- this.activeQuery = null;
22
- this.gpuQueries = [];
23
- this.threeRendererPatched = false;
24
- this.frameTimes = [];
25
- this.renderCount = 0;
26
- this.totalCpuDuration = 0;
27
- this.totalGpuDuration = 0;
28
- this.totalGpuDurationCompute = 0;
25
+ super({
26
+ trackGPU,
27
+ trackCPT,
28
+ trackHz,
29
+ trackFPS,
30
+ logsPerSecond,
31
+ graphsPerSecond,
32
+ samplesLog,
33
+ samplesGraph,
34
+ precision
35
+ });
29
36
  this.fpsPanel = null;
30
37
  this.msPanel = null;
31
38
  this.gpuPanel = null;
32
39
  this.gpuPanelCompute = null;
33
40
  this.vsyncPanel = null;
34
- this.averageFps = { logs: [], graph: [] };
35
- this.averageCpu = { logs: [], graph: [] };
36
- this.averageGpu = { logs: [], graph: [] };
37
- this.averageGpuCompute = { logs: [], graph: [] };
41
+ this.workerCpuPanel = null;
42
+ this.texturePanels = /* @__PURE__ */ new Map();
43
+ this.texturePanelRow = null;
44
+ this.textureCaptureWebGL = null;
45
+ this.textureCaptureWebGPU = null;
46
+ this.textureSourcesWebGL = /* @__PURE__ */ new Map();
47
+ this.textureSourcesWebGPU = /* @__PURE__ */ new Map();
48
+ this.texturePreviewWidth = textureCapture.DEFAULT_PREVIEW_WIDTH;
49
+ this.texturePreviewHeight = textureCapture.DEFAULT_PREVIEW_HEIGHT;
50
+ this.lastRendererWidth = 0;
51
+ this.lastRendererHeight = 0;
52
+ this.textureUpdatePending = false;
38
53
  this.updateCounter = 0;
39
54
  this.lastMin = {};
40
55
  this.lastMax = {};
@@ -53,6 +68,10 @@ const _Stats = class _Stats2 {
53
68
  this.HISTORY_SIZE = 120;
54
69
  this.VSYNC_THRESHOLD = 0.05;
55
70
  this.lastFrameTime = 0;
71
+ this.externalData = null;
72
+ this.hasNewExternalData = false;
73
+ this.isWorker = false;
74
+ this.averageWorkerCpu = { logs: [], graph: [] };
56
75
  this.handleClick = (event) => {
57
76
  event.preventDefault();
58
77
  this.showPanel(++this.mode % this.dom.children.length);
@@ -62,6 +81,8 @@ const _Stats = class _Stats2 {
62
81
  this.resizePanel(this.fpsPanel);
63
82
  if (this.msPanel)
64
83
  this.resizePanel(this.msPanel);
84
+ if (this.workerCpuPanel)
85
+ this.resizePanel(this.workerCpuPanel);
65
86
  if (this.gpuPanel)
66
87
  this.resizePanel(this.gpuPanel);
67
88
  if (this.gpuPanelCompute)
@@ -70,27 +91,19 @@ const _Stats = class _Stats2 {
70
91
  this.mode = mode;
71
92
  this.horizontal = horizontal;
72
93
  this.minimal = minimal;
73
- this.trackGPU = trackGPU;
74
- this.trackCPT = trackCPT;
75
- this.trackHz = trackHz;
76
- this.trackFPS = trackFPS;
77
- this.samplesLog = samplesLog;
78
- this.samplesGraph = samplesGraph;
79
- this.precision = precision;
80
- this.logsPerSecond = logsPerSecond;
81
- this.graphsPerSecond = graphsPerSecond;
82
- const prevGraphTime = performance.now();
83
- this.prevGraphTime = prevGraphTime;
84
94
  this.dom = document.createElement("div");
85
95
  this.initializeDOM();
86
- this.beginTime = performance.now();
87
- this.prevTextTime = this.beginTime;
88
- this.prevCpuTime = this.beginTime;
89
96
  this._panelId = 0;
90
97
  if (this.trackFPS) {
91
98
  this.fpsPanel = this.addPanel(new _Stats2.Panel("FPS", "#0ff", "#002"));
92
99
  this.msPanel = this.addPanel(new _Stats2.Panel("CPU", "#0f0", "#020"));
93
100
  }
101
+ if (this.trackGPU) {
102
+ this.gpuPanel = this.addPanel(new _Stats2.Panel("GPU", "#ff0", "#220"));
103
+ }
104
+ if (this.trackCPT) {
105
+ this.gpuPanelCompute = this.addPanel(new _Stats2.Panel("CPT", "#e1e1e1", "#212121"));
106
+ }
94
107
  if (this.trackHz === true) {
95
108
  this.vsyncPanel = new panelVsync.PanelVSync("", "#f0f", "#202");
96
109
  this.dom.appendChild(this.vsyncPanel.canvas);
@@ -116,124 +129,163 @@ const _Stats = class _Stats2 {
116
129
  window.addEventListener("resize", this.handleResize);
117
130
  }
118
131
  }
119
- async init(canvasOrGL) {
120
- if (!canvasOrGL) {
121
- console.error('Stats: The "canvas" parameter is undefined.');
132
+ /**
133
+ * Compute and update texture preview dimensions based on renderer aspect ratio
134
+ */
135
+ updateTexturePreviewDimensions() {
136
+ var _a, _b;
137
+ if (!this.renderer)
122
138
  return;
123
- }
124
- if (this.handleThreeRenderer(canvasOrGL))
125
- return;
126
- if (await this.handleWebGPURenderer(canvasOrGL))
139
+ const rendererWidth = ((_a = this.renderer.domElement) == null ? void 0 : _a.width) || 0;
140
+ const rendererHeight = ((_b = this.renderer.domElement) == null ? void 0 : _b.height) || 0;
141
+ if (rendererWidth === this.lastRendererWidth && rendererHeight === this.lastRendererHeight) {
127
142
  return;
128
- if (this.initializeWebGL(canvasOrGL)) {
129
- if (this.trackGPU) {
130
- this.initializeGPUTracking();
131
- }
143
+ }
144
+ if (rendererWidth === 0 || rendererHeight === 0)
132
145
  return;
146
+ this.lastRendererWidth = rendererWidth;
147
+ this.lastRendererHeight = rendererHeight;
148
+ const sourceAspect = rendererWidth / rendererHeight;
149
+ const panelAspect = textureCapture.DEFAULT_PREVIEW_WIDTH / textureCapture.DEFAULT_PREVIEW_HEIGHT;
150
+ let newWidth;
151
+ let newHeight;
152
+ if (sourceAspect > panelAspect) {
153
+ newWidth = textureCapture.DEFAULT_PREVIEW_WIDTH;
154
+ newHeight = Math.round(textureCapture.DEFAULT_PREVIEW_WIDTH / sourceAspect);
133
155
  } else {
134
- console.error("Stats-gl: Failed to initialize WebGL context");
135
- }
136
- }
137
- handleThreeRenderer(renderer) {
138
- if (renderer.isWebGLRenderer && !this.threeRendererPatched) {
139
- this.patchThreeRenderer(renderer);
140
- this.gl = renderer.getContext();
141
- if (this.trackGPU) {
142
- this.initializeGPUTracking();
156
+ newHeight = textureCapture.DEFAULT_PREVIEW_HEIGHT;
157
+ newWidth = Math.round(textureCapture.DEFAULT_PREVIEW_HEIGHT * sourceAspect);
158
+ }
159
+ newWidth = Math.max(newWidth, 16);
160
+ newHeight = Math.max(newHeight, 16);
161
+ if (newWidth !== this.texturePreviewWidth || newHeight !== this.texturePreviewHeight) {
162
+ this.texturePreviewWidth = newWidth;
163
+ this.texturePreviewHeight = newHeight;
164
+ if (this.textureCaptureWebGL) {
165
+ this.textureCaptureWebGL.resize(newWidth, newHeight);
143
166
  }
144
- return true;
145
- }
146
- return false;
147
- }
148
- async handleWebGPURenderer(renderer) {
149
- if (renderer.isWebGPURenderer) {
150
- if (this.trackGPU || this.trackCPT) {
151
- renderer.backend.trackTimestamp = true;
152
- if (!renderer._initialized) {
153
- await renderer.init();
154
- }
155
- if (renderer.hasFeature("timestamp-query")) {
156
- this.initializeWebGPUPanels();
157
- }
167
+ if (this.textureCaptureWebGPU) {
168
+ this.textureCaptureWebGPU.resize(newWidth, newHeight);
169
+ }
170
+ for (const panel2 of this.texturePanels.values()) {
171
+ panel2.setSourceSize(rendererWidth, rendererHeight);
158
172
  }
159
- this.info = renderer.info;
160
- this.patchThreeWebGPU(renderer);
161
- return true;
162
173
  }
163
- return false;
164
174
  }
165
- initializeWebGPUPanels() {
166
- if (this.trackGPU) {
167
- this.gpuPanel = this.addPanel(new _Stats2.Panel("GPU", "#ff0", "#220"));
168
- }
169
- if (this.trackCPT) {
170
- this.gpuPanelCompute = this.addPanel(new _Stats2.Panel("CPT", "#e1e1e1", "#212121"));
171
- }
175
+ onWebGPUTimestampSupported() {
172
176
  }
173
- initializeWebGL(canvasOrGL) {
174
- if (canvasOrGL instanceof WebGL2RenderingContext) {
175
- this.gl = canvasOrGL;
176
- } else if (canvasOrGL instanceof HTMLCanvasElement || canvasOrGL instanceof OffscreenCanvas) {
177
- this.gl = canvasOrGL.getContext("webgl2");
178
- if (!this.gl) {
179
- console.error("Stats: Unable to obtain WebGL2 context.");
180
- return false;
181
- }
182
- } else {
183
- console.error(
184
- "Stats: Invalid input type. Expected WebGL2RenderingContext, HTMLCanvasElement, or OffscreenCanvas."
185
- );
186
- return false;
187
- }
188
- return true;
177
+ onGPUTrackingInitialized() {
189
178
  }
190
- initializeGPUTracking() {
191
- if (this.gl) {
192
- this.ext = this.gl.getExtension("EXT_disjoint_timer_query_webgl2");
193
- if (this.ext) {
194
- this.gpuPanel = this.addPanel(new _Stats2.Panel("GPU", "#ff0", "#220"));
179
+ setData(data) {
180
+ this.externalData = data;
181
+ this.hasNewExternalData = true;
182
+ if (!this.isWorker && this.msPanel) {
183
+ this.isWorker = true;
184
+ this.workerCpuPanel = new _Stats2.Panel("WRK", "#f90", "#220");
185
+ const insertPosition = this.msPanel.id + 1;
186
+ this.workerCpuPanel.id = insertPosition;
187
+ if (this.gpuPanel && this.gpuPanel.id >= insertPosition) {
188
+ this.gpuPanel.id++;
189
+ this.resizePanel(this.gpuPanel);
195
190
  }
191
+ if (this.gpuPanelCompute && this.gpuPanelCompute.id >= insertPosition) {
192
+ this.gpuPanelCompute.id++;
193
+ this.resizePanel(this.gpuPanelCompute);
194
+ }
195
+ const msCanvas = this.msPanel.canvas;
196
+ if (msCanvas.nextSibling) {
197
+ this.dom.insertBefore(this.workerCpuPanel.canvas, msCanvas.nextSibling);
198
+ } else {
199
+ this.dom.appendChild(this.workerCpuPanel.canvas);
200
+ }
201
+ this.resizePanel(this.workerCpuPanel);
202
+ this._panelId++;
196
203
  }
197
204
  }
198
- begin() {
199
- this.beginProfiling("cpu-started");
200
- if (!this.gl || !this.ext)
201
- return;
202
- if (this.activeQuery) {
203
- this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);
204
- }
205
- this.activeQuery = this.gl.createQuery();
206
- if (this.activeQuery) {
207
- this.gl.beginQuery(this.ext.TIME_ELAPSED_EXT, this.activeQuery);
205
+ update() {
206
+ if (this.externalData) {
207
+ this.updateFromExternalData();
208
+ } else {
209
+ this.updateFromInternalData();
208
210
  }
209
211
  }
210
- end() {
211
- this.renderCount++;
212
- if (this.gl && this.ext && this.activeQuery) {
213
- this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);
214
- this.gpuQueries.push({ query: this.activeQuery });
215
- this.activeQuery = null;
216
- }
212
+ updateFromExternalData() {
213
+ const data = this.externalData;
217
214
  this.endProfiling("cpu-started", "cpu-finished", "cpu-duration");
215
+ this.addToAverage(this.totalCpuDuration, this.averageCpu);
216
+ this.totalCpuDuration = 0;
217
+ if (this.hasNewExternalData) {
218
+ this.addToAverage(data.cpu, this.averageWorkerCpu);
219
+ this.addToAverage(data.fps, this.averageFps);
220
+ this.addToAverage(data.gpu, this.averageGpu);
221
+ this.addToAverage(data.gpuCompute, this.averageGpuCompute);
222
+ this.hasNewExternalData = false;
223
+ }
224
+ this.renderPanels();
218
225
  }
219
- update() {
226
+ updateFromInternalData() {
220
227
  this.endProfiling("cpu-started", "cpu-finished", "cpu-duration");
221
- if (!this.info) {
228
+ if (this.webgpuNative) {
229
+ this.resolveTimestampsAsync();
230
+ } else if (!this.info) {
222
231
  this.processGpuQueries();
223
232
  } else {
224
233
  this.processWebGPUTimestamps();
225
234
  }
226
235
  this.updateAverages();
227
236
  this.resetCounters();
237
+ this.renderPanels();
228
238
  }
229
- processWebGPUTimestamps() {
230
- this.totalGpuDuration = this.info.render.timestamp;
231
- this.totalGpuDurationCompute = this.info.compute.timestamp;
239
+ renderPanels() {
240
+ var _a;
241
+ const currentTime = performance.now();
242
+ if (!this.isWorker) {
243
+ this.frameTimes.push(currentTime);
244
+ while (this.frameTimes.length > 0 && this.frameTimes[0] <= currentTime - 1e3) {
245
+ this.frameTimes.shift();
246
+ }
247
+ const fps = Math.round(this.frameTimes.length);
248
+ this.addToAverage(fps, this.averageFps);
249
+ }
250
+ const shouldUpdateText = currentTime >= this.prevTextTime + 1e3 / this.logsPerSecond;
251
+ const shouldUpdateGraph = currentTime >= this.prevGraphTime + 1e3 / this.graphsPerSecond;
252
+ const suffix = this.isWorker ? " ⛭" : "";
253
+ this.updatePanelComponents(this.fpsPanel, this.averageFps, 0, shouldUpdateText, shouldUpdateGraph, suffix);
254
+ this.updatePanelComponents(this.msPanel, this.averageCpu, this.precision, shouldUpdateText, shouldUpdateGraph, "");
255
+ if (this.workerCpuPanel && this.isWorker) {
256
+ this.updatePanelComponents(this.workerCpuPanel, this.averageWorkerCpu, this.precision, shouldUpdateText, shouldUpdateGraph, " ⛭");
257
+ }
258
+ if (this.gpuPanel) {
259
+ this.updatePanelComponents(this.gpuPanel, this.averageGpu, this.precision, shouldUpdateText, shouldUpdateGraph, suffix);
260
+ }
261
+ if (this.trackCPT && this.gpuPanelCompute) {
262
+ this.updatePanelComponents(this.gpuPanelCompute, this.averageGpuCompute, this.precision, shouldUpdateText, shouldUpdateGraph, suffix);
263
+ }
264
+ if (shouldUpdateText) {
265
+ this.prevTextTime = currentTime;
266
+ }
267
+ if (shouldUpdateGraph) {
268
+ this.prevGraphTime = currentTime;
269
+ if (this.texturePanels.size > 0 && !this.textureUpdatePending) {
270
+ this.textureUpdatePending = true;
271
+ this.updateTexturePanels().finally(() => {
272
+ this.textureUpdatePending = false;
273
+ });
274
+ }
275
+ this.captureStatsGLNodes();
276
+ }
277
+ if (this.vsyncPanel !== null) {
278
+ this.detectVSync(currentTime);
279
+ const vsyncValue = ((_a = this.detectedVSync) == null ? void 0 : _a.refreshRate) || 0;
280
+ if (shouldUpdateText && vsyncValue > 0) {
281
+ this.vsyncPanel.update(vsyncValue, vsyncValue);
282
+ }
283
+ }
232
284
  }
233
285
  resetCounters() {
234
286
  this.renderCount = 0;
235
287
  this.totalCpuDuration = 0;
236
- this.beginTime = this.endInternal();
288
+ this.beginTime = performance.now();
237
289
  }
238
290
  resizePanel(panel2) {
239
291
  panel2.canvas.style.position = "absolute";
@@ -266,23 +318,179 @@ const _Stats = class _Stats2 {
266
318
  }
267
319
  this.mode = id;
268
320
  }
269
- processGpuQueries() {
270
- if (!this.gl || !this.ext)
321
+ // ==========================================================================
322
+ // Texture Panel API
323
+ // ==========================================================================
324
+ /**
325
+ * Add a new texture preview panel
326
+ * @param name - Label for the texture panel
327
+ * @returns The created PanelTexture instance
328
+ */
329
+ addTexturePanel(name) {
330
+ if (!this.texturePanelRow) {
331
+ this.texturePanelRow = document.createElement("div");
332
+ this.texturePanelRow.style.cssText = `
333
+ position: absolute;
334
+ top: 48px;
335
+ left: 0;
336
+ display: flex;
337
+ flex-direction: row;
338
+ `;
339
+ this.dom.appendChild(this.texturePanelRow);
340
+ }
341
+ const panel2 = new panelTexture.PanelTexture(name);
342
+ panel2.canvas.style.position = "relative";
343
+ panel2.canvas.style.left = "";
344
+ panel2.canvas.style.top = "";
345
+ this.texturePanelRow.appendChild(panel2.canvas);
346
+ this.texturePanels.set(name, panel2);
347
+ return panel2;
348
+ }
349
+ /**
350
+ * Set texture source for a panel (Three.js render target)
351
+ * Auto-detects WebGL/WebGPU and extracts native handles
352
+ * @param name - Panel name
353
+ * @param source - Three.js RenderTarget or native texture
354
+ */
355
+ setTexture(name, source) {
356
+ this.updateTexturePreviewDimensions();
357
+ if (this.gl && !this.textureCaptureWebGL) {
358
+ this.textureCaptureWebGL = new textureCapture.TextureCaptureWebGL(this.gl, this.texturePreviewWidth, this.texturePreviewHeight);
359
+ }
360
+ if (this.gpuDevice && !this.textureCaptureWebGPU) {
361
+ this.textureCaptureWebGPU = new textureCapture.TextureCaptureWebGPU(this.gpuDevice, this.texturePreviewWidth, this.texturePreviewHeight);
362
+ }
363
+ const panel2 = this.texturePanels.get(name);
364
+ if (source.isWebGLRenderTarget && this.gl) {
365
+ const webglSource = textureCapture.extractWebGLSource(source, this.gl);
366
+ if (webglSource) {
367
+ this.textureSourcesWebGL.set(name, {
368
+ target: source,
369
+ ...webglSource
370
+ });
371
+ if (panel2) {
372
+ panel2.setSourceSize(webglSource.width, webglSource.height);
373
+ }
374
+ }
271
375
  return;
272
- this.totalGpuDuration = 0;
273
- this.gpuQueries.forEach((queryInfo, index) => {
274
- if (this.gl) {
275
- const available = this.gl.getQueryParameter(queryInfo.query, this.gl.QUERY_RESULT_AVAILABLE);
276
- const disjoint = this.gl.getParameter(this.ext.GPU_DISJOINT_EXT);
277
- if (available && !disjoint) {
278
- const elapsed = this.gl.getQueryParameter(queryInfo.query, this.gl.QUERY_RESULT);
279
- const duration = elapsed * 1e-6;
280
- this.totalGpuDuration += duration;
281
- this.gl.deleteQuery(queryInfo.query);
282
- this.gpuQueries.splice(index, 1);
376
+ }
377
+ if (source.isRenderTarget && this.gpuBackend) {
378
+ const gpuTexture = textureCapture.extractWebGPUSource(source, this.gpuBackend);
379
+ if (gpuTexture) {
380
+ this.textureSourcesWebGPU.set(name, gpuTexture);
381
+ if (panel2 && source.width && source.height) {
382
+ panel2.setSourceSize(source.width, source.height);
283
383
  }
284
384
  }
385
+ return;
386
+ }
387
+ if (source && typeof source.createView === "function") {
388
+ this.textureSourcesWebGPU.set(name, source);
389
+ return;
390
+ }
391
+ }
392
+ /**
393
+ * Set WebGL framebuffer source with explicit dimensions
394
+ * @param name - Panel name
395
+ * @param framebuffer - WebGL framebuffer
396
+ * @param width - Texture width
397
+ * @param height - Texture height
398
+ */
399
+ setTextureWebGL(name, framebuffer, width, height) {
400
+ this.updateTexturePreviewDimensions();
401
+ if (this.gl && !this.textureCaptureWebGL) {
402
+ this.textureCaptureWebGL = new textureCapture.TextureCaptureWebGL(this.gl, this.texturePreviewWidth, this.texturePreviewHeight);
403
+ }
404
+ this.textureSourcesWebGL.set(name, {
405
+ target: { isWebGLRenderTarget: true },
406
+ framebuffer,
407
+ width,
408
+ height
285
409
  });
410
+ const panel2 = this.texturePanels.get(name);
411
+ if (panel2) {
412
+ panel2.setSourceSize(width, height);
413
+ }
414
+ }
415
+ /**
416
+ * Set texture from ImageBitmap (for worker mode)
417
+ * @param name - Panel name
418
+ * @param bitmap - ImageBitmap transferred from worker
419
+ * @param sourceWidth - Optional source texture width for aspect ratio
420
+ * @param sourceHeight - Optional source texture height for aspect ratio
421
+ */
422
+ setTextureBitmap(name, bitmap, sourceWidth, sourceHeight) {
423
+ const panel2 = this.texturePanels.get(name);
424
+ if (panel2) {
425
+ if (sourceWidth !== void 0 && sourceHeight !== void 0) {
426
+ panel2.setSourceSize(sourceWidth, sourceHeight);
427
+ }
428
+ panel2.updateTexture(bitmap);
429
+ }
430
+ }
431
+ /**
432
+ * Remove a texture panel
433
+ * @param name - Panel name to remove
434
+ */
435
+ removeTexturePanel(name) {
436
+ const panel2 = this.texturePanels.get(name);
437
+ if (panel2) {
438
+ panel2.dispose();
439
+ panel2.canvas.remove();
440
+ this.texturePanels.delete(name);
441
+ this.textureSourcesWebGL.delete(name);
442
+ this.textureSourcesWebGPU.delete(name);
443
+ }
444
+ }
445
+ /**
446
+ * Capture and update all texture panels
447
+ * Called automatically during renderPanels at graphsPerSecond rate
448
+ */
449
+ async updateTexturePanels() {
450
+ this.updateTexturePreviewDimensions();
451
+ if (this.textureCaptureWebGL) {
452
+ for (const [name, source] of this.textureSourcesWebGL) {
453
+ const panel2 = this.texturePanels.get(name);
454
+ if (panel2) {
455
+ let framebuffer = source.framebuffer;
456
+ let width = source.width;
457
+ let height = source.height;
458
+ if (source.target.isWebGLRenderTarget && source.target.__webglFramebuffer) {
459
+ framebuffer = source.target.__webglFramebuffer;
460
+ width = source.target.width || width;
461
+ height = source.target.height || height;
462
+ }
463
+ const bitmap = await this.textureCaptureWebGL.capture(framebuffer, width, height, name);
464
+ if (bitmap) {
465
+ panel2.updateTexture(bitmap);
466
+ }
467
+ }
468
+ }
469
+ }
470
+ if (this.textureCaptureWebGPU) {
471
+ for (const [name, gpuTexture] of this.textureSourcesWebGPU) {
472
+ const panel2 = this.texturePanels.get(name);
473
+ if (panel2) {
474
+ const bitmap = await this.textureCaptureWebGPU.capture(gpuTexture);
475
+ if (bitmap) {
476
+ panel2.updateTexture(bitmap);
477
+ }
478
+ }
479
+ }
480
+ }
481
+ }
482
+ /**
483
+ * Capture StatsGL nodes registered by the addon
484
+ */
485
+ captureStatsGLNodes() {
486
+ const captures = this._statsGLCaptures;
487
+ if (!captures || captures.size === 0 || !this.renderer)
488
+ return;
489
+ for (const captureData of captures.values()) {
490
+ if (captureData.capture) {
491
+ captureData.capture(this.renderer);
492
+ }
493
+ }
286
494
  }
287
495
  detectVSync(currentTime) {
288
496
  if (this.lastFrameTime === 0) {
@@ -319,52 +527,19 @@ const _Stats = class _Stats2 {
319
527
  this.detectedVSync = null;
320
528
  }
321
529
  }
322
- endInternal() {
323
- var _a;
324
- const currentTime = performance.now();
325
- this.frameTimes.push(currentTime);
326
- while (this.frameTimes.length > 0 && this.frameTimes[0] <= currentTime - 1e3) {
327
- this.frameTimes.shift();
328
- }
329
- const fps = Math.round(this.frameTimes.length);
330
- this.addToAverage(fps, this.averageFps);
331
- const shouldUpdateText = currentTime >= this.prevTextTime + 1e3 / this.logsPerSecond;
332
- const shouldUpdateGraph = currentTime >= this.prevGraphTime + 1e3 / this.graphsPerSecond;
333
- this.updatePanelComponents(this.fpsPanel, this.averageFps, 0, shouldUpdateText, shouldUpdateGraph);
334
- this.updatePanelComponents(this.msPanel, this.averageCpu, this.precision, shouldUpdateText, shouldUpdateGraph);
335
- if (this.gpuPanel) {
336
- this.updatePanelComponents(this.gpuPanel, this.averageGpu, this.precision, shouldUpdateText, shouldUpdateGraph);
337
- }
338
- if (this.trackCPT && this.gpuPanelCompute) {
339
- this.updatePanelComponents(this.gpuPanelCompute, this.averageGpuCompute, this.precision, shouldUpdateText, shouldUpdateGraph);
340
- }
341
- if (shouldUpdateText) {
342
- this.prevTextTime = currentTime;
343
- }
344
- if (shouldUpdateGraph) {
345
- this.prevGraphTime = currentTime;
346
- }
347
- if (this.vsyncPanel !== null) {
348
- this.detectVSync(currentTime);
349
- const vsyncValue = ((_a = this.detectedVSync) == null ? void 0 : _a.refreshRate) || 0;
350
- if (shouldUpdateText && vsyncValue > 0) {
351
- this.vsyncPanel.update(vsyncValue, vsyncValue);
352
- }
353
- }
354
- return currentTime;
355
- }
356
- updatePanelComponents(panel2, averageArray, precision, shouldUpdateText, shouldUpdateGraph) {
530
+ updatePanelComponents(panel2, averageArray, precision, shouldUpdateText, shouldUpdateGraph, suffix = "") {
357
531
  if (!panel2 || averageArray.logs.length === 0)
358
532
  return;
359
- if (!(panel2.name in this.lastMin)) {
360
- this.lastMin[panel2.name] = Infinity;
361
- this.lastMax[panel2.name] = 0;
362
- this.lastValue[panel2.name] = 0;
533
+ const key = String(panel2.id);
534
+ if (!(key in this.lastMin)) {
535
+ this.lastMin[key] = Infinity;
536
+ this.lastMax[key] = 0;
537
+ this.lastValue[key] = 0;
363
538
  }
364
539
  const currentValue = averageArray.logs[averageArray.logs.length - 1];
365
- this.lastMax[panel2.name] = Math.max(...averageArray.logs);
366
- this.lastMin[panel2.name] = Math.min(this.lastMin[panel2.name], currentValue);
367
- this.lastValue[panel2.name] = this.lastValue[panel2.name] * 0.7 + currentValue * 0.3;
540
+ this.lastMax[key] = Math.max(...averageArray.logs);
541
+ this.lastMin[key] = Math.min(this.lastMin[key], currentValue);
542
+ this.lastValue[key] = this.lastValue[key] * 0.7 + currentValue * 0.3;
368
543
  const graphMax = Math.max(
369
544
  Math.max(...averageArray.logs),
370
545
  ...averageArray.graph.slice(-this.samplesGraph)
@@ -372,9 +547,10 @@ const _Stats = class _Stats2 {
372
547
  this.updateCounter++;
373
548
  if (shouldUpdateText) {
374
549
  panel2.update(
375
- this.lastValue[panel2.name],
376
- this.lastMax[panel2.name],
377
- precision
550
+ this.lastValue[key],
551
+ this.lastMax[key],
552
+ precision,
553
+ suffix
378
554
  );
379
555
  }
380
556
  if (shouldUpdateGraph) {
@@ -384,36 +560,6 @@ const _Stats = class _Stats2 {
384
560
  );
385
561
  }
386
562
  }
387
- beginProfiling(marker) {
388
- if (window.performance) {
389
- try {
390
- window.performance.clearMarks(marker);
391
- window.performance.mark(marker);
392
- } catch (error) {
393
- console.debug("Stats: Performance marking failed:", error);
394
- }
395
- }
396
- }
397
- endProfiling(startMarker, endMarker, measureName) {
398
- if (!window.performance || !endMarker || !startMarker)
399
- return;
400
- try {
401
- const entries = window.performance.getEntriesByName(startMarker, "mark");
402
- if (entries.length === 0) {
403
- this.beginProfiling(startMarker);
404
- }
405
- window.performance.clearMarks(endMarker);
406
- window.performance.mark(endMarker);
407
- window.performance.clearMeasures(measureName);
408
- const cpuMeasure = performance.measure(measureName, startMarker, endMarker);
409
- this.totalCpuDuration += cpuMeasure.duration;
410
- window.performance.clearMarks(startMarker);
411
- window.performance.clearMarks(endMarker);
412
- window.performance.clearMeasures(measureName);
413
- } catch (error) {
414
- console.debug("Stats: Performance measurement failed:", error);
415
- }
416
- }
417
563
  updatePanel(panel2, averageArray, precision = 2) {
418
564
  if (!panel2 || averageArray.logs.length === 0)
419
565
  return;
@@ -453,46 +599,65 @@ const _Stats = class _Stats2 {
453
599
  }
454
600
  }
455
601
  }
456
- updateAverages() {
457
- this.addToAverage(this.totalCpuDuration, this.averageCpu);
458
- this.addToAverage(this.totalGpuDuration, this.averageGpu);
459
- if (this.info && this.totalGpuDurationCompute !== void 0) {
460
- this.addToAverage(this.totalGpuDurationCompute, this.averageGpuCompute);
461
- }
462
- }
463
- addToAverage(value, averageArray) {
464
- averageArray.logs.push(value);
465
- if (averageArray.logs.length > this.samplesLog) {
466
- averageArray.logs = averageArray.logs.slice(-this.samplesLog);
467
- }
468
- averageArray.graph.push(value);
469
- if (averageArray.graph.length > this.samplesGraph) {
470
- averageArray.graph = averageArray.graph.slice(-this.samplesGraph);
471
- }
472
- }
473
602
  get domElement() {
474
603
  return this.dom;
475
604
  }
476
- patchThreeWebGPU(renderer) {
477
- const originalAnimationLoop = renderer.info.reset;
478
- const statsInstance = this;
479
- renderer.info.reset = function() {
480
- statsInstance.beginProfiling("cpu-started");
481
- originalAnimationLoop.call(this);
482
- };
483
- }
484
- patchThreeRenderer(renderer) {
485
- const originalRenderMethod = renderer.render;
486
- const statsInstance = this;
487
- renderer.render = function(scene, camera) {
488
- statsInstance.begin();
489
- originalRenderMethod.call(this, scene, camera);
490
- statsInstance.end();
491
- };
492
- this.threeRendererPatched = true;
605
+ /**
606
+ * Dispose of all resources. Call when done using Stats.
607
+ */
608
+ dispose() {
609
+ if (this.minimal) {
610
+ this.dom.removeEventListener("click", this.handleClick);
611
+ } else {
612
+ window.removeEventListener("resize", this.handleResize);
613
+ }
614
+ if (this.textureCaptureWebGL) {
615
+ this.textureCaptureWebGL.dispose();
616
+ this.textureCaptureWebGL = null;
617
+ }
618
+ if (this.textureCaptureWebGPU) {
619
+ this.textureCaptureWebGPU.dispose();
620
+ this.textureCaptureWebGPU = null;
621
+ }
622
+ for (const panel2 of this.texturePanels.values()) {
623
+ panel2.dispose();
624
+ }
625
+ this.texturePanels.clear();
626
+ this.textureSourcesWebGL.clear();
627
+ this.textureSourcesWebGPU.clear();
628
+ const captures = this._statsGLCaptures;
629
+ if (captures) {
630
+ for (const captureData of captures.values()) {
631
+ if (captureData.dispose) {
632
+ captureData.dispose();
633
+ }
634
+ }
635
+ captures.clear();
636
+ }
637
+ if (this.texturePanelRow) {
638
+ this.texturePanelRow.remove();
639
+ this.texturePanelRow = null;
640
+ }
641
+ this.dom.remove();
642
+ this.fpsPanel = null;
643
+ this.msPanel = null;
644
+ this.gpuPanel = null;
645
+ this.gpuPanelCompute = null;
646
+ this.vsyncPanel = null;
647
+ this.workerCpuPanel = null;
648
+ this.frameTimeHistory.length = 0;
649
+ this.averageWorkerCpu.logs.length = 0;
650
+ this.averageWorkerCpu.graph.length = 0;
651
+ super.dispose();
493
652
  }
494
653
  };
495
654
  _Stats.Panel = panel.Panel;
655
+ _Stats.PanelTexture = panelTexture.PanelTexture;
496
656
  let Stats = _Stats;
497
- module.exports = Stats;
657
+ exports.PanelTexture = panelTexture.PanelTexture;
658
+ exports.TextureCaptureWebGL = textureCapture.TextureCaptureWebGL;
659
+ exports.TextureCaptureWebGPU = textureCapture.TextureCaptureWebGPU;
660
+ exports.StatsProfiler = profiler.StatsProfiler;
661
+ exports.StatsGLCapture = statsGLNode.StatsGLCapture;
662
+ exports.default = Stats;
498
663
  //# sourceMappingURL=main.cjs.map