Bug 503827 - When changing songs with screen blanked, kscreenlocker_greet burns over 1 CPU core reloading media control icon
Summary: When changing songs with screen blanked, kscreenlocker_greet burns over 1 CPU...
Status: CONFIRMED
Alias: None
Product: plasmashell
Classification: Plasma
Component: Screen locking (other bugs)
Version First Reported In: 6.3.4
Platform: Other Linux
: NOR normal
Target Milestone: 1.0
Assignee: Plasma Bugs List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-05-06 06:11 UTC by nyanpasu64
Modified: 2025-06-18 16:57 UTC (History)
2 users (show)

See Also:
Latest Commit:
Version Fixed/Implemented In:
Sentry Crash Report:


Attachments
Terminal log of stack traces. (163.61 KB, text/html)
2025-05-06 06:11 UTC, nyanpasu64
Details
Different terminal log of stack traces. (43.35 KB, text/html)
2025-05-06 09:02 UTC, nyanpasu64
Details
Test audio files used to reproduce CPU burn in VLC. (536.55 KB, application/zip)
2025-06-18 02:07 UTC, nyanpasu64
Details

Note You need to log in before you can comment on or make changes to this bug.
Description nyanpasu64 2025-05-06 06:11:15 UTC
Created attachment 180982 [details]
Terminal log of stack traces.

SUMMARY
If I let a computer running KDE idle until the screen locks and turns off, then initiate song changes in mpd with mpd-mpris enabled, kscreenlocker_greet enters an infinite loop of decoding the album image until you tap a key to wake the screen.

STEPS TO REPRODUCE
This bug happens at random every few weeks on my server laptop with sleep disabled. Here are instructions to replicate it at will.

1. Install and `systemctl enable` mpd and mpd-mpris.
2. Load some songs with album art (which will show in KDE's lock screen)
3. Stop mpd playback.
4. Press Win+L to lock the screen (spawning kscreenlocker_greet), then wait until the screen goes black (or press Esc).
5. ssh into the machine and run:

sudo sh -c 'DEBUGINFOD_URLS=https://debuginfod.archlinux.org gdb -p `pgrep kscreenlocker`' (you may not need the full command if you can run gdb -p without root.) (replace DEBUGINFOD_URLS with distro of your choice)
b QQuickImageBase::loadPixmap
c

(When running gdb on system packages, watch for OOM errors, due to https://sourceware.org/bugzilla/show_bug.cgi?id=23710#c24. I even got a kernel panic once!)

6. Start a second ssh session to the machine and run htop to monitor CPU usage. (When I initially discovered this bug without htop running, I discovered it through fan noise.)
7. Using a mpd client of your choice, shuffle your song list, start playing a song (should breakpoint kscreenlocker_greet, if LTO with considerable delay), then press Next in the music player twice to begin playing 3 songs for a few seconds eaach (the images may not have to be different since kscreenlocker_greet decodes an image even when switching songs in the same album).
8. In gdb, type c a few times, then dis, then c again.

OBSERVED RESULT
kscreenlocker_greet burns over an entire CPU core until you press a key to show the UI.

EXPECTED RESULT
kscreenlocker_greet doesn't burn a CPU core.

SOFTWARE/OS VERSIONS
Operating System: Arch Linux 
KDE Plasma Version: 6.3.4
KDE Frameworks Version: 6.13.0
Qt Version: 6.9.0
Kernel Version: 6.14.4-arch1-1 (64-bit)
Graphics Platform: Wayland
Processors: 4 × Intel® Core™ i5-6200U CPU @ 2.30GHz
Memory: 7.6 GiB of RAM
Graphics Processor: Mesa Intel® HD Graphics 520
Manufacturer: LENOVO
Product Name: 80SA
System Version: Lenovo ideapad FLEX 4-1470

ADDITIONAL INFORMATION
Comment 1 nyanpasu64 2025-05-06 09:02:18 UTC
Created attachment 180987 [details]
Different terminal log of stack traces.

I've done a great deal of debugging about this issue.

- The bugged state is an infinite loop of QQuickImageBase::requestFinished (std::swap(d->pendingPix, d->currentPix)) → QQuickImage::pixmapChange → QQuickImage::updatePaintedGeometry → QQuickItem::setImplicitSize(full image dimensions) → QQuickImage::geometryChange → ...(property bindings) QQuickImageBase::loadPixmap (d->pendingPix->load(the same image again)).

- The bug does *not* happen if QQuickImage::updatePaintedGeometry operates on a d->currentPix of size 108x108 (*not* full image dimensions). This translates to setImplicitSize(108, 108), exactly twice the image item's existing dimensions of 54x54 (is this a DPI scaling thing? I'm on 1.25x.), which never calls QQuickImage::geometryChange.

    - I forgot what I did to exercise this test case... maybe lock the screen with a song playing *then* switch songs?
    - TODO what controls the size of pendingPix/currentPix being loaded?

- If you only play one song, the bug sometimes but not always happens.
- Debugging tip: you can use `loginctl unlock-session 2; sleep 1; loginctl lock-session 2` to restart the lock screen.

What normally happens?

- The album art is normally set by OrgFreedesktopDBusPropertiesInterface::PropertiesChanged → ... PlayerContainer::updateFromMap (this=<optimized out>, map=<optimized out>) at /usr/src/debug/plasma-workspace/plasma-workspace-6.3.4/libkmpris/playercontainer.cpp:638.
- In one of my runs, `QQuickLayout::updatePolish -> ... QQuickGridLayoutItem::setGeometry -> ... QQuickItem::geometryChange` loaded the same image a second time after D-Bus/PlayerContainer set it initially.
    - TODO does this terminate the CPU usage when you wake the screen?

What controls the size of an image being loaded?

- QQuickImage::updatePaintedGeometry() checks d->currentPix->width() and height(). These come from QQuickImageBase::loadPixmap (d->pendingPix->load(the same image again)), and the subsequent callback QQuickImageBase::requestFinished (std::swap(d->pendingPix, d->currentPix)).
    - QQuickImageBase::loadPixmap passes in d->sourcesize. This has width 0, and height 108 with the UI visible and 1976 with the UI blanked (during the bug). I wonder if QQuickLayout::updatePolish above sets the size.

With the image hidden, why does QQuickItem::setImplicitSize detect a geometry change?

- QQuickItem::setImplicitSize() sets d->implicit*, then calls d->width.setValueBypassingBindings(w) etc. on the input pixmap's size (matching the album art's size). This should ensure the next call with the same size sees wDone = hDone = true, returning before the call to geometryChange(). Why does d->width get set to 0 before the next call?
- If I run `p &(d->width.val)\n (double *) 0x64c7333990f0` and `watch *(double *) 0x64c7333990f0`, this shows that QQuickItem::setImplicitSize() is setting d->width = (image width). If I run `fin`, on the same line *without the function even returning* it sets d->width = 0.
    - Not sure, it appears the first call to geometryChange has some inline function frames which invoke QQuickItem::setImplicitSize() to 0 (missing in gdb's bt)?

How many d->pendingPix->load() requests are in flight simultaneously?
- IDK. 1? mpd-mpris only leaves one image in /tmp/mpd_mpris/ at a time, all old ones are deleted.

How do you prevent this CPU burn incident?
- IDK, maybe don't try to load an image while the UI is hidden?
    - Is this an upstream Qt Quick bug with QQuickItem::setImplicitSize failing and hitting undefined behavior?
- I don't know how all the QML bindings are arranged that QQuickImage::geometryChange tries to decode the image again.
Comment 2 nyanpasu64 2025-06-11 01:44:59 UTC
Simpler reproducer:

- Locate a song with album art: lock the screen, then switch songs until album art appears on the lock screen. Then unlock the screen.
- In mpd, play a song with no album art.
- In KDE, lock your screen and press Esc for the screen to go dark.
- In mpd, switch to playing a song with album art.

I've tested this three times and gotten CPU burn each time, with no failures to reproduce (so far).

This bug may also happen when a regular music player switches songs, though I have not tested.
Comment 3 Nate Graham 2025-06-12 17:44:26 UTC
So you have to change the song manually while the screen is locked? How exactly are you accomplishing that?
Comment 4 nyanpasu64 2025-06-12 23:14:31 UTC
mpd is a media player daemon that allows you to play songs on a server while controlling it remotely through desktop or web apps (like MyMPD server, MALP on Android, or KDE Connect to interact with mpd-mpris). If you're willing to wait longer, you can *wait for a song to finish playing* and move on to another one with album art (I cheated by seeking to the end of the previous song and waiting for it to finish).

I think the bug specifically happens with the "Fire Emblem Fates from khinsider" album art (1112x1112), and some Touhou songs in the past. It does *not* happen with the Xenogears OST from 81summer.blogspot.com (warning, janky website) album art (400x400); playing the song with screen off does not trigger CPU burn, but waking the screen *prevents* subsequent CPU burn with the screen off. I wonder if the picture has to be sufficiently large to trigger the infinite loop, but don't want to try gdb debugging right now.

Just as a proof of concept, I replicated this bug *without mpd* but just using a bog-standard *VLC media player*. I set a playlist to first play an untagged song, then a song from Fire Emblem Fates (any song should work, Lakeside Song is the smallest file size). After initiating the first song, I locked the screen and pressed Esc to hide the lock screen. Once the second song started playing, ssh->htop revealed that kscreenlocker_greet was burning over one CPU core.
Comment 5 Nate Graham 2025-06-17 21:05:35 UTC
Could you attach two tracks that can be used to reproduce the issue?
Comment 6 nyanpasu64 2025-06-18 02:07:23 UTC
Created attachment 182340 [details]
Test audio files used to reproduce CPU burn in VLC.

I reproduced the bug by loading these two tracks into the VLC playlist (visible by pressing Ctrl+L in VLC).

- Extract the ZIP file to a folder, and open it in Dolphin.
- Ensure Dolphin is sorting by name, so 01blank.ogg comes first.
- Select both files, right-click, Open With > VLC. (Turn down your volume if necessary!)
- Press Win+L to lock the screen, then Esc to hide the UI, before 01blank.ogg finishes playing (takes 15 seconds).

Once 01blank.ogg finishes playing, 02album.flac will play and the CPU burn will begin.
Comment 7 nyanpasu64 2025-06-18 05:52:29 UTC
Incredibly I've found that *playing* the second file *on another computer* (in Audacious) can *remotely* trigger >100% CPU usage.

- Both computers are running KDE and linked via KDE Connect.
- I played 2album.flac in Audacious media player (VLC should also work?). I think this transmits the album art to the computer sitting on its lock screen.
- Pausing the player stops CPU burn until I next stop and start playback (unpausing doesn't resume CPU burn). I suspect this is because the lock screen defaults to "No title\n Choose player automatically".

The CPU burn only happens when the screen is *black*. If I wait for the password field to disappear (but the clock is still visible), then start playback, I can no longer trigger CPU burn (even with screen off) until I unlock and lock the screen again. I think this is because the album art QQuickImage gains a "stable" size (rather than infinitely looping) and keeps it for the remainder of the process lifetime.
Comment 8 Nate Graham 2025-06-18 16:57:55 UTC
Incredible, I can reproduce the issue with the steps in comment 6. Seems like there are shenanigans with the image that we need to sort out.