Skip to content

基础对象

WebGPU 相对于之前的 WebGL 会相对复杂一些,要进行 WebGPU 的开发,需要创建和配置很多的 JavaScript 对象。这些对象的的最终目标可以归结为将命令发送到 GPU

更准确来讲,就是提交 命令缓冲区(command buffers)到客户 GPU 绑定的队列上。至少需要 6 个步骤:

  1. 获取浏览器的 Navigator,可以在这里检查浏览器是否支持 WebGPU;
  2. 如果浏览器支持 WebGPU,就可以从 Navigator 获取 GPUAdapter
  3. 使用 GPUAdapter 获取 GPUDevice
  4. 使用 GPUDevice 创建 GPUCommandEncoder
  5. 配置编码器(encoder)记录命令到缓冲区(buffer);
  6. 提交命令缓冲区到 GPUDevice 绑定的 GPUQueue

如果你想渲染图形,还需要额外的步骤,需要将 GPUDevice 和一个 Canvas 绑定。需要额外三个步骤:

  1. 在 HTML 中获取 Canvas 元素;
  2. Canvas 元素中获取 GPUCanvasContext
  3. 使用 GPUDevice 和 canvas 格式配置 GPUCanvasContext

一旦 GPUDevice 绑定到 Canvas,就可以通过调用 GPUDevice 上的方法渲染图形到 Canvas

现代浏览器都有 Navigator 对象,包含了当前浏览器支持的功能。例如 clipboard 代表可以读取系统的剪贴板。

if (!navigator.gpu) {
throw new Error("WebGPU not supported.");
}

gpu 提供了两个重要的方法:

  • requestAdapter():返回一个 GPUAdapterPromise 对象;
  • getPreferredCanvasFormat():返回一个字符串,浏览器下最好的 canvas 格式,例如:bgra8unorm

浏览器支持 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

还有两个有用的参数,featureslimits

  • features:可以获得 GPU 支持的功能;
  • limits:可以获得 GPU 可以操作的最大/最小的操作参数;

GPUAdapter 最重要的功能是提供 GPUDevice,同样是返回 Promise 对象:

const device = await adapter.requestDevice();

GPUDevice 作为客户 GPU 的 逻辑连接,在 WebGPU 的开发中是一个中心角色

GPUDevice 最重要的方法是 createCommandEncoder。这个对象用于创建和存储要发送给 GPU 的命令。

const encoder = device.createCommandEncoder();

以下三个方法是最重要的:

  • beginRenderPass:编码 render pass 用于执行图形渲染
  • beginComputePass:编码 compute pass 用于执行计算任务
  • finish:返回包含编码器命令的命令缓冲区

GPUDevice 有一个重要的属性是 queue,提供了 GPUQueue。为了执行 GPU 操作,需要调用 GPUQueue 的方法。

  • writeBuffer:更新 buffer 对象的数据
  • writeTexture:更新 texture 对象的数据
  • submit:通知 GPU 执行一个或多个命令

submit 方法特别重要,因为它告诉 GPU 要执行什么任务(图形渲染或者通用计算)。调用 submit 方法之后,可以通过 onSubmittedWorkDone 监测队列。

要在网页上展示渲染的图形,就需要使用 <canvas> 元素。需要三个步骤:

  1. 在 HTML 中创建 canvas 元素;
  2. 通过 JavaScript 获取该 canvas 元素,例如:选择器;
  3. 通过 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,
});