8000
Skip to content

Fix debug-profile slider stutter (#25500) - #25536

Open
bugsweeper wants to merge 2 commits into
bevyengine:mainfrom
bugsweeper:fix/issue-25500-slider-debug-perf
Open

Fix debug-profile slider stutter (#25500)#25536
bugsweeper wants to merge 2 commits into
bevyengine:mainfrom
bugsweeper:fix/issue-25500-slider-debug-perf

Conversation

@bugsweeper
Copy link
Copy Markdown
Contributor

Objective

  • Fixes feathers_gallery poor performance in debug mode #25500.
  • On debug builds, dragging the color slider/color plane in feathers_gallery updated in visible discrete steps instead of smoothly. Measured on Linux + NVIDIA RTX 4070 + Vulkan: out of 138 consecutive frames during a slow, controlled drag, only 86 states were unique (52 frames repeated the previous state) in debug, versus 129/138 unique in release. The slider's value updated correctly the whole time — this was a rendering smoothness problem, not an input problem.
  • Two causes were found:
    • EditableText triggered a full intrinsic-size recomputation (and thus a full Taffy layout pass) every frame, regardless of whether its rendered size had actually changed.
    • ColorSlider and ColorPlane moved their thumb every frame by writing Node::left/Node::top, which are layout-affecting properties and force a Taffy relayout on every frame during a drag.
    • Both are comparatively cheap in optimized builds but expensive enough in debug builds to visibly drop frames.

Solution

  • update_editable_text_content_size now caches the inputs that actually determine EditableText's intrinsic size (visible_width, visible_lines) in a new EditableTextContentSizeState component, and only recomputes when those specific fields change, instead of on every change to EditableText (which also churns from unrelated fields like cursor blink/edits). EditableTextContentSizeState is wired up as a required component of bevy_text::EditableText via register_required_components in UiPlugin, since bevy_text doesn't depend on bevy_ui.
  • ColorSlider and ColorPlane now position their thumb via UiTransform instead of Node::left/Node::top. UiTransform is applied after layout and doesn't invalidate Taffy, so moving the thumb no longer forces a relayout.
  • ColorPlane's thumb positioning was split out of update_plane_color into its own system, update_plane_thumb_position, which runs unconditionally every frame so the thumb keeps tracking the parent node's actual size (e.g. on window resize) even when the color value hasn't changed. update_plane_color keeps its original Changed filter, since it mutates Assets<ColorPlaneMaterial>, which is comparatively expensive to touch every frame.

Testing

  • cargo test -p bevy_ui --lib: 66/66 passed.
  • cargo test -p bevy_feathers --lib: 10/10 passed.
  • cargo fmt --check and git diff --check pass.
  • Manually verified in feathers_gallery (debug profile) that the color slider and color plane thumbs track the mouse correctly and land at the right position during and after a drag.
  • Manually verified that resizing the window while the color plane is visible keeps its thumb tracking the container's size correctly, both with and without a value change in between.
  • Measured debug-profile FPS during continuous slider drag: ~11-14 FPS before this fix, ~59-63 FPS after, both at rest and while continuously dragging.
  • Tested on Linux + NVIDIA RTX 4070 + Vulkan only. Not tested on Windows/macOS or other GPU vendors; the fix is platform-agnostic (it removes unnecessary layout/material work), so I don't expect platform-specific regressions, but review/testing on other platforms is welcome.

EditableText re-triggered intrinsic-size recomputation and a full
Taffy layout pass every frame regardless of whether its rendered
size had actually changed, and ColorSlider/ColorPlane moved their
thumb via Node::left/top (layout-affecting properties), forcing a
relayout on every frame during drag. In debug builds this made the
color slider/plane update in visible discrete steps instead of
smoothly.

- Cache the inputs that determine EditableText's intrinsic size
  (visible_width/visible_lines) and only recompute when they change.
- Move ColorSlider and ColorPlane thumb positioning to UiTransform,
  which doesn't invalidate layout, instead of Node::left/top.
- Split ColorPlane's thumb positioning into its own unfiltered system
  so it keeps tracking the container's resized size every frame,
  while update_plane_color keeps its Changed filter to avoid
  needlessly mutating Assets<ColorPlaneMaterial>.

Debug-profile FPS during continuous slider drag went from ~11-14 FPS
to ~59-63 FPS on Linux + NVIDIA RTX 4070 + Vulkan.
@bugsweeper
bugsweeper commented Aug 24, 2026
Copy link
Copy Markdown
Contributor Author

The macOS build job did not report a test failure; it was cancelled after reaching the workflow’s 40-minute timeout while running cargo run -p ci -- test. Ubuntu and Windows builds passed, as did run-examples-macos-metal. I’ll update the branch against current main to trigger a fresh run. If macOS times out again, could a maintainer please rerun the failed job?

…sue-25500-slider-debug-perf

# Conflicts:
#	crates/bevy_feathers/src/controls/color_slider.rs
@Zeophlite Zeophlite added A-UI Graphical user interfaces, styles, layouts, and widgets D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Aug 25, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in UI Aug 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-UI Graphical user interfaces, styles, layouts, and widgets D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

feathers_gallery poor performance in debug mode

2 participants

0