# 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( 0.0, 0.5), // Top vec2f(-0.5, -0.5), // Bottom Left vec2f( 0.5, -0.5) // Bottom Right ); var colors = array( 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 particles: array; @group(0) @binding(1) var 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>, 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 ( { // WebGPU Renderer wird automatisch verwendet wenn verfügbar // Fallback auf WebGL return undefined; }} frameloop="demand" > ); } // Feature Detection export function useWebGPUSupport() { const [supported, setSupported] = useState(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 { 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)