changed_windows calls slow current_monitor() on every Window change (macOS)
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 45/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- macos, rust
- Área
- desktop-dev, performance
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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.
- Lenguaje dominante
- Rust
- Estrellas
- 49.7k
- Forks
- 5k
- Merge medio
- 3 d 19 h
- PR fusionados (30 d)
- 134
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de bevyengine/bevy
-
C-Bug S-Needs-Triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
bevyengine/bevy#26536 ·
Los mantenedores suelen responder en 2 días
-
Placeholder has no defaultPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. AbiertoC-Feature S-Needs-Triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 62/100
bevyengine/bevy#26532 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
C-Feature S-Needs-Triage
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
bevyengine/bevy#26500 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
`Selected` should derive ReflectAbiertoC-Feature S-Needs-Triage
Dificultad 1/5 Menos de una hora Aptitud para principiantes 68/100
bevyengine/bevy#26499 ·
Los mantenedores suelen responder en 2 días
-
`compute_histogram` in auto exposure writes past the end of the 64-bin histogramPosiblemente ocupada @dev-matru la tomó hace 3 días. AbiertoA-Rendering C-Bug D-Straightforward S-Ready-For-Implementation X-Uncontroversial
Dificultad 2/5 1-3 horas Aptitud para principiantes 88/100
bevyengine/bevy#26479 ·
Los mantenedores suelen responder en 2 días
Todos los issues de bevyengine/bevy
Issues similares
-
bug UI
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
wardian-app/Wardian#1746 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
jlcodes99/cockpit-tools#3125 ·
Los mantenedores suelen responder en 2 días
-
bug user-sprint
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
Vondor/KassenSturz#967 ·
Los mantenedores suelen responder en 1 día
-
area/ci
Dificultad 1/5 Menos de una hora Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día
-
[BUG] Incremental sync warns "no stored highest_uid" on every round for folders with no new mailAbiertobug
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
rustmailer/bichon#411 ·