From 41b178b6ec5919e83a44d0bde7dffe74f95924e3 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Tue, 22 Mar 2022 15:34:21 +0100 Subject: [PATCH] Use atomic_refcell instead of parking_lot for wasm32 targets (#1404) Closes https://github.com/emilk/egui/issues/1401 --- Cargo.lock | 10 +++-- eframe/Cargo.toml | 1 - eframe/examples/custom_3d.rs | 2 +- egui_extras/Cargo.toml | 1 - egui_extras/src/image.rs | 2 +- egui_glow/Cargo.toml | 1 - egui_glow/src/epi_backend.rs | 2 +- epaint/Cargo.toml | 10 ++++- epaint/src/mutex.rs | 80 ++++++++++++++++++++++++++++++++++++ 9 files changed, 99 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c1e66bf3..a7f5b1e13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -203,6 +203,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "atomic_refcell" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d" + [[package]] name = "atty" version = "0.2.14" @@ -987,7 +993,6 @@ dependencies = [ "epi", "glow", "image", - "parking_lot 0.12.0", "poll-promise", "rfd", ] @@ -1057,7 +1062,6 @@ version = "0.17.0" dependencies = [ "egui", "image", - "parking_lot 0.12.0", "resvg", "tiny-skia", "usvg", @@ -1086,7 +1090,6 @@ dependencies = [ "glow", "glutin", "memoffset", - "parking_lot 0.12.0", "tracing", "wasm-bindgen", "web-sys", @@ -1200,6 +1203,7 @@ version = "0.17.0" dependencies = [ "ab_glyph", "ahash 0.7.6", + "atomic_refcell", "bytemuck", "cint", "criterion", diff --git a/eframe/Cargo.toml b/eframe/Cargo.toml index a502ce465..0c1e0b63e 100644 --- a/eframe/Cargo.toml +++ b/eframe/Cargo.toml @@ -71,6 +71,5 @@ image = { version = "0.24", default-features = false, features = [ "jpeg", "png", ] } -parking_lot = "0.12" poll-promise = "0.1" rfd = "0.8" diff --git a/eframe/examples/custom_3d.rs b/eframe/examples/custom_3d.rs index 6c4b5e6f0..f86d444e2 100644 --- a/eframe/examples/custom_3d.rs +++ b/eframe/examples/custom_3d.rs @@ -11,7 +11,7 @@ use eframe::egui; -use parking_lot::Mutex; +use egui::mutex::Mutex; use std::sync::Arc; fn main() { diff --git a/egui_extras/Cargo.toml b/egui_extras/Cargo.toml index 09ea707f3..7988b3408 100644 --- a/egui_extras/Cargo.toml +++ b/egui_extras/Cargo.toml @@ -28,7 +28,6 @@ svg = ["resvg", "tiny-skia", "usvg"] [dependencies] egui = { version = "0.17.0", path = "../egui", default-features = false } -parking_lot = "0.12" # Optional dependencies: diff --git a/egui_extras/src/image.rs b/egui_extras/src/image.rs index 4015acd30..b9001f201 100644 --- a/egui_extras/src/image.rs +++ b/egui_extras/src/image.rs @@ -1,4 +1,4 @@ -use parking_lot::Mutex; +use egui::mutex::Mutex; /// An image to be shown in egui. /// diff --git a/egui_glow/Cargo.toml b/egui_glow/Cargo.toml index fbf520261..717d8d7bc 100644 --- a/egui_glow/Cargo.toml +++ b/egui_glow/Cargo.toml @@ -63,7 +63,6 @@ epi = { version = "0.17.0", path = "../epi", optional = true } bytemuck = "1.7" glow = "0.11" memoffset = "0.6" -parking_lot = "0.12" tracing = "0.1" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/egui_glow/src/epi_backend.rs b/egui_glow/src/epi_backend.rs index 726116732..2e16e7ae7 100644 --- a/egui_glow/src/epi_backend.rs +++ b/egui_glow/src/epi_backend.rs @@ -54,7 +54,7 @@ pub fn run(app_name: &str, native_options: &epi::NativeOptions, app_creator: epi ); { - let event_loop_proxy = parking_lot::Mutex::new(event_loop.create_proxy()); + let event_loop_proxy = egui::mutex::Mutex::new(event_loop.create_proxy()); integration.egui_ctx.set_request_repaint_callback(move || { event_loop_proxy.lock().send_event(RequestRepaintEvent).ok(); }); diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index 3b42c7882..5316397e0 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -56,9 +56,17 @@ ahash = { version = "0.7", default-features = false, features = ["std"] } bytemuck = { version = "1.7.2", optional = true, features = ["derive"] } cint = { version = "^0.2.2", optional = true } nohash-hasher = "0.2" -parking_lot = "0.12" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. serde = { version = "1", optional = true, features = ["derive", "rc"] } +# native: +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +parking_lot = "0.12" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios. + +# web: +[target.'cfg(target_arch = "wasm32")'.dependencies] +atomic_refcell = "0.1" # Used instead of parking_lot on on wasm. See https://github.com/emilk/egui/issues/1401 + + [dev-dependencies] criterion = { version = "0.3", default-features = false } diff --git a/epaint/src/mutex.rs b/epaint/src/mutex.rs index 1d73ff7d7..b3639d199 100644 --- a/epaint/src/mutex.rs +++ b/epaint/src/mutex.rs @@ -2,9 +2,12 @@ // ---------------------------------------------------------------------------- +#[cfg(not(target_arch = "wasm32"))] #[cfg(not(debug_assertions))] mod mutex_impl { /// Provides interior mutability. + /// + /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. #[derive(Default)] pub struct Mutex(parking_lot::Mutex); @@ -24,9 +27,12 @@ mod mutex_impl { } } +#[cfg(not(target_arch = "wasm32"))] #[cfg(debug_assertions)] mod mutex_impl { /// Provides interior mutability. + /// + /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. #[derive(Default)] pub struct Mutex(parking_lot::Mutex); @@ -104,6 +110,7 @@ mod mutex_impl { } } +#[cfg(not(target_arch = "wasm32"))] mod rw_lock_impl { /// The lock you get from [`RwLock::read`]. pub use parking_lot::MappedRwLockReadGuard as RwLockReadGuard; @@ -112,6 +119,8 @@ mod rw_lock_impl { pub use parking_lot::MappedRwLockWriteGuard as RwLockWriteGuard; /// Provides interior mutability. + /// + /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. #[derive(Default)] pub struct RwLock(parking_lot::RwLock); @@ -133,12 +142,83 @@ mod rw_lock_impl { } } +#[cfg(not(target_arch = "wasm32"))] mod arc_impl { pub use std::sync::Arc; } // ---------------------------------------------------------------------------- +#[cfg(target_arch = "wasm32")] +mod mutex_impl { + // `atomic_refcell` will panic if multiple threads try to access the same value + + /// Provides interior mutability. + /// + /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. + #[derive(Default)] + pub struct Mutex(atomic_refcell::AtomicRefCell); + + /// The lock you get from [`Mutex`]. + pub use atomic_refcell::AtomicRefMut as MutexGuard; + + impl Mutex { + #[inline(always)] + pub fn new(val: T) -> Self { + Self(atomic_refcell::AtomicRefCell::new(val)) + } + + /// Panics if already locked. + #[inline(always)] + pub fn lock(&self) -> MutexGuard<'_, T> { + self.0.borrow_mut() + } + } +} + +#[cfg(target_arch = "wasm32")] +mod rw_lock_impl { + // `atomic_refcell` will panic if multiple threads try to access the same value + + /// The lock you get from [`RwLock::read`]. + pub use atomic_refcell::AtomicRef as RwLockReadGuard; + + /// The lock you get from [`RwLock::write`]. + pub use atomic_refcell::AtomicRefMut as RwLockWriteGuard; + + /// Provides interior mutability. + /// + /// Uses `parking_lot` crate on native targets, and `atomic_refcell` on `wasm32` targets. + #[derive(Default)] + pub struct RwLock(atomic_refcell::AtomicRefCell); + + impl RwLock { + #[inline(always)] + pub fn new(val: T) -> Self { + Self(atomic_refcell::AtomicRefCell::new(val)) + } + + #[inline(always)] + pub fn read(&self) -> RwLockReadGuard<'_, T> { + self.0.borrow() + } + + /// Panics if already locked. + #[inline(always)] + pub fn write(&self) -> RwLockWriteGuard<'_, T> { + self.0.borrow_mut() + } + } +} + +#[cfg(target_arch = "wasm32")] +mod arc_impl { + // pub use std::rc::Rc as Arc; // TODO(emilk): optimize single threaded code by using `Rc` instead of `Arc`. + pub use std::sync::Arc; +} + +// ---------------------------------------------------------------------------- + pub use arc_impl::Arc; pub use mutex_impl::{Mutex, MutexGuard}; pub use rw_lock_impl::{RwLock, RwLockReadGuard, RwLockWriteGuard};