WebGPU 是新的 WebGL。这意味着它是在网络浏览器中绘制 3D 的新方法。在我看来,这实际上非常好。它太好了,我认为它也将取代 Canvas 并成为在 Web 浏览器中绘制 2D 的新方式。事实上,它非常好,我认为它将取代Vulkan以及普通的 OpenGL,并成为在任何类型的软件中使用任何编程语言进行绘图的标准方式。这让我很兴奋。WebGPU 有点让人恼火——但只是一点点,而且它比它所取代的任何东西都要小得多。

WebGPU 上线……实际上是今天。Chrome 113 是在我完成这篇文章的最后几分钟发布的,现在应该可以在“关于 Chrome”对话框中使用。如果你点击这里,你看到一个彩虹三角形,你的网络浏览器有 WebGPU。到今年年底,WebGPU 将无处不在,出现在每个浏览器中。(所有这些都是指台式电脑。在手机上,它要到今年晚些时候才会出现在 Chrome 中;而苹果我不知道。也许再过一年。)

如果您不是程序员,这可能不会影响您。它可能会让我们更接近一个世界,在这个世界中,您可以像以前使用 Flash 一样在网络浏览器中正常玩游戏。但可能不是因为 WebGL 不是唯一的问题。

如果你是一名程序员,让我告诉你我认为这对你意味着什么。

以下部分:

  • 图形 API 的历史(你可以跳过这个)
  • 它像什么?
  • 我该如何使用它?
    • 打字稿 / NPM 世界
    • 我不知道什么是 NPM 我只想写 CSS 和我愚蠢的小脚本标签
    • Rust / C++ / 后人类相交四面体

图形 API 的历史(你可以跳过这个)

 

哟! 瑜珈
1991

回到过去,有两种在计算机上制作 3D 的方法:你做一堆数学;或者你买了一台 SGI 机器。SGI 是第一批设计电路来为您完成 3D 引擎渲染部分的人。他们有这个 C API 用于向硬件描述您的 3D 模型。在某些时候,很明显人们将开始为普通台式计算机制作插件卡,这些插件卡可以像 SGI 的大型 UNIX 机器一样加速,所以 SGI 发布了他们的 API 的公共版本,这样就可以编写代码既可以在 UNIX 机器上工作,也可以在假设的未来 PC 卡上工作。这是 OpenGL。IRIS GL 中的 `color()` 和 `rectf()` 变成了 OpenGL 中的 `glColor()` 和 `glRectf()`。

 

 

TLC 的“瀑布”
1995

当 PC 3D 卡真正成为你可以买到的东西时,事情变得有点混乱。微软没有与 OpenGL 签约,而是决定开发自己的东西 (Direct3D),一些 3D 卡供应商也开发了自己的东西API 标准,因此有一段时间某些游戏只能在某些显卡上加速,而编写游戏的人不得不编写 3D 管线,大约四次,一次作为软件渲染器,另一次用于他们想要支持的每种卡类型。我的看法是它是 Direct3D,而不是 OpenGL,它最终设法将所有这些争吵成一个标准,如果你当时使用的是非 Microsoft 操作系统,那真的很糟糕。DirectX(以及它衍生的“X Box”独立游戏机)似乎真的是试图通过让游戏公司在最低级别将 Microsoft 独占性连接到他们的代码中来将游戏公司锁定在 Microsoft 操作系统中,并且在一段时间内它确实奏效了。

 

 

史莱克
2000

情况确实如此,尽管在您开始从 Direct3D 用户那里听到它比 OpenGL 好用得多之前,它进入 Direct3D 生命周期的时间并不长,而且 OpenGL 很快就达到了在字面上比 Direct3D 落后多年的地步实施关键的早期功能,如着色器,因为定义 OpenGL 的卡供应商的架构审查委员会将永远在细节上争论不休,而微软可以只实施一些东西并期望卡供应商解决它。

 

让我们谈谈着色器。最初的 OpenGL 是一个“固定功能渲染器”,这意味着有人在 3D 渲染器中写下了步骤,并且它按顺序执行这些步骤。

[API] → 基元处理 → (1) 变换和光照 → 基元组装 → 光栅器 → (2) 纹理环境 → (2) 颜色总和 → (2) 雾 → (2) Alpha 测试 → 深度/模板 → 颜色缓冲混合→ 抖动 → [帧缓冲区]

修改后的 Khronos 组图像

“管道”中的每个盒子的侧面都有一些刻度盘,因此您可以配置每个功能的行为方式,但您几乎只能使用卡供应商提供的功能。如果您有阴影或雾,那是因为 OpenGL 或扩展公开了绘制阴影或雾的功能。如果您想要ARB 没有想到的其他功能,或者想要以独特的方式制作阴影或雾气,让您的游戏看起来与其他游戏不同,该怎么办?很烂是你。这很令人讨厌,所以最终引入了“可编程着色器”。注意到上面的一些框是黄色的吗?那些盒子变得可以更换。(1) 个盒子折叠成“顶点着色器”,(2) 个盒子变成“片段着色器”²。该软件将使用简单的类 C 语言上传计算机程序(上传程序的实际文本,您不会像普通程序一样编译它)³ 在运行时进入视频驱动程序,驱动程序会将其转换进入 ALU 的配置(或卡在内部实际执行的任何操作),您的程序将成为管道的那一部分。这打开了很多东西,但更重要的是它让牌张设计走上了一条有点奇怪的道路。突然之间,视频卡不再是专门的渲染工具。他们运行软件

 

时代杂志,“约翰·克里会成为什么样的总统?”
2004年

不久之后又发生了另一个变化。手持设备开始达到可以在其上进行 3D 渲染的程度(或者至少,使用 3D 视频卡硬件进行 2D 合成,就像台式机已经开始做的那样)。DirectX 从未参与这些应用程序的运行。但是在 00 年代中期的移动芯片上实现 OpenGL 很粗糙。在这一点上,OpenGL 有点……大。它具有 SGI IRIX 时代的所有这些遗留功能,然后它具有这种新的闪亮的 OpenGL 2.0 处理着色器和所有内容的方式,这不仅意味着您基本上有两个不相关的 API 并排坐在同一个 API 中,但也有很多 OpenGL 1.x 功能是陷阱。规范说每个视频卡都必须支持每个 OpenGL 功能,但它并没有说它必须在 Hardware 中支持它们,因此 00 年代卡供应商认为没有人真正使用某些 90 年代早期的功能,因此如果您使用这些功能,驱动程序将渲染屏幕,将整个屏幕复制到常规 RAM 中,在 CPU 上执行该功能,然后将结果复制回显卡. 意外激活这些陷阱功能之一可能会使您轻松地从 60 FPS 变为 1 FPS。所有这些遗留包袱都为新移动 GPU 的制造商带来了很多额外的工作,因此为了让 Khronos(此时 ARB 已经变成这样)变得更容易,引入了 OpenGL“ES”,它去掉了除您绝对需要的功能。您不必为每个多边形或每个顶点调用函数,而是必须使用更新的 API 为 OpenGL 提供内存块中的坐标列表⁴,您必须使用固定函数或不混合的着色器管道(取决于您使用的是 ES 1.x 还是 ES 2.x)等。这部分地使程序员的事情变得更简单,部分地提示了一些烦人的重写。但与着色器一样,最重要的是这种变化的长期奇怪预示:从这一点开始,Khronos 的决策越来越完全由硬件制造商的需求和需求驱动,而不是程序员。

 

 

苹果手机
2008年

随着世界上的 OpenGL ES 设备的出现,OpenGL 开始从“我猜是存在的其他图形 API”毕业并真正起飞。使用 OpenGL ES 的 iPhone 为大众市场提供了学习和使用 OpenGL 的坚实理由。任天堂游戏机开始使用 OpenGL 或类似的东西。OpenGL 在功能上或多或少地赶上了 DirectX,尤其是在您愿意使用扩展的情况下。浏览器供应商,在为我们提供原始 WebAudio API 的那种奇怪的狂妄自大中,将 OpenGL ES 改编为 JavaScript 作为“WebGL”,这没有任何意义,因为如前所述,OpenGL ES 就是将字节打包到充满几何图形的数组中,而 JavaScript 不会没有直接内存访问甚至整数,但他们向语言添加了压缩二进制数组无论如何都做了。因此,通过所有这些活动,听起来事情进展顺利,对吧?

 

 

宇宙小子
2013

不!一切都很糟糕!随着它的成熟,OpenGL 分裂成各种具有不同程度的交叉兼容性的略有不同的标准。OpenGL ES 2.0 在某种程度上与 OpenGL 3.3 相同。WebGL 2.0非常接近OpenGL ES 3.0,但又不完全是。解决 OpenGL 遗留下来的早期错误的每一次尝试似乎都以将整个 API 复制为名称和签名略有不同的新函数而告终。OpenGL 的一个很大的可用性问题是即使在 2.0 返工之后它有很多共享的全局状态,但是应该解决这个问题的附加系统(VAO 和 VBO)最终只会变得更多您必须跟踪的全局状态。10 年代的一个大趋势是“GPGPU”(通用 GPU);程序员开始意识到图形卡的工作原理和 CPU 的矢量单元一样好,但比 CPU 的矢量单元更容易编程,所以他们只是开始通过可怕的黑客来加速随机的非图形程序,比如将它们填充到像素着色器中并读回纹理包含编码结果。在最终解决计算着色器之前(换句话说:在放弃和复制 DirectX 的解决方案之前),Khronos 为实际迎合这一点而采取的最初步骤要么没有得到很好的采用(OpenCL),要么只是简单的坏主意(几何着色器)。这一切都建立起来了。就像在 pre-ES 时代一样,OpenGL 基本上变成了几个不相关的 API 坐在同一个头文件中,其中一些只在某些机器上起作用。没有什么能像你想要的那样有效;不同的视频卡供应商搞砸了复杂性,实现功能略有不同(尤其是可悲的是,实现了略微不同版本的着色器语言)或只是很糟糕,尤其是在臭名昭著的糟糕 Windows OpenGL 驱动程序中。

 

出路来自,反正我是这么看的,一个昙花一现的想法,叫做“ AZDO ”。这在技术上由一个 GDC 演讲组成⁵,我没有理由相信 GDC 演讲是这个想法的起源,但演讲所做的是为 Vulkan、DirectX 12 和 Metal 的基础想法命名。“接近零驱动程序开销”。想法是这样的:到 2015 年,视频卡在特定的工作方式上几乎已经标准化,并且这种方式是众所周知的,并且这种方式至少在十年内不会改变。图形 API 最初是围绕功能设计的他们公开了,但至少十年来,该功能与 GPU 的内部外观并不是 1:1 的映射。驱动程序已经变成了复杂的野兽,他们不只是按照你告诉他们的去做,而是试图凭直觉知道你想做什么,然后以最优化的方式去做,但他们往往猜错了,让软件作者处于试图凭直觉判断的丑陋境地驾驶员在任何一种情况下的直觉。AZDO 是关于通过图形 API 的针头,以这样一种方式,您的函数调用恰好与硬件实际执行的操作精确对齐,这样驱动程序就可以无事可做,事情就发生

 

星球大战:原力觉醒
2016年

或者我们可以从一开始就将图形 API 设计为 AZDO。那是伏尔甘。(以及 DirectX 12 和 Metal。)现代图形 API 基本上是抛弃驱动程序,或者更确切地说,让您的程序成为驱动程序。API 原语直接映射到 GPU 内部功能⁶,GPU 会按照您的要求进行操作,无需再猜测。这为您提供了难以置信的力量和控制力。还记得上面的“管道”图吗?现代 API 让您定义“管道对象”;图形着色器让你替换图表中的框,计算着色器让你用一个大的着色器程序替换图表,管道对象让你绘制自己的图表. 您可以决定哪些 GPU 内存块是源,哪些是目的地,它们是如何被解释的,GPU 对它们做了什么,以及调用了哪些着色器。所有旧的混乱根源都得到解决。状态绑定在定义明确的对象中,而不是全局的。卡供应商总是设计不同的着色器编译器,因此我们将用一种字节码格式替换文本着色器语言,这种格式易于实现并且更容易为其编写编译器。Vulkan 甚至允许您为 GPU 内存编写自己的分配器/释放器。

 

所以这一切都非常酷。只有一个问题,就是由于所有这些细粒度的复杂性,Vulkan 最终基本上无法由人类编写。事实上,这并不公平。DX12 和 Metal 提供或多或少相同程度的细粒度复杂性,而且从各方面来看,它们的编写都不是那么糟糕。实际问题是Vulkan 不是为人类编写而设计的。字面上地。科罗诺斯不想你写 Vulkan,或者更确切地说,他们不希望你直接写它。2015 年 Vulkan 发布时,我在房间里,在 GDC 街对面,他们向我们解释说,游戏开发人员越来越多地不再真正瞄准游戏 API 本身,而是瞄准高级中间件、Unity 或 Unreal或其他,所以 Vulkan 是一个为编写中间件而设计的 API。中间件开发人员当时也在房间里,Unity、Epic 和 Valve 的家伙。当 Khronos 的人解释这个时,他们喜气洋洋。他们的生活即将变得更加轻松。

我的生活即将变得更加艰难。Vulkan 很奇怪- 但它在某种程度上使某种可怕的机器变得很奇怪。每个 Vulkan 调用都涉及传递一个或两个巨大的结构,这些结构本身是其他巨大结构的森林,每个结构和子结构都以一个小的协议头开始,解释它是什么以及它有多大。在分配内存之前,您必须填写一个结构以返回一个结构,该结构告诉您应该在什么结构中构建内存分配请求。这些都没有任何意义——除非您之前设计过一种编程语言,在这种情况下,你正在阅读的所有内容都会跳出来告诉你“哦,这是人为设计的,因为它被设计成很容易绑定到具有奇怪内存管理技术的语言”“你。这是硬件制造商和中间件供应商之间的错综复杂的合同,而像……好吧,我这样的人不参与交易。

Khronos 没有忘记你和我。他们只是做了一个判断,这确实有某种意义,他们永远不会设计出完美符合人体工程学的开发人员 API,所以最好不要尝试,而是让它尽可能简单,以达到完美的效果符合人体工学的 API 写在上面,作为一个库。Khronos 认为在 Vulkan⁸ 发布后的几年内,人们会使用大量高质量的开源包装库,而不是直接使用 Vulkan。这些图书馆基本上没有物化。事实证明,编写软件是一种工作,开源项目不会因为人们希望它们实现而实现。

 

星球大战:天行者崛起
2019

这将我们引向另一个问题,即 Vulkan 在事后开发的问题。苹果问题。Vulkan 的理论是它将改变微软不断发布高质量尖端图形 API 而 OpenGL 是草率的开源追赶者的力量平衡。相反,GPU 供应商自己将提供 API,Vulkan 将成为通用标准,而 DirectX 将被简化为特定于平台的怪癖。但随后苹果拒绝了。Apple(他们已经推出了自己的产品 Metal)宣布他们不仅永远不会支持 Vulkan,他们也不会支持OpenGL,不再¹⁰。在我看来,这又是 DirectX;我们这个时代的主导操作系统供应商,就像 90 年代的微软一样,正在推动专有图形技术以促进开发人员锁定。但从 Apple 的角度来看,它可能看起来像——好吧,DirectX 在 90 年代从 Microsoft 的角度来看可能是这样的。他们忽略了硬件供应商提供的锯齿状金属,并提供了他们的开发人员真正想要使用的东西。

 

随着 Apple 的退出,场景看起来不同了。突然出现了用于 Windows 的下一代 API、用于 Mac/iPhone 的下一代 API 以及用于 Linux/Android 的下一代 API。除了 Linux 与 Vulkan 存在严重的驱动程序问题外,我一直在检查的许多 Linux 设备在 Vulkan推出七年后仍然不支持它。因此,真正能够原生运行 Vulkan 的平台只有 Android。这还不错。Vulkan 确实可以在 Windows 上运行并且几乎没有问题,尽管有资源编写 DX12 后端的人似乎更喜欢这样做。这些 API 的全部意义在于它们是轻量级的东西,非常轻松地位于硬件层之上,这意味着它们并没有真正的不同,在某种程度上存在名为 MoltenVK 的 Vulkan-on-Metal 仿真层,据报道几乎没有增加任何开销。但是如果你是一个开源的人,没有资源支付三个不同的人来编写模糊相似的平台后端,这不是很好。从技术上讲,您的代码可以在所有平台上运行,但您使用的是三种 API 中使用起来最不愉快的一种,并且您获得了在两个主要平台上都没有使用真正本机 API 的优势。您甚至可以更轻松地编写 DX12 和 Metal,而完全忘记 Vulkan(和 Android)。简而言之,Vulkan 解决了 OpenGL 的所有问题,其代价是做出了一些没有人愿意使用也没有人有理由使用的东西。

出路原来是一个叫做ANGLE的东西。让我备份一下。

 

超级食肉男孩
2010年,再一次

WebGL 是围绕 OpenGL ES 设计的。但它与 OpenGL ES 从未完全相同,而且从技术上讲,OpenGL ES 从未真正在桌面上运行过,而且桌面上的常规 OpenGL 也存在问题。所以浏览器的人最终意识到,如果你想在 Windows 上发布一个 OpenGL 兼容层,在 DirectX 中编写一个 OpenGL 模拟器实际上比直接使用 OpenGL 更容易,并且必须协商不同视频的 OpenGL 实现之间的各种不兼容性卡驱动程序。浏览器人员还意识到,如果不同 OpenGL 驱动程序之间的轻微兼容性差异是地狱,那么四种不同浏览器之间的轻微不兼容性差异乘以三种操作系统乘以不同的显卡驱动程序将是有史以来最糟糕的事情。我只能假设是绝望,我见过的真正跨公司开源协作最成功的例子出现了:ANGLE,一个 BSD 许可的 OpenGL 模拟器,最初由谷歌编写,但有来自两者的诚实到善良的贡献Firefox 和 Apple,几乎所有 Web 浏览器都使用它来支持 WebGL 。

 

实际上没有人想用 WebGL 对吧?我们想要一个“现代”API,那些 AZDO 东西之一。因此,一个 W3C 工作组坐下来制作 Web Vulkan,他们将其命名为 WebGPU。我不确定我对事件的看法是否可信,但从远处看,我的看法是 Apple 是工作组中要求最高的参与者,也是每个人自然而然会最害怕的参与者只是在整个努力中发挥作用,所以据报道,Apple 完全得到了他们要求的一切,WebGPU 看起来真的很像 Metal。但据报道,Metal 一直是三种现代图形 API 中最好用的,所以这……好吗?受到 ANGLE 成功的鼓舞(此时它开始被视为非网络应用程序中的独立库¹¹),有意识的人希望将这个新 API 与WebASM,他们采取了将标准同时定义为 JavaScript IDL 和 C 头文件的步骤,因此非浏览器应用程序可以将其用作库。

 

图形处理器
2023年

WebGPU 是 ANGLE 和 Metal 的孩子。WebGPU 是 Vulkan 缺少的开源“人体工程学层”。WebGPU 在网络浏览器中,Microsoft 和 Apple 在浏览器标准委员会中,所以他们被“收买”,WebGPU 不仅在他们的平台上工作得很好,而且 WebGPU 可以做的任何事情都将永远保持可行他们的操作系统,无论未来的开发人员锁定努力如何。(您不必担心功能漂移,就像我们已经在 MoltenVK 上看到的那样。)WebGPU 将在第一天推出(今天)对 JavaScript/TypeScript(因为它首先是为 JavaScript 设计的)、C++(因为 Chrome 实现是用 C 语言,而且它是开源的)和 Rust(因为 Firefox 实现是在 Rust 中,它是开源的)。

 

我觉得 WebGPU 是我一直在等待的东西。


它像什么?

我无法与 DirectX 或 Metal 进行比较,因为我个人都没有使用过。但特别是与 OpenGL 和 Vulkan 相比,我发现 WebGPU 使用起来确实令人耳目一新。我已经尝试过,真的尝试过编写 Vulkan,但每次都被复杂性打败了。相比之下,只有当复杂性增加了一些东西时,WebGPU 才能很好地增加复杂性。有_许多不同的对象需要跟踪,尤其是在初始化期间(见下文),但每个对象都代表一些真实的东西,我认为你不能在不带走有用功能的情况下从 API 中删除这些东西。(并且至少有一个很好的特性,你可以将所有的复杂性都塞进初始化时间,并使实际绘制帧的过程非常简洁。)WebGPU 迎合了那些认为编写自己的 raymarcher 可能很有趣的人,而不要求每个程序员都是那种认为自己编写malloc.

问题

存在三个问题。我将这样总结它们:

  • 文本
  • 线条
  • 可憎之物

文字和线条基本上是同一个问题。WebGPU 有点……没有。它可以画线,但它们只是真正用于调试——单像素宽度,你无法控制抗锯齿。因此,如果您想要一条“看起来很正常”的线条,您将使用定制的小网格和 SDF 着色器来做一些复杂的事情。与文本类似,您将得不到任何帮助——您将自己解析 OTF 字体文件并编写自己的 MSDF 着色器,或者更有可能找到一个为您处理文本的库。

这(除非你自己实现,否则没有线条或文本)对于低级图形 API 来说是完全正常的情况,但它对我来说有点烦人,因为网络浏览器已经有一个复杂的抗锯齿线渲染器(原始的 Canvas API ) 和世界上最先进的文本渲染器。(有一些方法可以将文本渲染到 Canvas API 纹理中,然后将 Canvas 内容作为纹理传输到 WebGPU 中,这对于某些目的应该有所帮助。)

然后是 WGSL,或者我认为是 The Abomination。您可能不会像我一样对此感到恼火。基本上:Vulkan 的好处之一是您不需要使用特定的着色器语言。OpenGL 使用 GLSL,DirectX 使用 HLSL。Vulkan 使用了一种称为 SPIR-V 的字节码,因此您可以从任何您想要的着色器语言中定位它。WebGPU 打算使用 SPIR-V,但后来 Apple 拒绝了。所以现在WebGPU使用WGSL这个专为WebGPU开发的新东西,作为它唯一的着色器语言。就着色器语言而言,它很好。也许它甚至还不错。我确信它比 GLSL 好。对于纯 JavaScript 用户来说,能够将着色器作为文本文件上传而不是必须编译为字节码可能是客观上的一种改进。但是天哪,如果有这样的选择就好了!(“桌面”


我该如何使用它?

您有三种使用 WebGPU 的选择:在浏览器中的 JavaScript 中使用它,在浏览器中的 WebASM 中的 Rust/C++ 中使用它,或者在独立应用程序中的 Rust/C++ 中使用它。Rust/C++ API 在语言差异允许的范围内尽可能接近 JavaScript 版本;Rust 和 C++ 的浏览器内/浏览器外 API 是相同的(除了像 SPIR-V 这样的独立特定功能)。在独立应用程序中,您将来自 Chrome 或 Firefox 的 WebGPU 组件作为库嵌入;您的代码不需要知道 WebGPU 库是否是一个真正的库,或者它是否只是通过您对浏览器的调用进行路由。

无论使用何种语言, w3.org 上的官方 WebGPU 规范文档都是该语言的清晰、可读的参考指南,适合以标准规范有时不适合的方式阅读。(我没有花那么多时间查看WGSL 规范,但它看起来差不多。)如果您在编写 WebGPU 时迷路了,我真的建议您检查规范。

WebGPU 中的大部分“工作”,除了编写着色器之外,都包括一个或多个“管道”对象的构造(当您的程序/场景首次启动时),每个“通道”对象一个,它描述了“我正在运行什么着色器” ,什么样的数据可以输入其中?”¹³。您可以在队列中端到端地链接管道:让计算通道生成顶点缓冲区,让渲染通道渲染到纹理中,执行最终渲染通道,使用渲染纹理渲染计算的顶点。

此处以图表的形式列出了初始设置 WebGPU 然后绘制框架所需创建的所有内容。这可能看起来有点势不可挡。别担心!实际上,您只是要从一些示例代码中复制和粘贴一大块样板文件。然而,在某些时候,您将需要返回并更改复制粘贴的样板文件,然后您将想要返回并查看这些对象之间的区别。

在初始化时:

上下文:一个 <canvas> 或窗口。 启动时存在。 WebGPU 实例:navigator.gpu。 启动时存在。 适配器:如果有多个视频卡,您可以选择一个。 将其提供给画布配置。 出售设备。 提供一个队列。 画布配置:你做这个。 提要到上下文。 队列:按顺序执行工作批次。 您稍后会用到它。 设备:与适配器的开放连接。 为画布配置提供颜色格式。 提供缓冲区、纹理和管道并将代码编译为着色器。 缓冲区:一块 GPU 内存。 您稍后会用到它。 纹理:GPU 内存格式化为图像。 您稍后会用到它。 着色器:顶点、片段或计算程序。 馈送至管道。 缓冲区布局:描述如何解释缓冲区中的字节。 就像 C 结构定义一样。 描述一个缓冲区。 馈送至管道。 顶点布局: 专门用于网格/三角形列表的缓冲区布局。 描述一个缓冲区。 馈送至管道。

对于每一帧:

第一步:取一个您希望更新此帧的缓冲区。 这将提供一个映射范围,它是一个类型化数组,可以从 GPU 缓冲区的一部分读取/写入数据。 当您“取消映射”映射范围时,更改将自动与此时相应的队列同步第二步:设备提供命令编码器。 上下文为该帧提供当前纹理。 将其提供给命令编码器并获得渲染通道。 (命令编码器还可以提供计算通道。将视口和剪刀矩形(这些只是数字)馈送到渲染通道。将管道馈送到剪刀矩形。将缓冲区(制服、顶点、索引)馈送到渲染通道。馈送纹理(着色器的输入)到渲染通道。将渲染通道和计算通道馈送到队列。

不分先后顺序的一些观察:

  • 在描述“网格”(要绘制的 3D 模型)时,“顶点”缓冲区是空间中的点列表,“索引”是一个可选缓冲区,包含绘制点的顺序。不确定你是否知道。
  • 现在“队列”对象似乎有点毫无意义,因为只有一个全局队列。但总有一天 WebGPU 会添加线程,然后可能会有不止一个。
  • 命令编码器一次只能处理一个通道;在请求下一个通行证之前,您必须将一个通行证标记为已完成。但是你可以制作多个命令编码器并一次将它们全部提交到队列中。
  • 回到 OpenGL 中,当您想在着色器上设置统一、属性或纹理时,您可以通过名称来完成。在 WebGPU 中,您必须在着色器中为这些东西分配编号,并按编号对它们进行寻址。¹⁴
  • 虽然纹理和缓冲区是两个不同的东西,但您可以指示 GPU 将纹理转换为缓冲区,反之亦然。
  • 我没有在上面列出“管道布局”或“绑定组布局”对象,因为老实说我不明白它们的作用。我只将它们设置为默认/空白。
  • 在 Rust API 中,“上下文”被称为“表面”。不知道有没有区别

获得更多特定于平台的信息:

TypeScript / NPM 世界

我知道为 TypeScript 学习 WebGPU 的最佳方法是Alain Galvin 的“Raw WebGPU”教程。对于以前没有使用过低级图形 API 的人来说,它比我上面的沙袋介绍要友好一些,并且它在最后有一个进一步资源的列表。

由于代码片段无法为您提供可运行的东西,Alain 的教程将完整的源代码库与教程代码链接在一起,而且我还有一个示例库,它基于 Alain 的教程代码并添加了简单的动画以及 Preact¹⁵。我和 Alain 的示例都使用了 NPM 和 WebPack¹⁶。

如果您不喜欢 TypeScript:无论如何我都建议为 WGPU 使用 TypeScript。除了 WGPU 调用之外,您实际上不必向任何内容添加类型,您可以键入“任何”所有内容。但是构建该管道对象涉及包含其他描述符的大描述符树,并且它只是普通的 JavaScript 字典,这很好,直到您拼错了一个键,或者忘记了一个键,或者不小心将 GPUPrimitiveState 表传递到它想要 GPUVertexState 表的地方。你的选择是让 TypeScript 告诉你犯了什么错误,或者被迫一遍又一遍地重新加载,看着事情一次又一次地崩溃。

我不知道什么是 NPM 我只想写 CSS 和我愚蠢的小脚本标签

如果您正在编写嵌入网页中的简单 JS 而不是加入 NPM hivemind,老实说,您可能更乐意首先使用three.js ¹⁷ 之类的东西,而不是忍受 WebGPU 的(相对而言)超低级冗长。您可以使用现有的 CDN将 three.js 直接包含在脚本标记中(尽管我建议放入子资源 SHA 哈希以保护您自己免受 CDN 的攻击)。

但!如果您想使用 WebGPU、Alain Galvin 的教程或他的示例代码中的 renderer.ts,仍然可以满足您的需求。: GPUBlah只要检查一下,只要变量上有一点瑕疵,就将其删除,TypeScript 现在是 JavaScript。正如我所说,WebGPU 的复杂性主要在于管道初始化。因此,我可以想象编写一个单独的<script>程序来设置一个适用于各种目的的管道对象,然后将该脚本包含在一堆小页面中,每个小页面都导入 ¹⁸ 管道,将一些浮点数输入缓冲区映射范围,然后绘制。您大概可以用十行来完成整个客户页面。

因此,正如我所提到的,对我来说,WebGPU 最令人兴奋的事情之一是您可以无缝地交叉编译使用它的代码,而无需针对浏览器或桌面进行更改。桌面代码使用实际浏览器实现的库化版本,因此行为差异的可能性很小。如果“在你的应用程序中包含浏览器的一部分”让你觉得你正在为代码膨胀的头痛做准备,那么在这种情况下不是这样;我能够将我的 Rust“Hello World”降低到 3.3 MB,这并不比 SDL 差多少,甚至没有尝试。(浏览器 hello world 就像 250k 加上一个 50k 自动生成的加载器,在我做任何严肃的缩小工作之前也是如此。)

如果你想用 Rust¹⁹ 编写 WebGPU,我建议你查看wgpu 项目的官方教程,或者wgpu 源代码库中的示例。在撰写本文时,在桌面上使用 Rust WebGPU 实际上比在浏览器中容易得多;这些库似乎大多在网络上运行良好,但 Rust-to-wasm 构建体验仍然有点粗糙。我确实在这里找到了一个非常好的wasm-pack 教程²⁰。然而,大多数 Rust-on-web 开发人员似乎使用(并且喜欢)一种叫做“ Trunk ”的东西。我还没有使用过 Trunk,但它取代了 wasm-pack 作为前端,并且似乎解决了我对 wasm-pack 的所有特定挫折。

我也有一个为 WebGPU 制作的示例 Rust 存储库,因为 wgpu 存储库中的示例没有随构建脚本一起提供。我的示例存储库非常基础²¹,只是 wgpu 项目中的“hello-triangle”示例,但添加了 Cargo.toml。它确实带有适用于 web 的单行构建指令,并且在桌面上运行时可以最大限度地--release减少磁盘使用。(它还会在没有 WebGPU 的情况下在 Web 上运行时打印一条错误消息,而 wgpu 示例不会。)您可以在此处查看此示例在浏览器中运行的编译形式。

C++

如果您使用的是 C++,则您要使用的库称为“Dawn”。我没有触及这个,但这里有一个非常详细的 Dawn/C++ 教程/介绍。先试试看。

后人类相交四面体

对未来有奇怪、混乱的白日梦。有一个名为rust-gpu 的实验项目可以将 Rust 编译为 SPIR-V。SPIR-V 到 WGSL 编译器已经存在,所以原则上应该已经可以用 Rust 编写 WebGPU 着色器,这只是编写将正确组件插入在一起的构建工具的问题。(我确实觉得,并且在上面抱怨过,WGSL 要求为在动态语言中使用替代着色器语言或 C++ 等构建系统损坏或没有构建系统的语言制造了障碍——但 Rust 非常擅长复杂的预构建处理,所以只要你不是在字面上即时构建着色器,那么它可能会让这变得容易。)

我想象一个纯 Rust 程序,其中某些函数被标记为编译到着色器,我可以在我的着色器和我的 CPU 代码之间共享数学辅助函数,或者我可以在“在编写之前将其作为过滤器运行”之间快速切换某些函数缓冲”或“将其作为计算着色器运行”,具体取决于性能考虑和心血来潮。我有一个使用计算着色器的现有项目并回答“这在 CPU 上还是在计算着色器上会更快吗?”²² 涉及将我的所有代码编写两次,然后编写复杂的脚手架代码来处理来回切换。那可能都是自动的。我能让事情变得比这更奇怪吗?我喜欢 Rust 用于低级引擎代码,但有时我更愿意为业务逻辑编写 TypeScript/”已经混合了 Rust 和 TypeScript,为此有大量的示例代码。我也可以在桌面上混合使用 Rust 和 TypeScript 吗?如果 wgpu 已经是我的图形引擎,我可以推入 Servo 或 QuickJS 或其他东西,并编写一个跨平台程序,在浏览器中作为 TypeScript 运行,其中嵌入了 wasm-bindgen Rust,或者在桌面上作为 Rust 运行,并在桌面上运行,并在其中包含 TypeScript 解释器。大多数 Rust GUI/游戏库已经在 wasm 中工作,并且有这个纯 Rust WebAudio 实现(它目前不是wasm-bindgen WebAudio 的直接替代品,但可以修复)。我想创建一个小型的仿网页游戏引擎,它具有 Electron 的所有优点而没有任何缺点。或者我可以只使用Tauri对于同样的事情,现在无需我做任何工作就可以工作。

我可以让它更奇怪?WebGPU 的规范作为机器可解析的 WebIDL 文件提供;这会让为 Lua 生成绑定变得异常容易吗?如果我可以将 Rust 编译为 WGSL 并编写一个纯 Rust-including-shaders 程序,我可以将TypeScript或 AssemblyScript 或其他东西编译为 WGSL 并编写一个纯 TypeScript-including-shaders 程序吗?或者,如果我关心的是不必用两种语言编写我的程序,而不是我在编写哪种语言,那么为什么不采用另一种方式呢?为 WGSL 编写一个 LLVM 后端,将其编译为 native+wasm 并在 WGSL 中编写一个包含着色器的完整程序。如果 w3 认为 WGSL 应该如此伟大,那为什么不呢?

好的,这是我的博客文章。


¹ 113 或更新

² “片段”是 OpenGL 的“像素”。

³我仍在尝试弄清楚现代视频卡是否只是基于 Quake 3 的内部架构。

⁴ 现在,那些坐标必须描述三角形。想画一个矩形?去你的,显然!

⁵(以及一系列 OpenGL 技术和扩展,在 OpenGL 被淘汰之前似乎没有人真正有机会使用。)

⁶ 为什么 Vulkan/WebGPU 中的“推送常量”不同于“制服”?好吧,因为在 GPU 芯片内部这是两种不同的东西。为什么你会使用一个而不是另一个?好吧,了解 GPU 芯片在做什么,然后您就会明白为什么在某些情况下这些可能更合适。这听起来像是很多精神开销吗?好吧,有时候,但老实说,与试图理解“VAO”是什么相比,它的精神开销更少。(编辑:事实证明 WebGPU 没有推送常量。我只是认为它们有,因为 Rust WebGPU 库将它们作为特定于桌面的扩展提供。无论如何,这是一个例子。)

⁷ 要求

⁸ 顺便说一下,你注意到星际迷航中那个俗气的笑话了吗?在 Khronos 董事会拥有席位的公司总市值达 6.1 万亿美元。这就是6​​.1万亿美元买来的幽默感。

⁹ 不过,有不错的基于 Vulkan 的 OSS游戏引擎LÖVR是我在工作中使用的基于 Lua 的游戏引擎,在其 Vulkan 后端之上有一个非常精简的 Lua 前端,可供初学者使用,但暴露了您真正关心的大部分 GPU 灵活性。(Lua API 本身也是 LÖVR 特定 C API 之上的薄包装器,并且图形模块设计原则上与 LÖVR 分离,所以如果我没有 WebGPU,我实际上可能会使用 LÖVR 的 C 前端现在甚至在 Lua 之外。)

¹⁰ 这使得 OpenGL 的碎片化问题更加严重,因为 OpenGL 的“最终”形式基本上是某个地方的 4.4-4.6 版本,而 Apple 到了 4.1 就停止了。因此,如果您想在 Mac 上发布 OpenGL 软件,无论允许的时间有多长,您的目标几乎是完全是 API 的最终全功能版本。这糟透了!4.3 中有一些重要的内容。

¹¹ Microsoft 在 Windows 11 中将 ANGLE 作为其 Android 兼容层的 OpenGL 组件提供,并且 ANGLE 还作为少数游戏的图形引擎提供,例如,呃…… [查看维基百科] Shovel Knight?!如果 ANGLE 从一开始就像 WebGPU 一样被设计为库重用,或者如果有人想使用 OpenGL,您可能会看到它使用得更多。

¹² 如果我是一个愤世嫉俗、偏执的阴谋论者,我会在这里提出这样一个理论,即 Apple 在某个时候决定他们想要保留起诉 Khronos 板上其他视频卡开发商的能力,所以他们积极拒绝让他们的代码接触任何触及 Vulkan 专利池的东西,以使自己免受反诉讼。或者,如果我是一个愤世嫉俗、偏执的阴谋论者,我就会这么说。假设地。

¹³ 如果您密切注意此处,您会注意到一些奇怪的事情:管线将缓冲区接口特定着色器组合在一起,因此您可以使用具有许多不同缓冲区但只有一个着色器或着色器对的单个管线。WebGPU 和 Vulkan 的早期用户发现,在一个中等大小的程序中,你最终需要大量管道对象,尽管管道对象本身是轻量级的,但创建管道对象可能有点慢,尤其是如果你必须在一个框架上创建多个。所以这是一个确定的痛点,必须提前考虑所有人您需要的管道对象并提前缓存它们,而 Vulkan 已经尝试通过像一个月前那样引入一种称为“着色器对象”的东西来解决这个问题。希望 WebGPU WG 会考虑在下一个修订版中做类似的事情。

¹⁴ 这让我很恼火,但我和更喜欢它的人谈过,我猜是因为他们在打错他们的制服名称时遇到了问题。

¹⁵ 这个示例比我发布此示例时希望拥有的要少一些。目前已知的问题:它带有一个 Preact Canvas 包装器,它强制执行画布的宽高比和整数倍尺寸要求,但它没有全屏运行的选项;如果您在非 WebGPU 浏览器中打开示例(也可能在其他情况下),则会出现不必要的滚动条;有一个名为“canvas2image.ts”的未使用文件,它应该用于让您将状态下载为 PNG 并且应该被连接或删除;如果您确实将 canvas2image 添加回去,它就不起作用,而且我不知道问题出在我这边还是Chrome 的问题;这些评论引用了 2021 WebGPU 中的一些概念,例如交换链。

¹⁶ 如果您不喜欢 WebPack,这意味着您对 JavaScript 了解足够多,您已经知道如何用其他东西替换示例中的 WebPack。

¹⁷ 不是特定的 three.js 背书。我从来没有用过它。人们似乎喜欢它。(BabylonJS)(RedGPU)替代品(PlayCanvas,顺便说一句,它非常酷)。

¹⁸ 等等,JS 模块/import现在只能在浏览器中工作吗?我什至不知道大声笑

¹⁹ 如果您正在使用 Rust,您很可能已经在使用 WebGPU。Rust 库很快就远远领先于它的 Firefox 父软件,并且一段时间以来已经被用作新兴 GUI 库(如Iced )的基础图形层。因此,您可以只使用 Iced 或 Bevy 来处理高级内容,然后在原始 WebGPU 中进行额外的绘制。我没试过。

²⁰ 如果你这样做会出现各种警告:如果你在 Windows 上,我建议安装 wasm-pack 二进制包,而不是尝试通过 cargo 安装它。如果您是从头开始构建 Web,而不是使用我的示例,请注意wgpu wiki 中的“截至 2022 年 9 月 20 日”这一稍微令人担忧的注释。

²¹ 在撰写本文时,该示例还有一些注意事项:它只能填充窗口,不能进行宽高比或整数倍限制;它没有动画;为了获得填充窗口的行为,我不得不将它基于winit PR,所以使用的 winit 版本比它可能的要旧一点;有未解决的警告;我不清楚我使用的 wgpu 示例代码的许可证状态,所以在我得到澄清或重写之前,即使在网络上使用此示例,您也应该遵循 wgpu MIT 许可证。我计划最终扩展此示例以包括控制器支持和声音。

²² 令人震惊的是,答案竟然是“这取决于您运行的设备”。

我想谈谈 WebGPU
标签: