UNPKG

@itwin/core-frontend

Version:
98 lines 5.29 kB
/*--------------------------------------------------------------------------------------------- * 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