playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
175 lines (174 loc) • 5.21 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { TRACEID_GPU_TIMINGS } from "../../core/constants.js";
import { Debug } from "../../core/debug.js";
import { Tracing } from "../../core/tracing.js";
class GpuProfiler {
constructor() {
/**
* Profiling slots allocated for the current frame, storing the names of the slots.
*
* @type {string[]}
* @ignore
*/
__publicField(this, "frameAllocations", []);
/**
* Map of past frame allocations, indexed by renderVersion
*
* @type {Map<number, string[]>}
* @ignore
*/
__publicField(this, "pastFrameAllocations", /* @__PURE__ */ new Map());
/**
* True if enabled in the current frame.
*
* @private
*/
__publicField(this, "_enabled", false);
/**
* The enable request for the next frame.
*
* @private
*/
__publicField(this, "_enableRequest", false);
/**
* The time it took to render the last frame on GPU, or 0 if the profiler is not enabled.
*
* @private
*/
__publicField(this, "_frameTime", 0);
/**
* Per-pass timing data, with accumulated timings for passes with the same name.
*
* @type {Map<string, number>}
* @private
*/
__publicField(this, "_passTimings", /* @__PURE__ */ new Map());
/**
* Cache for parsed pass names to avoid repeated string operations.
*
* @type {Map<string, string>}
* @private
*/
__publicField(this, "_nameCache", /* @__PURE__ */ new Map());
/**
* The maximum number of slots that can be allocated during the frame.
*/
__publicField(this, "maxCount", 9999);
}
loseContext() {
this.pastFrameAllocations.clear();
}
/**
* True to enable the profiler.
*
* @type {boolean}
*/
set enabled(value) {
this._enableRequest = value;
}
get enabled() {
return this._enableRequest;
}
/**
* Get the per-pass timing data.
*
* @type {Map<string, number>}
* @ignore
*/
get passTimings() {
return this._passTimings;
}
processEnableRequest() {
if (this._enableRequest !== this._enabled) {
this._enabled = this._enableRequest;
if (!this._enabled) {
this._frameTime = 0;
}
}
}
request(renderVersion) {
this.pastFrameAllocations.set(renderVersion, this.frameAllocations);
this.frameAllocations = [];
}
/**
* Parse a render pass name to a simplified form for stats.
* Uses a cache to avoid repeated string operations.
*
* @param {string} name - The original pass name (e.g., "RenderPassCompose").
* @returns {string} The parsed name (e.g., "compose").
* @private
*/
_parsePassName(name) {
let parsedName = this._nameCache.get(name);
if (parsedName === void 0) {
if (name.startsWith("RenderPass")) {
parsedName = name.substring(10);
} else {
parsedName = name;
}
this._nameCache.set(name, parsedName);
}
return parsedName;
}
report(renderVersion, timings) {
if (timings) {
const allocations = this.pastFrameAllocations.get(renderVersion);
if (!allocations) {
return;
}
Debug.assert(allocations.length === timings.length);
if (timings.length > 0) {
this._frameTime = timings.reduce((sum, t) => sum + t, 0);
}
this._passTimings.clear();
for (let i = 0; i < allocations.length; ++i) {
const name = allocations[i];
const timing = timings[i];
const parsedName = this._parsePassName(name);
this._passTimings.set(parsedName, (this._passTimings.get(parsedName) || 0) + timing);
}
if (Tracing.get(TRACEID_GPU_TIMINGS)) {
Debug.trace(TRACEID_GPU_TIMINGS, `-- GPU timings for frame ${renderVersion} --`);
let total = 0;
for (let i = 0; i < allocations.length; ++i) {
const name = allocations[i];
total += timings[i];
Debug.trace(TRACEID_GPU_TIMINGS, `${timings[i].toFixed(2)} ms ${name}`);
}
Debug.trace(TRACEID_GPU_TIMINGS, `${total.toFixed(2)} ms TOTAL`);
}
}
this.pastFrameAllocations.delete(renderVersion);
}
/**
* Allocate a slot for GPU timing during the frame. This slot is valid only for the current
* frame. This allows multiple timers to be used during the frame, each with a unique name.
*
* @param {string} name - The name of the slot.
* @returns {number} The assigned slot index, or -1 if the slot count exceeds the maximum number
* of slots.
*
* @ignore
*/
getSlot(name) {
if (this.frameAllocations.length >= this.maxCount) {
return -1;
}
const slot = this.frameAllocations.length;
this.frameAllocations.push(name);
return slot;
}
/**
* Number of slots allocated during the frame.
*
* @ignore
*/
get slotCount() {
return this.frameAllocations.length;
}
}
export {
GpuProfiler
};