Comparing version 3.2.0 to 3.3.0
import { Panel } from "./panel.js"; | ||
import { PanelVSync } from "./panelVsync.js"; | ||
const _Stats = class _Stats2 { | ||
constructor({ | ||
trackGPU = false, | ||
trackHz = false, | ||
logsPerSecond = 4, | ||
@@ -27,2 +29,3 @@ graphsPerSecond = 30, | ||
this.gpuPanelCompute = null; | ||
this.vsyncPanel = null; | ||
this.averageFps = { logs: [], graph: [] }; | ||
@@ -36,2 +39,16 @@ this.averageCpu = { logs: [], graph: [] }; | ||
this.lastValue = {}; | ||
this.VSYNC_RATES = [ | ||
{ refreshRate: 60, frameTime: 16.67 }, | ||
{ refreshRate: 75, frameTime: 13.33 }, | ||
{ refreshRate: 90, frameTime: 11.11 }, | ||
{ refreshRate: 120, frameTime: 8.33 }, | ||
{ refreshRate: 144, frameTime: 6.94 }, | ||
{ refreshRate: 165, frameTime: 6.06 }, | ||
{ refreshRate: 240, frameTime: 4.17 } | ||
]; | ||
this.detectedVSync = null; | ||
this.frameTimeHistory = []; | ||
this.HISTORY_SIZE = 120; | ||
this.VSYNC_THRESHOLD = 0.05; | ||
this.lastFrameTime = 0; | ||
this.handleClick = (event) => { | ||
@@ -53,2 +70,3 @@ event.preventDefault(); | ||
this.trackGPU = trackGPU; | ||
this.trackHz = trackHz; | ||
this.samplesLog = samplesLog; | ||
@@ -68,2 +86,7 @@ this.samplesGraph = samplesGraph; | ||
this.msPanel = this.addPanel(new _Stats2.Panel("CPU", "#0f0", "#020"), 1); | ||
if (this.trackHz === true) { | ||
this.vsyncPanel = new PanelVSync("", "#f0f", "#202"); | ||
this.dom.appendChild(this.vsyncPanel.canvas); | ||
this.vsyncPanel.setOffset(56, 35); | ||
} | ||
this.setupEventListeners(); | ||
@@ -254,3 +277,39 @@ } | ||
} | ||
detectVSync(currentTime) { | ||
if (this.lastFrameTime === 0) { | ||
this.lastFrameTime = currentTime; | ||
return; | ||
} | ||
const frameTime = currentTime - this.lastFrameTime; | ||
this.lastFrameTime = currentTime; | ||
this.frameTimeHistory.push(frameTime); | ||
if (this.frameTimeHistory.length > this.HISTORY_SIZE) { | ||
this.frameTimeHistory.shift(); | ||
} | ||
if (this.frameTimeHistory.length < 60) | ||
return; | ||
const avgFrameTime = this.frameTimeHistory.reduce((a, b) => a + b) / this.frameTimeHistory.length; | ||
const variance = this.frameTimeHistory.reduce((acc, time) => acc + Math.pow(time - avgFrameTime, 2), 0) / this.frameTimeHistory.length; | ||
const stability = Math.sqrt(variance); | ||
if (stability > 2) { | ||
this.detectedVSync = null; | ||
return; | ||
} | ||
let closestMatch = null; | ||
let smallestDiff = Infinity; | ||
for (const rate of this.VSYNC_RATES) { | ||
const diff = Math.abs(avgFrameTime - rate.frameTime); | ||
if (diff < smallestDiff) { | ||
smallestDiff = diff; | ||
closestMatch = rate; | ||
} | ||
} | ||
if (closestMatch && smallestDiff / closestMatch.frameTime <= this.VSYNC_THRESHOLD) { | ||
this.detectedVSync = closestMatch; | ||
} else { | ||
this.detectedVSync = null; | ||
} | ||
} | ||
endInternal() { | ||
var _a; | ||
const currentTime = performance.now(); | ||
@@ -279,2 +338,9 @@ this.frameTimes.push(currentTime); | ||
} | ||
if (this.vsyncPanel !== null) { | ||
this.detectVSync(currentTime); | ||
const vsyncValue = ((_a = this.detectedVSync) == null ? void 0 : _a.refreshRate) || 0; | ||
if (shouldUpdateText && vsyncValue > 0) { | ||
this.vsyncPanel.update(vsyncValue, vsyncValue); | ||
} | ||
} | ||
return currentTime; | ||
@@ -281,0 +347,0 @@ } |
@@ -19,3 +19,3 @@ declare class Panel { | ||
private createGradient; | ||
private initializeCanvas; | ||
initializeCanvas(): void; | ||
update(value: number, maxValue: number, decimals?: number): void; | ||
@@ -27,2 +27,3 @@ updateGraph(valueGraph: number, maxGraph: number): void; | ||
trackGPU?: boolean; | ||
trackHz?: boolean; | ||
logsPerSecond?: number; | ||
@@ -55,2 +56,3 @@ graphsPerSecond?: number; | ||
trackGPU: boolean; | ||
trackHz: boolean; | ||
samplesLog: number; | ||
@@ -79,2 +81,3 @@ samplesGraph: number; | ||
private gpuPanelCompute; | ||
private vsyncPanel; | ||
averageFps: AverageData; | ||
@@ -90,4 +93,10 @@ averageCpu: AverageData; | ||
private prevTextTime; | ||
private readonly VSYNC_RATES; | ||
private detectedVSync; | ||
private frameTimeHistory; | ||
private readonly HISTORY_SIZE; | ||
private readonly VSYNC_THRESHOLD; | ||
private lastFrameTime; | ||
static Panel: typeof Panel; | ||
constructor({ trackGPU, logsPerSecond, graphsPerSecond, samplesLog, samplesGraph, precision, minimal, horizontal, mode }?: StatsOptions); | ||
constructor({ trackGPU, trackHz, logsPerSecond, graphsPerSecond, samplesLog, samplesGraph, precision, minimal, horizontal, mode }?: StatsOptions); | ||
private initializeDOM; | ||
@@ -112,2 +121,3 @@ private setupEventListeners; | ||
processGpuQueries(): void; | ||
private detectVSync; | ||
endInternal(): number; | ||
@@ -114,0 +124,0 @@ private updatePanelComponents; |
import type * as THREE from 'three'; | ||
import { Panel } from './panel'; | ||
import { PanelVSync } from './panelVsync'; | ||
interface StatsOptions { | ||
trackGPU?: boolean; | ||
trackHz?: boolean; | ||
logsPerSecond?: number; | ||
@@ -25,2 +27,9 @@ graphsPerSecond?: number; | ||
interface VSyncInfo { | ||
refreshRate: number; | ||
frameTime: number; | ||
} | ||
interface InfoData { | ||
@@ -41,2 +50,3 @@ render: { | ||
public trackGPU: boolean; | ||
public trackHz: boolean; | ||
public samplesLog: number; | ||
@@ -70,2 +80,3 @@ public samplesGraph: number; | ||
private gpuPanelCompute: Panel | null = null; | ||
private vsyncPanel: PanelVSync | null = null; | ||
@@ -84,3 +95,19 @@ public averageFps: AverageData = { logs: [], graph: [] }; | ||
private readonly VSYNC_RATES: VSyncInfo[] = [ | ||
{ refreshRate: 60, frameTime: 16.67 }, | ||
{ refreshRate: 75, frameTime: 13.33 }, | ||
{ refreshRate: 90, frameTime: 11.11 }, | ||
{ refreshRate: 120, frameTime: 8.33 }, | ||
{ refreshRate: 144, frameTime: 6.94 }, | ||
{ refreshRate: 165, frameTime: 6.06 }, | ||
{ refreshRate: 240, frameTime: 4.17 } | ||
]; | ||
private detectedVSync: VSyncInfo | null = null; | ||
private frameTimeHistory: number[] = []; | ||
private readonly HISTORY_SIZE = 120; // 2 seconds worth of frames at 60fps | ||
private readonly VSYNC_THRESHOLD = 0.05; // 5% tolerance | ||
private lastFrameTime: number = 0; | ||
static Panel = Panel; | ||
@@ -90,2 +117,3 @@ | ||
trackGPU = false, | ||
trackHz = false, | ||
logsPerSecond = 4, | ||
@@ -104,2 +132,3 @@ graphsPerSecond = 30, | ||
this.trackGPU = trackGPU; | ||
this.trackHz = trackHz; | ||
this.samplesLog = samplesLog; | ||
@@ -127,2 +156,8 @@ this.samplesGraph = samplesGraph; | ||
if (this.trackHz === true) { | ||
this.vsyncPanel = new PanelVSync('', '#f0f', '#202'); | ||
this.dom.appendChild(this.vsyncPanel.canvas); | ||
this.vsyncPanel.setOffset(56, 35); | ||
} | ||
this.setupEventListeners(); | ||
@@ -380,3 +415,55 @@ } | ||
} | ||
private detectVSync(currentTime: number): void { | ||
if (this.lastFrameTime === 0) { | ||
this.lastFrameTime = currentTime; | ||
return; | ||
} | ||
// Calculate frame time | ||
const frameTime = currentTime - this.lastFrameTime; | ||
this.lastFrameTime = currentTime; | ||
// Add to histories | ||
this.frameTimeHistory.push(frameTime); | ||
if (this.frameTimeHistory.length > this.HISTORY_SIZE) { | ||
this.frameTimeHistory.shift(); | ||
} | ||
// Only start detection when we have enough samples | ||
if (this.frameTimeHistory.length < 60) return; | ||
// Calculate average frame time | ||
const avgFrameTime = this.frameTimeHistory.reduce((a, b) => a + b) / this.frameTimeHistory.length; | ||
// Calculate frame time stability (standard deviation) | ||
const variance = this.frameTimeHistory.reduce((acc, time) => | ||
acc + Math.pow(time - avgFrameTime, 2), 0) / this.frameTimeHistory.length; | ||
const stability = Math.sqrt(variance); | ||
// Only proceed if frame timing is relatively stable | ||
if (stability > 2) { // 2ms stability threshold | ||
this.detectedVSync = null; | ||
return; | ||
} | ||
// Find the closest VSync rate based on frame time | ||
let closestMatch: VSyncInfo | null = null; | ||
let smallestDiff = Infinity; | ||
for (const rate of this.VSYNC_RATES) { | ||
const diff = Math.abs(avgFrameTime - rate.frameTime); | ||
if (diff < smallestDiff) { | ||
smallestDiff = diff; | ||
closestMatch = rate; | ||
} | ||
} | ||
if (closestMatch && (smallestDiff / closestMatch.frameTime <= this.VSYNC_THRESHOLD)) { | ||
this.detectedVSync = closestMatch; | ||
} else { | ||
this.detectedVSync = null; | ||
} | ||
} | ||
endInternal() { | ||
@@ -416,2 +503,12 @@ const currentTime = performance.now(); | ||
if (this.vsyncPanel !== null) { | ||
this.detectVSync(currentTime); | ||
const vsyncValue = this.detectedVSync?.refreshRate || 0; | ||
if (shouldUpdateText && vsyncValue > 0) { | ||
this.vsyncPanel.update(vsyncValue, vsyncValue); | ||
} | ||
} | ||
return currentTime; | ||
@@ -418,0 +515,0 @@ } |
@@ -84,3 +84,3 @@ class Panel { | ||
private initializeCanvas() { | ||
public initializeCanvas() { | ||
if (!this.context) return; | ||
@@ -108,3 +108,3 @@ | ||
// Update only text portion | ||
update(value: number, maxValue: number, decimals: number = 0) { | ||
public update(value: number, maxValue: number, decimals: number = 0) { | ||
if (!this.context || !this.gradient) return; | ||
@@ -130,3 +130,3 @@ | ||
// Update only graph portion | ||
updateGraph(valueGraph: number, maxGraph: number) { | ||
public updateGraph(valueGraph: number, maxGraph: number) { | ||
if (!this.context || !this.gradient) return; | ||
@@ -133,0 +133,0 @@ |
{ | ||
"name": "stats-gl", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "author": "Renaud ROHLINGER (https://github.com/RenaudRohlinger)", |
@@ -38,4 +38,6 @@ # 📈 stats-gl | ||
trackGPU: false, | ||
logsPerSecond: 20, | ||
samplesLog: 100, | ||
trackHz: false, | ||
logsPerSecond: 4, | ||
graphsPerSecond: 30, | ||
samplesLog: 40, | ||
samplesGraph: 10, | ||
@@ -124,2 +126,5 @@ precision: 2, | ||
- `logsPerSecond`: How often to log performance data, in logs per second. | ||
- `graphsPerSecond`: How often to update the graph, in graphs per second. | ||
- `trackGPU`: A boolean value to enable or disable GPU tracking. | ||
- `trackHz`: A boolean value to enable or disable Hz tracking. | ||
- `samplesLog`: Number of recent log samples to keep for computing averages. | ||
@@ -126,0 +131,0 @@ - `samplesGraph`: Number of recent graph samples to keep for computing averages. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
108764
18
2217
150