From dd50cba9a75e2d2901f3af28375e84bf889e0114 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 20 Oct 2021 21:58:35 +0200 Subject: [PATCH] Optimize debug builds --- egui/src/context.rs | 16 ++++++++-------- egui/src/id.rs | 6 ++++++ epaint/src/mutex.rs | 44 +++++++++++++++++++++++++++++++------------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/egui/src/context.rs b/egui/src/context.rs index a08b40fb..6b9130c1 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -199,22 +199,24 @@ impl CtxRef { changed: false, // must be set by the widget itself }; + let mut memory = self.memory(); + if !enabled || !sense.focusable || !layer_id.allow_interaction() { // Not interested or allowed input: - self.memory().surrender_focus(id); + memory.surrender_focus(id); return response; } // We only want to focus labels if the screen reader is on. let interested_in_focus = - sense.interactive() || sense.focusable && self.memory().options.screen_reader; + sense.interactive() || sense.focusable && memory.options.screen_reader; if interested_in_focus { - self.memory().interested_in_focus(id); + memory.interested_in_focus(id); } if sense.click - && response.has_focus() + && memory.has_focus(response.id) && (self.input().key_pressed(Key::Space) || self.input().key_pressed(Key::Enter)) { // Space/enter works like a primary click for e.g. selected buttons @@ -224,8 +226,6 @@ impl CtxRef { self.register_interaction_id(id, rect); if sense.click || sense.drag { - let mut memory = self.memory(); - memory.interaction.click_interest |= hovered && sense.click; memory.interaction.drag_interest |= hovered && sense.drag; @@ -287,8 +287,8 @@ impl CtxRef { response.hovered &= response.is_pointer_button_down_on; // we don't hover widgets while interacting with *other* widgets } - if response.has_focus() && response.clicked_elsewhere() { - self.memory().surrender_focus(id); + if memory.has_focus(response.id) && response.clicked_elsewhere() { + memory.surrender_focus(id); } response diff --git a/egui/src/id.rs b/egui/src/id.rs index af15db83..73ab9042 100644 --- a/egui/src/id.rs +++ b/egui/src/id.rs @@ -88,9 +88,12 @@ impl std::hash::Hasher for IdHasher { fn write_u32(&mut self, _n: u32) { unreachable!("Invalid use of IdHasher"); } + + #[inline(always)] fn write_u64(&mut self, n: u64) { self.0 = n; } + fn write_usize(&mut self, _n: usize) { unreachable!("Invalid use of IdHasher"); } @@ -111,6 +114,7 @@ impl std::hash::Hasher for IdHasher { unreachable!("Invalid use of IdHasher"); } + #[inline(always)] fn finish(&self) -> u64 { self.0 } @@ -122,6 +126,8 @@ pub struct BuilIdHasher {} impl std::hash::BuildHasher for BuilIdHasher { type Hasher = IdHasher; + + #[inline(always)] fn build_hasher(&self) -> IdHasher { IdHasher::default() } diff --git a/epaint/src/mutex.rs b/epaint/src/mutex.rs index 932ef2e0..2d8e4cb2 100644 --- a/epaint/src/mutex.rs +++ b/epaint/src/mutex.rs @@ -7,6 +7,11 @@ compile_error!("Either feature \"single_threaded\" or \"multi_threaded\" must be // ---------------------------------------------------------------------------- +/// Provides interior mutability. Only thread-safe if the `multi_threaded` feature is enabled. +#[cfg(feature = "multi_threaded")] +#[derive(Default)] +pub struct Mutex(parking_lot::Mutex); + /// The lock you get from [`Mutex`]. #[cfg(feature = "multi_threaded")] #[cfg(not(debug_assertions))] @@ -17,14 +22,29 @@ pub use parking_lot::MutexGuard; #[cfg(debug_assertions)] pub struct MutexGuard<'a, T>(parking_lot::MutexGuard<'a, T>, *const ()); -/// Provides interior mutability. Only thread-safe if the `multi_threaded` feature is enabled. -#[cfg(feature = "multi_threaded")] +#[cfg(all(debug_assertions, feature = "multi_threaded"))] #[derive(Default)] -pub struct Mutex(parking_lot::Mutex); +struct HeldLocks(Vec<*const ()>); -#[cfg(debug_assertions)] +#[cfg(all(debug_assertions, feature = "multi_threaded"))] +impl HeldLocks { + fn insert(&mut self, lock: *const ()) { + // Very few locks will ever be held at the same time, so a linear search is fast + assert!( + !self.0.contains(&lock), + "Recursively locking a Mutex in the same thread is not supported" + ); + self.0.push(lock); + } + + fn remove(&mut self, lock: *const ()) { + self.0.retain(|&ptr| ptr != lock); + } +} + +#[cfg(all(debug_assertions, feature = "multi_threaded"))] thread_local! { - static HELD_LOCKS_TLS: std::cell::RefCell> = std::cell::RefCell::new(ahash::AHashSet::new()); + static HELD_LOCKS_TLS: std::cell::RefCell = Default::default(); } #[cfg(feature = "multi_threaded")] @@ -42,12 +62,8 @@ impl Mutex { let ptr = (&self.0 as *const parking_lot::Mutex<_>).cast::<()>(); // Store it in thread local storage while we have a lock guard taken out - HELD_LOCKS_TLS.with(|locks| { - if locks.borrow().contains(&ptr) { - panic!("Recursively locking a Mutex in the same thread is not supported"); - } else { - locks.borrow_mut().insert(ptr); - } + HELD_LOCKS_TLS.with(|held_locks| { + held_locks.borrow_mut().insert(ptr); }); MutexGuard(self.0.lock(), ptr) @@ -65,8 +81,8 @@ impl Mutex { impl Drop for MutexGuard<'_, T> { fn drop(&mut self) { let ptr = self.1; - HELD_LOCKS_TLS.with(|locks| { - locks.borrow_mut().remove(&ptr); + HELD_LOCKS_TLS.with(|held_locks| { + held_locks.borrow_mut().remove(ptr); }); } } @@ -76,6 +92,7 @@ impl Drop for MutexGuard<'_, T> { impl std::ops::Deref for MutexGuard<'_, T> { type Target = T; + #[inline(always)] fn deref(&self) -> &Self::Target { &self.0 } @@ -84,6 +101,7 @@ impl std::ops::Deref for MutexGuard<'_, T> { #[cfg(debug_assertions)] #[cfg(feature = "multi_threaded")] impl std::ops::DerefMut for MutexGuard<'_, T> { + #[inline(always)] fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }