@zkmake/three-meter 0.13.1 → 0.13.3

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.
@@ -152,11 +152,97 @@ const computeFrameStats = (intervals) => {
152
152
  refreshHz: refreshFrom(intervals)
153
153
  });
154
154
  };
155
+ // src/core/gpu-busy.ts
156
+ const FRAME_UID = /:f(\d+)$/;
157
+ /**
158
+ * The newest frame's busy ms: its passes' `[begin, end]` intervals (ns),
159
+ * merged. `null` when no pass of it has a usable pair.
160
+ */
161
+ const latestFrameBusyMs = (offsets, times) => {
162
+ let frame = -1;
163
+ const byFrame = /* @__PURE__ */ new Map();
164
+ for (const [uid, offset] of offsets) {
165
+ const match = FRAME_UID.exec(uid);
166
+ const begin = times[offset];
167
+ const end = times[offset + 1];
168
+ if (!match || begin === void 0 || end === void 0 || begin === 0n || end < begin) continue;
169
+ const id = Number(match[1]);
170
+ const intervals = byFrame.get(id) ?? [];
171
+ intervals.push([begin, end]);
172
+ byFrame.set(id, intervals);
173
+ frame = Math.max(frame, id);
174
+ }
175
+ const intervals = byFrame.get(frame);
176
+ if (!intervals) return null;
177
+ intervals.sort((a, b) => a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0);
178
+ let busy = 0n;
179
+ let [start, stop] = intervals[0];
180
+ for (const [begin, end] of intervals.slice(1)) if (begin <= stop) stop = end > stop ? end : stop;
181
+ else {
182
+ busy += stop - start;
183
+ start = begin;
184
+ stop = end;
185
+ }
186
+ busy += stop - start;
187
+ return Number(busy) / 1e6;
188
+ };
189
+ const isTimestampPool = (pool) => {
190
+ const candidate = pool;
191
+ return candidate?.queryOffsets instanceof Map && typeof candidate._resolveQueries === "function" && typeof candidate.resultBuffer?.getMappedRange === "function";
192
+ };
193
+ /** Wraps a WebGPU render timestamp pool, or `null` when it isn't one. */
194
+ const tapTimestampPool = (pool) => {
195
+ if (!isTimestampPool(pool) || !pool.resultBuffer) return null;
196
+ const buffer = pool.resultBuffer;
197
+ const resolve = pool._resolveQueries;
198
+ const getMappedRange = buffer.getMappedRange;
199
+ let offsets = null;
200
+ let latest = null;
201
+ pool._resolveQueries = function() {
202
+ offsets = new Map(this.queryOffsets);
203
+ return resolve.call(this);
204
+ };
205
+ buffer.getMappedRange = function(offset, size) {
206
+ const range = getMappedRange.call(this, offset, size);
207
+ if (offsets) {
208
+ try {
209
+ latest = latestFrameBusyMs(offsets, new BigUint64Array(range)) ?? latest;
210
+ } catch {}
211
+ offsets = null;
212
+ }
213
+ return range;
214
+ };
215
+ return {
216
+ take() {
217
+ const ms = latest;
218
+ latest = null;
219
+ return ms;
220
+ },
221
+ detach() {
222
+ pool._resolveQueries = resolve;
223
+ buffer.getMappedRange = getMappedRange;
224
+ }
225
+ };
226
+ };
155
227
  // src/core/gpu-timer.ts
228
+ /**
229
+ * Real GPU frame timing.
230
+ *
231
+ * WebGPU: Three's `trackTimestamp` + `resolveTimestampsAsync` (ms, a frame or
232
+ * two late), read as busy time through `gpu-busy.ts` since three's own number
233
+ * sums overlapping passes. Never calls `getExtension`: that is what remounted
234
+ * the canvas.
235
+ *
236
+ * WebGL2 fallback (Safari without WebGPU, or a forced GL backend):
237
+ * `EXT_disjoint_timer_query_webgl2`, same pool-of-queries pattern as the
238
+ * platform-typing monitor.
239
+ */
156
240
  var GpuTimer = class GpuTimer {
157
241
  lastMs = 0;
158
242
  webgpu;
159
243
  webgpuInFlight = false;
244
+ tappedPool = null;
245
+ tap = null;
160
246
  gl;
161
247
  ext;
162
248
  free = [];
@@ -216,18 +302,31 @@ var GpuTimer = class GpuTimer {
216
302
  }
217
303
  this.free.length = 0;
218
304
  this.pending.length = 0;
305
+ this.tap?.detach();
306
+ this.tap = null;
307
+ this.tappedPool = null;
219
308
  }
220
309
  pollWebgpu() {
221
310
  const resolve = this.webgpu?.resolveTimestampsAsync;
222
311
  if (!resolve || this.webgpuInFlight) return;
312
+ this.tapPool();
223
313
  this.webgpuInFlight = true;
224
314
  resolve.call(this.webgpu, "render").then((ms) => {
225
- if (typeof ms === "number" && Number.isFinite(ms)) this.lastMs = ms;
315
+ if (this.tap) this.lastMs = this.tap.take() ?? this.lastMs;
316
+ else if (typeof ms === "number" && Number.isFinite(ms)) this.lastMs = ms;
226
317
  this.webgpuInFlight = false;
227
318
  }).catch(() => {
228
319
  this.webgpuInFlight = false;
229
320
  });
230
321
  }
322
+ /** three makes the render pool on the first timed frame, and anew after a reset. */
323
+ tapPool() {
324
+ const pool = (this.webgpu?.backend)?.timestampQueryPool?.render;
325
+ if (!pool || pool === this.tappedPool) return;
326
+ this.tap?.detach();
327
+ this.tappedPool = pool;
328
+ this.tap = tapTimestampPool(pool);
329
+ }
231
330
  pollWebgl() {
232
331
  if (!this.gl || !this.ext) return;
233
332
  if (this.gl.getParameter(this.ext.GPU_DISJOINT_EXT)) {
@@ -698,4 +797,4 @@ var PerformanceMonitor = class {
698
797
  };
699
798
  export { RingBuffer as n, PerformanceMonitor as t };
700
799
 
701
- //# sourceMappingURL=performance-monitor-CKAI0-Dp.js.map
800
+ //# sourceMappingURL=performance-monitor-Dj5H2VXT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-monitor-Dj5H2VXT.js","names":[],"sources":["../src/core/environment.ts","../src/core/frame-stats.ts","../src/core/gpu-busy.ts","../src/core/gpu-timer.ts","../src/core/ring-buffer.ts","../src/core/scene-cost.ts","../src/core/performance-monitor.ts"],"sourcesContent":["/**\n * What the monitor is running on: three revision, rendering backend, GPU.\n * Read from the renderer and the page, never from an import of three.\n *\n * `WebGPURenderer` settles its backend in `init()`, so until then the backend\n * reads `null`; callers poll and the monitor caches once it is known.\n */\nimport type { Environment, PerfRenderer, RenderBackend } from \"./types.ts\";\n\ntype BackendShape = {\n device?: { adapterInfo?: AdapterInfoShape } | null;\n gl?: unknown;\n isWebGLBackend?: boolean;\n isWebGPUBackend?: boolean;\n parameters?: { forceWebGL?: boolean };\n};\n\ntype AdapterInfoShape = {\n architecture?: string;\n description?: string;\n device?: string;\n vendor?: string;\n};\n\ntype DebugRendererInfoExt = { readonly UNMASKED_RENDERER_WEBGL: number };\n\n/** three sets `window.__THREE__` to its revision on import (and warns on a second copy). */\nconst readThreeRevision = (): string | null => {\n const revision = (globalThis as { __THREE__?: unknown }).__THREE__;\n\n return typeof revision === \"string\" && revision !== \"\" ? revision : null;\n};\n\n/**\n * Trim a WebGL renderer string to the part a person recognises. Chrome wraps\n * it in ANGLE, e.g. `ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 (0x00002786)\n * Direct3D11 vs_5_0 ps_5_0, D3D11)` or `ANGLE (Apple, ANGLE Metal Renderer:\n * Apple M3 Pro, Unspecified Version)`.\n */\nconst cleanGpuName = (raw: string): string => {\n let name = raw.trim();\n const angle = /^ANGLE \\((.*)\\)$/.exec(name);\n\n if (angle) {\n const parts = angle[1]!.split(\", \");\n name = parts[1] ?? parts[0]!;\n }\n\n return name\n .replace(/^ANGLE [\\w ]+ Renderer: /, \"\")\n .replace(/ \\(0x[0-9a-f]+\\)/i, \"\")\n .replace(/ (Direct3D\\d*|OpenGL|Vulkan|Metal)\\b.*$/, \"\")\n .trim();\n};\n\nconst webglGpuName = (gl: WebGLRenderingContext | WebGL2RenderingContext): string | null => {\n // Firefox deprecates the extension but already returns the unmasked name from RENDERER.\n const ext = gl.getExtension(\"WEBGL_debug_renderer_info\") as DebugRendererInfoExt | null;\n const raw = gl.getParameter(ext ? ext.UNMASKED_RENDERER_WEBGL : gl.RENDERER) as unknown;\n\n return typeof raw === \"string\" && raw !== \"\" && raw !== \"WebKit WebGL\" ? cleanGpuName(raw) : null;\n};\n\n/** WebGPU reports vendors lowercase (`apple`, `nvidia`). */\nconst VENDOR_NAMES: Record<string, string> = {\n amd: \"AMD\",\n apple: \"Apple\",\n arm: \"Arm\",\n intel: \"Intel\",\n nvidia: \"NVIDIA\",\n qualcomm: \"Qualcomm\",\n};\n\n/**\n * `GPUDevice.adapterInfo`. Chrome leaves `description` empty to limit\n * fingerprinting, so this is usually vendor + architecture: `Apple metal-3`.\n */\nconst webgpuGpuName = (info: AdapterInfoShape | undefined): string | null => {\n if (!info) {\n return null;\n }\n\n if (info.description) {\n return info.description;\n }\n\n const vendor = info.vendor ? (VENDOR_NAMES[info.vendor] ?? info.vendor) : \"\";\n const name = [vendor, info.architecture].filter(Boolean).join(\" \");\n\n return name === \"\" ? null : name;\n};\n\nconst isWebglContext = (value: unknown): value is WebGLRenderingContext | WebGL2RenderingContext =>\n (typeof WebGL2RenderingContext !== \"undefined\" && value instanceof WebGL2RenderingContext) ||\n (typeof WebGLRenderingContext !== \"undefined\" && value instanceof WebGLRenderingContext);\n\nconst webglBackend = (gl: WebGLRenderingContext | WebGL2RenderingContext): RenderBackend =>\n typeof WebGL2RenderingContext !== \"undefined\" && gl instanceof WebGL2RenderingContext\n ? \"webgl2\"\n : \"webgl\";\n\nconst readEnvironment = (renderer: PerfRenderer): Environment => {\n const three = readThreeRevision();\n const backend = renderer.backend as BackendShape | undefined;\n\n // WebGPURenderer. Read the backend's own fields: `getContext()` before\n // `init()` is what the GPU timer learned not to touch.\n if (backend) {\n if (backend.isWebGPUBackend) {\n const device = backend.device;\n\n return device\n ? { backend: \"webgpu\", fallback: false, gpu: webgpuGpuName(device.adapterInfo), three }\n : { backend: null, fallback: false, gpu: null, three };\n }\n\n if (backend.isWebGLBackend && isWebglContext(backend.gl)) {\n return {\n backend: webglBackend(backend.gl),\n fallback: backend.parameters?.forceWebGL !== true,\n gpu: webglGpuName(backend.gl),\n three,\n };\n }\n\n return { backend: null, fallback: false, gpu: null, three };\n }\n\n // WebGLRenderer.\n const context = renderer.getContext?.();\n\n return isWebglContext(context)\n ? { backend: webglBackend(context), fallback: false, gpu: webglGpuName(context), three }\n : { backend: null, fallback: false, gpu: null, three };\n};\n\nexport { cleanGpuName, readEnvironment };\n","/**\n * Stutter statistics over a window of frame intervals. Average FPS hides a\n * hitch every few seconds; these don't. Stalls (hidden tab, breakpoint) never\n * reach the window, so they don't count as hitches.\n */\nimport type { FrameStats } from \"./types.ts\";\n\n/** A frame over this multiple of the window's median interval is a hitch. */\nconst HITCH_FACTOR = 2;\n\n/** Fewer frames than this and the refresh rate reads `null`. */\nconst REFRESH_MIN_FRAMES = 60;\n\n/** Common display refresh rates. A reading within 4% of one snaps to it. */\nconst REFRESH_RATES = [30, 48, 50, 60, 72, 75, 90, 100, 120, 144, 165, 180, 240, 360];\n\nconst EMPTY: FrameStats = Object.freeze({\n frames: 0,\n hitches: 0,\n lowFps: 0,\n p99Ms: 0,\n refreshHz: null,\n});\n\n/**\n * The rate the loop runs at when it keeps up: the fastest tenth of frames,\n * not the average, so slow frames don't drag it down. That is the display's\n * refresh rate, or the app's own cap if it throttles itself.\n *\n * Intervals are averaged with their neighbour first. A frame that starts late\n * leaves a short interval after it, and on a real 120 Hz display those short\n * ones alone read as 125–127 Hz; each pair averages back to the vsync.\n */\nconst refreshFrom = (intervals: readonly number[]): number | null => {\n if (intervals.length < REFRESH_MIN_FRAMES) {\n return null;\n }\n\n const pairs = intervals.slice(1).map((interval, index) => (interval + intervals[index]!) / 2);\n pairs.sort((a, b) => a - b);\n const rate = 1000 / pairs[Math.floor(pairs.length * 0.1)]!;\n const nearest = REFRESH_RATES.reduce((best, candidate) =>\n Math.abs(candidate - rate) < Math.abs(best - rate) ? candidate : best,\n );\n\n return Math.abs(nearest - rate) / nearest <= 0.04 ? nearest : Math.round(rate);\n};\n\nconst computeFrameStats = (intervals: readonly number[]): FrameStats => {\n const frames = intervals.length;\n\n if (frames === 0) {\n return EMPTY;\n }\n\n const sorted = [...intervals].sort((a, b) => a - b);\n // Nearest rank: the smallest interval at or above 99% of frames.\n const p99Ms = sorted[Math.ceil(frames * 0.99) - 1]!;\n\n // 1% low: the mean rate across the slowest 1% of frames (at least one frame).\n const slowest = Math.max(1, Math.ceil(frames * 0.01));\n let slowSum = 0;\n\n for (let index = frames - slowest; index < frames; index += 1) {\n slowSum += sorted[index]!;\n }\n\n const middle = frames >> 1;\n const median = frames % 2 === 0 ? (sorted[middle - 1]! + sorted[middle]!) / 2 : sorted[middle]!;\n const threshold = median * HITCH_FACTOR;\n let hitches = 0;\n\n for (const interval of intervals) {\n if (interval > threshold) {\n hitches += 1;\n }\n }\n\n return Object.freeze({\n frames,\n hitches,\n lowFps: 1000 / (slowSum / slowest),\n p99Ms,\n refreshHz: refreshFrom(intervals),\n });\n};\n\nexport { computeFrameStats, HITCH_FACTOR };\n","/**\n * WebGPU frame time as the GPU was busy, not the sum of its passes.\n *\n * three's `resolveTimestampsAsync` adds up `end - start` of every pass in the\n * frame. Tile-based GPUs (Apple, most mobile) run passes overlapped, each\n * pass's span includes waiting on the ones before it, and the sum lands far\n * above the frame: keytar-hero's 15 passes read 14 ms, busy for 1.7 ms. Here\n * the raw begin/end pairs are merged, so overlap counts once.\n *\n * three throws those raw values away, so the tap wraps two members of its\n * timestamp pool (`_resolveQueries` for the uid → query offsets,\n * `resultBuffer.getMappedRange` for the times). Internal API: when the shape\n * isn't there, there's no tap and the caller keeps three's sum.\n */\n\n/** The members of three's `WebGPUTimestampQueryPool` the tap reads. */\ntype TimestampPool = {\n queryOffsets: Map<string, number>;\n _resolveQueries: () => Promise<unknown>;\n resultBuffer: { getMappedRange: (offset?: number, size?: number) => ArrayBuffer } | null;\n};\n\ntype PoolTap = {\n /** Busy ms of the newest frame resolved since the last take, else `null`. */\n take(): number | null;\n /** Puts the pool's own members back. */\n detach(): void;\n};\n\nconst FRAME_UID = /:f(\\d+)$/;\n\n/**\n * The newest frame's busy ms: its passes' `[begin, end]` intervals (ns),\n * merged. `null` when no pass of it has a usable pair.\n */\nconst latestFrameBusyMs = (offsets: Map<string, number>, times: BigUint64Array): number | null => {\n let frame = -1;\n const byFrame = new Map<number, [bigint, bigint][]>();\n\n for (const [uid, offset] of offsets) {\n const match = FRAME_UID.exec(uid);\n const begin = times[offset];\n const end = times[offset + 1];\n\n // An unwritten query reads 0; a pass that didn't run can't count.\n if (!match || begin === undefined || end === undefined || begin === 0n || end < begin) {\n continue;\n }\n\n const id = Number(match[1]);\n const intervals = byFrame.get(id) ?? [];\n intervals.push([begin, end]);\n byFrame.set(id, intervals);\n frame = Math.max(frame, id);\n }\n\n const intervals = byFrame.get(frame);\n\n if (!intervals) {\n return null;\n }\n\n intervals.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));\n\n let busy = 0n;\n let [start, stop] = intervals[0]!;\n\n for (const [begin, end] of intervals.slice(1)) {\n if (begin <= stop) {\n stop = end > stop ? end : stop;\n } else {\n busy += stop - start;\n start = begin;\n stop = end;\n }\n }\n\n busy += stop - start;\n\n return Number(busy) / 1e6;\n};\n\nconst isTimestampPool = (pool: unknown): pool is TimestampPool => {\n const candidate = pool as Partial<TimestampPool> | null | undefined;\n\n return (\n candidate?.queryOffsets instanceof Map &&\n typeof candidate._resolveQueries === \"function\" &&\n typeof candidate.resultBuffer?.getMappedRange === \"function\"\n );\n};\n\n/** Wraps a WebGPU render timestamp pool, or `null` when it isn't one. */\nconst tapTimestampPool = (pool: unknown): PoolTap | null => {\n if (!isTimestampPool(pool) || !pool.resultBuffer) {\n return null;\n }\n\n const buffer = pool.resultBuffer;\n const resolve = pool._resolveQueries;\n const getMappedRange = buffer.getMappedRange;\n let offsets: Map<string, number> | null = null;\n let latest: number | null = null;\n\n // three clears the offsets before it maps the buffer: copy them first. One\n // resolve is in flight at a time, so one copy is enough.\n pool._resolveQueries = function (this: TimestampPool) {\n offsets = new Map(this.queryOffsets);\n\n return resolve.call(this);\n };\n\n buffer.getMappedRange = function (this: unknown, offset?: number, size?: number) {\n const range = getMappedRange.call(this, offset, size);\n\n if (offsets) {\n try {\n latest = latestFrameBusyMs(offsets, new BigUint64Array(range)) ?? latest;\n } catch {\n // A shape this tap doesn't know: three's sum still stands.\n }\n\n offsets = null;\n }\n\n return range;\n };\n\n return {\n take() {\n const ms = latest;\n latest = null;\n\n return ms;\n },\n detach() {\n pool._resolveQueries = resolve;\n buffer.getMappedRange = getMappedRange;\n },\n };\n};\n\nexport { latestFrameBusyMs, tapTimestampPool };\nexport type { PoolTap };\n","/**\n * Real GPU frame timing.\n *\n * WebGPU: Three's `trackTimestamp` + `resolveTimestampsAsync` (ms, a frame or\n * two late), read as busy time through `gpu-busy.ts` since three's own number\n * sums overlapping passes. Never calls `getExtension`: that is what remounted\n * the canvas.\n *\n * WebGL2 fallback (Safari without WebGPU, or a forced GL backend):\n * `EXT_disjoint_timer_query_webgl2`, same pool-of-queries pattern as the\n * platform-typing monitor.\n */\nimport { type PoolTap, tapTimestampPool } from \"./gpu-busy.ts\";\nimport type { PerfRenderer } from \"./types.ts\";\n\ntype DisjointTimerQueryExt = {\n readonly GPU_DISJOINT_EXT: number;\n readonly TIME_ELAPSED_EXT: number;\n};\n\nclass GpuTimer {\n private lastMs = 0;\n private readonly webgpu: PerfRenderer | null;\n private webgpuInFlight = false;\n private tappedPool: unknown = null;\n private tap: PoolTap | null = null;\n private readonly gl: WebGL2RenderingContext | null;\n private readonly ext: DisjointTimerQueryExt | null;\n private readonly free: WebGLQuery[] = [];\n private readonly pending: WebGLQuery[] = [];\n private active: WebGLQuery | null = null;\n\n private constructor(\n webgpu: PerfRenderer | null,\n gl: WebGL2RenderingContext | null,\n ext: DisjointTimerQueryExt | null,\n poolSize: number,\n ) {\n this.webgpu = webgpu;\n this.gl = gl;\n this.ext = ext;\n\n if (!gl) {\n return;\n }\n\n for (let index = 0; index < poolSize; index += 1) {\n const query = gl.createQuery();\n\n if (query) {\n this.free.push(query);\n }\n }\n }\n\n static create(renderer: PerfRenderer, poolSize: number): GpuTimer | null {\n const backend = renderer.backend as { trackTimestamp?: boolean } | undefined;\n\n if (backend?.trackTimestamp && renderer.resolveTimestampsAsync) {\n return new GpuTimer(renderer, null, null, poolSize);\n }\n\n const context = renderer.getContext?.();\n\n if (!(context instanceof WebGL2RenderingContext)) {\n return null;\n }\n\n const ext = context.getExtension(\n \"EXT_disjoint_timer_query_webgl2\",\n ) as DisjointTimerQueryExt | null;\n\n return ext ? new GpuTimer(null, context, ext, poolSize) : null;\n }\n\n begin() {\n if (this.webgpu || !this.gl || !this.ext) {\n return;\n }\n\n const query = this.free.pop();\n\n if (!query) {\n this.active = null;\n\n return;\n }\n\n this.active = query;\n this.gl.beginQuery(this.ext.TIME_ELAPSED_EXT, query);\n }\n\n end() {\n if (this.webgpu || !this.gl || !this.ext || !this.active) {\n return;\n }\n\n this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);\n this.pending.push(this.active);\n this.active = null;\n }\n\n poll() {\n if (this.webgpu) {\n this.pollWebgpu();\n\n return;\n }\n\n this.pollWebgl();\n }\n\n getMs() {\n return this.lastMs;\n }\n\n dispose() {\n if (this.gl && this.ext && this.active) {\n this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);\n this.active = null;\n }\n\n if (this.gl) {\n for (const query of this.free) {\n this.gl.deleteQuery(query);\n }\n\n for (const query of this.pending) {\n this.gl.deleteQuery(query);\n }\n }\n\n this.free.length = 0;\n this.pending.length = 0;\n this.tap?.detach();\n this.tap = null;\n this.tappedPool = null;\n }\n\n private pollWebgpu() {\n const resolve = this.webgpu?.resolveTimestampsAsync;\n\n if (!resolve || this.webgpuInFlight) {\n return;\n }\n\n this.tapPool();\n this.webgpuInFlight = true;\n\n void resolve\n .call(this.webgpu, \"render\")\n .then((ms) => {\n if (this.tap) {\n // No new frame resolved (three handed back its last value): keep ours.\n this.lastMs = this.tap.take() ?? this.lastMs;\n } else if (typeof ms === \"number\" && Number.isFinite(ms)) {\n this.lastMs = ms;\n }\n\n this.webgpuInFlight = false;\n })\n .catch(() => {\n this.webgpuInFlight = false;\n });\n }\n\n /** three makes the render pool on the first timed frame, and anew after a reset. */\n private tapPool() {\n const backend = this.webgpu?.backend as\n | { timestampQueryPool?: { render?: unknown } }\n | undefined;\n const pool = backend?.timestampQueryPool?.render;\n\n if (!pool || pool === this.tappedPool) {\n return;\n }\n\n this.tap?.detach();\n this.tappedPool = pool;\n this.tap = tapTimestampPool(pool);\n }\n\n private pollWebgl() {\n if (!this.gl || !this.ext) {\n return;\n }\n\n const disjoint = this.gl.getParameter(this.ext.GPU_DISJOINT_EXT) as boolean;\n\n if (disjoint) {\n while (this.pending.length > 0) {\n this.free.push(this.pending.shift()!);\n }\n\n return;\n }\n\n while (this.pending.length > 0) {\n const query = this.pending[0]!;\n const ready = this.gl.getQueryParameter(query, this.gl.QUERY_RESULT_AVAILABLE) as boolean;\n\n if (!ready) {\n break;\n }\n\n this.pending.shift();\n const ns = this.gl.getQueryParameter(query, this.gl.QUERY_RESULT) as number;\n this.lastMs = ns / 1e6;\n this.free.push(query);\n }\n }\n}\n\nexport { GpuTimer };\n","/**\n * Fixed-capacity numeric ring buffer. Backs the per-frame timing history the\n * view reads to draw sparklines. Push is O(1); `toArray()` returns values in\n * chronological (oldest → newest) order.\n */\nclass RingBuffer {\n private readonly data: Float32Array;\n private readonly capacity: number;\n private head = 0;\n private count = 0;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.data = new Float32Array(capacity);\n }\n\n push(value: number) {\n this.data[this.head] = value;\n this.head = (this.head + 1) % this.capacity;\n\n if (this.count < this.capacity) {\n this.count += 1;\n }\n }\n\n /** Values oldest → newest. Length grows up to capacity as samples accumulate. */\n toArray(): number[] {\n const out = Array.from<number>({ length: this.count });\n const start = (this.head - this.count + this.capacity) % this.capacity;\n\n for (let index = 0; index < this.count; index += 1) {\n out[index] = this.data[(start + index) % this.capacity]!;\n }\n\n return out;\n }\n\n clear() {\n this.head = 0;\n this.count = 0;\n }\n}\n\nexport { RingBuffer };\n","/**\n * Where a frame's draw calls and triangles come from, estimated from the\n * scene graph the way three's renderer walks it: hidden objects, other\n * layers and anything outside the camera's frustum are left out; each\n * visible material (or material group) is one draw call, two for a\n * transparent double-sided material. Main pass only: shadow maps and\n * post-processing passes aren't counted.\n *\n * Structural like the rest of core: no import of three, every field read\n * defensively, since this runs against whatever the app renders.\n */\nimport type { CostEntry, SceneCost } from \"./types.ts\";\n\ntype Elements = ArrayLike<number>;\n\ntype Sphere = { center: { x: number; y: number; z: number }; radius: number };\n\ntype GeometryShape = {\n attributes?: { position?: { count: number } };\n boundingSphere?: Sphere | null;\n drawRange?: { count: number; start: number };\n groups?: { count: number; materialIndex?: number; start: number }[];\n index?: { count: number } | null;\n name?: string;\n uuid?: string;\n};\n\ntype MaterialShape = {\n uuid?: string;\n forceSinglePass?: boolean;\n name?: string;\n side?: number;\n transparent?: boolean;\n type?: string;\n visible?: boolean;\n};\n\ntype ObjectShape = {\n boundingSphere?: Sphere | null;\n count?: number;\n frustumCulled?: boolean;\n geometry?: GeometryShape;\n isInstancedMesh?: boolean;\n isLine?: boolean;\n isMesh?: boolean;\n isPoints?: boolean;\n isSprite?: boolean;\n layers?: { mask: number };\n material?: MaterialShape | MaterialShape[];\n matrixWorld?: { elements: Elements };\n name?: string;\n type?: string;\n};\n\ntype CameraShape = {\n coordinateSystem?: number;\n layers?: { mask: number };\n matrixWorldInverse?: { elements: Elements };\n projectionMatrix?: { elements: Elements };\n reversedDepth?: boolean;\n};\n\ntype SceneShape = { traverseVisible?: (callback: (object: ObjectShape) => void) => void };\n\n/** three's `DoubleSide` and `WebGPUCoordinateSystem`. */\nconst DOUBLE_SIDE = 2;\nconst WEBGPU_COORDINATES = 2001;\n\ntype Plane = [number, number, number, number];\n\n/** Column-major `a × b`, as three stores matrices. */\nconst multiply = (a: Elements, b: Elements) => {\n const out = Array.from<number>({ length: 16 });\n\n for (let column = 0; column < 4; column += 1) {\n for (let row = 0; row < 4; row += 1) {\n let sum = 0;\n\n for (let k = 0; k < 4; k += 1) {\n sum += a[k * 4 + row]! * b[column * 4 + k]!;\n }\n\n out[column * 4 + row] = sum;\n }\n }\n\n return out;\n};\n\nconst normalize = (plane: Plane): Plane => {\n const length = Math.hypot(plane[0], plane[1], plane[2]) || 1;\n\n return [plane[0] / length, plane[1] / length, plane[2] / length, plane[3] / length];\n};\n\n/** Mirrors three's `Frustum.setFromProjectionMatrix`. Near and far only where the depth range is known. */\nconst frustumPlanes = (camera: CameraShape): Plane[] | null => {\n if (!camera.projectionMatrix || !camera.matrixWorldInverse) {\n return null;\n }\n\n const m = multiply(camera.projectionMatrix.elements, camera.matrixWorldInverse.elements);\n const row = (index: number): Plane => [m[index]!, m[index + 4]!, m[index + 8]!, m[index + 12]!];\n const [r0, r1, r2, r3] = [row(0), row(1), row(2), row(3)];\n const add = (a: Plane, b: Plane): Plane => [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]];\n const sub = (a: Plane, b: Plane): Plane => [a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]];\n\n const planes = [sub(r3, r0), add(r3, r0), add(r3, r1), sub(r3, r1)];\n\n if (!camera.reversedDepth) {\n planes.push(sub(r3, r2), camera.coordinateSystem === WEBGPU_COORDINATES ? r2 : add(r3, r2));\n }\n\n return planes.map(normalize);\n};\n\nconst inFrustum = (object: ObjectShape, planes: Plane[] | null) => {\n const sphere = object.boundingSphere ?? object.geometry?.boundingSphere;\n const e = object.matrixWorld?.elements;\n\n // three computes bounding spheres lazily while rendering; without one, count the object.\n if (!planes || !sphere || !e) {\n return true;\n }\n\n const { x, y, z } = sphere.center;\n const cx = e[0]! * x + e[4]! * y + e[8]! * z + e[12]!;\n const cy = e[1]! * x + e[5]! * y + e[9]! * z + e[13]!;\n const cz = e[2]! * x + e[6]! * y + e[10]! * z + e[14]!;\n const scale = Math.sqrt(\n Math.max(\n e[0]! ** 2 + e[1]! ** 2 + e[2]! ** 2,\n e[4]! ** 2 + e[5]! ** 2 + e[6]! ** 2,\n e[8]! ** 2 + e[9]! ** 2 + e[10]! ** 2,\n ),\n );\n const radius = sphere.radius * scale;\n\n // three's own test, `distance < -radius`. Written this way round a NaN plane (a camera with a\n // zero-size aspect, say) keeps the object, as three does, rather than hiding everything.\n return !planes.some(([a, b, c, d]) => a * cx + b * cy + c * cz + d < -radius);\n};\n\nconst layersMatch = (object: ObjectShape, camera: CameraShape) =>\n !object.layers || !camera.layers || (object.layers.mask & camera.layers.mask) !== 0;\n\nconst passes = (material: MaterialShape) =>\n material.transparent === true &&\n material.side === DOUBLE_SIDE &&\n material.forceSinglePass !== true\n ? 2\n : 1;\n\n/** Vertices a draw covers, clipped to `drawRange` and, when given, a group. */\nconst drawnVertices = (\n geometry: GeometryShape,\n group?: { count: number; start: number },\n): number => {\n const total = geometry.index?.count ?? geometry.attributes?.position?.count ?? 0;\n const rangeStart = geometry.drawRange?.start ?? 0;\n const rangeEnd = Math.min(total, rangeStart + (geometry.drawRange?.count ?? Infinity));\n const start = Math.max(rangeStart, group?.start ?? 0);\n const end = Math.min(rangeEnd, group ? group.start + group.count : Infinity);\n\n return Math.max(0, end - start);\n};\n\ntype Draw = { calls: number; material: MaterialShape; triangles: number };\n\n/** One draw per visible material, or per group when the material is an array. */\nconst drawsOf = (object: ObjectShape): Draw[] => {\n const { geometry, material } = object;\n\n if (!geometry || !material) {\n return [];\n }\n\n const instances = object.isInstancedMesh ? (object.count ?? 1) : 1;\n const trianglesFor = (vertices: number) =>\n object.isMesh ? Math.floor(vertices / 3) * instances : 0;\n\n if (Array.isArray(material)) {\n const draws: Draw[] = [];\n\n for (const group of geometry.groups ?? []) {\n const groupMaterial = material[group.materialIndex ?? 0];\n\n if (groupMaterial && groupMaterial.visible !== false) {\n const count = passes(groupMaterial);\n draws.push({\n calls: count,\n material: groupMaterial,\n triangles: trianglesFor(drawnVertices(geometry, group)) * count,\n });\n }\n }\n\n return draws;\n }\n\n return material.visible === false\n ? []\n : [\n {\n calls: passes(material),\n material,\n // A second pass draws the triangles again, and three's info counts them again.\n triangles: trianglesFor(drawnVertices(geometry)) * passes(material),\n },\n ];\n};\n\nconst objectLabel = (object: ObjectShape) =>\n object.name || object.geometry?.name || object.type || \"Object\";\n\nconst materialLabel = (material: MaterialShape) => material.name || material.type || \"Material\";\n\n/** A stable id for objects without a `uuid`, so keys survive between walks. */\nconst ids = new WeakMap<object, string>();\nlet nextId = 0;\n\nconst idOf = (value: object & { uuid?: string }) => {\n if (value.uuid) {\n return value.uuid;\n }\n\n let id = ids.get(value);\n\n if (!id) {\n nextId += 1;\n id = `#${nextId}`;\n ids.set(value, id);\n }\n\n return id;\n};\n\nconst entryFor = (groups: Map<unknown, CostEntry>, group: unknown, key: string, label: string) => {\n let entry = groups.get(group);\n\n if (!entry) {\n entry = { calls: 0, instances: 0, key, label, objects: [], triangles: 0 };\n groups.set(group, entry);\n }\n\n return entry;\n};\n\nconst byCost = (a: CostEntry, b: CostEntry) => b.calls - a.calls || b.triangles - a.triangles;\n\n/** Same label and geometry is one mesh row. */\nconst meshKeyOf = (object: ObjectShape) =>\n `mesh:${objectLabel(object)}\\u0000${object.geometry?.uuid ?? \"\"}`;\n\nconst materialsOf = (object: ObjectShape) =>\n object.material === undefined\n ? []\n : Array.isArray(object.material)\n ? object.material\n : [object.material];\n\n/**\n * Every drawable object in the scene that belongs to a row's `key`, on screen\n * or not: hiding a row has to catch the copies that orbit into view later.\n * Skips objects that are already hidden, like three does.\n */\nconst objectsForKey = (scene: unknown, key: string): unknown[] => {\n const root = scene as SceneShape;\n const found: unknown[] = [];\n\n if (typeof root?.traverseVisible !== \"function\") {\n return found;\n }\n\n root.traverseVisible((object) => {\n const drawable = object.isMesh || object.isLine || object.isPoints || object.isSprite;\n\n if (!drawable) {\n return;\n }\n\n const matches = key.startsWith(\"mesh:\")\n ? meshKeyOf(object) === key\n : materialsOf(object).some((material) => `material:${idOf(material)}` === key);\n\n if (matches) {\n found.push(object);\n }\n });\n\n return found;\n};\n\nconst computeSceneCost = (scene: unknown, camera: unknown): SceneCost | null => {\n const root = scene as SceneShape;\n const view = camera as CameraShape;\n\n if (typeof root?.traverseVisible !== \"function\") {\n return null;\n }\n\n const planes = frustumPlanes(view);\n // Same label and geometry is one row, so 500 unmerged copies read as \"tree ×500\".\n const meshes = new Map<unknown, CostEntry>();\n const materials = new Map<unknown, CostEntry>();\n let calls = 0;\n let triangles = 0;\n\n root.traverseVisible((object) => {\n const drawable = object.isMesh || object.isLine || object.isPoints || object.isSprite;\n\n if (!drawable || !layersMatch(object, view)) {\n return;\n }\n\n if (object.frustumCulled !== false && !object.isSprite && !inFrustum(object, planes)) {\n return;\n }\n\n const instances = object.isInstancedMesh ? (object.count ?? 1) : 1;\n const label = objectLabel(object);\n const meshKey = meshKeyOf(object);\n\n const draws = drawsOf(object);\n\n if (draws.length === 0) {\n return;\n }\n\n const mesh = entryFor(meshes, meshKey, meshKey, label);\n mesh.objects.push(object);\n mesh.instances += instances;\n // A multi-material object can draw one material in several groups; list it once per material.\n const listed = new Set<MaterialShape>();\n\n for (const draw of draws) {\n calls += draw.calls;\n triangles += draw.triangles;\n mesh.calls += draw.calls;\n mesh.triangles += draw.triangles;\n\n const material = entryFor(\n materials,\n draw.material,\n `material:${idOf(draw.material)}`,\n materialLabel(draw.material),\n );\n material.calls += draw.calls;\n material.triangles += draw.triangles;\n\n if (!listed.has(draw.material)) {\n listed.add(draw.material);\n material.objects.push(object);\n material.instances += instances;\n }\n }\n });\n\n return {\n calls,\n materials: [...materials.values()].sort(byCost),\n meshes: [...meshes.values()].sort(byCost),\n triangles,\n };\n};\n\nexport { computeSceneCost, objectsForKey };\n","import { readEnvironment } from \"./environment.ts\";\nimport { computeFrameStats } from \"./frame-stats.ts\";\nimport { GpuTimer } from \"./gpu-timer.ts\";\nimport { RingBuffer } from \"./ring-buffer.ts\";\nimport { computeSceneCost, objectsForKey } from \"./scene-cost.ts\";\nimport type {\n CostEntry,\n Environment,\n FrameStats,\n PerfRenderer,\n PerformanceMonitorOptions,\n Sample,\n SceneCost,\n TimingMetric,\n} from \"./types.ts\";\n\nconst DEFAULT_GPU_POOL_SIZE = 5;\n/** One monitor per renderer: a second would stack the `render` patch and double-count passes. */\nconst ATTACHED = new WeakSet<PerfRenderer>();\nconst DEFAULT_HISTORY_SIZE = 120;\nconst DEFAULT_FRAME_STATS_SIZE = 1000;\nconst FPS_SMOOTHING = 0.1;\n/**\n * A frame interval past this is a stall (hidden tab, breakpoint, laptop lid),\n * not a slow frame. It is left out of FPS so one gap doesn't flatten the\n * graph's scale for the whole history window.\n */\nconst STALL_MS = 1000;\n\nconst frameCalls = (info: PerfRenderer[\"info\"]) => info.render.drawCalls ?? info.render.calls;\n\nconst programCount = (info: PerfRenderer[\"info\"]) =>\n info.memory.programs ?? info.programs?.length ?? 0;\n\n/**\n * Collector of three.js frame metrics. Bracket each frame with {@link begin}/\n * {@link end}, or let {@link wrapAnimationLoop} or the R3F `PerfSampler` do it.\n * Works on WebGPURenderer (drawCalls, memory.programs, timestamp queries) and\n * on a WebGL renderer (calls, programs[], timer-query ext).\n *\n * While attached, `renderer.info.autoReset` is off and `info` is reset in\n * {@link begin}; host code that reads `renderer.info` mid-frame sees this\n * frame's counts only. {@link dispose} restores both.\n *\n * CPU time runs from {@link begin} to the return of the frame's last\n * `render()` call, which the `render` patch stamps. So it holds even when\n * {@link end} is only reached on the next tick, as in the R3F sampler: it is\n * the JS work of the frame, not the interval to the next one.\n */\nclass PerformanceMonitor {\n private readonly renderer: PerfRenderer;\n private readonly gpuTimer: GpuTimer | null;\n private readonly originalRender: PerfRenderer[\"render\"];\n private renderPasses = 0;\n private lastRenderEndAt: number | null = null;\n private readonly fpsHistory: RingBuffer;\n private readonly cpuHistory: RingBuffer;\n private readonly gpuHistory: RingBuffer;\n private readonly frameIntervals: RingBuffer;\n private frameStats: FrameStats | null = null;\n /** The render call with the most draw calls this frame, and the scene and camera it drew. */\n private mainPassCalls = -1;\n private mainPass: { camera: WeakRef<object>; scene: WeakRef<object> } | null = null;\n private cpuStart = 0;\n private lastBeginAt: number | null = null;\n private frameFps = 0;\n private smoothedFps = 0;\n private sample: Sample;\n private environment: Environment | null = null;\n\n constructor(options: PerformanceMonitorOptions) {\n const {\n renderer,\n trackGPU = true,\n gpuQueryPoolSize = DEFAULT_GPU_POOL_SIZE,\n historySize = DEFAULT_HISTORY_SIZE,\n frameStatsSize = DEFAULT_FRAME_STATS_SIZE,\n } = options;\n\n if (ATTACHED.has(renderer)) {\n throw new Error(\n \"three-meter: a PerformanceMonitor is already attached to this renderer. dispose() it first.\",\n );\n }\n\n ATTACHED.add(renderer);\n this.renderer = renderer;\n renderer.info.autoReset = false;\n this.originalRender = renderer.render;\n\n renderer.render = (...args: never[]) => {\n this.renderPasses += 1;\n const callsBefore = frameCalls(renderer.info);\n\n try {\n return this.originalRender.apply(renderer, args);\n } finally {\n this.lastRenderEndAt = performance.now();\n this.notePass(args[0], args[1], frameCalls(renderer.info) - callsBefore);\n }\n };\n\n this.gpuTimer = trackGPU ? GpuTimer.create(renderer, gpuQueryPoolSize) : null;\n this.fpsHistory = new RingBuffer(historySize);\n this.cpuHistory = new RingBuffer(historySize);\n this.gpuHistory = new RingBuffer(historySize);\n this.frameIntervals = new RingBuffer(frameStatsSize);\n this.sample = this.buildEmptySample();\n }\n\n begin() {\n const now = performance.now();\n\n if (this.lastBeginAt !== null) {\n const frameMs = now - this.lastBeginAt;\n\n // A stall keeps the previous reading rather than logging a near-zero frame.\n if (frameMs > 0 && frameMs <= STALL_MS) {\n this.frameFps = 1000 / frameMs;\n this.frameIntervals.push(frameMs);\n this.frameStats = null;\n }\n }\n\n this.lastBeginAt = now;\n this.cpuStart = now;\n this.lastRenderEndAt = null;\n this.renderPasses = 0;\n this.mainPassCalls = -1;\n this.renderer.info.reset();\n this.gpuTimer?.begin();\n }\n\n end() {\n const now = performance.now();\n // Without a render this frame there is nothing better than \"until end()\".\n const cpu = (this.lastRenderEndAt ?? now) - this.cpuStart;\n\n this.gpuTimer?.end();\n this.gpuTimer?.poll();\n\n const gpuMs = this.gpuTimer?.getMs() ?? 0;\n\n this.smoothedFps =\n this.smoothedFps === 0\n ? this.frameFps\n : this.smoothedFps + (this.frameFps - this.smoothedFps) * FPS_SMOOTHING;\n\n this.fpsHistory.push(this.frameFps);\n this.cpuHistory.push(cpu);\n this.gpuHistory.push(gpuMs);\n\n const info = this.renderer.info;\n\n this.sample = Object.freeze({\n cpu,\n fps: this.smoothedFps,\n gpu: { available: this.gpuTimer !== null, ms: gpuMs },\n render: {\n calls: frameCalls(info),\n lines: info.render.lines,\n passes: this.renderPasses,\n points: info.render.points,\n triangles: info.render.triangles,\n },\n resources: {\n geometries: info.memory.geometries,\n programs: programCount(info),\n textures: info.memory.textures,\n },\n });\n }\n\n getSample(): Sample {\n return this.sample;\n }\n\n getHistory(metric: TimingMetric): readonly number[] {\n switch (metric) {\n case \"fps\":\n return this.fpsHistory.toArray();\n case \"cpu\":\n return this.cpuHistory.toArray();\n case \"gpu\":\n return this.gpuHistory.toArray();\n }\n }\n\n /** 1% low, p99 frame time and hitches. Computed on read, cached until the next frame. */\n getFrameStats(): FrameStats {\n this.frameStats ??= computeFrameStats(this.frameIntervals.toArray());\n\n return this.frameStats;\n }\n\n /**\n * Where the main pass's draw calls and triangles come from, by mesh and by\n * material. Walks the scene graph, so read it on demand (the HUD does, at\n * 2 Hz while its section is open), not every frame. `null` before the first\n * render, or once the scene is garbage collected.\n */\n getSceneCost(): SceneCost | null {\n const scene = this.mainPass?.scene.deref();\n const camera = this.mainPass?.camera.deref();\n\n return scene && camera ? computeSceneCost(scene, camera) : null;\n }\n\n /**\n * Every visible object in the main scene behind a {@link CostEntry}'s `key`,\n * including ones outside the camera, which `getSceneCost()` leaves out.\n */\n getObjectsForKey(key: string): unknown[] {\n const scene = this.mainPass?.scene.deref();\n\n return scene ? objectsForKey(scene, key) : [];\n }\n\n /**\n * three revision, backend and GPU name. Cached once the backend is known;\n * before `WebGPURenderer.init()` settles it, `backend` is `null` and the\n * next call reads again.\n */\n getEnvironment(): Environment {\n if (this.environment) {\n return this.environment;\n }\n\n const environment = Object.freeze(readEnvironment(this.renderer));\n\n if (environment.backend !== null) {\n this.environment = environment;\n }\n\n return environment;\n }\n\n dispose() {\n ATTACHED.delete(this.renderer);\n this.renderer.info.autoReset = true;\n this.renderer.render = this.originalRender;\n this.gpuTimer?.dispose();\n this.fpsHistory.clear();\n this.cpuHistory.clear();\n this.gpuHistory.clear();\n this.frameIntervals.clear();\n this.frameStats = null;\n this.mainPass = null;\n }\n\n /**\n * The main pass is the render call that drew the most, so a post-processing\n * quad rendered last doesn't stand in for the scene. Weak references: the\n * monitor never keeps a scene alive.\n */\n private notePass(scene: unknown, camera: unknown, calls: number) {\n if (\n calls > this.mainPassCalls &&\n typeof scene === \"object\" &&\n scene !== null &&\n typeof camera === \"object\" &&\n camera !== null\n ) {\n this.mainPassCalls = calls;\n this.mainPass = { camera: new WeakRef(camera), scene: new WeakRef(scene) };\n }\n }\n\n private buildEmptySample(): Sample {\n return Object.freeze({\n cpu: 0,\n fps: 0,\n gpu: { available: this.gpuTimer !== null, ms: 0 },\n render: { calls: 0, lines: 0, passes: 0, points: 0, triangles: 0 },\n resources: { geometries: 0, programs: 0, textures: 0 },\n });\n }\n}\n\nexport { PerformanceMonitor };\n"],"mappings":"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"}
package/dist/react.js CHANGED
@@ -1,5 +1,5 @@
1
- import { t as PerformanceMonitor } from "./performance-monitor-CKAI0-Dp.js";
2
- import { t as mountPerfHud } from "./mount-perf-hud-DZ1_LUZ8.js";
1
+ import { t as PerformanceMonitor } from "./performance-monitor-Dj5H2VXT.js";
2
+ import { t as mountPerfHud } from "./mount-perf-hud-BRihOM2d.js";
3
3
  import { useEffect, useRef } from "react";
4
4
  import { useFrame, useThree } from "@react-three/fiber";
5
5
  // src/react/monitor-store.ts
package/dist/ui.js CHANGED
@@ -1 +1 @@
1
- export { l as DEFAULT_STORAGE_KEY, u as HudSettings, d as HudTheme, o as PERF_HUD_STYLES, n as PerformanceView, f as THEME_MODES, c as dockPanel, i as formatQuality, r as formatReport, s as injectStyles, p as isThemeMode, a as mountDevPanel, t as mountPerfHud, m as resolveBudgets } from "./mount-perf-hud-DZ1_LUZ8.js";
1
+ export { l as DEFAULT_STORAGE_KEY, u as HudSettings, d as HudTheme, o as PERF_HUD_STYLES, n as PerformanceView, f as THEME_MODES, c as dockPanel, i as formatQuality, r as formatReport, s as injectStyles, p as isThemeMode, a as mountDevPanel, t as mountPerfHud, m as resolveBudgets } from "./mount-perf-hud-BRihOM2d.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zkmake/three-meter",
3
- "version": "0.13.1",
3
+ "version": "0.13.3",
4
4
  "description": "Zero-dependency three.js frame metrics (FPS, CPU, GPU, draw calls) with a dockable HUD. Vanilla three and React Three Fiber adapters.",
5
5
  "keywords": [
6
6
  "devtools",
@@ -1 +0,0 @@
1
- {"version":3,"file":"performance-monitor-CKAI0-Dp.js","names":[],"sources":["../src/core/environment.ts","../src/core/frame-stats.ts","../src/core/gpu-timer.ts","../src/core/ring-buffer.ts","../src/core/scene-cost.ts","../src/core/performance-monitor.ts"],"sourcesContent":["/**\n * What the monitor is running on: three revision, rendering backend, GPU.\n * Read from the renderer and the page, never from an import of three.\n *\n * `WebGPURenderer` settles its backend in `init()`, so until then the backend\n * reads `null`; callers poll and the monitor caches once it is known.\n */\nimport type { Environment, PerfRenderer, RenderBackend } from \"./types.ts\";\n\ntype BackendShape = {\n device?: { adapterInfo?: AdapterInfoShape } | null;\n gl?: unknown;\n isWebGLBackend?: boolean;\n isWebGPUBackend?: boolean;\n parameters?: { forceWebGL?: boolean };\n};\n\ntype AdapterInfoShape = {\n architecture?: string;\n description?: string;\n device?: string;\n vendor?: string;\n};\n\ntype DebugRendererInfoExt = { readonly UNMASKED_RENDERER_WEBGL: number };\n\n/** three sets `window.__THREE__` to its revision on import (and warns on a second copy). */\nconst readThreeRevision = (): string | null => {\n const revision = (globalThis as { __THREE__?: unknown }).__THREE__;\n\n return typeof revision === \"string\" && revision !== \"\" ? revision : null;\n};\n\n/**\n * Trim a WebGL renderer string to the part a person recognises. Chrome wraps\n * it in ANGLE, e.g. `ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 (0x00002786)\n * Direct3D11 vs_5_0 ps_5_0, D3D11)` or `ANGLE (Apple, ANGLE Metal Renderer:\n * Apple M3 Pro, Unspecified Version)`.\n */\nconst cleanGpuName = (raw: string): string => {\n let name = raw.trim();\n const angle = /^ANGLE \\((.*)\\)$/.exec(name);\n\n if (angle) {\n const parts = angle[1]!.split(\", \");\n name = parts[1] ?? parts[0]!;\n }\n\n return name\n .replace(/^ANGLE [\\w ]+ Renderer: /, \"\")\n .replace(/ \\(0x[0-9a-f]+\\)/i, \"\")\n .replace(/ (Direct3D\\d*|OpenGL|Vulkan|Metal)\\b.*$/, \"\")\n .trim();\n};\n\nconst webglGpuName = (gl: WebGLRenderingContext | WebGL2RenderingContext): string | null => {\n // Firefox deprecates the extension but already returns the unmasked name from RENDERER.\n const ext = gl.getExtension(\"WEBGL_debug_renderer_info\") as DebugRendererInfoExt | null;\n const raw = gl.getParameter(ext ? ext.UNMASKED_RENDERER_WEBGL : gl.RENDERER) as unknown;\n\n return typeof raw === \"string\" && raw !== \"\" && raw !== \"WebKit WebGL\" ? cleanGpuName(raw) : null;\n};\n\n/** WebGPU reports vendors lowercase (`apple`, `nvidia`). */\nconst VENDOR_NAMES: Record<string, string> = {\n amd: \"AMD\",\n apple: \"Apple\",\n arm: \"Arm\",\n intel: \"Intel\",\n nvidia: \"NVIDIA\",\n qualcomm: \"Qualcomm\",\n};\n\n/**\n * `GPUDevice.adapterInfo`. Chrome leaves `description` empty to limit\n * fingerprinting, so this is usually vendor + architecture: `Apple metal-3`.\n */\nconst webgpuGpuName = (info: AdapterInfoShape | undefined): string | null => {\n if (!info) {\n return null;\n }\n\n if (info.description) {\n return info.description;\n }\n\n const vendor = info.vendor ? (VENDOR_NAMES[info.vendor] ?? info.vendor) : \"\";\n const name = [vendor, info.architecture].filter(Boolean).join(\" \");\n\n return name === \"\" ? null : name;\n};\n\nconst isWebglContext = (value: unknown): value is WebGLRenderingContext | WebGL2RenderingContext =>\n (typeof WebGL2RenderingContext !== \"undefined\" && value instanceof WebGL2RenderingContext) ||\n (typeof WebGLRenderingContext !== \"undefined\" && value instanceof WebGLRenderingContext);\n\nconst webglBackend = (gl: WebGLRenderingContext | WebGL2RenderingContext): RenderBackend =>\n typeof WebGL2RenderingContext !== \"undefined\" && gl instanceof WebGL2RenderingContext\n ? \"webgl2\"\n : \"webgl\";\n\nconst readEnvironment = (renderer: PerfRenderer): Environment => {\n const three = readThreeRevision();\n const backend = renderer.backend as BackendShape | undefined;\n\n // WebGPURenderer. Read the backend's own fields: `getContext()` before\n // `init()` is what the GPU timer learned not to touch.\n if (backend) {\n if (backend.isWebGPUBackend) {\n const device = backend.device;\n\n return device\n ? { backend: \"webgpu\", fallback: false, gpu: webgpuGpuName(device.adapterInfo), three }\n : { backend: null, fallback: false, gpu: null, three };\n }\n\n if (backend.isWebGLBackend && isWebglContext(backend.gl)) {\n return {\n backend: webglBackend(backend.gl),\n fallback: backend.parameters?.forceWebGL !== true,\n gpu: webglGpuName(backend.gl),\n three,\n };\n }\n\n return { backend: null, fallback: false, gpu: null, three };\n }\n\n // WebGLRenderer.\n const context = renderer.getContext?.();\n\n return isWebglContext(context)\n ? { backend: webglBackend(context), fallback: false, gpu: webglGpuName(context), three }\n : { backend: null, fallback: false, gpu: null, three };\n};\n\nexport { cleanGpuName, readEnvironment };\n","/**\n * Stutter statistics over a window of frame intervals. Average FPS hides a\n * hitch every few seconds; these don't. Stalls (hidden tab, breakpoint) never\n * reach the window, so they don't count as hitches.\n */\nimport type { FrameStats } from \"./types.ts\";\n\n/** A frame over this multiple of the window's median interval is a hitch. */\nconst HITCH_FACTOR = 2;\n\n/** Fewer frames than this and the refresh rate reads `null`. */\nconst REFRESH_MIN_FRAMES = 60;\n\n/** Common display refresh rates. A reading within 4% of one snaps to it. */\nconst REFRESH_RATES = [30, 48, 50, 60, 72, 75, 90, 100, 120, 144, 165, 180, 240, 360];\n\nconst EMPTY: FrameStats = Object.freeze({\n frames: 0,\n hitches: 0,\n lowFps: 0,\n p99Ms: 0,\n refreshHz: null,\n});\n\n/**\n * The rate the loop runs at when it keeps up: the fastest tenth of frames,\n * not the average, so slow frames don't drag it down. That is the display's\n * refresh rate, or the app's own cap if it throttles itself.\n *\n * Intervals are averaged with their neighbour first. A frame that starts late\n * leaves a short interval after it, and on a real 120 Hz display those short\n * ones alone read as 125–127 Hz; each pair averages back to the vsync.\n */\nconst refreshFrom = (intervals: readonly number[]): number | null => {\n if (intervals.length < REFRESH_MIN_FRAMES) {\n return null;\n }\n\n const pairs = intervals.slice(1).map((interval, index) => (interval + intervals[index]!) / 2);\n pairs.sort((a, b) => a - b);\n const rate = 1000 / pairs[Math.floor(pairs.length * 0.1)]!;\n const nearest = REFRESH_RATES.reduce((best, candidate) =>\n Math.abs(candidate - rate) < Math.abs(best - rate) ? candidate : best,\n );\n\n return Math.abs(nearest - rate) / nearest <= 0.04 ? nearest : Math.round(rate);\n};\n\nconst computeFrameStats = (intervals: readonly number[]): FrameStats => {\n const frames = intervals.length;\n\n if (frames === 0) {\n return EMPTY;\n }\n\n const sorted = [...intervals].sort((a, b) => a - b);\n // Nearest rank: the smallest interval at or above 99% of frames.\n const p99Ms = sorted[Math.ceil(frames * 0.99) - 1]!;\n\n // 1% low: the mean rate across the slowest 1% of frames (at least one frame).\n const slowest = Math.max(1, Math.ceil(frames * 0.01));\n let slowSum = 0;\n\n for (let index = frames - slowest; index < frames; index += 1) {\n slowSum += sorted[index]!;\n }\n\n const middle = frames >> 1;\n const median = frames % 2 === 0 ? (sorted[middle - 1]! + sorted[middle]!) / 2 : sorted[middle]!;\n const threshold = median * HITCH_FACTOR;\n let hitches = 0;\n\n for (const interval of intervals) {\n if (interval > threshold) {\n hitches += 1;\n }\n }\n\n return Object.freeze({\n frames,\n hitches,\n lowFps: 1000 / (slowSum / slowest),\n p99Ms,\n refreshHz: refreshFrom(intervals),\n });\n};\n\nexport { computeFrameStats, HITCH_FACTOR };\n","/**\n * Real GPU frame timing.\n *\n * WebGPU: Three's `trackTimestamp` + `resolveTimestampsAsync` (ms, a frame or\n * two late). Never calls `getExtension`: that is what remounted the canvas.\n *\n * WebGL2 fallback (Safari without WebGPU, or a forced GL backend):\n * `EXT_disjoint_timer_query_webgl2`, same pool-of-queries pattern as the\n * platform-typing monitor.\n */\nimport type { PerfRenderer } from \"./types.ts\";\n\ntype DisjointTimerQueryExt = {\n readonly GPU_DISJOINT_EXT: number;\n readonly TIME_ELAPSED_EXT: number;\n};\n\nclass GpuTimer {\n private lastMs = 0;\n private readonly webgpu: PerfRenderer | null;\n private webgpuInFlight = false;\n private readonly gl: WebGL2RenderingContext | null;\n private readonly ext: DisjointTimerQueryExt | null;\n private readonly free: WebGLQuery[] = [];\n private readonly pending: WebGLQuery[] = [];\n private active: WebGLQuery | null = null;\n\n private constructor(\n webgpu: PerfRenderer | null,\n gl: WebGL2RenderingContext | null,\n ext: DisjointTimerQueryExt | null,\n poolSize: number,\n ) {\n this.webgpu = webgpu;\n this.gl = gl;\n this.ext = ext;\n\n if (!gl) {\n return;\n }\n\n for (let index = 0; index < poolSize; index += 1) {\n const query = gl.createQuery();\n\n if (query) {\n this.free.push(query);\n }\n }\n }\n\n static create(renderer: PerfRenderer, poolSize: number): GpuTimer | null {\n const backend = renderer.backend as { trackTimestamp?: boolean } | undefined;\n\n if (backend?.trackTimestamp && renderer.resolveTimestampsAsync) {\n return new GpuTimer(renderer, null, null, poolSize);\n }\n\n const context = renderer.getContext?.();\n\n if (!(context instanceof WebGL2RenderingContext)) {\n return null;\n }\n\n const ext = context.getExtension(\n \"EXT_disjoint_timer_query_webgl2\",\n ) as DisjointTimerQueryExt | null;\n\n return ext ? new GpuTimer(null, context, ext, poolSize) : null;\n }\n\n begin() {\n if (this.webgpu || !this.gl || !this.ext) {\n return;\n }\n\n const query = this.free.pop();\n\n if (!query) {\n this.active = null;\n\n return;\n }\n\n this.active = query;\n this.gl.beginQuery(this.ext.TIME_ELAPSED_EXT, query);\n }\n\n end() {\n if (this.webgpu || !this.gl || !this.ext || !this.active) {\n return;\n }\n\n this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);\n this.pending.push(this.active);\n this.active = null;\n }\n\n poll() {\n if (this.webgpu) {\n this.pollWebgpu();\n\n return;\n }\n\n this.pollWebgl();\n }\n\n getMs() {\n return this.lastMs;\n }\n\n dispose() {\n if (this.gl && this.ext && this.active) {\n this.gl.endQuery(this.ext.TIME_ELAPSED_EXT);\n this.active = null;\n }\n\n if (this.gl) {\n for (const query of this.free) {\n this.gl.deleteQuery(query);\n }\n\n for (const query of this.pending) {\n this.gl.deleteQuery(query);\n }\n }\n\n this.free.length = 0;\n this.pending.length = 0;\n }\n\n private pollWebgpu() {\n const resolve = this.webgpu?.resolveTimestampsAsync;\n\n if (!resolve || this.webgpuInFlight) {\n return;\n }\n\n this.webgpuInFlight = true;\n\n void resolve\n .call(this.webgpu, \"render\")\n .then((ms) => {\n if (typeof ms === \"number\" && Number.isFinite(ms)) {\n this.lastMs = ms;\n }\n\n this.webgpuInFlight = false;\n })\n .catch(() => {\n this.webgpuInFlight = false;\n });\n }\n\n private pollWebgl() {\n if (!this.gl || !this.ext) {\n return;\n }\n\n const disjoint = this.gl.getParameter(this.ext.GPU_DISJOINT_EXT) as boolean;\n\n if (disjoint) {\n while (this.pending.length > 0) {\n this.free.push(this.pending.shift()!);\n }\n\n return;\n }\n\n while (this.pending.length > 0) {\n const query = this.pending[0]!;\n const ready = this.gl.getQueryParameter(query, this.gl.QUERY_RESULT_AVAILABLE) as boolean;\n\n if (!ready) {\n break;\n }\n\n this.pending.shift();\n const ns = this.gl.getQueryParameter(query, this.gl.QUERY_RESULT) as number;\n this.lastMs = ns / 1e6;\n this.free.push(query);\n }\n }\n}\n\nexport { GpuTimer };\n","/**\n * Fixed-capacity numeric ring buffer. Backs the per-frame timing history the\n * view reads to draw sparklines. Push is O(1); `toArray()` returns values in\n * chronological (oldest → newest) order.\n */\nclass RingBuffer {\n private readonly data: Float32Array;\n private readonly capacity: number;\n private head = 0;\n private count = 0;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.data = new Float32Array(capacity);\n }\n\n push(value: number) {\n this.data[this.head] = value;\n this.head = (this.head + 1) % this.capacity;\n\n if (this.count < this.capacity) {\n this.count += 1;\n }\n }\n\n /** Values oldest → newest. Length grows up to capacity as samples accumulate. */\n toArray(): number[] {\n const out = Array.from<number>({ length: this.count });\n const start = (this.head - this.count + this.capacity) % this.capacity;\n\n for (let index = 0; index < this.count; index += 1) {\n out[index] = this.data[(start + index) % this.capacity]!;\n }\n\n return out;\n }\n\n clear() {\n this.head = 0;\n this.count = 0;\n }\n}\n\nexport { RingBuffer };\n","/**\n * Where a frame's draw calls and triangles come from, estimated from the\n * scene graph the way three's renderer walks it: hidden objects, other\n * layers and anything outside the camera's frustum are left out; each\n * visible material (or material group) is one draw call, two for a\n * transparent double-sided material. Main pass only: shadow maps and\n * post-processing passes aren't counted.\n *\n * Structural like the rest of core: no import of three, every field read\n * defensively, since this runs against whatever the app renders.\n */\nimport type { CostEntry, SceneCost } from \"./types.ts\";\n\ntype Elements = ArrayLike<number>;\n\ntype Sphere = { center: { x: number; y: number; z: number }; radius: number };\n\ntype GeometryShape = {\n attributes?: { position?: { count: number } };\n boundingSphere?: Sphere | null;\n drawRange?: { count: number; start: number };\n groups?: { count: number; materialIndex?: number; start: number }[];\n index?: { count: number } | null;\n name?: string;\n uuid?: string;\n};\n\ntype MaterialShape = {\n uuid?: string;\n forceSinglePass?: boolean;\n name?: string;\n side?: number;\n transparent?: boolean;\n type?: string;\n visible?: boolean;\n};\n\ntype ObjectShape = {\n boundingSphere?: Sphere | null;\n count?: number;\n frustumCulled?: boolean;\n geometry?: GeometryShape;\n isInstancedMesh?: boolean;\n isLine?: boolean;\n isMesh?: boolean;\n isPoints?: boolean;\n isSprite?: boolean;\n layers?: { mask: number };\n material?: MaterialShape | MaterialShape[];\n matrixWorld?: { elements: Elements };\n name?: string;\n type?: string;\n};\n\ntype CameraShape = {\n coordinateSystem?: number;\n layers?: { mask: number };\n matrixWorldInverse?: { elements: Elements };\n projectionMatrix?: { elements: Elements };\n reversedDepth?: boolean;\n};\n\ntype SceneShape = { traverseVisible?: (callback: (object: ObjectShape) => void) => void };\n\n/** three's `DoubleSide` and `WebGPUCoordinateSystem`. */\nconst DOUBLE_SIDE = 2;\nconst WEBGPU_COORDINATES = 2001;\n\ntype Plane = [number, number, number, number];\n\n/** Column-major `a × b`, as three stores matrices. */\nconst multiply = (a: Elements, b: Elements) => {\n const out = Array.from<number>({ length: 16 });\n\n for (let column = 0; column < 4; column += 1) {\n for (let row = 0; row < 4; row += 1) {\n let sum = 0;\n\n for (let k = 0; k < 4; k += 1) {\n sum += a[k * 4 + row]! * b[column * 4 + k]!;\n }\n\n out[column * 4 + row] = sum;\n }\n }\n\n return out;\n};\n\nconst normalize = (plane: Plane): Plane => {\n const length = Math.hypot(plane[0], plane[1], plane[2]) || 1;\n\n return [plane[0] / length, plane[1] / length, plane[2] / length, plane[3] / length];\n};\n\n/** Mirrors three's `Frustum.setFromProjectionMatrix`. Near and far only where the depth range is known. */\nconst frustumPlanes = (camera: CameraShape): Plane[] | null => {\n if (!camera.projectionMatrix || !camera.matrixWorldInverse) {\n return null;\n }\n\n const m = multiply(camera.projectionMatrix.elements, camera.matrixWorldInverse.elements);\n const row = (index: number): Plane => [m[index]!, m[index + 4]!, m[index + 8]!, m[index + 12]!];\n const [r0, r1, r2, r3] = [row(0), row(1), row(2), row(3)];\n const add = (a: Plane, b: Plane): Plane => [a[0] + b[0], a[1] + b[1], a[2] + b[2], a[3] + b[3]];\n const sub = (a: Plane, b: Plane): Plane => [a[0] - b[0], a[1] - b[1], a[2] - b[2], a[3] - b[3]];\n\n const planes = [sub(r3, r0), add(r3, r0), add(r3, r1), sub(r3, r1)];\n\n if (!camera.reversedDepth) {\n planes.push(sub(r3, r2), camera.coordinateSystem === WEBGPU_COORDINATES ? r2 : add(r3, r2));\n }\n\n return planes.map(normalize);\n};\n\nconst inFrustum = (object: ObjectShape, planes: Plane[] | null) => {\n const sphere = object.boundingSphere ?? object.geometry?.boundingSphere;\n const e = object.matrixWorld?.elements;\n\n // three computes bounding spheres lazily while rendering; without one, count the object.\n if (!planes || !sphere || !e) {\n return true;\n }\n\n const { x, y, z } = sphere.center;\n const cx = e[0]! * x + e[4]! * y + e[8]! * z + e[12]!;\n const cy = e[1]! * x + e[5]! * y + e[9]! * z + e[13]!;\n const cz = e[2]! * x + e[6]! * y + e[10]! * z + e[14]!;\n const scale = Math.sqrt(\n Math.max(\n e[0]! ** 2 + e[1]! ** 2 + e[2]! ** 2,\n e[4]! ** 2 + e[5]! ** 2 + e[6]! ** 2,\n e[8]! ** 2 + e[9]! ** 2 + e[10]! ** 2,\n ),\n );\n const radius = sphere.radius * scale;\n\n // three's own test, `distance < -radius`. Written this way round a NaN plane (a camera with a\n // zero-size aspect, say) keeps the object, as three does, rather than hiding everything.\n return !planes.some(([a, b, c, d]) => a * cx + b * cy + c * cz + d < -radius);\n};\n\nconst layersMatch = (object: ObjectShape, camera: CameraShape) =>\n !object.layers || !camera.layers || (object.layers.mask & camera.layers.mask) !== 0;\n\nconst passes = (material: MaterialShape) =>\n material.transparent === true &&\n material.side === DOUBLE_SIDE &&\n material.forceSinglePass !== true\n ? 2\n : 1;\n\n/** Vertices a draw covers, clipped to `drawRange` and, when given, a group. */\nconst drawnVertices = (\n geometry: GeometryShape,\n group?: { count: number; start: number },\n): number => {\n const total = geometry.index?.count ?? geometry.attributes?.position?.count ?? 0;\n const rangeStart = geometry.drawRange?.start ?? 0;\n const rangeEnd = Math.min(total, rangeStart + (geometry.drawRange?.count ?? Infinity));\n const start = Math.max(rangeStart, group?.start ?? 0);\n const end = Math.min(rangeEnd, group ? group.start + group.count : Infinity);\n\n return Math.max(0, end - start);\n};\n\ntype Draw = { calls: number; material: MaterialShape; triangles: number };\n\n/** One draw per visible material, or per group when the material is an array. */\nconst drawsOf = (object: ObjectShape): Draw[] => {\n const { geometry, material } = object;\n\n if (!geometry || !material) {\n return [];\n }\n\n const instances = object.isInstancedMesh ? (object.count ?? 1) : 1;\n const trianglesFor = (vertices: number) =>\n object.isMesh ? Math.floor(vertices / 3) * instances : 0;\n\n if (Array.isArray(material)) {\n const draws: Draw[] = [];\n\n for (const group of geometry.groups ?? []) {\n const groupMaterial = material[group.materialIndex ?? 0];\n\n if (groupMaterial && groupMaterial.visible !== false) {\n const count = passes(groupMaterial);\n draws.push({\n calls: count,\n material: groupMaterial,\n triangles: trianglesFor(drawnVertices(geometry, group)) * count,\n });\n }\n }\n\n return draws;\n }\n\n return material.visible === false\n ? []\n : [\n {\n calls: passes(material),\n material,\n // A second pass draws the triangles again, and three's info counts them again.\n triangles: trianglesFor(drawnVertices(geometry)) * passes(material),\n },\n ];\n};\n\nconst objectLabel = (object: ObjectShape) =>\n object.name || object.geometry?.name || object.type || \"Object\";\n\nconst materialLabel = (material: MaterialShape) => material.name || material.type || \"Material\";\n\n/** A stable id for objects without a `uuid`, so keys survive between walks. */\nconst ids = new WeakMap<object, string>();\nlet nextId = 0;\n\nconst idOf = (value: object & { uuid?: string }) => {\n if (value.uuid) {\n return value.uuid;\n }\n\n let id = ids.get(value);\n\n if (!id) {\n nextId += 1;\n id = `#${nextId}`;\n ids.set(value, id);\n }\n\n return id;\n};\n\nconst entryFor = (groups: Map<unknown, CostEntry>, group: unknown, key: string, label: string) => {\n let entry = groups.get(group);\n\n if (!entry) {\n entry = { calls: 0, instances: 0, key, label, objects: [], triangles: 0 };\n groups.set(group, entry);\n }\n\n return entry;\n};\n\nconst byCost = (a: CostEntry, b: CostEntry) => b.calls - a.calls || b.triangles - a.triangles;\n\n/** Same label and geometry is one mesh row. */\nconst meshKeyOf = (object: ObjectShape) =>\n `mesh:${objectLabel(object)}\\u0000${object.geometry?.uuid ?? \"\"}`;\n\nconst materialsOf = (object: ObjectShape) =>\n object.material === undefined\n ? []\n : Array.isArray(object.material)\n ? object.material\n : [object.material];\n\n/**\n * Every drawable object in the scene that belongs to a row's `key`, on screen\n * or not: hiding a row has to catch the copies that orbit into view later.\n * Skips objects that are already hidden, like three does.\n */\nconst objectsForKey = (scene: unknown, key: string): unknown[] => {\n const root = scene as SceneShape;\n const found: unknown[] = [];\n\n if (typeof root?.traverseVisible !== \"function\") {\n return found;\n }\n\n root.traverseVisible((object) => {\n const drawable = object.isMesh || object.isLine || object.isPoints || object.isSprite;\n\n if (!drawable) {\n return;\n }\n\n const matches = key.startsWith(\"mesh:\")\n ? meshKeyOf(object) === key\n : materialsOf(object).some((material) => `material:${idOf(material)}` === key);\n\n if (matches) {\n found.push(object);\n }\n });\n\n return found;\n};\n\nconst computeSceneCost = (scene: unknown, camera: unknown): SceneCost | null => {\n const root = scene as SceneShape;\n const view = camera as CameraShape;\n\n if (typeof root?.traverseVisible !== \"function\") {\n return null;\n }\n\n const planes = frustumPlanes(view);\n // Same label and geometry is one row, so 500 unmerged copies read as \"tree ×500\".\n const meshes = new Map<unknown, CostEntry>();\n const materials = new Map<unknown, CostEntry>();\n let calls = 0;\n let triangles = 0;\n\n root.traverseVisible((object) => {\n const drawable = object.isMesh || object.isLine || object.isPoints || object.isSprite;\n\n if (!drawable || !layersMatch(object, view)) {\n return;\n }\n\n if (object.frustumCulled !== false && !object.isSprite && !inFrustum(object, planes)) {\n return;\n }\n\n const instances = object.isInstancedMesh ? (object.count ?? 1) : 1;\n const label = objectLabel(object);\n const meshKey = meshKeyOf(object);\n\n const draws = drawsOf(object);\n\n if (draws.length === 0) {\n return;\n }\n\n const mesh = entryFor(meshes, meshKey, meshKey, label);\n mesh.objects.push(object);\n mesh.instances += instances;\n // A multi-material object can draw one material in several groups; list it once per material.\n const listed = new Set<MaterialShape>();\n\n for (const draw of draws) {\n calls += draw.calls;\n triangles += draw.triangles;\n mesh.calls += draw.calls;\n mesh.triangles += draw.triangles;\n\n const material = entryFor(\n materials,\n draw.material,\n `material:${idOf(draw.material)}`,\n materialLabel(draw.material),\n );\n material.calls += draw.calls;\n material.triangles += draw.triangles;\n\n if (!listed.has(draw.material)) {\n listed.add(draw.material);\n material.objects.push(object);\n material.instances += instances;\n }\n }\n });\n\n return {\n calls,\n materials: [...materials.values()].sort(byCost),\n meshes: [...meshes.values()].sort(byCost),\n triangles,\n };\n};\n\nexport { computeSceneCost, objectsForKey };\n","import { readEnvironment } from \"./environment.ts\";\nimport { computeFrameStats } from \"./frame-stats.ts\";\nimport { GpuTimer } from \"./gpu-timer.ts\";\nimport { RingBuffer } from \"./ring-buffer.ts\";\nimport { computeSceneCost, objectsForKey } from \"./scene-cost.ts\";\nimport type {\n CostEntry,\n Environment,\n FrameStats,\n PerfRenderer,\n PerformanceMonitorOptions,\n Sample,\n SceneCost,\n TimingMetric,\n} from \"./types.ts\";\n\nconst DEFAULT_GPU_POOL_SIZE = 5;\n/** One monitor per renderer: a second would stack the `render` patch and double-count passes. */\nconst ATTACHED = new WeakSet<PerfRenderer>();\nconst DEFAULT_HISTORY_SIZE = 120;\nconst DEFAULT_FRAME_STATS_SIZE = 1000;\nconst FPS_SMOOTHING = 0.1;\n/**\n * A frame interval past this is a stall (hidden tab, breakpoint, laptop lid),\n * not a slow frame. It is left out of FPS so one gap doesn't flatten the\n * graph's scale for the whole history window.\n */\nconst STALL_MS = 1000;\n\nconst frameCalls = (info: PerfRenderer[\"info\"]) => info.render.drawCalls ?? info.render.calls;\n\nconst programCount = (info: PerfRenderer[\"info\"]) =>\n info.memory.programs ?? info.programs?.length ?? 0;\n\n/**\n * Collector of three.js frame metrics. Bracket each frame with {@link begin}/\n * {@link end}, or let {@link wrapAnimationLoop} or the R3F `PerfSampler` do it.\n * Works on WebGPURenderer (drawCalls, memory.programs, timestamp queries) and\n * on a WebGL renderer (calls, programs[], timer-query ext).\n *\n * While attached, `renderer.info.autoReset` is off and `info` is reset in\n * {@link begin}; host code that reads `renderer.info` mid-frame sees this\n * frame's counts only. {@link dispose} restores both.\n *\n * CPU time runs from {@link begin} to the return of the frame's last\n * `render()` call, which the `render` patch stamps. So it holds even when\n * {@link end} is only reached on the next tick, as in the R3F sampler: it is\n * the JS work of the frame, not the interval to the next one.\n */\nclass PerformanceMonitor {\n private readonly renderer: PerfRenderer;\n private readonly gpuTimer: GpuTimer | null;\n private readonly originalRender: PerfRenderer[\"render\"];\n private renderPasses = 0;\n private lastRenderEndAt: number | null = null;\n private readonly fpsHistory: RingBuffer;\n private readonly cpuHistory: RingBuffer;\n private readonly gpuHistory: RingBuffer;\n private readonly frameIntervals: RingBuffer;\n private frameStats: FrameStats | null = null;\n /** The render call with the most draw calls this frame, and the scene and camera it drew. */\n private mainPassCalls = -1;\n private mainPass: { camera: WeakRef<object>; scene: WeakRef<object> } | null = null;\n private cpuStart = 0;\n private lastBeginAt: number | null = null;\n private frameFps = 0;\n private smoothedFps = 0;\n private sample: Sample;\n private environment: Environment | null = null;\n\n constructor(options: PerformanceMonitorOptions) {\n const {\n renderer,\n trackGPU = true,\n gpuQueryPoolSize = DEFAULT_GPU_POOL_SIZE,\n historySize = DEFAULT_HISTORY_SIZE,\n frameStatsSize = DEFAULT_FRAME_STATS_SIZE,\n } = options;\n\n if (ATTACHED.has(renderer)) {\n throw new Error(\n \"three-meter: a PerformanceMonitor is already attached to this renderer. dispose() it first.\",\n );\n }\n\n ATTACHED.add(renderer);\n this.renderer = renderer;\n renderer.info.autoReset = false;\n this.originalRender = renderer.render;\n\n renderer.render = (...args: never[]) => {\n this.renderPasses += 1;\n const callsBefore = frameCalls(renderer.info);\n\n try {\n return this.originalRender.apply(renderer, args);\n } finally {\n this.lastRenderEndAt = performance.now();\n this.notePass(args[0], args[1], frameCalls(renderer.info) - callsBefore);\n }\n };\n\n this.gpuTimer = trackGPU ? GpuTimer.create(renderer, gpuQueryPoolSize) : null;\n this.fpsHistory = new RingBuffer(historySize);\n this.cpuHistory = new RingBuffer(historySize);\n this.gpuHistory = new RingBuffer(historySize);\n this.frameIntervals = new RingBuffer(frameStatsSize);\n this.sample = this.buildEmptySample();\n }\n\n begin() {\n const now = performance.now();\n\n if (this.lastBeginAt !== null) {\n const frameMs = now - this.lastBeginAt;\n\n // A stall keeps the previous reading rather than logging a near-zero frame.\n if (frameMs > 0 && frameMs <= STALL_MS) {\n this.frameFps = 1000 / frameMs;\n this.frameIntervals.push(frameMs);\n this.frameStats = null;\n }\n }\n\n this.lastBeginAt = now;\n this.cpuStart = now;\n this.lastRenderEndAt = null;\n this.renderPasses = 0;\n this.mainPassCalls = -1;\n this.renderer.info.reset();\n this.gpuTimer?.begin();\n }\n\n end() {\n const now = performance.now();\n // Without a render this frame there is nothing better than \"until end()\".\n const cpu = (this.lastRenderEndAt ?? now) - this.cpuStart;\n\n this.gpuTimer?.end();\n this.gpuTimer?.poll();\n\n const gpuMs = this.gpuTimer?.getMs() ?? 0;\n\n this.smoothedFps =\n this.smoothedFps === 0\n ? this.frameFps\n : this.smoothedFps + (this.frameFps - this.smoothedFps) * FPS_SMOOTHING;\n\n this.fpsHistory.push(this.frameFps);\n this.cpuHistory.push(cpu);\n this.gpuHistory.push(gpuMs);\n\n const info = this.renderer.info;\n\n this.sample = Object.freeze({\n cpu,\n fps: this.smoothedFps,\n gpu: { available: this.gpuTimer !== null, ms: gpuMs },\n render: {\n calls: frameCalls(info),\n lines: info.render.lines,\n passes: this.renderPasses,\n points: info.render.points,\n triangles: info.render.triangles,\n },\n resources: {\n geometries: info.memory.geometries,\n programs: programCount(info),\n textures: info.memory.textures,\n },\n });\n }\n\n getSample(): Sample {\n return this.sample;\n }\n\n getHistory(metric: TimingMetric): readonly number[] {\n switch (metric) {\n case \"fps\":\n return this.fpsHistory.toArray();\n case \"cpu\":\n return this.cpuHistory.toArray();\n case \"gpu\":\n return this.gpuHistory.toArray();\n }\n }\n\n /** 1% low, p99 frame time and hitches. Computed on read, cached until the next frame. */\n getFrameStats(): FrameStats {\n this.frameStats ??= computeFrameStats(this.frameIntervals.toArray());\n\n return this.frameStats;\n }\n\n /**\n * Where the main pass's draw calls and triangles come from, by mesh and by\n * material. Walks the scene graph, so read it on demand (the HUD does, at\n * 2 Hz while its section is open), not every frame. `null` before the first\n * render, or once the scene is garbage collected.\n */\n getSceneCost(): SceneCost | null {\n const scene = this.mainPass?.scene.deref();\n const camera = this.mainPass?.camera.deref();\n\n return scene && camera ? computeSceneCost(scene, camera) : null;\n }\n\n /**\n * Every visible object in the main scene behind a {@link CostEntry}'s `key`,\n * including ones outside the camera, which `getSceneCost()` leaves out.\n */\n getObjectsForKey(key: string): unknown[] {\n const scene = this.mainPass?.scene.deref();\n\n return scene ? objectsForKey(scene, key) : [];\n }\n\n /**\n * three revision, backend and GPU name. Cached once the backend is known;\n * before `WebGPURenderer.init()` settles it, `backend` is `null` and the\n * next call reads again.\n */\n getEnvironment(): Environment {\n if (this.environment) {\n return this.environment;\n }\n\n const environment = Object.freeze(readEnvironment(this.renderer));\n\n if (environment.backend !== null) {\n this.environment = environment;\n }\n\n return environment;\n }\n\n dispose() {\n ATTACHED.delete(this.renderer);\n this.renderer.info.autoReset = true;\n this.renderer.render = this.originalRender;\n this.gpuTimer?.dispose();\n this.fpsHistory.clear();\n this.cpuHistory.clear();\n this.gpuHistory.clear();\n this.frameIntervals.clear();\n this.frameStats = null;\n this.mainPass = null;\n }\n\n /**\n * The main pass is the render call that drew the most, so a post-processing\n * quad rendered last doesn't stand in for the scene. Weak references: the\n * monitor never keeps a scene alive.\n */\n private notePass(scene: unknown, camera: unknown, calls: number) {\n if (\n calls > this.mainPassCalls &&\n typeof scene === \"object\" &&\n scene !== null &&\n typeof camera === \"object\" &&\n camera !== null\n ) {\n this.mainPassCalls = calls;\n this.mainPass = { camera: new WeakRef(camera), scene: new WeakRef(scene) };\n }\n }\n\n private buildEmptySample(): Sample {\n return Object.freeze({\n cpu: 0,\n fps: 0,\n gpu: { available: this.gpuTimer !== null, ms: 0 },\n render: { calls: 0, lines: 0, passes: 0, points: 0, triangles: 0 },\n resources: { geometries: 0, programs: 0, textures: 0 },\n });\n }\n}\n\nexport { PerformanceMonitor };\n"],"mappings":"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"}