mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
Keep track of dependencies between GalleyCaches and keep them alive
This commit is contained in:
@@ -728,6 +728,10 @@ impl FontsImpl {
|
|||||||
struct CachedGalley {
|
struct CachedGalley {
|
||||||
/// When it was last used
|
/// When it was last used
|
||||||
last_used: u32,
|
last_used: u32,
|
||||||
|
/// Hashes of all other entries this one depends on for quick re-layout.
|
||||||
|
/// Their `last_used`s should be updated alongside this one to make sure they're
|
||||||
|
/// not evicted.
|
||||||
|
children: Option<Arc<[u64]>>,
|
||||||
galley: Arc<Galley>,
|
galley: Arc<Galley>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -739,12 +743,12 @@ struct GalleyCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl GalleyCache {
|
impl GalleyCache {
|
||||||
fn layout(
|
fn layout_internal(
|
||||||
&mut self,
|
&mut self,
|
||||||
fonts: &mut FontsImpl,
|
fonts: &mut FontsImpl,
|
||||||
mut job: LayoutJob,
|
mut job: LayoutJob,
|
||||||
allow_split_paragraphs: bool,
|
allow_split_paragraphs: bool,
|
||||||
) -> Arc<Galley> {
|
) -> (u64, Arc<Galley>) {
|
||||||
if job.wrap.max_width.is_finite() {
|
if job.wrap.max_width.is_finite() {
|
||||||
// Protect against rounding errors in egui layout code.
|
// Protect against rounding errors in egui layout code.
|
||||||
|
|
||||||
@@ -772,32 +776,56 @@ impl GalleyCache {
|
|||||||
|
|
||||||
let hash = crate::util::hash(&job); // TODO(emilk): even faster hasher?
|
let hash = crate::util::hash(&job); // TODO(emilk): even faster hasher?
|
||||||
|
|
||||||
match self.cache.entry(hash) {
|
(hash, match self.cache.entry(hash) {
|
||||||
std::collections::hash_map::Entry::Occupied(entry) => {
|
std::collections::hash_map::Entry::Occupied(entry) => {
|
||||||
// The job was found in cache - no need to re-layout.
|
// The job was found in cache - no need to re-layout.
|
||||||
let cached = entry.into_mut();
|
let cached = entry.into_mut();
|
||||||
cached.last_used = self.generation;
|
cached.last_used = self.generation;
|
||||||
cached.galley.clone()
|
|
||||||
|
let galley = cached.galley.clone();
|
||||||
|
if let Some(children) = &cached.children {
|
||||||
|
for child_hash in children.clone().iter() {
|
||||||
|
if let Some(cached_child) = self.cache.get_mut(child_hash) {
|
||||||
|
cached_child.last_used = self.generation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
galley
|
||||||
}
|
}
|
||||||
std::collections::hash_map::Entry::Vacant(entry) => {
|
std::collections::hash_map::Entry::Vacant(entry) => {
|
||||||
let job = Arc::new(job);
|
let job = Arc::new(job);
|
||||||
if allow_split_paragraphs && should_cache_each_paragraph_individually(&job) {
|
if allow_split_paragraphs && should_cache_each_paragraph_individually(&job) {
|
||||||
let galley = self.layout_each_paragraph_individuallly(fonts, job);
|
let mut child_hashes = Vec::new();
|
||||||
// TODO(afishhh): This Galley cannot be added directly into the cache without taking
|
let galley = self.layout_each_paragraph_individuallly(fonts, job, &mut child_hashes);
|
||||||
// extra precautions to make sure all component paragraph Galleys are not invalidated
|
let galley = Arc::new(galley);
|
||||||
// immediately next frame (since their `last_used` will not be updated).
|
self.cache.insert(hash, CachedGalley {
|
||||||
Arc::new(galley)
|
last_used: self.generation,
|
||||||
|
children: Some(child_hashes.into()),
|
||||||
|
galley: galley.clone()
|
||||||
|
});
|
||||||
|
galley
|
||||||
} else {
|
} else {
|
||||||
let galley = super::layout(fonts, job);
|
let galley = super::layout(fonts, job);
|
||||||
let galley = Arc::new(galley);
|
let galley = Arc::new(galley);
|
||||||
entry.insert(CachedGalley {
|
entry.insert(CachedGalley {
|
||||||
last_used: self.generation,
|
last_used: self.generation,
|
||||||
|
children: None,
|
||||||
galley: galley.clone(),
|
galley: galley.clone(),
|
||||||
});
|
});
|
||||||
galley
|
galley
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(
|
||||||
|
&mut self,
|
||||||
|
fonts: &mut FontsImpl,
|
||||||
|
job: LayoutJob,
|
||||||
|
allow_split_paragraphs: bool,
|
||||||
|
) -> Arc<Galley> {
|
||||||
|
self.layout_internal(fonts, job, allow_split_paragraphs).1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split on `\n` and lay out (and cache) each paragraph individually.
|
/// Split on `\n` and lay out (and cache) each paragraph individually.
|
||||||
@@ -805,6 +833,7 @@ impl GalleyCache {
|
|||||||
&mut self,
|
&mut self,
|
||||||
fonts: &mut FontsImpl,
|
fonts: &mut FontsImpl,
|
||||||
job: Arc<LayoutJob>,
|
job: Arc<LayoutJob>,
|
||||||
|
child_hashes: &mut Vec<u64>
|
||||||
) -> Galley {
|
) -> Galley {
|
||||||
profiling::function_scope!();
|
profiling::function_scope!();
|
||||||
|
|
||||||
@@ -878,7 +907,8 @@ impl GalleyCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(emilk): we could lay out each paragraph in parallel to get a nice speedup on multicore machines.
|
// TODO(emilk): we could lay out each paragraph in parallel to get a nice speedup on multicore machines.
|
||||||
let galley = self.layout(fonts, paragraph_job, false);
|
let (hash, galley) = self.layout_internal(fonts, paragraph_job, false);
|
||||||
|
child_hashes.push(hash);
|
||||||
|
|
||||||
// This will prevent us from invalidating cache entries unnecessarily:
|
// This will prevent us from invalidating cache entries unnecessarily:
|
||||||
if max_rows_remaining != usize::MAX {
|
if max_rows_remaining != usize::MAX {
|
||||||
|
|||||||
Reference in New Issue
Block a user