基础对象
WebGPU 相对于之前的 WebGL 会相对复杂一些,要进行 WebGPU 的开发,需要创建和配置很多的 JavaScript 对象。这些对象的的最终目标可以归结为将命令发送到 GPU。
更准确来讲,就是提交 命令缓冲区(command buffers)到客户 GPU 绑定的队列上。至少需要 6 个步骤:
- 获取浏览器的
Navigator
,可以在这里检查浏览器是否支持 WebGPU; - 如果浏览器支持 WebGPU,就可以从
Navigator
获取GPUAdapter
; - 使用
GPUAdapter
获取GPUDevice
; - 使用
GPUDevice
创建GPUCommandEncoder
- 配置编码器(encoder)记录命令到缓冲区(buffer);
- 提交命令缓冲区到
GPUDevice
绑定的GPUQueue
。
如果你想渲染图形,还需要额外的步骤,需要将 GPUDevice
和一个 Canvas
绑定。需要额外三个步骤:
- 在 HTML 中获取
Canvas
元素; - 从
Canvas
元素中获取GPUCanvasContext
; - 使用
GPUDevice
和 canvas 格式配置GPUCanvasContext
;
一旦 GPUDevice
绑定到 Canvas
,就可以通过调用 GPUDevice
上的方法渲染图形到 Canvas
。
Navigator
Section titled “Navigator”现代浏览器都有 Navigator
对象,包含了当前浏览器支持的功能。例如 clipboard
代表可以读取系统的剪贴板。
if (!navigator.gpu) { throw new Error("WebGPU not supported.");}
gpu
提供了两个重要的方法:
requestAdapter()
:返回一个GPUAdapter
的Promise
对象;getPreferredCanvasFormat()
:返回一个字符串,浏览器下最好的 canvas 格式,例如:bgra8unorm
GPUAdapter
Section titled “GPUAdapter”浏览器支持 WebGPU,不代表用户的硬件支持 WebGPU 的渲染和计算。 因此需要使用 requestAdapter
获得 GPUAdapter
。
需要注意的是,requestAdapter
返回的是一个 Promise
的占位对象。每一个 Promise
有三种状态:
pending
:操作还没有完成fulfillment
:操作完成rejection
:发生错误
通常会使用 await
等待操作完成:
const adapter = await navigator.gpu.requestAdapter();if (!adapter) { throw new Error("No appropriate GPUAdapter found.");}
获取到 GPUAdapter
后,就可以通过 info
获取到用户渲染和计算能力。
const info = adapter.info;
if (info) { console.log("Vendor: " + info.vendor); console.log("Architecture: " + info.architecture); console.log("Device: " + info.device); console.log("Description: " + info.description);}
完整的支持属性可以参考:GPUAdapterInfo
还有两个有用的参数,features
和 limits
。
features
:可以获得 GPU 支持的功能;limits
:可以获得 GPU 可以操作的最大/最小的操作参数;
GPUAdapter
最重要的功能是提供 GPUDevice
,同样是返回 Promise
对象:
const device = await adapter.requestDevice();
GPUDevice
Section titled “GPUDevice”GPUDevice
作为客户 GPU 的 逻辑连接,在 WebGPU 的开发中是一个中心角色。
GPUCommandEncoder
Section titled “GPUCommandEncoder”GPUDevice
最重要的方法是 createCommandEncoder
。这个对象用于创建和存储要发送给 GPU 的命令。
const encoder = device.createCommandEncoder();
以下三个方法是最重要的:
beginRenderPass
:编码 render pass 用于执行图形渲染beginComputePass
:编码 compute pass 用于执行计算任务finish
:返回包含编码器命令的命令缓冲区
GPUQueue
Section titled “GPUQueue”GPUDevice
有一个重要的属性是 queue
,提供了 GPUQueue
。为了执行 GPU 操作,需要调用 GPUQueue
的方法。
writeBuffer
:更新 buffer 对象的数据writeTexture
:更新 texture 对象的数据submit
:通知 GPU 执行一个或多个命令
submit
方法特别重要,因为它告诉 GPU 要执行什么任务(图形渲染或者通用计算)。调用 submit
方法之后,可以通过 onSubmittedWorkDone
监测队列。
Canvas
Section titled “Canvas”要在网页上展示渲染的图形,就需要使用 <canvas>
元素。需要三个步骤:
- 在 HTML 中创建 canvas 元素;
- 通过 JavaScript 获取该 canvas 元素,例如:选择器;
- 通过 canvas 的上下文(context)进行配置;
<!-- 在 HTML 中创建 canvas 元素 --><canvas id="mycanvas" width="400" height="200"></canvas>
获取 HTML 元素一般可以通过选择器或者 ID:
// 标签选择器const canvas = document.querySelector("canvas");// ID 选择器const canvas = document.getElementById("mycanvas");
之后就可以给这个 canvas
赋予 webgpu
的 context:
const context = canvas.getContext("webgpu");
最后一步,就是完成配置:
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device: device, format: canvasFormat,});
基础对象
if (!navigator.gpu) { throw new Error("WebGPU not supported.");}
const adapter = await navigator.gpu.requestAdapter();if (!adapter) { throw new Error("No appropriate GPUAdapter found.");}
const info = adapter.info;
if (info) { console.log("Vendor: " + info.vendor); console.log("Architecture: " + info.architecture); console.log("Device: " + info.device); console.log("Description: " + info.description);}
const device = await adapter.requestDevice();// const encoder = device.createCommandEncoder();
const canvas = document.getElementById(id);if (!canvas) { throw new Error(`No canvas element found: ${id}`);}
const context = canvas.getContext("webgpu");if (!context) { throw new Error("Failed to get WebGPU context.");}
const canvasFormat = navigator.gpu.getPreferredCanvasFormat();context.configure({ device: device, format: canvasFormat,});