Before a single pixel exists, every frame begins with a stampede of geometry: a modern game pushes millions of vertices through the GPU in a few milliseconds. The geometry front end is the run of hardware that receives that stampede — fetching vertices from memory, dispatching their shading, then clipping, culling and measuring each triangle — and its one goal is to hand the rasterizer a tidy stream of screen-space triangles with their maths precomputed. Everything here is about doing the least work possible: shade each vertex once (not six times), and throw away every triangle you can before anyone rasterizes it.
A mesh arrives as two buffers: a vertex buffer (the actual positions, normals,
UVs) and an index buffer (triangles described as triples of indices into it). The
indices are the efficiency machine. In a typical grid-like mesh, each vertex is shared by around
six triangles — so naively shading three vertices per triangle would run the
vertex shader six times on the same data. The input assembler's fix is a small
post-transform vertex cache: when a triangle references index 4217, the hardware
first checks whether vertex 4217 was shaded recently; on a hit it reuses the stored result and the
vertex shader never runs. With cache-friendly index order, a mesh of
The shading itself is not fixed-function at all: the assembler bundles un-cached vertices into
warps and dispatches them to the SM pool (as
Shaded vertices return from the SMs in
The front end's last act is primitive setup: for each surviving triangle it
precomputes exactly the numbers the rasterizer will consume millions of times — the three
edge-equation coefficients
And it has a price: setup costs the same whether the triangle covers ten thousand pixels or one. As artists push geometric density toward pixel-sized triangles, per-triangle overhead stops being noise and becomes the bill — the "small-triangle problem", and the one-line motivation for the modern mesh-shader pipelines that batch tiny triangles more cleverly.
Step through one tiny frame's worth of front-end work: two triangles arrive, one leaves — clipped, measured and packaged for the rasterizer.
Here is the front end's bookkeeping in miniature: a small indexed grid mesh runs through backface culling and the vertex cache, and the counters show why both circuits exist. Try flipping some winding orders or shrinking the cache-free path in your head first — then run it.
Twelve vertices serve over thirty vertex-shader slots — the cache converts sharing in the mesh into shading you never pay for. On a real million-vertex mesh the same two counters are the difference between a frame that fits its budget and one that does not.
Setup builds a fixed-size packet per triangle, and the rasterizer stamps out pixels in parallel blocks — machinery that shines when a triangle covers hundreds of pixels. Film-quality assets invert the ratio: a statue scanned at sub-millimetre detail can average less than one pixel per triangle. Now the per-triangle cost (fetch, cache lookup, cull test, setup) dominates, the wide parallel pixel hardware stamps mostly-empty blocks, and effective throughput collapses — some hardware loses an order of magnitude of fill efficiency on pixel-sized triangles. That is why the newest pipelines add mesh shaders (compute-style shaders that cull and emit small batches of triangles wholesale) and why engines like Nanite rasterize their tiniest triangles in software on the SMs — when triangles shrink to pixels, the specialised hardware's assumptions dissolve, and the pendulum swings back toward programmability.
It feels obvious that the GPU should skip shading for triangles it will throw away. It cannot: facing is decided by the screen-space signed area, and screen positions are the vertex shader's output. The positions must exist before the determinant can be computed. So every back-facing triangle — typically half your mesh — pays the full vertex-shading bill and is then discarded. With a heavyweight vertex shader (skinning, morph targets, elaborate animation), that is real money burned on invisible geometry. This is exactly why engines cull coarsely and early on the CPU or in a compute pre-pass — frustum-testing whole objects, occlusion-testing clusters — so the hardware front end only ever sees geometry with a fighting chance of being drawn. The hardware cull is the last line of defence, not the plan.