Skip to content

Commit b15f3f1

Browse files
mvaligurskyMartin Valigursky
andauthored
Improved WebGPU error reporting, main focus on shader compilation issues (#7435)
* Improved WebGPU error reporting, main focus on shader compilation issues * remove commented out line * word change --------- Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
1 parent 506ef55 commit b15f3f1

9 files changed

+80
-24
lines changed

src/platform/graphics/webgpu/webgpu-bind-group.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class WebgpuBindGroup {
2929

3030
this.bindGroup = device.wgpu.createBindGroup(desc);
3131

32-
WebgpuDebug.end(device, {
32+
WebgpuDebug.end(device, 'BindGroup creation', {
3333
debugFormat: this.debugFormat,
3434
desc: desc,
3535
format: bindGroup.format,

src/platform/graphics/webgpu/webgpu-compute-pipeline.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class WebgpuComputePipeline extends WebgpuPipeline {
4949
DebugHelper.setLabel(pipeline, `ComputePipeline-${_pipelineId}`);
5050
Debug.trace(TRACEID_COMPUTEPIPELINE_ALLOC, `Alloc: Id ${_pipelineId}`, desc);
5151

52-
WebgpuDebug.end(this.device, {
52+
WebgpuDebug.end(this.device, 'ComputePipeline creation', {
5353
computePipeline: this,
5454
desc: desc,
5555
shader

src/platform/graphics/webgpu/webgpu-debug.js

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,23 +57,78 @@ class WebgpuDebug {
5757
* End the previous error scope, and print errors if any.
5858
*
5959
* @param {WebgpuGraphicsDevice} device - The graphics device.
60+
* @param {string} label - The label for the error scope.
6061
* @param {...any} args - Additional parameters that form the error message.
6162
*/
62-
static end(device, ...args) {
63+
static async end(device, label, ...args) {
6364
const header = WebgpuDebug._scopes.pop();
6465
const marker = WebgpuDebug._markers.pop();
6566
Debug.assert(header, 'Non matching end.');
6667

67-
device.wgpu.popErrorScope().then((error) => {
68-
if (error) {
69-
const count = WebgpuDebug._loggedMessages.get(error.message) ?? 0;
70-
if (count < MAX_DUPLICATES) {
71-
const tooMany = count === MAX_DUPLICATES - 1 ? ' (Too many errors, ignoring this one from now)' : '';
72-
WebgpuDebug._loggedMessages.set(error.message, count + 1);
73-
console.error(`WebGPU ${header} error: ${error.message}`, tooMany, 'while rendering', marker, ...args);
74-
}
68+
const error = await device.wgpu.popErrorScope();
69+
if (error) {
70+
const count = WebgpuDebug._loggedMessages.get(error.message) ?? 0;
71+
if (count < MAX_DUPLICATES) {
72+
const tooMany = count === MAX_DUPLICATES - 1 ? ' (Too many errors, ignoring this one from now)' : '';
73+
WebgpuDebug._loggedMessages.set(error.message, count + 1);
74+
console.error(`WebGPU ${label} ${header} error: ${error.message}`, tooMany, 'while rendering', marker, ...args);
7575
}
76-
});
76+
}
77+
}
78+
79+
/**
80+
* Ends the shader validation scope by retrieving and logging any compilation errors
81+
* or warnings from the shader module. Also handles WebGPU validation errors, while
82+
* avoiding duplicate error messages.
83+
*
84+
* @param {WebgpuGraphicsDevice} device - The WebGPU graphics device.
85+
* @param {GPUShaderModule} shaderModule - The compiled WebGPU shader module.
86+
* @param {string} source - The original shader source code.
87+
* @param {number} [contextLines] - The number of lines before and after the error to log.
88+
* @param {...any} args - Additional parameters providing context about the shader.
89+
*/
90+
static async endShader(device, shaderModule, source, contextLines = 2, ...args) {
91+
const header = WebgpuDebug._scopes.pop();
92+
const marker = WebgpuDebug._markers.pop();
93+
Debug.assert(header, 'Non-matching error scope end.');
94+
95+
// Capture popErrorScope error (if any)
96+
const error = await device.wgpu.popErrorScope();
97+
let errorMessage = '';
98+
99+
if (error) {
100+
errorMessage += `WebGPU ShaderModule creation ${header} error: ${error.message}`;
101+
errorMessage += ` - While rendering ${marker}\n`;
102+
}
103+
104+
// Get shader compilation errors
105+
const compilationInfo = await shaderModule.getCompilationInfo();
106+
107+
if (compilationInfo.messages.length > 0) {
108+
// split source into lines
109+
const sourceLines = source.split('\n');
110+
111+
compilationInfo.messages.forEach((message, index) => {
112+
const { type, lineNum, linePos, message: msg } = message;
113+
const lineIndex = lineNum - 1; // Convert to zero-based index
114+
115+
errorMessage += `\n----- ${type.toUpperCase()} ${index + 1} context: :${lineNum}:${linePos} ${type}: ${msg}\n`;
116+
117+
// Extract surrounding lines for context
118+
const startLine = Math.max(0, lineIndex - contextLines);
119+
const endLine = Math.min(sourceLines.length, lineIndex + contextLines + 1);
120+
121+
for (let i = startLine; i < endLine; i++) {
122+
const linePrefix = i === lineIndex ? '> ' : ' ';
123+
errorMessage += `${linePrefix}${i + 1}: ${sourceLines[i]}\n`;
124+
}
125+
});
126+
}
127+
128+
// only log if there are errors or messages
129+
if (errorMessage) {
130+
console.error(errorMessage, ...args);
131+
}
77132
}
78133
}
79134

src/platform/graphics/webgpu/webgpu-graphics-device.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,8 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
427427
// assign current frame's render texture
428428
wrt.assignColorTexture(this, outColorBuffer);
429429

430-
WebgpuDebug.end(this);
431-
WebgpuDebug.end(this);
430+
WebgpuDebug.end(this, 'frameStart');
431+
WebgpuDebug.end(this, 'frameStart');
432432
}
433433

434434
frameEnd() {
@@ -587,7 +587,7 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
587587
passEncoder.draw(primitive.count, numInstances, primitive.base, 0);
588588
}
589589

590-
WebgpuDebug.end(this, {
590+
WebgpuDebug.end(this, 'Drawing', {
591591
vb0,
592592
vb1,
593593
ib,
@@ -787,8 +787,8 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
787787
}
788788
}
789789

790-
WebgpuDebug.end(this, { renderPass });
791-
WebgpuDebug.end(this, { renderPass });
790+
WebgpuDebug.end(this, 'RenderPass', { renderPass });
791+
WebgpuDebug.end(this, 'RenderPass', { renderPass });
792792
}
793793

794794
startComputePass(name) {
@@ -821,8 +821,8 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
821821
// each render pass can use different number of bind groups
822822
this.bindGroupFormats.length = 0;
823823

824-
WebgpuDebug.end(this);
825-
WebgpuDebug.end(this);
824+
WebgpuDebug.end(this, 'ComputePass');
825+
WebgpuDebug.end(this, 'ComputePass');
826826
}
827827

828828
computeDispatch(computes, name = 'Unnamed') {

src/platform/graphics/webgpu/webgpu-render-pipeline.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
365365
DebugHelper.setLabel(pipeline, `RenderPipeline-${_pipelineId}`);
366366
Debug.trace(TRACEID_RENDERPIPELINE_ALLOC, `Alloc: Id ${_pipelineId}, stack: ${DebugGraphics.toString()}`, desc);
367367

368-
WebgpuDebug.end(this.device, {
368+
WebgpuDebug.end(this.device, 'RenderPipeline creation', {
369369
renderPipeline: this,
370370
desc: desc,
371371
shader

src/platform/graphics/webgpu/webgpu-render-target.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,8 @@ class WebgpuRenderTarget {
275275

276276
this.initialized = true;
277277

278-
WebgpuDebug.end(device, { renderTarget });
279-
WebgpuDebug.end(device, { renderTarget });
278+
WebgpuDebug.end(device, 'RenderTarget initialization', { renderTarget });
279+
WebgpuDebug.end(device, 'RenderTarget initialization', { renderTarget });
280280
}
281281

282282
initDepthStencil(device, wgpu, renderTarget) {

src/platform/graphics/webgpu/webgpu-shader.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class WebgpuShader {
118118
});
119119
DebugHelper.setLabel(shaderModule, `${shaderType}:${this.shader.label}`);
120120

121-
WebgpuDebug.end(device, {
121+
WebgpuDebug.endShader(device, shaderModule, code, 6, {
122122
shaderType,
123123
source: code,
124124
shader: this.shader

src/platform/graphics/webgpu/webgpu-texture.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class WebgpuTexture {
120120
this.gpuTexture = wgpu.createTexture(this.desc);
121121
DebugHelper.setLabel(this.gpuTexture, `${texture.name}${texture.cubemap ? '[cubemap]' : ''}${texture.volume ? '[3d]' : ''}`);
122122

123-
WebgpuDebug.end(device, {
123+
WebgpuDebug.end(device, 'Texture creation', {
124124
desc: this.desc,
125125
texture
126126
});

utils/rollup-build-target.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const STRIP_FUNCTIONS = [
6161
'WebgpuDebug.memory',
6262
'WebgpuDebug.internal',
6363
'WebgpuDebug.end',
64+
'WebgpuDebug.endShader',
6465
'WorldClustersDebug.render'
6566
];
6667

0 commit comments

Comments
 (0)