WebGPU - 次世代Web向けGPU API

20分 で読める | 2025.01.21

WebGPUとは

WebGPUは、Webブラウザから低レベルのGPU機能にアクセスするための次世代APIです。WebGLの後継として設計され、Vulkan、Metal、Direct3D 12などのモダンなグラフィックスAPIを抽象化しています。

flowchart TB
    subgraph Web["Webアプリケーション"]
        App["JavaScript/TypeScript"]
    end

    subgraph API["グラフィックスAPI"]
        WebGPU["WebGPU API"]
    end

    subgraph Native["ネイティブAPI"]
        Vulkan["Vulkan<br/>(Linux/Android)"]
        Metal["Metal<br/>(macOS/iOS)"]
        D3D12["Direct3D 12<br/>(Windows)"]
    end

    subgraph GPU["GPU"]
        Hardware["GPUハードウェア"]
    end

    App --> WebGPU
    WebGPU --> Vulkan
    WebGPU --> Metal
    WebGPU --> D3D12
    Vulkan --> Hardware
    Metal --> Hardware
    D3D12 --> Hardware

WebGL vs WebGPU

特徴WebGL 2.0WebGPU
設計年20172023
ベースOpenGL ES 3.0Vulkan/Metal/D3D12
コンピュートシェーダー×
マルチスレッド×
メモリ管理自動明示的
バインドグループ×
シェーダー言語GLSLWGSL

基本的な使い方

1. GPUアダプターの取得

async function initWebGPU(): Promise<{ device: GPUDevice; context: GPUCanvasContext }> {
  // GPUアダプターを要求
  const adapter = await navigator.gpu?.requestAdapter();
  if (!adapter) {
    throw new Error('WebGPU not supported');
  }

  // GPUデバイスを取得
  const device = await adapter.requestDevice();

  // キャンバスコンテキストを設定
  const canvas = document.querySelector('canvas')!;
  const context = canvas.getContext('webgpu')!;
  const format = navigator.gpu.getPreferredCanvasFormat();

  context.configure({
    device,
    format,
    alphaMode: 'premultiplied',
  });

  return { device, context };
}

2. シェーダーの作成(WGSL)

// 頂点シェーダー
@vertex
fn vertexMain(@location(0) position: vec3f) -> @builtin(position) vec4f {
    return vec4f(position, 1.0);
}

// フラグメントシェーダー
@fragment
fn fragmentMain() -> @location(0) vec4f {
    return vec4f(1.0, 0.5, 0.2, 1.0); // オレンジ色
}

3. レンダリングパイプライン

function createPipeline(device: GPUDevice, format: GPUTextureFormat): GPURenderPipeline {
  const shaderModule = device.createShaderModule({
    code: `
      @vertex
      fn vertexMain(@location(0) position: vec3f) -> @builtin(position) vec4f {
        return vec4f(position, 1.0);
      }

      @fragment
      fn fragmentMain() -> @location(0) vec4f {
        return vec4f(1.0, 0.5, 0.2, 1.0);
      }
    `,
  });

  return device.createRenderPipeline({
    layout: 'auto',
    vertex: {
      module: shaderModule,
      entryPoint: 'vertexMain',
      buffers: [{
        arrayStride: 12, // 3 floats * 4 bytes
        attributes: [{
          format: 'float32x3',
          offset: 0,
          shaderLocation: 0,
        }],
      }],
    },
    fragment: {
      module: shaderModule,
      entryPoint: 'fragmentMain',
      targets: [{ format }],
    },
  });
}

コンピュートシェーダー(GPGPU)

WebGPUの最大の特徴は、グラフィックス以外の汎用計算(GPGPU)が可能なことです。

行列演算の例

async function matrixMultiply(device: GPUDevice, a: Float32Array, b: Float32Array): Promise<Float32Array> {
  const size = Math.sqrt(a.length);

  // バッファ作成
  const bufferA = device.createBuffer({
    size: a.byteLength,
    usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
  });
  const bufferB = device.createBuffer({
    size: b.byteLength,
    usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
  });
  const bufferResult = device.createBuffer({
    size: a.byteLength,
    usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
  });

  device.queue.writeBuffer(bufferA, 0, a);
  device.queue.writeBuffer(bufferB, 0, b);

  // コンピュートシェーダー
  const shaderModule = device.createShaderModule({
    code: `
      @group(0) @binding(0) var<storage, read> matrixA: array<f32>;
      @group(0) @binding(1) var<storage, read> matrixB: array<f32>;
      @group(0) @binding(2) var<storage, read_write> result: array<f32>;

      @compute @workgroup_size(8, 8)
      fn main(@builtin(global_invocation_id) id: vec3u) {
        let row = id.x;
        let col = id.y;
        let size = ${size}u;

        if (row >= size || col >= size) { return; }

        var sum = 0.0;
        for (var i = 0u; i < size; i++) {
          sum += matrixA[row * size + i] * matrixB[i * size + col];
        }
        result[row * size + col] = sum;
      }
    `,
  });

  // パイプライン作成
  const pipeline = device.createComputePipeline({
    layout: 'auto',
    compute: {
      module: shaderModule,
      entryPoint: 'main',
    },
  });

  // バインドグループ
  const bindGroup = device.createBindGroup({
    layout: pipeline.getBindGroupLayout(0),
    entries: [
      { binding: 0, resource: { buffer: bufferA } },
      { binding: 1, resource: { buffer: bufferB } },
      { binding: 2, resource: { buffer: bufferResult } },
    ],
  });

  // 実行
  const commandEncoder = device.createCommandEncoder();
  const passEncoder = commandEncoder.beginComputePass();
  passEncoder.setPipeline(pipeline);
  passEncoder.setBindGroup(0, bindGroup);
  passEncoder.dispatchWorkgroups(Math.ceil(size / 8), Math.ceil(size / 8));
  passEncoder.end();

  // 結果を読み取り
  const readBuffer = device.createBuffer({
    size: a.byteLength,
    usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
  });
  commandEncoder.copyBufferToBuffer(bufferResult, 0, readBuffer, 0, a.byteLength);
  device.queue.submit([commandEncoder.finish()]);

  await readBuffer.mapAsync(GPUMapMode.READ);
  const result = new Float32Array(readBuffer.getMappedRange().slice(0));
  readBuffer.unmap();

  return result;
}

WGSL(WebGPU Shading Language)

WebGPU専用のシェーダー言語で、Rustに似た構文を持ちます。

基本構文

// 変数宣言
var<private> count: u32 = 0;
let constant: f32 = 3.14159;

// 構造体
struct Vertex {
    @location(0) position: vec3f,
    @location(1) color: vec4f,
}

// 関数
fn add(a: f32, b: f32) -> f32 {
    return a + b;
}

// 組み込み関数
fn example() {
    let v = vec3f(1.0, 2.0, 3.0);
    let len = length(v);           // ベクトル長
    let n = normalize(v);          // 正規化
    let d = dot(v, n);             // 内積
    let c = cross(v, n);           // 外積
    let m = max(1.0, 2.0);         // 最大値
    let s = sin(3.14 / 2.0);       // 三角関数
}

ユースケース

1. 機械学習推論

// ブラウザ上でのニューラルネットワーク推論
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-webgpu';

await tf.setBackend('webgpu');
const model = await tf.loadGraphModel('model.json');
const prediction = model.predict(inputTensor);

2. 画像・動画処理

@group(0) @binding(0) var inputTexture: texture_2d<f32>;
@group(0) @binding(1) var outputTexture: texture_storage_2d<rgba8unorm, write>;

@compute @workgroup_size(8, 8)
fn blur(@builtin(global_invocation_id) id: vec3u) {
    // ガウシアンブラー処理
    var sum = vec4f(0.0);
    let weights = array<f32, 9>(
        0.0625, 0.125, 0.0625,
        0.125,  0.25,  0.125,
        0.0625, 0.125, 0.0625
    );

    for (var dy = -1; dy <= 1; dy++) {
        for (var dx = -1; dx <= 1; dx++) {
            let coord = vec2i(id.xy) + vec2i(dx, dy);
            let color = textureLoad(inputTexture, coord, 0);
            sum += color * weights[(dy + 1) * 3 + (dx + 1)];
        }
    }

    textureStore(outputTexture, vec2i(id.xy), sum);
}

3. 物理シミュレーション

struct Particle {
    position: vec3f,
    velocity: vec3f,
}

@group(0) @binding(0) var<storage, read_write> particles: array<Particle>;

@compute @workgroup_size(64)
fn simulate(@builtin(global_invocation_id) id: vec3u) {
    let index = id.x;
    var p = particles[index];

    // 重力
    p.velocity.y -= 9.8 * deltaTime;

    // 位置更新
    p.position += p.velocity * deltaTime;

    // 地面との衝突
    if (p.position.y < 0.0) {
        p.position.y = 0.0;
        p.velocity.y *= -0.8; // 反発係数
    }

    particles[index] = p;
}

ブラウザサポート

ブラウザサポート状況
Chrome 113+◎ 完全サポート
Edge 113+◎ 完全サポート
Firefox△ フラグで有効化
Safari 17+○ サポート

関連記事

まとめ

WebGPUは、Webプラットフォームに革新的なGPU機能をもたらします。

  • モダンAPI: Vulkan/Metal/D3D12の抽象化
  • コンピュートシェーダー: GPGPU対応
  • WGSL: 安全で表現力豊かなシェーダー言語
  • 高性能: 低オーバーヘッドな設計

3Dグラフィックス、機械学習、科学計算など、GPU性能を必要とするWebアプリケーションの可能性を大きく広げます。

この技術を体系的に学びたいですか?

未来学では東証プライム上場企業のITエンジニアが24時間サポート。月額24,800円から、退会金0円のオンラインIT塾です。

LINEで無料相談する
← 一覧に戻る