题干与适用场景
这是浏览器平台与发布工程结合的前端题。应用已有 WebGL 或 CPU 路径,想在支持 WebGPU 的设备上启用更高性能渲染,同时覆盖只能提供受限 API 子集的设备。题目要求讨论 compatibility mode 的能力探测与限制差异,不把“拿到 adapter”误当作“所有 shader、格式和性能都可用”。
GPUWeb 规范把 compatibility mode 定义为受限的 WebGPU 子集,目标是映射到较旧图形 API;实现仍可能拒绝 adapter、限制可用 feature 或在运行中丢失 device。发布方案必须把可用性、正确性和性能分别测量。
面试官考察点
- 是否先建立能力矩阵,再选择 adapter、feature 和 limits。
- 是否把 core、compatibility、WebGL 和 CPU 路径定义为有序的产品降级,而不是一段布尔判断。
- 是否知道
GPUDevice.lost是异步终止信号,恢复需要重建资源和渲染状态。 - 是否能设计真实设备灰度、质量门槛、隐私友好的遥测和快速回滚。
- 是否能区分“渲染正确”“延迟达标”和“功耗可接受”三个结果。
回答前需要澄清的问题
- 目标是渲染、通用计算还是浏览器内推理?不同用途对 storage、纹理格式和精度的要求不同。
- 低端设备必须保留什么体验?答案决定 WebGL、CPU 或静态结果的最低路径。
- 是否允许在首次加载做短暂 capability probe?若不允许,只能依赖历史设备画像并承担误判。
- 设备丢失时能否重新初始化 canvas 和资源?如果不能,必须提前设计可恢复的 UI 状态。
- 灰度按浏览器、GPU、驱动、地区还是用户分组?分组决定如何发现特定驱动回归。
30 秒回答框架
“我会先探测 WebGPU、adapter、feature 和 limits,再把 core、compatibility、WebGL、CPU 或静态结果作为明确的能力阶梯。初始化只创建符合该阶梯的 shader、pipeline 和资源;每个关键路径有正确性测试与性能预算。监听 device.lost,用单飞恢复流程重建 device、资源和 canvas 状态,失败则降级并记录原因。灰度按浏览器、GPU、驱动和应用版本分层,监控初始化成功率、设备丢失、渲染错误、p95 帧耗时和电量代理指标,异常时关闭新路径而不改变旧路径。”
分步骤深入解答
第一步:把能力探测写成契约
先确认安全上下文和 navigator.gpu,再请求 adapter。adapter 返回后读取可用 features 与 limits;不要只检查 API 对象存在。将结果归类为 core、compatibility、WebGL 或 CPU,并把浏览器、操作系统、GPU vendor、驱动和应用版本作为匿名化遥测维度。
Compatibility mode 的价值是扩大可运行设备范围,代价是可用 feature、limits 和性能上界更保守。应用应把必需能力写成清单:纹理格式、绑定布局、storage 大小、workgroup 上限和精度。缺少任一必需能力时,选择下一阶路径,而不是运行到 shader 创建才失败。
第二步:让渲染资源随能力档位构建
每个档位有自己的 shader 变体、pipeline 描述和资源预算。先构建最小三角形或小批量推理的 smoke test,确认 command submission 与结果校验,再进入完整场景。不要在 core 路径创建的 bind group 或纹理格式上假设 compatibility 也接受。
若资源创建失败,记录结构化错误并释放本档位对象。静态后备图、WebGL 画布或 CPU 结果必须共享产品状态模型,保证用户仍能完成任务;后备路径不能偷偷宣称同等帧率或精度。
第三步:处理设备丢失与恢复竞态
GPUDevice.lost 会在 device 生命周期结束时 resolve。监听它后进入 recovering 状态:停止提交新 work,取消或标记旧帧,重新请求 adapter/device,按能力档位重建 shader、pipeline、buffer、texture 和 bind group,最后恢复渲染循环。用 generation token 或单飞 promise 防止两个恢复流程交叉覆盖新 device。
如果 lost 的原因表示资源压力或驱动问题,重试次数和间隔必须有上限。连续失败时切换 WebGL 或 CPU,并让 UI 说明功能已降级。既有 device-loss 题侧重恢复实现;本题更关注 compatibility 能力矩阵与发布控制,两者要分开回答。
第四步:设计灰度与回滚
先在内部设备矩阵运行,再按浏览器版本、GPU vendor、驱动、操作系统和地区逐层扩大。灰度开关必须能在服务端或配置层快速关闭,但不能让配置下发成为渲染正确性的单点依赖;客户端始终保留安全默认值。
核心指标包括 adapter 请求失败率、device 创建失败率、首次可交互时间、p50/p95 帧耗时或推理延迟、shader/pipeline 错误、设备丢失率、恢复成功率、降级率和任务完成率。按硬件分层后才看得出某一驱动的回归。遥测只保留粗粒度设备标签与版本,避免收集完整指纹。
第五步:验证正确性、性能和功耗
正确性测试比较 WebGPU、compatibility、WebGL 和 CPU 的结果容差、纹理颜色、几何边界和推理输出。性能测试固定场景、分辨率和 batch,报告 p50/p95,不把单台旗舰设备的平均值当作保证。后台或低电量场景还要测提交频率、内存和设备温度代理信号。
回归门槛应按档位设定:compatibility 只需满足产品最低帧率与结果误差,不能拿 core 的预算硬套。若新路径导致错误率、功耗或恢复时间越过阈值,关闭该档位并保留 WebGL/CPU 结果,随后用最小复现收集驱动信息。
设计取舍与边界
#### 只用 API 探测 vs 设备画像
实时探测最准确,却增加首次加载成本;设备画像能快速决策,却可能过期或形成指纹。用短探测确认硬能力,画像只用于排序和灰度,不用于绕过实际 limits。
#### Compatibility mode vs WebGL
Compatibility mode 可以保留 WebGPU 的资源和命令模型,便于共享部分架构;WebGL 覆盖面与成熟度可能更好,但 shader、同步和性能模型不同。选择依据是必需能力、正确性迁移成本与用户任务,而不是 API 新旧。
#### 自动恢复 vs 立即降级
一次有界恢复适合短暂资源压力;无限重试会造成卡顿和功耗放大。恢复失败或连续丢失达到阈值后,立即切换后备路径并记录一次可诊断事件。
高质量示范回答
“我会把 WebGPU 发布拆成能力矩阵、资源构建、恢复状态机和灰度控制。先确认安全上下文、请求 adapter,再读取 feature 与 limits,把 core、compatibility、WebGL、CPU 排成能力阶梯;每阶只创建它支持的 shader 和资源。监听 device.lost 后停止提交,用 generation token 保证只有一个恢复流程,重新创建 device 与全部 GPU 对象,失败则降级。灰度按浏览器、GPU、驱动和版本分层,监控初始化、帧耗时、错误、丢失、恢复和任务完成率,并保留远程关闭开关。Compatibility mode 扩大覆盖,不等于性能保证,所以正确性、延迟和功耗要分别验收。”
常见错误
- 只检查
navigator.gpu→ adapter 或 device 仍可能拒绝,feature 和 limits 也可能不足 → 建立能力矩阵并逐项验证。 - 把 compatibility mode 当作低配 core → shader、格式和 limits 可能不兼容 → 为档位构建独立资源清单和 smoke test。
- 设备丢失后只重新调用渲染函数 → 旧资源属于失效 device → 通过单飞恢复流程重建全部资源和状态。
- 无限重试 device 创建 → 驱动故障会变成卡顿与功耗放大 → 设置次数、间隔和最终降级。
- 只看平均帧率 → 少数 GPU 或长尾设备可能彻底失败 → 按浏览器、GPU、驱动分层看 p95 和任务完成率。
追问及应对
Compatibility mode 的 limits 比 core 小,如何决定能否运行?
把每个任务的硬需求写成 feature、纹理格式、storage、workgroup 与精度清单,和实际 adapter limits 比较。满足清单才进入该档位;否则选择 WebGL、CPU 或静态结果,并在遥测中记录缺失项。
device 丢失时用户正在编辑内容,能不能直接刷新页面?
不能把刷新当默认恢复。先把编辑状态保存在应用层,暂停 GPU work,尝试一次有界重建;重建失败后切换后备渲染,保留编辑状态并提示视觉效果已降级。只有状态无法安全迁移时才要求重新加载,并给出恢复入口。
某个驱动的丢失率突然升高,如何回滚?
按 GPU、驱动、浏览器和应用版本确认分层异常,先关闭该组合的 compatibility 灰度,保留其他组合。检查初始化、shader、资源压力和 lost 原因,再用最小场景复现;修复后从内部设备矩阵重新开始,不直接恢复全量。
如何证明 WebGL 后备没有改变业务结果?
为同一输入建立跨后端 golden 集,比较像素或推理输出的允许误差,并测试边界、空输入和高负载。业务完成率、结果正确率和延迟分别设门槛;满足视觉相似不代表推理数值或交互时序等价。