perf(thumbnails): stream filmstrip previews in background - #1107
Conversation
|
AI-assisted comment (model: GPT-6). With several thumbnail and preview PRs open, I wanted to make the dependencies and integration work for my contributions easier to follow. Four of my PRs form a stack, split from #1104 into focused changes. Their intended review and merge order is:
Each later PR currently includes the earlier changes. I can rebase the remaining branches after each merge so their diffs show only the next step. If another contributor’s overlapping PR lands first, I can handle the corresponding updates to mine and rerun the checks. My fifth open PR, #1058 — Metadata-based lens correction for Sony ARW and DNG, is a separate feature and can be reviewed separately from this stack. A compatibility review of #1107/#1119 against the other open work found:
The full Linux checks on #1119, including #1107, also passed: 5,654 tests passed, with lint, type, and format checks clean. Would starting with #1107 and proceeding through the stack fit your preferred review workflow? I’m happy to handle the rebases and integration follow-ups to keep the work on your side small. |
…rotate Reported on the marcinz606#1107 thread's compatibility review of marcinz606#1124: rotating a frame while generate_missing_thumbnails is still decoding it left the thumbnail in the old orientation. rotate_thumbnails/flip_thumbnails only turn a thumbnail already cached in memory or on disk — a frame mid-decode has neither yet, so the turn was silently dropped, and the decode's own result (get_thumbnail_worker never reads saved geometry) then landed and persisted to disk in the old orientation, served back verbatim on every later request. _turn_thumbnails now queues the turn in _thumbnail_pending_correction when disk has nothing yet, and _apply_thumbnails replays it onto that decode's own delivery before committing it to memory and disk. Pruned against the current roll so a removed-then-re-added file with the same content hash never inherits a stale queued turn. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…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>
…ails control (#1127) * feat(thumbnails): re-render bulk-edited frames' thumbnails in the background 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. * fix(thumbnails): resume a background refresh a real batch pre-empted 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. * fix(thumbnails): wire Batch Analysis into the background refresh too _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. * fix(thumbnails): don't drop a bulk write that lands mid-pre-emption, 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. * feat(thumbnails): manual Update Thumbnails control, cancellable 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. * fix(thumbnails): defer a background refresh started under memory pressure The background thumbnail refresh (#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 #1107 thread: it never touches the GPU texture pool (#1121) bounds, since its ImageProcessor is CPU-only, but its RAM use was uncoordinated with #1121's own memory-safety margin. refresh_thumbnails_for() now checks available system memory against the same MIN_RAM_RESERVE_BYTES reserve #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> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Marcin Zawalski <zawalskimarcin@gmail.com>
* feat(rotate): batch rotate and flip across a multi-selection The 90° rotate/flip toolbar buttons and shortcuts previously only ever touched the active frame. They now fan out to every other selected thumbnail too, each turned relative to its own saved geometry, with undo history recorded per frame and their filmstrip thumbnails turned in place. A selection that has explicitly excluded the active frame (ctrl-click toggled off) skips it too, matching toggle_mark's rule that selection wins over "what's on screen". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(rotate): correct a background thumbnail decode that outraces the rotate Reported on the #1107 thread's compatibility review of #1124: rotating a frame while generate_missing_thumbnails is still decoding it left the thumbnail in the old orientation. rotate_thumbnails/flip_thumbnails only turn a thumbnail already cached in memory or on disk — a frame mid-decode has neither yet, so the turn was silently dropped, and the decode's own result (get_thumbnail_worker never reads saved geometry) then landed and persisted to disk in the old orientation, served back verbatim on every later request. _turn_thumbnails now queues the turn in _thumbnail_pending_correction when disk has nothing yet, and _apply_thumbnails replays it onto that decode's own delivery before committing it to memory and disk. Pruned against the current roll so a removed-then-re-added file with the same content hash never inherits a stale queued turn. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Marcin Zawalski <zawalskimarcin@gmail.com>
AI-assisted comment (model: GPT-5).
Summary
Relation to #1104
This is the first focused extraction from #1104. As noted in the split comment, the larger draft is being divided into smaller PRs before review.
This PR contains only filmstrip orchestration and presentation. Source decoding is unchanged. Bounded DNG and LinearRaw loading, adaptive GPU prefetch and memory accounting, and the half-frame and IR preview fixes will follow separately.
Verification