Skip to content

perf(mister): fade grid covers in the presenter - #591

Merged
wizzomafizzo merged 2 commits into
mainfrom
perf/presenter-cover-fade
Nov 2, 2026
Merged

wizzomafizzo merged 2 commits into
mainfrom
perf/presenter-cover-fade

Conversation

@wizzomafizzo

@wizzomafizzo wizzomafizzo commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Grid covers fade in again on a MiSTer HDMI render. The fade now runs in the presenter instead of in Slint, so a page of covers landing no longer repaints the grid every frame.

Closes #538

Cover fade

  • Slint paints a landed cover once, at full strength. The presenter keeps the pixels that were under it, narrows them to the pixels the cover changed, and for 180 ms mixes them into each row it publishes (frame_transition::CoverFades). Slint keeps rendering everything else.
  • A fade ends early, showing what Slint painted, when Slint repaints its pixels with something else (focus ring, page change, modal), when a page slide starts, or when the frame changes size.
  • All three presenters run it (vblank latch, fb0, native CRT). The CRT head of a dual-head pair mirrors state rather than pixels, so it keeps Slint's fade.
  • Covers for the page on screen are held until the page has them all or the first has waited 150 ms, then land in one frame (zaparoo_app::cover_landing). Covers fetched a few at a time would otherwise each cost a slow frame while earlier ones were fading.
  • Only art fetched from Core fades (GridCell.fetched). Built-in system logos cut in. A placeholder colour that arrives while its tile is on screen fades in too.
  • Off under Reduce motion and on a 1080p-or-taller MiSTer render, as before. The hold is off there too.
  • On the DE10-Nano at 960x540, frames that only advance fades cost about 2.6 ms. Frames Slint draws during fades now cost about the same as frames without them.

Motion timings

What Was Now
List and menu scroll on one press (Motion.scroll-ms) 240 ms 120 ms
Accept press-feedback wait 90 ms 50 ms
Page slides (Hub, Systems, Games, MiSTer cached slide) 240 ms ease-in-out 200 ms ease-out (12 frames)
Focus zoom, desktop 160 ms 110 ms
Detail-pane cover fade 180 ms 120 ms
  • The options menu scrolls at the repeat pace when a key is held, the way the browse lists do, instead of restarting a 240 ms ease on every repeat.

Other

  • Screen titles take the width their neighbours leave, never less than the old third, instead of a fixed third. This covers the top bar and the CRT header.
  • Options menu pages (Manage, Write to token, discs, alternate versions) no longer show a title.
  • Detail pane metadata from Core is kept in memory (256 KB, least recently used out, cleared when a scrape or reindex finishes). The rows above and below are fetched once the selection rests, so stepping onto a neighbour no longer blanks the metadata.
  • Fast-scroll rail in the HDMI list layout sits inside the card, inset by its padding, instead of straddling the card's border.

Testing

  • just lint and just test pass. New tests cover the fade compositor, RGB565 mixing, landing detection, the landing hold, the detail metadata cache, and the cover-fade route test for fetched art and logos.
  • Run on a DE10-Nano over HDMI (latch presenter, 960x540): frame timings measured with temporary logging, which is removed in this PR.
  • Not run on hardware: native CRT, fb0 and dual head.

Summary by CodeRabbit

  • New Features
    • Newly loaded cover art now fades into grid tiles and detail panes, with coordinated timing as page artwork arrives.
    • Game details can appear more quickly when browsing between nearby items.
  • Improvements
    • Scrolling and page transitions use more consistent motion, with updated timing.
    • Context menus no longer display a page title.
    • Button-press feedback is shorter, and cover and zoom animations have updated durations.
  • Documentation
    • Updated guidance on scrolling, cover fades, and motion settings.

Slint paints a landed cover once and the MiSTer presenters mix the
pixels that were under it into each published row for the fade, so a
page of covers no longer repaints the grid every frame. Covers for the
page on screen land together, only art fetched from Core fades, and a
placeholder colour that arrives in place fades too.

Also: browse titles size from their neighbours instead of a fixed
third, shorter list scroll, Accept, page slide and zoom timings, the
options menu follows a held key and drops its page titles, the detail
pane caches Core's metadata and fetches its neighbours, and the
fast-scroll rail sits inside the HDMI list card.
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f7f6a7e8-693d-4ee0-b2e3-6558250c9d60

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 2ce805a6-cfa7-41d2-9b43-7eb95e85e47b
Commits

Reviewing files that changed from the base of the PR and between 8f34289 and 4a4b3b4.

Files selected for processing: 30
  • docs/slint-gotchas.md
  • docs/style.md
  • rust/frontend/src/cover_fade.rs
  • rust/frontend/src/display.rs
  • rust/frontend/src/dual_head.rs
  • rust/frontend/src/frame_transition.rs
  • rust/frontend/src/games.rs
  • rust/frontend/src/hub.rs
  • rust/frontend/src/lib.rs
  • rust/frontend/src/mister/ddr.rs
  • rust/frontend/src/mister/fb0.rs
  • rust/frontend/src/mister/latch.rs
  • rust/frontend/src/mister/mod.rs
  • rust/frontend/src/mister/platform.rs
  • rust/frontend/src/mister/transition.rs
  • rust/frontend/src/route_motion.rs
  • rust/frontend/src/router.rs
  • rust/frontend/src/systems.rs
  • rust/frontend/src/view_model.rs
  • rust/frontend/translations/frontend.pot
  • rust/frontend/ui/app.slint
  • rust/frontend/ui/browse_list.slint
  • rust/frontend/ui/chrome.slint
  • rust/frontend/ui/setup.slint
  • rust/frontend/ui/theme.slint
  • rust/frontend/ui/tiles.slint
  • rust/zaparoo-app/src/cover_landing.rs
  • rust/zaparoo-app/src/input.rs
  • rust/zaparoo-app/src/lib.rs
  • rust/zaparoo-app/src/media_list.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

This PR adds presenter-side grid-cover fades on MiSTer and coordinates cover arrivals. It adds a cache for focused-detail metadata. It also updates scrolling, transition timing, context-menu layout, and header sizing.

Changes: Grid-cover fade pipeline

Layer / File(s) Summary
Identify and coordinate cover arrivals
rust/frontend/src/view_model.rs, rust/frontend/ui/tiles.slint, rust/frontend/src/games.rs, rust/frontend/src/hub.rs, rust/zaparoo-app/src/cover_landing.rs, rust/frontend/src/lib.rs
Cell publication reports newly landed fetched art. On MiSTer, cover arrivals can be held while the active Games or Hub page is waiting for covers, then published together or after the hold expires.
Map cover regions and compose fades
rust/frontend/src/cover_fade.rs, rust/frontend/src/frame_transition.rs, rust/frontend/src/mister/mod.rs, rust/frontend/src/mister/transition.rs
The frontend maps newly landed cells to rectangles. The fade compositor captures underlying pixels, mixes them with the landed cover over 11 frame periods, and ends fades when repaint, slide, or frame-size changes occur. Slide easing and browse transition duration also change.
Integrate fades with MiSTer presentation
rust/frontend/src/mister/ddr.rs, rust/frontend/src/mister/fb0.rs, rust/frontend/src/mister/latch.rs, rust/frontend/src/mister/platform.rs
The presenters mix fade output into copied rows or rectangles and publish fade damage. Platform loops present active fades when no normal frame renders.
Select fade policy and document behavior
rust/frontend/src/display.rs, rust/frontend/src/lib.rs, rust/frontend/ui/theme.slint, rust/frontend/ui/tiles.slint, rust/frontend/src/route_motion.rs, docs/slint-gotchas.md
Display seeding selects presenter or Slint tile fades. Tests distinguish fetched art from built-in logos. Documentation describes renderer-specific fades and updated reveal and zoom durations.

Frontend motion and layout

Layer / File(s) Summary
Update scrolling and motion timing
rust/frontend/ui/theme.slint, rust/frontend/ui/app.slint, rust/frontend/ui/browse_list.slint, rust/frontend/ui/setup.slint, rust/frontend/src/games.rs, rust/frontend/src/hub.rs, rust/frontend/src/systems.rs, rust/zaparoo-app/src/input.rs, docs/style.md, docs/slint-gotchas.md
A 120 ms Motion.scroll-ms duration is applied to scrolling controls. Page and swoop timings change, and press feedback changes from 90 ms to 50 ms.
Adjust context-menu navigation and layout
rust/frontend/ui/app.slint, rust/frontend/src/router.rs, rust/frontend/src/dual_head.rs
The context menu no longer reserves a title band. Held-key navigation supplies a repeat interval used for steady row scrolling, and the dual-head overlay mirrors the new timing property.
Size header titles around side content
rust/frontend/ui/chrome.slint, rust/frontend/ui/app.slint, rust/frontend/translations/frontend.pot
Header title sizing uses measured side-content widths. The non-CRT list fast-scroll rail is inset within its card. The translation catalog refreshes source references without changing message IDs or translations.

Focused-detail metadata cache

Layer / File(s) Summary
Cache and prefetch detail metadata
rust/zaparoo-app/src/media_list.rs, rust/zaparoo-app/src/lib.rs, rust/frontend/src/games.rs, rust/frontend/src/lib.rs
A bounded LRU cache stores detail rows by identity. The games view reads cached details, prefetches eligible neighbors, and clears the cache when media changes or jobs complete.

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant MediaEvents
  participant Frontend
  participant GamesHub
  participant ViewModel
  participant PresenterFades
  participant Presenter
  MediaEvents->>Frontend: deliver settled covers
  Frontend->>GamesHub: coordinate cover landing
  GamesHub->>ViewModel: publish grid cells
  ViewModel->>GamesHub: return newly landed indices
  GamesHub->>PresenterFades: request cover rectangles
  PresenterFades->>Presenter: provide mixed fade rows and damage bounds
Loading
Merge Risk: Low · previous review 4a4b3

Held context-menu scrolling may look uneven, an inactive cover fade may waste presentation work, and detail metadata may remain stale after an update. The PR is mergeable with owner acceptance of these fixes or follow-up.

Pre-merge checks: Passed 2 · Failed 2 · Inconclusive 1

Failed Failed checks: 2 warnings · 1 inconclusive

Check name Status Explanation Resolution
Out of Scope Changes check Warning The PR includes changes with no demonstrated connection to issue [#538]. These include detail metadata caching and prefetching, options-menu title removal and scrolling, title-width layout changes, fa… Remove the unrelated UI and metadata-cache changes from this PR, or link separate active issues that define their coding requirements and submit them as separate scoped changes. Retain changes that directly support the presenter cover fade,…
Docstring Coverage Warning Docstring coverage is 52.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check Inconclusive The description covers the required template sections: Summary (the opening paragraph), Motivation (Closes #538), Test plan (the Testing section, including the hardware tested and the untested present… Add a Screenshots / recordings section. The template requires one for visual changes. Include 720p and, if possible, 240p captures, or run just snapshots and attach the output. Tick the checklist items that the author has completed, or st…
Passed Passed checks: 2 passed
Check name Status Explanation
Title check Passed The title "perf(mister): fade grid covers in the presenter" names the main change: grid-cover fades moved from Slint into the MiSTer presenter. The changeset matches this, including cover_fade.rs, fra…
Linked Issues check Passed Issue [#538] requires presenter-side cover fades, early termination when other content changes, rectangle mapping including rotated layouts, support for vblank latch, fb0, native CRT, and dual-head ha…
Full details: Title check

Explanation

The title "perf(mister): fade grid covers in the presenter" names the main change: grid-cover fades moved from Slint into the MiSTer presenter. The changeset matches this, including cover_fade.rs, frame_transition.rs CoverFades, and the presenter integrations in mister/latch.rs, fb0.rs, and transition.rs. The title omits secondary changes such as motion timings, cover landing hold, and metadata caching, which the title does not need to cover.

Full details: Linked Issues check

Explanation

Issue [#538] requires presenter-side cover fades, early termination when other content changes, rectangle mapping including rotated layouts, support for vblank latch, fb0, native CRT, and dual-head handling. CoverFades captures pre-render pixels, narrows repaint damage, mixes rows for 11 frame periods, and ends fades on repaint, overlap, or frame-size changes. request_cover_fades maps and clips scene rectangles through window insets and rotation. PresenterFades is integrated with the presenter transition path, and the platform exposes fade-only presentation for idle turns. The PR summary reports tests for compositor behavior, RGB565 mixing, landing detection, hold timing, and fetched-art versus logo routing. The implementation evidence supports the linked issue's coding requirements.

Full details: Out of Scope Changes check

Explanation

The PR includes changes with no demonstrated connection to issue [#538]. These include detail metadata caching and prefetching, options-menu title removal and scrolling, title-width layout changes, fast-scroll-rail placement, and broad motion-timing changes such as press feedback and detail-pane fades. These changes are separate UI behavior and data-cache work, not presenter-side grid-cover fading.

Resolution

Remove the unrelated UI and metadata-cache changes from this PR, or link separate active issues that define their coding requirements and submit them as separate scoped changes. Retain changes that directly support the presenter cover fade, its landing policy, rendering integration, tests, and documentation.

Full details: Docstring Coverage

Explanation

Docstring coverage is 52.44% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 82 functions across 21 files. (9 skipped: 9 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Full details: Description check

Explanation

The description covers the required template sections: Summary (the opening paragraph), Motivation (Closes #538), Test plan (the Testing section, including the hardware tested and the untested presenters), and the Checklist items for lint and test. The Screenshots / recordings section is absent. The template marks it as required for visual changes, and this PR changes visual behaviour (fades, timings, title sizing, and the fast-scroll rail). The checklist boxes are not ticked, and the ARM32 and dirty-region items are not addressed explicitly.

Resolution

Add a Screenshots / recordings section. The template requires one for visual changes. Include 720p and, if possible, 240p captures, or run just snapshots and attach the output. Tick the checklist items that the author has completed, or state why each one does not apply. In particular, state whether the software renderer dirty-region item and the ARM32 item were checked against docs/slint-gotchas.md and docs/architecture.md.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Fix comments: Fix CodeRabbit comments on this PR

Comment thread rust/frontend/src/frame_transition.rs Resolved
Comment thread rust/frontend/src/games.rs Resolved
Comment thread rust/frontend/src/router.rs Resolved
- A held key in the options menu glides at constant speed: a modal-owned
  repeat is now tracked on its own, without reaching the screen behind.
- A metadata fetch that started before the detail cache was cleared no
  longer puts its result back.
- Only the screen on display requests cover fades, and a request no
  render has taken within 100 ms is dropped.
@wizzomafizzo
wizzomafizzo merged commit d82f1ba into main Nov 2, 2026
6 checks passed
@wizzomafizzo
wizzomafizzo deleted the perf/presenter-cover-fade branch November 2, 2026 21:30
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.

perf(mister): fade grid covers in the presenter instead of in Slint

1 participant