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

部分Intel集成显卡WebGL着色器输出异常问题排查

WebGL着色器跨GPU平台输出不一致问题

问题现象

同一段WebGL着色器在Apple M1设备(iMac/iPhone)和Intel Haswell-ULT集成显卡设备(Thinkpad 440、Thinkpad 13 Chromebook)上输出完全不同:

  • 同一设备上不同浏览器输出一致:M1设备上Chrome/Safari输出相同,Intel设备上Chrome/GNOME Web输出相同
  • 多数测试者看到的是Apple版本输出,仅少数Intel设备显示差异版本

原始着色器代码

JS逻辑

const gl = document.querySelector("canvas").getContext("webgl");
gl.canvas.width = gl.canvas.height = 512
gl.viewport(0, 0, 512, 512);
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  a_Position: {
    numComponents: 2,
    data: [-1, -1, -1, 3, 3, -1]
  },
});
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);

顶点着色器

attribute vec4 a_Position;

varying vec2 v_Position;
varying vec2 v_TexCoord;

void main() {
    v_Position = a_Position.xy;
    v_TexCoord = a_Position.xy / 2.0 + 0.5;
    gl_Position = a_Position;
}

片段着色器

precision highp float;

varying vec2 v_Position;
varying vec2 v_TexCoord;

vec2 compMult(vec2 u, vec2 v) {
  return vec2(u.x * v.x - u.y * v.y, u.x * v.y + u.y * v.x);
}

vec2 G(vec3 x) {
  float lenx = length(x);
  float ang = 350.0 * lenx;
  return vec2(cos(ang), sin(ang)) / lenx;
}

void main() {
  gl_FragColor.a = 1.0;
  vec3 x0 = vec3(v_TexCoord, 1);
  vec2 amplitude;
  for(int i = 0; i < 10; i++) {
    for(int j = 0; j < 10; j++) {
      vec2 pos = 0.05 + vec2(i, j) / 10.0;
      vec3 x = vec3(0.4 + 0.2 * pos, 0);
      float disx0x = distance(x0, x);
      amplitude += compMult(
        G(x - vec3(-0.4765625, -0.671875, 300)),
        compMult(
          vec2(-1.0 / disx0x, 350.0),
          G(x - x0) / disx0x
        )
      );
    }
  }
  gl_FragColor.r = length(amplitude) / 10.0;
}

设备输出对比

  • Apple设备输出:Apple设备WebGL输出
  • Intel设备输出:Intel设备WebGL输出

简化测试代码(无循环版本)

JS逻辑(与原始一致)

const gl = document.querySelector("canvas").getContext("webgl");
gl.canvas.width = gl.canvas.height = 512
gl.viewport(0, 0, 512, 512);
const programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
const bufferInfo = twgl.createBufferInfoFromArrays(gl, {
  a_Position: {
    numComponents: 2,
    data: [-1, -1, -1, 3, 3, -1]
  },
});
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);

顶点着色器(与原始一致)

attribute vec4 a_Position;

varying vec2 v_Position;
varying vec2 v_TexCoord;

void main() {
    v_Position = a_Position.xy;
    v_TexCoord = a_Position.xy / 2.0 + 0.5;
    gl_Position = a_Position;
}

片段着色器

precision highp float;

varying vec2 v_Position;
varying vec2 v_TexCoord;

vec2 compMult(vec2 u, vec2 v) {
  return vec2(u.x * v.x - u.y * v.y, u.x * v.y + u.y * v.x);
}

vec2 G(vec3 x) {
  float lenx = length(x);
  float ang = 350.0 * lenx;
  return vec2(cos(ang), sin(ang)) / lenx;
}

void main() {
  gl_FragColor.a = 1.0;
  vec3 x0 = vec3(v_TexCoord, 1);
  vec2 pos = floor(8.0 * v_TexCoord) / 8.0;
  vec3 x = vec3(0.375 + 0.25 * pos, 0);
  float disx0x = distance(x0, x);
  vec2 amplitude = compMult(
    G(x - vec3(-0.46875, -0.5, 300.0)),
    compMult(
      vec2(-1.0 / disx0x, 350.0),
      G(x - x0)
    )
  );
  gl_FragColor.rgb = vec3(0.5 + amplitude, 0.5);
}

简化代码的异常表现

Intel设备上出现不符合预期的灰色区块:Intel设备简化代码输出
从算法逻辑看,灰色区域应与其他区块表现一致,且已确认:

  • 未使用小数值除法导致精度问题
  • distance(x, x0)与distance(x, vec3(-0.46875, -0.5, 300))数值均不会过小
  • 常量已改为精确二进制表示

问题原因与解决建议

核心原因

这种跨GPU平台的输出差异,本质是不同GPU硬件对浮点数运算的精度实现存在差异,尤其是在涉及三角函数和复杂向量运算的场景:

  1. 三角函数精度放大偏差:cos(350.0 * lenx)和sin(350.0 * lenx)中,350是大系数,微小的lenx计算差异会被放大,导致角度计算出现明显偏差,最终影响G函数的输出向量。
  2. 运算顺序优化差异:不同GPU的编译器会对运算顺序进行不同的优化(比如乘法结合律的应用),在多次复数乘法(compMult)的累积计算中,微小的精度误差会被叠加放大,最终导致输出结果完全不同。
  3. Intel Haswell架构浮点特性:Haswell集成显卡在高精度浮点运算的一致性上,与Apple M1 GPU存在差异,尤其是处理大系数缩放的三角函数时,误差累积更明显。

解决建议

  • 对三角函数的输入角度进行模2π处理,避免角度过大导致的精度丢失:float ang = mod(350.0 * lenx, 2.0 * 3.14159265);
  • 调整运算顺序,减少误差累积,比如将除法运算提前或拆分复杂的复合乘法
  • 添加微小偏移量避免极端情况:lenx = max(length(x), 1e-6);,防止除零或精度突变

内容的提问来源于stack exchange,提问作者fweth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 16:45:44