diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index 27e206d657af8..0a97da009ac62 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -119,6 +119,9 @@ impl PluginGroup for PipelinedDefaultPlugins { group.add(bevy_asset::AssetPlugin::default()); group.add(bevy_scene::ScenePlugin::default()); + #[cfg(feature = "bevy_winit")] + group.add(bevy_winit::WinitPlugin::default()); + #[cfg(feature = "bevy_render2")] { group.add(bevy_render2::RenderPlugin::default()); @@ -137,8 +140,5 @@ impl PluginGroup for PipelinedDefaultPlugins { #[cfg(feature = "bevy_gltf2")] group.add(bevy_gltf2::GltfPlugin::default()); } - - #[cfg(feature = "bevy_winit")] - group.add(bevy_winit::WinitPlugin::default()); } } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index af072b7a60f9f..8e84bd2480340 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -26,14 +26,6 @@ use winit::{ }; use winit::dpi::LogicalSize; -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -use winit::platform::unix::EventLoopExtUnix; #[derive(Default)] pub struct WinitPlugin; @@ -43,6 +35,9 @@ impl Plugin for WinitPlugin { app.init_resource::() .set_runner(winit_runner) .add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system()); + let event_loop = EventLoop::new(); + handle_initial_window_events(&mut app.world, &event_loop); + app.insert_non_send_resource(event_loop); } } @@ -207,21 +202,22 @@ where } pub fn winit_runner(app: App) { - winit_runner_with(app, EventLoop::new()); -} - -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -pub fn winit_runner_any_thread(app: App) { - winit_runner_with(app, EventLoop::new_any_thread()); + winit_runner_with(app); } -pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) { +// #[cfg(any( +// target_os = "linux", +// target_os = "dragonfly", +// target_os = "freebsd", +// target_os = "netbsd", +// target_os = "openbsd" +// ))] +// pub fn winit_runner_any_thread(app: App) { +// winit_runner_with(app, EventLoop::new_any_thread()); +// } + +pub fn winit_runner_with(mut app: App) { + let mut event_loop = app.world.remove_non_send::>().unwrap(); let mut create_window_event_reader = ManualEventReader::::default(); let mut app_exit_event_reader = ManualEventReader::::default(); app.world.insert_non_send(event_loop.create_proxy()); @@ -525,3 +521,22 @@ fn handle_create_window_events( }); } } + +fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) { + let world = world.cell(); + let mut winit_windows = world.get_resource_mut::().unwrap(); + let mut windows = world.get_resource_mut::().unwrap(); + let mut create_window_events = world.get_resource_mut::>().unwrap(); + let mut window_created_events = world.get_resource_mut::>().unwrap(); + for create_window_event in create_window_events.drain() { + let window = winit_windows.create_window( + event_loop, + create_window_event.id, + &create_window_event.descriptor, + ); + windows.add(window); + window_created_events.send(WindowCreated { + id: create_window_event.id, + }); + } +} diff --git a/pipelined/bevy_render2/Cargo.toml b/pipelined/bevy_render2/Cargo.toml index 694b500e3d439..cfeca598b9aac 100644 --- a/pipelined/bevy_render2/Cargo.toml +++ b/pipelined/bevy_render2/Cargo.toml @@ -44,6 +44,9 @@ hexasphere = "4.0" parking_lot = "0.11.0" crevice = { path = "../../crates/crevice", version = "0.6.0" } +[target.'cfg(target_arch = "wasm32")'.dependencies] +wgpu = { version = "0.11.0", features = ["spirv", "webgl"] } + [features] png = ["image/png"] hdr = ["image/hdr"] diff --git a/pipelined/bevy_render2/src/lib.rs b/pipelined/bevy_render2/src/lib.rs index ce28144d00714..c10e5baa5a25d 100644 --- a/pipelined/bevy_render2/src/lib.rs +++ b/pipelined/bevy_render2/src/lib.rs @@ -84,15 +84,40 @@ struct ScratchRenderWorld(World); impl Plugin for RenderPlugin { fn build(&self, app: &mut App) { - let (instance, device, queue) = - futures_lite::future::block_on(renderer::initialize_renderer( - wgpu::util::backend_bits_from_env().unwrap_or(Backends::PRIMARY), - &wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::HighPerformance, - ..Default::default() + let default_backend = if cfg!(not(target_arch = "wasm32")) { + Backends::PRIMARY + } else { + Backends::GL + }; + let backends = wgpu::util::backend_bits_from_env().unwrap_or(default_backend); + let instance = wgpu::Instance::new(backends); + let surface = { + let world = app.world.cell(); + let windows = world.get_resource_mut::().unwrap(); + let raw_handle = windows.get_primary().map(|window| unsafe { + let handle = window.raw_window_handle().get_handle(); + instance.create_surface(&handle) + }); + raw_handle + }; + let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer( + &instance, + &wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: surface.as_ref(), + ..Default::default() + }, + &wgpu::DeviceDescriptor { + features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES, + #[cfg(not(target_arch = "wasm32"))] + limits: wgpu::Limits::default(), + #[cfg(target_arch = "wasm32")] + limits: wgpu::Limits { + ..wgpu::Limits::downlevel_webgl2_defaults() }, - &wgpu::DeviceDescriptor::default(), - )); + ..Default::default() + }, + )); app.insert_resource(device.clone()) .insert_resource(queue.clone()) .init_resource::(); diff --git a/pipelined/bevy_render2/src/renderer/mod.rs b/pipelined/bevy_render2/src/renderer/mod.rs index 840faed624036..461df246308ce 100644 --- a/pipelined/bevy_render2/src/renderer/mod.rs +++ b/pipelined/bevy_render2/src/renderer/mod.rs @@ -8,7 +8,7 @@ pub use render_device::*; use crate::{render_graph::RenderGraph, view::ExtractedWindows}; use bevy_ecs::prelude::*; use std::sync::Arc; -use wgpu::{Backends, CommandEncoder, DeviceDescriptor, Instance, Queue, RequestAdapterOptions}; +use wgpu::{CommandEncoder, DeviceDescriptor, Instance, Queue, RequestAdapterOptions}; pub fn render_system(world: &mut World) { world.resource_scope(|world, mut graph: Mut| { @@ -42,12 +42,10 @@ pub type RenderQueue = Arc; pub type RenderInstance = Instance; pub async fn initialize_renderer( - backends: Backends, + instance: &Instance, request_adapter_options: &RequestAdapterOptions<'_>, device_descriptor: &DeviceDescriptor<'_>, -) -> (RenderInstance, RenderDevice, RenderQueue) { - let instance = wgpu::Instance::new(backends); - +) -> (RenderDevice, RenderQueue) { let adapter = instance .request_adapter(request_adapter_options) .await @@ -72,7 +70,7 @@ pub async fn initialize_renderer( .unwrap(); let device = Arc::new(device); let queue = Arc::new(queue); - (instance, RenderDevice::from(device), queue) + (RenderDevice::from(device), queue) } pub struct RenderContext { diff --git a/pipelined/bevy_render2/src/texture/mod.rs b/pipelined/bevy_render2/src/texture/mod.rs index cd25dd57387ae..59eb1f5dc11d0 100644 --- a/pipelined/bevy_render2/src/texture/mod.rs +++ b/pipelined/bevy_render2/src/texture/mod.rs @@ -42,7 +42,7 @@ pub trait BevyDefault { impl BevyDefault for wgpu::TextureFormat { fn bevy_default() -> Self { - if cfg!(target_os = "android") { + if cfg!(target_os = "android") || cfg!(target_arch = "wasm32") { // Bgra8UnormSrgb texture missing on some Android devices wgpu::TextureFormat::Rgba8UnormSrgb } else {