diff --git a/Cargo.toml b/Cargo.toml index 6612b1630986e..0d25cd6168bec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,6 +115,10 @@ debug_asset_server = ["bevy_internal/debug_asset_server"] # Enable animation support, and glTF animation loading animation = ["bevy_internal/animation"] +# alternative async executors, defaults to futures-lite +async-io = ["bevy_internal/async-io"] +tokio = ["bevy_internal/tokio"] + [dependencies] bevy_dylib = { path = "crates/bevy_dylib", version = "0.9.0-dev", default-features = false, optional = true } bevy_internal = { path = "crates/bevy_internal", version = "0.9.0-dev", default-features = false } diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index bd6874d683f83..df8e6558477cf 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -12,6 +12,8 @@ keywords = ["bevy"] default = [] filesystem_watcher = ["notify"] debug_asset_server = ["filesystem_watcher"] +async-io = ["bevy_tasks/async-io"] +tokio = ["bevy_tasks/tokio"] [dependencies] # bevy @@ -43,6 +45,5 @@ js-sys = "0.3" ndk-glue = { version = "0.5" } [dev-dependencies] -futures-lite = "1.4.0" tempfile = "3.2.0" bevy_core = { path = "../bevy_core", version = "0.9.0-dev" } diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 46b2a0f5502e3..a203d9a87c5f7 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -800,8 +800,7 @@ mod test { let path: AssetPath = "file.not-a-real-extension".into(); let handle = asset_server.get_handle_untyped(path.get_id()); - let err = futures_lite::future::block_on(asset_server.load_async(path.clone(), true)) - .unwrap_err(); + let err = bevy_tasks::block_on(asset_server.load_async(path.clone(), true)).unwrap_err(); assert!(match err { AssetServerError::MissingAssetLoader { extensions } => { extensions == ["not-a-real-extension"] @@ -820,8 +819,7 @@ mod test { let path: AssetPath = "an/invalid/path.png".into(); let handle = asset_server.get_handle_untyped(path.get_id()); - let err = futures_lite::future::block_on(asset_server.load_async(path.clone(), true)) - .unwrap_err(); + let err = bevy_tasks::block_on(asset_server.load_async(path.clone(), true)).unwrap_err(); assert!(matches!(err, AssetServerError::AssetIoError(_))); assert_eq!(asset_server.get_load_state(handle), LoadState::Failed); @@ -836,8 +834,7 @@ mod test { let path: AssetPath = "fake.fail".into(); let handle = asset_server.get_handle_untyped(path.get_id()); - let err = futures_lite::future::block_on(asset_server.load_async(path.clone(), true)) - .unwrap_err(); + let err = bevy_tasks::block_on(asset_server.load_async(path.clone(), true)).unwrap_err(); assert!(matches!(err, AssetServerError::AssetLoaderError(_))); assert_eq!(asset_server.get_load_state(handle), LoadState::Failed); @@ -860,8 +857,7 @@ mod test { fn load_asset(path: AssetPath, world: &World) -> HandleUntyped { let asset_server = world.resource::(); - let id = futures_lite::future::block_on(asset_server.load_async(path.clone(), true)) - .unwrap(); + let id = bevy_tasks::block_on(asset_server.load_async(path.clone(), true)).unwrap(); asset_server.get_handle_untyped(id) } diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index f38c60c203f9a..5cfbe75cdc533 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -63,6 +63,10 @@ bevy_ci_testing = ["bevy_app/bevy_ci_testing", "bevy_render/ci_limits"] # Enable animation support, and glTF animation loading animation = ["bevy_animation", "bevy_gltf?/bevy_animation"] +# alternative async executors, defaults to futures-lite +async-io = ["bevy_tasks/async-io"] +tokio = ["bevy_tasks/tokio"] + [dependencies] # bevy bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 9e7c676ac1564..da3e26087b686 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -59,7 +59,7 @@ once_cell = "1.4.1" # TODO: replace once_cell with std equivalent if/when this l downcast-rs = "1.2.0" thread_local = "1.1" thiserror = "1.0" -futures-lite = "1.4.0" +futures-lite = "1.12" anyhow = "1.0" hex = "0.4.2" hexasphere = "7.2" diff --git a/crates/bevy_tasks/Cargo.toml b/crates/bevy_tasks/Cargo.toml index 0358f95c1b458..56acc536853e6 100644 --- a/crates/bevy_tasks/Cargo.toml +++ b/crates/bevy_tasks/Cargo.toml @@ -8,8 +8,13 @@ repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy"] +[features] +async-io = ["async-global-executor/async-io"] +tokio = ["async-global-executor/tokio"] + [dependencies] -futures-lite = "1.4.0" +futures-lite = "1.12.0" +async-global-executor= { version="2.2.0", default-features = false } async-executor = "1.3.0" async-channel = "1.4.2" once_cell = "1.7" diff --git a/crates/bevy_tasks/src/lib.rs b/crates/bevy_tasks/src/lib.rs index 62c42a7717868..e0b9aab92a8d3 100644 --- a/crates/bevy_tasks/src/lib.rs +++ b/crates/bevy_tasks/src/lib.rs @@ -23,6 +23,10 @@ pub use usages::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool}; mod iter; pub use iter::ParallelIterator; +// re-export block_on so that consumers don't need to explicitly depend on the async engine being used. +// it uses futures-lite by default, async-io and tokio are optional behind features +pub use async_global_executor::block_on; + #[allow(missing_docs)] pub mod prelude { #[doc(hidden)] diff --git a/crates/bevy_tasks/src/task_pool.rs b/crates/bevy_tasks/src/task_pool.rs index e0ac0101d56ac..f7891f6f97dcc 100644 --- a/crates/bevy_tasks/src/task_pool.rs +++ b/crates/bevy_tasks/src/task_pool.rs @@ -119,7 +119,7 @@ impl TaskPool { .spawn(move || { let shutdown_future = ex.run(shutdown_rx.recv()); // Use unwrap_err because we expect a Closed error - future::block_on(shutdown_future).unwrap_err(); + crate::block_on(shutdown_future).unwrap_err(); }) .expect("Failed to spawn thread.") }) @@ -269,11 +269,11 @@ impl TaskPool { // forward until the tasks that are spawned by this scope() call // complete. (If the caller of scope() happens to be a thread in // this thread pool, and we only have one thread in the pool, then - // simply calling future::block_on(spawned) would deadlock.) + // simply calling crate::block_on(spawned) would deadlock.) let mut spawned = task_scope_executor.spawn(get_results); loop { - if let Some(result) = future::block_on(future::poll_once(&mut spawned)) { + if let Some(result) = crate::block_on(future::poll_once(&mut spawned)) { break result; }; diff --git a/docs/cargo_features.md b/docs/cargo_features.md index 8d0db4604380e..59d43c05aea54 100644 --- a/docs/cargo_features.md +++ b/docs/cargo_features.md @@ -44,3 +44,5 @@ |subpixel_glyph_atlas|Enable this to cache glyphs using subpixel accuracy. This increases texture memory usage as each position requires a separate sprite in the glyph atlas, but provide more accurate character spacing.| |bevy_ci_testing|Used for running examples in CI.| |debug_asset_server|Enabling this turns on "hot reloading" of built in assets, such as shaders.| +|tokio|Use tokio as task execution engine.| +|async-io|Use async-io as task execution engine.| diff --git a/examples/async_tasks/async_compute.rs b/examples/async_tasks/async_compute.rs index d0f4466d76eaf..fc8e02aa90e4b 100644 --- a/examples/async_tasks/async_compute.rs +++ b/examples/async_tasks/async_compute.rs @@ -88,7 +88,7 @@ fn handle_tasks( box_material_handle: Res, ) { for (entity, mut task) in &mut transform_tasks { - if let Some(transform) = future::block_on(future::poll_once(&mut task.0)) { + if let Some(transform) = bevy::tasks::block_on(future::poll_once(&mut task.0)) { // Add our new PbrBundle of components to our tagged entity commands.entity(entity).insert(PbrBundle { mesh: box_mesh_handle.clone(),