diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index b447125c36d09..8e0dea7c3002a 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -87,7 +87,6 @@ use crate::{ texture::TexturePlugin, view::{ViewPlugin, WindowRenderPlugin}, }; -use alloc::sync::Arc; use batching::gpu_preprocessing::BatchingPlugin; use bevy_app::{App, AppLabel, Plugin, SubApp}; use bevy_asset::{AssetApp, AssetServer}; @@ -108,7 +107,6 @@ use render_asset::{ RenderAssetBytesPerFrame, RenderAssetBytesPerFrameLimiter, }; use settings::RenderResources; -use std::sync::Mutex; use sync_world::{despawn_temporary_render_entities, entity_sync_system, SyncWorldPlugin}; /// Contains the default Bevy rendering backend based on wgpu. @@ -285,9 +283,6 @@ pub mod graph { pub struct CameraDriverLabel; } -#[derive(Resource)] -struct FutureRenderResources(Arc>>); - /// A label for the rendering sub-app. #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)] pub struct RenderApp; @@ -298,64 +293,32 @@ impl Plugin for RenderPlugin { app.init_asset::() .init_asset_loader::(); - match &self.render_creation { - RenderCreation::Manual(resources) => { - let future_render_resources_wrapper = Arc::new(Mutex::new(Some(resources.clone()))); - app.insert_resource(FutureRenderResources( - future_render_resources_wrapper.clone(), - )); - // SAFETY: Plugins should be set up on the main thread. - unsafe { initialize_render_app(app) }; - } - RenderCreation::Automatic(render_creation) => { - if let Some(backends) = render_creation.backends { - let future_render_resources_wrapper = Arc::new(Mutex::new(None)); - app.insert_resource(FutureRenderResources( - future_render_resources_wrapper.clone(), - )); - - let primary_window = app - .world_mut() - .query_filtered::<&RawHandleWrapperHolder, With>() - .single(app.world()) - .ok() - .cloned(); - - let settings = render_creation.clone(); - - #[cfg(feature = "raw_vulkan_init")] - let raw_vulkan_init_settings = app - .world_mut() - .get_resource::() - .cloned() - .unwrap_or_default(); - - let async_renderer = async move { - let render_resources = renderer::initialize_renderer( - backends, - primary_window, - &settings, - #[cfg(feature = "raw_vulkan_init")] - raw_vulkan_init_settings, - ) - .await; - - *future_render_resources_wrapper.lock().unwrap() = Some(render_resources); - }; - - // In wasm, spawn a task and detach it for execution - #[cfg(target_arch = "wasm32")] - bevy_tasks::IoTaskPool::get() - .spawn_local(async_renderer) - .detach(); - // Otherwise, just block for it to complete - #[cfg(not(target_arch = "wasm32"))] - bevy_tasks::block_on(async_renderer); - - // SAFETY: Plugins should be set up on the main thread. - unsafe { initialize_render_app(app) }; - } - } + let primary_window = app + .world_mut() + .query_filtered::<&RawHandleWrapperHolder, With>() + .single(app.world()) + .ok() + .cloned(); + + #[cfg(feature = "raw_vulkan_init")] + let raw_vulkan_init_settings = app + .world_mut() + .get_resource::() + .cloned() + .unwrap_or_default(); + + let render_resources = self.render_creation.create_render( + primary_window, + #[cfg(feature = "raw_vulkan_init")] + raw_vulkan_init_settings, + ); + + if let Some(render_resources) = render_resources { + app.insert_resource(render_resources); + // SAFETY: Plugins should be set up on the main thread. + unsafe { initialize_render_app(app) }; + } else { + bevy_log::warn!("No backends found, renderer will not be initialized."); }; app.add_plugins(( @@ -390,21 +353,11 @@ impl Plugin for RenderPlugin { } } - fn ready(&self, app: &App) -> bool { - app.world() - .get_resource::() - .and_then(|frr| frr.0.try_lock().map(|locked| locked.is_some()).ok()) - .unwrap_or(true) - } - fn finish(&self, app: &mut App) { load_shader_library!(app, "maths.wgsl"); load_shader_library!(app, "color_operations.wgsl"); load_shader_library!(app, "bindless.wgsl"); - if let Some(future_render_resources) = - app.world_mut().remove_resource::() - { - let render_resources = future_render_resources.0.lock().unwrap().take().unwrap(); + if let Some(render_resources) = app.world_mut().remove_resource::() { let RenderResources(device, queue, adapter_info, render_adapter, instance, ..) = render_resources; diff --git a/crates/bevy_render/src/settings.rs b/crates/bevy_render/src/settings.rs index c3b284ecc13b4..fe32b4859b486 100644 --- a/crates/bevy_render/src/settings.rs +++ b/crates/bevy_render/src/settings.rs @@ -1,7 +1,10 @@ use crate::renderer::{ - RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue, + self, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue, }; -use alloc::borrow::Cow; +use alloc::{borrow::Cow, sync::Arc}; +use bevy_ecs::resource::Resource; +use bevy_window::RawHandleWrapperHolder; +use std::sync::Mutex; pub use wgpu::{ Backends, Dx12Compiler, Features as WgpuFeatures, Gles3MinorVersion, InstanceFlags, @@ -144,15 +147,14 @@ impl Default for WgpuSettings { } } -#[derive(Clone)] +#[derive(Clone, Resource)] pub struct RenderResources( pub RenderDevice, pub RenderQueue, pub RenderAdapterInfo, pub RenderAdapter, pub RenderInstance, - #[cfg(feature = "raw_vulkan_init")] - pub crate::renderer::raw_vulkan_init::AdditionalVulkanFeatures, + #[cfg(feature = "raw_vulkan_init")] pub renderer::raw_vulkan_init::AdditionalVulkanFeatures, ); /// An enum describing how the renderer will initialize resources. This is used when creating the [`RenderPlugin`](crate::RenderPlugin). @@ -176,7 +178,7 @@ impl RenderCreation { adapter: RenderAdapter, instance: RenderInstance, #[cfg(feature = "raw_vulkan_init")] - additional_vulkan_features: crate::renderer::raw_vulkan_init::AdditionalVulkanFeatures, + additional_vulkan_features: renderer::raw_vulkan_init::AdditionalVulkanFeatures, ) -> Self { RenderResources( device, @@ -189,6 +191,49 @@ impl RenderCreation { ) .into() } + + /// Creates [`RenderResources`] from this [`RenderCreation`] and an optional primary window. + /// Note: [`RenderCreation::Manual`] will ignore the provided primary window. + pub fn create_render( + &self, + primary_window: Option, + #[cfg(feature = "raw_vulkan_init")] + raw_vulkan_init_settings: renderer::raw_vulkan_init::RawVulkanInitSettings, + ) -> Option { + match self { + RenderCreation::Manual(resources) => Some(resources.clone()), + RenderCreation::Automatic(render_creation) => { + let backends = render_creation.backends?; + let future_render_resources_wrapper = Arc::new(Mutex::new(None)); + let render_resources = future_render_resources_wrapper.clone(); + + let settings = render_creation.clone(); + + let async_renderer = async move { + let render_resources = renderer::initialize_renderer( + backends, + primary_window, + &settings, + #[cfg(feature = "raw_vulkan_init")] + raw_vulkan_init_settings, + ) + .await; + + *future_render_resources_wrapper.lock().unwrap() = Some(render_resources); + }; + + // In wasm, spawn a task and detach it for execution + #[cfg(target_arch = "wasm32")] + bevy_tasks::IoTaskPool::get() + .spawn_local(async_renderer) + .detach(); + // Otherwise, just block for it to complete + #[cfg(not(target_arch = "wasm32"))] + bevy_tasks::block_on(async_renderer); + render_resources.lock().unwrap().clone() + } + } + } } impl From for RenderCreation {