From ddea3e15be847d0370845523b4965ffd335fb1c5 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Mon, 9 Aug 2021 13:53:32 +0800 Subject: [PATCH 1/4] Make tokio / async-io optional task execution engines behind optional features --- Cargo.toml | 7 +- crates/bevy_asset/Cargo.toml | 3 +- crates/bevy_asset/src/asset_server.rs | 13 +- crates/bevy_internal/Cargo.toml | 4 + crates/bevy_tasks/Cargo.toml | 8 + crates/bevy_tasks/src/countdown_event.rs | 0 crates/bevy_tasks/src/lib.rs | 4 + crates/bevy_tasks/src/task_pool.rs | 6 +- crates/bevy_wgpu/Cargo.toml | 38 + crates/bevy_wgpu/src/lib.rs | 0 .../renderer/wgpu_render_resource_context.rs | 693 ++++++++++++++++++ deny.toml | 38 +- docs/cargo_features.md | 2 + examples/async_tasks/async_compute.rs | 4 +- 14 files changed, 787 insertions(+), 33 deletions(-) create mode 100644 crates/bevy_tasks/src/countdown_event.rs create mode 100644 crates/bevy_wgpu/Cargo.toml create mode 100644 crates/bevy_wgpu/src/lib.rs create mode 100644 crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs diff --git a/Cargo.toml b/Cargo.toml index 6612b1630986e..9f9241e1ca0ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ keywords = ["game", "engine", "gamedev", "graphics", "bevy"] license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/bevyengine/bevy" +resolver = "2" [workspace] exclude = ["benches", "crates/bevy_ecs_compile_fail_tests"] @@ -115,6 +116,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 } @@ -131,7 +136,7 @@ ron = "0.8.0" serde = { version = "1", features = ["derive"] } bytemuck = "1.7" # Needed to poll Task examples -futures-lite = "1.11.3" +futures-lite = "1.12.0" crossbeam-channel = "0.5.0" [[example]] 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..6b0da9d9a43f5 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -7,7 +7,7 @@ use crate::{ use anyhow::Result; use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_log::warn; -use bevy_tasks::IoTaskPool; +use bevy_tasks::{self, TaskPool}; use bevy_utils::{Entry, HashMap, Uuid}; use crossbeam_channel::TryRecvError; use parking_lot::{Mutex, RwLock}; @@ -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); @@ -859,7 +856,7 @@ mod test { app.add_system(update_asset_storage_system::.after(FreeUnusedAssets)); fn load_asset(path: AssetPath, world: &World) -> HandleUntyped { - let asset_server = world.resource::(); + let asset_server = world.get_resource::().unwrap(); let id = futures_lite::future::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..b71608031f290 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", "bevy_wgpu/async-io"] +tokio = ["bevy_tasks/tokio", "bevy_wgpu/tokio"] + [dependencies] # bevy bevy_app = { path = "../bevy_app", version = "0.9.0-dev" } diff --git a/crates/bevy_tasks/Cargo.toml b/crates/bevy_tasks/Cargo.toml index 0358f95c1b458..28b562c2081f1 100644 --- a/crates/bevy_tasks/Cargo.toml +++ b/crates/bevy_tasks/Cargo.toml @@ -8,8 +8,16 @@ repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy"] +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[features] +async-io = ["async-global-executor/async-io"] +tokio = ["async-global-executor/tokio"] + [dependencies] futures-lite = "1.4.0" +async-global-executor= { version="2.0.2", default-features = false } +futures-lite = "1.12.0" +event-listener = "2.4.0" async-executor = "1.3.0" async-channel = "1.4.2" once_cell = "1.7" diff --git a/crates/bevy_tasks/src/countdown_event.rs b/crates/bevy_tasks/src/countdown_event.rs new file mode 100644 index 0000000000000..e69de29bb2d1d 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/crates/bevy_wgpu/Cargo.toml b/crates/bevy_wgpu/Cargo.toml new file mode 100644 index 0000000000000..af6797cd770b1 --- /dev/null +++ b/crates/bevy_wgpu/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "bevy_wgpu" +version = "0.5.0" +edition = "2018" +authors = [ + "Bevy Contributors ", + "Carter Anderson ", +] +description = "A wgpu render backend for Bevy Engine" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[features] +default = ["bevy_winit"] +trace = ["wgpu/trace"] +async-io = ["async-global-executor/async-io"] +tokio = ["async-global-executor/tokio"] + +[dependencies] +# bevy +bevy_app = { path = "../bevy_app", version = "0.5.0" } +bevy_asset = { path = "../bevy_asset", version = "0.5.0" } +bevy_core = { path = "../bevy_core", version = "0.5.0" } +bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.5.0" } +bevy_ecs = { path = "../bevy_ecs", version = "0.5.0" } +bevy_render = { path = "../bevy_render", version = "0.5.0" } +bevy_window = { path = "../bevy_window", version = "0.5.0" } +bevy_winit = { path = "../bevy_winit", optional = true, version = "0.5.0" } +bevy_utils = { path = "../bevy_utils", version = "0.5.0" } + +# other +wgpu = "0.9" +crossbeam-channel = "0.5.0" +crossbeam-utils = "0.8.1" +parking_lot = "0.11.0" +async-global-executor= { version="2.0.2", default-features = false } \ No newline at end of file diff --git a/crates/bevy_wgpu/src/lib.rs b/crates/bevy_wgpu/src/lib.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs new file mode 100644 index 0000000000000..2168e6109f631 --- /dev/null +++ b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs @@ -0,0 +1,693 @@ +use crate::{wgpu_type_converter::WgpuInto, WgpuBindGroupInfo, WgpuResources}; + +use crate::wgpu_type_converter::OwnedWgpuVertexBufferLayout; +use bevy_asset::{Assets, Handle, HandleUntyped}; +use bevy_render::{ + pipeline::{ + BindGroupDescriptor, BindGroupDescriptorId, BindingShaderStage, PipelineDescriptor, + }, + renderer::{ + BindGroup, BufferId, BufferInfo, BufferMapMode, RenderResourceBinding, + RenderResourceContext, RenderResourceId, SamplerId, TextureId, + }, + shader::{glsl_to_spirv, Shader, ShaderError, ShaderSource}, + texture::{Extent3d, SamplerDescriptor, TextureDescriptor}, +}; +use bevy_utils::tracing::trace; +use bevy_window::{Window, WindowId}; +use std::{ + borrow::Cow, + num::{NonZeroU32, NonZeroU64}, + ops::Range, + sync::Arc, +}; +use wgpu::util::DeviceExt; + +#[derive(Clone, Debug)] +pub struct WgpuRenderResourceContext { + pub device: Arc, + pub resources: WgpuResources, +} + +pub const COPY_BYTES_PER_ROW_ALIGNMENT: usize = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize; +pub const BIND_BUFFER_ALIGNMENT: usize = wgpu::BIND_BUFFER_ALIGNMENT as usize; +pub const COPY_BUFFER_ALIGNMENT: usize = wgpu::COPY_BUFFER_ALIGNMENT as usize; +pub const PUSH_CONSTANT_ALIGNMENT: u32 = wgpu::PUSH_CONSTANT_ALIGNMENT; + +impl WgpuRenderResourceContext { + pub fn new(device: Arc) -> Self { + WgpuRenderResourceContext { + device, + resources: WgpuResources::default(), + } + } + + pub fn set_window_surface(&self, window_id: WindowId, surface: wgpu::Surface) { + let mut window_surfaces = self.resources.window_surfaces.write(); + window_surfaces.insert(window_id, surface); + } + + pub fn copy_buffer_to_buffer( + &self, + command_encoder: &mut wgpu::CommandEncoder, + source_buffer: BufferId, + source_offset: u64, + destination_buffer: BufferId, + destination_offset: u64, + size: u64, + ) { + let buffers = self.resources.buffers.read(); + + let source = buffers.get(&source_buffer).unwrap(); + let destination = buffers.get(&destination_buffer).unwrap(); + command_encoder.copy_buffer_to_buffer( + source, + source_offset, + destination, + destination_offset, + size, + ); + } + + #[allow(clippy::too_many_arguments)] + pub fn copy_texture_to_texture( + &self, + command_encoder: &mut wgpu::CommandEncoder, + source_texture: TextureId, + source_origin: [u32; 3], // TODO: replace with math type + source_mip_level: u32, + destination_texture: TextureId, + destination_origin: [u32; 3], // TODO: replace with math type + destination_mip_level: u32, + size: Extent3d, + ) { + let textures = self.resources.textures.read(); + let source = textures.get(&source_texture).unwrap(); + let destination = textures.get(&destination_texture).unwrap(); + command_encoder.copy_texture_to_texture( + wgpu::ImageCopyTexture { + texture: source, + mip_level: source_mip_level, + origin: wgpu::Origin3d { + x: source_origin[0], + y: source_origin[1], + z: source_origin[2], + }, + }, + wgpu::ImageCopyTexture { + texture: destination, + mip_level: destination_mip_level, + origin: wgpu::Origin3d { + x: destination_origin[0], + y: destination_origin[1], + z: destination_origin[2], + }, + }, + size.wgpu_into(), + ) + } + + #[allow(clippy::too_many_arguments)] + pub fn copy_texture_to_buffer( + &self, + command_encoder: &mut wgpu::CommandEncoder, + source_texture: TextureId, + source_origin: [u32; 3], // TODO: replace with math type + source_mip_level: u32, + destination_buffer: BufferId, + destination_offset: u64, + destination_bytes_per_row: u32, + size: Extent3d, + ) { + let buffers = self.resources.buffers.read(); + let textures = self.resources.textures.read(); + + let source = textures.get(&source_texture).unwrap(); + let destination = buffers.get(&destination_buffer).unwrap(); + command_encoder.copy_texture_to_buffer( + wgpu::ImageCopyTexture { + texture: source, + mip_level: source_mip_level, + origin: wgpu::Origin3d { + x: source_origin[0], + y: source_origin[1], + z: source_origin[2], + }, + }, + wgpu::ImageCopyBuffer { + buffer: destination, + layout: wgpu::ImageDataLayout { + offset: destination_offset, + bytes_per_row: NonZeroU32::new(destination_bytes_per_row), + rows_per_image: NonZeroU32::new(size.height), + }, + }, + size.wgpu_into(), + ); + } + + #[allow(clippy::too_many_arguments)] + pub fn copy_buffer_to_texture( + &self, + command_encoder: &mut wgpu::CommandEncoder, + source_buffer: BufferId, + source_offset: u64, + source_bytes_per_row: u32, + destination_texture: TextureId, + destination_origin: [u32; 3], // TODO: replace with math type + destination_mip_level: u32, + size: Extent3d, + ) { + let buffers = self.resources.buffers.read(); + let textures = self.resources.textures.read(); + + let source = buffers.get(&source_buffer).unwrap(); + let destination = textures.get(&destination_texture).unwrap(); + command_encoder.copy_buffer_to_texture( + wgpu::ImageCopyBuffer { + buffer: source, + layout: wgpu::ImageDataLayout { + offset: source_offset, + bytes_per_row: NonZeroU32::new(source_bytes_per_row), + rows_per_image: NonZeroU32::new(size.height), + }, + }, + wgpu::ImageCopyTexture { + texture: destination, + mip_level: destination_mip_level, + origin: wgpu::Origin3d { + x: destination_origin[0], + y: destination_origin[1], + z: destination_origin[2], + }, + }, + size.wgpu_into(), + ); + } + + pub fn create_bind_group_layout(&self, descriptor: &BindGroupDescriptor) { + if self + .resources + .bind_group_layouts + .read() + .get(&descriptor.id) + .is_some() + { + return; + } + + let mut bind_group_layouts = self.resources.bind_group_layouts.write(); + // TODO: consider re-checking existence here + let bind_group_layout_entries = descriptor + .bindings + .iter() + .map(|binding| { + let shader_stage = if binding.shader_stage + == BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT + { + wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT + } else if binding.shader_stage == BindingShaderStage::VERTEX { + wgpu::ShaderStage::VERTEX + } else if binding.shader_stage == BindingShaderStage::FRAGMENT { + wgpu::ShaderStage::FRAGMENT + } else { + panic!("Invalid binding shader stage.") + }; + wgpu::BindGroupLayoutEntry { + binding: binding.index, + visibility: shader_stage, + ty: (&binding.bind_type).wgpu_into(), + count: None, + } + }) + .collect::>(); + let wgpu_descriptor = wgpu::BindGroupLayoutDescriptor { + entries: bind_group_layout_entries.as_slice(), + label: None, + }; + let bind_group_layout = self.device.create_bind_group_layout(&wgpu_descriptor); + bind_group_layouts.insert(descriptor.id, bind_group_layout); + } + + fn try_next_swap_chain_texture(&self, window_id: bevy_window::WindowId) -> Option { + let mut window_swap_chains = self.resources.window_swap_chains.write(); + let mut swap_chain_outputs = self.resources.swap_chain_frames.write(); + + let window_swap_chain = window_swap_chains.get_mut(&window_id).unwrap(); + let next_texture = window_swap_chain.get_current_frame().ok()?; + let id = TextureId::new(); + swap_chain_outputs.insert(id, next_texture); + Some(id) + } +} + +impl RenderResourceContext for WgpuRenderResourceContext { + fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> SamplerId { + let mut samplers = self.resources.samplers.write(); + + let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).wgpu_into(); + let sampler = self.device.create_sampler(&descriptor); + + let id = SamplerId::new(); + samplers.insert(id, sampler); + id + } + + fn create_texture(&self, texture_descriptor: TextureDescriptor) -> TextureId { + let mut textures = self.resources.textures.write(); + let mut texture_views = self.resources.texture_views.write(); + let mut texture_descriptors = self.resources.texture_descriptors.write(); + + let descriptor: wgpu::TextureDescriptor = (&texture_descriptor).wgpu_into(); + let texture = self.device.create_texture(&descriptor); + let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let id = TextureId::new(); + texture_descriptors.insert(id, texture_descriptor); + texture_views.insert(id, texture_view); + textures.insert(id, texture); + id + } + + fn create_buffer(&self, buffer_info: BufferInfo) -> BufferId { + // TODO: consider moving this below "create" for efficiency + let mut buffer_infos = self.resources.buffer_infos.write(); + let mut buffers = self.resources.buffers.write(); + + let buffer = self.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: buffer_info.size as u64, + usage: buffer_info.buffer_usage.wgpu_into(), + mapped_at_creation: buffer_info.mapped_at_creation, + }); + + let id = BufferId::new(); + buffer_infos.insert(id, buffer_info); + buffers.insert(id, Arc::new(buffer)); + id + } + + fn create_buffer_with_data(&self, mut buffer_info: BufferInfo, data: &[u8]) -> BufferId { + // TODO: consider moving this below "create" for efficiency + let mut buffer_infos = self.resources.buffer_infos.write(); + let mut buffers = self.resources.buffers.write(); + + buffer_info.size = data.len(); + let buffer = self + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + contents: data, + label: None, + usage: buffer_info.buffer_usage.wgpu_into(), + }); + + let id = BufferId::new(); + buffer_infos.insert(id, buffer_info); + buffers.insert(id, Arc::new(buffer)); + id + } + + fn remove_buffer(&self, buffer: BufferId) { + let mut buffer_infos = self.resources.buffer_infos.write(); + let mut buffers = self.resources.buffers.write(); + + buffers.remove(&buffer); + buffer_infos.remove(&buffer); + } + + fn remove_texture(&self, texture: TextureId) { + let mut textures = self.resources.textures.write(); + let mut texture_views = self.resources.texture_views.write(); + let mut texture_descriptors = self.resources.texture_descriptors.write(); + + textures.remove(&texture); + texture_views.remove(&texture); + texture_descriptors.remove(&texture); + } + + fn remove_sampler(&self, sampler: SamplerId) { + let mut samplers = self.resources.samplers.write(); + samplers.remove(&sampler); + } + + fn create_shader_module_from_source(&self, shader_handle: &Handle, shader: &Shader) { + let mut shader_modules = self.resources.shader_modules.write(); + let spirv: Cow<[u32]> = shader.get_spirv(None).unwrap().into(); + let shader_module = self + .device + .create_shader_module(&wgpu::ShaderModuleDescriptor { + label: None, + source: wgpu::ShaderSource::SpirV(spirv), + flags: Default::default(), + }); + shader_modules.insert(shader_handle.clone_weak(), shader_module); + } + + fn create_shader_module(&self, shader_handle: &Handle, shaders: &Assets) { + if self + .resources + .shader_modules + .read() + .get(shader_handle) + .is_some() + { + return; + } + let shader = shaders.get(shader_handle).unwrap(); + self.create_shader_module_from_source(shader_handle, shader); + } + + fn create_swap_chain(&self, window: &Window) { + let surfaces = self.resources.window_surfaces.read(); + let mut window_swap_chains = self.resources.window_swap_chains.write(); + + let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.wgpu_into(); + let surface = surfaces + .get(&window.id()) + .expect("No surface found for window."); + let swap_chain = self + .device + .create_swap_chain(surface, &swap_chain_descriptor); + + window_swap_chains.insert(window.id(), swap_chain); + } + + fn next_swap_chain_texture(&self, window: &bevy_window::Window) -> TextureId { + if let Some(texture_id) = self.try_next_swap_chain_texture(window.id()) { + texture_id + } else { + self.resources + .window_swap_chains + .write() + .remove(&window.id()); + self.create_swap_chain(window); + self.try_next_swap_chain_texture(window.id()) + .expect("Failed to acquire next swap chain texture!") + } + } + + fn drop_swap_chain_texture(&self, texture: TextureId) { + let mut swap_chain_outputs = self.resources.swap_chain_frames.write(); + swap_chain_outputs.remove(&texture); + } + + fn drop_all_swap_chain_textures(&self) { + let mut swap_chain_outputs = self.resources.swap_chain_frames.write(); + swap_chain_outputs.clear(); + } + + fn set_asset_resource_untyped( + &self, + handle: HandleUntyped, + render_resource: RenderResourceId, + index: u64, + ) { + let mut asset_resources = self.resources.asset_resources.write(); + asset_resources.insert((handle, index), render_resource); + } + + fn get_asset_resource_untyped( + &self, + handle: HandleUntyped, + index: u64, + ) -> Option { + let asset_resources = self.resources.asset_resources.read(); + asset_resources.get(&(handle, index)).cloned() + } + + fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: u64) { + let mut asset_resources = self.resources.asset_resources.write(); + asset_resources.remove(&(handle, index)); + } + + fn create_render_pipeline( + &self, + pipeline_handle: Handle, + pipeline_descriptor: &PipelineDescriptor, + shaders: &Assets, + ) { + if self + .resources + .render_pipelines + .read() + .get(&pipeline_handle) + .is_some() + { + return; + } + + let layout = pipeline_descriptor.get_layout().unwrap(); + for bind_group_descriptor in layout.bind_groups.iter() { + self.create_bind_group_layout(bind_group_descriptor); + } + + let bind_group_layouts = self.resources.bind_group_layouts.read(); + // setup and collect bind group layouts + let bind_group_layouts = layout + .bind_groups + .iter() + .map(|bind_group| bind_group_layouts.get(&bind_group.id).unwrap()) + .collect::>(); + + let pipeline_layout = self + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: bind_group_layouts.as_slice(), + push_constant_ranges: &[], + }); + + let owned_vertex_buffer_descriptors = layout + .vertex_buffer_descriptors + .iter() + .map(|v| v.wgpu_into()) + .collect::>(); + + let color_states = pipeline_descriptor + .color_target_states + .iter() + .map(|c| c.wgpu_into()) + .collect::>(); + + self.create_shader_module(&pipeline_descriptor.shader_stages.vertex, shaders); + + if let Some(ref fragment_handle) = pipeline_descriptor.shader_stages.fragment { + self.create_shader_module(fragment_handle, shaders); + } + + let shader_modules = self.resources.shader_modules.read(); + let vertex_shader_module = shader_modules + .get(&pipeline_descriptor.shader_stages.vertex) + .unwrap(); + + let fragment_shader_module = pipeline_descriptor + .shader_stages + .fragment + .as_ref() + .map(|fragment_handle| shader_modules.get(fragment_handle).unwrap()); + let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&pipeline_layout), + vertex: wgpu::VertexState { + module: vertex_shader_module, + entry_point: "main", + buffers: &owned_vertex_buffer_descriptors + .iter() + .map(|v| v.into()) + .collect::>(), + }, + fragment: pipeline_descriptor + .shader_stages + .fragment + .as_ref() + .map(|_| wgpu::FragmentState { + entry_point: "main", + module: fragment_shader_module.as_ref().unwrap(), + targets: color_states.as_slice(), + }), + primitive: pipeline_descriptor.primitive.clone().wgpu_into(), + depth_stencil: pipeline_descriptor + .depth_stencil + .clone() + .map(|depth_stencil| depth_stencil.wgpu_into()), + multisample: pipeline_descriptor.multisample.clone().wgpu_into(), + }; + + let render_pipeline = self + .device + .create_render_pipeline(&render_pipeline_descriptor); + let mut render_pipelines = self.resources.render_pipelines.write(); + render_pipelines.insert(pipeline_handle, render_pipeline); + } + + fn bind_group_descriptor_exists( + &self, + bind_group_descriptor_id: BindGroupDescriptorId, + ) -> bool { + let bind_group_layouts = self.resources.bind_group_layouts.read(); + bind_group_layouts.get(&bind_group_descriptor_id).is_some() + } + + fn create_bind_group( + &self, + bind_group_descriptor_id: BindGroupDescriptorId, + bind_group: &BindGroup, + ) { + if !self + .resources + .has_bind_group(bind_group_descriptor_id, bind_group.id) + { + trace!( + "start creating bind group for RenderResourceSet {:?}", + bind_group.id + ); + let texture_views = self.resources.texture_views.read(); + let samplers = self.resources.samplers.read(); + let buffers = self.resources.buffers.read(); + let bind_group_layouts = self.resources.bind_group_layouts.read(); + let mut bind_groups = self.resources.bind_groups.write(); + + let entries = bind_group + .indexed_bindings + .iter() + .map(|indexed_binding| { + let wgpu_resource = match &indexed_binding.entry { + RenderResourceBinding::Texture(resource) => { + let texture_view = texture_views + .get(resource) + .unwrap_or_else(|| panic!("{:?}", resource)); + wgpu::BindingResource::TextureView(texture_view) + } + RenderResourceBinding::Sampler(resource) => { + let sampler = samplers.get(resource).unwrap(); + wgpu::BindingResource::Sampler(sampler) + } + RenderResourceBinding::Buffer { buffer, range, .. } => { + let wgpu_buffer = buffers.get(buffer).unwrap(); + let size = NonZeroU64::new(range.end - range.start) + .expect("Size of the buffer needs to be greater than 0!"); + wgpu::BindingResource::Buffer(wgpu::BufferBinding { + buffer: wgpu_buffer, + offset: range.start, + size: Some(size), + }) + } + }; + wgpu::BindGroupEntry { + binding: indexed_binding.index, + resource: wgpu_resource, + } + }) + .collect::>(); + + let bind_group_layout = bind_group_layouts.get(&bind_group_descriptor_id).unwrap(); + let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor { + label: None, + layout: bind_group_layout, + entries: entries.as_slice(), + }; + let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor); + + let bind_group_info = bind_groups + .entry(bind_group_descriptor_id) + .or_insert_with(WgpuBindGroupInfo::default); + bind_group_info + .bind_groups + .insert(bind_group.id, wgpu_bind_group); + trace!( + "created bind group for RenderResourceSet {:?}", + bind_group.id + ); + } + } + + fn clear_bind_groups(&self) { + self.resources.bind_groups.write().clear(); + } + + fn remove_stale_bind_groups(&self) { + self.resources.remove_stale_bind_groups(); + } + + fn get_buffer_info(&self, buffer: BufferId) -> Option { + self.resources.buffer_infos.read().get(&buffer).cloned() + } + + fn write_mapped_buffer( + &self, + id: BufferId, + range: Range, + write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext), + ) { + let buffer = { + let buffers = self.resources.buffers.read(); + buffers.get(&id).unwrap().clone() + }; + let buffer_slice = buffer.slice(range); + let mut data = buffer_slice.get_mapped_range_mut(); + write(&mut data, self); + } + + fn read_mapped_buffer( + &self, + id: BufferId, + range: Range, + read: &dyn Fn(&[u8], &dyn RenderResourceContext), + ) { + let buffer = { + let buffers = self.resources.buffers.read(); + buffers.get(&id).unwrap().clone() + }; + let buffer_slice = buffer.slice(range); + let data = buffer_slice.get_mapped_range(); + read(&data, self); + } + + fn map_buffer(&self, id: BufferId, mode: BufferMapMode) { + let buffers = self.resources.buffers.read(); + let buffer = buffers.get(&id).unwrap(); + let buffer_slice = buffer.slice(..); + let wgpu_mode = match mode { + BufferMapMode::Read => wgpu::MapMode::Read, + BufferMapMode::Write => wgpu::MapMode::Write, + }; + let data = buffer_slice.map_async(wgpu_mode); + self.device.poll(wgpu::Maintain::Wait); + if async_global_executor::block_on(data).is_err() { + panic!("Failed to map buffer to host."); + } + } + + fn unmap_buffer(&self, id: BufferId) { + let buffers = self.resources.buffers.read(); + let buffer = buffers.get(&id).unwrap(); + buffer.unmap(); + } + + fn get_aligned_texture_size(&self, size: usize) -> usize { + (size + COPY_BYTES_PER_ROW_ALIGNMENT - 1) & !(COPY_BYTES_PER_ROW_ALIGNMENT - 1) + } + + fn get_aligned_uniform_size(&self, size: usize, dynamic: bool) -> usize { + if dynamic { + (size + BIND_BUFFER_ALIGNMENT - 1) & !(BIND_BUFFER_ALIGNMENT - 1) + } else { + size + } + } + + fn get_specialized_shader( + &self, + shader: &Shader, + macros: Option<&[String]>, + ) -> Result { + let spirv_data = match shader.source { + ShaderSource::Spirv(ref bytes) => bytes.clone(), + ShaderSource::Glsl(ref source) => glsl_to_spirv(source, shader.stage, macros)?, + }; + Ok(Shader { + source: ShaderSource::Spirv(spirv_data), + ..*shader + }) + } +} diff --git a/deny.toml b/deny.toml index 31a26b8ee5e18..9c2ab206eefee 100644 --- a/deny.toml +++ b/deny.toml @@ -35,24 +35,26 @@ wildcards = "deny" highlight = "all" # Certain crates/versions that will be skipped when doing duplicate detection. skip = [ - { name = "cfg-if", version = "0.1" }, # from winit v0.26.0 - { name = "core-foundation", version = "0.7" }, # from winit v0.26.0 - { name = "core-foundation-sys", version = "0.7" }, # from winit v0.26.0 - { name = "core-graphics", version = "0.19" }, # from winit v0.26.0 - { name = "ndk", version = "0.5" }, # from winit v0.26.1 - { name = "ndk", version = "0.6" }, # from rodio v0.16.0 - { name = "ndk-glue", version = "0.5" }, # from winit v0.26.1 - { name = "ndk-sys", version = "0.2" }, # from winit v0.26.1 - { name = "ndk-sys", version = "0.3" }, # from rodio v0.16.0 - { name = "parking_lot", version = "0.11" }, # from winit v0.26.1 - { name = "parking_lot_core", version = "0.8" }, # from winit v0.26.1 - { name = "raw-window-handle", version = "0.4" }, # from wgpu v0.13.0 - { name = "nix", version = "0.23.1" }, # from alsa v0.6.0 - { name = "windows_aarch64_msvc", version = "0.36" }, # from notify v5.0.0 - { name = "windows_i686_gnu", version = "0.36" }, # from notify v5.0.0 - { name = "windows_i686_msvc", version = "0.36" }, # from notify v5.0.0 - { name = "windows_x86_64_gnu", version = "0.36" }, # from notify v5.0.0 - { name = "windows_x86_64_msvc", version = "0.36" }, # from notify v5.0.0 + { name = "ahash", version = "0.4" }, + { name = "android_log-sys", version = "0.1" }, + { name = "cfg-if", version = "0.1" }, # https://github.com/rustwasm/console_error_panic_hook/pull/18 + { name = "core-foundation", version = "0.6" }, + { name = "core-foundation", version = "0.7" }, + { name = "core-foundation-sys", version = "0.6" }, + { name = "core-foundation-sys", version = "0.7" }, + { name = "core-graphics", version = "0.19" }, + { name = "fixedbitset", version = "0.2" }, + { name = "hashbrown", version = "0.9" }, + { name = "jni", version = "0.18.0" }, + { name = "jni", version = "0.19.0" }, + { name = "libm", version = "0.1" }, + { name = "mach", version = "0.2" }, + { name = "ndk", version = "0.2" }, + { name = "ndk-glue", version = "0.2" }, + { name = "num_enum", version = "0.4" }, + { name = "num_enum_derive", version = "0.4" }, + { name = "proc-macro-crate", version = "0.1" }, + { name = "stdweb", version = "0.1" }, ] [sources] 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..2720d8a1211c8 100644 --- a/examples/async_tasks/async_compute.rs +++ b/examples/async_tasks/async_compute.rs @@ -87,8 +87,8 @@ fn handle_tasks( box_mesh_handle: Res, 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)) { + for (entity, mut task) in transform_tasks { + if let Some(transform) = bevy::tasks::block_on(future::poll_once(&mut *task)) { // Add our new PbrBundle of components to our tagged entity commands.entity(entity).insert(PbrBundle { mesh: box_mesh_handle.clone(), From 42ee29b57fe43082d46b4da2b6f1e29847b202c5 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Sat, 26 Feb 2022 01:17:16 +0800 Subject: [PATCH 2/4] cleanup --- Cargo.toml | 1 - crates/bevy_crevice/Cargo.toml | 0 2 files changed, 1 deletion(-) create mode 100644 crates/bevy_crevice/Cargo.toml diff --git a/Cargo.toml b/Cargo.toml index 9f9241e1ca0ff..f202c3424c9a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ keywords = ["game", "engine", "gamedev", "graphics", "bevy"] license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/bevyengine/bevy" -resolver = "2" [workspace] exclude = ["benches", "crates/bevy_ecs_compile_fail_tests"] diff --git a/crates/bevy_crevice/Cargo.toml b/crates/bevy_crevice/Cargo.toml new file mode 100644 index 0000000000000..e69de29bb2d1d From e7f726dab2e7a2c13daae2942499e6b178db05c9 Mon Sep 17 00:00:00 2001 From: Pessi Date: Mon, 26 Sep 2022 15:11:06 +0200 Subject: [PATCH 3/4] Cleanup Cleanup Add new features to main bevy crate --- Cargo.toml | 2 +- crates/bevy_asset/src/asset_server.rs | 6 +- crates/bevy_crevice/Cargo.toml | 0 crates/bevy_internal/Cargo.toml | 4 +- crates/bevy_render/Cargo.toml | 2 +- crates/bevy_tasks/Cargo.toml | 5 +- crates/bevy_tasks/src/countdown_event.rs | 0 crates/bevy_wgpu/Cargo.toml | 38 - crates/bevy_wgpu/src/lib.rs | 0 .../renderer/wgpu_render_resource_context.rs | 693 ------------------ deny.toml | 38 +- examples/async_tasks/async_compute.rs | 4 +- 12 files changed, 28 insertions(+), 764 deletions(-) delete mode 100644 crates/bevy_crevice/Cargo.toml delete mode 100644 crates/bevy_tasks/src/countdown_event.rs delete mode 100644 crates/bevy_wgpu/Cargo.toml delete mode 100644 crates/bevy_wgpu/src/lib.rs delete mode 100644 crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs diff --git a/Cargo.toml b/Cargo.toml index f202c3424c9a6..0d25cd6168bec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,7 +135,7 @@ ron = "0.8.0" serde = { version = "1", features = ["derive"] } bytemuck = "1.7" # Needed to poll Task examples -futures-lite = "1.12.0" +futures-lite = "1.11.3" crossbeam-channel = "0.5.0" [[example]] diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 6b0da9d9a43f5..4999a08280912 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -7,7 +7,7 @@ use crate::{ use anyhow::Result; use bevy_ecs::system::{Res, ResMut, Resource}; use bevy_log::warn; -use bevy_tasks::{self, TaskPool}; +use bevy_tasks::IoTaskPool; use bevy_utils::{Entry, HashMap, Uuid}; use crossbeam_channel::TryRecvError; use parking_lot::{Mutex, RwLock}; @@ -856,8 +856,8 @@ mod test { app.add_system(update_asset_storage_system::.after(FreeUnusedAssets)); fn load_asset(path: AssetPath, world: &World) -> HandleUntyped { - let asset_server = world.get_resource::().unwrap(); - let id = futures_lite::future::block_on(asset_server.load_async(path.clone(), true)) + let asset_server = world.resource::(); + 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_crevice/Cargo.toml b/crates/bevy_crevice/Cargo.toml deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index b71608031f290..5cfbe75cdc533 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -64,8 +64,8 @@ bevy_ci_testing = ["bevy_app/bevy_ci_testing", "bevy_render/ci_limits"] animation = ["bevy_animation", "bevy_gltf?/bevy_animation"] # alternative async executors, defaults to futures-lite -async-io = ["bevy_tasks/async-io", "bevy_wgpu/async-io"] -tokio = ["bevy_tasks/tokio", "bevy_wgpu/tokio"] +async-io = ["bevy_tasks/async-io"] +tokio = ["bevy_tasks/tokio"] [dependencies] # bevy 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 28b562c2081f1..56acc536853e6 100644 --- a/crates/bevy_tasks/Cargo.toml +++ b/crates/bevy_tasks/Cargo.toml @@ -8,16 +8,13 @@ repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" keywords = ["bevy"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] async-io = ["async-global-executor/async-io"] tokio = ["async-global-executor/tokio"] [dependencies] -futures-lite = "1.4.0" -async-global-executor= { version="2.0.2", default-features = false } futures-lite = "1.12.0" -event-listener = "2.4.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/countdown_event.rs b/crates/bevy_tasks/src/countdown_event.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/crates/bevy_wgpu/Cargo.toml b/crates/bevy_wgpu/Cargo.toml deleted file mode 100644 index af6797cd770b1..0000000000000 --- a/crates/bevy_wgpu/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "bevy_wgpu" -version = "0.5.0" -edition = "2018" -authors = [ - "Bevy Contributors ", - "Carter Anderson ", -] -description = "A wgpu render backend for Bevy Engine" -homepage = "https://bevyengine.org" -repository = "https://github.com/bevyengine/bevy" -license = "MIT OR Apache-2.0" -keywords = ["bevy"] - -[features] -default = ["bevy_winit"] -trace = ["wgpu/trace"] -async-io = ["async-global-executor/async-io"] -tokio = ["async-global-executor/tokio"] - -[dependencies] -# bevy -bevy_app = { path = "../bevy_app", version = "0.5.0" } -bevy_asset = { path = "../bevy_asset", version = "0.5.0" } -bevy_core = { path = "../bevy_core", version = "0.5.0" } -bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.5.0" } -bevy_ecs = { path = "../bevy_ecs", version = "0.5.0" } -bevy_render = { path = "../bevy_render", version = "0.5.0" } -bevy_window = { path = "../bevy_window", version = "0.5.0" } -bevy_winit = { path = "../bevy_winit", optional = true, version = "0.5.0" } -bevy_utils = { path = "../bevy_utils", version = "0.5.0" } - -# other -wgpu = "0.9" -crossbeam-channel = "0.5.0" -crossbeam-utils = "0.8.1" -parking_lot = "0.11.0" -async-global-executor= { version="2.0.2", default-features = false } \ No newline at end of file diff --git a/crates/bevy_wgpu/src/lib.rs b/crates/bevy_wgpu/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs b/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs deleted file mode 100644 index 2168e6109f631..0000000000000 --- a/crates/bevy_wgpu/src/renderer/wgpu_render_resource_context.rs +++ /dev/null @@ -1,693 +0,0 @@ -use crate::{wgpu_type_converter::WgpuInto, WgpuBindGroupInfo, WgpuResources}; - -use crate::wgpu_type_converter::OwnedWgpuVertexBufferLayout; -use bevy_asset::{Assets, Handle, HandleUntyped}; -use bevy_render::{ - pipeline::{ - BindGroupDescriptor, BindGroupDescriptorId, BindingShaderStage, PipelineDescriptor, - }, - renderer::{ - BindGroup, BufferId, BufferInfo, BufferMapMode, RenderResourceBinding, - RenderResourceContext, RenderResourceId, SamplerId, TextureId, - }, - shader::{glsl_to_spirv, Shader, ShaderError, ShaderSource}, - texture::{Extent3d, SamplerDescriptor, TextureDescriptor}, -}; -use bevy_utils::tracing::trace; -use bevy_window::{Window, WindowId}; -use std::{ - borrow::Cow, - num::{NonZeroU32, NonZeroU64}, - ops::Range, - sync::Arc, -}; -use wgpu::util::DeviceExt; - -#[derive(Clone, Debug)] -pub struct WgpuRenderResourceContext { - pub device: Arc, - pub resources: WgpuResources, -} - -pub const COPY_BYTES_PER_ROW_ALIGNMENT: usize = wgpu::COPY_BYTES_PER_ROW_ALIGNMENT as usize; -pub const BIND_BUFFER_ALIGNMENT: usize = wgpu::BIND_BUFFER_ALIGNMENT as usize; -pub const COPY_BUFFER_ALIGNMENT: usize = wgpu::COPY_BUFFER_ALIGNMENT as usize; -pub const PUSH_CONSTANT_ALIGNMENT: u32 = wgpu::PUSH_CONSTANT_ALIGNMENT; - -impl WgpuRenderResourceContext { - pub fn new(device: Arc) -> Self { - WgpuRenderResourceContext { - device, - resources: WgpuResources::default(), - } - } - - pub fn set_window_surface(&self, window_id: WindowId, surface: wgpu::Surface) { - let mut window_surfaces = self.resources.window_surfaces.write(); - window_surfaces.insert(window_id, surface); - } - - pub fn copy_buffer_to_buffer( - &self, - command_encoder: &mut wgpu::CommandEncoder, - source_buffer: BufferId, - source_offset: u64, - destination_buffer: BufferId, - destination_offset: u64, - size: u64, - ) { - let buffers = self.resources.buffers.read(); - - let source = buffers.get(&source_buffer).unwrap(); - let destination = buffers.get(&destination_buffer).unwrap(); - command_encoder.copy_buffer_to_buffer( - source, - source_offset, - destination, - destination_offset, - size, - ); - } - - #[allow(clippy::too_many_arguments)] - pub fn copy_texture_to_texture( - &self, - command_encoder: &mut wgpu::CommandEncoder, - source_texture: TextureId, - source_origin: [u32; 3], // TODO: replace with math type - source_mip_level: u32, - destination_texture: TextureId, - destination_origin: [u32; 3], // TODO: replace with math type - destination_mip_level: u32, - size: Extent3d, - ) { - let textures = self.resources.textures.read(); - let source = textures.get(&source_texture).unwrap(); - let destination = textures.get(&destination_texture).unwrap(); - command_encoder.copy_texture_to_texture( - wgpu::ImageCopyTexture { - texture: source, - mip_level: source_mip_level, - origin: wgpu::Origin3d { - x: source_origin[0], - y: source_origin[1], - z: source_origin[2], - }, - }, - wgpu::ImageCopyTexture { - texture: destination, - mip_level: destination_mip_level, - origin: wgpu::Origin3d { - x: destination_origin[0], - y: destination_origin[1], - z: destination_origin[2], - }, - }, - size.wgpu_into(), - ) - } - - #[allow(clippy::too_many_arguments)] - pub fn copy_texture_to_buffer( - &self, - command_encoder: &mut wgpu::CommandEncoder, - source_texture: TextureId, - source_origin: [u32; 3], // TODO: replace with math type - source_mip_level: u32, - destination_buffer: BufferId, - destination_offset: u64, - destination_bytes_per_row: u32, - size: Extent3d, - ) { - let buffers = self.resources.buffers.read(); - let textures = self.resources.textures.read(); - - let source = textures.get(&source_texture).unwrap(); - let destination = buffers.get(&destination_buffer).unwrap(); - command_encoder.copy_texture_to_buffer( - wgpu::ImageCopyTexture { - texture: source, - mip_level: source_mip_level, - origin: wgpu::Origin3d { - x: source_origin[0], - y: source_origin[1], - z: source_origin[2], - }, - }, - wgpu::ImageCopyBuffer { - buffer: destination, - layout: wgpu::ImageDataLayout { - offset: destination_offset, - bytes_per_row: NonZeroU32::new(destination_bytes_per_row), - rows_per_image: NonZeroU32::new(size.height), - }, - }, - size.wgpu_into(), - ); - } - - #[allow(clippy::too_many_arguments)] - pub fn copy_buffer_to_texture( - &self, - command_encoder: &mut wgpu::CommandEncoder, - source_buffer: BufferId, - source_offset: u64, - source_bytes_per_row: u32, - destination_texture: TextureId, - destination_origin: [u32; 3], // TODO: replace with math type - destination_mip_level: u32, - size: Extent3d, - ) { - let buffers = self.resources.buffers.read(); - let textures = self.resources.textures.read(); - - let source = buffers.get(&source_buffer).unwrap(); - let destination = textures.get(&destination_texture).unwrap(); - command_encoder.copy_buffer_to_texture( - wgpu::ImageCopyBuffer { - buffer: source, - layout: wgpu::ImageDataLayout { - offset: source_offset, - bytes_per_row: NonZeroU32::new(source_bytes_per_row), - rows_per_image: NonZeroU32::new(size.height), - }, - }, - wgpu::ImageCopyTexture { - texture: destination, - mip_level: destination_mip_level, - origin: wgpu::Origin3d { - x: destination_origin[0], - y: destination_origin[1], - z: destination_origin[2], - }, - }, - size.wgpu_into(), - ); - } - - pub fn create_bind_group_layout(&self, descriptor: &BindGroupDescriptor) { - if self - .resources - .bind_group_layouts - .read() - .get(&descriptor.id) - .is_some() - { - return; - } - - let mut bind_group_layouts = self.resources.bind_group_layouts.write(); - // TODO: consider re-checking existence here - let bind_group_layout_entries = descriptor - .bindings - .iter() - .map(|binding| { - let shader_stage = if binding.shader_stage - == BindingShaderStage::VERTEX | BindingShaderStage::FRAGMENT - { - wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT - } else if binding.shader_stage == BindingShaderStage::VERTEX { - wgpu::ShaderStage::VERTEX - } else if binding.shader_stage == BindingShaderStage::FRAGMENT { - wgpu::ShaderStage::FRAGMENT - } else { - panic!("Invalid binding shader stage.") - }; - wgpu::BindGroupLayoutEntry { - binding: binding.index, - visibility: shader_stage, - ty: (&binding.bind_type).wgpu_into(), - count: None, - } - }) - .collect::>(); - let wgpu_descriptor = wgpu::BindGroupLayoutDescriptor { - entries: bind_group_layout_entries.as_slice(), - label: None, - }; - let bind_group_layout = self.device.create_bind_group_layout(&wgpu_descriptor); - bind_group_layouts.insert(descriptor.id, bind_group_layout); - } - - fn try_next_swap_chain_texture(&self, window_id: bevy_window::WindowId) -> Option { - let mut window_swap_chains = self.resources.window_swap_chains.write(); - let mut swap_chain_outputs = self.resources.swap_chain_frames.write(); - - let window_swap_chain = window_swap_chains.get_mut(&window_id).unwrap(); - let next_texture = window_swap_chain.get_current_frame().ok()?; - let id = TextureId::new(); - swap_chain_outputs.insert(id, next_texture); - Some(id) - } -} - -impl RenderResourceContext for WgpuRenderResourceContext { - fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> SamplerId { - let mut samplers = self.resources.samplers.write(); - - let descriptor: wgpu::SamplerDescriptor = (*sampler_descriptor).wgpu_into(); - let sampler = self.device.create_sampler(&descriptor); - - let id = SamplerId::new(); - samplers.insert(id, sampler); - id - } - - fn create_texture(&self, texture_descriptor: TextureDescriptor) -> TextureId { - let mut textures = self.resources.textures.write(); - let mut texture_views = self.resources.texture_views.write(); - let mut texture_descriptors = self.resources.texture_descriptors.write(); - - let descriptor: wgpu::TextureDescriptor = (&texture_descriptor).wgpu_into(); - let texture = self.device.create_texture(&descriptor); - let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); - - let id = TextureId::new(); - texture_descriptors.insert(id, texture_descriptor); - texture_views.insert(id, texture_view); - textures.insert(id, texture); - id - } - - fn create_buffer(&self, buffer_info: BufferInfo) -> BufferId { - // TODO: consider moving this below "create" for efficiency - let mut buffer_infos = self.resources.buffer_infos.write(); - let mut buffers = self.resources.buffers.write(); - - let buffer = self.device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: buffer_info.size as u64, - usage: buffer_info.buffer_usage.wgpu_into(), - mapped_at_creation: buffer_info.mapped_at_creation, - }); - - let id = BufferId::new(); - buffer_infos.insert(id, buffer_info); - buffers.insert(id, Arc::new(buffer)); - id - } - - fn create_buffer_with_data(&self, mut buffer_info: BufferInfo, data: &[u8]) -> BufferId { - // TODO: consider moving this below "create" for efficiency - let mut buffer_infos = self.resources.buffer_infos.write(); - let mut buffers = self.resources.buffers.write(); - - buffer_info.size = data.len(); - let buffer = self - .device - .create_buffer_init(&wgpu::util::BufferInitDescriptor { - contents: data, - label: None, - usage: buffer_info.buffer_usage.wgpu_into(), - }); - - let id = BufferId::new(); - buffer_infos.insert(id, buffer_info); - buffers.insert(id, Arc::new(buffer)); - id - } - - fn remove_buffer(&self, buffer: BufferId) { - let mut buffer_infos = self.resources.buffer_infos.write(); - let mut buffers = self.resources.buffers.write(); - - buffers.remove(&buffer); - buffer_infos.remove(&buffer); - } - - fn remove_texture(&self, texture: TextureId) { - let mut textures = self.resources.textures.write(); - let mut texture_views = self.resources.texture_views.write(); - let mut texture_descriptors = self.resources.texture_descriptors.write(); - - textures.remove(&texture); - texture_views.remove(&texture); - texture_descriptors.remove(&texture); - } - - fn remove_sampler(&self, sampler: SamplerId) { - let mut samplers = self.resources.samplers.write(); - samplers.remove(&sampler); - } - - fn create_shader_module_from_source(&self, shader_handle: &Handle, shader: &Shader) { - let mut shader_modules = self.resources.shader_modules.write(); - let spirv: Cow<[u32]> = shader.get_spirv(None).unwrap().into(); - let shader_module = self - .device - .create_shader_module(&wgpu::ShaderModuleDescriptor { - label: None, - source: wgpu::ShaderSource::SpirV(spirv), - flags: Default::default(), - }); - shader_modules.insert(shader_handle.clone_weak(), shader_module); - } - - fn create_shader_module(&self, shader_handle: &Handle, shaders: &Assets) { - if self - .resources - .shader_modules - .read() - .get(shader_handle) - .is_some() - { - return; - } - let shader = shaders.get(shader_handle).unwrap(); - self.create_shader_module_from_source(shader_handle, shader); - } - - fn create_swap_chain(&self, window: &Window) { - let surfaces = self.resources.window_surfaces.read(); - let mut window_swap_chains = self.resources.window_swap_chains.write(); - - let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.wgpu_into(); - let surface = surfaces - .get(&window.id()) - .expect("No surface found for window."); - let swap_chain = self - .device - .create_swap_chain(surface, &swap_chain_descriptor); - - window_swap_chains.insert(window.id(), swap_chain); - } - - fn next_swap_chain_texture(&self, window: &bevy_window::Window) -> TextureId { - if let Some(texture_id) = self.try_next_swap_chain_texture(window.id()) { - texture_id - } else { - self.resources - .window_swap_chains - .write() - .remove(&window.id()); - self.create_swap_chain(window); - self.try_next_swap_chain_texture(window.id()) - .expect("Failed to acquire next swap chain texture!") - } - } - - fn drop_swap_chain_texture(&self, texture: TextureId) { - let mut swap_chain_outputs = self.resources.swap_chain_frames.write(); - swap_chain_outputs.remove(&texture); - } - - fn drop_all_swap_chain_textures(&self) { - let mut swap_chain_outputs = self.resources.swap_chain_frames.write(); - swap_chain_outputs.clear(); - } - - fn set_asset_resource_untyped( - &self, - handle: HandleUntyped, - render_resource: RenderResourceId, - index: u64, - ) { - let mut asset_resources = self.resources.asset_resources.write(); - asset_resources.insert((handle, index), render_resource); - } - - fn get_asset_resource_untyped( - &self, - handle: HandleUntyped, - index: u64, - ) -> Option { - let asset_resources = self.resources.asset_resources.read(); - asset_resources.get(&(handle, index)).cloned() - } - - fn remove_asset_resource_untyped(&self, handle: HandleUntyped, index: u64) { - let mut asset_resources = self.resources.asset_resources.write(); - asset_resources.remove(&(handle, index)); - } - - fn create_render_pipeline( - &self, - pipeline_handle: Handle, - pipeline_descriptor: &PipelineDescriptor, - shaders: &Assets, - ) { - if self - .resources - .render_pipelines - .read() - .get(&pipeline_handle) - .is_some() - { - return; - } - - let layout = pipeline_descriptor.get_layout().unwrap(); - for bind_group_descriptor in layout.bind_groups.iter() { - self.create_bind_group_layout(bind_group_descriptor); - } - - let bind_group_layouts = self.resources.bind_group_layouts.read(); - // setup and collect bind group layouts - let bind_group_layouts = layout - .bind_groups - .iter() - .map(|bind_group| bind_group_layouts.get(&bind_group.id).unwrap()) - .collect::>(); - - let pipeline_layout = self - .device - .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: None, - bind_group_layouts: bind_group_layouts.as_slice(), - push_constant_ranges: &[], - }); - - let owned_vertex_buffer_descriptors = layout - .vertex_buffer_descriptors - .iter() - .map(|v| v.wgpu_into()) - .collect::>(); - - let color_states = pipeline_descriptor - .color_target_states - .iter() - .map(|c| c.wgpu_into()) - .collect::>(); - - self.create_shader_module(&pipeline_descriptor.shader_stages.vertex, shaders); - - if let Some(ref fragment_handle) = pipeline_descriptor.shader_stages.fragment { - self.create_shader_module(fragment_handle, shaders); - } - - let shader_modules = self.resources.shader_modules.read(); - let vertex_shader_module = shader_modules - .get(&pipeline_descriptor.shader_stages.vertex) - .unwrap(); - - let fragment_shader_module = pipeline_descriptor - .shader_stages - .fragment - .as_ref() - .map(|fragment_handle| shader_modules.get(fragment_handle).unwrap()); - let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor { - label: None, - layout: Some(&pipeline_layout), - vertex: wgpu::VertexState { - module: vertex_shader_module, - entry_point: "main", - buffers: &owned_vertex_buffer_descriptors - .iter() - .map(|v| v.into()) - .collect::>(), - }, - fragment: pipeline_descriptor - .shader_stages - .fragment - .as_ref() - .map(|_| wgpu::FragmentState { - entry_point: "main", - module: fragment_shader_module.as_ref().unwrap(), - targets: color_states.as_slice(), - }), - primitive: pipeline_descriptor.primitive.clone().wgpu_into(), - depth_stencil: pipeline_descriptor - .depth_stencil - .clone() - .map(|depth_stencil| depth_stencil.wgpu_into()), - multisample: pipeline_descriptor.multisample.clone().wgpu_into(), - }; - - let render_pipeline = self - .device - .create_render_pipeline(&render_pipeline_descriptor); - let mut render_pipelines = self.resources.render_pipelines.write(); - render_pipelines.insert(pipeline_handle, render_pipeline); - } - - fn bind_group_descriptor_exists( - &self, - bind_group_descriptor_id: BindGroupDescriptorId, - ) -> bool { - let bind_group_layouts = self.resources.bind_group_layouts.read(); - bind_group_layouts.get(&bind_group_descriptor_id).is_some() - } - - fn create_bind_group( - &self, - bind_group_descriptor_id: BindGroupDescriptorId, - bind_group: &BindGroup, - ) { - if !self - .resources - .has_bind_group(bind_group_descriptor_id, bind_group.id) - { - trace!( - "start creating bind group for RenderResourceSet {:?}", - bind_group.id - ); - let texture_views = self.resources.texture_views.read(); - let samplers = self.resources.samplers.read(); - let buffers = self.resources.buffers.read(); - let bind_group_layouts = self.resources.bind_group_layouts.read(); - let mut bind_groups = self.resources.bind_groups.write(); - - let entries = bind_group - .indexed_bindings - .iter() - .map(|indexed_binding| { - let wgpu_resource = match &indexed_binding.entry { - RenderResourceBinding::Texture(resource) => { - let texture_view = texture_views - .get(resource) - .unwrap_or_else(|| panic!("{:?}", resource)); - wgpu::BindingResource::TextureView(texture_view) - } - RenderResourceBinding::Sampler(resource) => { - let sampler = samplers.get(resource).unwrap(); - wgpu::BindingResource::Sampler(sampler) - } - RenderResourceBinding::Buffer { buffer, range, .. } => { - let wgpu_buffer = buffers.get(buffer).unwrap(); - let size = NonZeroU64::new(range.end - range.start) - .expect("Size of the buffer needs to be greater than 0!"); - wgpu::BindingResource::Buffer(wgpu::BufferBinding { - buffer: wgpu_buffer, - offset: range.start, - size: Some(size), - }) - } - }; - wgpu::BindGroupEntry { - binding: indexed_binding.index, - resource: wgpu_resource, - } - }) - .collect::>(); - - let bind_group_layout = bind_group_layouts.get(&bind_group_descriptor_id).unwrap(); - let wgpu_bind_group_descriptor = wgpu::BindGroupDescriptor { - label: None, - layout: bind_group_layout, - entries: entries.as_slice(), - }; - let wgpu_bind_group = self.device.create_bind_group(&wgpu_bind_group_descriptor); - - let bind_group_info = bind_groups - .entry(bind_group_descriptor_id) - .or_insert_with(WgpuBindGroupInfo::default); - bind_group_info - .bind_groups - .insert(bind_group.id, wgpu_bind_group); - trace!( - "created bind group for RenderResourceSet {:?}", - bind_group.id - ); - } - } - - fn clear_bind_groups(&self) { - self.resources.bind_groups.write().clear(); - } - - fn remove_stale_bind_groups(&self) { - self.resources.remove_stale_bind_groups(); - } - - fn get_buffer_info(&self, buffer: BufferId) -> Option { - self.resources.buffer_infos.read().get(&buffer).cloned() - } - - fn write_mapped_buffer( - &self, - id: BufferId, - range: Range, - write: &mut dyn FnMut(&mut [u8], &dyn RenderResourceContext), - ) { - let buffer = { - let buffers = self.resources.buffers.read(); - buffers.get(&id).unwrap().clone() - }; - let buffer_slice = buffer.slice(range); - let mut data = buffer_slice.get_mapped_range_mut(); - write(&mut data, self); - } - - fn read_mapped_buffer( - &self, - id: BufferId, - range: Range, - read: &dyn Fn(&[u8], &dyn RenderResourceContext), - ) { - let buffer = { - let buffers = self.resources.buffers.read(); - buffers.get(&id).unwrap().clone() - }; - let buffer_slice = buffer.slice(range); - let data = buffer_slice.get_mapped_range(); - read(&data, self); - } - - fn map_buffer(&self, id: BufferId, mode: BufferMapMode) { - let buffers = self.resources.buffers.read(); - let buffer = buffers.get(&id).unwrap(); - let buffer_slice = buffer.slice(..); - let wgpu_mode = match mode { - BufferMapMode::Read => wgpu::MapMode::Read, - BufferMapMode::Write => wgpu::MapMode::Write, - }; - let data = buffer_slice.map_async(wgpu_mode); - self.device.poll(wgpu::Maintain::Wait); - if async_global_executor::block_on(data).is_err() { - panic!("Failed to map buffer to host."); - } - } - - fn unmap_buffer(&self, id: BufferId) { - let buffers = self.resources.buffers.read(); - let buffer = buffers.get(&id).unwrap(); - buffer.unmap(); - } - - fn get_aligned_texture_size(&self, size: usize) -> usize { - (size + COPY_BYTES_PER_ROW_ALIGNMENT - 1) & !(COPY_BYTES_PER_ROW_ALIGNMENT - 1) - } - - fn get_aligned_uniform_size(&self, size: usize, dynamic: bool) -> usize { - if dynamic { - (size + BIND_BUFFER_ALIGNMENT - 1) & !(BIND_BUFFER_ALIGNMENT - 1) - } else { - size - } - } - - fn get_specialized_shader( - &self, - shader: &Shader, - macros: Option<&[String]>, - ) -> Result { - let spirv_data = match shader.source { - ShaderSource::Spirv(ref bytes) => bytes.clone(), - ShaderSource::Glsl(ref source) => glsl_to_spirv(source, shader.stage, macros)?, - }; - Ok(Shader { - source: ShaderSource::Spirv(spirv_data), - ..*shader - }) - } -} diff --git a/deny.toml b/deny.toml index 9c2ab206eefee..31a26b8ee5e18 100644 --- a/deny.toml +++ b/deny.toml @@ -35,26 +35,24 @@ wildcards = "deny" highlight = "all" # Certain crates/versions that will be skipped when doing duplicate detection. skip = [ - { name = "ahash", version = "0.4" }, - { name = "android_log-sys", version = "0.1" }, - { name = "cfg-if", version = "0.1" }, # https://github.com/rustwasm/console_error_panic_hook/pull/18 - { name = "core-foundation", version = "0.6" }, - { name = "core-foundation", version = "0.7" }, - { name = "core-foundation-sys", version = "0.6" }, - { name = "core-foundation-sys", version = "0.7" }, - { name = "core-graphics", version = "0.19" }, - { name = "fixedbitset", version = "0.2" }, - { name = "hashbrown", version = "0.9" }, - { name = "jni", version = "0.18.0" }, - { name = "jni", version = "0.19.0" }, - { name = "libm", version = "0.1" }, - { name = "mach", version = "0.2" }, - { name = "ndk", version = "0.2" }, - { name = "ndk-glue", version = "0.2" }, - { name = "num_enum", version = "0.4" }, - { name = "num_enum_derive", version = "0.4" }, - { name = "proc-macro-crate", version = "0.1" }, - { name = "stdweb", version = "0.1" }, + { name = "cfg-if", version = "0.1" }, # from winit v0.26.0 + { name = "core-foundation", version = "0.7" }, # from winit v0.26.0 + { name = "core-foundation-sys", version = "0.7" }, # from winit v0.26.0 + { name = "core-graphics", version = "0.19" }, # from winit v0.26.0 + { name = "ndk", version = "0.5" }, # from winit v0.26.1 + { name = "ndk", version = "0.6" }, # from rodio v0.16.0 + { name = "ndk-glue", version = "0.5" }, # from winit v0.26.1 + { name = "ndk-sys", version = "0.2" }, # from winit v0.26.1 + { name = "ndk-sys", version = "0.3" }, # from rodio v0.16.0 + { name = "parking_lot", version = "0.11" }, # from winit v0.26.1 + { name = "parking_lot_core", version = "0.8" }, # from winit v0.26.1 + { name = "raw-window-handle", version = "0.4" }, # from wgpu v0.13.0 + { name = "nix", version = "0.23.1" }, # from alsa v0.6.0 + { name = "windows_aarch64_msvc", version = "0.36" }, # from notify v5.0.0 + { name = "windows_i686_gnu", version = "0.36" }, # from notify v5.0.0 + { name = "windows_i686_msvc", version = "0.36" }, # from notify v5.0.0 + { name = "windows_x86_64_gnu", version = "0.36" }, # from notify v5.0.0 + { name = "windows_x86_64_msvc", version = "0.36" }, # from notify v5.0.0 ] [sources] diff --git a/examples/async_tasks/async_compute.rs b/examples/async_tasks/async_compute.rs index 2720d8a1211c8..fc8e02aa90e4b 100644 --- a/examples/async_tasks/async_compute.rs +++ b/examples/async_tasks/async_compute.rs @@ -87,8 +87,8 @@ fn handle_tasks( box_mesh_handle: Res, box_material_handle: Res, ) { - for (entity, mut task) in transform_tasks { - if let Some(transform) = bevy::tasks::block_on(future::poll_once(&mut *task)) { + for (entity, mut task) in &mut transform_tasks { + 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(), From 5be66be5a4a3b2f8705388abc4ee45665eb875c2 Mon Sep 17 00:00:00 2001 From: Pessi Date: Sat, 1 Oct 2022 22:26:26 +0200 Subject: [PATCH 4/4] Format --- crates/bevy_asset/src/asset_server.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 4999a08280912..a203d9a87c5f7 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -857,8 +857,7 @@ mod test { fn load_asset(path: AssetPath, world: &World) -> HandleUntyped { let asset_server = world.resource::(); - let id = bevy_tasks::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) }