Erste Schritte jenseits von WebGL
WebGPU ist die moderne Antwort des Webs auf direkte GPU-Programmierung und löst schrittweise WebGL als Standard für aufwendige Grafik- und Berechnungsaufgaben im Browser ab. Wer die Grundkonzepte einmal verstanden hat, dem eröffnet sich Zugriff auf Compute-Shader, effizientere Speicherverwaltung und eine deutlich modernere API.
Inhaltsverzeichnis
- 1. Warum WebGL an seine Grenzen stößt
- 2. Das GPUDevice als zentraler Einstiegspunkt
- 3. Command-Buffer und explizite Befehlserstellung
- 4. Shader in WGSL schreiben
- 5. Compute-Shader für Berechnungen jenseits von Grafik
- 6. Puffer, Bindgroups und explizite Speicherverwaltung
- 7. Wann sich der Umstieg von WebGL lohnt
- 8. Aktueller Stand des Browser-Supports
- 9. Ein minimales, vollständiges Dreieck
- 10. Zusammenfassung
- 11. FAQ
1. Warum WebGL an seine Grenzen stößt
WebGL basiert auf OpenGL ES, einer API, die für die Grafik-Hardware und Programmiermodelle des frühen 2010er-Jahrzehnts konzipiert wurde. Moderne GPUs arbeiten heute mit deutlich anderen Konzepten wie expliziten Command-Buffern, Pipeline-Objekten und paralleler Befehlserstellung, die WebGL nur umständlich oder gar nicht abbilden kann.
Das äußert sich in der Praxis als CPU-Overhead: WebGL-Aufrufe wie gl.drawArrays() lösen intern viel Validierungs- und Zustandsverwaltungs-Arbeit im Treiber aus, was bei komplexen Szenen mit vielen Draw-Calls zum Flaschenhals wird. WebGPU wurde von Grund auf für moderne Grafik-APIs wie Vulkan, Metal und Direct3D 12 konzipiert und übernimmt deren effizientere Grundprinzipien. Dazu zählt auch eine deutlich striktere Validierung zur Erstellungszeit von Pipelines und Ressourcen, statt Fehler erst mitten im Rendering an versteckter Stelle auszulösen, was Fehlersuche in komplexen Anwendungen spürbar erleichtert.
2. Das GPUDevice als zentraler Einstiegspunkt
Der Einstieg in WebGPU beginnt mit dem Anfordern eines GPUAdapter über navigator.gpu.requestAdapter(), der die verfügbare GPU-Hardware repräsentiert. Aus diesem Adapter lässt sich anschließend ein GPUDevice anfordern, die eigentliche Schnittstelle, über die sämtliche weiteren Operationen laufen. Sowohl Adapter- als auch Device-Anforderung erfolgen asynchron und können mit optionalen Feature- und Limit-Anforderungen parametrisiert werden, sodass eine Anwendung gezielt nur die Fähigkeiten anfragt, die sie tatsächlich benötigt.
Das Device kapselt Ressourcen wie Puffer, Texturen und Pipelines und stellt Queues bereit, über die Befehle an die GPU gesendet werden. Anders als bei WebGL, wo ein globaler Kontext implizit Zustand hält, ist bei WebGPU jede Ressource explizit erzeugt und referenziert, was Fehlerquellen reduziert und Optimierungen durch den Browser erleichtert.
async function initWebGPU() {
if (!navigator.gpu) {
throw new Error('WebGPU wird von diesem Browser nicht unterstützt');
}
const adapter = await navigator.gpu.requestAdapter();
if (!adapter) {
throw new Error('Kein geeigneter GPU-Adapter gefunden');
}
const device = await adapter.requestDevice();
const canvas = document.querySelector('#gpu-canvas');
const context = canvas.getContext('webgpu');
context.configure({
device,
format: navigator.gpu.getPreferredCanvasFormat(),
});
return { device, context };
}
3. Command-Buffer und explizite Befehlserstellung
Statt Befehle einzeln und sofort an die GPU zu senden, sammelt WebGPU sie in einem GPUCommandEncoder, der Zeichnen-, Compute- und Kopieroperationen aufzeichnet. Am Ende wird daraus ein GPUCommandBuffer erzeugt, der gebündelt über eine GPUQueue zur Ausführung eingereicht wird.
Dieses Modell erlaubt es der Anwendung, Befehle auf mehreren CPU-Threads parallel vorzubereiten, bevor sie gesammelt eingereicht werden, ein Muster, das aus nativer Grafikprogrammierung stammt und in WebGL schlicht nicht existierte. Für typische Web-Anwendungen bedeutet das vor allem: weniger CPU-Zeit pro Frame und mehr Vorhersagbarkeit bei komplexen Szenen. Selbst wenn eine konkrete Anwendung nicht aktiv mehrere Threads für die Befehlserstellung nutzt, profitiert sie allein durch das Batching-Prinzip von weniger einzelnen Treiber-Aufrufen pro Frame.
function renderFrame(device, context, pipeline) {
const encoder = device.createCommandEncoder();
const textureView = context.getCurrentTexture().createView();
const renderPass = encoder.beginRenderPass({
colorAttachments: [{
view: textureView,
clearValue: { r: 0.05, g: 0.05, b: 0.08, a: 1 },
loadOp: 'clear',
storeOp: 'store',
}],
});
renderPass.setPipeline(pipeline);
renderPass.draw(3);
renderPass.end();
device.queue.submit([encoder.finish()]);
}
4. Shader in WGSL schreiben
WebGPU nutzt mit WGSL, der WebGPU Shading Language, eine eigene, textbasierte Sprache für Vertex-, Fragment- und Compute-Shader, anstelle des von WebGL bekannten GLSL. WGSL wurde speziell für Sicherheit und einfache Übersetzung in die Shader-Sprachen der zugrunde liegenden nativen APIs entworfen, was Browsern hilft, konsistentes Verhalten über Plattformen hinweg zu garantieren.
Syntaktisch erinnert WGSL an eine Mischung aus Rust und C, mit expliziten Typannotationen und klar definierten Ein- und Ausgabestrukturen für jede Shader-Stufe. Wer bereits GLSL kennt, findet sich schnell zurecht, muss sich aber an die strengeren Typregeln und die explizite Struktur-Deklaration gewöhnen. Viele Tooling-Anbieter, darunter Editor-Erweiterungen für Syntax-Highlighting und Linting, unterstützen WGSL inzwischen ebenfalls, was den Einstieg gegenüber den Anfangstagen der Sprache spürbar erleichtert hat.
const shaderCode = `
@vertex
fn vs_main(@builtin(vertex_index) index: u32) -> @builtin(position) vec4f {
var positions = array<vec2f, 3>(
vec2f( 0.0, 0.5),
vec2f(-0.5, -0.5),
vec2f( 0.5, -0.5)
);
return vec4f(positions[index], 0.0, 1.0);
}
@fragment
fn fs_main() -> @location(0) vec4f {
return vec4f(0.2, 0.7, 1.0, 1.0);
}
`;
const shaderModule = device.createShaderModule({ code: shaderCode });
5. Compute-Shader für Berechnungen jenseits von Grafik
Neben klassischem Grafik-Rendering bietet WebGPU vollwertige Compute-Shader, mit denen sich beliebige parallele Berechnungen direkt auf der GPU ausführen lassen, etwa Physik-Simulationen, Bildverarbeitung oder sogar kleinere Machine-Learning-Inferenzen. WebGL kannte diese Fähigkeit praktisch nicht, Umwege über Texturen als Datenspeicher waren nötig.
Ein Compute-Shader wird ähnlich wie ein Grafik-Shader in WGSL geschrieben, arbeitet aber auf Work-Groups aus parallelen Threads, die über @compute @workgroup_size(...) deklariert werden. Ergebnisse landen in Storage-Buffern, die anschließend zurück zur CPU gelesen oder direkt für weiteres Rendering wiederverwendet werden können.
6. Puffer, Bindgroups und explizite Speicherverwaltung
Anders als bei WebGL, wo Uniforms und Attribute über implizite Locations angesprochen werden, verwaltet WebGPU Speicherressourcen über explizite GPUBuffer-Objekte und GPUBindGroup-Strukturen, die genau festlegen, welche Ressource an welcher Bindungsstelle im Shader verfügbar ist. Ein Buffer wird mit einer festen Größe und einem Nutzungsflag wie GPUBufferUsage.VERTEX oder GPUBufferUsage.STORAGE erzeugt, wodurch der Browser und letztlich der Treiber von Anfang an wissen, wie die Ressource optimal im Speicher platziert werden sollte.
Diese Explizitheit wirkt zunächst nach mehr Boilerplate-Code als das freizügigere WebGL-Modell, zahlt sich aber bei größeren Anwendungen aus: Bindgroups lassen sich vorab erstellen und zwischen Frames wiederverwenden, statt bei jedem Zeichenaufruf erneut Zustand zu setzen. Für Teams, die von WebGL kommen, ist dieser Schritt meist die größte gedankliche Umstellung, weil er verlangt, Ressourcen-Layout und Bindungs-Struktur schon beim Pipeline-Entwurf festzulegen, statt sie beiläufig zur Laufzeit zusammenzustecken.
7. Wann sich der Umstieg von WebGL lohnt
Für einfache 2D-Visualisierungen, kleine 3D-Szenen oder Projekte mit begrenztem Zeitbudget bleibt WebGL oft die pragmatischere Wahl, da die Toolchain reifer ist und deutlich mehr Bibliotheken, Tutorials und fertige Beispiele existieren. WebGPU lohnt sich vor allem dort, wo CPU-Overhead durch viele Draw-Calls zum echten Problem wird oder wo Compute-Shader gebraucht werden.
Auch Projekte, die stark auf GPU-basierte Physik, Partikel-Simulationen mit hunderttausenden Elementen oder eigene Rendering-Pipelines mit modernen Techniken wie Deferred Shading setzen, profitieren deutlich stärker von WebGPU als von WebGL. Die Entscheidung sollte an der tatsächlichen Flaschenhals-Analyse hängen, nicht an reiner Neugier auf die neue API. Ein pragmatischer Zwischenweg besteht darin, bestehende WebGL-Anwendungen zunächst unverändert zu lassen und WebGPU gezielt für einzelne, neue Feature-Bereiche einzusetzen, etwa eine neu hinzukommende Partikel-Simulation, während der Rest der Anwendung unangetastet bleibt.
8. Aktueller Stand des Browser-Supports
Chrome und Edge unterstützen WebGPU inzwischen standardmäßig auf Desktop und zunehmend auch auf Android, Firefox bietet Unterstützung hinter Flags beziehungsweise in aktuellen Versionen bereits stabil, Safari zieht mit eigenem Implementierungsfortschritt nach. Der Support wächst spürbar schneller als seinerzeit bei WebGL in dessen Anfangsjahren.
Für produktive Anwendungen empfiehlt sich weiterhin eine Feature-Detection über if ('gpu' in navigator) kombiniert mit einem WebGL-Fallback-Pfad, insbesondere wenn die Zielgruppe ältere Geräte oder Browser umfasst. Bibliotheken wie Three.js bieten inzwischen experimentelle WebGPU-Renderer neben ihrem etablierten WebGL-Renderer an. Auch auf mobilen Geräten ist Vorsicht angebracht: Selbst wenn ein GPUAdapter erfolgreich angefordert werden kann, unterscheiden sich Limits wie maximale Buffergröße oder Anzahl gleichzeitiger Bindgroups teils deutlich zwischen Desktop- und Mobil-GPUs, weshalb sich ein Blick in adapter.limits vor dem produktiven Einsatz lohnt.
9. Ein minimales, vollständiges Dreieck
Um die Konzepte greifbar zu machen, folgt hier ein vollständiges, wenn auch minimales Beispiel, das die zuvor beschriebenen Bausteine, Device, Shader-Modul, Render-Pipeline und Command-Buffer, zu einem lauffähigen Dreieck zusammensetzt. Dieses Muster ist der klassische Einstiegspunkt in praktisch jedem WebGPU-Tutorial und bildet die Grundlage für komplexere Szenen.
Die folgende Tabelle fasst die wichtigsten konzeptionellen Unterschiede zwischen WebGL und WebGPU zusammen und hilft bei der Einschätzung, welche API für ein konkretes Projekt die passendere Grundlage ist.
async function createTrianglePipeline(device, format) {
const module = device.createShaderModule({ code: shaderCode });
return device.createRenderPipeline({
layout: 'auto',
vertex: { module, entryPoint: 'vs_main' },
fragment: {
module,
entryPoint: 'fs_main',
targets: [{ format }],
},
primitive: { topology: 'triangle-list' },
});
}
const { device, context } = await initWebGPU();
const format = navigator.gpu.getPreferredCanvasFormat();
const pipeline = await createTrianglePipeline(device, format);
renderFrame(device, context, pipeline);
| Aspekt | WebGL | WebGPU | Auswirkung |
|---|---|---|---|
| Shader-Sprache | GLSL | WGSL | Andere Syntax, striktere Typisierung |
| Befehlsmodell | Sofortiger State-basierter Aufruf | Command-Buffer, gebündelte Einreichung | Weniger CPU-Overhead bei vielen Draw-Calls |
| Compute-Fähigkeit | Nicht vorgesehen, Workarounds über Texturen | Native Compute-Shader | Direkte GPU-Berechnungen ohne Umwege |
| Browser-Reife | Sehr breit, seit vielen Jahren stabil | Wachsend, Chrome/Edge/Firefox voran | WebGL bleibt sicherer Fallback |
Mironsoft
Moderne Browser-APIs, Performance und wartbares JavaScript
JavaScript, das im echten Browser robust bleibt, nicht nur im Tutorial?
Wir prüfen bestehenden Frontend-Code auf veraltete Patterns, unnötige Bibliotheken und Performance-Fallen und ersetzen sie durch moderne, native Browser-APIs, die weniger Bundle-Gewicht und weniger Wartungslast bedeuten.
Code-Review
Veraltete Patterns, unnötige Dependencies und Memory Leaks systematisch aufspüren.
Performance-Optimierung
Bundle-Größe, Ladezeit und Runtime-Performance mit modernen APIs verbessern.
Modernisierung
Native Browser-APIs statt schwerer Bibliotheken gezielt einführen.
10. Zusammenfassung
WebGPU: Das Wichtigste auf einen Blick
Einstieg
GPUAdapter anfordern, daraus GPUDevice erzeugen, zentraler Ausgangspunkt aller Operationen.
Befehle
Command-Encoder sammelt Operationen, gebündelte Einreichung über die Queue reduziert CPU-Overhead.
Shader
WGSL ersetzt GLSL, unterstützt sowohl Grafik- als auch Compute-Shader.
Entscheidung
Umstieg lohnt sich bei vielen Draw-Calls oder echtem Compute-Bedarf, sonst bleibt WebGL pragmatisch.