All checks were successful
Check & deploy / build (pull_request) Successful in 1m51s
74 lines
2.2 KiB
TypeScript
74 lines
2.2 KiB
TypeScript
const PERF_STATS_REFRESH_MS = 200;
|
|
const ZERO_STAT_TEXT = '0';
|
|
const ZERO_FRAME_TIME_TEXT = '0ms';
|
|
const ZERO_RESOLUTION_TEXT = '0x0';
|
|
|
|
interface PerfStatsSnapshot {
|
|
time: DOMHighResTimeStamp;
|
|
fps: number;
|
|
agentCount: number;
|
|
frameTimeMs: number;
|
|
gpuPassTimeMs?: number;
|
|
renderWidth: number;
|
|
renderHeight: number;
|
|
}
|
|
|
|
export class PerfStatsOverlay {
|
|
private readonly element: HTMLDivElement;
|
|
private previousUpdateTime = Number.NEGATIVE_INFINITY;
|
|
private previousText = '';
|
|
|
|
public constructor(parent: HTMLElement) {
|
|
this.element = document.createElement('div');
|
|
this.element.className = 'perf-stats-overlay';
|
|
this.element.setAttribute('aria-hidden', 'true');
|
|
parent.append(this.element);
|
|
}
|
|
|
|
public update({
|
|
time,
|
|
fps,
|
|
agentCount,
|
|
frameTimeMs,
|
|
gpuPassTimeMs,
|
|
renderWidth,
|
|
renderHeight,
|
|
}: PerfStatsSnapshot): void {
|
|
if (time - this.previousUpdateTime < PERF_STATS_REFRESH_MS) {
|
|
return;
|
|
}
|
|
|
|
this.previousUpdateTime = time;
|
|
const text = `FPS ${formatFps(fps)}\nAgents ${formatAgentCount(agentCount)}\nFrame ${formatFrameTime(frameTimeMs)}\nGPU passes ${formatFrameTime(gpuPassTimeMs)}\nResolution ${formatResolution(renderWidth, renderHeight)}`;
|
|
if (text !== this.previousText) {
|
|
this.element.textContent = text;
|
|
this.previousText = text;
|
|
}
|
|
}
|
|
|
|
public destroy(): void {
|
|
this.element.remove();
|
|
}
|
|
}
|
|
|
|
const formatFps = (fps: number): string =>
|
|
Number.isFinite(fps) ? Math.max(0, Math.round(fps)).toString() : ZERO_STAT_TEXT;
|
|
|
|
const formatAgentCount = (agentCount: number): string =>
|
|
Number.isFinite(agentCount)
|
|
? Math.max(0, Math.round(agentCount)).toLocaleString('en-US')
|
|
: ZERO_STAT_TEXT;
|
|
|
|
const formatFrameTime = (frameTimeMs: number | undefined): string => {
|
|
if (typeof frameTimeMs !== 'number' || !Number.isFinite(frameTimeMs)) {
|
|
return ZERO_FRAME_TIME_TEXT;
|
|
}
|
|
|
|
const safeFrameTimeMs = Math.max(0, frameTimeMs);
|
|
return `${safeFrameTimeMs.toFixed(safeFrameTimeMs < 10 ? 1 : 0)}ms`;
|
|
};
|
|
|
|
const formatResolution = (width: number, height: number): string =>
|
|
Number.isFinite(width) && Number.isFinite(height)
|
|
? `${Math.max(0, Math.round(width))}x${Math.max(0, Math.round(height))}`
|
|
: ZERO_RESOLUTION_TEXT;
|