Dual-Eye Rendering with GL_EXT_multiview in GLSL

Rendering stereoscopic scenes for virtual and augmented reality requires presenting slightly offset perspectives for each eye, a process that traditionally doubles CPU draw calls and state changes. The GL_EXT_multiview OpenGL extension solves this bottleneck by allowing a single draw call to dispatch geometry simultaneously to multiple render targets. By integrating with GLSL through dedicated built-in variables and layout qualifiers, this extension shifts the burden of multi-perspective duplication to the GPU hardware, streamlining the stereoscopic rendering pipeline and significantly lowering latency and CPU overhead.

The Problem with Traditional Dual-Eye Rendering

Conventional VR pipelines render a scene by executing two full rendering passes: one for the left eye and one for the right eye. This approach forces the CPU to prepare, record, and dispatch commands twice for every mesh, doubling uniform updates and driver validation overhead. While instanced rendering can batch these operations, it still incurs per-instance processing costs and can introduce pipeline synchronization delays.

How GL_EXT_multiview Solves the Overhead

GL_EXT_multiview enables the GPU to draw primitives to multiple layers of a 2D texture array simultaneously within a single draw call. Instead of binding separate framebuffers or dispatching separate passes, the application binds a multiview framebuffer with two layers. The graphics pipeline then broadcasts the geometry to both eye targets, duplicating the work at the hardware level where view-dependent differences occur.

Integration in GLSL

The extension exposes key mechanisms directly in GLSL shaders, primarily within the vertex shader:

  1. View Count Declaration: Shaders declare the number of simultaneous views using an input layout qualifier. For stereo rendering, this is set to two views:

    #extension GL_EXT_multiview : enable
    layout(num_views = 2) in;
  2. The gl_ViewID_OVR Input: The driver injects an internal integer variable, gl_ViewID_OVR, which specifies the target view currently being processed (typically 0 for the left eye and 1 for the right eye).

  3. Per-View Transformations: Rather than relying on a single Model-View-Projection (MVP) matrix, the shader defines an array of matrices for the respective views:

    uniform mat4 u_ViewProjection[2];
    
    void main() {
        mat4 mvp = u_ViewProjection[gl_ViewID_OVR] * u_Model;
        gl_Position = mvp * vec4(a_Position, 1.0);
    }

Hardware Execution and Optimization

When GL_EXT_multiview is active, the GPU processes the view separation intelligently:

  • Single Pipeline Setup: Primitives are submitted once. View-invariant operations (such as skinning, physics, or early object-space transforms) can be computed once, while only the projection and view transforms are evaluated per gl_ViewID_OVR.
  • Hardware Geometry Routing: Modern GPUs route the resulting primitives to the corresponding layer of the render target array based on the view index. Fixed-function hardware handles viewport transformations, scissoring, and primitive clipping independently per view.
  • Tile-Based Deferred Renderers (TBDR): On mobile VR architectures, multiview allows binning and tiling steps to occur once for both views, conserving memory bandwidth and avoiding redundant rasterizer state setup.

By eliminating redundant API commands on the CPU and parallelizing stereoscopic projection on the GPU, GL_EXT_multiview serves as a fundamental building block for low-latency, high-frame-rate rendering in modern GLSL pipelines.