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

了解 WebGPU 如何释放 GPU 的强大力量,以提升机器学习性能和图形渲染速度。

François Beaufort
François Beaufort

全新的 WebGPU API 可大幅提升图形和机器学习工作负载的性能。本文探讨了 WebGPU 在 WebGL 当前解决方案的基础上进行了怎样的改进,并提前对未来发展进行了展望。但我们首先介绍一下开发 WebGPU 的原因。

WebGPU 上的上下文

WebGL 于 2011 年登陆 Chrome。WebGL 允许 Web 应用利用 GPU,可在网络上实现令人惊叹的体验,包括 Google 地球、互动式音乐视频和 3D 房地产演示等等。WebGL 基于 OpenGL 系列 API,这些 API 最初开发于 1992 年。那是很久以前了!可以想象,从那以后,GPU 硬件已经有了很大的进步。

为了跟上这一发展步伐,开发了一类新的 API,以便更高效地与现代 GPU 硬件进行交互。Direct3D 12MetalVulkan 等 API。这些新 API 为 GPU 编程的高要求新用例提供支持,例如机器学习的爆炸式增长和渲染算法的进步。WebGPU 是 WebGL 的继任者,它将这类新型现代 API 的先进技术带到了 Web 中。

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 循环已完全释放以执行其他任务,从而确保与网页的互动保持响应。

metaballs 演示

WebGPU 还可以实现之前不实用的复杂视觉效果。以下示例是在热门的 Babylon.js 库中创建的,海平面完全是在 GPU 上模拟的。逼真的动态是由彼此相互连接的许多独立波组成的。但是,直接模拟每个 wave 的成本太高。

海洋演示

正因如此,该演示使用名为快速傅里叶转换的高级算法。这种方法没有将所有波表示为复杂的位置数据,而是使用光谱数据,这种方法执行计算的效率更高。然后,每一帧使用伏里叶转换从光谱数据转换为表示波高的位置数据。

加快机器学习推断速度

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

长期以来,广告素材开发者一直在重新利用 WebGL 的呈现 API 来执行机器学习计算等非呈现操作。然而,这需要通过绘制三角形的像素作为启动计算的方式,并在纹理中仔细打包和解压缩张量数据,而不是更通用的内存访问。

图示:使用 WebGL 执行单个机器学习运算符时出现的低效问题,包括冗余内存加载、冗余计算以及每个线程写入的值很少。
使用 WebGL 执行单个机器学习运算符。

如果以这种方式使用 WebGL,开发者必须使他们的代码无法满足专为绘图设计的 API 的预期。再加上缺乏计算之间的共享内存访问等基本功能,导致重复工作和性能欠佳。

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

WebGPU 计算着色器中的各种效率提升,包括共享内存加载、共享计算和对内存的灵活写入。
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 的聊天效率较低,因此您可以通过更少的函数调用完成更多任务。我们专注于预先执行重量级验证,使关键绘制循环尽可能精简。此外,我们还提供渲染捆绑包等新的 API,支持您提前录制大量绘制命令,然后只需调用一次即可重放这些命令。

为了演示像渲染捆绑包这样的功能带来的显著不同,下面是 Babylon.js 的另一个演示。他们的 WebGL 2 渲染程序可以执行所有 JavaScript 调用,以每秒约 500 次呈现这个艺术画廊场景。非常好!

画廊

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

现代图形 API 以复杂性而闻名,以简单性换取极大的优化机会。另一方面,WebGPU 侧重于跨平台兼容性,在大多数情况下,自动处理传统上难以解决的问题,如资源同步。

这样做有一个好处,即 WebGPU 易于学习和使用。它依赖于网络平台的现有功能来执行图片和视频加载等操作,并依靠常见的 JavaScript 模式(例如用于异步操作的 Promise)。这有助于将所需的样板代码量降至最低。只需不到 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 的优势可能就像更改一个标志一样简单!

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 中,您将构建经典的康威生命游戏的 GPU 版本。此 Codelab 将逐步引导您完成该过程,因此即使您是第一次进行 GPU 开发,也可以尝试一下。

您还可以通过 WebGPU 示例了解该 API。从传统的“Hello 三角形”到更完整的渲染和计算流水线,演示了各种技术。最后,请查看我们的其他资源