From 1aa1e6c6ab2b21ef860443e4d89e2f4f45f01962 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 25 Aug 2021 17:28:25 +0200 Subject: [PATCH] Move pooling of line wrappers into `FontCache` Co-Authored-By: Nathan Sobo --- gpui/src/elements/text.rs | 4 +- gpui/src/font_cache.rs | 62 ++++++++++++++++++++++++-- gpui/src/presenter.rs | 2 +- gpui/src/text_layout.rs | 50 +-------------------- zed/src/editor/display_map/wrap_map.rs | 7 +-- 5 files changed, 65 insertions(+), 60 deletions(-) diff --git a/gpui/src/elements/text.rs b/gpui/src/elements/text.rs index 45aaab465771194c8574b29abff03be7239d74e4..0459a6882944ecfe8682b9debec847647c5dd52c 100644 --- a/gpui/src/elements/text.rs +++ b/gpui/src/elements/text.rs @@ -7,7 +7,7 @@ use crate::{ vector::{vec2f, Vector2F}, }, json::{ToJson, Value}, - text_layout::{Line, LineWrapper, ShapedBoundary}, + text_layout::{Line, ShapedBoundary}, DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint, }; use serde_json::json; @@ -60,7 +60,7 @@ impl Element for Text { .unwrap(); let line_height = cx.font_cache.line_height(font_id, self.font_size); - let mut wrapper = LineWrapper::acquire(font_id, self.font_size, cx.font_system.clone()); + let mut wrapper = cx.font_cache.line_wrapper(font_id, self.font_size); let mut lines = Vec::new(); let mut line_count = 0; let mut max_line_width = 0_f32; diff --git a/gpui/src/font_cache.rs b/gpui/src/font_cache.rs index 75ee206b35e7e3c35400ed584216da3bc2e512ff..b1deb802fd5bb18b83023a1be71910a53a8626de 100644 --- a/gpui/src/font_cache.rs +++ b/gpui/src/font_cache.rs @@ -2,10 +2,16 @@ use crate::{ fonts::{FontId, Metrics, Properties}, geometry::vector::{vec2f, Vector2F}, platform, + text_layout::LineWrapper, }; use anyhow::{anyhow, Result}; +use ordered_float::OrderedFloat; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; -use std::{collections::HashMap, sync::Arc}; +use std::{ + collections::HashMap, + ops::{Deref, DerefMut}, + sync::Arc, +}; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct FamilyId(usize); @@ -22,6 +28,12 @@ pub struct FontCacheState { families: Vec, font_selections: HashMap>, metrics: HashMap, + wrapper_pool: HashMap<(FontId, OrderedFloat), Vec>, +} + +pub struct LineWrapperHandle { + wrapper: Option, + font_cache: Arc, } unsafe impl Send for FontCache {} @@ -30,9 +42,10 @@ impl FontCache { pub fn new(fonts: Arc) -> Self { Self(RwLock::new(FontCacheState { fonts, - families: Vec::new(), - font_selections: HashMap::new(), - metrics: HashMap::new(), + families: Default::default(), + font_selections: Default::default(), + metrics: Default::default(), + wrapper_pool: Default::default(), })) } @@ -160,6 +173,47 @@ impl FontCache { pub fn scale_metric(&self, metric: f32, font_id: FontId, font_size: f32) -> f32 { metric * font_size / self.metric(font_id, |m| m.units_per_em as f32) } + + pub fn line_wrapper(self: &Arc, font_id: FontId, font_size: f32) -> LineWrapperHandle { + let mut state = self.0.write(); + let wrappers = state + .wrapper_pool + .entry((font_id, OrderedFloat(font_size))) + .or_default(); + let wrapper = wrappers + .pop() + .unwrap_or_else(|| LineWrapper::new(font_id, font_size, state.fonts.clone())); + LineWrapperHandle { + wrapper: Some(wrapper), + font_cache: self.clone(), + } + } +} + +impl Drop for LineWrapperHandle { + fn drop(&mut self) { + let mut state = self.font_cache.0.write(); + let wrapper = self.wrapper.take().unwrap(); + state + .wrapper_pool + .get_mut(&(wrapper.font_id, OrderedFloat(wrapper.font_size))) + .unwrap() + .push(wrapper); + } +} + +impl Deref for LineWrapperHandle { + type Target = LineWrapper; + + fn deref(&self) -> &Self::Target { + self.wrapper.as_ref().unwrap() + } +} + +impl DerefMut for LineWrapperHandle { + fn deref_mut(&mut self) -> &mut Self::Target { + self.wrapper.as_mut().unwrap() + } } #[cfg(test)] diff --git a/gpui/src/presenter.rs b/gpui/src/presenter.rs index 030b8262ccb5d2d4cea271d46a9eb96ab90a387c..80739a8be66ea0f2b502853e0be48c40d1c60de1 100644 --- a/gpui/src/presenter.rs +++ b/gpui/src/presenter.rs @@ -173,7 +173,7 @@ pub struct LayoutContext<'a> { rendered_views: &'a mut HashMap, parents: &'a mut HashMap, view_stack: Vec, - pub font_cache: &'a FontCache, + pub font_cache: &'a Arc, pub font_system: Arc, pub text_layout_cache: &'a TextLayoutCache, pub asset_cache: &'a AssetCache, diff --git a/gpui/src/text_layout.rs b/gpui/src/text_layout.rs index 8591dbe7f2bf3359f561a1222a06d1014f3ba7c7..71db39947664c825864ac7e7f9bdbbf051061d3c 100644 --- a/gpui/src/text_layout.rs +++ b/gpui/src/text_layout.rs @@ -7,7 +7,6 @@ use crate::{ }, platform, scene, FontSystem, PaintContext, }; -use lazy_static::lazy_static; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use smallvec::SmallVec; @@ -16,7 +15,6 @@ use std::{ collections::HashMap, hash::{Hash, Hasher}, iter, - ops::{Deref, DerefMut}, sync::Arc, }; @@ -307,10 +305,6 @@ impl Run { } } -lazy_static! { - static ref WRAPPER_POOL: Mutex> = Default::default(); -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Boundary { pub ix: usize, @@ -331,8 +325,8 @@ impl Boundary { pub struct LineWrapper { font_system: Arc, - font_id: FontId, - font_size: f32, + pub(crate) font_id: FontId, + pub(crate) font_size: f32, cached_ascii_char_widths: [f32; 128], cached_other_char_widths: HashMap, } @@ -340,23 +334,6 @@ pub struct LineWrapper { impl LineWrapper { pub const MAX_INDENT: u32 = 256; - pub fn acquire( - font_id: FontId, - font_size: f32, - font_system: Arc, - ) -> LineWrapperHandle { - let wrapper = if let Some(mut wrapper) = WRAPPER_POOL.lock().pop() { - if wrapper.font_id != font_id || wrapper.font_size != font_size { - wrapper.cached_ascii_char_widths = [f32::NAN; 128]; - wrapper.cached_other_char_widths.clear(); - } - wrapper - } else { - LineWrapper::new(font_id, font_size, font_system) - }; - LineWrapperHandle(Some(wrapper)) - } - pub fn new(font_id: FontId, font_size: f32, font_system: Arc) -> Self { Self { font_system, @@ -534,29 +511,6 @@ impl LineWrapper { } } -pub struct LineWrapperHandle(Option); - -impl Drop for LineWrapperHandle { - fn drop(&mut self) { - let wrapper = self.0.take().unwrap(); - WRAPPER_POOL.lock().push(wrapper) - } -} - -impl Deref for LineWrapperHandle { - type Target = LineWrapper; - - fn deref(&self) -> &Self::Target { - self.0.as_ref().unwrap() - } -} - -impl DerefMut for LineWrapperHandle { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0.as_mut().unwrap() - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/zed/src/editor/display_map/wrap_map.rs b/zed/src/editor/display_map/wrap_map.rs index c8c8f067ca5066a085663f62568b0db4295ea54c..3ba9690c640fcafdd109931c3cebe5dbaefe1a65 100644 --- a/zed/src/editor/display_map/wrap_map.rs +++ b/zed/src/editor/display_map/wrap_map.rs @@ -115,15 +115,13 @@ impl WrapMap { if let Some(wrap_width) = wrap_width { let mut new_snapshot = self.snapshot.clone(); - let font_system = cx.platform().fonts(); let font_cache = cx.font_cache().clone(); let settings = self.settings.clone(); let task = cx.background().spawn(async move { let font_id = font_cache .select_font(settings.buffer_font_family, &Default::default()) .unwrap(); - let mut line_wrapper = - LineWrapper::acquire(font_id, settings.buffer_font_size, font_system); + let mut line_wrapper = font_cache.line_wrapper(font_id, settings.buffer_font_size); let tab_snapshot = new_snapshot.tab_snapshot.clone(); let range = TabPoint::zero()..tab_snapshot.max_point(); new_snapshot @@ -193,7 +191,6 @@ impl WrapMap { if self.background_task.is_none() { let pending_edits = self.pending_edits.clone(); let mut snapshot = self.snapshot.clone(); - let font_system = cx.platform().fonts(); let font_cache = cx.font_cache().clone(); let settings = self.settings.clone(); let update_task = cx.background().spawn(async move { @@ -201,7 +198,7 @@ impl WrapMap { .select_font(settings.buffer_font_family, &Default::default()) .unwrap(); let mut line_wrapper = - LineWrapper::acquire(font_id, settings.buffer_font_size, font_system); + font_cache.line_wrapper(font_id, settings.buffer_font_size); for (tab_snapshot, edits) in pending_edits { snapshot .update(tab_snapshot, &edits, wrap_width, &mut line_wrapper)