M5 — Pipeline & Patterns: Universal Rendering Pipeline, Programming Models, Tooling, and Cross-API Terminology
This module synthesises the four API modules (M1 OpenGL®, M2 GLSL, M3 WebGL™, M4 Vulkan®) into a single mental model. All four APIs implement the same underlying rendering pipeline — what differs is how stages are configured, how state is managed, and how work is submitted to the GPU. The sections below establish the canonical pipeline diagram (CF-10), contrast the two dominant programming models (CF-11), catalogue the tooling surface (CF-16), and provide a cross-API terminology map that enforces IN-05 (“fragment shader”, never “pixel shader”) across the module set.
Section 1 — The Universal Rendering Pipeline
The Khronos OpenGL Wiki “Rendering Pipeline Overview” article enumerates the canonical stage sequence that OpenGL, WebGL, and Vulkan all implement [Khronos OGL Wiki — Rendering Pipeline Overview — khronos.org/opengl/wiki/Rendering_Pipeline_Overview]. Tessellation and geometry stages are optional; every other stage is present in every conformant implementation.
CPU GPU PIPELINE
=== ============
Application [ Vertex Specification ] (VAOs, VBOs, attribute layout)
Vertex data ---> [ Vertex Buffers ]
(attributes, indices) |
v
[ Vertex Shader ] <-- GLSL/SPIR-V, required
|
v
[ Tessellation Control ] (opt — GL 4.0+ / Vulkan)
|
v
[ Tessellation Eval. ] (opt — GL 4.0+ / Vulkan)
|
v
[ Geometry Shader ] (opt — GL 3.2+ / Vulkan)
|
v
[ Vertex Post-Processing ] (fixed-function)
| - Clipping against view frustum
| - Perspective divide (clip -> NDC)
| - Viewport transform (NDC -> window)
| - Face culling (front/back)
|
v
[ Primitive Assembly ] (fixed — group vertices into primitives)
|
v
[ Rasterization ] (fixed — primitives -> fragments)
|
v
[ Fragment Shader ] <-- GLSL/SPIR-V, required for colour output
|
v
[ Per-Sample Operations] (fixed-function, configurable)
| - Scissor test
| - Depth test
| - Stencil test
| - Blending
|
v
FRAMEBUFFER (colour, depth, stencil attachments)
The diagram above is authoritative across OpenGL (M1), WebGL (M3),
and Vulkan (M4); GLSL (M2) populates the programmable stages shown in
the diagram. Compute shader dispatches (GL 4.3+ / GLSL 4.30+ / Vulkan
1.0+) run outside this graphics pipeline — launched via
glDispatchCompute in OpenGL or vkCmdDispatch
in Vulkan — but share the same shader-programming model and
resource-binding primitives [Khronos OGL Wiki — Shader —
khronos.org/opengl/wiki/Shader], [Vulkan 1.4 specification —
registry.khronos.org/vulkan/specs/latest/html/vkspec.html].
Section 2 — Stage-by-Stage Detail
The following subsections cover every stage in the canonical pipeline. Each lists role, inputs, outputs, OpenGL and Vulkan naming where they differ, and whether the stage is optional or required.
2.1 Vertex Specification
- Role. The application sets up an ordered list of vertices with attribute data. Each attribute is a small set of data (position, normal, texture coordinate, colour, etc.) that downstream stages consume [Khronos OGL Wiki — Rendering Pipeline Overview].
- Inputs. Vertex Array Object (VAO), one or more
Vertex Buffer Objects (VBOs), optional Index Buffer Object (IBO /
Element Buffer Object — EBO) for indexed drawing. In Vulkan, the
analogue is the
VkBufferbound viavkCmdBindVertexBufferstogether with the vertex input state recorded in the pipeline object. - Outputs. A stream of per-vertex attribute records delivered to the vertex shader.
- OpenGL / Vulkan naming. OpenGL uses VAO + VBO;
Vulkan uses vertex input state objects and
VkBufferobjects bound through the command buffer. - Required in every draw call.
2.2 Vertex Shader
- Role. Runs once per vertex; transforms per-vertex attributes into clip-space coordinates [Khronos OGL Wiki — Shader].
- Inputs. Vertex attributes declared with the GLSL
inqualifier (bylayout(location = N)); built-insgl_VertexID,gl_InstanceID. - Outputs.
gl_Position(clip-space position,vec4) plus user-definedoutvariables. - OpenGL / Vulkan naming. Identical: “vertex shader” in both APIs. In Vulkan, the shader module is loaded as SPIR-V (Standard Portable Intermediate Representation — Version 5) rather than as GLSL source [Vulkan 1.4 specification §10].
- Required in every rendering program.
2.3 Tessellation Control Shader
- Role. Runs once per output control point of a tessellation patch; sets the tessellation levels that drive the fixed-function tessellator [Khronos OGL Wiki — Shader].
- Inputs. Per-vertex outputs of the vertex shader,
indexed by
gl_InvocationIDthroughgl_in[]. - Outputs.
gl_out[](per-control-point data) plusgl_TessLevelOuter[4]andgl_TessLevelInner[2]. - OpenGL / Vulkan naming. OpenGL and GLSL call it the
tessellation control shader; Vulkan SPIR-V uses the
execution model
TessellationControl. Direct3D terminology (“hull shader”) is out of scope for this module set. - Optional; must be paired with a tessellation evaluation shader when used. Introduced in OpenGL 4.0 (2010) and GLSL 4.00.
2.4 Tessellation Evaluation Shader
- Role. Runs once per tessellated vertex produced by the fixed-function tessellator; computes the final position of each new vertex by interpolating across the patch [Khronos OGL Wiki — Shader].
- Inputs. Control-point outputs from the tessellation
control shader;
gl_TessCoord. - Outputs.
gl_Positionand user-definedoutvariables. - OpenGL / Vulkan naming. OpenGL and GLSL:
tessellation evaluation shader. Vulkan SPIR-V execution model:
TessellationEvaluation. (Direct3D calls the equivalent stage the “domain shader.”) - Optional; can be used without a tessellation
control shader if default levels are set via
glPatchParameterfv.
2.5 Geometry Shader
- Role. Receives complete assembled primitives after vertex and tessellation processing; may emit zero or more primitives, potentially of a different primitive type.
- Inputs.
gl_in[]array for the input primitive;gl_PrimitiveIDIn. - Outputs. Emitted via
EmitVertex()andEndPrimitive(); output primitive type declared withlayout(triangle_strip, max_vertices = N) out;. - OpenGL / Vulkan naming. Identical in both APIs. Introduced in OpenGL 3.2 (2009) and GLSL 1.50.
- Optional. Carries significant performance overhead on many GPU architectures, so most modern engines avoid it in favour of compute-based alternatives. See M5 “Programming Models” section below and see [M1 §3.6] for the retained-mode pipeline this stage plugs into.
2.6 Vertex Post-Processing
- Role. Fixed-function pipeline sub-stages that transform clip-space vertex positions into rasterisation-ready window-space vertices [Khronos OGL Wiki — Rendering Pipeline Overview].
- Sub-stages. Clipping against the view-frustum boundaries; perspective divide (clip-space to Normalised Device Coordinates — NDC); viewport transform (NDC to window-space pixel coordinates); face culling (front-face / back-face discard).
- OpenGL / Vulkan naming. OpenGL groups these under
“vertex post-processing”; the Vulkan specification treats them as
individual fixed-function stages configured via
VkPipelineRasterizationStateCreateInfoand related structures. - Required and fixed-function in both APIs.
2.7 Primitive Assembly
- Role. Groups output vertices into primitives (triangle, triangle strip, triangle fan, line, line strip, point) according to the draw-call’s primitive topology.
- OpenGL / Vulkan naming. Identical. Vulkan’s
VkPrimitiveTopologyenum is the primitive-type selector set on the pipeline. - Required and fixed-function.
2.8 Rasterization
- Role. Converts continuous primitives into discrete fragments — one fragment per pixel the primitive covers, or one per sample under multisample antialiasing (MSAA).
- OpenGL / Vulkan naming. Identical in both APIs.
- Required and fixed-function; configurable via polygon mode, multisample state, and depth-bias parameters.
2.9 Fragment Shader
- Role. Runs once per fragment generated by rasterization; computes per-fragment colour and optionally depth [Khronos OGL Wiki — Shader].
- Inputs. Interpolated outputs from the previous
stage; built-ins
gl_FragCoord,gl_FrontFacing,gl_PointCoord. - Outputs. One or more
out vec4colour outputs mapped vialayout(location = N); optionalgl_FragDepth. - OpenGL / Vulkan naming. Both APIs use fragment shader. Direct3D’s “pixel shader” is a semantically equivalent but distinct term; this module set never uses “pixel shader” when referring to OpenGL, GLSL, WebGL, or Vulkan (IN-05).
- Required for colour output; may be omitted in depth-only shadow-map or pre-z passes.
2.10 Per-Sample Operations
- Role. Fixed-function, per-sample tests and blending that decide whether each fragment reaches the framebuffer and how it is combined with existing framebuffer contents [Khronos OGL Wiki — Rendering Pipeline Overview].
- Sub-stages. Scissor test, stencil test, depth test, blending (source / destination factors and blend equation), optional logical operations, and sRGB conversion.
- OpenGL / Vulkan naming. OpenGL configures these
with state-setting calls (
glEnable(GL_DEPTH_TEST),glBlendFunc, etc.); Vulkan bakes them into the pipeline state object viaVkPipelineDepthStencilStateCreateInfoandVkPipelineColorBlendStateCreateInfo. - Required and configurable in both APIs.
2.11 Framebuffer Write
- Role. Terminal stage: surviving fragments are written to the colour, depth, and stencil attachments of the bound framebuffer.
- OpenGL / Vulkan naming. OpenGL uses
glBindFramebufferwith a Framebuffer Object (FBO). Vulkan uses either a traditionalVkFramebuffer+VkRenderPasspair or — since Vulkan 1.3 — inline dynamic rendering viavkCmdBeginRenderingspecifying attachments directly in the command buffer [Vulkan 1.4 specification §10]. - Required.
Section 3 — Two Programming Models
OpenGL (including its WebGL embedding) and Vulkan occupy opposite ends of a design spectrum. OpenGL is a state machine with implicit synchronisation managed by the driver; Vulkan is a pipeline-state-object API with explicit, application-managed synchronisation and memory. The table below contrasts them across the dimensions most relevant to everyday application development [OpenGL 4.6 core profile specification — registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf], [Vulkan 1.4 specification — registry.khronos.org/vulkan/specs/latest/html/vkspec.html].
| Concern | OpenGL / WebGL | Vulkan |
|---|---|---|
| State management | Global state machine; glEnable/glDisable,
bound objects, current program all carried implicitly. Draw call
inherits current state. |
Immutable pipeline state objects (VkPipeline). All
shader, vertex-input, rasterizer, depth-stencil, and blend state baked
into the pipeline at creation time. |
| Command submission | Immediate-style retained-mode calls (glDrawArrays,
glDrawElements, gl.drawArraysInstanced in
WebGL). The driver queues work on a single context per thread. |
Work is recorded into VkCommandBuffer objects, then
submitted in batches via vkQueueSubmit. Multiple threads
may record independent command buffers simultaneously. |
| Synchronisation | Implicit — the driver inserts barriers between draw calls as needed.
The glMemoryBarrier call is required only for compute /
image load-store. |
Explicit — application declares pipeline barriers
(vkCmdPipelineBarrier), fences (VkFence for
CPU-GPU), and semaphores (VkSemaphore for GPU-GPU,
including timeline semaphores in 1.2+). |
| Shader compilation | GLSL source passed to the driver at runtime via
glShaderSource + glCompileShader +
glLinkProgram. OpenGL 4.6 adds optional SPIR-V ingestion
via glShaderBinary. |
SPIR-V binary only. Shaders are pre-compiled offline (typically with
glslang) and loaded with vkCreateShaderModule.
No GLSL front-end in the driver. |
| Memory allocation | Driver-managed. glBufferData and
glTexImage2D allocate and own GPU memory transparently.
Applications do not select heaps or alignment. |
Application-managed. VkDeviceMemory is allocated
explicitly from a chosen memory heap; VkBuffer and
VkImage objects are bound to sub-ranges. Sub-allocation via
the Vulkan Memory Allocator (VMA) is standard practice
[docs.vulkan.org]. |
| Validation / error reporting | Driver validates every draw call at runtime in production builds;
errors retrieved via glGetError or the
ARB_debug_output callback (core in GL 4.3). |
Zero per-call validation in production; correctness checking is done
by the Khronos validation layer during development only, via
VK_EXT_debug_utils callbacks [Khronos validation layer —
vulkan.lunarg.com]. |
| Threading | Single context per thread; context switching is expensive. WebGL inherits this constraint. | Multi-threaded command recording is a first-class design goal. Command pools are per-thread; queue submits serialise across threads. |
| Typical minimal-triangle code size | ~100 lines (WebGL), ~150 lines (OpenGL core profile). | ~1,000 lines to reach first-triangle with explicit instance, device, swapchain, render pass, pipeline, and command-buffer setup. |
Two structural consequences follow. First, Vulkan trades code volume for CPU scalability: the ARM Developer Community benchmark (October 2016) measured 1,270 J (OpenGL ES) versus 1,123 J (Vulkan) for the same rendered output on a Mali GPU — roughly an 11.6% reduction in total system energy, with ARM citing “an overall system power saving of around 15%” when CPU frequency reduction is included [ARM Developer Community — developer.arm.com]. Second, the validation-layer model inverts OpenGL’s driver-centric error handling: bugs in Vulkan applications surface during development through rich validation messages, and the production driver executes without any per-call safety checks [Vulkan validation layer — vulkan.lunarg.com].
Section 4 — Tooling by API
The following table covers the tools referenced by M1-M4 plus the two additions that the mission schema requires explicitly (CF-16). Every row names a real tool with a real source URL — no placeholder names.
| Tool | APIs supported | Role | Source |
|---|---|---|---|
| RenderDoc | OpenGL, OpenGL ES, WebGL (via browser embed), Vulkan, Direct3D 11/12, Metal | Open-source, stand-alone graphics frame debugger; captures full frames with per-drawcall state inspection and deterministic replay | renderdoc.org |
| NVIDIA Nsight Graphics | Vulkan, Direct3D 11/12, OpenGL (legacy) | Vendor GPU profiler / debugger on NVIDIA hardware; surfaces shader occupancy, memory bandwidth, pipeline utilisation metrics | developer.nvidia.com/nsight-graphics |
| AMD Radeon GPU Profiler (RGP) | Vulkan, Direct3D 12 | Vendor profiler on AMD hardware; shows hardware-level queue submission timelines and GPU front-end bottlenecks | gpuopen.com/rgp |
| Khronos validation layers (LunarG SDK) | Vulkan | Development-time runtime validator; catches parameter errors,
synchronisation hazards, pipeline layout mismatches, render-pass
coherence failures via the VK_EXT_debug_utils callback |
vulkan.lunarg.com/doc/view/latest/windows/khronos_validation_layer.html |
| SPIRV-Cross | SPIR-V to GLSL / HLSL / MSL / ESSL | Translates SPIR-V binary shader modules to target high-level shading languages; used internally by MoltenVK and by WebGPU back-ends for shader portability | github.com/KhronosGroup/SPIRV-Cross |
| glslang / glslangValidator | GLSL and GLSL ES input; SPIR-V output | Khronos reference compiler from GLSL to SPIR-V; the canonical front-end for the Vulkan shader toolchain and for OpenGL 4.6 SPIR-V ingestion | github.com/KhronosGroup/glslang |
| Spector.js | WebGL 1.0, WebGL 2.0 | Browser extension that captures and replays full WebGL frame recordings, showing draw-call state at issue time — the WebGL equivalent of RenderDoc | Chrome Web Store / Firefox Add-ons |
| ANGLE | OpenGL ES / WebGL source; Direct3D 9/11, OpenGL, Metal, Vulkan back-ends | Translation layer used by Chrome and Firefox as their WebGL back-end on Windows and macOS; shader translation through glslang + SPIRV-Cross | chromium.googlesource.com/angle/angle |
| MoltenVK | Vulkan source; Metal back-end | Vulkan-on-Metal translation layer for macOS/iOS; uses SPIRV-Cross to convert SPIR-V to Metal Shading Language (MSL) at pipeline-compile time | github.com/KhronosGroup/MoltenVK |
The Vulkan Documentation Project at docs.vulkan.org is
the canonical aggregator for the specification, the Vulkan Guide, and
the official tutorial [docs.vulkan.org]. For OpenGL, the Khronos OpenGL
Registry at registry.khronos.org/OpenGL/ hosts the core
specification, all extension definitions, and reference pages
[registry.khronos.org/OpenGL].
Section 5 — Cross-API Terminology Mapping
The table below unifies equivalent concepts across the four APIs in this module set. Row five is the load-bearing one for IN-05: all four APIs use fragment shader, never “pixel shader”. Row seven captures the fundamental programming-model split — OpenGL and WebGL have a shader program, Vulkan has a pipeline, and the two terms are not interchangeable.
| Concept | OpenGL | GLSL | WebGL | Vulkan |
|---|---|---|---|---|
| Shader source format | GLSL source (or SPIR-V binary in 4.6) | GLSL / GLSL ES source | GLSL ES source (via JS string) | SPIR-V binary only |
| Compiled shader unit | Shader object + program object | N/A (language-level) | WebGLShader + WebGLProgram | VkShaderModule (one per SPIR-V module) |
| Pipeline binding | Program object bound via glUseProgram |
N/A | gl.useProgram() |
VkPipeline bound via
vkCmdBindPipeline |
| Vertex attribute container | Vertex Buffer Object (VBO) | in qualifier in vertex shader |
WebGLBuffer (ARRAY_BUFFER target) |
VkBuffer bound via
vkCmdBindVertexBuffers |
| Per-fragment programmable stage | Fragment shader | Fragment shader | Fragment shader | Fragment shader |
| Uniform / constant data | Uniform variable or Uniform Buffer Object (UBO) | uniform qualifier, layout(std140)
blocks |
UBO in WebGL 2.0; per-uniform in WebGL 1.0 | VkDescriptorSet with uniform-buffer descriptors; push
constants for small payloads |
| Program / pipeline abstraction | Shader program (mutable, state-driven) | N/A | WebGLProgram | Pipeline (immutable VkPipeline) |
| Render target | Framebuffer (default framebuffer or FBO) | out variables in fragment shader |
WebGLFramebuffer | VkFramebuffer + VkRenderPass, or inline
dynamic rendering (1.3+) |
| Command submission unit | Individual draw call (glDrawArrays) |
N/A | Individual draw call (gl.drawArrays) |
Recorded command buffer submitted via
vkQueueSubmit |
| Synchronisation primitive | Implicit (driver inserts) + glFenceSync |
N/A | Implicit (driver inserts) | VkFence (CPU-GPU), VkSemaphore (GPU-GPU),
vkCmdPipelineBarrier (intra-queue) |
| Cross-API IR | Optional SPIR-V input (GL 4.6) | GLSL → SPIR-V via glslang | Not exposed | SPIR-V mandatory |
| Texture sampling handle | Sampler object + texture object | sampler2D / samplerCube uniform |
WebGLSampler + WebGLTexture | Combined or separate VkImageView +
VkSampler descriptors |
This terminology table is the primary enforcement mechanism for IN-05 and supports IN-04 (stage-name consistency) across M1-M4. Every reference to a programmable stage in this module set uses the name in the row-five header: vertex shader, tessellation control shader, tessellation evaluation shader, geometry shader, fragment shader, compute shader. The term “pixel shader” is reserved exclusively for HLSL / Direct3D contexts and does not appear in any of M1-M4 or elsewhere in M5.
Section 6 — Sources
- [standard] https://www.khronos.org/opengl/wiki/Rendering_Pipeline_Overview — Khronos OpenGL Wiki canonical pipeline stage enumeration
- [standard] https://www.khronos.org/opengl/wiki/Shader — Khronos OpenGL Wiki shader-stage reference
- [standard] https://registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf — OpenGL 4.6 core profile specification
- [standard] https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html — Vulkan 1.4 single-page HTML specification
- [standard] https://registry.khronos.org/SPIR-V/ — SPIR-V specification
- [standard] https://registry.khronos.org/OpenGL/ — OpenGL + GLSL registry (spec index)
- [standard] https://registry.khronos.org/vulkan/ — Vulkan specification registry
- [standard] https://github.com/KhronosGroup/glslang — glslang reference GLSL-to-SPIR-V compiler
- [standard] https://github.com/KhronosGroup/SPIRV-Cross — SPIR-V to GLSL/HLSL/MSL translator
- [professional] https://docs.vulkan.org/ — Vulkan Documentation Project (spec + guide + tutorial)
- [professional] https://renderdoc.org/ — RenderDoc graphics debugger (OpenGL, Vulkan, D3D)
- [professional] https://developer.nvidia.com/nsight-graphics — NVIDIA Nsight Graphics profiler
- [professional] https://gpuopen.com/rgp/ — AMD Radeon GPU Profiler
- [professional] https://vulkan.lunarg.com/doc/view/latest/windows/khronos_validation_layer.html — Khronos Vulkan validation layer
- [professional] https://chromium.googlesource.com/angle/angle/ — ANGLE translation layer
- [professional] https://github.com/KhronosGroup/MoltenVK — Vulkan-on-Metal translation layer
- [professional] https://developer.arm.com/community/arm-community-blogs/b/mobile-graphics-and-gaming-blog/posts/initial-comparison-of-vulkan-api-vs-opengl-es-api-on-arm — ARM Mali Vulkan vs OpenGL ES energy benchmark (1,270 J vs 1,123 J, ~15% system power saving)
- [encyclopedia] https://en.wikipedia.org/wiki/Rendering_pipeline — Rendering pipeline general reference
- [encyclopedia] https://en.wikipedia.org/wiki/Shader — Shader concept (vertex/fragment/geometry/compute)
Cross-references: M1 (OpenGL state machine maps to row “State management” in §3); M2 (GLSL stages populate the programmable boxes in §1 diagram; GLSL → SPIR-V toolchain is row “Shader compilation” in §3); M3 (WebGL state-machine model inherits from OpenGL ES 2.0 / 3.0 and appears in the OpenGL / WebGL column of §3 and §5); M4 (Vulkan pipeline state objects, command buffers, and explicit barriers populate the Vulkan column of §3 and §5).