mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
WebGL2 support (#3039)
# Objective Make possible to use wgpu gles backend on in the browser (wasm32 + WebGL2). ## Solution It is built on top of old @cart patch initializing windows before wgpu. Also: - initializes wgpu with `Backends::GL` and proper `wgpu::Limits` on wasm32 - changes default texture format to `wgpu::TextureFormat::Rgba8UnormSrgb` Co-authored-by: Mariusz Kryński <mrk@sed.pl>
This commit is contained in:
parent
a2ea9279b2
commit
7d932ac1d8
6 changed files with 79 additions and 38 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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::<WinitWindows>()
|
||||
.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());
|
||||
winit_runner_with(app);
|
||||
}
|
||||
|
||||
#[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());
|
||||
}
|
||||
// #[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, mut event_loop: EventLoop<()>) {
|
||||
pub fn winit_runner_with(mut app: App) {
|
||||
let mut event_loop = app.world.remove_non_send::<EventLoop<()>>().unwrap();
|
||||
let mut create_window_event_reader = ManualEventReader::<CreateWindow>::default();
|
||||
let mut app_exit_event_reader = ManualEventReader::<AppExit>::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::<WinitWindows>().unwrap();
|
||||
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
||||
let mut create_window_events = world.get_resource_mut::<Events<CreateWindow>>().unwrap();
|
||||
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@ parking_lot = "0.11.0"
|
|||
regex = "1.5"
|
||||
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"]
|
||||
|
|
|
@ -85,14 +85,39 @@ 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),
|
||||
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::<bevy_window::Windows>().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()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
&wgpu::DeviceDescriptor::default(),
|
||||
));
|
||||
app.insert_resource(device.clone())
|
||||
.insert_resource(queue.clone())
|
||||
|
|
|
@ -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<RenderGraph>| {
|
||||
|
@ -42,12 +42,10 @@ pub type RenderQueue = Arc<Queue>;
|
|||
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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue