基础对象
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,});