bevyengine / bevyengine/bevy

bevy async compute broke by MSAA in 0.15, 0.16, and 0.17

Open
#20,355 18 comments 0 reactions 0 assignees View on GitHub
A-Rendering A-Tasks C-Bug D-Async D-Complex I-Crash I-Regression S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.14.1 and 0.16.1

## \[Optional\] Relevant system information
8 core processor

## What you did
I copied the unofficial example from here. https://bevy-cheatbook.github.io/fundamentals/async-compute.html
I found that it didnt actually work. I minimized it to the provided file down below and it still didn't work. I then copied the official example and the only thing i had to change to break it was adding a camera

In every scenerio described the main thread hangs itself and the app crashes. I believe this is due to the weird programming going on in the bevy TaskPool or including the main thread in the compute thread pool which allows it no CPU time when I create expensive computations.

## What went wrong
I expect bevy async compute to not block main and not hang the app.

## Additional information

Image
Here is minimal code that breaks the unoffical example

```rs
use bevy::prelude::*;
use bevy::tasks::{AsyncComputeTaskPool, Task, TaskPoolBuilder};
use std::collections::HashMap;

#[derive(Resource, Default)]
struct MyMapGenTasks {
generating_chunks: HashMap>,
}

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(MyMapGenTasks::default())
.add_systems(Startup, setup)
.add_systems(Update, begin_generating_map_chunks)
.run();
}

fn setup(mut commands: Commands) {
commands.spawn(Camera3d::default());
AsyncComputeTaskPool::get_or_init(|| {
TaskPoolBuilder::new()
.num_threads(2)
.stack_size(16 * 1024 * 1024)
.build()
});
}

fn generate_map_chunk() {
let mut sum = 0.0;
for j in 1..u32::MAX {
sum += (j as f32).sin().cos().tan().sqrt() + j as f32 * 0.0001;
}
println!("sum: {}", sum);
}

fn begin_generating_map_chunks(mut my_tasks: ResMut) {
let task_pool: &'static AsyncComputeTaskPool = AsyncComputeTaskPool::get();
for chunk_coord in 0..1000 {
if my_tasks.generating_chunks.contains_key(&chunk_coord) {
continue;
}
let task = task_pool.spawn(async move { generate_map_chunk() });
my_tasks.generating_chunks.insert(chunk_coord, task);
}
}```

And there is code replacement that breaks the official example
```rs
// Pretend this is a time-intensive function. :)
async fn generate_map_chunk() {
let mut sum = 0.0;
for j in 1..u32::MAX {
sum += (j as f32).sin().cos().tan().sqrt() + j as f32 * 0.0001;
}
println!("sum: {}", sum);
}
generate_map_chunk().await;```
(i also tried a non async generate_map_chunk function.

Contributor guide

Open the contributing guide

Research direction

Start with the provided Rust reproduction using AsyncComputeTaskPool, TaskPoolBuilder, and the added Camera3d, then compare it with Bevy's official async compute example and the unofficial Async Compute documentation. Investigate why the intensive task submission causes the main thread to hang across the reported Bevy versions. Done means the reproduction no longer hangs or crashes while the async computation runs.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.