WebGPU代码Chrome正常显示三角形,Firefox仅显示背景求助
问题
以下代码在Chrome Dev 113中可正常显示三角形,但在Firefox Nightly 116中仅显示背景色,该问题在Linux和Android系统中均出现(未测试Windows及macOS)。已知WebGPU仍处于开发阶段,但官方WebGPU示例可在两款浏览器中正常运行,请问代码存在什么问题?
代码如下:
export class Graphics3D { #gpu; #adapter; #device; /** * @type {HTMLCanvasElement} */ #canvas; #context; #renderPipeline; #vertices; #vertexBuffer; /** * * @param {HTMLCanvasElement} canvas */ constructor(canvas) { this.#canvas = canvas; } /** * * @param {HTMLCanvasElement} canvas * @returns {Promise<void>} */ async init() { this.#gpu = navigator.gpu; if (!this.#gpu) { throw Error("WebGPU not supported"); } this.#adapter = await this.#gpu.requestAdapter(); if (!this.#adapter) { throw Error("Couldn't request WebGPU adapter."); } this.#device = await this.#adapter.requestDevice(); /** * @type {HTMLScriptElement} */ const shadersElement = document.getElementById('wgsl-shaders'); const shaderModule = this.#device.createShaderModule({ code: shadersElement.textContent, }); this.#context = this.#canvas.getContext("webgpu"); this.#context.configure({ device: this.#device, format: this.#gpu.getPreferredCanvasFormat(), alphaMode: "premultiplied", }); this.#vertices = new Float32Array([ // Vertex 1 -1, -1, 0, 1, // XYZW 1, 0, 0, 1, // RGBA // Vertex 2 1, -1, 0, 1, // XYZW 0, 1, 0, 1, // RGBA // Vertex 3 0, 1, 0, 1, // XYZW 0, 0, 1, // RGBA ]); this.#vertexBuffer = this.#device.createBuffer({ size: this.#vertices.byteLength, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, }); this.#device.queue.writeBuffer(this.#vertexBuffer, 0, this.#vertices, 0, this.#vertices.length); this.#renderPipeline = this.#device.createRenderPipeline({ vertex: { module: shaderModule, entryPoint: "vertex_main", buffers: [{ attributes: [{ shaderLocation: 0, // position offset: 0, format: "float32x4", }, { shaderLocation: 1, // color offset: 16, format: "float32x4", }], arrayStride: 32, stepMode: "vertex", }], }, fragment: { module: shaderModule, entryPoint: "fragment_main", targets: [{ format: this.#gpu.getPreferredCanvasFormat(), }], }, primitive: { topology: "triangle-list", frontFace: "ccw", }, layout: "auto", }); } /** * * @param {DOMHighResTimeStamp} _timestamp */ render(_timestamp) { const commandEncoder = this.#device.createCommandEncoder(); const passEncoder = commandEncoder.beginRenderPass({ colorAttachments: [{ clearValue: { r: 0.0, g: 0.5, b: 1.0, a: 1.0 }, loadOp: "clear", storeOp: "store", view: this.#context.getCurrentTexture().createView(), }], }); passEncoder.setPipeline(this.#renderPipeline); passEncoder.setVertexBuffer(0, this.#vertexBuffer); passEncoder.draw(3); passEncoder.end(); this.#device.queue.submit([commandEncoder.finish()]); } }
问题分析与解决
导致跨浏览器差异的核心原因是WGSL着色器未严格遵循WebGPU规范,Firefox对规范的执行更为严格,而Chrome做了兼容处理,重点排查并修正以下几点:
1. 着色器的规范标注缺失
WebGPU强制要求着色器入口和关键变量必须添加规范修饰符:
- 顶点着色器需用
@vertex标注入口函数,输出变量必须带@builtin(position)修饰(表示最终屏幕位置),输入变量要用@location(n)对应代码中设置的shaderLocation - 片段着色器需用
@fragment标注入口函数,输出变量需用@location(0)对应渲染管线的颜色目标
示例正确着色器结构:
// 顶点着色器 @vertex fn vertex_main( @location(0) position: vec4<f32>, @location(1) color: vec4<f32> ) -> @builtin(position) vec4<f32> { return position; } // 片段着色器 @fragment fn fragment_main(@location(0) color: vec4<f32>) -> @location(0) vec4<f32> { return color; }
2. 顶点缓冲区写入参数优化
代码中writeBuffer的最后一个参数是手动传入的元素数,可省略该参数,让浏览器自动计算写入字节数,避免手动计算错误:
// 优化后 this.#device.queue.writeBuffer(this.#vertexBuffer, 0, this.#vertices);
3. Canvas尺寸匹配
确保Canvas的width/height属性与实际显示像素一致,避免因分辨率不匹配导致渲染区域异常:
// 在configure上下文前添加 const dpr = window.devicePixelRatio; this.#canvas.width = this.#canvas.clientWidth * dpr; this.#canvas.height = this.#canvas.clientHeight * dpr;
以上几点中,着色器的规范标注是导致Firefox不渲染图形的最可能原因,优先修正WGSL代码即可解决问题。
内容的提问来源于stack exchange,提问作者James Downer
相关产品推荐
相关产品推荐

