Skip to content

Stop an idle window from drawing every refresh - #100

Open
thisisgm wants to merge 1 commit into
omacom:mainfrom
thisisgm:idle
Open

thisisgm wants to merge 1 commit into
omacom:mainfrom
thisisgm:idle

Conversation

@thisisgm

Copy link
Copy Markdown

One fix, in one commit with its own test: now and then a Folio window that is doing nothing keeps drawing a frame at every refresh of the screen, with its render thread on about half a core, until it is closed. A race in Qt sets it off, and the cache buffer of Folio's views is what walks into it. The views now make their rows without that buffer. The suite goes from 194 to 197 tests. No library, depends or optdepends entry is added.

What you'd notice

  • An idle window stays idle. A window left open on a folder no longer has a chance of holding half a core and the GPU for as long as it lives, which on a laptop is fan noise and battery.
  • The grid settles sooner on a folder of pictures or videos. At the start it makes thumbnails for fewer rows past the bottom edge: 87 where it made 105, in the window measured below.
  • Nothing else moves. The list and the columns make the same rows as before, and every view draws what it drew.

Numbers

How often it happens depends on timing, so the counts are small and uneven. Measured on a mini PC, cold starts on a folder of 2,000 videos and pictures:

Build Starts Windows that never went idle
0.1.1 24 4
0.1.1 with the cache buffer off 24 0
#26's branch, this week 18 1
main, this week 54 0
Builds with the cache buffer off, this week (18 of them with this commit's settings) 72 0

In each of the four caught on 0.1.1 a probe counted 479 or 480 frames in every 4 seconds on a still, complete window (a 120 Hz screen), for the two minutes it was watched. The one this week used 42.6 s of CPU in the measured window, against about 11 s for its neighbours.

The same folder, thumbnails made anew at each start, page cache dropped, 6 runs a view, main and this branch in one session (the build measured has this commit's view settings; review since then named the 320 and tightened the test):

View First window, main this branch Settled, main this branch CPU, main this branch Memory, main this branch
Grid 906 to 1,007 ms 894 to 1,038 ms 4,533 to 5,194 ms 3,981 to 4,253 ms 18.5 to 19.5 s 16.0 to 16.5 s 156.1 to 163.4 MiB 152.9 to 159.9 MiB
List 853 to 964 ms 892 to 993 ms 2,878 to 3,094 ms 2,966 to 3,226 ms 9.5 to 9.8 s 9.1 to 9.9 s 130.5 to 137.3 MiB 131.1 to 138.0 MiB
Columns 887 to 994 ms 950 to 1,007 ms 2,988 to 3,170 ms 3,058 to 3,365 ms 10.5 to 11.0 s 10.8 to 11.2 s 145.3 to 151.1 MiB 151.8 to 155.6 MiB

On a folder of 100,000 files the two are level in every view: first window 894 to 971 ms against 904 to 959 ms in the grid, memory 235.6 to 236.0 MiB against 229.5 to 240.3 MiB, and the same for the list and the columns.

Holding Down through 300 files in the grid, measured on 0.1.1 with the same change: the time from the key to its frame was 10.3 ms at the median either way, and 13.9 ms at most against 14.9 ms. No frame took longer than one refresh at 60 Hz.

How it works

  • A ListView or GridView with a cache buffer (Qt's default is 320 pixels) fills that buffer later than the rows it shows: each refill starts a 16 ms pause job, bufferPause, in QQuickItemViewPrivate::refill().
  • In QQmlAnimationTimer, a queued stopTimer is skipped while a start is pending. If the pending job is then stopped while it is still in animationsToStart, it is taken off that list and nothing queues another stop. The animation timer stays registered with no job, the animation driver never stops, and the window is redrawn at every refresh. This is Qt Declarative 6.12.0, and the same code is in Qt's dev branch.
  • With cacheBuffer: 0 no pause job is ever started, so the views cannot reach that state.
  • The list and the three lists of the columns get displayMarginBeginning and displayMarginEnd of 320 pixels, which refill() fills at once, with the rows shown and with no timer: the rows that exist are the ones that existed before.
  • The grid gets no margins. A GridView makes a row past each edge by itself, and rows inside a display margin are drawn, not only made: every tile is a layer, and margins there cost 7 MiB on the large folder.

Tests

One new case with a row for each view (grid, list, columns), failing for all three without the commit. It opens the real pane on a folder of 60 entries in a short window, moves the view to its end and back, and checks that in the list and the columns rows reach 320 pixels behind the top edge and as far past the bottom one at once, and that in every view no row is added in the 300 ms after: a cache buffer's timer adds its rows in that time. Eleven mutants, each taking one of the new properties from one view or halving the 320, all fail it.

Limits

  • The columns weigh 3 to 5 MiB more on a folder of thumbnails (the table above), since their margin rows are now drawn. Without margins they would be lighter than main and rows would be made as they scroll in; I kept the rows they had.
  • The race itself is Qt's and is still there for any view that sets a cache buffer. Folio's views no longer do.
  • The counts above say how often it was seen, not how often it will be: it is timing, and main did not show it in this week's 54 starts.

Qt's cache buffer makes them later, from a 16 ms timer of its own, and
a race in Qt can leave that timer running: an idle window then draws a
frame every refresh. The list and the columns make the same rows at
once with display margins; the grid keeps its own row past each edge.
@greptile-apps

greptile-apps Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable defects were found.

Summary

Turns off Qt's deferred cache buffer in the folder views to avoid the reported idle redraw race.

  • Folder views make nearby rows without a delayed cache refill.

Reviews (1) · Last reviewed commit: "Make the rows past a view's edges with t..." · Reviewed by Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant