bevyengine / bevyengine/bevy

`RequestRedraw` doesn't work as expected

Open
#16,817 1 comment 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## Bevy version

0.15.0

## Relevant system information

```ignore
AdapterInfo { name: "NVIDIA GeForce RTX 4070 SUPER", vendor: 4318, device: 10115, device_type: DiscreteGpu, driver: "NVIDIA", driver_info: "565.90", backend: Vulkan }
```

## What you did

There is a white button. When you press it, it becomes black with a transition in 0.2 s. This is a desktop app, so I need to send `RequestRedraw` manually. If the transition has not finished, it will call `redraw_request_events.send(RequestRedraw)`, so this system will still be called to redraw next frame.

```rust
fn update_background_color(
mut buttons: Query<(&mut CustomButton, &mut BackgroundColor)>,
mut redraw_request_events: EventWriter,
) {
for (mut button, mut background_color) in buttons.iter_mut() {
if let Some(transition) = &button.transition {
/// Unit: second
const TRANSITION_DURATION: f32 = 0.2;
let t = transition.start_time.elapsed().unwrap().as_secs_f32();

info!("t = {t} s");
if t > TRANSITION_DURATION {
button.transition = None;
info!("transition finished");
continue;
}
let y = EasingCurve::new(0.0, 1.0, EaseFunction::SineIn)
.sample(t / TRANSITION_DURATION)
.unwrap();
background_color.0 = transition.start.mix(&transition.end, y);
redraw_request_events.send(RequestRedraw);
}
}
}
```

However, the output is:
```
2024-12-14T09:16:26.746642Z INFO bevy_demo: t = 0.0000055 s
2024-12-14T09:16:27.136166Z INFO bevy_demo: t = 0.3895302 s
2024-12-14T09:16:27.136300Z INFO bevy_demo: transition finished
```

It shows that nearly 400ms after `09:16:26.746642`, the next redraw is called.

Click me to expand the `main.rs`

```rust
use bevy::{prelude::*, window::RequestRedraw, winit::WinitSettings};
use std::time::SystemTime;

const DEFAULT_BUTTON_BACKGROUND_COLOR: Color = Color::WHITE;
const PRESSED_BUTTON_BACKGROUND_COLOR: Color = Color::BLACK;

#[derive(Component)]
#[require(
Button,
BackgroundColor(|| BackgroundColor(DEFAULT_BUTTON_BACKGROUND_COLOR)),
)]
pub struct CustomButton {
transition: Option,
}

struct Transition {
start: Color,
end: Color,
start_time: std::time::SystemTime,
}

fn on_interaction(
mut buttons: Query<(&mut CustomButton, &BackgroundColor, &Interaction), Changed>,
) {
for (mut button, background_color, interaction) in buttons.iter_mut() {
match interaction {
Interaction::Pressed => {
button.transition = Some(Transition {
start: background_color.0,
end: PRESSED_BUTTON_BACKGROUND_COLOR,
start_time: SystemTime::now(),
});
}
Interaction::None => {
button.transition = Some(Transition {
start: background_color.0,
end: DEFAULT_BUTTON_BACKGROUND_COLOR,
start_time: SystemTime::now(),
});
}
_ => {}
}
}
}

fn update_background_color(
mut buttons: Query<(&mut CustomButton, &mut BackgroundColor)>,
mut redraw_request_events: EventWriter,
) {
for (mut button, mut background_color) in buttons.iter_mut() {
if let Some(transition) = &button.transition {
/// Unit: second
const TRANSITION_DURATION: f32 = 0.2;
let t = transition.start_time.elapsed().unwrap().as_secs_f32();

info!("t = {t} s");
if t > TRANSITION_DURATION {
button.transition = None;
info!("transition finished");
continue;
}
let y = EasingCurve::new(0.0, 1.0, EaseFunction::SineIn)
.sample(t / TRANSITION_DURATION)
.unwrap();
background_color.0 = transition.start.mix(&transition.end, y);
redraw_request_events.send(RequestRedraw);
}
}
}

fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn((
CustomButton {
transition: None,
},
Node {
width: Val::Px(200.0),
height: Val::Px(100.0),
..default()
},
));
}

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(WinitSettings::desktop_app())
.add_systems(Startup, setup)
.add_systems(Update, (on_interaction, update_background_color))
.run();
}

```

## What went wrong

It should be like this:

```
2024-12-14T09:16:13.352178Z INFO bevy_demo: t = 0.0000044 s
2024-12-14T09:16:13.360099Z INFO bevy_demo: t = 0.0079271 s
2024-12-14T09:16:13.360687Z INFO bevy_demo: t = 0.0085149 s
2024-12-14T09:16:13.361251Z INFO bevy_demo: t = 0.0090788 s
// ...
2024-12-14T09:16:13.540491Z INFO bevy_demo: t = 0.1883187 s
2024-12-14T09:16:13.544745Z INFO bevy_demo: t = 0.19257231 s
2024-12-14T09:16:13.550594Z INFO bevy_demo: t = 0.19842151 s
2024-12-14T09:16:13.556571Z INFO bevy_demo: t = 0.2043975 s
2024-12-14T09:16:13.556679Z INFO bevy_demo: transition finished
```

Contributor guide

Open the contributing guide

Research direction

Start with the embedded main.rs reproduction, especially WinitSettings::desktop_app(), RequestRedraw, and update_background_color. Compare the observed redraw timing with the expected per-frame progression, then trace the redraw event handling to determine why requests are delayed; done means the transition advances at roughly frame cadence for its full duration.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.