bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Sprite flickers then stops rendering completely when despawning and respawning it

Open AyeTbk opened this issue 3 years ago • 1 comments

Bevy version

0.9, but I also compiled against earlier releases (down to 0.5) and they all behaved the same.

What you did

This is a minimal reproduction of a bug I encounter in my game. There is a system that creates a sprite entity if none already exists so that there is always one. There is another system that despawns said sprite, on command, by pressing D (exactly what triggers the despawn doesnt matter though, this just gives manual control).

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup)
        .add_system(spawn_sprite_if_not_there)
        .add_system(despawn_sprite_on_keypress)
        .run();
}

fn setup(mut commands: Commands) {
    commands.spawn(Camera2dBundle::default());
}

fn spawn_sprite_if_not_there(
    mut commands: Commands,
    query: Query<(Entity, &Sprite)>,
    asset_server: Res<AssetServer>,
) {
    let sprite_exists = query.iter().count() > 0;
    if sprite_exists {
        return;
    }

    commands.spawn(SpriteBundle {
        texture: asset_server.load("image.png"),
        ..Default::default()
    });
}

fn despawn_sprite_on_keypress(
    mut commands: Commands,
    query: Query<Entity, With<Sprite>>,
    keyboard_input: Res<Input<KeyCode>>,
) {
    if keyboard_input.just_pressed(KeyCode::D) {
        for entity in query.iter() {
            commands.entity(entity).despawn();
        }
    }
}

What went wrong

Initially the sprite appears as expected. When I press D to despawn it, another identical sprite entity is created, but it seemingly renders for a single frame then disappears. The entity exists, but it's not displaying. Pressing D another time to delete the sprite and let another one be created results in a single frame flicker of the sprite's image and then back to nothing.

I would expect to just see the sprite.

Additional information

What I think is the most important bits of information I have is this:

  • Modifying the code to spawn multiple identical sprites instead of one will continue to replicate the bug only if they are all deleted at the same time. If deleting the sprites one by one (across frames), then the bug doesn't occur. In other words, it seems that the bug only occurs when at some point, the Image is no longer used by any entity and then used again in a later frame. So long as it remains in use by something, the bug doesn't occur.
  • I checked if it happens when using UI nodes instead of sprites, and it does.

Other pertinent information:

  • As mentionned above, I checked across Bevy releases to see if this was new to 0.9, but it's present in all the verisons I checked.
  • I checked on my Linux install on my desktop with a AMD GPU testing with Vulkan, on my Windows install on the same desktop testing with both Vulkan and Dx12, and on my laptop's integrated graphics on Linux. The bug happens in all of them.
  • The ordering of the two systems doesn't matter. Putting the systems in different stages doesn't matter.

AyeTbk avatar Nov 15 '22 00:11 AyeTbk

By despawning your sprite, you trigger asset cleanup for your image. When re-adding the sprite just after, the image is being reloaded, but cleanup is not unscheduled. Asset cleanup happens next, and there isn't an image to display anymore.

As a workaround, you can keep the handle to your image somewhere like in a resource, which could help you avoid reloading it from file

mockersf avatar Nov 15 '22 00:11 mockersf