MMX and the 3D cards
2026-10-23, ninth session.

Page 7 of Galleria's track textures. Left: the 8-bit page from GALLERIA.BL3, as the software builds draw it. Middle: the 16-bit RGB565 page from GALLERIA.BL4. Right: the same page halved by point sampling, as the 3dfx build loads it because its flag in the file is 1 (shown at twice its size). Exported with pod-viewer export. © Ubi Soft; shown from our own viewer.
Why MMX mattered
Intel launched the Pentium with MMX on 8 January 1997. POD was one of the games that showed it off: it was sold with new MMX computers and appears on Intel's own CD of MMX titles. The disc holds eight builds of the game, a plain Pentium build and an MMX build for each of four renderers. So the question for this session was simple: what does the MMX build do differently?
What the MMX build changes
Listing every MMX instruction in PODMMX.EXE gives 813 of them in 25 routines, in two hand-written assembly modules. Matching each routine to its caller and then to the same caller in WINPOD.EXE found the plain version of almost every one.
The first module is a new sound mixer. The Pentium build mixes all channels in one routine with the floating-point unit. The MMX build has one routine per channel kind. Each scales four samples at a time with pmulhw and adds them into the mix with a saturating add. Around it sit four effects that the Pentium build does not have in this form: a reverb, a flanger, an echo and a stereo widener built from a 32-tap filter.
The second module belongs to the software renderer. The renderer draws front to back and keeps one bit per screen pixel of what is already covered. The MMX build marks that mask 64 pixels at a time, clears the uncovered pixels in 8-byte stores and draws textured spans in groups of four pixels.
Measured, not assumed
GameFrame's Unicorn emulator ran both versions of the coverage-mask routine on 300 random sets of spans. They agreed every time on which spans are hidden, on the result flag and on the covered pixels. The bytes of the mask differed, because the two versions number the bits the other way round inside each word. Each build reads only its own layout.
The MMX mixer was run on 500 random channels against a model written from the instruction rules alone. The model only matched once it copied one quirk. The pan volume is computed with a signed byte multiply, so a pan of exactly 0 or 128 flips the sign of the loud side.
Three cards, three approaches
- 3dfx gets everything. The Glide build uploads every texture to the card, the track pages as 16-bit RGB565 straight from the file, and draws all the faces itself. It is the only build that loads the
.BL4tracks. - ATI 3D Rage gets very little. The build never registers a texture with the chip. Only untextured faces go to the card; every textured face is still drawn by the software span routines.
- S3 ViRGE textures on the chip, without perspective correction, through the S3D Toolkit's function table.
The extra numbers in .BL4
The track session had found 16 flags and one extra word per face in the 16-bit tracks that the software build never reads. The 3dfx build reads both. Each flag belongs to a texture page: 1 means "load this page at half size". Galleria, Sewer, Veitland and Canyon have eight pages, and each flags one page so that no track needs more than seven full pages of the Voodoo's texture memory. The word per face is a mirror group, 0 for an ordinary face and n for a face of reflecting plane n. The 3dfx build collects those faces into planes, under strings that read "Mirror_Faces".
Two new libraries
crates/mmx holds the exact behaviour of every MMX instruction, so a port can reproduce the 1997 arithmetic bit for bit. crates/gpu-1997 decodes every texture format of the three chips' APIs, including 3dfx's compressed NCC format, and lists what each card accepts. Both are tested and could move to GameFrame for other games of the period.
Next
- Compare the textured spans pixel for pixel, and the two mixers sample for sample.
- Find the S3 build's texture format, and how the 3dfx build draws its mirrors.
- A renderer switch in the viewer, to show a track as each card drew it.