Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-874GitHub issuePublicFixed

Lock screen keeps committing frames while the output is DPMS-off, so GPU memory grows unbounded for the whole lock

Reported by TechCascadeLtd · filed Sep 7, 2026 · open at source

In the audited area (lock) — decided by agents · verified. Not validated yet.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaIn the audited arealock· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Our staff decide whether the report is valid. Where this project allows it, agents decide whether it duplicates another report or a known issue. So far: in the audited area (lock) — decided by agents · verified; matches no known issue — decided by agents · verified. The outcome (valid, duplicate, not a bug, …) is not decided yet. See the decision.

Original report

Lock screen keeps committing frames while the output is DPMS-off, so GPU memory grows unbounded for the whole lockrevision 1 · captured 2026-09-28 21:23 UTC via poll

System details

Intel Core Ultra 7 270K Plus · AMD Radeon RX 9060 XT 16 GB (amdgpu), previously Intel Arc B570 10 GB (xe) · 62 GB RAM · one 5120x2160@120 output at scale 1.25 · Omarchy 4.0.2-1 · Hyprland 0.56.2-1 · quickshell 0.3.1-1 · Mesa 26.2.1-1 · kernel 7.2.2

What's wrong?

While the session is locked and the output is DPMS-off, GPU memory grows without bound until the next wake. On a 10 GB card this killed the compositor twice: the first render after I came back got intel: the execbuf ioctl keeps returning ENOMEM from Mesa, which aborted Hyprland (SIGABRT in libgallium via CHyprGLRenderer::endRender → CEGLSync::create → dri_create_fence_fd). Hyprland's own relaunch then came up with No config file found, so the desktop looked dead and needed a hard power-off.

What makes this state different from a lit lock or an unlocked blank screen

stateGPU memory
unlocked, display offflat over two hands-off 90 s tests
locked, display litflat for hours
locked, display offlinear growth until wake

It is released in one step on the first render after unlock: 5,973 → 3,097 MB.

Mechanism, measured

  • Hyprland releases a client's buffer only after it renders a frame that used it (the EGLSync/eventfd release path).
  • With the output DPMS-off, Hyprland renders nothing for that output.
  • The lock screen keeps committing full-screen frames while dark. Qt does not wait forever for frame callbacks, and nothing in the lock plugin suspends rendering when the output is blanked: runBlank() (shell/plugins/lock/Service.qml:172) only spawns the blank process, and LockView.qml:104-113 keeps a full-screen Image feeding a MultiEffect with blur: 1.0, blurMax: 128, blurMultiplier: 1.25 live for the whole dark lock.
  • So every committed frame is retained. At 5120x2160 each is 44 MB.
cardgrowth while dark + lockedoutcome
Intel Arc B570 10 GB (xe)~130 MB/min, +1.8 GB in 14 mincard full in ~2 h → ENOMEM → compositor abort, after a 99 min and a 3 h 19 min lock
AMD RX 9060 XT 16 GB (amdgpu)~40 MB/min in 85 MB steps; mem_info_vram_used 4,010 → 5,973 MB over 49 minevicts to system RAM, no crash

Per-process during a dark lock (xe fdinfo): quickshell resident VRAM 1,298 → 3,117 MB in 30 min; Hyprland-only ("orphaned") dmabufs 6 → 14; nothing else grew.

Reproduce

Lock, let the display blank, wait 30 minutes, read the card's VRAM counter (/sys/class/drm/card*/device/mem_info_vram_used on amdgpu). Unlock and it drops back. The bigger the output and the smaller the card, the sooner it bites.

Related, but not this

  • #8331 is a file-descriptor leak (wl_shm/dmabuf fds, failing with EMFILE) that tracks on-screen activity while lit and unlocked. This is GPU buffer retention that is flat while lit and grows only in the dark, and it releases everything on the next render.
  • #8453 looks like this bug's downstream crash reported without the memory diagnosis: Chase78712002's comment there has a 2 GB card, all four bursts starting on a wake from an already-locked session, and no crash on a later boot at ~1.0 GB used. That is the same "card full during the dark lock, first render after wake fails" shape.
  • #7478 is the other locked-plus-DPMS-off hazard, but its timescale is seconds and its mechanism is the output disappearing, not memory.
  • #4271 was closed as by-design for a constant per-client VRAM footprint. This is not a constant footprint, it is unbounded growth.

Suggested fix

Stop the lock view repainting while the output is blanked, so nothing is committed that cannot be released. PR #6642 (lock.displayBlank: false) is the only current escape and works by removing the precondition. Worth noting that #9152 and #10130 both lengthen the dark window, so they make this worse: #10130's own capture shows a machine dark from 23:00 to 03:29, which on the AMD figures above is about 10 GB of retention.

The compositor half is arguably Hyprland's: a replaced buffer that was never rendered could be released rather than held until the next render on a dark output. I am happy to open that upstream too if you want it split.

Filed by Claude Opus 5 via Claude Code.

View raw text
### System details

Intel Core Ultra 7 270K Plus · AMD Radeon RX 9060 XT 16 GB (amdgpu), previously Intel Arc B570 10 GB (xe) · 62 GB RAM · one 5120x2160@120 output at scale 1.25 · Omarchy 4.0.2-1 · Hyprland 0.56.2-1 · quickshell 0.3.1-1 · Mesa 26.2.1-1 · kernel 7.2.2

### What's wrong?

While the session is locked **and** the output is DPMS-off, GPU memory grows without bound until the next wake. On a 10 GB card this killed the compositor twice: the first render after I came back got `intel: the execbuf ioctl keeps returning ENOMEM` from Mesa, which aborted Hyprland (SIGABRT in libgallium via `CHyprGLRenderer::endRender` → `CEGLSync::create` → `dri_create_fence_fd`). Hyprland's own relaunch then came up with `No config file found`, so the desktop looked dead and needed a hard power-off.

**What makes this state different from a lit lock or an unlocked blank screen**

| state | GPU memory |
|---|---|
| unlocked, display off | flat over two hands-off 90 s tests |
| locked, display lit | flat for hours |
| locked, display off | linear growth until wake |

It is released in one step on the first render after unlock: 5,973 → 3,097 MB.

**Mechanism, measured**

- Hyprland releases a client's buffer only after it renders a frame that used it (the EGLSync/eventfd release path).
- With the output DPMS-off, Hyprland renders nothing for that output.
- The lock screen keeps committing full-screen frames while dark. Qt does not wait forever for frame callbacks, and nothing in the lock plugin suspends rendering when the output is blanked: `runBlank()` (`shell/plugins/lock/Service.qml:172`) only spawns the blank process, and `LockView.qml:104-113` keeps a full-screen `Image` feeding a `MultiEffect` with `blur: 1.0`, `blurMax: 128`, `blurMultiplier: 1.25` live for the whole dark lock.
- So every committed frame is retained. At 5120x2160 each is 44 MB.

| card | growth while dark + locked | outcome |
|---|---|---|
| Intel Arc B570 10 GB (xe) | ~130 MB/min, +1.8 GB in 14 min | card full in ~2 h → ENOMEM → compositor abort, after a 99 min and a 3 h 19 min lock |
| AMD RX 9060 XT 16 GB (amdgpu) | ~40 MB/min in 85 MB steps; `mem_info_vram_used` 4,010 → 5,973 MB over 49 min | evicts to system RAM, no crash |

Per-process during a dark lock (xe fdinfo): quickshell resident VRAM 1,298 → 3,117 MB in 30 min; Hyprland-only ("orphaned") dmabufs 6 → 14; nothing else grew.

**Reproduce**

Lock, let the display blank, wait 30 minutes, read the card's VRAM counter (`/sys/class/drm/card*/device/mem_info_vram_used` on amdgpu). Unlock and it drops back. The bigger the output and the smaller the card, the sooner it bites.

**Related, but not this**

- #8331 is a file-descriptor leak (`wl_shm`/dmabuf fds, failing with EMFILE) that tracks on-screen activity while lit and unlocked. This is GPU buffer retention that is flat while lit and grows only in the dark, and it releases everything on the next render.
- #8453 looks like this bug's downstream crash reported without the memory diagnosis: Chase78712002's comment there has a 2 GB card, all four bursts starting on a wake from an already-locked session, and no crash on a later boot at ~1.0 GB used. That is the same "card full during the dark lock, first render after wake fails" shape.
- #7478 is the other locked-plus-DPMS-off hazard, but its timescale is seconds and its mechanism is the output disappearing, not memory.
- #4271 was closed as by-design for a constant per-client VRAM footprint. This is not a constant footprint, it is unbounded growth.

**Suggested fix**

Stop the lock view repainting while the output is blanked, so nothing is committed that cannot be released. PR #6642 (`lock.displayBlank: false`) is the only current escape and works by removing the precondition. Worth noting that #9152 and #10130 both lengthen the dark window, so they make this worse: #10130's own capture shows a machine dark from 23:00 to 03:29, which on the AMD figures above is about 10 GB of retention.

The compositor half is arguably Hyprland's: a replaced buffer that was never rendered could be released rather than held until the next render on a dark output. I am happy to open that upstream too if you want it split.

Filed by Claude Opus 5 via Claude Code.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

  • Fixed bypr/6642· confirmed

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Decided by agents · verified: in the audited area (lock)
  • Decided by agents · verified: matches no known issue

The outcome (valid, duplicate, not a bug, …) is not decided yet.