跳到主要内容

WebGL扩展与移动端

桌面 Chrome 能跑不等于手机能跑。移动端的差异不是「API 名字」,而是 limits、可渲染格式、上下文会被系统收回、GPU 会降频。生产默认 WebGL2:实例化、VAO、多 render target 已是核心,不要按 WebGL1 扩展表抄。

1. 必查 MAX_TEXTURE_SIZE(以及一串 limits)

export interface GlLimits {
maxTextureSize: number;
maxRenderbufferSize: number;
maxViewport: readonly [number, number];
maxColorAttachments: number;
}

export function readGlLimits(gl: WebGL2RenderingContext): GlLimits {
const vp = gl.getParameter(gl.MAX_VIEWPORT_DIMS) as Int32Array;
return {
maxTextureSize: gl.getParameter(gl.MAX_TEXTURE_SIZE) as number,
maxRenderbufferSize: gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) as number,
maxViewport: [vp[0] ?? 0, vp[1] ?? 0],
maxColorAttachments: gl.getParameter(gl.MAX_COLOR_ATTACHMENTS) as number,
};
}

旧移动 GPU 常见 4096;桌面 8192 / 16384。超了:纹理黑、FBO incomplete、或缩小 drawing buffer。图集和离屏按 探测值 切块,不要写死 8192。DPR 封顶见 05

还要看:MAX_VERTEX_UNIFORM_VECTORSMAX_TEXTURE_IMAGE_UNITSMAX_SAMPLES。超 uniform 的失败形态是链接成功、画面错,不一定有清晰 log。

2. 浮点纹理:采样 ≠ 可渲染 ≠ 线性过滤

WebGL2 核心能 创建 部分 float / half 格式当纹理。这不表示:

  • 能绑成 FBO 颜色附件(要 EXT_color_buffer_float / EXT_color_buffer_half_float);
  • LINEAR 过滤(要 OES_texture_float_linear / OES_texture_half_float_linear)。
export interface FloatCaps {
renderable: boolean;
halfRenderable: boolean;
floatLinear: boolean;
}

export function detectFloatCaps(gl: WebGL2RenderingContext): FloatCaps {
return {
renderable: gl.getExtension("EXT_color_buffer_float") !== null,
halfRenderable: gl.getExtension("EXT_color_buffer_half_float") !== null,
floatLinear: gl.getExtension("OES_texture_float_linear") !== null,
};
}

适用:HDR 中间缓冲、G-buffer、粒子模拟读回纹理。
不适用:假设 iOS / 低端 Android 能线性采样 RGBA32F。失败就降半精度、关线性、或把 pass 挪回 Canvas 2D 小分辨率。

WEBGL_depth_texture 在 WebGL2 不需要(深度纹理核心有)。查它当能力位会误判。

3. 实例化是 WebGL2 核心

drawArraysInstanceddrawElementsInstancedvertexAttribDivisor 不必 ANGLE_instanced_arrays。只有明确降级 WebGL1 才 get 该扩展。合批见 06

移动端实例化能跑,不等于万实例 × 复杂 FS 能 60fps。先砍 overdraw 和纹理带宽。

4. iOS 丢失与热节流

Safari / WKWebView 在内存压力、切 App、系统杀 GPU 时发 webglcontextlost。必须 preventDefault + 资源表重建,见 04。iOS 上「偶发白屏」优先查丢失,而不是 shader。

热节流:掉帧时 EXT_disjoint_timer_query_webgl2GPU_DISJOINT_EXT 会跳。温度上来之后同一套 draw 变慢,不是合批突然坏了。对策:封顶 DPR、降粒子、降 shadow pass;不要在节流时加大分辨率「补偿清晰度」。

failIfMajorPerformanceCaveat: true:避免软件实现冒充 GPU。移动端拿到 caveat 时应走 2D / 静态图,不要静默 5fps。

5. 其它移动端边角

项目处理
precision highp float 在 FS部分 GPU 降 mediump;颜色条带时显式探测
动态循环 / 非 constant 索引编译失败只在真机
antialias: true隐式 MSAA 吃带宽;需要时自建 FBO
视频纹理texImage2D 视频帧 + CORS;不要经 2D canvas 多拷一次
后台hidden 停 rAF 上传,见 04 提交

图标、可复制文字、无障碍不要用 GL 冒充 DOM,走 SVG

6. 失败形态

症状原因
大图黑、小图好MAX_TEXTURE_SIZE
HDR pass 桌面好、iOS 黑EXT_color_buffer_float
float 贴图马赛克无 float linear,NEAREST 或未降级
切回 App 白屏丢失未重建
过一会儿掉到 20fps热节流,还在 3x DPR + MSAA
getContext 成功但 5fps软件光栅,未设 caveat

权威资料

核对日期:2026-08-26