The same image on two GPUs a decade apart
A doubt sat under this whole series. The renderer on the Nano is a carved-down fork of the reference: backward pass deleted, spherical harmonics dropped to degree 0, five patches to make 2023 code compile for a 2015 chip, and one intrinsic swapped for speed. It draws a locomotive that looks right. Looking right is not being right. The open question, since the first post, was whether it draws what the reference rasterizer would draw, or just something close.
Answering it needs the reference rasterizer, which needs a modern GPU and PyTorch, neither of which the Nano has. So the check ran on a second machine with an RTX 5080, the two renderers coordinating through the same git repository.
Same inputs, one variable
The comparison is built to isolate the rasterizer. Both machines render the same .ply, from the same camera, at the same SH degree, with the same activations on the splats. The camera matrices come from one file both renderers read. The only thing that differs between the two frames is the rasterizer itself: the stripped sm_53 port on the Nano, the stock reference on the 5080. Whatever disagrees is the port.
The same gotcha, a decade apart
The reference rasterizer would not build for the 5080 either. Its CUDA architecture list stops at 86, and the 5080 is Blackwell, sm_120, so the build produces nothing that runs until you add 120 to the list. Back in the porting post, getting onto Maxwell meant adding 53 to that same list, which stops at 86 from the low side. One line, the same line, at both ends of a ten-year span. A renderer’s build assumptions are a window onto exactly the hardware its authors had in front of them.
Eight bytes

Each frame is 863×480, 1,242,720 bytes. They differ in eight.
MAE 0.00001 / 255 max 1 differing 8 / 1,242,720 (0.0006%)
Every one of the eight is off by a single level out of 255. The amplified difference image is uniformly black: no regions, no edges, no structure, just eight isolated pixels one step apart. A port bug shows up as a shape, a wrong edge or a tinted patch. This is rounding.
The rounding has a known source. The one deliberate change to the math was swapping expf for the faster __expf in the falloff, the optimization from the profiling post. That intrinsic is good to a couple of units in the last place, and the rest is floating-point arithmetic landing in a different order on two unrelated GPUs. The single change made to the renderer is also the only measurable difference it produces, and it comes to one level on eight pixels out of 1.24 million.
What this settles
I did not write an approximation of the reference. The stripped renderer is the reference, recompiled for a chip a decade older, correct to within rounding. Every earlier “matches the photo” was a claim about the whole pipeline, training included. This is the narrower and harder one: feed the two rasterizers the same Gaussians and the same camera, and they return the same image.
That closes the last open item in the ledger. A forward-only Gaussian Splatting renderer, hand-patched onto a 2019 board, renders a real capture at about 17 frames a second, and does it pixel-for-pixel. The proof ran on a GPU from the other end of the decade, in the same repository, a few commits later.
The two machines coordinated through dated handoff docs on main.
Next: the backward pass the Nano deleted trains a better model than any prune.
Real-time Gaussian Splatting on a $99 board
- Compiling a 2023 CUDA renderer for a 2015 GPU
- Gaussian Splatting on a Jetson Nano: the bottleneck wasn't the sort
- Most of a Gaussian scene is haze: pruning a real capture onto a $99 board
- I downloaded 120 KB of a 14 GB file to find the camera
- The same image on two GPUs a decade apart (this post)
New parts publish weekly; this list grows as each one goes live.