How the GameCube drew worlds.
We start from the very beginning — what a digital picture even is — assuming you know nothing about computer graphics. Once the vocabulary is solid, we follow a frame through Nintendo's remarkable Flipper chip and out through Dolphin's emulator. Sixteen modules, each with live, software-rendered labs so you can drag, spin and break every idea, not just read it. No game artwork ships with this page; every image is drawn procedurally in your browser.
3D graphics fundamentals
Pixels, triangles, transforms, rasterisation, textures, lighting and the z-buffer — the universal vocabulary of real-time 3D, explained from zero.
The Flipper GPU
The chip, its command FIFO, hardware T&L, the 16-stage TEV combiner, texture compression and the embedded framebuffer.
Emulating in Dolphin
Turning fixed-function state into generated shaders, ubershaders vs stutter, and the settings that map to it all.
3D graphics fundamentals
This first part is pure fundamentals — nothing about any specific console or chip yet. It's the toolkit that every real-time renderer is built from, whether that's a phone, a modern PC GPU, or the chip we'll meet in Part II. We build the vocabulary one word at a time — pixel, vertex, transform, rasterise, texture, shade, depth-test — and you can drag and see each idea in a live lab. If a term is ever used before it's explained, that's a bug; tell us. Everything in Parts II and III is just these seven ideas wired together.
Pictures as pixels
Let's start with what a picture on a screen physically is. Lean in close to any display — a TV, a phone, the family CRT the GameCube was plugged into — and the image falls apart into a grid of tiny glowing dots. Each dot is a pixel (from “picture element”), and it can show exactly one colour at a time. Step back and your eye fuses the grid into a smooth image. That's all a digital picture is: a rectangular grid of single-colour dots.
To put a picture inside a computer, then, we just need a way to write
down one colour as numbers. The trick — and it's borrowed straight
from your own eyes, which sense colour with three kinds of cone cell —
is to describe every colour as a mix of red, green and
blue light. Three numbers, each usually from 0 (none) to 255
(full blast), and any colour on screen falls out:
(255, 0, 0) is pure red,
(255, 255, 255) is white,
(0, 0, 0) is black,
(255, 207, 59) is a warm yellow. This scheme is
called RGB,
and each of the three numbers is a channel.
Now string it together. One picture = a grid of pixels; one pixel = three numbers. So a whole picture is just a long, ordered list of numbers — three per pixel, row after row. The block of memory that holds that list for the image currently on screen has a name you'll hear constantly for the rest of this course: the framebuffer. Draw into the framebuffer, and you've drawn onto the screen.
A mosaic portrait is thousands of small single-colour tiles. Up close: coloured squares. Across the room: a face. A pixel grid is a mosaic whose tiles you can repaint sixty times a second — and the framebuffer is the numbered order sheet telling you which tile goes where. (If you've taken the sibling audio course, this should feel familiar: a framebuffer is to images exactly what a list of samples is to sound — the thing itself, as plain numbers.)
Two more words and the module's vocabulary is complete. The resolution is the size of the grid — how many pixels across and down. More pixels = finer detail = more memory: a 640 × 480 image at 3 bytes per pixel is about 900 KB, which is why resolution was precious on 2001-era hardware (you'll see the exact, surprisingly small numbers the GameCube worked with in Module 13). And a grid-of-pixels image is called a raster image — remember the word, because Module 04 is about rasterisation, the moment 3D shapes get turned into exactly this kind of grid.
Play with the idea below. The little landscape is repainted from scratch at whatever grid size you pick — drag the resolution from a chunky 8 × 8 up to 256 × 256 and watch detail appear as pixels shrink. Then switch off channels: with only R lit you're literally seeing one third of the framebuffer's numbers. Hover any pixel to read its three values.
- A digital image is a grid of pixels; each pixel is one colour, stored as three RGB numbers (0–255 per channel).
- The framebuffer is the memory holding those numbers for the on-screen image — draw into it and the screen changes.
- Resolution = the grid's size; more pixels means finer detail and more memory.
- A grid-of-pixels image is a raster image — the destination every 3D scene must eventually reach.
From 3D to triangles
Module 01 gave us the destination: a grid of coloured pixels. But a game world isn't stored as pixels — if it were, you could only ever look at it from one fixed angle, like a photograph. A 3D world is stored as geometry: shapes floating in space, which the machine re-draws from wherever the camera happens to be, sixty times a second.
The atom of that geometry is the vertex (plural
vertices): a single point in 3D space, written as three
coordinates (x, y, z) — how far right, how far up, how
far away. A vertex on its own is just a dot; the shape appears when
you join vertices up. Join two and you have an edge; join three and
you have the workhorse of all real-time graphics: the
triangle. A model built from many triangles sharing
their vertices — a character, a tree, Hyrule — is called a
mesh.
Why triangles, and not squares or pentagons or smooth curves? Three reasons, and they're all about being cheap and foolproof:
- A triangle is always flat. Three points define exactly one plane — you cannot bend a triangle. A four-cornered polygon can twist like a Pringle, and then “which way is it facing?” has no single answer. Triangles never have that problem.
- A triangle is unambiguous. Its three corners settle everything about it: its edges, its facing, and (as Module 04 will show) exactly which pixels it covers, with three simple tests.
- Triangles are universal. Any polygon can be diced into triangles, and any curved surface can be approximated by enough small ones. So the hardware only needs to be brilliant at one thing, done millions of times.
A disco ball looks round from across the room, but it's really hundreds of small flat mirrors. Every “curved” surface you've seen in a game is the same trick: flat triangles, small enough that your eye rounds them off. Use more, smaller mirrors and the ball looks rounder — at the cost of more work.
One more idea completes the picture. A vertex usually carries more than its position: it can also hold a colour of its own, a texture address (Module 05), and a little arrow describing which way the surface faces there (Module 06). These extras are the vertex's attributes, and they're the raw ingredients every later stage cooks with. When you meet the real hardware in Module 09 you'll find it has an entire sub-system just for fetching vertices and their attributes efficiently — on a console, even the shape of this data is a performance decision.
- 3D worlds are stored as geometry (redrawable from any angle), not pixels.
- A vertex is a point (x, y, z); a mesh is many triangles sharing vertices.
- Triangles win because they're always flat, unambiguous, and can approximate anything.
- Vertices carry attributes — colour, texture coordinates, a facing arrow — used by every later module.
Transforms & projection
We now have a mesh of vertices in 3D, and a screen that is a flat 2D
grid. This module is the bridge: how does a point (x, y, z)
end up at a particular pixel? The answer is a short chain of
coordinate hops — worth learning by name, because the hardware in
Module 10 is literally organised around them.
A mesh is modelled in its own private coordinates, with the origin somewhere convenient — between a character's feet, say. That's model space. To place the character in the level — walked to the bridge, turned to face east — every vertex is moved, rotated, maybe scaled, into the level's shared coordinates: world space. Then comes a sneaky, brilliant step: rather than move a camera through the world, we shift the entire world the opposite way, so the camera sits at the origin looking straight ahead. Those camera-relative coordinates are view space, and they make the final step almost embarrassingly easy.
Each of those hops is carried out by a matrix — don't flinch at the word. A matrix here is just a small table of numbers (4 × 4) that, multiplied against a vertex, applies a move-rotate-scale in one go. The magic property, and the only one you need: multiplying two matrices together fuses two steps into one. Model→world and world→view collapse into a single model-view matrix, so the machine does one multiplication per vertex instead of a parade of them. When Module 10 mentions the GPU's “matrix memory,” this table of numbers is what lives there.
Stand at a window, close one eye, and trace what you see onto the glass with a marker. You have just performed a perspective projection: every 3D point was collapsed along its line of sight onto a flat pane. Renaissance artists did exactly this with gridded glass panes; a renderer does it with arithmetic. The window is your screen; your fixed eye is the camera.
So how does the arithmetic version work? In view space the camera
looks down the z axis, so a vertex's z is simply its
distance ahead. Perspective projection is then one
division: divide x and y by z (scaled by the lens strength).
A point twice as far away gets its offsets halved — and that single
division is the entire reason distant things look small, rails
converge, and 3D feels three-dimensional. The lens strength comes
from the field of view
(FOV): wide angle = more world squeezed onto the screen.
A vertex sits at (1.0, 0.5) sideways/up in view space.
At depth z = 2 it projects to
(1.0/2, 0.5/2) = (0.5, 0.25) on screen. Walk it back to
z = 4 and it lands at (0.25, 0.125) —
same object, half the size. That's perspective, in its entirety.
Two footnotes complete the picture. First, the region the camera can actually see — a truncated pyramid spreading from the eye, capped by a near and far plane — is called the view frustum; geometry outside it is thrown away or trimmed at its walls (clipping), so no time is wasted on things behind you. Second, there's a simpler projection that skips the divide entirely: orthographic projection just drops the z — no shrinking with distance at all. It looks wrong for worlds but perfect for flat things, which is exactly why games use it for menus and HUDs.
The lab below runs this entire module in about forty lines of arithmetic — the same forty lines the hardware version bakes into silicon. Rotate the cube (model→world), pull it away from the camera (world→view), widen the lens, and — the best button on this page — flip between perspective and orthographic and watch depth itself switch off: the ground grid's rails stop converging and distance stops mattering.
- A vertex hops through named spaces: model → world → view → screen.
- Each hop is a matrix — a small number-table — and matrices fuse, so the chain collapses to one multiply per vertex.
- Perspective projection is a division by depth; that one divide is why far things look small.
- The frustum bounds what's visible (clipping trims the rest); orthographic projection skips the divide — used for menus and HUDs.
Rasterisation — from triangle to pixels
Here is the hinge of the whole course. Module 03 left our triangle projected onto the screen — but a screen (Module 01) isn't a sheet of paper; it's a grid of pixels. Something has to decide, pixel by pixel, which cells of the grid this triangle covers. That act is rasterisation — literally “turning into a raster image” — and the machinery that does it is called the rasteriser.
The rule is stricter than you might guess. A pixel isn't “a bit covered” or “mostly covered” — the hardware tests one exact point, the pixel centre, and asks a yes/no question: is this point inside the triangle? The elegant part is how it asks. Each of the triangle's three edges splits the plane into two halves. For each edge there's a tiny formula — an edge test, just two multiplies and a subtract — whose sign says which side of that edge the point is on. Inside the correct half-plane of all three edges at once? Then the pixel centre is inside the triangle, and the pixel is covered. No trigonometry, no curves: three sign checks, repeated across the grid at ferocious speed. This is the single operation GPUs were invented to do.
Rasterisation is spray-painting through a stencil onto graph paper. The stencil's opening is the triangle; the graph-paper cells are pixels. A cell counts as painted if its centre dot got paint. Cells along the cut edge become the familiar “staircase” of jagged pixels — walk close to any GameCube-era game and you can see exactly those stairs, because this is precisely how its pictures were made.
Interpolation: spreading the vertices across the face
Knowing a pixel is covered isn't enough — we need to know what
value it should take. The three vertices carry attributes
(Module 02): colours, and soon texture coordinates and lighting. A
pixel in the middle of the triangle should get a smooth blend of all
three. Delightfully, the machinery is already paid for: those three
edge-test numbers double as weights. A pixel near vertex A
gets a big A-weight and small B and C weights; normalise the three
and you can blend any attribute:
value = wA·A + wB·B + wC·C. These weights are called
barycentric coordinates,
and this blend — interpolation — is how a
three-cornered description becomes a smoothly varying surface. Every
gradient, every texture lookup, every soft lighting falloff in
Parts I and II rides on it. (One honest complication waits for
Module 05: after Module 03's perspective divide, the blend must be
depth-corrected or textures visibly swim — the hardware handles it,
but it's why the maths is called perspective-correct
interpolation.)
In the lab, drag the three vertices around the big-pixel grid. Every dot is a pixel centre; cells light up when their centre passes all three edge tests — watch the staircase crawl along the edges as you move a vertex. Then switch to interpolate and the covered pixels take their barycentric blend of the three vertex colours.
- Rasterisation decides which pixels a triangle covers, by testing each pixel centre.
- The test is three edge tests — sign checks against the triangle's three half-planes. Cheap, exact, and massively repeatable.
- The same edge values, normalised, become barycentric weights that interpolate any vertex attribute across the face.
- Edge staircases (“jaggies”) are the visible fingerprint of the pixel-centre rule.
Texturing — gluing pictures onto triangles
Interpolated vertex colours (Module 04) give you smooth gradients — but a brick wall isn't a gradient. Modelling every brick as geometry would cost millions of triangles, and Module 02 taught us triangles are money. The industry's great cheat: keep the wall as two triangles and glue a picture of bricks onto them. The picture is a texture, and to keep vocabularies straight, its pixels get their own name: texels.
The glue is a pair of numbers per vertex called
UV coordinates:
u says how far across the texture that corner grabs,
v how far down, each running 0 to 1. They're
vertex attributes, so Module 04's interpolation spreads them across
the face for free: every covered pixel gets its own fractional
(u, v), and the renderer fetches the texture there — a step
called sampling. (This is where the
perspective-correct fine print from Module 04 earns its keep:
interpolate UVs without the depth correction and the picture
visibly bends and swims across the surface — a glitch PlayStation-era
games wore openly; the hardware we meet in Part II corrects it.)
Texturing is gift-wrapping geometry. The wrapping paper is the texture; the UVs are pencil marks on the paper saying “this printed spot glues to this corner of the box.” Stretch the paper between the marks and the pattern lands on the surface. Aim two corners at the same spot on the paper and the pattern squashes; that stretching and squashing is entirely under the artist's control.
Sampling: which texel, exactly?
An interpolated (u, v) almost never lands dead-centre on one texel — it lands between texels (the audio course hits the identical problem between audio samples, and solves it the identical way). The renderer must decide what colour “between” means, and the decision has a quality ladder:
- Nearest — grab whichever texel is closest. Cheapest, but surfaces look blocky up close, and the winner snaps from texel to texel as things move — edges crawl and sparkle.
- Bilinear filtering — fetch the four surrounding texels and blend them by closeness, in both directions. Smooth up close, and the standard on GameCube-class hardware.
But bilinear hides a nastier problem at the other end of the distance scale. Picture a 64-texel-wide floor tile so far away it covers 4 pixels on screen. Each pixel now “contains” hundreds of texels, but a bilinear sample still reads only four of them — a random pinprick into a region that ought to be averaged. Move the camera a hair and the pinprick lands somewhere new: the distance shimmers and boils. Readers of the audio course will recognise this instantly — it is aliasing, the same disease as audio's folded-back frequencies: detail finer than your sampling grid doesn't vanish, it turns into garbage.
The graphics cure is the mipmap: alongside the full texture, pre-store it at half size, quarter size, and so on down to a single texel — each level a correctly averaged miniature (the memory cost is only one-third extra). When a surface is far away, sample the level whose texels are about the size of your pixels: the averaging was done in advance. Distant ground goes calm; the price is a touch of blur far away, and a visible seam where levels change — which fancier filtering (trilinear: blend two levels) smooths over.
The lab renders a genuine perspective floor, texel by texel, in software. Let it scroll and compare the three filters — the difference is unmistakable in motion: nearest crawls everywhere, bilinear is lovely up close but boils in the distance, and bilinear + mipmap calms the horizon at the cost of softness. Every texture-quality slider you've ever seen in a game is negotiating this exact trade.
- Textures put detail on cheap geometry; texels are the texture's own pixels; per-vertex UVs are the glue.
- Interpolated UVs land between texels — nearest snaps (blocky, crawly); bilinear blends the 4 neighbours.
- Distant surfaces cram many texels per pixel; single samples turn that detail into shimmer — texture aliasing.
- Mipmaps pre-average the texture at every scale (⅓ extra memory) so distant pixels sample calm data.
Light & shade
Texture a sphere with our checkerboard and it still looks like a flat sticker, because nothing about it responds to light. Real objects are bright where they face a light source and dark where they face away. To fake that, each point on a surface needs to know which way it's facing — and that's one more vertex attribute: the normal, a tiny arrow of length one sticking straight out of the surface. Flat wall: all normals parallel. Sphere: normals fan outward like a hedgehog. Normals are authored with the mesh, and (Module 04 again) they interpolate across triangles like any other attribute.
With normals in hand, the era's entire lighting model is two intuitions dressed as arithmetic:
- Diffuse — matte surfaces are brightest facing the light, fading as they turn away. Arithmetically: brightness follows the angle between the normal and the light direction (the famous
N·L— 1 facing dead-on, 0 at 90°). Chalk, cloth, skin: mostly diffuse. - Specular — shiny surfaces add a bright highlight where light bounces mirror-like toward your eye; the tighter the highlight, the glossier the material reads. It depends on the viewer's position, not just the light's — tilt a glossy card and the gleam slides.
Add a floor of ambient light — a flat minimum so
shadowed sides don't crush to pure black, standing in for all the
light bouncing around the room — and you have the classic recipe:
colour ≈ ambient + diffuse·(N·L) + specular·gleam.
It's an approximation physicists would wince at, and it drew a
decade of beautiful games.
Hold a torch near a matte wall: the bright patch is where the wall faces the torch, dimming smoothly around it — that's diffuse. Now aim it at a framed picture: one glaring spot of glass jumps out, and it moves as you move — that's specular. The dim visibility everywhere else, from light bouncing off every wall, is ambient.
N·L diffuse shading. Right: the same lit values displayed flat (one colour per face — visible facets) vs Gouraud (corner values interpolated — the facets melt).Where to run the recipe: per-vertex (Gouraud) shading
One decision remains: run that recipe at every pixel, or only at every vertex? Per-pixel is far more work — 2001-era hardware could not afford it as a general diet. The era's standard, and the GameCube's native mode, is per-vertex lighting, universally called Gouraud shading (after Henri Gouraud, 1971): compute the full recipe at the three corners only, then let Module 04's barycentric interpolation smear the resulting colours across the face for free. For a mesh of thousands of vertices covering hundreds of thousands of pixels, that's a spectacular discount.
The discount has a tell, and once you see it you'll spot it in every GameCube game: interpolation can only blend between corner values, never invent a peak inside a face. Diffuse light varies slowly, so it survives beautifully — but a tight specular highlight that should bloom mid-triangle gets sampled at three corners that all miss it: the highlight dims, wobbles, or breaks into a starburst on coarse meshes. In the lab, drop specular to zero and flat vs Gouraud is a subtle facet story; crank specular and drag the light slowly — watch the highlight pulse as it crosses faces. That pulse is Gouraud's signature, and half the reason Part II's TEV tricks (Module 11) were so prized for faking crisper shine.
- Normals tell each surface point which way it faces; they're vertex attributes like colour and UVs.
- The classic recipe: ambient floor + diffuse (N·L) + a viewer-dependent specular highlight.
- Gouraud shading runs the recipe per vertex and interpolates colours — the era's affordable standard, and the GameCube's native mode.
- Its tell: tight specular highlights dim and pulse, because interpolation can't invent a peak inside a face.
Depth & blending
One problem remains before Part I's toolkit is complete, and it sounds too obvious to need solving: near things must appear in front of far things. But triangles are drawn one after another, each splatting its pixels into the framebuffer — and a triangle drawn later lands on top, regardless of whether it's actually nearer. Draw the mountain after the castle and the mountain sits in front of the castle.
The oldest fix is the painter's algorithm: sort everything by distance and draw back-to-front, like a painter laying down sky, then hills, then trees. It fails in two ways. Sorting thousands of triangles every frame is expensive — and worse, sometimes no correct order exists: two triangles that pass through each other (or three that overlap in a cycle) each need to be both in front of and behind the other. A whole-triangle decision can't be right everywhere.
The fix that won is gloriously blunt: stop deciding per triangle and decide per pixel. Next to the framebuffer, keep a second grid the same size — the z-buffer (or depth buffer) — holding, for every pixel, the depth of the nearest thing drawn there so far. When a triangle wants to colour a pixel, its interpolated depth (Module 04's machinery again — depth is just one more attribute) is compared first: nearer than what's stored? Draw, and record the new depth. Farther? Skip. Draw order stops mattering; intersecting triangles resolve exactly, pixel by pixel, along their true crossing line. The cost is honest: a whole second buffer's worth of memory and a read-compare-write at every covered pixel — remember that bill when Module 08 shows you the extreme lengths Flipper's designers went to to pay it.
Every pixel runs a deli counter where lowest number wins. Each arriving triangle-pixel holds a ticket — its depth. The counter keeps the smallest ticket seen so far, and a newcomer either beats it (new colour, new record) or is turned away. Nobody needs to queue in order, because the record-keeping makes order irrelevant. That's the z-buffer.
Blending: where the z-buffer meets its match
Everything so far assumed opaque surfaces. But games need glass,
water, smoke, fire — things you can see through. For that,
a pixel gains a fourth channel next to R, G and B:
alpha,
its opacity. Drawing a translucent pixel means alpha
blending: mix the incoming colour with whatever's already
in the framebuffer —
result = new·α + behind·(1−α) — the on-screen cousin of
the audio course's mixing equation.
And here's the sting: blending re-introduces the ordering problem the z-buffer just solved. Mixing with “what's already there” only gives the right answer if everything behind the glass was drawn first — order matters again, by construction. Worse, the z-buffer actively fights you: a translucent surface that writes its depth then rejects things behind it that should have shown through, drawn a moment later. The standard truce, on GameCube as everywhere since: draw all opaque geometry first (z-buffer reigns), then sort just the translucent bits back-to-front and blend them on top. It's a compromise with real cracks — sort by what, for triangles that interpenetrate? — and transparency has stayed genuinely awkward in real-time graphics ever since. In the lab, drop the magenta triangle's alpha and watch each mode fail in its own way.
That completes the toolkit: pixels, triangles, transforms, rasterisation, textures, lighting, and depth. Every frame of every GameCube game is these seven ideas run in a row, millions of times, sixteen milliseconds at a time. Time to meet the chip that ran them.
- Later draws overwrite earlier ones, so visibility needs solving; whole-triangle sorting (painter's algorithm) is costly and sometimes impossible.
- The z-buffer stores per-pixel depth and keeps the nearest — order-independent, exact even for intersecting triangles.
- Alpha blending mixes new colour with the framebuffer (new·α + behind·(1−α)) for glass, smoke and water.
- Blending needs back-to-front order again — so engines draw opaque first, then sorted translucents. Transparency stays painful.
The Flipper GPU
Now we put the Part I toolkit into real silicon. The GameCube draws everything with one remarkable chip — Flipper — that is far more than a graphics processor: it's the hub the whole console hangs off. These six modules cover the chip itself, how the CPU feeds it commands, its hardware transform-and-lighting unit, the TEV combiner that gave GameCube games their looks, its texture machinery, and the strange, wonderful journey a finished pixel takes to reach a 2001 television. From here on we'll name real hardware, but every piece maps back to a fundamental you already know.
Meet Flipper
The GameCube's graphics chip is called Flipper, and it has a pedigree worth knowing. It was designed by ArtX, a company founded largely by engineers from Silicon Graphics — the team whose previous console work had produced the Nintendo 64's graphics hardware. ArtX was acquired by ATI while Flipper was in development (which is why the finished console wears an ATI badge), and the chip was manufactured by NEC. It runs at 162 MHz — exactly one third of the 485 MHz Gekko CPU, keeping the two clocks in lockstep.
Calling Flipper a “GPU” undersells it. It's really the console's hub — what we'd now call a system-on-chip. Alongside the graphics pipeline it houses the memory controller for the console's main RAM, the I/O interfaces for controllers, discs and memory cards, the video interface that drives the TV (Module 13) — and the entire audio DSP, the star of this course's sibling audio course. Every sound and every pixel that console ever produced passed through this one piece of silicon.
The headline feature: memory inside the chip
Now recall two bills that Part I ran up. Module 07's z-buffer demands a read-compare-write at every covered pixel; Module 05's texture sampling demands four texel fetches per pixel, per texture. At 2001 clock speeds, ordinary external memory simply could not serve that firehose — bandwidth, not arithmetic, is the classic wall GPUs hit. Flipper's designers answered with the chip's defining feature: they put the hottest memory inside the chip itself, as embedded 1T-SRAM — about 3 MB of it, split into two pools:
- An embedded framebuffer — the EFB, roughly 2 MB — where the frame being drawn lives: Module 01's framebuffer and Module 07's z-buffer, physically on the die. Every pixel write, depth test and blend happens here at full speed, never touching external RAM.
- A texture cache — TMEM, about 1 MB — staging the textures currently in use so Module 05's four-fetches-per-pixel habit is served on-chip too.
The result: the operations Part I showed to be the most punishing became the operations Flipper never worried about. The trade — and Part II keeps meeting it — is that on-chip memory is small, and everything must be staged in and copied out through main RAM (24 MB, itself 1T-SRAM). Module 12 shows how textures squeeze into that 1 MB; Module 13 shows the copy-out dance the little EFB forces on every single frame.
A restaurant kitchen doesn't run to the pantry for every pinch of salt: the chef keeps a small tray of everything within arm's reach and restocks it between rushes. Flipper's embedded memory is that tray — tiny (2 MB EFB, 1 MB TMEM) but reachable without breaking stride, while the pantry (24 MB of main RAM) holds everything else and refills the tray in bulk.
On paper. Flipper's four pixel pipelines at 162 MHz give a theoretical fill rate of about 648 megapixels per second, and Nintendo quoted 6–12 million polygons per second as a realistic in-game figure rather than a lab-condition peak — a small marketing rebellion in an era of inflated numbers. Treat all such figures as ceilings; real frames spend their budget on Part I's whole chain, not one stage.
- Flipper: designed by ex-SGI engineers at ArtX (finished under ATI), fabbed by NEC, clocked at 162 MHz — ⅓ of the CPU clock.
- It's a system-on-chip: graphics plus the memory controller, I/O, video interface and the audio DSP.
- Its defining trick is ~3 MB of embedded 1T-SRAM: a ~2 MB EFB for the frame being drawn and 1 MB TMEM for textures.
- Embedded memory bought bandwidth — the true currency of Module 05's and 07's per-pixel costs — at the price of being small.
Feeding the chip — the CP, the FIFO & vertex formats
A GPU is only as fast as the queue feeding it. If the CPU had to hand Flipper one triangle at a time and wait for each to finish, both chips would spend most of every frame idle. So the two processors communicate the way a busy kitchen does: through an order rail. The CPU writes drawing commands into a ring of memory called the FIFO, and Flipper's command processor (the CP, the front door in Module 08's diagram) consumes it at its own pace. Producer and consumer never wait for each other unless the ring runs completely full or empty.
The CPU side has a lovely piece of engineering grease. Writing single words to memory-mapped hardware is slow, so the Gekko CPU has a write-gather pipe: point it at the FIFO and every individual store the game makes is silently collected into full-size bursts. The game's code just says “position, colour, position, colour…” and the hardware packs the stream densely behind its back. GX — the GameCube's graphics API — is essentially a library of small functions that push bytes into this pipe.
The CPU is the kitchen, Flipper is the diner, and the FIFO is the conveyor rail between them. The kitchen keeps placing plates without asking whether the last was eaten; the diner keeps lifting plates without visiting the kitchen. Both run flat out, and only a completely full or empty rail ever stalls anyone.
That last row deserves the spotlight, because it's where the console's memory frugality shines. Flipper's vertex formats are configurable per attribute: a game declares, up front, “positions are 16-bit integers with a scale, colours are RGBA bytes, UVs are 8-bit fractions, and everything arrives as indices into these arrays.” A cube needs only 8 positions in memory even though its 12 triangles reference corners 36 times; a terrain's height grid can be 16-bit instead of float. Compare the audio course's Module 04 — 4-bit ADPCM instead of 16-bit PCM — and you'll see the same house philosophy: on a console, the format of the data is a design decision, and bytes are budget.
Emulator foreshadowing. Everything Dolphin knows about a frame arrives through this FIFO — which is why Dolphin's graphics debugger can record a “FIFO log” of the raw command stream and replay it, frame-perfect, with no game running at all. When Part III translates GPU state into shaders, the state it's translating is precisely what these commands set.
- CPU and GPU are decoupled by a FIFO command ring in main RAM — producer and consumer run flat out.
- Gekko's write-gather pipe turns the game's individual stores into efficient bursts; GX is the library that feeds it.
- Display lists pre-record command runs for cheap replay.
- Configurable vertex formats + indexed attribute arrays store shared data once, in the smallest type that suffices — bytes are budget.
Hardware T&L — the XF unit
Once the CP has assembled a vertex, it hands it to the XF unit — the transform engine, and the reason the GameCube's spec sheet could say hardware T&L (transform and lighting). On mid-90s consoles, Module 03's matrix-multiply-per-vertex ran on the CPU (or a CPU-adjacent coprocessor), eating cycles the game wanted for physics and AI. Flipper's generation moved the whole job onto the graphics chip: the CPU describes where things are, and XF does the arithmetic for every single vertex.
XF is Module 03 made physical. It holds a small on-chip matrix memory — dozens of slots for model-view and texture matrices — and each incoming vertex says which slots to use. That per-vertex choice is sneakily powerful: a jointed character loads one matrix per bone, and each vertex picks (or blends) its bone's matrix — skinned animation, essentially free. After transforming, XF handles clipping against Module 03's frustum, and the perspective divide happens on the way to the rasteriser.
Then comes the “L.” XF implements Module 06's recipe — per-vertex, Gouraud-style, exactly as that module described — for up to 8 hardware lights, whose results land in two colour channels — two independent lit colours per vertex (each with its own alpha). Why two? Because they flow downstream as separate ingredients: a game can light the main material on channel 0 and, say, a rim or highlight term on channel 1, and let Module 11's TEV combine them in different ways. XF also runs texgen — generating or transforming texture coordinates per vertex, which is how effects like projected shadows and environment-mapped shine get their UVs without the CPU computing any of it.
XF is a hand-cranked pasta machine bolted to the pipeline: raw vertex dough goes in one end and every piece comes out rolled (transformed), trimmed to the tray (clipped) and seasoned (lit) — identically, tirelessly, one per crank at 162 MHz. The CPU's only job is choosing which rollers to install: it loads the matrices and light settings, then feeds dough.
Note what XF is not: programmable. You cannot upload code to it; you configure it — which matrices, which lights, which texgens — from a fixed menu. The same is true of the TEV we meet next, and that single word, fixed-function, is the entire plot of Part III: Dolphin must recreate a menu-driven chip on modern GPUs that only speak programmable shaders.
- XF is hardware T&L: Module 03's transforms and Module 06's per-vertex lighting, in fixed-function silicon.
- On-chip matrix memory with per-vertex slot choice makes skinned characters nearly free.
- Up to 8 lights accumulate into two per-vertex colour channels; texgen manufactures UVs for effects.
- XF is configured, not programmed — remember “fixed-function” for Part III.
The TEV — pixel shaders before pixel shaders
A rasterised pixel arrives carrying ingredients: up to eight texture samples (Module 05), the two lit vertex colours interpolated across the face (Modules 06 and 10), and a handful of constants. Something must decide how they combine into one final colour — texture times lighting? plus a glow? blended by a mask? On a modern GPU you'd write a small program (a pixel shader) to say so. Flipper predates pixel shaders. Instead it offers the TEV — the Texture EnVironment unit — and it is the single most characterful piece of silicon in the console.
The TEV is a chain of up to 16 stages. Each stage
is the same tiny machine: it selects four inputs — called
a, b, c and d —
from a menu (a texture's colour, a rasterised colour channel, a
konst
constant, the previous stage's result, 0, 1…), and computes, per
channel:
out = a·(1−c) + b·c + d
(plus an optional bias, a scale, and a clamp — and a parallel copy
of the whole apparatus for alpha). Squint at that formula: it's a
dial. With c at 0 you get a + d;
at 1 you get b + d; in between it fades — and because
c can be a texture or a lit colour, the fade can vary
per pixel. Results land in one of a few accumulator
registers
that later stages read back — so stages compose, like a recipe of
up to sixteen steps.
A synthesiser plays anything (a shader). The
TEV
is a mixing desk: sixteen channel strips, each with the same
knobs — pick sources, set the blend, route to a bus. You can't
teach a desk a new knob, but a good engineer patches those
sixteen strips into effects the designers never imagined. That's
exactly what GameCube-era graphics programmers were: mix
engineers, one a·(1−c)+b·c+d at a time.
a, b, c, d from the ingredient menu; the fixed blend a·(1−c)+b·c+d (with bias/scale/clamp, and a parallel alpha path) writes a register that later stages can read. Configuration, not code — but sixteen composable steps go a very long way.What sixteen little blends can do
The obvious patch is one stage: texture × lighting (set
b = texture, c = rasterised colour — try
it below). But composed stages built the era's signature looks.
Cel-shaded games in the Wind Waker style fed a lit colour through a
gradient-ramp texture to snap smooth Gouraud shading into flat
poster bands, and layered outline tricks on top. Metroid Prime-style
visor effects — raindrops and reflections that seem to sit on the
glass in front of your face — were TEV layerings of environment
maps and overlays. Heat shimmer, dream sequences, poison fog:
games achieved these as full-screen TEV recipes over an
already-rendered frame (using a copy trick Module 13 explains).
None of this was “a feature” — it was engineers
discovering what the mixing desk could be patched into.
The lab below is one genuine TEV colour stage, run per pixel in
software over a procedural stone texture and a fake per-vertex
lighting gradient. Start with the presets, then free-patch: set
c to konst and pick a colour — you've built a tint
fader. Set a to ras, b to konst,
c to tex — now the texture chooses where the
konst colour appears. Sixteen of these, remember, chained.
Counting configurations. Each stage picks 4 inputs from over a dozen sources, an operation, bias, scale, clamp and destination — for colour and alpha — times 16 stages, times the texture, texgen and lighting state feeding it. The number of distinct TEV setups games can (and do) use is astronomical. File that thought: it is exactly the combinatorial explosion that makes Part III's Module 14 hard.
- The TEV decides every pixel's final colour: up to 16 chained combiner stages, each computing a·(1−c)+b·c+d (with bias/scale/clamp, plus an alpha twin).
- Inputs come from textures, the two lit colour channels, konst constants and result registers — so stages compose.
- It's configured, not programmed — “pixel shaders before pixel shaders.”
- The era's famous looks — cel-shading bands, visor overlays, full-screen filters — were TEV recipes, not features.
Textures on GameCube — tiles, formats & CMPR
Module 08 left us a problem shaped like a triangle of constraints: textures make scenes rich (Module 05), TMEM is 1 MB, and main RAM is 24 MB for everything. This module is how the GameCube squeezed whole worlds through that needle: store textures in clever layouts, in the smallest format each one can tolerate, and compress the big ones 4-to-1.
Tiled layouts: locality is bandwidth
First, a subtlety about order. The obvious way to store an image is row by row — but think about how Module 05 reads it: a bilinear fetch wants a little 2×2 square of texels, and a triangle's pixels wander around a 2D neighbourhood. In row-major order, vertically adjacent texels live far apart in memory. So GameCube textures are stored in small rectangular tiles — little blocks (4×4 texels in many formats) laid out one after another, each filling exactly one 32-byte memory burst. A neighbourhood fetch lands in one or two bursts instead of four scattered rows. Nothing about the image changes; only the byte order does — remember this when Dolphin has to un-shuffle it in Part III.
A toolbox of formats
Second, per-texture thrift. Like the vertex formats of Module 09, texture formats are a menu, and artists picked the cheapest that survives:
| Format | Bits/texel | What it stores | Typical use |
|---|---|---|---|
| I4 / I8 | 4 / 8 | Intensity only (greyscale) | Light maps, shadow blobs, font glyphs |
| IA4 / IA8 | 8 / 16 | Intensity + alpha | Smoke, glow sprites, UI |
| RGB565 | 16 | Full colour, coarse (5+6+5 bits) | Opaque surfaces without gradients |
| RGB5A3 | 16 | Switches per texel: 5-bit colour + punchy alpha, or 4-bit colour + 3-bit alpha | Textures needing some translucency |
| RGBA8 | 32 | Full 8-bit everything (stored as two 16-bit halves in the tiles) | The few textures that must be perfect |
| CI4 / CI8 | 4 / 8 | Index into a small colour palette | Flat-shaded art, recolourable skins |
| CMPR | 4 | Block compression — this module's star | Almost everything big |
CMPR: four bits per texel that look like sixteen
The workhorse is CMPR, the GameCube's block compression format (the same family as the PC world's S3TC/DXT1). It rests on a simple observation: within any small patch of a real texture, the colours usually vary along one direction — light wood to dark wood, grass to shadow. So compress each 4×4 block of texels independently into 8 bytes:
- Store two endpoint colours,
c0andc1(16-bit RGB565 each) — the ends of that block's colour range. - Derive two more colours between them, at ⅓ and ⅔ of the way — four palette entries for the price of two.
- For each of the 16 texels, store a 2-bit index picking one of the four.
Count it: 2 bytes + 2 bytes + 16 × 2 bits
= 8 bytes for what
RGB565 stores in 32 — a clean 4:1 saving (8:1
against full RGBA8). And because every block is the same tidy size,
the hardware can decode any texel directly during sampling, no
unzipping step, no history. The cost is visible if you know where
to look: a block whose colours don't fit on one line — a
rainbow sparkle, a noisy patch — must be flattened onto four
colours, and blocky 4×4 artefacts appear. (One GameCube nicety: if
c0 ≤ c1 the fourth entry becomes transparent
instead, buying cut-out alpha — foliage! — for free.)
CMPR turns each 4×4 stamp of the image into a paint-by-numbers kit: the kit box lists just two paints (the endpoints), you're allowed to mix two blends of them, and the stamp is a grid of numbers 1–4. Sixteen numbered cells and a two-paint list is vastly smaller than sixteen full colour swatches — and it looks right whenever the stamp really was painted from two paints, which, in nature, is almost always.
The lab compresses a procedural image block by block, live. Scrub across it (or click the image): smooth sky and sea blocks reconstruct almost perfectly; then find the hard-edged sun rim or the noisy rocks at lower left, where four palette entries clearly aren't enough. This exact encoder-vs-image negotiation happened for every texture the era shipped.
- Textures are stored as small tiles matched to 32-byte memory bursts — neighbourhood fetches arrive in one burst.
- Formats are a thrift menu: 4-bit greyscale to 32-bit RGBA, palettes included — pick the cheapest that survives.
- CMPR packs each 4×4 block into 8 bytes: two RGB565 endpoints, two derived colours, 2-bit indices — ~4:1, decodable at random.
- Its failure mode is any block whose colours don't fit one line — and c0 ≤ c1 buys 1-bit cut-out alpha.
From EFB to your TV
Module 08 promised the little EFB would force a dance, and here it is. The frame Flipper just drew lives in ~2 MB of on-chip memory — but the television can't see inside the chip, and the next frame needs that space now. So every frame ends with a copy-out: dedicated hardware sweeps the EFB and writes the finished image into main RAM. The destination buffer is called the XFB (eXternal FrameBuffer), and the copy engine is no dumb mover — it transforms the image on the way through.
First, it converts colour. TVs of the era didn't want RGB; broadcast video speaks YUV — brightness (Y) separated from colour (U, V) — and, because your eye resolves brightness far more finely than hue, the colour components are stored at half horizontal resolution (so-called 4:2:2). The XFB is YUV, which also halves its memory versus 24-bit RGB. It's the video cousin of everything Module 12 preached: spend bits where perception looks.
Second — and this is pure 2001 — the copy can filter vertically. A standard-definition TV draws interlaced video: odd scanlines one sixtieth of a second, even lines the next. A crisp single-pixel-tall detail therefore blinks at 30 Hz — the notorious interlace flicker. The copy engine's copy filter blends each output line with its neighbours on the way to the XFB, softening exactly those details. Games shipped genuinely, deliberately blurred vertically — tuned for glass CRTs. (Half the “wow” of emulators today is simply switching that filter and interlacing off.)
The EFB is the photographer's negative — pristine, full-detail, but useless to hang on a wall and needed for the next shot. The copy-out is making the print: on the way to paper (the XFB) the image is colour-converted for the paper stock (YUV) and slightly softened so it looks right in the living room's frame (the deflicker filter). The negative is then wiped and reused.
Those EFB numbers hide a real design trade worth reading twice. About 2 MB is enough for 640×528 pixels at 24 bits of colour plus 24 bits of depth — and no more. Want destination alpha for layered effects? The same 24 bits must be re-cut as 6 bits per channel (RGBA6): you buy an effect with colour precision. Want higher resolution? There is nowhere to put it — the ceiling is burned into the die. (Numbers around the edges of this — exact row counts, the anti-aliasing pixel format — vary by source and mode, so treat the table above as the shape rather than gospel.)
One more copy-out trick ties Part II together: the engine can copy a region of the EFB into memory as a texture instead of as an XFB. Render the scene, copy it to a texture, feed it back through Module 11's TEV — that loop is how the era did heat haze, Wind Waker-style full-screen effects, real-time reflections and Metroid-style visor distortion. Remember EFB copies; in Part III they become one of Dolphin's most consequential settings.
The last hop is the VI — the video interface from Module 08's diagram. It reads the XFB line by line at the television's fixed rhythm (interlaced 60 Hz fields for NTSC, 50 for PAL; progressive 480p over component cables in games that support it) and generates the analogue signal. The VI doesn't wait for the GPU: it scans out whatever XFB it's pointed at, on schedule, forever. Games juggle two or three XFBs so one can be scanned while the next is copied — and the CPU can even scribble into an XFB directly, which is exactly how some games draw menus and videos. That little fact will come back with teeth in Module 15.
- Frames are drawn in the on-chip EFB, then copied out every frame to an XFB in main RAM for display.
- The copy converts to YUV 4:2:2 (half-res colour) and can vertically filter to tame interlace flicker — era-authentic softness.
- The EFB tops out around 640×528; 24-bit colour or 6-bit-per-channel with destination alpha — resolution and precision were die-sized.
- EFB→texture copies feed frames back through the TEV (reflections, haze, full-screen looks); the VI scans XFBs to the TV on a fixed clock.
Emulating it in Dolphin
Finally: how does software on your PC stand in for that physical chip? Graphics is where emulation gets philosophically weird — Dolphin must recreate a GPU with no shaders on top of modern GPUs that speak nothing but shaders, fake a 2 MB on-chip framebuffer that games poke directly, and decide how faithful to be to a machine that was tuned for interlaced CRTs. These three modules connect the whole course to the actual settings you'll toggle in the emulator.
A GPU without shaders, on a GPU with nothing but
Recall the two kinds of machine this course has now shown you. Flipper (Modules 10–11) is fixed-function: a menu of switches — TEV stage inputs, lighting channels, blend modes — with behaviour selected, not written. Your PC's GPU is the opposite: it has essentially no fixed-function colour hardware left, only programmable units running shaders written in languages like GLSL. So Dolphin's video code is, at heart, a translator: it watches the state the game programs into the virtual Flipper (through Module 09's FIFO), and for each distinct configuration it generates the source code of a shader that behaves identically — a chain of multiply-adds mimicking each TEV stage, Module 10's lighting recipe, the fog, the blend — then hands it to your GPU driver to compile and run.
Elegant — with one structural flaw. Module 11's note counted the configurations: they're astronomical, so Dolphin cannot pre-compile “all GameCube shaders” up front. It only discovers which ones a game uses when the game uses them. And the first time each new configuration appears — a boss's new attack, a particle burst, a room's new material — the frame cannot be finished until the driver compiles the new shader. Driver compilation takes tens of milliseconds; a 60 fps frame is 16.7 ms. The result is shader-compilation stutter: the game hitches at exactly the moments something new happens, which is exactly when you care. Caching compiled shaders on disk helps the second playthrough; it cannot help the first encounter, and no amount of CPU speed fixes it.
Specialised shaders are like hiring a dedicated translator for each document type that crosses your desk: unbeatable once trained, but the first contract in Portuguese stops the office for an hour of hiring. An ubershader is a single simultaneous interpreter who already speaks everything: each sentence takes a little longer, but nothing ever stops the office.
That interpreter is Dolphin's celebrated answer, shipped in 2017
after years of work: the ubershader. Instead of
generating a specialised program per configuration, write one
enormous shader that receives the TEV/XF configuration as
data — uniforms describing the 16 stages' selections — and
executes Module 11's a·(1−c)+b·c+d loop with branches,
per pixel, at runtime. A software TEV interpreter, running
on the GPU. Compile it once when the game boots and every
configuration a game can ever set is already runnable. The price is
honest: all that branching makes every pixel cost more, so
ubershaders lean on raw GPU muscle. Hence the hybrid mode most
players use: render new configurations through the ubershader
while the specialised version compiles in the background,
then swap over — steady frames, specialised speed, a few frames
late.
The lab simulates the trade. A stream of draw calls arrives; walking into new areas brings configurations the cache has never seen. Watch the frame-time strip: specialised runs lowest but spikes savagely on every first encounter; ubershader draws a calm, slightly higher plateau; hybrid stays calm while the cache quietly fills. The modes share one random seed, so the comparison is fair.
- Dolphin translates fixed-function TEV/XF state into generated shader source, compiled by your GPU driver.
- Configurations are astronomical and only discovered at use — first sights force compiles mid-game: shader stutter.
- Ubershaders invert the idea: one boot-compiled giant shader interprets the configuration as data, per pixel.
- Steady-but-heavier vs fast-but-stuttery; hybrid mode uses the ubershader as a bridge while specialised shaders compile behind it.
The hard parts
Shaders were the glamorous problem. The grinding ones all trace back to a single theme: games were written against Part II's exact memory layout, and a PC GPU doesn't have one. Four examples define the settings you'll meet in Module 16.
1 · Games that read the framebuffer back
On real hardware the EFB is just memory-mapped pixels, and Nintendo let the CPU read and write it directly. Games used that freely: reading a pixel under the cursor to detect what you're aiming at, sampling rendered colours to drive gameplay or save-file thumbnails, poking pixels for effects. On a PC, the emulated frame lives across a bus in GPU memory; reading one pixel back means a pipeline stall — the GPU must finish everything queued, then ship data back — a catastrophe repeated per frame. Dolphin therefore offers accuracy tiers: emulate EFB access faithfully (correct, sometimes slow), or skip it (fast, and the handful of games that depend on it quietly break — a cursor that selects nothing, a mechanic that never triggers).
2 · Real XFB vs a convenient lie
Module 13's honest path — EFB → YUV XFB in RAM → VI — is how some games play videos and draw menus: they write into the XFB with the CPU, never “drawing” at all. Emulating that faithfully means actually maintaining CPU-visible XFB memory and scanning display output from it (correct even for those tricks, but the output inherits real-hardware softness and resolution). The fast path skips the XFB round-trip and presents the rendered frame directly — beautiful and quick, until a game plays its intro video into the XFB and you get a black screen. Modern Dolphin defaults to faithful-enough hybrids, but the tension is permanent: the more literally you emulate Module 13, the more you also emulate its deliberate blur.
3 · Internal resolution: the upgrade that can't be free
The single most-loved emulator feature: render at 3×, 5×, 7× the EFB's resolution — internal resolution scaling — and 2001 geometry snaps into modern crispness, because Part I's triangles are resolution-independent mathematics. But Module 13 taught you the trick that breaks it: EFB→texture copies. Games building bloom or heat-haze sample those copies at hand-tuned pixel offsets — half a texel here, one line there — calibrated forever against a 640-wide frame. Scale the frame 3× and a “one pixel” offset is now a third of what the artist intended: glows sit off-centre, blur pyramids drift, outlines double. Dolphin carries per-game fixes and heuristics, but the honest statement is: native-calibrated sampling maths can only be perfectly right at native size.
4 · The texture cache dilemma
Module 12's textures live in game RAM, and games may rewrite them at any moment — animated water, video textures, procedural page flips. Faithful emulation would re-decode (un-tile, un-CMPR, re-upload) every texture every time it might have changed; that's absurdly slow, so Dolphin keeps decoded textures in a cache keyed by hashes of the source bytes. Hash rarely and a game that rewrote a texture shows the stale one; hash paranoidly and the CPU burns. That's the “texture cache accuracy” slider: literally how suspicious to be, purchasable in frames per second.
Blowing a classic up for a giant screen flatters everything shot on the original negative — that's geometry at high internal resolution. But every effect that was composited at print size — matte lines, optical glows — now sits visibly wrong, because its measurements were in print pixels. The restorer chooses per shot: keep it faithful and soft, or remaster and risk artefacts. Dolphin's accuracy settings are those choices, made per game.
- CPU reads/pokes of the EFB are trivial on hardware, pipeline-stalling on PC — hence accuracy tiers that trade correctness for speed.
- Faithful XFB emulation keeps CPU-drawn videos/menus working but inherits native softness; skipping it is fast until a game writes the XFB directly.
- Internal-resolution scaling flatters geometry but breaks native-calibrated sampling (bloom offsets) in EFB-copy effects.
- The texture cache trades hashing suspicion for speed — stale textures vs burned CPU.
Try it in Dolphin
You now have the full picture, so let's make it hands-on. Open Dolphin's Graphics configuration and read it with this course's eyes. (Exact option names shift between Dolphin versions — treat these as the ideas to look for, not gospel strings.)
- Backend (Vulkan, OpenGL, Direct3D, Metal…) — which backend API, shader language and driver Module 14's generated code is fed to. Backends differ mostly in compilation behaviour and driver quality, which is why stutter can differ per backend.
- Internal resolution — Module 15’s beautiful, imperfect upgrade: render at a multiple of the native resolution. Geometry scales free; watch bloom-heavy games for misaligned glow.
- Shader compilation mode — Module 14 as a menu: specialised (fastest, stutters), ubershaders always (steadiest, heaviest), or the hybrid/asynchronous modes that bridge with the ubershader while compiling. “Compile shaders before starting” trades boot time for early smoothness.
- “Store EFB copies to texture only”-style options — Module 13's copy-out, tiered: keep copies purely as GPU textures (fast; breaks games that read them from RAM) or mirror them into emulated RAM (faithful, slower). The same tiering exists for XFB copies.
- “Skip EFB access from CPU”-style options — Module 15's readback problem as a checkbox: speed, purchased with the handful of games whose aiming cursors and mechanics read pixels.
- Texture cache accuracy — Module 15’s texture cache hashing-suspicion slider; nudge toward accurate when animated textures misbehave.
- Scaled EFB copies, per-pixel lighting, widescreen & aspect hacks — enhancement toggles whose artefacts you can now predict: each one substitutes modern maths where a game expected Module 13's exact layout.
Aircraft cockpits look like walls of arbitrary switches — until you've walked the hangar and seen the engine, the flaps and the fuel lines each switch commands. You've just walked Flipper's hangar. Dolphin's Graphics dialog is the cockpit: every checkbox is wired to a stage you've now touched, and the figure below draws the wiring.
A great closing exercise, in the spirit of the audio course's final A/B test: pick a bloom-heavy GameCube title, set internal resolution to native 1×, and stare at a glow effect; then jump to 3× and watch Module 15 happen — the world sharpens while the glow slides subtly off its source. Then open the shader-compilation modes and walk into a new area under specialised vs hybrid ubershaders: the hitch you feel (or don't) is Module 14, live. You're no longer toggling mystery checkboxes — you're steering a pipeline you know stage by stage.
- You can follow a pixel from a vertex in model space to a scanline on a CRT — and through Dolphin to your monitor.
- You know why one chip housed the whole console's soul: framebuffer, textures, audio DSP and all.
- You can read Dolphin's Graphics dialog as a map of Flipper — and predict what every speed hack trades away.
- Sibling course: how the same little box made sound — the DSP you met in Module 08 has sixteen modules of its own.
- And when you'd rather drive GX than study it: the homebrew course shows you how to write your own code for this machine — every TEV stage on this page is yours to program.