diff --git a/vello_cpu/src/fine/mod.rs b/vello_cpu/src/fine/mod.rs index fdbf32b48..12a1a39bc 100644 --- a/vello_cpu/src/fine/mod.rs +++ b/vello_cpu/src/fine/mod.rs @@ -24,6 +24,7 @@ use crate::fine::common::rounded_blurred_rect::BlurredRoundedRectFiller; use crate::peniko::{BlendMode, ImageQuality}; use crate::region::Region; use crate::util::EncodedImageExt; +use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; use core::fmt::Debug; @@ -40,7 +41,7 @@ use vello_common::fearless_simd::{ use vello_common::filter_effects::Filter; use vello_common::kurbo::Affine; use vello_common::mask::Mask; -use vello_common::paint::{ImageResolver, ImageSource, Paint, PremulColor, Tint}; +use vello_common::paint::{ImageId, ImageResolver, ImageSource, Paint, PremulColor, Tint}; use vello_common::pixmap::Pixmap; use vello_common::simd::Splat4thExt; use vello_common::tile::Tile; @@ -544,6 +545,12 @@ pub struct Fine> { paint_buf: Vec, /// Buffer for storing gradient interpolation parameters (t values). f32_buf: Vec, + /// The most recently resolved opaque image. + /// + /// Caching it avoids hitting the image resolver (and the reference count of the + /// pixmap, which is shared between all threads) for each command that references + /// the same image, such as glyphs drawn from the same glyph atlas page. + resolved_image: Option<(ImageId, Arc)>, /// The current strip row y-coordinate in scene/filter coordinates. row_y: u16, /// The origin of the current target we are rendering into. @@ -564,6 +571,7 @@ impl> Fine { buffer_pool: VecPool::new(false), paint_buf: Vec::new(), f32_buf: Vec::new(), + resolved_image: None, row_y: 0, origin: (0, 0), } @@ -1077,12 +1085,18 @@ impl> Fine { } } EncodedPaint::Image(image) => { - let pixmap = match &image.source { - ImageSource::Pixmap(pixmap) => pixmap.clone(), - ImageSource::OpaqueId { id, .. } => resources - .image_resolver - .resolve(*id) - .unwrap_or_else(|| panic!("Image {:?} not found in registry", id)), + let pixmap: &Pixmap = match &image.source { + ImageSource::Pixmap(pixmap) => pixmap, + ImageSource::OpaqueId { id, .. } => { + if !matches!(&self.resolved_image, Some((cached, _)) if cached == id) { + let pixmap = resources + .image_resolver + .resolve(*id) + .unwrap_or_else(|| panic!("Image {:?} not found in registry", id)); + self.resolved_image = Some((*id, pixmap)); + } + &self.resolved_image.as_ref().unwrap().1 + } ImageSource::ExternalTexture { .. } => { unimplemented!("External textures are not supported by `vello_cpu`") } @@ -1096,7 +1110,7 @@ impl> Fine { fill_complex_paint!( image.may_have_transparency, T::plain_medium_quality_image_painter( - simd, image, &pixmap, sampler_x, sampler_y + simd, image, pixmap, sampler_x, sampler_y ), tint ); @@ -1104,7 +1118,7 @@ impl> Fine { fill_complex_paint!( image.may_have_transparency, T::high_quality_image_painter( - simd, image, &pixmap, sampler_x, sampler_y + simd, image, pixmap, sampler_x, sampler_y ), tint ); @@ -1116,7 +1130,7 @@ impl> Fine { fill_complex_paint!( image.may_have_transparency, T::medium_quality_image_painter( - simd, image, &pixmap, sampler_x, sampler_y + simd, image, pixmap, sampler_x, sampler_y ), tint ); @@ -1124,7 +1138,7 @@ impl> Fine { fill_complex_paint!( image.may_have_transparency, T::high_quality_image_painter( - simd, image, &pixmap, sampler_x, sampler_y + simd, image, pixmap, sampler_x, sampler_y ), tint ); @@ -1133,14 +1147,14 @@ impl> Fine { (false, true) => { fill_complex_paint!( image.may_have_transparency, - T::plain_nn_image_painter(simd, image, &pixmap, sampler_x, sampler_y), + T::plain_nn_image_painter(simd, image, pixmap, sampler_x, sampler_y), tint ); } (true, true) => { fill_complex_paint!( image.may_have_transparency, - T::nn_image_painter(simd, image, &pixmap, sampler_x, sampler_y), + T::nn_image_painter(simd, image, pixmap, sampler_x, sampler_y), tint ); }