Warning, /firebird/packages/firebird-ng/display/src/lib/services/perf.service.ts is written in an unsupported language. File is not indexed.
0001 // perf.service.ts (optimized snippet)
0002 import { Injectable } from '@angular/core';
0003 import { BehaviorSubject } from 'rxjs';
0004 import {WebGPURenderer} from "three/webgpu";
0005 export interface PerfLog {
0006 fps: number;
0007 frameTime: number; // Changed from 'cpu' to 'frameTime'
0008 calls: number;
0009 triangles: number;
0010 /** Render scheduling mode of the loop (config `rendering.mode`). */
0011 mode: 'continuous' | 'on-demand';
0012 /** True when on-demand and nothing rendered in the last interval — the
0013 * display is up to date, not hung. FPS reads 0 by design while idle. */
0014 idle: boolean;
0015 }
0016
0017 @Injectable({
0018 providedIn: 'root',
0019 })
0020 export class PerfService {
0021 private perfSubject = new BehaviorSubject<PerfLog>({
0022 fps: 0,
0023 frameTime: 0,
0024 calls: 0,
0025 triangles: 0,
0026 mode: 'continuous',
0027 idle: false,
0028 });
0029 public perf$ = this.perfSubject.asObservable();
0030
0031 private lastUpdateTime = performance.now();
0032 private frameCount = 0;
0033 private frameTimes: number[] = [];
0034 private readonly updateInterval = 250; // milliseconds
0035
0036 /**
0037 * Called every animation-frame tick. `rendered` says whether this tick
0038 * actually rendered — FPS counts rendered frames only, so an idle
0039 * on-demand loop correctly decays to 0 (flagged `idle`, not a hang).
0040 */
0041 public updateStats(renderer: WebGPURenderer, frameStartTime: number, rendered = true, continuous = true) {
0042 const now = performance.now();
0043
0044 if (rendered) {
0045 this.frameCount++;
0046 this.frameTimes.push(now - frameStartTime);
0047 }
0048
0049 // Check if the interval has elapsed
0050 if (now - this.lastUpdateTime >= this.updateInterval) {
0051 const deltaSeconds = (now - this.lastUpdateTime) / 1000;
0052 const fps = this.frameCount / deltaSeconds;
0053
0054 // Average frame time over rendered frames (0 while idle)
0055 const avgFrameTime = this.frameTimes.length
0056 ? this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length
0057 : 0;
0058
0059 // Read renderer info only once
0060 const info = renderer.info.render as { calls: number; triangles: number; drawCalls?: number };
0061
0062 // WebGPURenderer semantics differ from WebGLRenderer: info.render.calls is a
0063 // cumulative total that never resets, while drawCalls holds the per-frame count.
0064 const callsPerFrame = info.drawCalls !== undefined ? info.drawCalls : info.calls;
0065
0066 const log: PerfLog = {
0067 fps: fps,
0068 frameTime: avgFrameTime,
0069 calls: callsPerFrame,
0070 triangles: info.triangles,
0071 mode: continuous ? 'continuous' : 'on-demand',
0072 idle: !continuous && this.frameCount === 0,
0073 };
0074
0075 this.perfSubject.next(log);
0076
0077 // Reset counters
0078 this.lastUpdateTime = now;
0079 this.frameCount = 0;
0080 this.frameTimes = [];
0081 }
0082 }
0083 }