WebGPU の新機能(Chrome 121)

François Beaufort
François Beaufort

Android で WebGPU をサポートする

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

近日中には、Android 11 を搭載するデバイスを含め、幅広い Android デバイスにサポートを段階的に拡大していく予定です。幅広いハードウェア構成でシームレスなエクスペリエンスを実現するには、さらなるテストと最適化が必要です。問題 chromium:1497815 をご覧ください。

<ph type="x-smartling-placeholder">
</ph> Chrome for Android で動作する WebGPU サンプルのスクリーンショット
Chrome for Android で動作する WebGPU のサンプル

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

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

初期テストでは、DXC を使用した場合にコンピューティング シェーダーのコンパイル速度が平均 20% 向上したという結果が出ています。

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

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

GPUAdapter"timestamp-query" 機能が利用可能になったときに、次のことができるようになりました。

  • "timestamp-query" 機能を使用して GPUDevice をリクエストします。
  • "timestamp" 型の GPUQuerySet を作成します。
  • GPUComputePassDescriptor.timestampWritesGPURenderPassDescriptor.timestampWrites を使用して、GPUQuerySet でタイムスタンプ値を書き込む場所を定義します。
  • resolveQuerySet() でタイムスタンプ値を GPUBuffer に解決します。
  • 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 ブラウザで「WebGPU のデベロッパー向け機能」を有効にすると、タイムスタンプの量子化を無効にできます。フラグchrome://flags/#enable-webgpu-developer-features で設定します。詳細については、タイムスタンプ クエリの量子化をご覧ください。

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

<ph type="x-smartling-placeholder">
</ph> タイムスタンプ クエリを使用した 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-featuresflag が有効になります。次の例と問題 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 に表示されるアダプター情報のメモリヒープ。

夜明けの最新情報

WGSL の言語機能を処理するために、wgpu::InstanceHasWGSLLanguageFeature メソッドと EnumerateWGSLLanguageFeatures メソッドが追加されました。問題 dawn:2260 をご覧ください。

非標準の wgpu::Feature::BufferMapExtendedUsages 機能を使用すると、wgpu::BufferUsage::MapRead または wgpu::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 ローカル ストレージシェーダー機能マルチプレーナー形式

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