stats-gl 3.7.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 -84
- 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 +417 -244
- package/dist/main.cjs.map +1 -1
- package/dist/main.js +415 -243
- 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 +335 -72
- 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 +514 -403
- 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,11 +1,18 @@
|
|
|
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,
|
|
8
14
|
trackHz = false,
|
|
15
|
+
trackFPS = true,
|
|
9
16
|
logsPerSecond = 4,
|
|
10
17
|
graphsPerSecond = 30,
|
|
11
18
|
samplesLog = 40,
|
|
@@ -15,23 +22,34 @@ const _Stats = class _Stats2 {
|
|
|
15
22
|
horizontal = true,
|
|
16
23
|
mode = 0
|
|
17
24
|
} = {}) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
super({
|
|
26
|
+
trackGPU,
|
|
27
|
+
trackCPT,
|
|
28
|
+
trackHz,
|
|
29
|
+
trackFPS,
|
|
30
|
+
logsPerSecond,
|
|
31
|
+
graphsPerSecond,
|
|
32
|
+
samplesLog,
|
|
33
|
+
samplesGraph,
|
|
34
|
+
precision
|
|
35
|
+
});
|
|
36
|
+
this.fpsPanel = null;
|
|
37
|
+
this.msPanel = null;
|
|
28
38
|
this.gpuPanel = null;
|
|
29
39
|
this.gpuPanelCompute = null;
|
|
30
40
|
this.vsyncPanel = null;
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
34
|
-
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;
|
|
35
53
|
this.updateCounter = 0;
|
|
36
54
|
this.lastMin = {};
|
|
37
55
|
this.lastMax = {};
|
|
@@ -50,13 +68,21 @@ const _Stats = class _Stats2 {
|
|
|
50
68
|
this.HISTORY_SIZE = 120;
|
|
51
69
|
this.VSYNC_THRESHOLD = 0.05;
|
|
52
70
|
this.lastFrameTime = 0;
|
|
71
|
+
this.externalData = null;
|
|
72
|
+
this.hasNewExternalData = false;
|
|
73
|
+
this.isWorker = false;
|
|
74
|
+
this.averageWorkerCpu = { logs: [], graph: [] };
|
|
53
75
|
this.handleClick = (event) => {
|
|
54
76
|
event.preventDefault();
|
|
55
77
|
this.showPanel(++this.mode % this.dom.children.length);
|
|
56
78
|
};
|
|
57
79
|
this.handleResize = () => {
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
if (this.fpsPanel)
|
|
81
|
+
this.resizePanel(this.fpsPanel);
|
|
82
|
+
if (this.msPanel)
|
|
83
|
+
this.resizePanel(this.msPanel);
|
|
84
|
+
if (this.workerCpuPanel)
|
|
85
|
+
this.resizePanel(this.workerCpuPanel);
|
|
60
86
|
if (this.gpuPanel)
|
|
61
87
|
this.resizePanel(this.gpuPanel);
|
|
62
88
|
if (this.gpuPanelCompute)
|
|
@@ -65,24 +91,19 @@ const _Stats = class _Stats2 {
|
|
|
65
91
|
this.mode = mode;
|
|
66
92
|
this.horizontal = horizontal;
|
|
67
93
|
this.minimal = minimal;
|
|
68
|
-
this.trackGPU = trackGPU;
|
|
69
|
-
this.trackCPT = trackCPT;
|
|
70
|
-
this.trackHz = trackHz;
|
|
71
|
-
this.samplesLog = samplesLog;
|
|
72
|
-
this.samplesGraph = samplesGraph;
|
|
73
|
-
this.precision = precision;
|
|
74
|
-
this.logsPerSecond = logsPerSecond;
|
|
75
|
-
this.graphsPerSecond = graphsPerSecond;
|
|
76
|
-
const prevGraphTime = performance.now();
|
|
77
|
-
this.prevGraphTime = prevGraphTime;
|
|
78
94
|
this.dom = document.createElement("div");
|
|
79
95
|
this.initializeDOM();
|
|
80
|
-
this.beginTime = performance.now();
|
|
81
|
-
this.prevTextTime = this.beginTime;
|
|
82
|
-
this.prevCpuTime = this.beginTime;
|
|
83
96
|
this._panelId = 0;
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
if (this.trackFPS) {
|
|
98
|
+
this.fpsPanel = this.addPanel(new _Stats2.Panel("FPS", "#0ff", "#002"));
|
|
99
|
+
this.msPanel = this.addPanel(new _Stats2.Panel("CPU", "#0f0", "#020"));
|
|
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
|
+
}
|
|
86
107
|
if (this.trackHz === true) {
|
|
87
108
|
this.vsyncPanel = new panelVsync.PanelVSync("", "#f0f", "#202");
|
|
88
109
|
this.dom.appendChild(this.vsyncPanel.canvas);
|
|
@@ -108,124 +129,163 @@ const _Stats = class _Stats2 {
|
|
|
108
129
|
window.addEventListener("resize", this.handleResize);
|
|
109
130
|
}
|
|
110
131
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (this.
|
|
132
|
+
/**
|
|
133
|
+
* Compute and update texture preview dimensions based on renderer aspect ratio
|
|
134
|
+
*/
|
|
135
|
+
updateTexturePreviewDimensions() {
|
|
136
|
+
var _a, _b;
|
|
137
|
+
if (!this.renderer)
|
|
117
138
|
return;
|
|
118
|
-
|
|
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) {
|
|
119
142
|
return;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
this.initializeGPUTracking();
|
|
123
|
-
}
|
|
143
|
+
}
|
|
144
|
+
if (rendererWidth === 0 || rendererHeight === 0)
|
|
124
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);
|
|
125
155
|
} else {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.
|
|
133
|
-
|
|
134
|
-
|
|
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);
|
|
135
166
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (renderer.isWebGPURenderer) {
|
|
142
|
-
if (this.trackGPU || this.trackCPT) {
|
|
143
|
-
renderer.backend.trackTimestamp = true;
|
|
144
|
-
if (!renderer._initialized) {
|
|
145
|
-
await renderer.init();
|
|
146
|
-
}
|
|
147
|
-
if (renderer.hasFeature("timestamp-query")) {
|
|
148
|
-
this.initializeWebGPUPanels();
|
|
149
|
-
}
|
|
167
|
+
if (this.textureCaptureWebGPU) {
|
|
168
|
+
this.textureCaptureWebGPU.resize(newWidth, newHeight);
|
|
169
|
+
}
|
|
170
|
+
for (const panel2 of this.texturePanels.values()) {
|
|
171
|
+
panel2.setSourceSize(rendererWidth, rendererHeight);
|
|
150
172
|
}
|
|
151
|
-
this.info = renderer.info;
|
|
152
|
-
this.patchThreeWebGPU(renderer);
|
|
153
|
-
return true;
|
|
154
173
|
}
|
|
155
|
-
return false;
|
|
156
174
|
}
|
|
157
|
-
|
|
158
|
-
if (this.trackGPU) {
|
|
159
|
-
this.gpuPanel = this.addPanel(new _Stats2.Panel("GPU", "#ff0", "#220"));
|
|
160
|
-
}
|
|
161
|
-
if (this.trackCPT) {
|
|
162
|
-
this.gpuPanelCompute = this.addPanel(new _Stats2.Panel("CPT", "#e1e1e1", "#212121"));
|
|
163
|
-
}
|
|
175
|
+
onWebGPUTimestampSupported() {
|
|
164
176
|
}
|
|
165
|
-
|
|
166
|
-
if (canvasOrGL instanceof WebGL2RenderingContext) {
|
|
167
|
-
this.gl = canvasOrGL;
|
|
168
|
-
} else if (canvasOrGL instanceof HTMLCanvasElement || canvasOrGL instanceof OffscreenCanvas) {
|
|
169
|
-
this.gl = canvasOrGL.getContext("webgl2");
|
|
170
|
-
if (!this.gl) {
|
|
171
|
-
console.error("Stats: Unable to obtain WebGL2 context.");
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
} else {
|
|
175
|
-
console.error(
|
|
176
|
-
"Stats: Invalid input type. Expected WebGL2RenderingContext, HTMLCanvasElement, or OffscreenCanvas."
|
|
177
|
-
);
|
|
178
|
-
return false;
|
|
179
|
-
}
|
|
180
|
-
return true;
|
|
177
|
+
onGPUTrackingInitialized() {
|
|
181
178
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
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);
|
|
190
|
+
}
|
|
191
|
+
if (this.gpuPanelCompute && this.gpuPanelCompute.id >= insertPosition) {
|
|
192
|
+
this.gpuPanelCompute.id++;
|
|
193
|
+
this.resizePanel(this.gpuPanelCompute);
|
|
187
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++;
|
|
188
203
|
}
|
|
189
204
|
}
|
|
190
|
-
|
|
191
|
-
this.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);
|
|
196
|
-
}
|
|
197
|
-
this.activeQuery = this.gl.createQuery();
|
|
198
|
-
if (this.activeQuery) {
|
|
199
|
-
this.gl.beginQuery(this.ext.TIME_ELAPSED_EXT, this.activeQuery);
|
|
205
|
+
update() {
|
|
206
|
+
if (this.externalData) {
|
|
207
|
+
this.updateFromExternalData();
|
|
208
|
+
} else {
|
|
209
|
+
this.updateFromInternalData();
|
|
200
210
|
}
|
|
201
211
|
}
|
|
202
|
-
|
|
203
|
-
this.
|
|
204
|
-
if (this.gl && this.ext && this.activeQuery) {
|
|
205
|
-
this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);
|
|
206
|
-
this.gpuQueries.push({ query: this.activeQuery });
|
|
207
|
-
this.activeQuery = null;
|
|
208
|
-
}
|
|
212
|
+
updateFromExternalData() {
|
|
213
|
+
const data = this.externalData;
|
|
209
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();
|
|
210
225
|
}
|
|
211
|
-
|
|
226
|
+
updateFromInternalData() {
|
|
212
227
|
this.endProfiling("cpu-started", "cpu-finished", "cpu-duration");
|
|
213
|
-
if (
|
|
228
|
+
if (this.webgpuNative) {
|
|
229
|
+
this.resolveTimestampsAsync();
|
|
230
|
+
} else if (!this.info) {
|
|
214
231
|
this.processGpuQueries();
|
|
215
232
|
} else {
|
|
216
233
|
this.processWebGPUTimestamps();
|
|
217
234
|
}
|
|
218
235
|
this.updateAverages();
|
|
219
236
|
this.resetCounters();
|
|
237
|
+
this.renderPanels();
|
|
220
238
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
+
}
|
|
224
284
|
}
|
|
225
285
|
resetCounters() {
|
|
226
286
|
this.renderCount = 0;
|
|
227
287
|
this.totalCpuDuration = 0;
|
|
228
|
-
this.beginTime =
|
|
288
|
+
this.beginTime = performance.now();
|
|
229
289
|
}
|
|
230
290
|
resizePanel(panel2) {
|
|
231
291
|
panel2.canvas.style.position = "absolute";
|
|
@@ -258,23 +318,179 @@ const _Stats = class _Stats2 {
|
|
|
258
318
|
}
|
|
259
319
|
this.mode = id;
|
|
260
320
|
}
|
|
261
|
-
|
|
262
|
-
|
|
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
|
+
}
|
|
263
375
|
return;
|
|
264
|
-
|
|
265
|
-
this.
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
const duration = elapsed * 1e-6;
|
|
272
|
-
this.totalGpuDuration += duration;
|
|
273
|
-
this.gl.deleteQuery(queryInfo.query);
|
|
274
|
-
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);
|
|
275
383
|
}
|
|
276
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
|
|
277
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
|
+
}
|
|
278
494
|
}
|
|
279
495
|
detectVSync(currentTime) {
|
|
280
496
|
if (this.lastFrameTime === 0) {
|
|
@@ -311,52 +527,19 @@ const _Stats = class _Stats2 {
|
|
|
311
527
|
this.detectedVSync = null;
|
|
312
528
|
}
|
|
313
529
|
}
|
|
314
|
-
|
|
315
|
-
var _a;
|
|
316
|
-
const currentTime = performance.now();
|
|
317
|
-
this.frameTimes.push(currentTime);
|
|
318
|
-
while (this.frameTimes.length > 0 && this.frameTimes[0] <= currentTime - 1e3) {
|
|
319
|
-
this.frameTimes.shift();
|
|
320
|
-
}
|
|
321
|
-
const fps = Math.round(this.frameTimes.length);
|
|
322
|
-
this.addToAverage(fps, this.averageFps);
|
|
323
|
-
const shouldUpdateText = currentTime >= this.prevTextTime + 1e3 / this.logsPerSecond;
|
|
324
|
-
const shouldUpdateGraph = currentTime >= this.prevGraphTime + 1e3 / this.graphsPerSecond;
|
|
325
|
-
this.updatePanelComponents(this.fpsPanel, this.averageFps, 0, shouldUpdateText, shouldUpdateGraph);
|
|
326
|
-
this.updatePanelComponents(this.msPanel, this.averageCpu, this.precision, shouldUpdateText, shouldUpdateGraph);
|
|
327
|
-
if (this.gpuPanel) {
|
|
328
|
-
this.updatePanelComponents(this.gpuPanel, this.averageGpu, this.precision, shouldUpdateText, shouldUpdateGraph);
|
|
329
|
-
}
|
|
330
|
-
if (this.trackCPT && this.gpuPanelCompute) {
|
|
331
|
-
this.updatePanelComponents(this.gpuPanelCompute, this.averageGpuCompute, this.precision, shouldUpdateText, shouldUpdateGraph);
|
|
332
|
-
}
|
|
333
|
-
if (shouldUpdateText) {
|
|
334
|
-
this.prevTextTime = currentTime;
|
|
335
|
-
}
|
|
336
|
-
if (shouldUpdateGraph) {
|
|
337
|
-
this.prevGraphTime = currentTime;
|
|
338
|
-
}
|
|
339
|
-
if (this.vsyncPanel !== null) {
|
|
340
|
-
this.detectVSync(currentTime);
|
|
341
|
-
const vsyncValue = ((_a = this.detectedVSync) == null ? void 0 : _a.refreshRate) || 0;
|
|
342
|
-
if (shouldUpdateText && vsyncValue > 0) {
|
|
343
|
-
this.vsyncPanel.update(vsyncValue, vsyncValue);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
return currentTime;
|
|
347
|
-
}
|
|
348
|
-
updatePanelComponents(panel2, averageArray, precision, shouldUpdateText, shouldUpdateGraph) {
|
|
530
|
+
updatePanelComponents(panel2, averageArray, precision, shouldUpdateText, shouldUpdateGraph, suffix = "") {
|
|
349
531
|
if (!panel2 || averageArray.logs.length === 0)
|
|
350
532
|
return;
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
this.
|
|
354
|
-
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;
|
|
355
538
|
}
|
|
356
539
|
const currentValue = averageArray.logs[averageArray.logs.length - 1];
|
|
357
|
-
this.lastMax[
|
|
358
|
-
this.lastMin[
|
|
359
|
-
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;
|
|
360
543
|
const graphMax = Math.max(
|
|
361
544
|
Math.max(...averageArray.logs),
|
|
362
545
|
...averageArray.graph.slice(-this.samplesGraph)
|
|
@@ -364,9 +547,10 @@ const _Stats = class _Stats2 {
|
|
|
364
547
|
this.updateCounter++;
|
|
365
548
|
if (shouldUpdateText) {
|
|
366
549
|
panel2.update(
|
|
367
|
-
this.lastValue[
|
|
368
|
-
this.lastMax[
|
|
369
|
-
precision
|
|
550
|
+
this.lastValue[key],
|
|
551
|
+
this.lastMax[key],
|
|
552
|
+
precision,
|
|
553
|
+
suffix
|
|
370
554
|
);
|
|
371
555
|
}
|
|
372
556
|
if (shouldUpdateGraph) {
|
|
@@ -376,36 +560,6 @@ const _Stats = class _Stats2 {
|
|
|
376
560
|
);
|
|
377
561
|
}
|
|
378
562
|
}
|
|
379
|
-
beginProfiling(marker) {
|
|
380
|
-
if (window.performance) {
|
|
381
|
-
try {
|
|
382
|
-
window.performance.clearMarks(marker);
|
|
383
|
-
window.performance.mark(marker);
|
|
384
|
-
} catch (error) {
|
|
385
|
-
console.debug("Stats: Performance marking failed:", error);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
endProfiling(startMarker, endMarker, measureName) {
|
|
390
|
-
if (!window.performance || !endMarker || !startMarker)
|
|
391
|
-
return;
|
|
392
|
-
try {
|
|
393
|
-
const entries = window.performance.getEntriesByName(startMarker, "mark");
|
|
394
|
-
if (entries.length === 0) {
|
|
395
|
-
this.beginProfiling(startMarker);
|
|
396
|
-
}
|
|
397
|
-
window.performance.clearMarks(endMarker);
|
|
398
|
-
window.performance.mark(endMarker);
|
|
399
|
-
window.performance.clearMeasures(measureName);
|
|
400
|
-
const cpuMeasure = performance.measure(measureName, startMarker, endMarker);
|
|
401
|
-
this.totalCpuDuration += cpuMeasure.duration;
|
|
402
|
-
window.performance.clearMarks(startMarker);
|
|
403
|
-
window.performance.clearMarks(endMarker);
|
|
404
|
-
window.performance.clearMeasures(measureName);
|
|
405
|
-
} catch (error) {
|
|
406
|
-
console.debug("Stats: Performance measurement failed:", error);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
563
|
updatePanel(panel2, averageArray, precision = 2) {
|
|
410
564
|
if (!panel2 || averageArray.logs.length === 0)
|
|
411
565
|
return;
|
|
@@ -445,46 +599,65 @@ const _Stats = class _Stats2 {
|
|
|
445
599
|
}
|
|
446
600
|
}
|
|
447
601
|
}
|
|
448
|
-
updateAverages() {
|
|
449
|
-
this.addToAverage(this.totalCpuDuration, this.averageCpu);
|
|
450
|
-
this.addToAverage(this.totalGpuDuration, this.averageGpu);
|
|
451
|
-
if (this.info && this.totalGpuDurationCompute !== void 0) {
|
|
452
|
-
this.addToAverage(this.totalGpuDurationCompute, this.averageGpuCompute);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
addToAverage(value, averageArray) {
|
|
456
|
-
averageArray.logs.push(value);
|
|
457
|
-
if (averageArray.logs.length > this.samplesLog) {
|
|
458
|
-
averageArray.logs = averageArray.logs.slice(-this.samplesLog);
|
|
459
|
-
}
|
|
460
|
-
averageArray.graph.push(value);
|
|
461
|
-
if (averageArray.graph.length > this.samplesGraph) {
|
|
462
|
-
averageArray.graph = averageArray.graph.slice(-this.samplesGraph);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
602
|
get domElement() {
|
|
466
603
|
return this.dom;
|
|
467
604
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
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();
|
|
485
652
|
}
|
|
486
653
|
};
|
|
487
654
|
_Stats.Panel = panel.Panel;
|
|
655
|
+
_Stats.PanelTexture = panelTexture.PanelTexture;
|
|
488
656
|
let Stats = _Stats;
|
|
489
|
-
|
|
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;
|
|
490
663
|
//# sourceMappingURL=main.cjs.map
|