Skip to content

perf(desktop-gpui): keep waveform paths cached while the timeline scrolls - #2763

Open
richiemcilroy wants to merge 3 commits into
mainfrom
perf/waveform-follow-cache
Open

richiemcilroy wants to merge 3 commits into
mainfrom
perf/waveform-follow-cache

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 20, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #2486.

What

#2486's waveform path cache hits while the timeline is still. But while playback follows the playhead zoomed in, the visible slice slides every frame. That changed the cached geometry's range, origin and clip, so the path was re-tessellated on every frame. The timeline bench (CAP_GPUI_AUTO_TIMELINE_BENCH=1) on main: follow built 299 paths and reused 1 in 300 draws, about +1 ms per frame (2.6 ms mean against 1.8 ms for tick).

Two changes:

  • Paths are built relative to their canvas and moved into place with translated_path at paint time, so a segment that only moves on screen keeps the same cache key.
  • The cached span is waveform_window: the visible slice grown to a window anchored on a quarter-viewport grid (at most 1.5× the zoom span). A scrolling timeline then reuses one path for a quarter-viewport of travel, about one rebuild per 5 s of follow-mode playback at 20 s zoom, instead of one per frame.

Look

  • Whole segment visible (the default zoom, and every segment that fits on screen): the window is exactly the visible slice, so the path is the same as before, just built relative and translated (vertices within 0.01 px).
  • Zoomed in:
    • the sample grid is anchored to the window rather than to the left edge of the view, so it no longer re-samples, and so no longer shimmers, as the view scrolls;
    • sample density stays at waveform_sample_count's 2 samples per pixel over the window;
    • the extra part of the window outside the view is clipped by the segment mask and the timeline's overflow_hidden.

Tests

  • the_waveform_window_always_covers_the_visible_slice
  • a_fully_visible_segment_covers_exactly_its_visible_slice
  • scrolling_reuses_the_window_for_a_quarter_viewport: 60 s of 60 fps follow uses at most 13 windows.
  • a_translated_relative_path_matches_one_built_in_place
  • follow_mode_paths_are_built_once_per_window: at most 3 builds in 600 follow frames, where main builds 600.

RetriggerView in GreptileConfidence Score: 4/5

The PR appears safe to merge, with non-blocking improvements to the scrolling test and waveform detail at the sample limit.

Findings

  1. P2 Scrolling test misses changing positions ▶
  2. P2 Wider windows lose waveform detail ▶
Fix with agent prompt
### Issue 1
apps/desktop-gpui/src/editor_timeline.rs:4766-4769
`follow_mode_paths_are_built_once_per_window` changes only `range`; `origin`, `size`, and `clip_bounds` stay fixed in the helper. Those fields are part of the cache key, and changing screen coordinates caused the original cache misses. This test would still pass if `render_waveform` accidentally used screen coordinates again.

Build the test geometry through the same code as `render_waveform`, vary the canvas position, and check that scrolling within one window still hits the cache.

### Issue 2
apps/desktop-gpui/src/editor_timeline.rs:3268-3270
The wider window shares the existing 6,000-sample limit, leaving fewer samples in view once that limit is reached. For example, a 2,500-pixel viewport showing 1,000 seconds previously requested 5,000 samples. A full 1.5-viewport window now gets 6,000 samples across 1,500 seconds, leaving about 4,000 samples in view.

`waveform_path` reads individual peaks rather than taking the loudest peak between samples, so this can skip more short sounds. Preserve the visible sample budget when sizing the wider window, and add a test for the sample limit.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Keeps waveform paths cached as the timeline scrolls.

  • Zoomed-in timelines reuse waveform paths as playback scrolls.

Two non-blocking improvements remain: exercise changing canvas positions in the scrolling test, and preserve visible detail when the wider window reaches the sample limit. Review checks were static; tests and native UI capture were not run.

Reviews (1) · Last reviewed commit: "perf(desktop-gpui): keep waveform paths ..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 20, 2026 12:55pm UTC

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

Comment on lines +4766 to +4769
let geometry = WaveformGeometry {
range: (window_start, window_end),
..waveform_geometry(peaks.clone())
};

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.

P2 Scrolling test misses changing positions

follow_mode_paths_are_built_once_per_window changes only range; origin, size, and clip_bounds stay fixed in the helper. Those fields are part of the cache key, and changing screen coordinates caused the original cache misses. This test would still pass if render_waveform accidentally used screen coordinates again.

Build the test geometry through the same code as render_waveform, vary the canvas position, and check that scrolling within one window still hits the cache.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/editor_timeline.rs
Line: 4766-4769

Comment:
**Scrolling test misses changing positions**

`follow_mode_paths_are_built_once_per_window` changes only `range`; `origin`, `size`, and `clip_bounds` stay fixed in the helper. Those fields are part of the cache key, and changing screen coordinates caused the original cache misses. This test would still pass if `render_waveform` accidentally used screen coordinates again.

Build the test geometry through the same code as `render_waveform`, vary the canvas position, and check that scrolling within one window still hits the cache.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment on lines +3268 to +3270
let window_width = ((window_end - window_start) * px_per_sec) as f32;
let size = gpui::size(px(window_width), px(wave_height));
let samples = waveform_sample_count(window_width as f64);

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.

P2 Wider windows lose waveform detail

The wider window shares the existing 6,000-sample limit, leaving fewer samples in view once that limit is reached. For example, a 2,500-pixel viewport showing 1,000 seconds previously requested 5,000 samples. A full 1.5-viewport window now gets 6,000 samples across 1,500 seconds, leaving about 4,000 samples in view.

waveform_path reads individual peaks rather than taking the loudest peak between samples, so this can skip more short sounds. Preserve the visible sample budget when sizing the wider window, and add a test for the sample limit.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/editor_timeline.rs
Line: 3268-3270

Comment:
**Wider windows lose waveform detail**

The wider window shares the existing 6,000-sample limit, leaving fewer samples in view once that limit is reached. For example, a 2,500-pixel viewport showing 1,000 seconds previously requested 5,000 samples. A full 1.5-viewport window now gets 6,000 samples across 1,500 seconds, leaving about 4,000 samples in view.

`waveform_path` reads individual peaks rather than taking the loudest peak between samples, so this can skip more short sounds. Preserve the visible sample budget when sizing the wider window, and add a test for the sample limit.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Capy found no issues.

Open in Capy

This branch was successfully deployed

2 active deployments
Preview – cap-web — 72316213 Deployed Oct 20, 2026 by vercel[bot]
Preview – cap-status — 72316213 Deployed Oct 20, 2026 by vercel[bot]
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