From c9193b586b7a53ddd29308bcc19f660b7b8e05a9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 8 Jan 2024 19:31:50 +0100 Subject: [PATCH] WIP --- crates/gpui/src/view.rs | 53 +++++++++++++++++++++------------------ crates/gpui/src/window.rs | 33 +++++++++++++++++++++++- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/crates/gpui/src/view.rs b/crates/gpui/src/view.rs index 7d9b8092ee..9d504627ab 100644 --- a/crates/gpui/src/view.rs +++ b/crates/gpui/src/view.rs @@ -95,7 +95,7 @@ impl Element for View { } fn paint(&mut self, _: Bounds, element: &mut Self::State, cx: &mut WindowContext) { - element.take().unwrap().paint(cx); + cx.with_view_id(self.entity_id(), |cx| element.take().unwrap().paint(cx)); } } @@ -272,33 +272,36 @@ impl Element for AnyView { } fn paint(&mut self, bounds: Bounds, state: &mut Self::State, cx: &mut WindowContext) { - if !self.cache { - state.element.take().unwrap().paint(cx); - return; - } - - if let Some(cache_key) = state.cache_key.as_mut() { - if cache_key.bounds == bounds - && cache_key.content_mask == cx.content_mask() - && cache_key.stacking_order == *cx.stacking_order() - && cache_key.text_style == cx.text_style() - { - println!("could reuse geometry for view {}", self.entity_id()); + cx.with_view_id(self.entity_id(), |cx| { + if !self.cache { + state.element.take().unwrap().paint(cx); + return; } - } - let mut element = state - .element - .take() - .unwrap_or_else(|| (self.request_layout)(self, cx).1); - element.draw(bounds.origin, bounds.size.into(), cx); + if let Some(cache_key) = state.cache_key.as_mut() { + if cache_key.bounds == bounds + && cache_key.content_mask == cx.content_mask() + && cache_key.stacking_order == *cx.stacking_order() + && cache_key.text_style == cx.text_style() + && !cx.window.dirty_views.contains(&self.entity_id()) + { + println!("could reuse geometry for view {}", self.entity_id()); + } + } - state.cache_key = Some(ViewCacheKey { - bounds, - stacking_order: cx.stacking_order().clone(), - content_mask: cx.content_mask(), - text_style: cx.text_style(), - }); + let mut element = state + .element + .take() + .unwrap_or_else(|| (self.request_layout)(self, cx).1); + element.draw(bounds.origin, bounds.size.into(), cx); + + state.cache_key = Some(ViewCacheKey { + bounds, + stacking_order: cx.stacking_order().clone(), + content_mask: cx.content_mask(), + text_style: cx.text_style(), + }); + }) } } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index edd98e8385..98c81d3883 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -12,7 +12,7 @@ use crate::{ VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::{anyhow, Context as _, Result}; -use collections::FxHashMap; +use collections::{FxHashMap, FxHashSet}; use derive_more::{Deref, DerefMut}; use futures::{ channel::{mpsc, oneshot}, @@ -256,6 +256,7 @@ pub struct Window { pub(crate) element_id_stack: GlobalElementId, pub(crate) rendered_frame: Frame, pub(crate) next_frame: Frame, + pub(crate) dirty_views: FxHashSet, frame_arena: Arena, pub(crate) focus_handles: Arc>>, focus_listeners: SubscriberSet<(), AnyWindowFocusListener>, @@ -295,6 +296,8 @@ pub(crate) struct Frame { pub(crate) next_stacking_order_id: u32, content_mask_stack: Vec>, element_offset_stack: Vec>, + pub(crate) view_parents: FxHashMap, + pub(crate) view_stack: Vec, } impl Frame { @@ -310,6 +313,8 @@ impl Frame { depth_map: Default::default(), content_mask_stack: Vec::new(), element_offset_stack: Vec::new(), + view_parents: FxHashMap::default(), + view_stack: Vec::new(), } } @@ -319,6 +324,8 @@ impl Frame { self.dispatch_tree.clear(); self.depth_map.clear(); self.next_stacking_order_id = 0; + self.view_parents.clear(); + debug_assert!(self.view_stack.is_empty()); } fn focus_path(&self) -> SmallVec<[FocusId; 8]> { @@ -404,6 +411,7 @@ impl Window { element_id_stack: GlobalElementId::default(), rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())), next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())), + dirty_views: FxHashSet::default(), frame_arena: Arena::new(1024 * 1024), focus_handles: Arc::new(RwLock::new(SlotMap::with_key())), focus_listeners: SubscriberSet::new(), @@ -1423,6 +1431,7 @@ impl<'a> WindowContext<'a> { } self.window.drawing = false; + self.window.dirty_views.clear(); ELEMENT_ARENA.with_borrow_mut(|element_arena| element_arena.clear()); scene @@ -2119,6 +2128,13 @@ pub trait BorrowWindow: BorrowMut + BorrowMut { result } + fn with_view_id(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R { + self.window_mut().next_frame.view_stack.push(view_id); + let result = f(self); + self.window_mut().next_frame.view_stack.pop(); + result + } + /// Update the global element offset relative to the current offset. This is used to implement /// scrolling. fn with_element_offset( @@ -2476,6 +2492,21 @@ impl<'a, V: 'static> ViewContext<'a, V> { } pub fn notify(&mut self) { + let mut dirty_view_id = Some(self.view.entity_id()); + while let Some(view_id) = dirty_view_id { + if self.window_cx.window.dirty_views.insert(view_id) { + dirty_view_id = self + .window_cx + .window + .rendered_frame + .view_parents + .get(&view_id) + .copied(); + } else { + break; + } + } + if !self.window.drawing { self.window_cx.notify(); self.window_cx.app.push_effect(Effect::Notify {