You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:07:15