Reuse line layouts when reusing view
This commit is contained in:
parent
18eaefd0ed
commit
cbbba41748
3 changed files with 80 additions and 27 deletions
|
@ -9,11 +9,11 @@ pub use line_layout::*;
|
||||||
pub use line_wrapper::*;
|
pub use line_wrapper::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
px, Bounds, DevicePixels, Hsla, Pixels, PlatformTextSystem, Point, Result, SharedString, Size,
|
px, Bounds, DevicePixels, EntityId, Hsla, Pixels, PlatformTextSystem, Point, Result,
|
||||||
UnderlineStyle,
|
SharedString, Size, UnderlineStyle,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use collections::FxHashMap;
|
use collections::{FxHashMap, FxHashSet};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||||
|
@ -186,6 +186,10 @@ impl TextSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_view<R>(&self, view_id: EntityId, f: impl FnOnce() -> R) -> R {
|
||||||
|
self.line_layout_cache.with_view(view_id, f)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn layout_line(
|
pub fn layout_line(
|
||||||
&self,
|
&self,
|
||||||
text: &str,
|
text: &str,
|
||||||
|
@ -361,7 +365,11 @@ impl TextSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_frame(&self) {
|
pub fn start_frame(&self) {
|
||||||
self.line_layout_cache.start_frame()
|
self.line_layout_cache.start_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end_frame(&self, reused_views: &FxHashSet<EntityId>) {
|
||||||
|
self.line_layout_cache.end_frame(reused_views)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_wrapper(
|
pub fn line_wrapper(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{px, FontId, GlyphId, Pixels, PlatformTextSystem, Point, Size};
|
use crate::{px, EntityId, FontId, GlyphId, Pixels, PlatformTextSystem, Point, Size};
|
||||||
use collections::FxHashMap;
|
use collections::{FxHashMap, FxHashSet};
|
||||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -236,6 +236,7 @@ impl WrappedLineLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct LineLayoutCache {
|
pub(crate) struct LineLayoutCache {
|
||||||
|
view_stack: Mutex<Vec<EntityId>>,
|
||||||
previous_frame: Mutex<FxHashMap<CacheKey, Arc<LineLayout>>>,
|
previous_frame: Mutex<FxHashMap<CacheKey, Arc<LineLayout>>>,
|
||||||
current_frame: RwLock<FxHashMap<CacheKey, Arc<LineLayout>>>,
|
current_frame: RwLock<FxHashMap<CacheKey, Arc<LineLayout>>>,
|
||||||
previous_frame_wrapped: Mutex<FxHashMap<CacheKey, Arc<WrappedLineLayout>>>,
|
previous_frame_wrapped: Mutex<FxHashMap<CacheKey, Arc<WrappedLineLayout>>>,
|
||||||
|
@ -246,6 +247,7 @@ pub(crate) struct LineLayoutCache {
|
||||||
impl LineLayoutCache {
|
impl LineLayoutCache {
|
||||||
pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
|
pub fn new(platform_text_system: Arc<dyn PlatformTextSystem>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
view_stack: Mutex::default(),
|
||||||
previous_frame: Mutex::default(),
|
previous_frame: Mutex::default(),
|
||||||
current_frame: RwLock::default(),
|
current_frame: RwLock::default(),
|
||||||
previous_frame_wrapped: Mutex::default(),
|
previous_frame_wrapped: Mutex::default(),
|
||||||
|
@ -254,11 +256,43 @@ impl LineLayoutCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_frame(&self) {
|
pub fn end_frame(&self, reused_views: &FxHashSet<EntityId>) {
|
||||||
|
debug_assert_eq!(self.view_stack.lock().len(), 0);
|
||||||
|
|
||||||
let mut prev_frame = self.previous_frame.lock();
|
let mut prev_frame = self.previous_frame.lock();
|
||||||
let mut curr_frame = self.current_frame.write();
|
let mut curr_frame = self.current_frame.write();
|
||||||
|
for (key, layout) in prev_frame.drain() {
|
||||||
|
if key
|
||||||
|
.parent_view_id
|
||||||
|
.map_or(false, |view_id| reused_views.contains(&view_id))
|
||||||
|
{
|
||||||
|
curr_frame.insert(key, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
std::mem::swap(&mut *prev_frame, &mut *curr_frame);
|
std::mem::swap(&mut *prev_frame, &mut *curr_frame);
|
||||||
curr_frame.clear();
|
|
||||||
|
let mut prev_frame_wrapped = self.previous_frame_wrapped.lock();
|
||||||
|
let mut curr_frame_wrapped = self.current_frame_wrapped.write();
|
||||||
|
for (key, layout) in prev_frame_wrapped.drain() {
|
||||||
|
if key
|
||||||
|
.parent_view_id
|
||||||
|
.map_or(false, |view_id| reused_views.contains(&view_id))
|
||||||
|
{
|
||||||
|
curr_frame_wrapped.insert(key, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::mem::swap(&mut *prev_frame_wrapped, &mut *curr_frame_wrapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_view<R>(&self, view_id: EntityId, f: impl FnOnce() -> R) -> R {
|
||||||
|
self.view_stack.lock().push(view_id);
|
||||||
|
let result = f();
|
||||||
|
self.view_stack.lock().pop();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_view_id(&self) -> Option<EntityId> {
|
||||||
|
self.view_stack.lock().last().copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_wrapped_line(
|
pub fn layout_wrapped_line(
|
||||||
|
@ -273,6 +307,7 @@ impl LineLayoutCache {
|
||||||
font_size,
|
font_size,
|
||||||
runs,
|
runs,
|
||||||
wrap_width,
|
wrap_width,
|
||||||
|
parent_view_id: self.parent_view_id(),
|
||||||
} as &dyn AsCacheKeyRef;
|
} as &dyn AsCacheKeyRef;
|
||||||
|
|
||||||
let current_frame = self.current_frame_wrapped.upgradable_read();
|
let current_frame = self.current_frame_wrapped.upgradable_read();
|
||||||
|
@ -301,6 +336,7 @@ impl LineLayoutCache {
|
||||||
font_size,
|
font_size,
|
||||||
runs: SmallVec::from(runs),
|
runs: SmallVec::from(runs),
|
||||||
wrap_width,
|
wrap_width,
|
||||||
|
parent_view_id: self.parent_view_id(),
|
||||||
};
|
};
|
||||||
current_frame.insert(key, layout.clone());
|
current_frame.insert(key, layout.clone());
|
||||||
layout
|
layout
|
||||||
|
@ -313,6 +349,7 @@ impl LineLayoutCache {
|
||||||
font_size,
|
font_size,
|
||||||
runs,
|
runs,
|
||||||
wrap_width: None,
|
wrap_width: None,
|
||||||
|
parent_view_id: self.parent_view_id(),
|
||||||
} as &dyn AsCacheKeyRef;
|
} as &dyn AsCacheKeyRef;
|
||||||
|
|
||||||
let current_frame = self.current_frame.upgradable_read();
|
let current_frame = self.current_frame.upgradable_read();
|
||||||
|
@ -331,6 +368,7 @@ impl LineLayoutCache {
|
||||||
font_size,
|
font_size,
|
||||||
runs: SmallVec::from(runs),
|
runs: SmallVec::from(runs),
|
||||||
wrap_width: None,
|
wrap_width: None,
|
||||||
|
parent_view_id: self.parent_view_id(),
|
||||||
};
|
};
|
||||||
current_frame.insert(key, layout.clone());
|
current_frame.insert(key, layout.clone());
|
||||||
layout
|
layout
|
||||||
|
@ -348,12 +386,13 @@ trait AsCacheKeyRef {
|
||||||
fn as_cache_key_ref(&self) -> CacheKeyRef;
|
fn as_cache_key_ref(&self) -> CacheKeyRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq)]
|
#[derive(Debug, Eq)]
|
||||||
struct CacheKey {
|
struct CacheKey {
|
||||||
text: String,
|
text: String,
|
||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
runs: SmallVec<[FontRun; 1]>,
|
runs: SmallVec<[FontRun; 1]>,
|
||||||
wrap_width: Option<Pixels>,
|
wrap_width: Option<Pixels>,
|
||||||
|
parent_view_id: Option<EntityId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -362,6 +401,7 @@ struct CacheKeyRef<'a> {
|
||||||
font_size: Pixels,
|
font_size: Pixels,
|
||||||
runs: &'a [FontRun],
|
runs: &'a [FontRun],
|
||||||
wrap_width: Option<Pixels>,
|
wrap_width: Option<Pixels>,
|
||||||
|
parent_view_id: Option<EntityId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PartialEq for (dyn AsCacheKeyRef + 'a) {
|
impl<'a> PartialEq for (dyn AsCacheKeyRef + 'a) {
|
||||||
|
@ -385,6 +425,7 @@ impl AsCacheKeyRef for CacheKey {
|
||||||
font_size: self.font_size,
|
font_size: self.font_size,
|
||||||
runs: self.runs.as_slice(),
|
runs: self.runs.as_slice(),
|
||||||
wrap_width: self.wrap_width,
|
wrap_width: self.wrap_width,
|
||||||
|
parent_view_id: self.parent_view_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1461,14 +1461,11 @@ impl<'a> WindowContext<'a> {
|
||||||
self.window.focus_invalidated = false;
|
self.window.focus_invalidated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.text_system().start_frame();
|
|
||||||
if let Some(requested_handler) = self.window.rendered_frame.requested_input_handler.as_mut()
|
if let Some(requested_handler) = self.window.rendered_frame.requested_input_handler.as_mut()
|
||||||
{
|
{
|
||||||
requested_handler.handler = self.window.platform_window.take_input_handler();
|
requested_handler.handler = self.window.platform_window.take_input_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window.layout_engine.as_mut().unwrap().clear();
|
|
||||||
self.window.next_frame.clear();
|
|
||||||
let root_view = self.window.root_view.take().unwrap();
|
let root_view = self.window.root_view.take().unwrap();
|
||||||
|
|
||||||
self.with_z_index(0, |cx| {
|
self.with_z_index(0, |cx| {
|
||||||
|
@ -1528,11 +1525,6 @@ impl<'a> WindowContext<'a> {
|
||||||
self.platform.set_cursor_style(cursor_style);
|
self.platform.set_cursor_style(cursor_style);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.window
|
|
||||||
.next_frame
|
|
||||||
.reuse_views(&mut self.window.rendered_frame);
|
|
||||||
self.window.next_frame.scene.finish();
|
|
||||||
|
|
||||||
// Register requested input handler with the platform window.
|
// Register requested input handler with the platform window.
|
||||||
if let Some(requested_input) = self.window.next_frame.requested_input_handler.as_mut() {
|
if let Some(requested_input) = self.window.next_frame.requested_input_handler.as_mut() {
|
||||||
if let Some(handler) = requested_input.handler.take() {
|
if let Some(handler) = requested_input.handler.take() {
|
||||||
|
@ -1540,15 +1532,24 @@ impl<'a> WindowContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let previous_focus_path = self.window.rendered_frame.focus_path();
|
self.window
|
||||||
let previous_window_active = self.window.rendered_frame.window_active;
|
.next_frame
|
||||||
mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame);
|
.reuse_views(&mut self.window.rendered_frame);
|
||||||
let current_focus_path = self.window.rendered_frame.focus_path();
|
self.window.next_frame.scene.finish();
|
||||||
let current_window_active = self.window.rendered_frame.window_active;
|
self.window.layout_engine.as_mut().unwrap().clear();
|
||||||
|
self.text_system()
|
||||||
|
.end_frame(&self.window.next_frame.reused_views);
|
||||||
|
ELEMENT_ARENA.with_borrow_mut(|element_arena| element_arena.clear());
|
||||||
|
|
||||||
self.window.refreshing = false;
|
self.window.refreshing = false;
|
||||||
self.window.drawing = false;
|
self.window.drawing = false;
|
||||||
ELEMENT_ARENA.with_borrow_mut(|element_arena| element_arena.clear());
|
|
||||||
|
let previous_focus_path = self.window.rendered_frame.focus_path();
|
||||||
|
let previous_window_active = self.window.rendered_frame.window_active;
|
||||||
|
mem::swap(&mut self.window.rendered_frame, &mut self.window.next_frame);
|
||||||
|
self.window.next_frame.clear();
|
||||||
|
let current_focus_path = self.window.rendered_frame.focus_path();
|
||||||
|
let current_window_active = self.window.rendered_frame.window_active;
|
||||||
|
|
||||||
if previous_focus_path != current_focus_path
|
if previous_focus_path != current_focus_path
|
||||||
|| previous_window_active != current_window_active
|
|| previous_window_active != current_window_active
|
||||||
|
@ -2005,10 +2006,13 @@ impl<'a> WindowContext<'a> {
|
||||||
view_id: EntityId,
|
view_id: EntityId,
|
||||||
f: impl FnOnce(&mut Self) -> R,
|
f: impl FnOnce(&mut Self) -> R,
|
||||||
) -> R {
|
) -> R {
|
||||||
|
let text_system = self.text_system().clone();
|
||||||
|
text_system.with_view(view_id, || {
|
||||||
self.window.next_frame.view_stack.push(view_id);
|
self.window.next_frame.view_stack.push(view_id);
|
||||||
let result = f(self);
|
let result = f(self);
|
||||||
self.window.next_frame.view_stack.pop();
|
self.window.next_frame.view_stack.pop();
|
||||||
result
|
result
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
|
pub(crate) fn paint_view<R>(&mut self, view_id: EntityId, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue