WebGPU:解锁浏览器对新式 GPU 的访问权限

了解 WebGPU 如何释放 GPU 的强大功能,以实现更快的机器学习性能和更好的图形渲染。

Corentin Wallez
Corentin Wallez
François Beaufort
François Beaufort

全新的 WebGPU API 可在图形和机器学习工作负载方面大幅提升性能。本文探讨了 WebGPU 如何对当前 WebGL 解决方案进行改进,并抢先了解未来的发展情况。但首先,我们提供一些背景信息来解释开发 WebGPU 的原因。

WebGPU 上的上下文

WebGL 于 2011 年在 Chrome 中推出。WebGL 可让 Web 应用利用 GPU,从而为 Web 带来惊艳的体验,包括 Google 地球、互动式音乐视频和 3D 房地产演示等等。WebGL 基于 OpenGL 系列 API,首次开发于 1992 年。那是很久以前的事了!可以想象,自那之后,GPU 硬件发生了很大的发展。

为了跟上这一发展步伐,我们开发了一个新的 API,可以更高效地与现代 GPU 硬件交互。Direct3D 12MetalVulkan 等 API。这些新的 API 为 GPU 编程的新应用场景提供了支持,例如机器学习的爆炸和渲染算法的进步。WebGPU 是 WebGL 的继任者,它将这种新型现代 API 的进步带入了网络。

WebGPU 为浏览器带来了许多新的 GPU 编程可能性。它更好地反映了现代 GPU 硬件的工作原理,同时也为将来更高级的 GPU 功能奠定了基础。自 2017 年以来,此 API 已在 W3C 的“Web GPU”组中正式加入,由 Apple、Google、Mozilla、Microsoft 和 Intel 等众多公司联合推出。经过 6 年的不懈努力,现在,我们很高兴地宣布,Web 平台中最重大的一项新增功能终于面世了!

目前,Chrome 113 在 ChromeOS、macOS 和 Windows 上支持 WebGPU,其他平台也即将推出。衷心感谢其他 Chromium 贡献者和 Intel 团队,特别感谢帮助我们实现这一愿景。

现在,我们来看看 WebGPU 能够实现的一些激动人心的应用场景。

解锁新的 GPU 工作负载进行渲染

计算着色器等 WebGPU 功能可实现将新类算法移植到 GPU 上。例如,算法可以为场景添加更多动态细节、模拟物理现象等等!还有一些以前只能在 JavaScript 中完成的工作负载,现在现在可以转移到 GPU 上了。

以下视频展示了用于对这些元球表面进行三角定位的行进立方体算法。在视频的前 20 秒内,当使用 JavaScript 运行时,算法难以跟上网页的仅以 8 FPS 的速度运行,从而导致动画出现卡顿。为了保持其在 JavaScript 中的性能,我们需要大幅降低细节级别。

当我们将同一算法移至计算着色器时,会发现一个昼夜交替的现象,在 20 秒后在视频中出现。网页现在能以 60 FPS 的流畅运行,性能大幅提升,而其他效果仍有很大的性能提升空间。此外,网页的主 JavaScript 循环完全被释放出来以用于其他任务,从而确保与网页的互动保持迅速响应。

<ph type="x-smartling-placeholder">
</ph>
Metaballs 演示

WebGPU 还可以实现以前无法实现的复杂视觉效果。在下例(在热门的 Babylon.js 库中创建)中,海平面完全在 GPU 上模拟。逼真的动态通过许多独立的波次相互添加而形成。但直接模拟每个波的成本太高。

<ph type="x-smartling-placeholder">
</ph>
海洋演示

因此,本演示使用了名为 Fast Fourier Transform 的高级算法。这种方法使用光谱数据,可以更高效地执行计算,而不是将所有波表示为复杂的位置数据。然后,每一帧都使用福里叶转换从光谱数据转换为表示波高度的位置数据。

加快机器学习推断速度

WebGPU 还有助于加快机器学习的运行速度,机器学习近年来已成为 GPU 的主要用途。

长久以来,广告素材开发者都在重复使用 WebGL 的渲染 API 来执行非渲染操作,例如机器学习计算。然而,这需要绘制三角形像素作为启动计算的方式,并在纹理中仔细打包和解包张量数据,而不是更通用的内存访问。

<ph type="x-smartling-placeholder">
</ph> 使用 WebGL 执行单个机器学习运算符时会产生的低效问题,包括冗余内存加载、冗余计算以及每个线程写入的值很少。 <ph type="x-smartling-placeholder">
</ph> 使用 WebGL 执行单个机器学习运算符。

以这种方式使用 WebGL 需要开发者奇怪地让其代码符合专为绘图设计的 API 的预期。再加上计算之间缺少共享内存访问等基本功能,会导致重复工作和性能欠佳。

计算着色器是 WebGPU 的主要新功能,可以消除这些痛点。计算着色器提供更灵活的编程模型,利用 GPU 的大规模并行特性,同时不受严格渲染操作结构的限制。

<ph type="x-smartling-placeholder">
</ph> WebGPU 计算着色器的各种效率提升,包括共享内存加载、共享计算和灵活的内存写入。 <ph type="x-smartling-placeholder">
</ph> WebGPU 计算着色器的效率。

计算着色器提供了更多机会在着色器工作组内共享数据和计算结果,从而提高效率。与之前尝试使用 WebGL 实现相同目的相比,这可以带来显著的改进。

举个例子,在 TensorFlow.js 中对图像扩散模型的初始端口从 WebGL 转移到 WebGPU 后,在各种硬件上都实现了 3 倍的性能提升。经过测试,在一些硬件上,图片的渲染时间不到 10 秒。由于这是一个早期的端口,我们相信 WebGPU 和 TensorFlow.js 都有更多改进的空间!请参阅 2023 年 Web 机器学习领域的新动态?Google I/O 大会专题演讲。

但 WebGPU 不仅仅是将 GPU 功能引入 Web。

专为 JavaScript 而设计

实现这些用例的功能已有一段时间可供特定于平台的桌面和移动开发者使用,而我们面临的挑战就是要以一种感觉像是网络平台自然组成部分的方式公开这些功能。

WebGPU 的开发借鉴了十多年来使用 WebGL 进行出色工作的开发者的后见之明。我们能够将他们遇到的问题、遇到的瓶颈和提出的问题纳入他们,并将所有反馈都集中到这个新的 API 中。

我们发现,WebGL 的全局状态模型使得创建强大的可组合库和应用变得困难和脆弱。因此,WebGPU 显著减少了开发者在发送 GPU 命令时需要跟踪的状态数量。

我们听说调试 WebGL 应用很麻烦,因此 WebGPU 包含更灵活的错误处理机制,这些机制不会降低您的性能。我们竭尽全力确保您从该 API 返回的每条消息都易于理解且可操作

我们还发现,进行过多 JavaScript 调用的开销往往是复杂 WebGL 应用的瓶颈。因此,WebGPU API 的聊天语言减少,因此您可以通过更少的函数调用来完成更多操作。我们专注于预先执行重量级验证,使关键绘制循环尽可能精简。此外,我们还提供 Render Bundle 等新 API,让您可以提前记录大量绘制命令,只需调用一次即可重放这些命令。

为了说明渲染捆绑包等功能可以带来哪些显著的不同,下面我们再来看一个来自 Babylon.js 的演示。他们的 WebGL 2 渲染程序可以执行所有 JavaScript 调用,以大约每秒 500 次的速度渲染这个画廊场景。太棒了!

<ph type="x-smartling-placeholder">
</ph>
美术馆

不过,他们的 WebGPU 渲染程序可实现一项称作“快照渲染”的功能。此功能基于 WebGPU 渲染软件包构建,可将同一场景的提交速度提高 10 倍以上。这显著降低了开销,使得 WebGPU 能够渲染更复杂的场景,同时让应用能够并行使用 JavaScript 执行更多操作。

现代图形 API 以复杂性和极致优化机会为代价而享有盛誉。另一方面,WebGPU 专注于跨平台兼容性,在大多数情况下会自动处理资源同步等传统上很难解决的问题。

这有一个令人欣喜的副作用,即 WebGPU 易于学习和使用。它依赖 Web 平台的现有功能来加载图片和视频等,并利用 promise 等众所周知的 JavaScript 模式来实现异步操作。这有助于将所需的样板代码量保持在最低限度。只需不到 50 行代码,就能在屏幕上显示第一个三角形。

<canvas id="canvas" width="512" height="512"></canvas>
<script type="module">
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();

  const context = canvas.getContext("webgpu");
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
  const shaderModule = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({
    layout: "auto",
    vertex: {
      module: shaderModule,
      entryPoint: "vertexMain",
    },
    fragment: {
      module: shaderModule,
      entryPoint: "fragmentMain",
      targets: [{ format }],
    },
  });
  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];
  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
</script>

总结

我们很高兴看到 WebGPU 为网络平台带来的所有新的可能性,我们也期待看到您发现的 WebGPU 的所有炫酷新用例!

围绕 WebGL 构建了一个充满活力的库和框架生态系统,这个生态系统也渴望使用 WebGPU。许多热门的 JavaScript WebGL 库正在开发中或已经完成了对 WebGPU 的支持,并且在某些情况下,利用 WebGPU 的优势可能就像更改一个标志一样简单!

<ph type="x-smartling-placeholder">
</ph> Babylon.js、Construct 3、Google 地球、Google Meet、PlayCanvas、Sketchfab、Three.JS、TensorFlow.js 和 Unity。
具有已完成或正在进行的 WebGPU 端口的框架、应用和库。

Chrome 113 的首个版本只是一个开始。虽然我们的初始版本适用于 Windows、ChromeOS 和 MacOS,但我们计划在不久的将来将 WebGPU 引入其他平台,例如 Android 和 Linux。

不仅 Chrome 团队也在努力推出 WebGPU,我们也正在 Firefox 和 WebKit 中实施。

此外,已在 W3C 中设计新功能,这些功能在硬件中可用后便会公开。例如:在 Chrome 中,我们计划尽快支持在着色器中使用 16 位浮点数DP4a 类指令,以便进一步提升机器学习性能。

WebGPU 是一个广泛的 API,如果您投资它,可以解锁令人惊叹的性能。今天,我们只能粗略介绍它的优势,但如果您想开始使用 WebGPU,请查看我们的入门 Codelab:您的首个 WebGPU 应用。在此 Codelab 中,您将构建经典的《Conway's Game of Life》的 GPU 版本。此 Codelab 会逐步引导您完成该过程,即使这是您首次进行 GPU 开发,也可以试用。

WebGPU 示例也有助于您了解该 API。它们的范围包括传统的“你好 三角形”来演示各种技术,从而实现更完整的渲染和计算流水线。最后,请查看我们的其他资源