diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69802293146..23cb3c2e98b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,6 +77,13 @@ jobs: target: wasm32-unknown-unknown kind: webgl + # Emscripten WebGL + - name: WebAssembly emscripten + os: ubuntu-20.04 + channel: stable + target: wasm32-unknown-emscripten + kind: compile + name: Check ${{ matrix.name }} runs-on: ${{ matrix.os }} diff --git a/Cargo.lock b/Cargo.lock index de656cabee0..c20a05146ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -601,8 +601,7 @@ dependencies = [ [[package]] name = "glow" version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f04649123493bc2483cbef4daddb45d40bbdae5adb221a63a23efdb0cc99520" +source = "git+https://github.com/caiiiycuk/glow?rev=5abe786#5abe786973f0ccc2a8c37a44e360dc9f7ca73e43" dependencies = [ "js-sys", "slotmap", @@ -743,6 +742,7 @@ checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" dependencies = [ "libc", "libloading", + "pkg-config", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f11e2f43826..c9660902bc2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ default-members = ["wgpu", "wgpu-hal", "wgpu-info"] [patch."https://github.com/zakarumych/gpu-alloc"] #gpu-alloc = { path = "../gpu-alloc/gpu-alloc" } -[patch."https://github.com/grovesNL/glow"] +[patch."https://github.com/caiiiycuk/glow"] #glow = { path = "../glow" } [patch.crates-io] diff --git a/run-wasm-emscripten-example.sh b/run-wasm-emscripten-example.sh new file mode 100755 index 00000000000..0ed99a09d76 --- /dev/null +++ b/run-wasm-emscripten-example.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +set -e + +set -- hello-triangle +echo "Compiling..." +EMMAKEN_CFLAGS="-g -s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry -s FULL_ES3=1" cargo build --example $1 --target wasm32-unknown-emscripten + +mkdir -p target/wasm-examples/$1/ +cp target/wasm32-unknown-emscripten/debug/examples/* target/wasm-examples/$1 +cat wasm-resources/index.em.template.html | sed "s/{{example}}/$1/g" > target/wasm-examples/$1/index.html + +# Find a serving tool to host the example +SERVE_CMD="" +SERVE_ARGS="" +if which basic-http-server; then + SERVE_CMD="basic-http-server" + SERVE_ARGS="target/wasm-examples/$1 -a 127.0.0.1:1234" +elif which miniserve && python3 -m http.server --help > /dev/null; then + SERVE_CMD="miniserve" + SERVE_ARGS="target/wasm-examples/$1 -p 1234 --index index.html" +elif python3 -m http.server --help > /dev/null; then + SERVE_CMD="python3" + SERVE_ARGS="-m http.server --directory target/wasm-examples/$1 1234" +fi + +# Exit if we couldn't find a tool to serve the example with +if [ "$SERVE_CMD" = "" ]; then + echo "Couldn't find a utility to use to serve the example web page. You can serve the `target/wasm-examples/$1` folder yourself using any simple static http file server." +fi + +echo "Serving example with $SERVE_CMD at http://localhost:1234" +$SERVE_CMD $SERVE_ARGS diff --git a/wasm-resources/index.em.template.html b/wasm-resources/index.em.template.html new file mode 100644 index 00000000000..216b8d7c942 --- /dev/null +++ b/wasm-resources/index.em.template.html @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 359a9a108e0..03afe5b7610 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -43,7 +43,9 @@ gpu-descriptor = { version = "0.2", optional = true } inplace_it = { version ="0.3.3", optional = true } # backend: Gles -glow = { version = "0.11", optional = true } +# TODO: remove caiiiycuk/glow when +# https://github.com/grovesNL/glow/pull/195 will be merged +glow = { git = "https://github.com/caiiiycuk/glow", rev = "5abe786", optional = true } # backend: Dx12 bit-set = { version = "0.5", optional = true } @@ -59,6 +61,10 @@ egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], option #Note: it's only unused on Apple platforms libloading = { version = "0.7", optional = true } +[target.'cfg(target_os = "emscripten")'.dependencies] +egl = { package = "khronos-egl", version = "4.1", features = ["static", "no-pkg-config"], optional = true } +libloading = { version = "0.7", optional = true } + [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] } native = { package = "d3d12", version = "0.4.1", features = ["libloading"], optional = true } @@ -68,7 +74,7 @@ mtl = { package = "metal", version = "0.23.1" } objc = "0.2.5" core-graphics-types = "0.1" -[target.'cfg(target_arch = "wasm32")'.dependencies] +[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] wasm-bindgen = { version = "0.2" } web-sys = { version = "0.3", features = ["Window", "HtmlCanvasElement", "WebGl2RenderingContext"] } js-sys = { version = "0.3" } @@ -86,4 +92,6 @@ features = ["wgsl-in"] [dev-dependencies] env_logger = "0.8" + +[target.'cfg(not(target_os = "emscripten"))'.dev-dependencies] winit = "0.26" diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 722041048a9..8003246ad1f 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1096,6 +1096,8 @@ impl crate::Device for super::Device { #[cfg_attr(target_arch = "wasm32", allow(clippy::needless_borrow))] Ok(fence.get_latest(&self.shared.context.lock())) } + + #[cfg_attr(target_os = "emscripten", allow(unreachable_code, unused_variables))] unsafe fn wait( &self, fence: &super::Fence, @@ -1114,6 +1116,12 @@ impl crate::Device for super::Device { .iter() .find(|&&(value, _)| value >= wait_value) .unwrap(); + + // for some reason signature of glow's client_wait_sync didn't match to emscripten's client_wait_sync + // however it should be noop in emscripten + #[cfg(target_os = "emscripten")] + return Ok(true); + match gl.client_wait_sync(sync, glow::SYNC_FLUSH_COMMANDS_BIT, timeout_ns as i32) { // for some reason firefox returns WAIT_FAILED, to investigate #[cfg(target_arch = "wasm32")] diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 96bf0d81a31..01b610033f6 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -10,7 +10,9 @@ const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1; const EGL_CONTEXT_FLAGS_KHR: i32 = 0x30FC; const EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR: i32 = 0x0001; const EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: i32 = 0x30BF; +#[cfg_attr(target_os = "emscripten", allow(dead_code))] const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8; +#[cfg_attr(target_os = "emscripten", allow(dead_code))] const EGL_PLATFORM_X11_KHR: u32 = 0x31D5; const EGL_GL_COLORSPACE_KHR: u32 = 0x309D; const EGL_GL_COLORSPACE_SRGB_KHR: u32 = 0x3089; @@ -23,12 +25,20 @@ type WlDisplayConnectFun = type WlDisplayDisconnectFun = unsafe extern "system" fn(display: *const raw::c_void); +#[cfg(not(target_os = "emscripten"))] +type EglInstance = egl::DynamicInstance; + +#[cfg(target_os = "emscripten")] +type EglInstance = egl::Instance; + +#[cfg_attr(target_os = "emscripten", allow(dead_code))] type WlEglWindowCreateFun = unsafe extern "system" fn( surface: *const raw::c_void, width: raw::c_int, height: raw::c_int, ) -> *mut raw::c_void; +#[cfg_attr(target_os = "emscripten", allow(dead_code))] type WlEglWindowResizeFun = unsafe extern "system" fn( window: *const raw::c_void, width: raw::c_int, @@ -141,7 +151,7 @@ enum SrgbFrameBufferKind { /// Choose GLES framebuffer configuration. fn choose_config( - egl: &egl::DynamicInstance, + egl: &EglInstance, display: egl::Display, srgb_kind: SrgbFrameBufferKind, ) -> Result<(egl::Config, bool), crate::InstanceError> { @@ -249,7 +259,7 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m /// exclusive access when shared with multiple threads. pub struct AdapterContext { glow_context: Mutex, - egl: Arc>, + egl: Arc, egl_display: egl::Display, pub(super) egl_context: egl::Context, egl_pbuffer: Option, @@ -261,7 +271,7 @@ unsafe impl Send for AdapterContext {} /// A guard containing a lock to an [`AdapterContext`] pub struct AdapterContextLock<'a> { glow_context: MutexGuard<'a, glow::Context>, - egl: &'a Arc>, + egl: &'a Arc, egl_display: egl::Display, } @@ -331,7 +341,7 @@ impl AdapterContext { #[derive(Debug)] struct Inner { - egl: Arc>, + egl: Arc, #[allow(unused)] version: (i32, i32), supports_native_window: bool, @@ -341,6 +351,7 @@ struct Inner { /// Dummy pbuffer (1x1). /// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`. pbuffer: Option, + #[cfg_attr(target_os = "emscripten", allow(dead_code))] wl_display: Option<*mut raw::c_void>, /// Method by which the framebuffer should support srgb srgb_kind: SrgbFrameBufferKind, @@ -349,7 +360,7 @@ struct Inner { impl Inner { fn create( flags: crate::InstanceFlags, - egl: Arc>, + egl: Arc, display: egl::Display, ) -> Result { let version = egl.initialize(display).map_err(|_| crate::InstanceError)?; @@ -443,8 +454,12 @@ impl Inner { } }; + #[cfg(target_os = "emscripten")] + let pbuffer = None; + // Testing if context can be binded without surface // and creating dummy pbuffer surface if not. + #[cfg(not(target_os = "emscripten"))] let pbuffer = if version >= (1, 5) || display_extensions.contains("EGL_KHR_surfaceless_context") { log::info!("\tEGL context: +surfaceless"); @@ -494,7 +509,12 @@ unsafe impl Send for Instance {} unsafe impl Sync for Instance {} impl crate::Instance for Instance { + #[cfg_attr(target_os = "emscripten", allow(unused_variables, unused_mut))] unsafe fn init(desc: &crate::InstanceDescriptor) -> Result { + #[cfg(target_os = "emscripten")] + let egl = Arc::new(egl::Instance::new(egl::Static)); + + #[cfg(not(target_os = "emscripten"))] let egl = match egl::DynamicInstance::::load_required() { Ok(egl) => Arc::new(egl), Err(e) => { @@ -528,6 +548,7 @@ impl crate::Instance for Instance { None }; + #[cfg(not(target_os = "emscripten"))] let display = if let (Some(library), Some(egl)) = (wayland_library, egl.upcast::()) { @@ -553,6 +574,9 @@ impl crate::Instance for Instance { egl.get_display(egl::DEFAULT_DISPLAY).unwrap() }; + #[cfg(target_os = "emscripten")] + let display = egl.get_display(egl::DEFAULT_DISPLAY).unwrap(); + if desc.flags.contains(crate::InstanceFlags::VALIDATION) && client_ext_str.contains(&"EGL_KHR_debug") { @@ -582,7 +606,10 @@ impl crate::Instance for Instance { }) } - #[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))] + #[cfg_attr( + any(target_os = "macos", target_os = "emscripten"), + allow(unused, unused_mut, unreachable_code) + )] unsafe fn create_surface( &self, has_handle: &impl HasRawWindowHandle, @@ -611,6 +638,7 @@ impl crate::Instance for Instance { return Err(crate::InstanceError); } } + #[cfg(not(target_os = "emscripten"))] Rwh::Wayland(handle) => { /* Wayland displays are not sharable between surfaces so if the * surface we receive from this handle is from a different @@ -645,6 +673,8 @@ impl crate::Instance for Instance { drop(old_inner); } } + #[cfg(target_os = "emscripten")] + Rwh::Web(_) => {} other => { log::error!("Unsupported window: {:?}", other); return Err(crate::InstanceError); @@ -736,7 +766,7 @@ pub struct Swapchain { #[derive(Debug)] pub struct Surface { - egl: Arc>, + egl: Arc, wsi_library: Option>, config: egl::Config, display: egl::Display, @@ -875,6 +905,8 @@ impl crate::Surface for Surface { wl_window = Some(window); window } + #[cfg(target_os = "emscripten")] + Rwh::Web(handle) => handle.id as *mut std::ffi::c_void, _ => unreachable!(), }; @@ -900,6 +932,7 @@ impl crate::Surface for Surface { attributes.push(egl::ATTRIB_NONE as i32); // Careful, we can still be in 1.4 version even if `upcast` succeeds + #[cfg(not(target_os = "emscripten"))] let raw_result = if let Some(egl) = self.egl.upcast::() { let attributes_usize = attributes .into_iter() @@ -920,6 +953,14 @@ impl crate::Surface for Surface { ) }; + #[cfg(target_os = "emscripten")] + let raw_result = self.egl.create_window_surface( + self.display, + self.config, + native_window_ptr, + Some(&attributes), + ); + match raw_result { Ok(raw) => (raw, wl_window), Err(e) => { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 1d59b7f7434..26534a8053d 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -56,9 +56,9 @@ To address this, we invalidate the vertex buffers based on: */ -#[cfg(not(target_arch = "wasm32"))] +#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] mod egl; -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] mod web; mod adapter; @@ -67,10 +67,10 @@ mod conv; mod device; mod queue; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] use self::egl::{AdapterContext, Instance, Surface}; -#[cfg(target_arch = "wasm32")] +#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] use self::web::{AdapterContext, Instance, Surface}; use arrayvec::ArrayVec; diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 91631f4913b..f2a517af0e3 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -1102,10 +1102,10 @@ impl crate::Queue for super::Queue { surface: &mut super::Surface, texture: super::Texture, ) -> Result<(), crate::SurfaceError> { - #[cfg(not(target_arch = "wasm32"))] + #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] let gl = &self.shared.context.get_without_egl_lock(); - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] let gl = &self.shared.context.glow_context; surface.present(texture, gl) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index d92961d5db3..b319494aa60 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -83,13 +83,13 @@ trace = ["serde", "wgc/trace"] replay = ["serde", "wgc/replay"] webgl = ["wgc"] -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc] +[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dependencies.wgc] package = "wgpu-core" path = "../wgpu-core" version = "0.11" features = ["raw-window-handle"] -[target.'cfg(target_arch = "wasm32")'.dependencies.wgc] +[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies.wgc] package = "wgpu-core" path = "../wgpu-core" version = "0.11" @@ -101,7 +101,7 @@ package = "wgpu-types" path = "../wgpu-types" version = "0.11" -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.hal] +[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dependencies.hal] package = "wgpu-hal" path = "../wgpu-hal" version = "0.11" @@ -126,9 +126,11 @@ noise = { version = "0.7", default-features = false } obj = "0.10" png = "0.16" rand = "0.7.2" + +[target.'cfg(not(target_os = "emscripten"))'.dev-dependencies] winit = "0.26" -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +[target.'cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))'.dev-dependencies] async-executor = "1.0" pollster = "0.2" env_logger = "0.8" @@ -152,7 +154,7 @@ rev = "29571cc" #version = "0.7" features = ["wgsl-out"] -[target.'cfg(target_arch = "wasm32")'.dependencies] +[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] wasm-bindgen = "0.2.76" # remember to change version in wiki as well web-sys = { version = "0.3.53", features = [ "Document", @@ -283,7 +285,7 @@ wasm-bindgen-futures = "0.4.23" # enable parking_lot's wasm-bindgen feature so that it, in turn, enables that of crate `instant` parking_lot = { version = "0.11", features = ["wasm-bindgen"] } -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dev-dependencies] console_error_panic_hook = "0.1.6" console_log = "0.1.2" # We need the Location feature in the framework examples diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs index 885ca20127a..b049cae8147 100644 --- a/wgpu/examples/hello-triangle/main.rs +++ b/wgpu/examples/hello-triangle/main.rs @@ -1,11 +1,40 @@ +#[cfg(target_os = "emscripten")] +use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use std::borrow::Cow; +#[cfg(not(target_os = "emscripten"))] use winit::{ event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::Window, }; -async fn run(event_loop: EventLoop<()>, window: Window) { +#[cfg(target_os = "emscripten")] +struct Window {} + +#[cfg(target_os = "emscripten")] +struct Size { + width: u32, + height: u32, +} + +#[cfg(target_os = "emscripten")] +impl Window { + fn inner_size(self: &Window) -> Size { + Size { + width: 640, + height: 400, + } + } +} + +#[cfg(target_os = "emscripten")] +unsafe impl HasRawWindowHandle for Window { + fn raw_window_handle(&self) -> RawWindowHandle { + RawWindowHandle::Web(raw_window_handle::WebHandle::empty()) + } +} + +async fn run(#[cfg(not(target_os = "emscripten"))] event_loop: EventLoop<()>, window: Window) { let size = window.inner_size(); let instance = wgpu::Instance::new(wgpu::Backends::all()); let surface = unsafe { instance.create_surface(&window) }; @@ -67,6 +96,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { multiview: None, }); + #[cfg_attr(target_os = "emscripten", allow(unused_mut))] let mut config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: swapchain_format, @@ -77,6 +107,45 @@ async fn run(event_loop: EventLoop<()>, window: Window) { surface.configure(&device, &config); + fn redraw( + surface: &wgpu::Surface, + device: &wgpu::Device, + render_pipeline: &wgpu::RenderPipeline, + queue: &wgpu::Queue, + ) { + let frame = surface + .get_current_texture() + .expect("Failed to acquire next swap chain texture"); + let view = frame + .texture + .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); + { + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color::GREEN), + store: true, + }, + }], + depth_stencil_attachment: None, + }); + rpass.set_pipeline(render_pipeline); + rpass.draw(0..3, 0..1); + } + + queue.submit(Some(encoder.finish())); + frame.present(); + } + + #[cfg(target_os = "emscripten")] + redraw(&surface, &device, &render_pipeline, &queue); + + #[cfg(not(target_os = "emscripten"))] event_loop.run(move |event, _, control_flow| { // Have the closure take ownership of the resources. // `event_loop.run` never returns, therefore we must do this to ensure @@ -94,35 +163,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { config.height = size.height; surface.configure(&device, &config); } - Event::RedrawRequested(_) => { - let frame = surface - .get_current_texture() - .expect("Failed to acquire next swap chain texture"); - let view = frame - .texture - .create_view(&wgpu::TextureViewDescriptor::default()); - let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); - { - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, - color_attachments: &[wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::GREEN), - store: true, - }, - }], - depth_stencil_attachment: None, - }); - rpass.set_pipeline(&render_pipeline); - rpass.draw(0..3, 0..1); - } - - queue.submit(Some(encoder.finish())); - frame.present(); - } + Event::RedrawRequested(_) => redraw(&surface, &device, &render_pipeline, &queue), Event::WindowEvent { event: WindowEvent::CloseRequested, .. @@ -133,16 +174,18 @@ async fn run(event_loop: EventLoop<()>, window: Window) { } fn main() { - let event_loop = EventLoop::new(); - let window = winit::window::Window::new(&event_loop).unwrap(); #[cfg(not(target_arch = "wasm32"))] { + let event_loop = EventLoop::new(); + let window = winit::window::Window::new(&event_loop).unwrap(); env_logger::init(); // Temporarily avoid srgb formats for the swapchain on the web pollster::block_on(run(event_loop, window)); } - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] { + let event_loop = EventLoop::new(); + let window = winit::window::Window::new(&event_loop).unwrap(); std::panic::set_hook(Box::new(console_error_panic_hook::hook)); console_log::init().expect("could not initialize logger"); use winit::platform::web::WindowExtWebSys; @@ -157,4 +200,21 @@ fn main() { .expect("couldn't append canvas to document body"); wasm_bindgen_futures::spawn_local(run(event_loop, window)); } + #[cfg(target_os = "emscripten")] + { + use env_logger::Builder; + use log::LevelFilter; + + let window = Window {}; + Builder::new() + .format(|_buf, record| { + let message = format!("{}: {}", record.level(), record.args()); + println!("{}", &message); + Ok(()) + }) + .filter(None, LevelFilter::Info) + .init(); + + pollster::block_on(run(window)); + } } diff --git a/wgpu/src/backend/mod.rs b/wgpu/src/backend/mod.rs index e73d66ad895..bf08cb5f334 100644 --- a/wgpu/src/backend/mod.rs +++ b/wgpu/src/backend/mod.rs @@ -1,12 +1,32 @@ -#[cfg(all(target_arch = "wasm32", not(feature = "webgl")))] +#[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "webgl") +))] mod web; -#[cfg(all(target_arch = "wasm32", not(feature = "webgl")))] +#[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "webgl") +))] pub(crate) use web::{BufferMappedRange, Context}; -#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))] +#[cfg(any( + not(target_arch = "wasm32"), + target_os = "emscripten", + feature = "webgl" +))] mod direct; -#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))] +#[cfg(any( + not(target_arch = "wasm32"), + target_os = "emscripten", + feature = "webgl" +))] pub(crate) use direct::{BufferMappedRange, Context}; -#[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))] +#[cfg(any( + not(target_arch = "wasm32"), + target_os = "emscripten", + feature = "webgl" +))] mod native_gpu_future; diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 82869e020ad..3a97e213071 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1511,7 +1511,11 @@ impl Instance { /// # Safety /// /// - canvas must be a valid element to create a surface upon. - #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))] + #[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "webgl") + ))] pub unsafe fn create_surface_from_canvas( &self, canvas: &web_sys::HtmlCanvasElement, @@ -1527,7 +1531,11 @@ impl Instance { /// # Safety /// /// - canvas must be a valid OffscreenCanvas to create a surface upon. - #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))] + #[cfg(all( + target_arch = "wasm32", + not(target_os = "emscripten"), + not(feature = "webgl") + ))] pub unsafe fn create_surface_from_offscreen_canvas( &self, canvas: &web_sys::OffscreenCanvas,