Render: raster effects are made again when patterns, symbols, images, settings or fonts change

The renderer kept the rasters of an object's drop shadows, outer glows
and filtered content (Gaussian Blur, Feather and the Photoshop-style
filters), and drew them again while the object, the zoom and rotation
and the ink plane stayed the same. The content drawn into a raster also
reads things outside the object: patterns, symbols, brushes, images,
document, layer and color settings, the knockout a group inherits, the
fonts, and the options the frame is drawn with. When one of them
changed, a renderer that had drawn the object went on drawing the
raster it had kept, made from the old values.

Each kept raster now records what its content was drawn from: which of
those things the object reads, found by walking the object when the
raster is made, and a hash of their values then. The renderer draws
the raster only while that hash is the same in the current frame. Once
a frame, the renderer hashes the document's patterns, symbols and
images. It hashes their art and pixels by the addresses of their
shared values, and it keeps weak references to those values while a
raster made with them is kept, so no other value can take one of those
addresses. A filtered raster also records the color channels its
filters split, and under De-Interlace the raster resolution.

A temporary release test timed the inputs of 400 kept rasters at about
10 microseconds a frame.
This commit is contained in:
dotCooCoo
2026-10-13 00:34:41 +07:00
committed by bflatastic
parent 8754646784
commit f4e72fe6a5
8 changed files with 583 additions and 39 deletions
+14
View File
@@ -12,6 +12,7 @@
//! dimmed copies of it at the neighbouring tile positions and the tile edge.
use std::cell::RefCell;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use vectorcraft_doc::pattern::{Overlap, PatternDef, TileType};
@@ -57,6 +58,19 @@ fn same_art(a: &[Arc<Node>], b: &[Arc<Node>]) -> bool {
a.len() == b.len() && a.iter().zip(b).all(|(x, y)| Arc::ptr_eq(x, y))
}
/// Hash what pattern `def`'s tiling is drawn from, as the tile cache checks it: its name, the
/// addresses of its art, its tile, tile type and overlap.
pub(crate) fn hash_tiling(def: &PatternDef, h: &mut impl Hasher) {
def.name.hash(h);
def.art.iter().for_each(|a| (Arc::as_ptr(a) as usize).hash(h));
[def.tile.x0, def.tile.y0, def.tile.x1, def.tile.y1].map(f64::to_bits).hash(h);
std::mem::discriminant(&def.tile_type).hash(h);
if let TileType::BrickByRow { offset } | TileType::BrickByColumn { offset } = def.tile_type {
offset.to_bits().hash(h);
}
(def.overlap.right_in_front, def.overlap.bottom_in_front).hash(h);
}
/// Power-of-two raster scale for a pattern seen at device scale `s`, capped so the super-tile
/// stays under [`MAX_TILE_PX`].
pub(crate) fn raster_scale(s: f64, period: (f64, f64)) -> f64 {