bevyengine / bevyengine/bevy

Bevy crashes when disabling Camera entities

Open
#20,301 6 comments 0 reactions 0 assignees View on GitHub
A-Rendering C-Bug D-Domain-Agnostic D-Straightforward S-Ready-For-Implementation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.16.1

## What you did

Here is a mini repro:

```rust
use bevy::{ecs::entity_disabling::Disabled, prelude::*};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, input)
.run();
}

#[derive(Component)]
struct SingleCamera(Entity);

fn setup(mut commands: Commands) {
let camera = commands.spawn((
Camera3d::default(),
Camera {
is_active: true,
..Default::default()
},
// Disabled
)).id();

commands.spawn(SingleCamera(camera));
}

fn input(
mut commands: Commands,
input: Res>,
camera: Query<&SingleCamera>,
mut cameras: Query<(&mut Camera, Has)>
) {
let entity = camera.single().unwrap().0;
let mut camera = cameras.single_mut().unwrap();
if input.just_released(KeyCode::Space) {
// now set is_active to true and insert the "Disabled" component
camera.0.is_active = false;
commands.entity(entity).insert(Disabled);
}
}
```

Run this App and press "Space", there will be a crash with message

```
thread 'Compute Task Pool (4)' panicked at /bevy/crates/bevy_core_pipeline/src/core_3d/mod.rs:833:22:
The depth texture usage should already exist for this target
```

## Additional information

I tried to dig into the source code to figure out what exactly causes this. Here are my findings.

It seems that the components like `ExtractedView` are not automatically cleaned up from render world after each run of render pipeline. This the reason why we need to manually remove them once the corresponding camera becomes inactive.

https://github.com/bevyengine/bevy/blob/383b3510455c431f34cf3f2c6e3c2d40eddce744/crates/bevy_render/src/camera/camera.rs#L1133-L1144

However, when the camera is disabled by a `Disabled` component, it is filtered out from the query, thus makes the extracted components remain in the render world, even we set `camera.is_active` to `false`. However, there are serval tasks like `prepare_core_3d_depth_textures` highly relies on the existence of these extracted components to determine currently active cameras.

https://github.com/bevyengine/bevy/blob/383b3510455c431f34cf3f2c6e3c2d40eddce744/crates/bevy_core_pipeline/src/core_3d/mod.rs#L766

So this function will panic as the camera simply does not exist.

I added a `Has` filter to query of `extract_cameras` and changed the condition here

https://github.com/bevyengine/bevy/blob/383b3510455c431f34cf3f2c6e3c2d40eddce744/crates/bevy_render/src/camera/camera.rs#L1133

to

```
if !camera.is_active || disabled {
```

Then the mini repro works.

P.S. I'm not familiar when bevy's codebase, so my analysis could be wrong. I would appreciate it if someone can correct me.

Contributor guide

Open the contributing guide

Research direction

Reproduce the crash with the Rust mini repro, then inspect extract_cameras in crates/bevy_render/src/camera/camera.rs and prepare_core_3d_depth_textures in crates/bevy_core_pipeline/src/core_3d/mod.rs. Trace how disabling a camera affects extracted render-world components and verify that the repro no longer panics when the camera is disabled.

Written by the indexing model from the issue text.

Assessment

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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.