Skip to content

Commit 7d932ac

Browse files
cartmrk-its
andcommitted
WebGL2 support (bevyengine#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>
1 parent a2ea927 commit 7d932ac

File tree

6 files changed

+80
-39
lines changed

6 files changed

+80
-39
lines changed

crates/bevy_internal/src/default_plugins.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ impl PluginGroup for PipelinedDefaultPlugins {
119119
group.add(bevy_asset::AssetPlugin::default());
120120
group.add(bevy_scene::ScenePlugin::default());
121121

122+
#[cfg(feature = "bevy_winit")]
123+
group.add(bevy_winit::WinitPlugin::default());
124+
122125
#[cfg(feature = "bevy_render2")]
123126
{
124127
group.add(bevy_render2::RenderPlugin::default());
@@ -137,8 +140,5 @@ impl PluginGroup for PipelinedDefaultPlugins {
137140
#[cfg(feature = "bevy_gltf2")]
138141
group.add(bevy_gltf2::GltfPlugin::default());
139142
}
140-
141-
#[cfg(feature = "bevy_winit")]
142-
group.add(bevy_winit::WinitPlugin::default());
143143
}
144144
}

crates/bevy_winit/src/lib.rs

+36-21
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,6 @@ use winit::{
2626
};
2727

2828
use winit::dpi::LogicalSize;
29-
#[cfg(any(
30-
target_os = "linux",
31-
target_os = "dragonfly",
32-
target_os = "freebsd",
33-
target_os = "netbsd",
34-
target_os = "openbsd"
35-
))]
36-
use winit::platform::unix::EventLoopExtUnix;
3729

3830
#[derive(Default)]
3931
pub struct WinitPlugin;
@@ -43,6 +35,9 @@ impl Plugin for WinitPlugin {
4335
app.init_resource::<WinitWindows>()
4436
.set_runner(winit_runner)
4537
.add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system());
38+
let event_loop = EventLoop::new();
39+
handle_initial_window_events(&mut app.world, &event_loop);
40+
app.insert_non_send_resource(event_loop);
4641
}
4742
}
4843

@@ -207,21 +202,22 @@ where
207202
}
208203

209204
pub fn winit_runner(app: App) {
210-
winit_runner_with(app, EventLoop::new());
211-
}
212-
213-
#[cfg(any(
214-
target_os = "linux",
215-
target_os = "dragonfly",
216-
target_os = "freebsd",
217-
target_os = "netbsd",
218-
target_os = "openbsd"
219-
))]
220-
pub fn winit_runner_any_thread(app: App) {
221-
winit_runner_with(app, EventLoop::new_any_thread());
205+
winit_runner_with(app);
222206
}
223207

224-
pub fn winit_runner_with(mut app: App, mut event_loop: EventLoop<()>) {
208+
// #[cfg(any(
209+
// target_os = "linux",
210+
// target_os = "dragonfly",
211+
// target_os = "freebsd",
212+
// target_os = "netbsd",
213+
// target_os = "openbsd"
214+
// ))]
215+
// pub fn winit_runner_any_thread(app: App) {
216+
// winit_runner_with(app, EventLoop::new_any_thread());
217+
// }
218+
219+
pub fn winit_runner_with(mut app: App) {
220+
let mut event_loop = app.world.remove_non_send::<EventLoop<()>>().unwrap();
225221
let mut create_window_event_reader = ManualEventReader::<CreateWindow>::default();
226222
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
227223
app.world.insert_non_send(event_loop.create_proxy());
@@ -525,3 +521,22 @@ fn handle_create_window_events(
525521
});
526522
}
527523
}
524+
525+
fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) {
526+
let world = world.cell();
527+
let mut winit_windows = world.get_resource_mut::<WinitWindows>().unwrap();
528+
let mut windows = world.get_resource_mut::<Windows>().unwrap();
529+
let mut create_window_events = world.get_resource_mut::<Events<CreateWindow>>().unwrap();
530+
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
531+
for create_window_event in create_window_events.drain() {
532+
let window = winit_windows.create_window(
533+
event_loop,
534+
create_window_event.id,
535+
&create_window_event.descriptor,
536+
);
537+
windows.add(window);
538+
window_created_events.send(WindowCreated {
539+
id: create_window_event.id,
540+
});
541+
}
542+
}

pipelined/bevy_render2/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ parking_lot = "0.11.0"
4545
regex = "1.5"
4646
crevice = { path = "../../crates/crevice", version = "0.6.0" }
4747

48+
[target.'cfg(target_arch = "wasm32")'.dependencies]
49+
wgpu = { version = "0.11.0", features = ["spirv", "webgl"] }
50+
4851
[features]
4952
png = ["image/png"]
5053
hdr = ["image/hdr"]

pipelined/bevy_render2/src/lib.rs

+33-8
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,40 @@ struct ScratchRenderWorld(World);
8585

8686
impl Plugin for RenderPlugin {
8787
fn build(&self, app: &mut App) {
88-
let (instance, device, queue) =
89-
futures_lite::future::block_on(renderer::initialize_renderer(
90-
wgpu::util::backend_bits_from_env().unwrap_or(Backends::PRIMARY),
91-
&wgpu::RequestAdapterOptions {
92-
power_preference: wgpu::PowerPreference::HighPerformance,
93-
..Default::default()
88+
let default_backend = if cfg!(not(target_arch = "wasm32")) {
89+
Backends::PRIMARY
90+
} else {
91+
Backends::GL
92+
};
93+
let backends = wgpu::util::backend_bits_from_env().unwrap_or(default_backend);
94+
let instance = wgpu::Instance::new(backends);
95+
let surface = {
96+
let world = app.world.cell();
97+
let windows = world.get_resource_mut::<bevy_window::Windows>().unwrap();
98+
let raw_handle = windows.get_primary().map(|window| unsafe {
99+
let handle = window.raw_window_handle().get_handle();
100+
instance.create_surface(&handle)
101+
});
102+
raw_handle
103+
};
104+
let (device, queue) = futures_lite::future::block_on(renderer::initialize_renderer(
105+
&instance,
106+
&wgpu::RequestAdapterOptions {
107+
power_preference: wgpu::PowerPreference::HighPerformance,
108+
compatible_surface: surface.as_ref(),
109+
..Default::default()
110+
},
111+
&wgpu::DeviceDescriptor {
112+
features: wgpu::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
113+
#[cfg(not(target_arch = "wasm32"))]
114+
limits: wgpu::Limits::default(),
115+
#[cfg(target_arch = "wasm32")]
116+
limits: wgpu::Limits {
117+
..wgpu::Limits::downlevel_webgl2_defaults()
94118
},
95-
&wgpu::DeviceDescriptor::default(),
96-
));
119+
..Default::default()
120+
},
121+
));
97122
app.insert_resource(device.clone())
98123
.insert_resource(queue.clone())
99124
.add_asset::<Shader>()

pipelined/bevy_render2/src/renderer/mod.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub use render_device::*;
88
use crate::{render_graph::RenderGraph, view::ExtractedWindows};
99
use bevy_ecs::prelude::*;
1010
use std::sync::Arc;
11-
use wgpu::{Backends, CommandEncoder, DeviceDescriptor, Instance, Queue, RequestAdapterOptions};
11+
use wgpu::{CommandEncoder, DeviceDescriptor, Instance, Queue, RequestAdapterOptions};
1212

1313
pub fn render_system(world: &mut World) {
1414
world.resource_scope(|world, mut graph: Mut<RenderGraph>| {
@@ -42,12 +42,10 @@ pub type RenderQueue = Arc<Queue>;
4242
pub type RenderInstance = Instance;
4343

4444
pub async fn initialize_renderer(
45-
backends: Backends,
45+
instance: &Instance,
4646
request_adapter_options: &RequestAdapterOptions<'_>,
4747
device_descriptor: &DeviceDescriptor<'_>,
48-
) -> (RenderInstance, RenderDevice, RenderQueue) {
49-
let instance = wgpu::Instance::new(backends);
50-
48+
) -> (RenderDevice, RenderQueue) {
5149
let adapter = instance
5250
.request_adapter(request_adapter_options)
5351
.await
@@ -72,7 +70,7 @@ pub async fn initialize_renderer(
7270
.unwrap();
7371
let device = Arc::new(device);
7472
let queue = Arc::new(queue);
75-
(instance, RenderDevice::from(device), queue)
73+
(RenderDevice::from(device), queue)
7674
}
7775

7876
pub struct RenderContext {

pipelined/bevy_render2/src/texture/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub trait BevyDefault {
4242

4343
impl BevyDefault for wgpu::TextureFormat {
4444
fn bevy_default() -> Self {
45-
if cfg!(target_os = "android") {
45+
if cfg!(target_os = "android") || cfg!(target_arch = "wasm32") {
4646
// Bgra8UnormSrgb texture missing on some Android devices
4747
wgpu::TextureFormat::Rgba8UnormSrgb
4848
} else {

0 commit comments

Comments
 (0)