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