mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-29 20:27:05 -06:00
#1244: render caches bounded by bytes, evicting the least recently used instead of clearing
Text geometry, clips, clip paints, effect art, brushes, live effects, pattern tiles and freeform grids were capped by entry count and cleared wholesale on overflow, so a document past the cap (e.g. more than 4,096 type objects) recomputed every entry on every frame. A FrameCache keeps per-entry byte sizes and last-used frames, drops the least recently used entries of earlier frames, and sweeps stale ones. Text geometry keeps its glyph outlines once instead of twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
454f1737a3
commit
c4214be9d7
@@ -12,7 +12,6 @@
|
||||
//! dimmed copies of it at the neighbouring tile positions and the tile edge.
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use vectorcraft_doc::pattern::{Overlap, PatternDef, TileType};
|
||||
@@ -22,6 +21,7 @@ use vello_cpu::peniko::{Extend, ImageQuality, ImageSampler};
|
||||
use vello_cpu::{Pixmap, RenderContext};
|
||||
|
||||
use crate::ink::Ink;
|
||||
use crate::lru::{self, FrameCache};
|
||||
use crate::{Frame, RenderOptions, Rendered, Renderer};
|
||||
|
||||
/// Largest super-tile raster side (pixels).
|
||||
@@ -36,14 +36,19 @@ struct TileEntry {
|
||||
pixmap: Arc<Pixmap>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PatternCache {
|
||||
/// Per ink ([`Ink`] as index).
|
||||
tiles: [HashMap<String, TileEntry>; 3],
|
||||
/// Per ink ([`Ink`] as index), each within [`lru::PATTERN_BUDGET`], least recently used first out.
|
||||
tiles: [FrameCache<String, TileEntry>; 3],
|
||||
renderer: Option<Box<Renderer>>,
|
||||
depth: u32,
|
||||
}
|
||||
|
||||
impl Default for PatternCache {
|
||||
fn default() -> Self {
|
||||
Self { tiles: std::array::from_fn(|_| FrameCache::new(lru::PATTERN_BUDGET, usize::MAX)), renderer: None, depth: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static CACHE: RefCell<PatternCache> = RefCell::new(PatternCache::default());
|
||||
}
|
||||
@@ -137,10 +142,10 @@ pub(crate) fn set_pattern_paint(ctx: &mut RenderContext, name: &str, xf: Affine,
|
||||
let scale = raster_scale(s, (pw, ph));
|
||||
let params = (def.tile, def.tile_type, def.overlap);
|
||||
let hit = CACHE.with(|c| {
|
||||
c.borrow().tiles[ink as usize]
|
||||
.get(name)
|
||||
.filter(|e| e.scale == scale && e.params == params && same_art(&e.art, &def.art))
|
||||
.map(|e| (e.pixmap.clone(), e.sx, e.sy))
|
||||
let mut c = c.borrow_mut();
|
||||
let tiles = &mut c.tiles[ink as usize];
|
||||
let t = tiles.tick();
|
||||
tiles.get(name, t).filter(|e| e.scale == scale && e.params == params && same_art(&e.art, &def.art)).map(|e| (e.pixmap.clone(), e.sx, e.sy))
|
||||
});
|
||||
let (pm, sx, sy) = match hit {
|
||||
Some(h) => h,
|
||||
@@ -156,10 +161,8 @@ pub(crate) fn set_pattern_paint(ctx: &mut RenderContext, name: &str, xf: Affine,
|
||||
CACHE.with(|c| {
|
||||
let mut c = c.borrow_mut();
|
||||
let tiles = &mut c.tiles[ink as usize];
|
||||
if tiles.len() > 64 {
|
||||
tiles.clear();
|
||||
}
|
||||
tiles.insert(name.to_string(), TileEntry { art: def.art.clone(), params, scale, sx, sy, pixmap: pm.clone() });
|
||||
let (t, bytes) = (tiles.tick(), size_of::<TileEntry>() + w as usize * h as usize * 4);
|
||||
tiles.insert(name.to_string(), TileEntry { art: def.art.clone(), params, scale, sx, sy, pixmap: pm.clone() }, bytes, t);
|
||||
});
|
||||
(pm, sx, sy)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user