diff --git a/Cargo.lock b/Cargo.lock index 1353b7d8..54821faf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" +[[package]] +name = "atomic_refcell" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bc31dce067eab974c815a9deb95f6217806de7b53685d7fc31f8ccf3fb2539f" + [[package]] name = "atty" version = "0.2.14" @@ -579,6 +585,7 @@ name = "egui" version = "0.5.0" dependencies = [ "ahash", + "atomic_refcell", "criterion", "parking_lot", "rusttype", @@ -618,7 +625,6 @@ version = "0.5.0" dependencies = [ "egui", "js-sys", - "parking_lot", "serde", "serde_json", "wasm-bindgen", @@ -853,9 +859,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ "cfg-if 1.0.0", - "js-sys", - "wasm-bindgen", - "web-sys", ] [[package]] diff --git a/README.md b/README.md index bbeb94a6..ef18c526 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ ui.label(format!("Hello '{}', age {}", name, age)); * Modular: You should be able to use small parts of Egui and combine them in new ways * Safe: there is no `unsafe` code in Egui * Minimal dependencies - * Egui uses [`rusttype`](https://crates.io/crates/rusttype) to render text and [`ahash`](https://crates.io/crates/ahash) + [`parking_lot`](https://crates.io/crates/parking_lot) for a speed boost. + * [`rusttype`](https://crates.io/crates/rusttype), [`atomic_refcell`](https://crates.io/crates/atomic_refcell) and [`ahash`](https://crates.io/crates/ahash). Egui is *not* a framework. Egui is a library you call into, not an environment you program for. diff --git a/egui/Cargo.toml b/egui/Cargo.toml index 4abefbc2..2cad4e01 100644 --- a/egui/Cargo.toml +++ b/egui/Cargo.toml @@ -20,7 +20,8 @@ include = [ [dependencies] ahash = { version = "0.6", features = ["std"], default-features = false } -parking_lot = "0.11" # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios +atomic_refcell = { version = "0.1", optional = true } # Used instead of parking_lot when you are always using Egui in a single thread. About as fast as parking_lot. +parking_lot = { version = "0.11", optional = true } # Using parking_lot over std::sync::Mutex gives 50% speedups in some real-world scenarios rusttype = "0.9" serde = { version = "1", features = ["derive"], optional = true } serde_json = { version = "1", optional = true } @@ -28,6 +29,10 @@ serde_json = { version = "1", optional = true } [dev-dependencies] criterion = { version = "0.3", default-features = false } +[features] +default = ["atomic_refcell"] # Using the same egui::Context from multiple threads will result in a panic. +multi_threaded = ["parking_lot"] # Only needed if you plan to use the same egui::Context from multiple threads. + [[bench]] name = "benchmark" harness = false diff --git a/egui/src/paint/font.rs b/egui/src/paint/font.rs index efad2286..c4b88389 100644 --- a/egui/src/paint/font.rs +++ b/egui/src/paint/font.rs @@ -2,13 +2,12 @@ use std::sync::Arc; use { ahash::AHashMap, - parking_lot::RwLock, rusttype::{point, Scale}, }; use crate::{ math::{vec2, Vec2}, - mutex::Mutex, + mutex::{Mutex, RwLock}, paint::{Galley, Row}, }; diff --git a/egui/src/util/mutex.rs b/egui/src/util/mutex.rs index 5604f66f..5c71ff8f 100644 --- a/egui/src/util/mutex.rs +++ b/egui/src/util/mutex.rs @@ -1,12 +1,15 @@ -//! Helper module for a Mutex that -//! detects double-locking on the same thread in debug mode. +//! Helper module that wraps some Mutex types with different implementations. -// TODO: feature-flag for `parking_lot` vs `std::sync::Mutex`. +// ---------------------------------------------------------------------------- + +#[cfg(feature = "multi_threaded")] pub use parking_lot::MutexGuard; +#[cfg(feature = "multi_threaded")] #[derive(Default)] pub struct Mutex(parking_lot::Mutex); +#[cfg(feature = "multi_threaded")] impl Mutex { #[inline(always)] pub fn new(val: T) -> Self { @@ -30,6 +33,89 @@ impl Mutex { } } +// --------------------- + +#[cfg(feature = "multi_threaded")] +pub use parking_lot::{RwLockReadGuard, RwLockWriteGuard}; + +#[cfg(feature = "multi_threaded")] +#[derive(Default)] +pub struct RwLock(parking_lot::RwLock); + +#[cfg(feature = "multi_threaded")] +impl RwLock { + #[inline(always)] + pub fn new(val: T) -> Self { + Self(parking_lot::RwLock::new(val)) + } + + #[inline(always)] + pub fn read(&self) -> RwLockReadGuard<'_, T> { + self.0.read() + } + + #[inline(always)] + pub fn write(&self) -> RwLockWriteGuard<'_, T> { + self.0.write() + } +} + +// ---------------------------------------------------------------------------- +// `atomic_refcell` will panic if multiple threads try to access the same value + +#[cfg(not(feature = "multi_threaded"))] +pub use atomic_refcell::AtomicRefMut as MutexGuard; + +#[cfg(not(feature = "multi_threaded"))] +#[derive(Default)] +pub struct Mutex(atomic_refcell::AtomicRefCell); + +#[cfg(not(feature = "multi_threaded"))] +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(not(feature = "multi_threaded"))] +pub use { + atomic_refcell::AtomicRef as RwLockReadGuard, atomic_refcell::AtomicRefMut as RwLockWriteGuard, +}; + +#[cfg(not(feature = "multi_threaded"))] +#[derive(Default)] +pub struct RwLock(atomic_refcell::AtomicRefCell); + +#[cfg(not(feature = "multi_threaded"))] +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() + } +} + +// ---------------------------------------------------------------------------- + impl Clone for Mutex where T: Clone, @@ -38,12 +124,3 @@ where Self::new(self.lock().clone()) } } - -// impl PartialEq for Mutex -// where -// T: PartialEq, -// { -// fn eq(&self, other: &Self) -> bool { -// std::ptr::eq(self, other) || self.lock().eq(&other.lock()) -// } -// } diff --git a/egui_web/Cargo.toml b/egui_web/Cargo.toml index 9269204d..9c9f62f6 100644 --- a/egui_web/Cargo.toml +++ b/egui_web/Cargo.toml @@ -18,7 +18,6 @@ crate-type = ["cdylib", "rlib"] [dependencies] egui = { version = "0.5.0", path = "../egui", features = ["serde"] } js-sys = "0.3" -parking_lot = { version = "0.11", features = ["wasm-bindgen"] } serde = "1" serde_json = "1" wasm-bindgen = "0.2"