WebGL vs WebGPU Compute Shaders Architecture

This article examines the core architectural differences between traditional graphics-bound shaders in WebGL and modern compute shaders in WebGPU. While WebGL forces general-purpose computing through the constraints of the rasterization pipeline, WebGPU introduces a dedicated compute pipeline designed for parallel data processing. Below is a direct comparison of their execution models, memory hierarchies, dispatch mechanisms, and synchronization capabilities.

Pipeline Coupling and Execution Model

WebGL is built on top of OpenGL ES, meaning all programmable operations must flow through a rigid graphics pipeline. To run non-graphical calculations in WebGL (GPGPU), developers must encode data into textures, bind them as inputs, render a full-screen quad, and use fragment shaders to write the results to a Framebuffer Object (FBO). This model introduces unnecessary overhead from the rasterizer, depth testing, and primitive assembly stages.

WebGPU decouples computation from rendering entirely. It provides a distinct GPUComputePipeline that operates independently of screen coordinates, triangles, or framebuffers. Compute shaders are written in WGSL (WebGPU Shading Language) and are invoked directly on raw memory buffers without touching the graphics pipeline.

Thread Dispatch and Workgroup Organization

WebGL fragment shaders process fragments (pixels) on an implicit grid determined by the viewport resolution and geometry coverage. Developers have no control over how individual shader invocations are scheduled, grouped, or mapped onto the GPU's hardware execution units (Streaming Multiprocessors or Compute Units).

WebGPU compute shaders utilize an explicit thread hierarchy:

  • Invocations: The smallest unit of execution, representing a single thread.
  • Workgroups: A 3D grid of invocations (defined via @workgroup_size(x, y, z) in WGSL) that run concurrently on the same compute unit.
  • Dispatch Grid: A 3D grid of workgroups dispatched via dispatchWorkgroups(x, y, z).

This layout gives developers direct control over data locality and parallel scaling, matching the physical compute hardware of modern desktop and mobile GPUs.

Memory Hierarchy and Data Access

In WebGL, memory access is strictly asymmetrical:

  • Shaders can read from 2D/3D textures and uniform arrays.
  • Shaders can only write by outputting values to assigned render targets (draw buffers).
  • Threads cannot share data with neighboring threads during execution; inter-thread communication requires completing a draw call and reading the resulting texture in a subsequent pass.

WebGPU provides a multi-tiered memory model:

  • Storage Buffers: Structured, arbitrary-sized memory buffers that can be both read and written directly by compute invocations using standard pointers and array indices.
  • Workgroup Shared Memory: A fast, on-chip memory space (var<workgroup>) shared exclusively among all invocations within a single workgroup. This acts like software-managed L1 cache, allowing threads to collaborate on shared data tiles without round-tripping to global VRAM.

Synchronization and Atomic Operations

WebGL does not support inter-invocation synchronization or atomic operations. Race conditions cannot be avoided natively, which makes operations like histogram generation, parallel prefix sums, or custom sorting algorithms either inefficient or impossible in a single pass.

WebGPU compute shaders support:

  • Barrier Synchronization: Functions like workgroupBarrier() and storageBarrier() ensure all threads in a workgroup reach the same execution point and all memory writes are committed before proceeding.
  • Atomic Primitives: Native atomic types (atomic<u32>, atomic<i32>) and atomic operations (atomicAdd, atomicExchange, atomicCompareExchangeWeak) allow threads to safely update global and shared memory without race conditions.

Architectural Summary

Feature WebGL (Fragment GPGPU) WebGPU Compute Shaders
Pipeline Target Graphics (Vertex/Fragment) Dedicated Compute Pipeline
Primary Data Primitive Textures and Framebuffers Raw Buffers and Storage Textures
Execution Topology Fixed to 2D viewports / render targets User-defined 3D workgroups and grids
Inter-Thread Sharing None (requires a new render pass) Workgroup shared memory
Synchronization None within a pass Workgroup barriers and memory barriers
Atomics Unsupported Supported on storage and workgroup memory