Remove mutex for Font::glyph_info_cache
This commit is contained in:
parent
b0196527e5
commit
2fe3dd0c58
4 changed files with 50 additions and 51 deletions
|
@ -700,7 +700,7 @@ impl Context {
|
|||
self.request_repaint();
|
||||
}
|
||||
|
||||
self.fonts().lock().end_frame();
|
||||
self.fonts().end_frame();
|
||||
|
||||
{
|
||||
let ctx_impl = &mut *self.write();
|
||||
|
@ -1015,7 +1015,7 @@ impl Context {
|
|||
|
||||
ui.label(format!(
|
||||
"There are {} text galleys in the layout cache",
|
||||
self.fonts().lock().num_galleys_in_cache()
|
||||
self.fonts().num_galleys_in_cache()
|
||||
))
|
||||
.on_hover_text("This is approximately the number of text strings on screen");
|
||||
ui.add_space(16.0);
|
||||
|
|
|
@ -209,7 +209,7 @@ pub struct Font {
|
|||
replacement_glyph: (FontIndex, GlyphInfo),
|
||||
pixels_per_point: f32,
|
||||
row_height: f32,
|
||||
glyph_info_cache: RwLock<AHashMap<char, (FontIndex, GlyphInfo)>>,
|
||||
glyph_info_cache: AHashMap<char, (FontIndex, GlyphInfo)>,
|
||||
}
|
||||
|
||||
impl Font {
|
||||
|
@ -295,35 +295,30 @@ impl Font {
|
|||
|
||||
pub fn uv_rect(&self, c: char) -> UvRect {
|
||||
self.glyph_info_cache
|
||||
.read()
|
||||
.get(&c)
|
||||
.map(|gi| gi.1.uv_rect)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Width of this character in points.
|
||||
pub fn glyph_width(&self, c: char) -> f32 {
|
||||
pub fn glyph_width(&mut self, c: char) -> f32 {
|
||||
self.glyph_info(c).1.advance_width
|
||||
}
|
||||
|
||||
/// `\n` will (intentionally) show up as the replacement character.
|
||||
fn glyph_info(&self, c: char) -> (FontIndex, GlyphInfo) {
|
||||
{
|
||||
if let Some(font_index_glyph_info) = self.glyph_info_cache.read().get(&c) {
|
||||
return *font_index_glyph_info;
|
||||
}
|
||||
fn glyph_info(&mut self, c: char) -> (FontIndex, GlyphInfo) {
|
||||
if let Some(font_index_glyph_info) = self.glyph_info_cache.get(&c) {
|
||||
return *font_index_glyph_info;
|
||||
}
|
||||
|
||||
let font_index_glyph_info = self.glyph_info_no_cache_or_fallback(c);
|
||||
let font_index_glyph_info = font_index_glyph_info.unwrap_or(self.replacement_glyph);
|
||||
self.glyph_info_cache
|
||||
.write()
|
||||
.insert(c, font_index_glyph_info);
|
||||
self.glyph_info_cache.insert(c, font_index_glyph_info);
|
||||
font_index_glyph_info
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn glyph_info_and_font_impl(&self, c: char) -> (Option<&FontImpl>, GlyphInfo) {
|
||||
pub(crate) fn glyph_info_and_font_impl(&mut self, c: char) -> (Option<&FontImpl>, GlyphInfo) {
|
||||
if self.fonts.is_empty() {
|
||||
return (None, self.replacement_glyph.1);
|
||||
}
|
||||
|
@ -332,12 +327,10 @@ impl Font {
|
|||
(Some(font_impl), glyph_info)
|
||||
}
|
||||
|
||||
fn glyph_info_no_cache_or_fallback(&self, c: char) -> Option<(FontIndex, GlyphInfo)> {
|
||||
fn glyph_info_no_cache_or_fallback(&mut self, c: char) -> Option<(FontIndex, GlyphInfo)> {
|
||||
for (font_index, font_impl) in self.fonts.iter().enumerate() {
|
||||
if let Some(glyph_info) = font_impl.glyph_info(c) {
|
||||
self.glyph_info_cache
|
||||
.write()
|
||||
.insert(c, (font_index, glyph_info));
|
||||
self.glyph_info_cache.insert(c, (font_index, glyph_info));
|
||||
return Some((font_index, glyph_info));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,23 +233,27 @@ impl Default for FontDefinitions {
|
|||
/// Create one and reuse. Cheap to clone.
|
||||
///
|
||||
/// Wrapper for `Arc<Mutex<FontsImpl>>`.
|
||||
pub struct Fonts(Arc<Mutex<FontsImpl>>);
|
||||
pub struct Fonts {
|
||||
fonts: Arc<Mutex<FontsImpl>>,
|
||||
galley_cache: Arc<Mutex<GalleyCache>>,
|
||||
}
|
||||
|
||||
impl Fonts {
|
||||
/// Create a new [`Fonts`] for text layout.
|
||||
/// This call is expensive, so only create one [`Fonts`] and then reuse it.
|
||||
pub fn new(pixels_per_point: f32, definitions: FontDefinitions) -> Self {
|
||||
Self(Arc::new(Mutex::new(FontsImpl::new(
|
||||
pixels_per_point,
|
||||
definitions,
|
||||
))))
|
||||
let fonts = Arc::new(Mutex::new(FontsImpl::new(pixels_per_point, definitions)));
|
||||
Self {
|
||||
fonts,
|
||||
galley_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Access the underlying [`FontsImpl`].
|
||||
#[doc(hidden)]
|
||||
#[inline]
|
||||
pub fn lock(&self) -> crate::mutex::MutexGuard<'_, FontsImpl> {
|
||||
self.0.lock()
|
||||
self.fonts.lock()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -277,7 +281,16 @@ impl Fonts {
|
|||
/// The implementation uses memoization so repeated calls are cheap.
|
||||
/// #[inline]
|
||||
pub fn layout_job(&self, job: LayoutJob) -> Arc<Galley> {
|
||||
self.lock().layout_job(job)
|
||||
self.galley_cache.lock().layout(&mut self.fonts.lock(), job)
|
||||
}
|
||||
|
||||
pub fn num_galleys_in_cache(&self) -> usize {
|
||||
self.galley_cache.lock().num_galleys_in_cache()
|
||||
}
|
||||
|
||||
/// Must be called once per frame to clear the [`Galley`] cache.
|
||||
pub fn end_frame(&self) {
|
||||
self.galley_cache.lock().end_frame();
|
||||
}
|
||||
|
||||
/// Will wrap text at the given width and line break at `\n`.
|
||||
|
@ -324,6 +337,14 @@ impl Fonts {
|
|||
))
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// pub struct CachedFonts {
|
||||
// fonts: Arc<Mutex<FontsImpl>>,
|
||||
// galley_cache: Arc<Mutex<GalleyCache>>,
|
||||
// }
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// The collection of fonts used by `epaint`.
|
||||
|
@ -334,7 +355,6 @@ pub struct FontsImpl {
|
|||
definitions: FontDefinitions,
|
||||
fonts: BTreeMap<TextStyle, Font>,
|
||||
atlas: Arc<Mutex<TextureAtlas>>,
|
||||
galley_cache: Mutex<GalleyCache>,
|
||||
}
|
||||
|
||||
impl FontsImpl {
|
||||
|
@ -384,7 +404,6 @@ impl FontsImpl {
|
|||
definitions,
|
||||
fonts,
|
||||
atlas,
|
||||
galley_cache: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,6 +421,11 @@ impl FontsImpl {
|
|||
&self.fonts[&text_style]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn font_mut(&mut self, text_style: TextStyle) -> &mut Font {
|
||||
self.fonts.get_mut(&text_style).unwrap()
|
||||
}
|
||||
|
||||
/// Call each frame to get the change to the font texture since last call.
|
||||
pub fn font_image_delta(&self) -> Option<crate::ImageDelta> {
|
||||
self.atlas.lock().take_delta()
|
||||
|
@ -413,32 +437,14 @@ impl FontsImpl {
|
|||
}
|
||||
|
||||
/// Width of this character in points.
|
||||
pub fn glyph_width(&self, text_style: TextStyle, c: char) -> f32 {
|
||||
self.fonts[&text_style].glyph_width(c)
|
||||
pub fn glyph_width(&mut self, text_style: TextStyle, c: char) -> f32 {
|
||||
self.font_mut(text_style).glyph_width(c)
|
||||
}
|
||||
|
||||
/// Height of one row of text. In points
|
||||
pub fn row_height(&self, text_style: TextStyle) -> f32 {
|
||||
self.fonts[&text_style].row_height()
|
||||
}
|
||||
|
||||
/// Layout some text.
|
||||
/// This is the most advanced layout function.
|
||||
/// See also [`Self::layout`], [`Self::layout_no_wrap`] and
|
||||
/// [`Self::layout_delayed_color`].
|
||||
///
|
||||
/// The implementation uses memoization so repeated calls are cheap.
|
||||
pub fn layout_job(&self, job: LayoutJob) -> Arc<Galley> {
|
||||
self.galley_cache.lock().layout(self, job)
|
||||
}
|
||||
pub fn num_galleys_in_cache(&self) -> usize {
|
||||
self.galley_cache.lock().num_galleys_in_cache()
|
||||
}
|
||||
|
||||
/// Must be called once per frame to clear the [`Galley`] cache.
|
||||
pub fn end_frame(&self) {
|
||||
self.galley_cache.lock().end_frame();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -457,7 +463,7 @@ struct GalleyCache {
|
|||
}
|
||||
|
||||
impl GalleyCache {
|
||||
fn layout(&mut self, fonts: &FontsImpl, job: LayoutJob) -> Arc<Galley> {
|
||||
fn layout(&mut self, fonts: &mut FontsImpl, job: LayoutJob) -> Arc<Galley> {
|
||||
let hash = crate::util::hash(&job); // TODO: even faster hasher?
|
||||
|
||||
match self.cache.entry(hash) {
|
||||
|
|
|
@ -50,7 +50,7 @@ struct Paragraph {
|
|||
///
|
||||
/// In most cases you should use [`Fonts::layout_job`] instead
|
||||
/// since that memoizes the input, making subsequent layouting of the same text much faster.
|
||||
pub fn layout(fonts: &FontsImpl, job: Arc<LayoutJob>) -> Galley {
|
||||
pub fn layout(fonts: &mut FontsImpl, job: Arc<LayoutJob>) -> Galley {
|
||||
let mut paragraphs = vec![Paragraph::default()];
|
||||
for (section_index, section) in job.sections.iter().enumerate() {
|
||||
layout_section(fonts, &job, section_index as u32, section, &mut paragraphs);
|
||||
|
@ -75,7 +75,7 @@ pub fn layout(fonts: &FontsImpl, job: Arc<LayoutJob>) -> Galley {
|
|||
}
|
||||
|
||||
fn layout_section(
|
||||
fonts: &FontsImpl,
|
||||
fonts: &mut FontsImpl,
|
||||
job: &LayoutJob,
|
||||
section_index: u32,
|
||||
section: &LayoutSection,
|
||||
|
@ -86,7 +86,7 @@ fn layout_section(
|
|||
byte_range,
|
||||
format,
|
||||
} = section;
|
||||
let font = fonts.font(format.style);
|
||||
let font = fonts.font_mut(format.style);
|
||||
let font_height = font.row_height();
|
||||
|
||||
let mut paragraph = out_paragraphs.last_mut().unwrap();
|
||||
|
|
Loading…
Reference in a new issue