Skip to content

Commit

Permalink
Use atomic_refcell instead of parking_lot for wasm32 targets (#1404)
Browse files Browse the repository at this point in the history
Closes #1401
  • Loading branch information
emilk authored Mar 22, 2022
1 parent e5aeb16 commit 41b178b
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 10 deletions.
10 changes: 7 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion eframe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion eframe/examples/custom_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

use eframe::egui;

use parking_lot::Mutex;
use egui::mutex::Mutex;
use std::sync::Arc;

fn main() {
Expand Down
1 change: 0 additions & 1 deletion egui_extras/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
2 changes: 1 addition & 1 deletion egui_extras/src/image.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use parking_lot::Mutex;
use egui::mutex::Mutex;

/// An image to be shown in egui.
///
Expand Down
1 change: 0 additions & 1 deletion egui_glow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion egui_glow/src/epi_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
Expand Down
10 changes: 9 additions & 1 deletion epaint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
80 changes: 80 additions & 0 deletions epaint/src/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(parking_lot::Mutex<T>);

Expand All @@ -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<T>(parking_lot::Mutex<T>);

Expand Down Expand Up @@ -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;
Expand All @@ -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<T>(parking_lot::RwLock<T>);

Expand All @@ -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<T>(atomic_refcell::AtomicRefCell<T>);

/// The lock you get from [`Mutex`].
pub use atomic_refcell::AtomicRefMut as MutexGuard;

impl<T> Mutex<T> {
#[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<T>(atomic_refcell::AtomicRefCell<T>);

impl<T> RwLock<T> {
#[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};
Expand Down

0 comments on commit 41b178b

Please sign in to comment.