mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +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_asset::AssetPlugin::default());
|
||||||
group.add(bevy_scene::ScenePlugin::default());
|
group.add(bevy_scene::ScenePlugin::default());
|
||||||
|
|
||||||
|
#[cfg(feature = "bevy_winit")]
|
||||||
|
group.add(bevy_winit::WinitPlugin::default());
|
||||||
|
|
||||||
#[cfg(feature = "bevy_render2")]
|
#[cfg(feature = "bevy_render2")]
|
||||||
{
|
{
|
||||||
group.add(bevy_render2::RenderPlugin::default());
|
group.add(bevy_render2::RenderPlugin::default());
|
||||||
|
@ -137,8 +140,5 @@ impl PluginGroup for PipelinedDefaultPlugins {
|
||||||
#[cfg(feature = "bevy_gltf2")]
|
#[cfg(feature = "bevy_gltf2")]
|
||||||
group.add(bevy_gltf2::GltfPlugin::default());
|
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;
|
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)]
|
#[derive(Default)]
|
||||||
pub struct WinitPlugin;
|
pub struct WinitPlugin;
|
||||||
|
@ -43,6 +35,9 @@ impl Plugin for WinitPlugin {
|
||||||
app.init_resource::<WinitWindows>()
|
app.init_resource::<WinitWindows>()
|
||||||
.set_runner(winit_runner)
|
.set_runner(winit_runner)
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system());
|
.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) {
|
pub fn winit_runner(app: App) {
|
||||||
winit_runner_with(app, EventLoop::new());
|
winit_runner_with(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(
|
// #[cfg(any(
|
||||||
target_os = "linux",
|
// target_os = "linux",
|
||||||
target_os = "dragonfly",
|
// target_os = "dragonfly",
|
||||||
target_os = "freebsd",
|
// target_os = "freebsd",
|
||||||
target_os = "netbsd",
|
// target_os = "netbsd",
|
||||||
target_os = "openbsd"
|
// target_os = "openbsd"
|
||||||
))]
|
// ))]
|
||||||
pub fn winit_runner_any_thread(app: App) {
|
// pub fn winit_runner_any_thread(app: App) {
|
||||||
winit_runner_with(app, EventLoop::new_any_thread());
|
// 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 create_window_event_reader = ManualEventReader::<CreateWindow>::default();
|
||||||
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
|
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
|
||||||
app.world.insert_non_send(event_loop.create_proxy());
|
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"
|
regex = "1.5"
|
||||||
crevice = { path = "../../crates/crevice", version = "0.6.0" }
|
crevice = { path = "../../crates/crevice", version = "0.6.0" }
|
||||||
|
|
||||||
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
|
wgpu = { version = "0.11.0", features = ["spirv", "webgl"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
png = ["image/png"]
|
png = ["image/png"]
|
||||||
hdr = ["image/hdr"]
|
hdr = ["image/hdr"]
|
||||||
|
|
|
@ -85,15 +85,40 @@ struct ScratchRenderWorld(World);
|
||||||
|
|
||||||
impl Plugin for RenderPlugin {
|
impl Plugin for RenderPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
let (instance, device, queue) =
|
let default_backend = if cfg!(not(target_arch = "wasm32")) {
|
||||||
futures_lite::future::block_on(renderer::initialize_renderer(
|
Backends::PRIMARY
|
||||||
wgpu::util::backend_bits_from_env().unwrap_or(Backends::PRIMARY),
|
} else {
|
||||||
&wgpu::RequestAdapterOptions {
|
Backends::GL
|
||||||
power_preference: wgpu::PowerPreference::HighPerformance,
|
};
|
||||||
..Default::default()
|
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()
|
||||||
},
|
},
|
||||||
&wgpu::DeviceDescriptor::default(),
|
..Default::default()
|
||||||
));
|
},
|
||||||
|
));
|
||||||
app.insert_resource(device.clone())
|
app.insert_resource(device.clone())
|
||||||
.insert_resource(queue.clone())
|
.insert_resource(queue.clone())
|
||||||
.add_asset::<Shader>()
|
.add_asset::<Shader>()
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub use render_device::*;
|
||||||
use crate::{render_graph::RenderGraph, view::ExtractedWindows};
|
use crate::{render_graph::RenderGraph, view::ExtractedWindows};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use std::sync::Arc;
|
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) {
|
pub fn render_system(world: &mut World) {
|
||||||
world.resource_scope(|world, mut graph: Mut<RenderGraph>| {
|
world.resource_scope(|world, mut graph: Mut<RenderGraph>| {
|
||||||
|
@ -42,12 +42,10 @@ pub type RenderQueue = Arc<Queue>;
|
||||||
pub type RenderInstance = Instance;
|
pub type RenderInstance = Instance;
|
||||||
|
|
||||||
pub async fn initialize_renderer(
|
pub async fn initialize_renderer(
|
||||||
backends: Backends,
|
instance: &Instance,
|
||||||
request_adapter_options: &RequestAdapterOptions<'_>,
|
request_adapter_options: &RequestAdapterOptions<'_>,
|
||||||
device_descriptor: &DeviceDescriptor<'_>,
|
device_descriptor: &DeviceDescriptor<'_>,
|
||||||
) -> (RenderInstance, RenderDevice, RenderQueue) {
|
) -> (RenderDevice, RenderQueue) {
|
||||||
let instance = wgpu::Instance::new(backends);
|
|
||||||
|
|
||||||
let adapter = instance
|
let adapter = instance
|
||||||
.request_adapter(request_adapter_options)
|
.request_adapter(request_adapter_options)
|
||||||
.await
|
.await
|
||||||
|
@ -72,7 +70,7 @@ pub async fn initialize_renderer(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let device = Arc::new(device);
|
let device = Arc::new(device);
|
||||||
let queue = Arc::new(queue);
|
let queue = Arc::new(queue);
|
||||||
(instance, RenderDevice::from(device), queue)
|
(RenderDevice::from(device), queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderContext {
|
pub struct RenderContext {
|
||||||
|
|
|
@ -42,7 +42,7 @@ pub trait BevyDefault {
|
||||||
|
|
||||||
impl BevyDefault for wgpu::TextureFormat {
|
impl BevyDefault for wgpu::TextureFormat {
|
||||||
fn bevy_default() -> Self {
|
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
|
// Bgra8UnormSrgb texture missing on some Android devices
|
||||||
wgpu::TextureFormat::Rgba8UnormSrgb
|
wgpu::TextureFormat::Rgba8UnormSrgb
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue