D986 - A frame's passes dumped one by one, and their outputs judged

Status: decided Date: 2026-10-26 known_by: measured

ORBISTOUN_PASS_DUMP=1 dumps every pass of each frame ORBISTOUN_FRAME_AT names, busy:N included, into passes-<flip>/ where the frames go. A pass is one compute dispatch, or one run of draws into the same colour targets. Consecutive draws into the same targets extend one pass, and the targets are read back only once something else comes next. After each pass, the images it wrote are written out: a dispatch's stored images as the device answered them, and a run of draws' colour targets as read back. Two listings go beside them:

An image a pass left as it found it is listed by the earlier file. A pass the host refused is listed with what it would have written, where its preparation got that far.

orbistoun-cli passes <dir> turns a dump into one picture an image, passes.html, and a table. The table flags each pass whose output:

It names the first pass whose output is non-finite or noise.

A cache of guest memory checked only against host writes must first settle the range it covers, as a read of it would. Settling covers a frame still on the device, a copy or fill deferred onto its pages, and a queued submission's draws over it. GuestMemory::settle does this without reading: it is a no-op by default, and the command processor's reader implements it. Texture binds (tiled, linear and mip chains) and draw buffers call it before they consult their caches.

Why: Grand Theft Auto V's in-world frame showed coloured static. The pass dump of flip 5349 found the first non-finite output in the lighting pass (311), which read the reflection chain at 0x7400e82c0000. The chain is drawn one level at a time, each level sampling the one before, and every level had sampled the chain as the texel cache last held it. That was zeros for the large levels, and stale contents for the mip tail. The tail level then held NaN, and the lighting spread that NaN over every surface.

A cache answer skipped the read that would have written the pending frame back. It also skipped the read that would have carried out the deferred copy, and the read that would have marked the preparation as read ahead of queued draws (D882). The host's write watch never saw a write, so the cache stayed valid indefinitely.

Rejected: