Repository navigation
perf(rendering): cache per-frame bind groups, mask buffers and the resolved wallpaper path - #2871
Merged
Merged
Conversation
…d the resolved wallpaper path
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
richiemcilroy
force-pushed
the
perf/rendering-per-frame-caches
branch
from
October 22, 2026 03:02
3ba2b3c to
9b17c38
Compare
This comment has been minimized.
This comment has been minimized.
…t deterministically
richiemcilroy
force-pushed
the
perf/rendering-per-frame-caches
branch
from
October 22, 2026 03:28
9b17c38 to
0ee475f
Compare
This comment has been minimized.
This comment has been minimized.
richiemcilroy
marked this pull request as ready for review
October 22, 2026 06:23
Member
Author
|
@greptileai review |
| } | ||
|
|
||
| let resolved = match &self.0 { | ||
| Some((cached, resolved)) if cached == path => resolved.clone(), |
There was a problem hiding this comment.
Missing background paths remain cached after the file is restored
Medium Severity
If a project's image is temporarily unavailable on its first render, clean_background_path returns None and this cache retains that result. Restoring the file or reconnecting its drive never reaches BackgroundTextureCache::ensure: subsequent frames keep producing the white fallback. Switching to a color and reselecting the same image also fails because the non-image branches leave this entry intact. Previously, path existence was checked again and the image recovered. Avoid indefinitely caching failed lookups, or provide invalidation and retry when the source is reselected.
This comment has been minimized.
This comment has been minimized.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Per frame, the renderer rebuilt GPU bindings and touched the disk even when nothing they depend on had changed:
String::replacecalls and aPath::existsstat every frame.create_buffer_init) and bind group every frame.This PR builds each of these only when its inputs change. The output is byte-identical.
SourceBindGroupscache keys each bind group by the uniform buffer and the session texture view it samples. That is at most two per buffer, one for each ping-pong texture. Entries for views the session no longer owns are dropped at the start of each render, so a resized session's old textures are released.RendererLayers::rendercalls (the transition path submits the outgoing frame first), which the cursor and display uniforms already rely on.Measurements
Scratch A/B on Blacksmith (
ci/rendering-caches-ab, never merge), based16fd199bvs this branch, in one job per OS. Fixture:cap_verify::fixture10 s 1080p30 display recording, extended with:The "effects" variant also adds a colour grade, blur and pixelate masks, and a 3D camera segment with radial blur. Each bench renders 300 frames at 1920x1080 in a release-style build; the numbers are medians of 7 interleaved rounds. Bind groups and buffers are counted at
wgpu-halcreate calls.macOS 26 (blacksmith-6vcpu-macos-26, Metal)
Linux (blacksmith-8vcpu-ubuntu-2404, lavapipe)
Per frame, the CPU spent in prepare (excluding the display upload) plus layer render drops:
Layer render on the cursor-only scene is a few µs higher on both runners, but the totals above already include that. Frame wall time is dominated by the GPU and readback, and is unchanged within run-to-run noise. Export is encoder- or GPU-bound, so its time moves only slightly (macOS cursor + wallpaper -6%, Linux -4%; effects is flat).
Identity:
per_frame_cachesintegration test also passes on base.Tests
tests/per_frame_caches.rsrenders frames with reused layers and compares them byte for byte with layers built fresh for each frame. The scenarios are recorded cursor images that switch ids, a circle cursor, a wallpaper, a colour grade, blur/pixelate/highlight masks, 3D camera gaussian and bokeh blur, and an animated gradient with background blur. They include a session resize. Windows WARP renders the mask scene differently on identical fresh renders (frame 0 differed between two fresh layer stacks), so that one scene is skipped on WARP. It runs on Metal and lavapipe.per_frame_cache_tests(lib) checks that the cursor bind group stays the same across frames. It deletes the wallpaper after the first frame and checks that the background never falls back. It also checks that mask buffers and colour grade/mask bind groups stop at the expected counts.image_path_is_checked_on_disk_only_when_the_source_changes(background).

Confidence Score: 5/5
The PR appears safe to merge; no actionable issues were found.Summary
Caches GPU bindings, reuses mask buffers, and remembers resolved background paths to reduce work between frames.
Reviews (1) · Last reviewed commit: "test(rendering): skip the mask scene on ..." · Reviewed by Greptile