赞
踩
https://developer.chrome.com/blog/from-webgl-to-webgpu/
作为一名 WebGL 开发人员,您可能会对开始使用 WebGPU 感到既害怕又兴奋,WebGPU 是 WebGL 的后继者,它将现代图形 API 的进步带到了Web端。
令人欣慰的是,WebGL 和 WebGPU 共享许多核心概念。 这两个 API 都允许您在 GPU 上运行称为着色器的小程序。 WebGL 支持顶点和片段着色器,而 WebGPU 也支持计算着色器。 WebGL 使用 OpenGL 着色语言 (GLSL),而 WebGPU 使用 WebGPU 着色语言 (WGSL)。 尽管两种语言不同,但基本概念大多相同。
考虑到这一点,本文重点介绍了 WebGL 和 WebGPU 之间的一些差异,以帮助您入门。
WebGL 有很多全局状态,某些设置适用于所有渲染操作,例如绑定哪些纹理和缓冲区。 您可以通过调用各种 API 函数来设置此全局状态,并且在您更改它之前它一直有效。 WebGL 中的全局状态是错误的主要来源,因为很容易忘记更改全局设置。 此外,全局状态使代码共享变得困难,因为开发人员需要小心,不要意外地更改全局状态,从而影响代码的其他部分。
WebGPU 是无状态 API,并且不维护全局状态。 相反,它使用管道的概念来封装 WebGL 中全局的所有渲染状态。 管道包含要使用的混合、拓扑和属性等信息。 管道是不可变的。 如果要更改某些设置,则需要创建另一个管道。 WebGPU 还使用命令编码器将命令一起批处理并按照记录的顺序执行它们。 例如,这在阴影贴图中很有用,在一次通过对象时,应用程序可以记录多个命令流,每个命令流对应每个灯光的阴影贴图。
总而言之,由于 WebGL 的全局状态模型使得创建健壮、可组合的库和应用程序变得困难且脆弱,因此 WebGPU 显着减少了开发人员在向 GPU 发送命令时需要跟踪的状态量。
在 GPU 上,发送命令并同步等待它们通常效率很低,因为这可能会刷新管道并导致气泡。 在 WebGPU 和 WebGL 中尤其如此,它们使用多进程架构,GPU 驱动程序在与 JavaScript 不同的进程中运行。
例如,在 WebGL 中,调用 gl.getError() 需要从 JavaScript 进程到 GPU 进程并返回的同步 IPC。 当两个进程通信时,这可能会导致 CPU 端出现堵塞。
为了避免这些堵塞,WebGPU 被设计为完全异步的。 错误模型和所有其他操作都是异步发生的。 例如,当您创建纹理时,操作看起来立即成功,即使纹理实际上是错误的。 您只能异步发现错误。 这种设计可以保持跨进程通信无气泡,并为应用程序提供可靠的性能。
计算着色器是在 GPU 上运行以执行通用计算的程序。 它们仅在 WebGPU 中可用,在 WebGL 中不可用。
与顶点和片段着色器不同,它们不仅限于图形处理,而且可用于各种任务,例如机器学习、物理模拟和科学计算。 计算着色器由数百甚至数千个线程并行执行,这使得它们对于处理大型数据集非常高效。 阅读这篇有关 WebGPU 的内容广泛的文章,了解 GPU 计算和更多详细信息。
使用 JavaScript 和 WebAssembly 处理视频帧有一些缺点:将数据从 GPU 内存复制到 CPU 内存的成本,以及工作线程和 CPU 线程可以实现的并行性有限。 WebGPU 没有这些限制,由于它与 WebCodecs API 紧密集成,因此非常适合处理视频帧。
以下代码片段展示了如何将 VideoFrame 作为外部纹理导入到 WebGPU 中并对其进行处理。
- (function render() {
- const videoFrame = new VideoFrame(video);
- applyFilter(videoFrame);
- requestAnimationFrame(render);
- })();
-
- function applyFilter(videoFrame) {
- const texture = device.importExternalTexture({ source: videoFrame });
- const bindgroup = device.createBindGroup({
- layout: pipeline.getBindGroupLayout(0),
- entries: [{ binding: 0, resource: texture }],
- });
- // Finally, submit commands to GPU
- }
WebGPU 强制您请求限制。 默认情况下,requestDevice() 返回的 GPUDevice 可能与物理设备的硬件功能不匹配,而是所有 GPU 的合理且最低的公分母。 通过要求开发人员请求设备限制,WebGPU 确保应用程序将在尽可能多的设备上运行。
在您创建 WebGL 上下文并提供上下文属性(例如 alpha、抗锯齿、colorSpace、深度、preserveDrawingBuffer 或模板)后,WebGL 会自动管理画布。
另一方面,WebGPU 要求您自己管理画布。 例如,要在 WebGPU 中实现抗锯齿,您需要创建多重采样纹理并对其进行渲染。 然后,您可以将多重采样纹理解析为常规纹理,并将该纹理绘制到画布上。 这种手动管理允许您从单个 GPUDevice 对象输出到任意数量的画布。 相比之下,WebGL 只能为每个画布创建一个上下文。
顺便说一句,浏览器目前对每页的 WebGL 画布数量有限制。 在撰写本文时,Chrome 和 Safari 最多只能同时使用 16 个 WebGL 画布; Firefox 最多可以创建 200 个。 另一方面,每页的 WebGPU 画布数量没有限制。
WebGPU 为从 API 返回的每条消息提供一个调用堆栈。 这意味着您可以快速查看代码中发生错误的位置,这有助于调试和修复错误。
除了提供调用堆栈之外,WebGPU 错误消息也易于理解且可操作。 错误消息通常包括错误的描述以及如何修复错误的建议。
WebGPU 还允许您为每个 WebGPU 对象提供自定义标签。 然后浏览器会在 GPUError 消息、控制台警告和浏览器开发人员工具中使用该标签。
在 WebGL 中,许多事物都是通过名称联系起来的。 例如,您可以在 GLSL 中声明一个名为 myUniform 的统一变量,并使用 gl.getUniformLocation(program, 'myUniform') 获取其位置。 如果您错误输入统一变量的名称,这会很方便,因为您会收到错误消息。
另一方面,在 WebGPU 中,一切都完全通过字节偏移或索引(通常称为位置)连接。 您有责任保持 WGSL 和 JavaScript 中代码的位置同步。
在WebGL中,您可以创建纹理的0级mip,然后调用gl.generateMipmap()。 然后,WebGL 将为您生成所有其他 mip 级别。
在 WebGPU 中,您必须自己生成 mipmap,没有内置函数可以执行此操作。 请参阅规范讨论以了解有关该决定的更多信息。 您可以使用 webgpu-utils 等方便的库来生成 mipmap 或学习如何自己生成。
WebGL 和 WebGPU 均支持统一缓冲区,并允许您将有限大小的常量参数传递给着色器。 存储缓冲区看起来很像统一缓冲区,但仅受 WebGPU 支持,并且比统一缓冲区更强大、更灵活。
存储纹理仅在 WebGPU 中受支持,并且对于纹理来说就像存储缓冲区对于统一缓冲区一样。 它们比常规纹理更灵活,支持随机访问写入(以及将来的读取)。
在 WebGL 中,您可以创建缓冲区或纹理,然后分别使用 gl.bufferData() 和 gl.texImage2D() 随时更改其大小。
在 WebGPU 中,缓冲区和纹理是不可变的。 这意味着创建后您无法更改它们的大小、用途或格式。 您只能更改其内容。
在WebGL中,Z剪辑空间范围是从-1到1。在WebGPU中,Z剪辑空间范围是从0到1。这意味着z值为0的对象距离相机最近,而z值为0的对象距离相机最近。 1 是最远的。
WebGL 使用 OpenGL 约定,其中 Y 轴向上,Z 轴朝向观察者。 WebGPU 使用 Metal 约定,其中 Y 轴向下,Z 轴在屏幕之外。 请注意,在帧缓冲区坐标、视口坐标和片段/像素坐标中,Y 轴方向向下。 在剪辑空间中,Y 轴方向仍然像 WebGL 中一样向上。
其他探讨WebGL和WebGPU的文章:
1、Chrome和safari最多同时使用16个WebGL画布,Firefox最多可创建200个,而WebGPU画布没有限制。
2、WebGPU可以共享纹理,将 GPUDevice 对象输出到任意数量的画布。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。