WebGPU の新機能(Chrome 121)

François Beaufort
François Beaufort

Android での WebGPU のサポート

Chrome チームは、Qualcomm GPU と ARM GPU を搭載した Android 12 以降を搭載したデバイスの Chrome 121 で WebGPU がデフォルトで有効になったことを発表いたします。

サポートは、Android 11 を搭載したデバイスなど、より広範な Android デバイスに徐々に拡大される予定です。この拡大は、より広範なハードウェア構成でシームレスなエクスペリエンスを確保するためのさらなるテストと最適化に依存します。issue chromium:1497815 をご覧ください。

Android 版 Chrome で実行されている WebGPU サンプルのスクリーンショット。
Chrome for Android で実行されている WebGPU サンプル。

Windows でのシェーダー コンパイルに FXC ではなく DXC を使用する

Chrome は、SM6+ グラフィック ハードウェアを搭載した Windows D3D12 マシンで、DXC(DirectX コンパイラ)の機能を使用してシェーダーをコンパイルするようになりました。これまで、WebGPU は Windows でのシェーダー コンパイルに FXC(FX コンパイラ)を使用していました。FXC は機能しますが、DXC にある機能セットとパフォーマンスの最適化がありませんでした。

初期テストでは、FXC と比較して DXC を使用すると、コンピューティング シェーダーのコンパイル速度が平均 20% 向上しています。

コンピューティング パスとレンダリング パスのタイムスタンプ クエリ

タイムスタンプ クエリを使用すると、WebGPU アプリケーションは、GPU コマンドがコンピューティング パスとレンダリング パスの実行にかかる時間を正確に(ナノ秒単位で)測定できます。これらは、GPU ワークロードのパフォーマンスと動作に関する分析情報を得るために広く使用されています。

GPUAdapter"timestamp-query" 機能が使用可能な場合は、次の操作を行うことができます。

  • "timestamp-query"」機能を使用して GPUDevice をリクエストします。
  • GPUQuerySet のタイプが "timestamp" のを作成します。
  • GPUComputePassDescriptor.timestampWritesGPURenderPassDescriptor.timestampWrites を使用して、GPUQuerySet にタイムスタンプ値を書き込む場所を定義します。
  • タイムスタンプ値を GPUBufferresolveQuerySet() を使用して解決します。
  • GPUBuffer から CPU に結果をコピーして、タイムスタンプ値を読み取ります。
  • タイムスタンプ値を BigInt64Array としてデコードします。

次の例と 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 ブラウザでは、アプリの開発中に chrome://flags/#enable-webgpu-developer-features で "WebGPU デベロッパー機能" [flag] を有効にすることで、タイムスタンプの量子化を無効にできます。詳しくは、タイムスタンプ クエリの量子化をご覧ください。

GPU がタイムスタンプ カウンタをリセットすることがあります。これにより、タイムスタンプ間の差分が負の値になるなど、予期しない値が発生する可能性があります。次の Compute Boids サンプルにタイムスタンプ クエリのサポートを追加する git diff の変更を確認することをおすすめします。

タイムスタンプ クエリを特徴とする Compute Boids サンプルのスクリーンショット。
タイムスタンプ クエリを備えた Compute Boids サンプル。

シェーダー モジュールのデフォルトのエントリ ポイント

デベロッパー エクスペリエンスを向上させるため、コンピューティング パイプラインまたはレンダリング パイプラインを作成するときに、シェーダー モジュールの entryPoint を省略できるようになりました。シェーダー ステージの一意のエントリ ポイントがシェーダー コードで見つからない場合は、GPUValidationError がトリガーされます。次の例と 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 }] },
});

GPUExternalTexture の色空間として display-p3 をサポートする

`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 で有効になっている場合にのみアクセスできます。次の例と 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)   { /* ... */ }
}
アダプタ情報にメモリヒープが表示されている https://webgpureport.org のスクリーンショット。
https://webgpureport.org に表示されるアダプター情報メモリヒープ。

Dawn の最新情報

wgpu::InstanceHasWGSLLanguageFeature メソッドと EnumerateWGSLLanguageFeatures メソッドが追加され、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 テクスチャ形式パス内のタイムスタンプ クエリピクセル ローカル ストレージシェーダー機能、および マルチプレーン形式

Chrome チームは、Dawn の公式 GitHub リポジトリを作成しました。

これは主なハイライトの一部にすぎません。コミットの完全なリストをご覧ください。

WebGPU の新機能

WebGPU の新機能シリーズで取り上げられたすべての機能の一覧です。

Chrome 147 ~ 148

Chrome 146

Chrome 145

Chrome 144

Chrome 143

Chrome 142

Chrome 141

Chrome 140

Chrome 139

Chrome 138

Chrome 137

Chrome 136

Chrome 135

Chrome 134

Chrome 133

Chrome 132

Chrome 131

Chrome 130

Chrome 129

Chrome 128

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