DEVICE_LOST (Xid 31) switching split deferred lighting off live: intermediates freed mid-recording, set 0 / set 3 keep their views #809

Closed
opened 2026-10-17 15:51:07 +00:00 by sky_line · 1 comment
Owner

Symptom: switching RenderVKDeferredSplit from 1 to 0 in a running session (deferred lighting on) loses the GPU within 1–3 frames, every time. Seen on a GTX 1080 with NVIDIA 580 on Linux at 3840×2062. The kernel log shows NVRM: Xid 31 ... MMU Fault: ENGINE GRAPHICS GPC0 GPCCLIENT_T1_x ... FAULT_PDE ACCESS_TYPE_READ, meaning the texture unit read unmapped memory. The breadcrumbs end at g_p2_barrier (right after deferred lighting, before pass 2). The log shows VKDeferSplit: intermediates freed (split lighting off) just before the loss.

An offscreen snapshot taken after the switch hits the same fault. With split lighting off from login, so the intermediates are never created, snapshots and rendering are fine.

What's established

  • The free in deferSplitFrame (vkDeviceWaitIdle + destroyDeferSplitTargets) runs inside recordWorld, after the frame's command buffer has begun.
  • Delaying the destroy by a couple of frames (retire instead of destroy) only moves the fault to the frame the images are finally destroyed. So some GPU work keeps reading the split intermediates in every frame after the switch, not only the switch frame.
  • ensureDeferSplitTargets writes set 3 and draw set 0 bindings 41–43 (visibility reuse) under the open command buffer. Set 0 is PARTIALLY_BOUND, not UPDATE_AFTER_BIND, and resizeProbesIfNeeded (#521) documents that this is invalid. On free, nothing rewrites set 0's bindings 41–43 or set 3, so bound sets keep views of destroyed images.
  • Not the cause (tested):
    • The no-stall resize copy-on-write swaps: RenderVKResizeNoStall 0 still crashes.
    • RenderVKDeferVisReuse 0 before enabling split still crashes (bindings 41/42 still point at the sun / projector images).
    • A tag on the pad0 visibility-reuse flags. Cluster draws store their view index in pad0, so an odd index read as VISR_ON, which is a separate wrong-visibility bug while split lighting runs.
  • RenderVKDebugDescriptorTracking reported 0 stale binds, so it doesn't cover these bindings.

Likely fix, the established pattern

  1. Move the split-intermediate create / free / re-create (and its descriptor writes) out of the open command buffer, into the pre-step before the frame's command buffer begins, as resizeProbesIfNeeded does.
  2. On free, write 1×1 placeholders into draw set 0 bindings 41–43 and set 3, so no bound set names a destroyed view.
  3. Keep retire for anything a frame in flight may still use.
  4. Also fold in two hardening changes:
    • tag the VISR_* flags in pad0, because of the cluster view index collision;
    • retire instead of destroy in destroyDeferSplitTargets when called mid-frame.

Impact: players who change the split lighting setting in-world can crash. It also blocks making single-pass ("uber") lighting the default on Pascal-class cards, which measured about −1.4 ms at 4K on a GTX 1080 at Firestorm-equivalent settings.

Repro: at 4K, live RenderVKDeferredSplit 1 → 0. To check a fix, repeat 1 → 0 → 1 three times, with an offscreen snapshot after each 0.

**Symptom:** switching `RenderVKDeferredSplit` from 1 to 0 in a running session (deferred lighting on) loses the GPU within 1–3 frames, every time. Seen on a GTX 1080 with NVIDIA 580 on Linux at 3840×2062. The kernel log shows `NVRM: Xid 31 ... MMU Fault: ENGINE GRAPHICS GPC0 GPCCLIENT_T1_x ... FAULT_PDE ACCESS_TYPE_READ`, meaning the texture unit read unmapped memory. The breadcrumbs end at `g_p2_barrier` (right after deferred lighting, before pass 2). The log shows `VKDeferSplit: intermediates freed (split lighting off)` just before the loss. An offscreen snapshot taken after the switch hits the same fault. With split lighting off from login, so the intermediates are never created, snapshots and rendering are fine. **What's established** - The free in `deferSplitFrame` (`vkDeviceWaitIdle` + `destroyDeferSplitTargets`) runs inside `recordWorld`, after the frame's command buffer has begun. - Delaying the destroy by a couple of frames (retire instead of destroy) only moves the fault to the frame the images are finally destroyed. So some GPU work keeps reading the split intermediates in **every** frame after the switch, not only the switch frame. - `ensureDeferSplitTargets` writes set 3 and draw set 0 bindings 41–43 (visibility reuse) **under the open command buffer**. Set 0 is PARTIALLY_BOUND, not UPDATE_AFTER_BIND, and `resizeProbesIfNeeded` (#521) documents that this is invalid. On free, nothing rewrites set 0's bindings 41–43 or set 3, so bound sets keep views of destroyed images. - **Not the cause** (tested): - The no-stall resize copy-on-write swaps: `RenderVKResizeNoStall 0` still crashes. - `RenderVKDeferVisReuse 0` before enabling split still crashes (bindings 41/42 still point at the sun / projector images). - A tag on the `pad0` visibility-reuse flags. Cluster draws store their view index in `pad0`, so an odd index read as `VISR_ON`, which is a separate wrong-visibility bug while split lighting runs. - `RenderVKDebugDescriptorTracking` reported 0 stale binds, so it doesn't cover these bindings. **Likely fix, the established pattern** 1. Move the split-intermediate create / free / re-create (and its descriptor writes) out of the open command buffer, into the pre-step before the frame's command buffer begins, as `resizeProbesIfNeeded` does. 2. On free, write 1×1 placeholders into draw set 0 bindings 41–43 and set 3, so no bound set names a destroyed view. 3. Keep retire for anything a frame in flight may still use. 4. Also fold in two hardening changes: - tag the `VISR_*` flags in `pad0`, because of the cluster view index collision; - retire instead of destroy in `destroyDeferSplitTargets` when called mid-frame. **Impact:** players who change the split lighting setting in-world can crash. It also blocks making single-pass ("uber") lighting the default on Pascal-class cards, which measured about −1.4 ms at 4K on a GTX 1080 at Firestorm-equivalent settings. **Repro:** at 4K, live `RenderVKDeferredSplit` 1 → 0. To check a fix, repeat 1 → 0 → 1 three times, with an offscreen snapshot after each 0.
sky_line added this to the Slipstream project 2026-10-17 15:51:08 +00:00
Author
Owner

Fixed in 1.4.1 (3a0437bffe). Reopen if you still see it.

Fixed in 1.4.1 (3a0437bffe). Reopen if you still see it.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream#809
No description provided.