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/README.md +360 -86
- package/addons/StatsGLNode.js +201 -0
- package/addons/StatsGLNodeWorker.js +198 -0
- package/dist/core.cjs +421 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.js +421 -0
- package/dist/core.js.map +1 -0
- package/dist/main.cjs +406 -241
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +404 -240
- package/dist/main.js.map +1 -1
- package/dist/panel.cjs +12 -3
- package/dist/panel.cjs.map +1 -1
- package/dist/panel.js +12 -3
- package/dist/panel.js.map +1 -1
- package/dist/panelTexture.cjs +93 -0
- package/dist/panelTexture.cjs.map +1 -0
- package/dist/panelTexture.js +93 -0
- package/dist/panelTexture.js.map +1 -0
- package/dist/profiler.cjs +95 -0
- package/dist/profiler.cjs.map +1 -0
- package/dist/profiler.js +95 -0
- package/dist/profiler.js.map +1 -0
- package/dist/stats-gl.d.ts +332 -71
- package/dist/statsGLNode.cjs +89 -0
- package/dist/statsGLNode.cjs.map +1 -0
- package/dist/statsGLNode.js +89 -0
- package/dist/statsGLNode.js.map +1 -0
- package/dist/textureCapture.cjs +283 -0
- package/dist/textureCapture.cjs.map +1 -0
- package/dist/textureCapture.js +283 -0
- package/dist/textureCapture.js.map +1 -0
- package/lib/core.ts +579 -0
- package/lib/main.ts +506 -401
- package/lib/panel.ts +18 -4
- package/lib/panelTexture.ts +122 -0
- package/lib/profiler.ts +124 -0
- package/lib/statsGLNode.ts +124 -0
- package/lib/textureCapture.ts +403 -0
- package/lib/webgpu.d.ts +190 -0
- package/package.json +6 -4
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
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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.
|
|
35
|
-
this.
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
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
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
125
|
-
|
|
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
|
-
|
|
129
|
-
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
199
|
-
this.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
211
|
-
this.
|
|
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
|
-
|
|
226
|
+
updateFromInternalData() {
|
|
220
227
|
this.endProfiling("cpu-started", "cpu-finished", "cpu-duration");
|
|
221
|
-
if (
|
|
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
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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 =
|
|
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
|
-
|
|
270
|
-
|
|
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
|
-
|
|
273
|
-
this.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (
|
|
278
|
-
|
|
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
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
this.
|
|
362
|
-
this.
|
|
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[
|
|
366
|
-
this.lastMin[
|
|
367
|
-
this.lastValue[
|
|
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[
|
|
376
|
-
this.lastMax[
|
|
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
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
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
|