Optimizing glTF Indexed Draw Calls for GPU Cache
This article explores how the glTF (GL Transmission Format) specification structures indexed draw calls to maximize GPU post-transform and pre-transform cache efficiency. By understanding how glTF organizes accessors, buffer views, and topological indices, developers can implement state-of-the-art vertex ordering algorithms that minimize redundant vertex shading operations and maximize memory bandwidth during hardware rasterization.
The Anatomy of an Indexed Draw Call in glTF
In glTF, an indexed draw call is defined at the
mesh.primitive level. A primitive specifies an
indices property, which points to an accessor
referencing raw data in a bufferView. The vertex attributes
(such as POSITION, NORMAL, and
TEXCOORD_0) are maintained as separate or interleaved
accessors pointing to their respective attribute data.
When the GPU renders this primitive, it reads the index stream to assemble primitives (typically triangles). If an index refers to a vertex that has already been transformed and resides in the GPU’s internal cache, the hardware can skip execution of the vertex shader for that vertex, significantly increasing throughput.
Maximizing the Post-Transform Vertex Cache (FIFO/LRU)
The post-transform vertex cache stores the output of recently executed vertex shaders. Hardware implementations typically range from 16 to 64 entries operating under a First-In, First-Out (FIFO) or Least Recently Used (LRU) eviction policy.
To maximize hits in this cache, glTF files structure the index buffer using cache-aware reordering algorithms, such as Tom Forsyth's algorithm or the Tipsify algorithm:
- Triangle Locality: Triangles sharing vertices are grouped closely together in the index stream.
- Reuse Distance Minimization: The distance between consecutive occurrences of the same index is minimized to ensure the vertex remains in the cache before eviction.
- Average Transform-to-Vertex (ATVR) Metric: An unoptimized triangle mesh typically has an ATVR around 2.0 to 3.0. By structuring the glTF index accessor through cache optimization algorithms, the ATVR approaches the theoretical minimum of 0.5 to 0.7 for manifold triangle meshes.
Maximizing the Pre-Transform Vertex Cache and Memory Coherency
Once the index buffer is organized for the post-transform cache, the actual vertex attribute buffers must be organized for the pre-transform cache. The pre-transform cache is essentially the GPU's L1/L2 data cache handling vertex fetch memory bandwidth.
- Vertex Reordering: Vertices in the attribute
bufferVieware reordered so that their layout in linear memory matches the exact order of their first appearance in the optimized index buffer. - Sequential Streaming: When the GPU reads vertex data, memory is accessed sequentially rather than scattered randomly across the buffer. This ensures high cache line utilization (typically 64 or 128 bytes per line), preventing unneeded data from consuming memory bus bandwidth.
- Data Interleaving: In glTF, developers can
interleave vertex attributes inside a single
bufferViewusing thebyteStrideproperty. Interleaving places all attributes for a single vertex (e.g., Position, Normal, UV) in contiguous memory, ensuring a single memory fetch populates the GPU cache with all necessary data for that vertex.
Leveraging glTF Extensions for Cache Optimization
Standard glTF data can be prepared for optimal cache performance
during asset pipeline export using tools like
meshoptimizer. Furthermore, the glTF ecosystem provides
official extensions that preserve and enforce these cache-friendly
structures:
- EXT_meshopt_compression: This extension encodes index and vertex data specifically ordered for GPU caches. It compresses index sequences as topological edge runs and vertex attributes as quantized, delta-encoded streams. Upon decompression on the CPU or via compute shaders at runtime, the layout remains completely optimized for the target GPU cache architecture.
- KHR_mesh_quantization: By quantizing vertex data
(e.g., using
SHORTorBYTEaccessors instead of standardFLOAT), attribute memory footprints are reduced. Smaller vertex footprints allow more vertices to fit inside a single GPU cache line, directly amplifying the effectiveness of both pre-transform and post-transform caches.