WebGPU 的新变化 (Chrome 121)

François Beaufort
François Beaufort

在 Android 上支持 WebGPU

Chrome 团队非常高兴地宣布,在搭载 Android 12 及更高版本且由 Qualcomm 和 ARM GPU 提供支持的设备上,Chrome 121 中现已默认启用 WebGPU。

我们将逐步扩大支持范围,涵盖更广泛的 Android 设备,包括在不久的将来搭载 Android 11 的设备。此次扩展将取决于进一步的测试和优化,以确保在更广泛的硬件配置中实现无缝体验。请参阅问题 chromium:1497815

在 Chrome(Android 版)上运行的 WebGPU 示例的屏幕截图。
在 Chrome(Android 版)上运行的 WebGPU 示例。

在 Windows 上使用 DXC(而非 FXC)进行着色器编译

现在,Chrome 利用 DXC (DirectX Compiler) 的强大功能,在配备 SM6+ 图形硬件的 Windows D3D12 计算机上编译着色器。之前,WebGPU 依赖 FXC (FX Compiler) 在 Windows 上进行着色器编译。虽然功能正常,但 FXC 缺乏 DXC 中的功能集和性能优化。

初始测试显示,与 FXC 相比,使用 DXC 时计算着色器的编译速度平均提高了 20%。

计算传递和渲染传递中的时间戳查询

时间戳查询可让 WebGPU 应用精确测量其 GPU 命令执行计算和渲染通道所花费的时间(精确到纳秒)。它们大量用于深入了解 GPU 工作负载的性能和行为。

GPUAdapter 中提供 "timestamp-query" 功能时,您现在可以执行以下操作:

请参阅以下示例并发出 dawn:1800 问题。

const adapter = await navigator.gpu.requestAdapter();
if (!adapter.features.has("timestamp-query")) {
  throw new Error("Timestamp query feature is not available");
}
// Explicitly request timestamp query feature.
const device = await adapter.requestDevice({
  requiredFeatures: ["timestamp-query"],
});
const commandEncoder = device.createCommandEncoder();

// Create a GPUQuerySet which holds 2 timestamp query results: one for the
// beginning and one for the end of compute pass execution.
const querySet = device.createQuerySet({ type: "timestamp", count: 2 });
const timestampWrites = {
  querySet,
  beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins.
  endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends.
};
const passEncoder = commandEncoder.beginComputePass({ timestampWrites });
// TODO: Set pipeline, bind group, and dispatch work to be performed.
passEncoder.end();

// Resolve timestamps in nanoseconds as a 64-bit unsigned integer into a GPUBuffer.
const size = 2 * BigInt64Array.BYTES_PER_ELEMENT;
const resolveBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
});
commandEncoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);

// Read GPUBuffer memory.
const resultBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
});
commandEncoder.copyBufferToBuffer(resolveBuffer, 0, resultBuffer, 0, size);

// Submit commands to the GPU.
device.queue.submit([commandEncoder.finish()]);

// Log compute pass duration in nanoseconds.
await resultBuffer.mapAsync(GPUMapMode.READ);
const times = new BigInt64Array(resultBuffer.getMappedRange());
console.log(`Compute pass duration: ${Number(times[1] - times[0])}ns`);
resultBuffer.unmap();

由于存在计时攻击问题,时间戳查询采用 100 微秒的分辨率进行量化,因此可在精度和安全性之间实现很好的折衷。在 Chrome 浏览器中,您可以通过启用“WebGPU 开发者功能”来停用时间戳量化flag chrome://flags/#enable-webgpu-developer-features。如需了解详情,请参阅时间戳查询量化

由于 GPU 可能会偶尔重置时间戳计数器,从而导致出现意外的值(例如时间戳之间的负增量),因此建议您查看 git diff 变更,该变更为以下 Compute Boids 示例添加了时间戳查询支持。

包含时间戳查询的 Compute Boids 示例的屏幕截图。
包含时间戳查询的 Compute Boids 示例。

着色器模块的默认入口点

为了提升开发者体验,您现在可以在创建计算或渲染流水线时省略着色器模块的 entryPoint。如果在着色器代码中找不到着色器阶段的唯一入口点,则会触发 GPUValidationError。请参阅以下示例和issue dawn:2254

const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
const module = myDevice.createShaderModule({ code });
const format = navigator.gpu.getPreferredCanvasFormat();
const pipeline = await myDevice.createRenderPipelineAsync({
  layout: "auto",
  vertex: { module, entryPoint: "vertexMain" },
  fragment: { module, entryPoint: "fragmentMain", targets: [{ format }] },
  vertex: { module },
  fragment: { module, targets: [{ format }] },
});

支持 display-p3 作为 GPUExternalTexture 颜色空间

现在,在使用 importExternalTexture() 从 HDR 视频导入 GPUExternalTexture 时,您可以设置 "display-p3" 目标颜色空间。查看 WebGPU 如何处理颜色空间。请参阅以下示例并问题 chromium:1330250

// Create texture from HDR video.
const video = document.querySelector("video");
const texture = myDevice.importExternalTexture({
  source: video,
  colorSpace: "display-p3",
});

内存堆信息

为了帮助您在应用开发过程中预测内存限制,requestAdapterInfo() 现在公开了 memoryHeaps 信息,例如适配器上可用内存堆的大小和类型。此实验性功能仅在“WebGPU 开发者功能”中chrome://flags/#enable-webgpu-developer-features 上的 flag 已启用。请参阅以下示例和issue dawn:2249

const adapter = await navigator.gpu.requestAdapter();
const adapterInfo = await adapter.requestAdapterInfo();

for (const { size, properties } of adapterInfo.memoryHeaps) {
  console.log(size); // memory heap size in bytes
  if (properties & GPUHeapProperty.DEVICE_LOCAL)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_VISIBLE)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_COHERENT) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_UNCACHED) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_CACHED)   { /* ... */ }
}
<ph type="x-smartling-placeholder">
</ph> https://webgpureport.org 屏幕截图,显示了适配器信息中的内存堆。
https://webgpureport.org 上显示的适配器信息内存堆。

Dawn 最新动态

添加了 wgpu::Instance 上的 HasWGSLLanguageFeatureEnumerateWGSLLanguageFeatures 方法,用于处理 WGSL 语言功能。请参阅问题 dawn:2260

借助非标准 wgpu::Feature::BufferMapExtendedUsages 功能,您可以使用 wgpu::BufferUsage::MapReadwgpu::BufferUsage::MapWrite 以及任何其他 wgpu::BufferUsage 创建 GPU 缓冲区。请参阅以下示例并问题 dawn:2204

wgpu::BufferDescriptor descriptor = {
  .size = 128,
  .usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Uniform
};
wgpu::Buffer uniformBuffer = device.CreateBuffer(&descriptor);

uniformBuffer.MapAsync(wgpu::MapMode::Write, 0, 128,
   [](WGPUBufferMapAsyncStatus status, void* userdata)
   {
      wgpu::Buffer* buffer = static_cast<wgpu::Buffer*>(userdata);
      memcpy(buffer->GetMappedRange(), data, sizeof(data));
   },
   &uniformBuffer);

已记录以下功能:ANGLE 纹理共享受 D3D11 保护的多线程隐式设备同步Norm16 纹理格式卡券内的时间戳查询Pixel 本地存储着色器功能多平面}格式{/15

Chrome 团队为 Dawn 创建了一个官方的 GitHub 代码库

本指南仅涵盖部分重要内容。查看详尽的提交内容列表

WebGPU 的新变化

WebGPU 新变化系列涵盖的所有内容的列表。

Chrome 127

Chrome 126

Chrome 125

Chrome 124

Chrome 123

Chrome 122

Chrome 121

Chrome 120

Chrome 119

Chrome 118

Chrome 117

Chrome 116

Chrome 115

Chrome 114

Chrome 113