playcanvas
Version:
PlayCanvas WebGL game engine
150 lines (147 loc) • 6.72 kB
JavaScript
import { Debug } from '../../../core/debug.js';
import { DebugGraphics } from '../debug-graphics.js';
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
/**
* @import { WebgpuGraphicsDevice } from './webgpu-graphics-device.js'
*/ // Maximum number of times a duplicate error message is logged.
var MAX_DUPLICATES = 5;
/**
* Internal WebGPU debug system. Note that the functions only execute in the debug build, and are
* stripped out in other builds.
*/ class WebgpuDebug {
/**
* Start a validation error scope.
*
* @param {WebgpuGraphicsDevice} device - The graphics device.
*/ static validate(device) {
device.wgpu.pushErrorScope('validation');
WebgpuDebug._scopes.push('validation');
WebgpuDebug._markers.push(DebugGraphics.toString());
}
/**
* Start an out-of-memory error scope.
*
* @param {WebgpuGraphicsDevice} device - The graphics device.
*/ static memory(device) {
device.wgpu.pushErrorScope('out-of-memory');
WebgpuDebug._scopes.push('out-of-memory');
WebgpuDebug._markers.push(DebugGraphics.toString());
}
/**
* Start an internal error scope.
*
* @param {WebgpuGraphicsDevice} device - The graphics device.
*/ static internal(device) {
device.wgpu.pushErrorScope('internal');
WebgpuDebug._scopes.push('internal');
WebgpuDebug._markers.push(DebugGraphics.toString());
}
/**
* End the previous error scope, and print errors if any.
*
* @param {WebgpuGraphicsDevice} device - The graphics device.
* @param {string} label - The label for the error scope.
* @param {...any} args - Additional parameters that form the error message.
*/ static end(device, label) {
for(var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
args[_key - 2] = arguments[_key];
}
return _async_to_generator(function*() {
var header = WebgpuDebug._scopes.pop();
var marker = WebgpuDebug._markers.pop();
Debug.assert(header, 'Non matching end.');
var error = yield device.wgpu.popErrorScope();
if (error) {
var _WebgpuDebug__loggedMessages_get;
var count = (_WebgpuDebug__loggedMessages_get = WebgpuDebug._loggedMessages.get(error.message)) != null ? _WebgpuDebug__loggedMessages_get : 0;
if (count < MAX_DUPLICATES) {
var tooMany = count === MAX_DUPLICATES - 1 ? ' (Too many errors, ignoring this one from now)' : '';
WebgpuDebug._loggedMessages.set(error.message, count + 1);
console.error("WebGPU " + label + " " + header + " error: " + error.message, tooMany, 'while rendering', marker, ...args);
}
}
})();
}
/**
* Ends the shader validation scope by retrieving and logging any compilation errors
* or warnings from the shader module. Also handles WebGPU validation errors, while
* avoiding duplicate error messages.
*
* @param {WebgpuGraphicsDevice} device - The WebGPU graphics device.
* @param {GPUShaderModule} shaderModule - The compiled WebGPU shader module.
* @param {string} source - The original shader source code.
* @param {number} [contextLines] - The number of lines before and after the error to log.
* @param {...any} args - Additional parameters providing context about the shader.
*/ static endShader(device, shaderModule, source, contextLines) {
if (contextLines === void 0) contextLines = 2;
for(var _len = arguments.length, args = new Array(_len > 4 ? _len - 4 : 0), _key = 4; _key < _len; _key++){
args[_key - 4] = arguments[_key];
}
return _async_to_generator(function*() {
var header = WebgpuDebug._scopes.pop();
var marker = WebgpuDebug._markers.pop();
Debug.assert(header, 'Non-matching error scope end.');
// Capture popErrorScope error (if any)
var error = yield device.wgpu.popErrorScope();
var errorMessage = '';
if (error) {
errorMessage += "WebGPU ShaderModule creation " + header + " error: " + error.message;
errorMessage += " - While rendering " + marker + "\n";
}
// Get shader compilation errors
var compilationInfo = yield shaderModule.getCompilationInfo();
if (compilationInfo.messages.length > 0) {
// split source into lines
var sourceLines = source.split('\n');
compilationInfo.messages.forEach((message, index)=>{
var { type, lineNum, linePos, message: msg } = message;
var lineIndex = lineNum - 1; // Convert to zero-based index
errorMessage += "\n----- " + type.toUpperCase() + " " + (index + 1) + " context: :" + lineNum + ":" + linePos + " " + type + ": " + msg + "\n";
// Extract surrounding lines for context
var startLine = Math.max(0, lineIndex - contextLines);
var endLine = Math.min(sourceLines.length, lineIndex + contextLines + 1);
for(var i = startLine; i < endLine; i++){
var linePrefix = i === lineIndex ? '> ' : ' ';
errorMessage += "" + linePrefix + (i + 1) + ": " + sourceLines[i] + "\n";
}
});
}
// only log if there are errors or messages
if (errorMessage) {
console.error(errorMessage, ...args);
}
})();
}
}
WebgpuDebug._scopes = [];
WebgpuDebug._markers = [];
/** @type {Map<string,number>} */ WebgpuDebug._loggedMessages = new Map();
export { WebgpuDebug };