@itwin/core-frontend
Version:
iTwin.js frontend components
98 lines • 5.29 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module WebGL
*/
import { BeTimePoint, StopWatch } from "@itwin/core-bentley";
import { System } from "./System";
/** @internal */
export class PerformanceMetrics {
_beginTimePoints = []; // stack of time points
_operationNames = []; // stack of operation names
_allTimePoints1 = []; // queue 1 of data needed to make frameTimings; use 2 copies for double buffering
_allTimePoints2 = []; // queue 2 of data needed to make frameTimings; use 2 copies for double buffering
_updateallTimePoints1 = true; // determine which buffer to use for the frame timings; used for double buffering the frame timings
frameTimings = new Map();
gatherGlFinish = false; // Set to true if gathering data for display-performance-test-app
gatherCurPerformanceMetrics = false; // Set to true if gathering data for Profile GPU
curSpfTimeIndex = 0;
spfTimes = [];
spfSum = 0;
fpsTimer = new StopWatch(undefined, true);
fpsTimerStart = 0;
constructor(gatherGlFinish = false, gatherCurPerformanceMetrics = false, gpuResults) {
this.gatherGlFinish = gatherGlFinish;
this.gatherCurPerformanceMetrics = gatherCurPerformanceMetrics;
if (gpuResults)
System.instance.debugControl.resultsCallback = gpuResults;
}
beginFrame(sceneTime = 0) {
this._beginTimePoints = [];
this._operationNames = [];
this.frameTimings = new Map();
this.frameTimings.set("Scene Time", sceneTime);
this._operationNames.push("Total Time");
this._operationNames.push("CPU Total Time");
const now = BeTimePoint.now();
this._beginTimePoints.push(now); // this first time point used to calculate total time at the end
this._beginTimePoints.push(now); // this second time point used to calculate total cpu time at the end
}
beginOperation(operationName) {
this._operationNames.push(operationName);
this._beginTimePoints.push(BeTimePoint.now());
}
endOperation() {
const endTimePoint = BeTimePoint.now();
const beginTimePoint = this._beginTimePoints.pop() ?? endTimePoint;
const operationName = this._operationNames.pop();
if (operationName) { // Add data to queue now, calculate time later; helps eliminate time spent timing things in 'Total Time'
if (this._updateallTimePoints1) // Push to currently active allTimePoints buffer
this._allTimePoints1.push({ begin: beginTimePoint, end: endTimePoint, name: operationName });
else
this._allTimePoints2.push({ begin: beginTimePoint, end: endTimePoint, name: operationName });
}
}
endFrame() {
this.endOperation();
// Use double buffering here to ensure that we grab a COMPLETE set of timings from a SINGLE run when grabbing timing data while continuously rendering
this._updateallTimePoints1 = !this._updateallTimePoints1; // Switch to other allTimePoints buffer
if (this._updateallTimePoints1) { // Get data from the old buffer that was just completed
this._allTimePoints2.forEach((record) => this.frameTimings.set(record.name, record.end.milliseconds - record.begin.milliseconds));
this._allTimePoints2 = []; // Reset to empty
}
else {
this._allTimePoints1.forEach((record) => this.frameTimings.set(record.name, record.end.milliseconds - record.begin.milliseconds));
this._allTimePoints1 = []; // Reset to empty
}
this._beginTimePoints = []; // This should be back to [] at this point
this._operationNames = []; // This should be back to [] at this point
}
completeFrameTimings(fbo) {
if (this.gatherCurPerformanceMetrics) {
const fpsTimerElapsed = this.fpsTimer.currentSeconds - this.fpsTimerStart;
if (this.spfTimes[this.curSpfTimeIndex])
this.spfSum -= this.spfTimes[this.curSpfTimeIndex];
this.spfSum += fpsTimerElapsed;
this.spfTimes[this.curSpfTimeIndex] = fpsTimerElapsed;
this.curSpfTimeIndex++;
if (this.curSpfTimeIndex >= 50)
this.curSpfTimeIndex = 0;
this.fpsTimerStart = this.fpsTimer.currentSeconds;
}
const system = System.instance;
if (this.gatherGlFinish && !system.isGLTimerSupported) {
this.beginOperation("Finish GPU Queue");
// Ensure all previously queued webgl commands are finished by reading back one pixel since gl.Finish didn't work
const bytes = new Uint8Array(4);
const gl = system.context;
system.frameBufferStack.execute(fbo, true, false, () => {
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, bytes);
});
this.endOperation();
}
this.endFrame();
}
}
//# sourceMappingURL=PerformanceMetrics.js.map