# WebGPU: Next-Gen Browser Graphics

**Meta-Description:** WebGPU für 3D-Grafik im Browser. Performance-Vergleich zu WebGL, Compute Shaders und Three.js WebGPU Renderer.

**Keywords:** WebGPU, WebGL, 3D Graphics, Compute Shaders, GPU Programming, Three.js, Browser Graphics

---

## Einführung

**WebGPU** ist der Nachfolger von WebGL und bringt moderne GPU-Architektur in den Browser. Mit **Compute Shaders**, besserer Performance und Support in allen Major Browsern (seit 2025) ist WebGPU bereit für Production.

---

## WebGPU vs WebGL

```
┌─────────────────────────────────────────────────────────────┐
│              WEBGPU VS WEBGL COMPARISON                      │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Architecture:                                              │
│                                                             │
│  WebGL (2011):                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  JavaScript                                          │   │
│  │      ↓                                              │   │
│  │  OpenGL ES (State Machine)                          │   │
│  │      ↓                                              │   │
│  │  Driver Translation Layer                           │   │
│  │      ↓                                              │   │
│  │  GPU                                                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  WebGPU (2023):                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  JavaScript / WASM                                   │   │
│  │      ↓                                              │   │
│  │  WebGPU API (Modern, Low-Level)                     │   │
│  │      ↓                                              │   │
│  │  Native GPU APIs (Vulkan/Metal/D3D12)              │   │
│  │      ↓                                              │   │
│  │  GPU                                                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Performance Comparison:                                    │
│  ├── Draw Calls: WebGPU 10x faster (Render Bundles)       │
│  ├── Compute: WebGPU has Compute Shaders (WebGL: none)    │
│  ├── Multi-threading: WebGPU supports parallel encoding   │
│  └── Memory: WebGPU explicit resource management          │
│                                                             │
│  Browser Support (2026):                                    │
│  ├── Chrome/Edge: ✅ (since April 2023)                   │
│  ├── Firefox: ✅ (since July 2025)                        │
│  ├── Safari: ✅ (since June 2025, Safari 26)              │
│  └── Mobile: Partial (Chrome Android, Safari iOS 26)      │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Basic WebGPU Setup

```typescript
// lib/webgpu-setup.ts

async function initWebGPU(): Promise<{
  device: GPUDevice;
  context: GPUCanvasContext;
  format: GPUTextureFormat;
}> {
  // Check Support
  if (!navigator.gpu) {
    throw new Error('WebGPU not supported');
  }

  // Request Adapter
  const adapter = await navigator.gpu.requestAdapter({
    powerPreference: 'high-performance'
  });

  if (!adapter) {
    throw new Error('No GPU adapter found');
  }

  // Request Device
  const device = await adapter.requestDevice({
    requiredFeatures: [],
    requiredLimits: {}
  });

  // Canvas Context
  const canvas = document.querySelector('canvas')!;
  const context = canvas.getContext('webgpu')!;

  const format = navigator.gpu.getPreferredCanvasFormat();

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

  return { device, context, format };
}
```

---

## Triangle Rendering

```typescript
// webgpu-triangle.ts

const vertexShaderCode = /* wgsl */ `
  struct VertexOutput {
    @builtin(position) position: vec4f,
    @location(0) color: vec4f,
  }

  @vertex
  fn vertexMain(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
    var positions = array<vec2f, 3>(
      vec2f( 0.0,  0.5),  // Top
      vec2f(-0.5, -0.5),  // Bottom Left
      vec2f( 0.5, -0.5)   // Bottom Right
    );

    var colors = array<vec4f, 3>(
      vec4f(1.0, 0.0, 0.0, 1.0),  // Red
      vec4f(0.0, 1.0, 0.0, 1.0),  // Green
      vec4f(0.0, 0.0, 1.0, 1.0)   // Blue
    );

    var output: VertexOutput;
    output.position = vec4f(positions[vertexIndex], 0.0, 1.0);
    output.color = colors[vertexIndex];
    return output;
  }
`;

const fragmentShaderCode = /* wgsl */ `
  @fragment
  fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
    return color;
  }
`;

async function renderTriangle() {
  const { device, context, format } = await initWebGPU();

  // Shader Module
  const shaderModule = device.createShaderModule({
    code: vertexShaderCode + fragmentShaderCode
  });

  // Pipeline
  const pipeline = device.createRenderPipeline({
    layout: 'auto',
    vertex: {
      module: shaderModule,
      entryPoint: 'vertexMain'
    },
    fragment: {
      module: shaderModule,
      entryPoint: 'fragmentMain',
      targets: [{ format }]
    },
    primitive: {
      topology: 'triangle-list'
    }
  });

  // Render Loop
  function frame() {
    const commandEncoder = device.createCommandEncoder();

    const renderPass = commandEncoder.beginRenderPass({
      colorAttachments: [{
        view: context.getCurrentTexture().createView(),
        clearValue: { r: 0.1, g: 0.1, b: 0.1, a: 1.0 },
        loadOp: 'clear',
        storeOp: 'store'
      }]
    });

    renderPass.setPipeline(pipeline);
    renderPass.draw(3);  // 3 vertices
    renderPass.end();

    device.queue.submit([commandEncoder.finish()]);
    requestAnimationFrame(frame);
  }

  frame();
}
```

---

## Compute Shaders

```typescript
// webgpu-compute.ts

// Particle Simulation mit Compute Shader
const computeShaderCode = /* wgsl */ `
  struct Particle {
    position: vec2f,
    velocity: vec2f,
  }

  struct SimParams {
    deltaTime: f32,
    gravity: f32,
  }

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

  @compute @workgroup_size(64)
  fn main(@builtin(global_invocation_id) id: vec3u) {
    let index = id.x;
    if (index >= arrayLength(&particles)) {
      return;
    }

    var particle = particles[index];

    // Apply Gravity
    particle.velocity.y -= params.gravity * params.deltaTime;

    // Update Position
    particle.position += particle.velocity * params.deltaTime;

    // Bounce off boundaries
    if (particle.position.y < -1.0) {
      particle.position.y = -1.0;
      particle.velocity.y *= -0.8;  // Energy loss
    }

    if (abs(particle.position.x) > 1.0) {
      particle.velocity.x *= -1.0;
    }

    particles[index] = particle;
  }
`;

async function setupParticleSimulation(
  device: GPUDevice,
  particleCount: number
) {
  // Initialize Particles
  const particleData = new Float32Array(particleCount * 4);
  for (let i = 0; i < particleCount; i++) {
    particleData[i * 4 + 0] = (Math.random() - 0.5) * 2;  // x
    particleData[i * 4 + 1] = Math.random();              // y
    particleData[i * 4 + 2] = (Math.random() - 0.5) * 0.1; // vx
    particleData[i * 4 + 3] = 0;                           // vy
  }

  // Particle Buffer
  const particleBuffer = device.createBuffer({
    size: particleData.byteLength,
    usage: GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
    mappedAtCreation: true
  });
  new Float32Array(particleBuffer.getMappedRange()).set(particleData);
  particleBuffer.unmap();

  // Uniform Buffer
  const uniformBuffer = device.createBuffer({
    size: 8,  // 2 x float32
    usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
  });

  // Compute Pipeline
  const computeModule = device.createShaderModule({ code: computeShaderCode });

  const computePipeline = device.createComputePipeline({
    layout: 'auto',
    compute: {
      module: computeModule,
      entryPoint: 'main'
    }
  });

  // Bind Group
  const bindGroup = device.createBindGroup({
    layout: computePipeline.getBindGroupLayout(0),
    entries: [
      { binding: 0, resource: { buffer: particleBuffer } },
      { binding: 1, resource: { buffer: uniformBuffer } }
    ]
  });

  return {
    particleBuffer,
    uniformBuffer,
    computePipeline,
    bindGroup,
    particleCount
  };
}

function runComputePass(
  device: GPUDevice,
  simulation: Awaited<ReturnType<typeof setupParticleSimulation>>,
  deltaTime: number
) {
  const { uniformBuffer, computePipeline, bindGroup, particleCount } = simulation;

  // Update Uniforms
  device.queue.writeBuffer(
    uniformBuffer,
    0,
    new Float32Array([deltaTime, 9.81])
  );

  // Dispatch Compute
  const commandEncoder = device.createCommandEncoder();
  const computePass = commandEncoder.beginComputePass();

  computePass.setPipeline(computePipeline);
  computePass.setBindGroup(0, bindGroup);
  computePass.dispatchWorkgroups(Math.ceil(particleCount / 64));
  computePass.end();

  device.queue.submit([commandEncoder.finish()]);
}
```

---

## Three.js WebGPU Renderer

```typescript
// three-webgpu.ts
import * as THREE from 'three';
import WebGPURenderer from 'three/addons/renderers/webgpu/WebGPURenderer.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

async function initThreeWebGPU() {
  // WebGPU Renderer
  const renderer = new WebGPURenderer({ antialias: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.setPixelRatio(window.devicePixelRatio);
  document.body.appendChild(renderer.domElement);

  // Initialize WebGPU
  await renderer.init();

  // Scene Setup
  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x111111);

  // Camera
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.position.z = 5;

  // Controls
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;

  // Lights
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight);

  const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
  directionalLight.position.set(10, 10, 10);
  scene.add(directionalLight);

  // Objects
  const geometry = new THREE.TorusKnotGeometry(1, 0.3, 100, 16);
  const material = new THREE.MeshStandardMaterial({
    color: 0x00ff88,
    metalness: 0.5,
    roughness: 0.2
  });
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);

  // Animation Loop
  function animate() {
    requestAnimationFrame(animate);

    mesh.rotation.x += 0.01;
    mesh.rotation.y += 0.01;

    controls.update();
    renderer.render(scene, camera);
  }

  animate();

  // Resize Handler
  window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });
}
```

---

## React Three Fiber mit WebGPU

```tsx
// components/WebGPUScene.tsx
'use client';

import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment } from '@react-three/drei';
import { Suspense } from 'react';

export function WebGPUScene() {
  return (
    <Canvas
      gl={(canvas) => {
        // WebGPU Renderer wird automatisch verwendet wenn verfügbar
        // Fallback auf WebGL
        return undefined;
      }}
      frameloop="demand"
    >
      <Suspense fallback={null}>
        <Environment preset="city" />
        <OrbitControls />

        <mesh>
          <torusKnotGeometry args={[1, 0.3, 100, 16]} />
          <meshStandardMaterial color="#00ff88" metalness={0.5} roughness={0.2} />
        </mesh>
      </Suspense>
    </Canvas>
  );
}

// Feature Detection
export function useWebGPUSupport() {
  const [supported, setSupported] = useState<boolean | null>(null);

  useEffect(() => {
    setSupported('gpu' in navigator);
  }, []);

  return supported;
}
```

---

## Performance Benchmarks

```typescript
// benchmarks/webgpu-vs-webgl.ts

interface BenchmarkResult {
  name: string;
  webgl: number;
  webgpu: number;
  speedup: number;
}

const benchmarks: BenchmarkResult[] = [
  {
    name: 'Draw Calls (1000 objects)',
    webgl: 16.7,    // ms
    webgpu: 1.5,    // ms
    speedup: 11.1
  },
  {
    name: 'Particle System (100k)',
    webgl: 33.3,    // ms (CPU-bound)
    webgpu: 2.1,    // ms (GPU Compute)
    speedup: 15.9
  },
  {
    name: 'Shadow Mapping',
    webgl: 8.2,     // ms
    webgpu: 3.4,    // ms
    speedup: 2.4
  },
  {
    name: 'Post-Processing (5 passes)',
    webgl: 12.5,    // ms
    webgpu: 4.8,    // ms
    speedup: 2.6
  },
  {
    name: 'ML Inference (ONNX)',
    webgl: 45.0,    // ms (limited)
    webgpu: 8.0,    // ms (Compute)
    speedup: 5.6
  }
];

// Render Bundles für maximale Performance
async function createRenderBundle(device: GPUDevice, pipeline: GPURenderPipeline) {
  const encoder = device.createRenderBundleEncoder({
    colorFormats: ['bgra8unorm']
  });

  encoder.setPipeline(pipeline);

  // Pre-record alle Draw Calls
  for (let i = 0; i < 1000; i++) {
    encoder.draw(3);
  }

  return encoder.finish();
}
```

---

## Feature Detection & Fallback

```typescript
// lib/gpu-detection.ts

interface GPUCapabilities {
  webgpu: boolean;
  webgl2: boolean;
  webgl: boolean;
  computeShaders: boolean;
  maxTextureSize: number;
}

async function detectGPUCapabilities(): Promise<GPUCapabilities> {
  const capabilities: GPUCapabilities = {
    webgpu: false,
    webgl2: false,
    webgl: false,
    computeShaders: false,
    maxTextureSize: 0
  };

  // WebGPU Check
  if ('gpu' in navigator) {
    try {
      const adapter = await navigator.gpu.requestAdapter();
      if (adapter) {
        capabilities.webgpu = true;
        capabilities.computeShaders = true;

        const limits = adapter.limits;
        capabilities.maxTextureSize = limits.maxTextureDimension2D;
      }
    } catch {
      // WebGPU not available
    }
  }

  // WebGL2 Check
  const canvas = document.createElement('canvas');
  const gl2 = canvas.getContext('webgl2');
  if (gl2) {
    capabilities.webgl2 = true;
    capabilities.maxTextureSize = Math.max(
      capabilities.maxTextureSize,
      gl2.getParameter(gl2.MAX_TEXTURE_SIZE)
    );
  }

  // WebGL Check
  const gl = canvas.getContext('webgl');
  if (gl) {
    capabilities.webgl = true;
  }

  return capabilities;
}

// Adaptive Rendering
async function createRenderer(canvas: HTMLCanvasElement) {
  const caps = await detectGPUCapabilities();

  if (caps.webgpu) {
    console.log('Using WebGPU renderer');
    return createWebGPURenderer(canvas);
  }

  if (caps.webgl2) {
    console.log('Using WebGL2 renderer');
    return createWebGL2Renderer(canvas);
  }

  if (caps.webgl) {
    console.log('Using WebGL renderer (limited features)');
    return createWebGLRenderer(canvas);
  }

  throw new Error('No GPU rendering available');
}
```

---

## Fazit

WebGPU bietet:

1. **10x Performance**: Render Bundles, weniger Overhead
2. **Compute Shaders**: GPU für Berechnungen nutzen
3. **Moderne API**: Basiert auf Vulkan/Metal/D3D12
4. **Browser Support**: Alle Major Browser (2025/2026)

Die Zukunft der Browser-Grafik ist WebGPU.

---

## Bildprompts

1. "WebGPU particle simulation with 100k particles, compute shader visualization"
2. "Performance comparison chart WebGL vs WebGPU, bar graph"
3. "Modern GPU architecture diagram, WebGPU pipeline stages"

---

## Quellen

- [WebGPU MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API)
- [WebGPU Supported in All Browsers](https://web.dev/blog/webgpu-supported-major-browsers)
- [Three.js WebGPU Roadmap](https://threejsroadmap.com/blog/webgl-vs-webgpu-explained)
- [Chrome WebGPU Blog](https://developer.chrome.com/blog/webgpu-io2023)
