All posts
DebuggingJuly 15, 20264 min read

640,000:1 — The Depth-Buffer Ratio That Wedged a GPU Driver

Cockpit view rendered nothing. Chase and orbit were fine. The cause was two constants that were individually reasonable and jointly capable of hanging an integrated GPU — and the investigation is a lesson in what counts as evidence.

The bug report was simple: switch to cockpit view and the scene renders nothing, on every aircraft. Chase view fine, orbit view fine. On the target hardware — an Intel Iris integrated GPU, exactly the class of machine classroom courseware actually runs on — the cockpit was a blank.

Except it was not rendering nothing. The render loop had stopped. The canvas was frozen on its last clear, which reads as "renders nothing" rather than as what it was: a wedged driver. That misread cost real time, because you debug a black screen by looking for culling and camera bugs, and you debug a hang by looking for what the GPU choked on.

Two reasonable constants, one absurd ratio

Cockpit view needs a near plane close enough that the instrument panel 30 cm from your eye is not clipped: ours was 0.05 m. It also wants a far plane distant enough to see terrain from altitude: ours was 32 km. Each number is defensible in isolation. Together they are a near:far ratio of 640,000:1, and a 24-bit depth buffer distributes its precision logarithmically — the bulk of it lands in the first few metres, and everything past mid-range collapses into a handful of depth values.

The textbook consequence is z-fighting: distant surfaces flickering through each other. Both the author and the reviewer of that code knew the textbook, reasoned from it, and concluded a bad ratio produces artefacts, not hangs. On this hardware, both were wrong. Whatever the Iris driver does with a degenerate depth range, it does not do it gracefully — the render loop stopped and never came back.

The elimination process

  1. 01Bisect against a running browser. Reasoning from the code had already produced a confident wrong answer, so we stopped reasoning and started removing. Half the cockpit scene at a time, reload, observe.
  2. 02The decisive experiment: an empty scene still hangs. A build rendering one light and zero geometry — no cockpit model, no canvas textures, no HUD — still wedged. That single result eliminated every component in the scene graph as the cause and pointed squarely at a driver interaction with the render state itself.
  3. 03With geometry exonerated, the camera state was what remained — and the cockpit view was the only view overriding the near plane down to 0.05.

Two clean loads are a coin flip

The most expensive mistake in this investigation was epistemic, not technical. After an early candidate fix, the cockpit rendered correctly twice in a row, and we recorded the bug as fixed. On the identical commit, it later froze repeatedly. Two successes on an intermittent failure are the good side of a coin flip, not evidence — and we had to write a follow-up commit whose only purpose was to correct the record. The project convention that came out of it: an intermittent bug is not "fixed" until the fix survives ten consecutive reloads on the hardware that showed the failure, and a claim without that is written up as a candidate, not a conclusion.

The fix, and the comment that guards it

The load-bearing comment, abridged
// Cockpit frustum: 0.12 near / 12,000 far — a 100,000:1 ratio.
// Do NOT tighten near back toward 0.05. At 0.05:32000 (640,000:1)
// the depth range wedges the Intel Iris driver: the render loop
// halts and the canvas freezes on its last clear. The failure is
// SILENT on discrete GPUs — it will look fine on your machine
// and hang on the classroom laptops this product is sold for.

The ratio came down to 100,000:1 — near 0.12 m, which still clears the instrument panel, and far 12 km, which still covers the training area. Each camera view now asserts its own frustum idempotently every frame (two float compares) instead of latching it behind an init flag, because the previous latch had leaked the cockpit’s far plane into chase view for the rest of the session. And the comment above the constants is deliberately loud, because this failure mode is invisible on the discrete GPU a developer is probably sitting at. Someone tightening that near plane would see nothing wrong locally and ship a build that hangs in the classroom. When a bug is silent on developer hardware, the comment is the only regression test that runs at code-review time.