Skip to content

WebGL - Graphics Pipeline

The WebGL graphics pipeline (or rendering pipeline) is the sequence of steps WebGL takes to transform your 3D scene description (vertices, shaders, textures) into the 2D image displayed on your canvas. Understanding this process helps in optimizing performance and debugging rendering issues.

The pipeline involves stages executed on the CPU (via JavaScript) and stages executed on the GPU (fixed-function hardware and programmable shaders). Data flows from your application code, through the pipeline, ultimately resulting in pixels in the framebuffer.

  • Data Preparation: Define vertex coordinates, colors, texture coordinates, indices using JavaScript Typed Arrays.
  • Resource Allocation: Create WebGL resources like buffers (gl.createBuffer), textures (gl.createTexture), shader programs (gl.createProgram).
  • Data Transfer: Upload data from JavaScript Typed Arrays to GPU buffers (gl.bufferData) and textures (gl.texImage2D).
  • Shader Compilation/Linking: Compile GLSL shader code (gl.compileShader) and link into a program (gl.linkProgram).
  • State Configuration: Set various WebGL states (viewport, clear color, depth test, blend functions, active texture unit).
  • Attribute/Uniform Setup: Configure how vertex attributes read data from buffers (gl.vertexAttribPointer, gl.enableVertexAttribArray) and set uniform values (gl.uniform*).
  • Issuing Draw Calls: Instruct the GPU to render using gl.drawArrays or gl.drawElements.

Based on the draw call (drawArrays or drawElements) and the attribute configurations (vertexAttribPointer), the GPU fetches the required vertex data from the bound VBOs (and IBO if using drawElements).

  • Receives vertex attributes (position, color, etc.) and uniforms.
  • Performs calculations like transformations (Model-View-Projection), lighting calculations per vertex, texture coordinate generation.
  • Must output the final vertex position in Homogeneous Clip Space coordinates to the built-in gl_Position variable.
  • Can pass interpolated data (like color, texture coords) to the fragment shader via varying variables.

4. Primitive Assembly (GPU - Fixed Function)

Section titled “4. Primitive Assembly (GPU - Fixed Function)”

The transformed vertices are assembled into geometric primitives (points, lines, triangles) according to the mode specified in the draw call and the vertex order/indices.

  • Clipping: Discarding parts of primitives outside the [-1, +1] clip space volume.
  • Perspective Divide: Dividing clip space coordinates (x, y, z) by w to get Normalized Device Coordinates (NDC).
  • Viewport Transform: Mapping NDC coordinates to window (pixel) coordinates based on gl.viewport.
  • Culling: Optionally discarding front-facing or back-facing triangles (gl.enable(gl.CULL_FACE)).
  • Interpolation: Calculating the values of varying variables for each pixel (‘fragment’) inside the primitive by smoothly blending the values from the primitive’s vertices.
  • Receives interpolated varying values from the vertex shader.
  • Receives uniforms.
  • Performs operations like texture sampling (texture2D), per-pixel lighting calculations, fog effects.
  • Must output the final RGBA color of the fragment to the built-in gl_FragColor variable (in WebGL 1).

7. Per-Fragment Operations (GPU - Fixed Function)

Section titled “7. Per-Fragment Operations (GPU - Fixed Function)”
  • Pixel Ownership Test: (Internal) Determines if the pixel belongs to the WebGL context.
  • Scissor Test: Discards fragments outside a defined rectangle (gl.scissor).
  • Stencil Test: Compares/modifies values in the stencil buffer (gl.stencilFunc, gl.stencilOp).
  • Depth Test: Compares the fragment’s depth with the depth buffer (gl.depthFunc). Discards hidden fragments.
  • Blending: Combines the fragment’s color with the color buffer (gl.blendFunc).
  • Dithering: (Optional) Simulates more colors.

If a fragment passes all enabled tests, its color, depth, and stencil values are written to the corresponding buffers in the framebuffer.

The final destination holding the rendered image (color buffer) and associated depth/stencil information. By default, this is the buffer associated with the HTML canvas element, which is then displayed by the browser.

  • CPU Role: Setup, data preparation, state management, initiating draws.
  • GPU Role: Massively parallel execution of vertex/fragment shaders, fixed-function geometry processing and testing.
  • Programmable Stages: Vertex Shader and Fragment Shader give developers control.
  • Data Flow: Data moves from JS -> Buffers -> Vertex Shader -> Rasterizer -> Fragment Shader -> Framebuffer.
  • Performance: Minimize CPU-GPU communication (use buffers), optimize shaders, leverage fixed-function tests (like depth test) efficiently.