feat(thumbnails): background thumbnail refresh + manual Update Thumbnails control - #1127
Conversation
|
Heads up: merge #1118 before this one. It touches the same hunk in When this rebases past #1118, fold |
…kground Reset/Apply Settings/Apply Preset and the scan-setup wizard write a new WorkspaceConfig straight to the DB for every non-active target frame, but nothing refreshed that frame's filmstrip thumbnail short of opening it. A new ThumbnailRenderWorker, on its own CPU-only ImageProcessor and off the shared batch lane, re-renders each touched frame and persists its thumbnail without blocking Export or any other real batch. A batch that actually shares norm_thread with it (Auto Crop All, roll analysis) pre-empts it within one frame's processing time instead of waiting out the whole roll.
Auto Crop All and roll analysis correctly cut a running thumbnail refresh short to get norm_thread back, but nothing retried the frames it left behind — they stayed stale until the next unrelated bulk edit touched them, silently. Track which frames a generation didn't get to, fold them into a resume set on cancellation, and re-request them the moment norm_thread is free again; Qt's own queuing keeps this from ever racing the real batch that pre-empted it. Also surfaces a status message when this happens instead of stopping without a trace.
_on_normalization_finished and apply_normalization_roll write a new roll-wide luma/color baseline to every loaded frame's saved settings, the same shape of bulk write Apply Settings/Preset and scan setup already trigger a background thumbnail refresh from — but neither emitted frames_edited_offscreen, so every non-active frame's thumbnail went stale after a batch analysis and stayed that way.
…wire Auto Crop All A bulk write arriving while a resume generation was already using norm_thread (most notably Batch Analysis's own completion write, during the window its own pre-emption opened) was silently dropped instead of retried, reintroducing the exact staleness this feature exists to fix. Fold it into the resume backlog instead. Auto Crop All's own completion handler writes a new crop/rotation to every non-active frame but never offered them for a thumbnail refresh — a sixth unwired bulk-write site, the most visible kind since it's a geometry change. Wired it up the same way as the others. Also drops a status message that was always overwritten in the same call stack before it could ever be seen.
A toolbar button (whole roll) and a context-menu entry (current selection) let the user force the background thumbnail refresh on demand, for staleness an automatic trigger missed or predates one. Both reuse refresh_thumbnails_for unchanged. While one is running, the same control turns into Cancel — a very large accidentally-opened folder needs a way out. Unlike a real batch's pre-emption, cancelling discards the backlog outright instead of resuming it once norm_thread frees up.
…sure The background thumbnail refresh (marcinz606#1127) grows its own preview cache on top of whatever the navigation and Auto Crop All caches already hold, per the coordination note on the marcinz606#1107 thread: it never touches the GPU texture pool (marcinz606#1121) bounds, since its ImageProcessor is CPU-only, but its RAM use was uncoordinated with marcinz606#1121's own memory-safety margin. refresh_thumbnails_for() now checks available system memory against the same MIN_RAM_RESERVE_BYTES reserve marcinz606#1121's prefetch admission uses (promoted from prefetch_policy's private constant) before starting a generation, and retries later instead of proceeding under pressure. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2974e69 to
51af764
Compare
|
Thanks for the note on the #1107 thread about coordinating with #1121's memory work — added in 51af764. GPU needed no coordination: RAM was the real gap: this refresh gets its own Fix: |
# Conflicts: # docs/USER_GUIDE.md # negpy/desktop/view/sidebar/files.py
Summary
Applying settings, a preset, a scan-setup change, or Batch Analysis to more than the
current frame writes straight to the DB for every other touched frame — but nothing
refreshed those frames' filmstrip thumbnails short of opening them by hand.
opening it.
batch is refused because of it.
immediately (within about one frame) instead of waiting it out — the frames that got
cut short are automatically retried once they're done, with a status message so it's
not silent.
render can't reproduce how their canvas joins two half configs.
(current selection) let you force this on demand, for staleness an automatic trigger
missed or predates one. The same control turns into Cancel while it's running —
a very large accidentally-opened folder needs a way out, and unlike a real batch's
pre-emption, cancelling discards the backlog outright instead of resuming it.
How it works
desktop/workers/render.py: newThumbnailRenderWorker, its own CPU-onlyImageProcessorand decode cache, on the existingnorm_thread.desktop/session.py/desktop/controller.py: aframes_edited_offscreensignalfired by every bulk-write path (Apply Settings, Apply Preset, scan setup, Batch
Analysis, Apply Normalization Roll), dispatching
refresh_thumbnails_for._begin_batchpre-empts a running refresh only for the two batch types that actuallyshare its thread (Auto Crop All, Batch Analysis) — everything else runs alongside it
untouched.
desktop/view/sidebar/files.py: the manual toolbar button and context-menu entry,routed through new
request_thumbnail_refresh/cancel_thumbnail_refreshcontrollermethods — same
refresh_thumbnails_forplumbing underneath, no new backend path.Heads up on overlapping open PRs
conflict: it inserts
reset_roll_settingsinsession.pyright afterapply_preset_fields, the exact function this PR adds aframes_edited_offscreen.emit(...)block to the tail of — same hunk. It also edits theidentical
docs/USER_GUIDE.mdright-click-menu sentence this PR does. Both are trivialto resolve by keeping both additions; whichever of us merges second does it by hand.
Separately: this PR's
frames_edited_offscreensignal is wired into Apply Settings,Apply Preset, scan setup, Batch Analysis, and Apply Normalization Roll, but not into
fix(session): let a roll-wide reset undo an unwanted setting (#1047) #1118's
reset_roll_settings— so a roll-wide or selection reset still leaves non-activeframes' thumbnails stale after both land, unless
reset_roll_settingsis later wired toemit it too (or Film strip: two-column negative stats, stale-thumbnail indicator #1115's stale-dot approach lands and catches it structurally instead).
Test plan
make lint/make typecleansignal emit, the manual control's dispatch/cancel behavior, and the real widget
wiring (toolbar button, context menu)
also fails on
main)exporting a frame mid-refresh, Batch Analysis pre-empting and resuming, opening a
different non-active frame mid-refresh, a forced-Slide-mode frame's color
surviving the background render unchanged, the manual Update Thumbnails button
and context-menu entry, and cancelling a roll-wide run mid-flight