4.5 扩展补丁 vs WebGL2 内置 本节摘要:WebGL1 用扩展把一批 ES 3 能力提前塞进浏览器:VAO、实例化、深度纹理、多绘制缓冲、浮点纹理、元素索引 32 位。WebGL2 把其中多数收进核心,着色器升到 300 es,并补上变换反馈、三维纹理、UBO 这些扩展补不全的洞。继续在 1.0 上堆扩展,是在维护一张会漂的能力矩阵;迁 2.0 是换合同。能锁 2.0 就少写检测。必须兼容 1.0 时,把扩展失败映射成效果降级,而不是同一条路径硬跑。 本节导航 阅读完本节,你应当能够: 把常用 WebGL1 扩展对应到 WebGL2 核心对象或函数 列出扩展补不上、必须 2.
本节摘要:WebGL1 用扩展把一批 ES 3 能力提前塞进浏览器:VAO、实例化、深度纹理、多绘制缓冲、浮点纹理、元素索引 32 位。WebGL2 把其中多数收进核心,着色器升到 300 es,并补上变换反馈、三维纹理、UBO 这些扩展补不全的洞。继续在 1.0 上堆扩展,是在维护一张会漂的能力矩阵;迁 2.0 是换合同。能锁 2.0 就少写检测。必须兼容 1.0 时,把扩展失败映射成效果降级,而不是同一条路径硬跑。
阅读完本节,你应当能够:
getExtension("OES_vertex_array_object") 成功时,你得到另一套函数名。失败时,你仍停在全局属性指针时代。浏览器可以改扩展支持,用户可以关硬件加速。把产品建立在一长串扩展上,等于把测试矩阵交给组合爆炸。WebGL2 的 createVertexArray 写在规范核心路径,测试从“各扩展是否存在”变成“上下文是否 2”。
补丁的价值是历史过渡:在 2.0 覆盖不足时,让 1.0 也能实例化草地。过渡期结束后,内部工具继续测扩展是亏的。面向老设备的营销页可以留在 1.0 加两三个最稳的扩展,而不是把 2.0 特性表用扩展逐条追。
WebGL1 核心 + 扩展矩阵 ≈ 部分 WebGL2 WebGL2 核心 ≈ ES 3.0 合同,仍无计算着色器
| 能力 | WebGL1 | WebGL2 |
|---|---|---|
| VAO | OES_vertex_array_object | 核心 |
| 实例化 | ANGLE_instanced_arrays | 核心 |
| 深度纹理 | WEBGL_depth_texture | 核心 |
| 多颜色附件 | WEBGL_draw_buffers | 核心 MRT |
| 浮点纹理 | OES_texture_float 等,过滤另扩 | 更完整 |
| 标准导数 | OES_standard_derivatives | 核心 |
| 32 位索引 | OES_element_index_uint | 核心 |
| sRGB | EXT_sRGB | 更完整 |
| 各向异性 | EXT_texture_filter_anisotropic | 仍常是扩展 |
| 压缩纹理 | 一堆平台扩展 | 仍是扩展矩阵 |
| 三维纹理 | 基本无 | 核心 |
| 变换反馈 | 无 | 核心 |
| UBO | 无 | 核心 |
| 整数纹理 | 无 | 核心 |
各向异性与压缩纹理提醒我们:2.0 不是“所有扩展退休”。资产压缩仍要按 GPU 家族回退。2.0 收编的是绘图对象模型,不是整个生态。
function tryVAO(gl) { if (gl.createVertexArray) return { create: gl.createVertexArray.bind(gl), native: true }; const ext = gl.getExtension("OES_vertex_array_object"); if (!ext) return null; return { create: ext.createVertexArrayOES.bind(ext), native: false }; }
注意 bind 到正确对象。把扩展函数接到丢失的 gl 上会在上下文恢复后炸掉。恢复流程要重新 getExtension。

检测代码可以深。产品表必须浅:无实例化则草地密度降成静态合批;无浮点 FBO 则 Bloom 关;无深度纹理则平面影。每一条扩展对应一条用户能感知的损失。没有表,程序员会嵌套六层 if 还以为有回退。
着色器不要用宏在一份字符串里同时服务 1.00 与 300 es,除非你有编译器。两套资产,CPU 按版本选。扩展启用的导数、instanced 输入,也要在着色器里用对应的扩展指令。漏指令则编译失败,表现为“这台机能拿扩展却画不出来”。
⚠️ 常见坑:开发机扩展齐全,CI 无头浏览器缺扩展,测试全绿、用户全黑。能力检测要在启动时打日志或遥测,而不是假设。
💡 关键直觉:扩展是租来的能力,核心是买来的能力。租约能应急,不能当房本。
各向异性过滤常常仍要扩展,2.0 里也是。地面材质可以检测,失败则 LINEAR_MIPMAP_LINEAR。这是画质档,不是功能档。功能档是“能不能画阴影贴图”;画质档是“斜看清不清”。分清两档,产品才知道哪条失败必须关功能,哪条只降一级过滤。
现有 WebGL 存量代码仍要管。新项目若锁现代浏览器,可直接 WebGL2 或评估 WebGPU。本文集合同停在 WebGL。把 WebGPU 当 WebGL3 扩展会误导:那是另一套对象模型。对照思维可迁移:仍问数据在哪一端、哪份合同。检测表不能迁移。
扩展组合爆炸时,用“能力包”而不是单点。包 A:VAO+实例化+深度纹理,对应 1.0 增强前向。包 B:再加 draw buffers 与浮点,对应简易后处理。包 C:2.0 核心,对应延迟与反馈。产品只承诺包,不承诺单个扩展名。某扩展缺了就整包降级,避免五层嵌套。遥测上报包等级,美术按包做三档资源。这是版本轴的运营化。
调试扩展如 WEBGL_debug_renderer_info、WEBGL_debug_shaders 不要在生产依赖。它们能帮你看 GPU 名与转译后的源码,转译源码对查移动端编译器很有用。但用户可以没有它们。生产路径只依赖绘图合同。
上下文属性 failIfMajorPerformanceCaveat 会在软件渲染时拒绝给上下文。要不要拒绝是产品问题:给软件渲染一张静图,还是让它以 2 帧运行。不要 silently 拿到软件渲染还按 60 帧做粒子。检测 renderer 字符串里的 SwiftShader 一类,降到静态。这不是扩展表,是创建合同,和 1.1 的 getContext 策略连在一起。
扩展启用指令在 GLSL 里必须匹配。GL_OES_standard_derivatives 在 1.0 FS 用 fwidth 做抗锯齿或法线,忘了指令就编译失败。2.0 里导数是核心。同一份抗锯齿逻辑,两套源码或用预处理器由 CPU 注入第一行。注入要测试,不要假设桌面编译器会忽略未知指令。
拿不到任何上下文时,产品应有静图或 CSS 方案。这不是 WebGL 失败,是设备合同。检测放在第一帧之前。给用户一句人话:三维预览不可用,而不是控制台 invalid。扩展失败同理,用人话对应降级表。遥测记包等级。没有静图路径的营销页,会在关键渠道全白。全白比低配 3D 更伤转化。版本选择从这里已经是产品,不只是图形。
缺扩展或 300 es 编译失败。启动打能力包与着色器日志。黑屏用人话静图。不要假设 ANGLE 桌面等于 Adreno。抽样四类机。黑屏优先当合同失败,不当随机。
else 分支复制粘贴漏改。降级表要测:强制 1.0 跑一遍 CI。空 fallback 比没有更危险,因为它给人已兼容的错觉。测失败路径与测成功路径同等重要。
可能落到软件渲染。检测 renderer,改静图或降粒子到零。继续跑完整 PBR 是在用 CPU 模拟 GPU,电量与体验双杀。创建时可 failIfMajorPerformanceCaveat。拿到 caveat 上下文要当失败处理。
CI 至少跑两档:强制 webgl2、强制 webgl1 无扩展。1.0 无扩展那档必须走降级表,调用到 2.0 符号即失败。能力包枚举写进启动日志与遥测。软件渲染当失败。静图路径有自动截图对比。扩展指令与 GLSL 版本由模板注入,禁止手写散落。新效果合入要声明依赖哪一包。声明缺失则按低包裁效果,不许裸调用扩展。这是把 1.1 与 4.5 接成门禁。门禁比 wiki 有效。
能力包 CI 是本节的牙齿。没有牙齿,降级表是摆设。强制 1.0 跑用例,碰到 createVertexArray 以外的 2.0 符号就失败。着色器模板注入 version 与扩展指令,散落的手写指令审查打回。软件渲染当失败走静图。静图要和产品经理签过,避免临时决定在渠道全白。遥测包等级,运营按等级看转化,而不是按“支不支持 WebGL”二值。二值会把 1.0 增强档与软件渲染混成一堆。调试扩展只在开发构建启用。生产依赖 debug_renderer_info 会在隐私模式或策略下缺数据,逻辑不应依赖它。依赖能力对象。对象是合同,字符串是八卦。
降级表每条要有强制失败用例。没有用例的 else 视为不存在。存在幻觉比缺失更危险。幻觉会让市场承诺兼容,渠道却全白。全白时程序说有 fallback。有用例的 fallback 才会真的画简化场景。简化场景要截图进 CI。截图是合同的照片,文字不是。
现场对照时只改一个变量。同时改版本、封装、通道,归因会消失。消失之后只能靠感觉,感觉正是本书要拆掉的东西。把改动写成一条,测完再写下一条。一条一条,四组对照才用得上。用不上的对照表只是装饰。装饰填不满格子,格子空着就不要标完工。能力包这一格改完,强制 1.0 跑失败用例,不要只在开发机点一次。
下一节对照谁来实现这些合同:完整引擎、2D 引擎,还是裸 API 加独立加载器。