changed_windows calls slow current_monitor() on every Window change (macOS)
I maintainer di solito rispondono entro 2 giorni
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 45/100
- Tipo di issue
- Bug
- Chiarezza
- Abbastanza chiara
- Stato di attività
- Attiva
- Stack tecnologico
- macos, rust
- Ambito
- desktop-dev, performance
Direzione di ricerca
Start with listen_for_ime_input_when_text_input_focused and update_ime_position in the bevy_ui_widgets text input plugin, which write ime_enabled and ime_position on Window every frame. Then read changed_windows in bevy_winit, where current_monitor() runs for every changed window. Done when those writes happen only on real value changes and the monitor lookup is skipped when position, size and scale factor are unchanged, which you can check by sampling an idle macOS run.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Bevy version
- Original: 0.19.0
- Current: 0.20.1 (the code involved is unchanged on
mainas of 2026-11-13)
Relevant system information
cargo 1.98.0-nightly (598ab48ec 2026-06-17)- macOS 26 (Darwin 25.5), Apple Silicon, 120 Hz ProMotion display
DefaultPluginswith default features (sobevy_ui_widgetsis included)
What's performing poorly?
After upgrading our game from 0.19.0 to 0.20.1, it dropped from 120 to 60 fps under vsync on macOS. It's a 3D game using DefaultPlugins; we use no Bevy text inputs (all text fields are egui).
Profiling showed bevy_winit::system::changed_windows running every frame, even with no input at all. Most of its time is spent in winit::Window::current_monitor(). On macOS that goes through CGDisplayCreateUUIDFromDisplayID / SLSCopyDisplayUUID, a round trip to the window server costing about 1 ms per call. That took roughly 10% of the main thread, enough to push frames past the 8.3 ms budget of a 120 Hz display.
There are two causes.
1. TextInputPlugin marks the window changed every frame. In bevy_ui_widgets:
listen_for_ime_input_when_text_input_focuseddoeswindow.ime_enabled = ime_wanted;every frame, unconditionally;update_ime_positiondoeswindow.ime_position = ...;every frame while a text input is focused.
Both writes go through Mut<Window>, so Changed<Window> fires even when the value is unchanged, and changed_windows does its full sync every frame. This affects any app using DefaultPlugins, whether it has text inputs or not.
2. changed_windows looks up the monitor on every Window change. Even with cause 1 gone, changed_windows calls current_monitor() for every window that changed that frame. Moving the mouse changes the Window (bevy_winit writes the cursor position into it on CursorMoved). In a game the cursor moves on most frames (aiming, clicking, camera drag), so the ~1 ms lookup still runs on most frames during normal play.
To reproduce on macOS: any app with DefaultPlugins and a window; profile it while idle and while moving the mouse over the window, and look for changed_windows → current_monitor.
Before and After Traces
These are 10-second macOS sample profiles of the same 0.20.1 build, idle (no input), uncapped present mode. I don't have a 0.19 trace.
- Before (
TextInputPluginenabled, the default):changed_windows→current_monitorin 526 of 5271 main-thread samples.create_monitorsin 251. - After (
DefaultPlugins.build().disable::<bevy::ui_widgets::TextInputPlugin>()):changed_windowsabsent.create_monitorsin 2. Main-thread time inApp::updatedown about 20% (4479 → 3546 samples).
I haven't profiled the mouse-moving case (cause 2) separately.
Additional information
- Workaround for cause 1: disable
TextInputPluginif you don't use Bevy text inputs. Cause 2 has no workaround short of patchingbevy_winit. - Possible fix for cause 1: only assign
ime_enabled/ime_positionwhen the value differs. - Possible fix for cause 2: a window can only end up on another monitor when its position, size or scale factor changes.
changed_windowscould store those from the last lookup and only callcurrent_monitor()when one differs, or when the window has noOnMonitoryet.outer_position(),outer_size()andscale_factor()are cheap on macOS (they read theNSWindowframe). Where the position isn't available (Wayland), it could fall back to the current behaviour.
- Lingua principale
- Rust
- Stelle
- 49.7k
- Fork
- 5k
- Merge medio
- 3g 19h
- PR unite (30g)
- 134
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di bevyengine/bevy
-
C-Bug S-Needs-Triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
bevyengine/bevy#26536 ·
I maintainer di solito rispondono entro 2 giorni
-
Placeholder has no defaultForse già presa Una pull request collegata a questa issue è aperta o già unita. ApertaC-Feature S-Needs-Triage
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 62/100
bevyengine/bevy#26532 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
C-Feature S-Needs-Triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
bevyengine/bevy#26500 · 1 commento ·
I maintainer di solito rispondono entro 2 giorni
-
C-Feature S-Needs-Triage
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 68/100
bevyengine/bevy#26499 ·
I maintainer di solito rispondono entro 2 giorni
-
`compute_histogram` in auto exposure writes past the end of the 64-bin histogramForse già presa @dev-matru l’ha presa 3 giorni fa. ApertaA-Rendering C-Bug D-Straightforward S-Ready-For-Implementation X-Uncontroversial
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
bevyengine/bevy#26479 ·
I maintainer di solito rispondono entro 2 giorni
Tutte le issue di bevyengine/bevy
Issue simili
-
bug UI
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
wardian-app/Wardian#1746 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
jlcodes99/cockpit-tools#3125 ·
I maintainer di solito rispondono entro 2 giorni
-
bug user-sprint
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
Vondor/KassenSturz#967 ·
I maintainer di solito rispondono entro 1 giorno
-
area/ci
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno
-
[BUG] Incremental sync warns "no stored highest_uid" on every round for folders with no new mailApertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
rustmailer/bichon#411 ·