Post 104

A Thousand Lights, Six Times Faster

The 1000-light stress scene drops from 25 ms to 4 ms a frame on an RTX 5070. The culprit was not the lights themselves but the bounce-light cache politely interviewing every single light for every ray it traced. It now samples sixteen of them and trusts statistics, which is what statistics are for.

The 1000-light stress patch ran at 20 fps on an RTX 5070, which is the kind of number that makes a discrete GPU feel underappreciated, especially when an integrated laptop chip was quietly beating it. The original diagnosis blamed CPU submission overhead. The GPU timestamps disagreed: the processor was idling at under a millisecond a frame while the GPU chewed on 23 milliseconds of something that did not care about resolution at all. Quarter the pixels, same frame time. Add lights, linearly worse. That signature points at exactly one subsystem.

It was the bounce-light cache, the thing that makes a red wall blush onto the floor. Every frame it re-traces a slice of its world-grid, and every traced ray that hits a surface asked every light in the scene what it thought about that surface. Eight thousand cells, sixty-four rays each, one thousand lights: up to half a billion light evaluations per frame, for an effect whose entire job is to be a soft low-frequency wash.

Sixteen lights in a trench coat

The fix is the standard one from the many-lights playbook: stop summing, start sampling. Past sixteen active lights, each ray hit now evaluates a sixteen-light random subset and scales the result, an unbiased estimate of the full sum. The subset is chosen deterministically per cell and rotated on every re-trace, so the cache’s own temporal averaging smooths across subsets the same way it already smooths across its staggered refresh. Scenes with sixteen lights or fewer keep the exact loop, bit for bit.

The estimator’s arithmetic is pinned by a CPU-side test that runs the same hash and the same index mapping four hundred thousand times against known sums, and the performance is pinned by re-baked hardware baselines: the thousand-light scene’s GPU time fell from 33 to under 4 milliseconds at the 99th percentile, and the 200-light club scene now renders offline at around 300 fps. The discrete GPU is, at last, faster than the laptop chip it shares a chassis with.

While building the verification for this we also caught the bounce cache converging to slightly different answers on different engine launches, an older and entirely separate bug that is now filed with a reproduction harness and a trail of evidence. The renderer should give the same answer twice; it will.

What it buys you

Stack a thousand lights in a patch and the frame budget barely notices. The bounce lighting looks the same, arrives at the same answer, and no longer bills you per light for the privilege.

← All posts