Problem
Under VRAM pressure amdgpu can refuse an atomic commit with ENOMEM (the kernel fails to pin the new framebuffer). The previous frame stays on screen, but NeferWL treated the error as fatal: the output stopped and stayed dark until the next hotplug.
Change
- ENOMEM on a frame, state or modeset commit keeps the output: the last frame stays on screen and the commit retries with a backoff from 16 ms to 1 s, without limit and without the stuck-recovery modeset.
- The frame lifecycle tracks the current wait kind (flip, busy, nomem) apart from the memory-refusal run, so EBUSY after ENOMEM keeps its event unblocking and modeset recovery.
- Direct scanout refused for memory pauses scanout for 2 s and composes into the resident output images.
- Signalled render fences are reaped during retries, so long refusals do not accumulate descriptors.
- Protected (locked) commits keep their existing retry path: a refused frame is never certified or reported.
- Logs: one warn per refusal run, another after 5 s, info
commit recoveredwith attempts and outage.
Checks
make check, make race, make mocks-check, staticcheck ./...; unit tests for backoff, ENOMEM→EBUSY, lasting refusal, modeset retry, scanout fallback, protected path, fence reaping. Not tested on real hardware under memory pressure.
Out of scope: renderer out-of-memory and GBM allocation failures at start/resume still stop the output.