Repository navigation
Commit bc0ac76
fps: Cap the headline by asking the platform what the panel runs at (longbridge#2956)
## Summary
Follow-up to longbridge#2954. `MAX FPS` was capped by a refresh rate inferred from
the gaps between presents. That inference cannot work: those gaps are
whole multiples of the panel's period, so they bound it **from below and
never from above** — 41.7ms is six refreshes at 144Hz and one at 24Hz,
and nothing in the timing distinguishes them.
Four estimators, four wrong readings on real windows, the last three
found in longbridge-lite:
| Estimator | Read | Should have been |
| --- | --- | --- |
| Shortest gap ever seen | 169 | 144 — a compositor catch-up is not a
refresh |
| Densest group of gaps | 149 | 144 — bucketing truncates the
distribution it measures |
| Densest group of gaps | 75 | ~137 — the densest thing a demand-drawing
window does is idle |
| Fastest sustained run | **24** | ~116 — the application's own timer
fired every 41.7ms |
| Frame budget until established | **60** | ~167 — a ceiling under the
truth hides the figure entirely |
A steady 41.7ms application tick is indistinguishable from a 24Hz panel.
No tuning gets past that.
## Changes
**The guessing is gone, and the platform is asked instead.** GPUI hands
out the platform's own display handle through `DisplayId`, and the HUD
takes it from there:
- **macOS** — `CGDisplayCopyDisplayMode` on the `CGDirectDisplayID`
- **Windows** — `EnumDisplaySettingsW` on the monitor's device name
- **Wayland** — object ids are per-connection and mean nothing across
one, so the outputs are enumerated again and matched to GPUI's displays
by the identity it derives from their names
- **X11 and everything else** — no query, so no cap
A panel that reports no fixed rate — which is what ProMotion honestly is
through CoreGraphics — is read as no cap. Where nobody will say, the
reading is left uncapped rather than held to a guess.
**The answer is re-asked when the window moves to another display**, and
not otherwise: it is a property of the panel, and on some platforms
asking is a round trip.
**The warm-up stays.** Frames from before the HUD was mounted, and the
cold ones right after it, are dropped rather than measured, so a window
that just opened still reads healthy.
## Verified
On Wayland against two panels, with a temporary probe:
```
output 1492e027-… -> 143.998 Hz (compositor: 143.999)
output 09e7b298-… -> 59.997 Hz (compositor: 59.997)
window on the first -> 143.998 Hz
```
and the HUD on that window, `FRAME 4.3ms` — 232 uncapped — reading **MAX
144**, from the moment it opened and with no interaction.
**Not verified on hardware:** the macOS and Windows queries could not be
compiled here, let alone run. The Wayland path and everything above it
is measured.
## Test plan
- [ ] macOS: `MAX` stops at the panel's rate on an external display; a
built-in ProMotion panel reads uncapped
- [ ] Windows: `MAX` stops at the panel's rate
- [ ] Drag the window between two monitors of different rates: `MAX`
follows
- [ ] A window with a regular timer (quote ticks, a clock) is not capped
by its own cadence
- [ ] A window that just opened still reads `DROP 0.0%` and a green
`P95`
## AI Assistance
> 🤖 Code and docs generated by Claude Code; the wrong readings were
caught by the author on real windows. Verified locally on Linux/Wayland
with 144Hz and 60Hz panels; `cargo test -p gpui-fps` (28) passes, clippy
`--deny warnings` clean. The macOS and Windows queries are unverified —
they cannot be built on this machine.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01USSMRpQ5W58YP3UKUCzrri
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex <codex@openai.com>1 parent b586fad commit bc0ac76
8 files changed
Lines changed: 307 additions & 315 deletions
File tree
- crates/fps
- src
- website
- docs
- zh-CN/docs
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
32 | 33 | | |
33 | 34 | | |
34 | 35 | | |
| |||
42 | 43 | | |
43 | 44 | | |
44 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
45 | 50 | | |
46 | 51 | | |
| 52 | + | |
47 | 53 | | |
48 | 54 | | |
49 | 55 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
| 43 | + | |
43 | 44 | | |
44 | 45 | | |
45 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
6 | | - | |
7 | | - | |
8 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
121 | 122 | | |
122 | 123 | | |
123 | 124 | | |
124 | | - | |
125 | | - | |
126 | | - | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
127 | 128 | | |
128 | 129 | | |
129 | 130 | | |
| |||
142 | 143 | | |
143 | 144 | | |
144 | 145 | | |
145 | | - | |
| 146 | + | |
146 | 147 | | |
147 | 148 | | |
148 | 149 | | |
149 | | - | |
150 | | - | |
151 | | - | |
152 | | - | |
153 | | - | |
154 | | - | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
158 | 158 | | |
159 | 159 | | |
160 | | - | |
161 | | - | |
162 | | - | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
| |||
184 | 184 | | |
185 | 185 | | |
186 | 186 | | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
187 | 191 | | |
188 | 192 | | |
189 | 193 | | |
| |||
204 | 208 | | |
205 | 209 | | |
206 | 210 | | |
| 211 | + | |
207 | 212 | | |
208 | 213 | | |
209 | 214 | | |
| |||
336 | 341 | | |
337 | 342 | | |
338 | 343 | | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
339 | 357 | | |
340 | 358 | | |
341 | 359 | | |
| |||
347 | 365 | | |
348 | 366 | | |
349 | 367 | | |
350 | | - | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
351 | 372 | | |
352 | 373 | | |
353 | 374 | | |
| |||
497 | 518 | | |
498 | 519 | | |
499 | 520 | | |
500 | | - | |
| 521 | + | |
501 | 522 | | |
| 523 | + | |
502 | 524 | | |
503 | 525 | | |
504 | 526 | | |
| |||
739 | 761 | | |
740 | 762 | | |
741 | 763 | | |
742 | | - | |
| 764 | + | |
| 765 | + | |
743 | 766 | | |
| 767 | + | |
| 768 | + | |
744 | 769 | | |
745 | | - | |
746 | | - | |
747 | | - | |
| 770 | + | |
| 771 | + | |
748 | 772 | | |
749 | | - | |
| 773 | + | |
750 | 774 | | |
751 | | - | |
752 | | - | |
753 | 775 | | |
754 | | - | |
| 776 | + | |
755 | 777 | | |
756 | 778 | | |
757 | 779 | | |
| |||
0 commit comments