1use crate::render::{ATLAS_IMAGE_ID_BASE, DEFAULT_GLYPH_ATLAS_SIZE};
15use crate::{
16 CompositeMode, Image, ImageSource, PaintType, Pixmap, RasterizerSettings, RenderContext,
17 RenderMode, RenderSettings, Resources, color, kurbo, peniko,
18};
19use alloc::boxed::Box;
20use alloc::sync::Arc;
21use alloc::vec::Vec;
22use color::palette::css::BLACK;
23use core::fmt::Debug;
24use core::ops::RangeInclusive;
25use glifo::atlas::{
26 AtlasConfig, AtlasSlot, GlyphAtlas, GlyphCacheConfig, ImageCache, PendingClearRect,
27};
28use glifo::{AtlasCacher, DrawSink, GlyphRunBackend};
29use glifo::{Glyph, renderer};
30use kurbo::{Affine, BezPath, Rect};
31use peniko::BlendMode;
32use peniko::color::{AlphaColor, Srgb};
33use vello_common::fearless_simd::Level;
34use vello_common::paint::ImageId;
35
36fn atlas_page_image_id(page_index: u32) -> ImageId {
37 ImageId::new(ATLAS_IMAGE_ID_BASE + page_index)
38}
39
40#[derive(Debug)]
41pub(crate) struct GlyphAtlasResources {
42 pub(crate) glyph_atlas: GlyphAtlas,
43 pub(crate) image_cache: ImageCache,
44 pub(crate) glyph_renderer: Box<RenderContext>,
45 pub(crate) pixmaps: Vec<Arc<Pixmap>>,
55 page_width: u16,
57 page_height: u16,
59}
60
61impl GlyphAtlasResources {
62 pub(crate) fn with_config(
63 page_width: u16,
64 page_height: u16,
65 level: Level,
66 eviction_config: GlyphCacheConfig,
67 ) -> Self {
68 Self {
69 glyph_atlas: GlyphAtlas::with_config(eviction_config),
70 image_cache: ImageCache::new_with_config(AtlasConfig::default()),
71 glyph_renderer: Box::new(RenderContext::new_with(
72 page_width,
73 page_height,
74 RenderSettings {
75 level,
76 num_threads: 0,
77 },
78 )),
79 pixmaps: Vec::new(),
80 page_width,
81 page_height,
82 }
83 }
84
85 pub(crate) fn maintain(&mut self) {
86 self.glyph_atlas.maintain(&mut self.image_cache);
87 }
88}
89
90fn ensure_page(
92 pixmaps: &mut Vec<Arc<Pixmap>>,
93 page_width: u16,
94 page_height: u16,
95 page_index: usize,
96) {
97 while pixmaps.len() <= page_index {
98 pixmaps.push(Arc::new(Pixmap::new(page_width, page_height)));
99 }
100}
101
102impl Resources {
103 pub(crate) fn prepare_glyph_cache(&mut self, render_mode: RenderMode) {
104 if self.glyph_resources.is_some() {
105 self.sync_glyph_cache(render_mode);
106 }
107 }
108
109 pub(crate) fn maintain_glyph_cache(&mut self) {
110 self.glyph_prep_cache.maintain();
111
112 if let Some(glyph_resources) = self.glyph_resources.as_mut() {
113 glyph_resources.maintain();
114 let page_count = glyph_resources.pixmaps.len();
115 for page_index in 0..page_count {
116 self.image_registry.destroy_atlas_page(page_index as u32);
117 }
118 self.clear_evicted_glyph_atlas_regions();
119 }
120 }
121
122 fn ensure_glyph_resources(&mut self, level: Level) {
123 if self.glyph_resources.is_none() {
124 self.glyph_resources = Some(GlyphAtlasResources::with_config(
125 DEFAULT_GLYPH_ATLAS_SIZE,
126 DEFAULT_GLYPH_ATLAS_SIZE,
127 level,
128 GlyphCacheConfig::default(),
129 ));
130 }
131 }
132
133 fn sync_glyph_cache(&mut self, render_mode: RenderMode) {
135 let glyph_resources = self
136 .glyph_resources
137 .as_mut()
138 .expect("glyph atlas resources must exist before syncing");
139
140 for upload in glyph_resources.glyph_atlas.drain_pending_uploads() {
142 let page_index = upload.atlas_slot.page_index as usize;
143 ensure_page(
144 &mut glyph_resources.pixmaps,
145 glyph_resources.page_width,
146 glyph_resources.page_height,
147 page_index,
148 );
149 let pixmap = Arc::get_mut(&mut glyph_resources.pixmaps[page_index])
150 .expect("atlas pixmap should be uniquely owned during bitmap upload");
151 copy_pixmap_to_atlas(
152 &upload.pixmap,
153 pixmap,
154 upload.atlas_slot.x,
155 upload.atlas_slot.y,
156 upload.atlas_slot.width,
157 upload.atlas_slot.height,
158 );
159 }
160
161 let glyph_renderer = glyph_resources.glyph_renderer.as_mut();
164 glyph_resources
165 .glyph_atlas
166 .replay_pending_atlas_commands(|recorder| {
167 let page_index = recorder.page_index as usize;
168 ensure_page(
169 &mut glyph_resources.pixmaps,
170 glyph_resources.page_width,
171 glyph_resources.page_height,
172 page_index,
173 );
174 let page = Arc::get_mut(&mut glyph_resources.pixmaps[page_index])
175 .expect("atlas page pixmap must be uniquely owned during replay");
176
177 glyph_renderer.reset();
178 renderer::replay_atlas_commands(&mut recorder.commands, glyph_renderer);
179 glyph_renderer.flush();
180 glyph_renderer.render_with(
181 page,
182 &mut Self::default(),
183 RasterizerSettings {
184 render_mode,
185 composite_mode: CompositeMode::SrcOver,
186 ..Default::default()
187 },
188 );
189 });
190
191 for (page_index, pixmap) in glyph_resources.pixmaps.iter().enumerate() {
192 self.image_registry
193 .register_atlas_page(page_index as u32, Arc::clone(pixmap));
194 }
195 }
196
197 fn clear_evicted_glyph_atlas_regions(&mut self) {
198 let glyph_resources = self
199 .glyph_resources
200 .as_mut()
201 .expect("glyph atlas resources must exist before clearing");
202 for clear in glyph_resources.glyph_atlas.drain_pending_clear_rects() {
203 let pixmap = Arc::get_mut(&mut glyph_resources.pixmaps[clear.page_index as usize])
204 .expect("atlas pixmap should be uniquely owned during region clearing");
205 clear_pixmap_region(pixmap, clear);
206 }
207 }
208}
209
210#[doc(hidden)]
211#[derive(Debug)]
212pub struct CpuGlyphRunBackend<'a> {
213 pub ctx: &'a mut RenderContext,
214 pub resources: &'a mut Resources,
215 pub atlas_cache_enabled: bool,
216}
217
218impl<'a> CpuGlyphRunBackend<'a> {
219 fn render_glyphs<Glyphs>(
220 self,
221 run: glifo::GlyphRun<'a>,
222 glyphs: Glyphs,
223 render: impl FnOnce(&mut glifo::GlyphRunRenderer<'a, 'a, Glyphs>, &mut RenderContext),
224 ) where
225 Glyphs: Iterator<Item = Glyph> + Clone,
226 {
227 let atlas_cacher = if self.atlas_cache_enabled {
228 self.resources
229 .ensure_glyph_resources(self.ctx.render_settings.level);
230 let glyph_resources = self
231 .resources
232 .glyph_resources
233 .as_mut()
234 .expect("glyph atlas resources must exist after initialization");
235 AtlasCacher::Enabled(
236 &mut glyph_resources.glyph_atlas,
237 &mut glyph_resources.image_cache,
238 )
239 } else {
240 AtlasCacher::Disabled
241 };
242
243 let mut glyph_run = run.build(
244 glyphs,
245 self.resources.glyph_prep_cache.as_mut(),
246 atlas_cacher,
247 );
248 render(&mut glyph_run, self.ctx);
249 }
250}
251
252impl<'a> GlyphRunBackend<'a> for CpuGlyphRunBackend<'a> {
253 fn atlas_cache(mut self, enabled: bool) -> Self {
254 self.atlas_cache_enabled = enabled;
255 self
256 }
257
258 fn fill_glyphs<Glyphs>(self, run: glifo::GlyphRun<'a>, glyphs: Glyphs)
259 where
260 Glyphs: Iterator<Item = Glyph> + Clone,
261 {
262 self.render_glyphs(run, glyphs, |glyph_run, ctx| glyph_run.fill_glyphs(ctx));
263 }
264
265 fn stroke_glyphs<Glyphs>(self, run: glifo::GlyphRun<'a>, glyphs: Glyphs)
266 where
267 Glyphs: Iterator<Item = Glyph> + Clone,
268 {
269 self.render_glyphs(run, glyphs, |glyph_run, ctx| {
270 let stroke_adjustment = glyph_run.stroke_adjustment();
271 let original_width = ctx.stroke().width;
272 ctx.stroke_mut().width *= stroke_adjustment;
273 glyph_run.stroke_glyphs(ctx);
274 ctx.stroke_mut().width = original_width;
275 });
276 }
277
278 fn render_decoration<Glyphs>(
279 self,
280 run: glifo::GlyphRun<'a>,
281 glyphs: Glyphs,
282 x_range: RangeInclusive<f32>,
283 baseline_y: f32,
284 offset: f32,
285 size: f32,
286 buffer: f32,
287 ) where
288 Glyphs: Iterator<Item = Glyph> + Clone,
289 {
290 self.render_glyphs(run, glyphs, |glyph_run, ctx| {
291 glyph_run.render_decoration(x_range, baseline_y, offset, size, buffer, ctx);
292 });
293 }
294}
295
296pub type GlyphRunBuilder<'a> = glifo::GlyphRunBuilder<'a, CpuGlyphRunBackend<'a>>;
298
299fn clear_pixmap_region(dst: &mut Pixmap, rect: PendingClearRect) {
304 let dst_stride = dst.width() as usize;
305 let dst_data = dst.data_as_u8_slice_mut();
306 let clear_width = rect.width as usize;
307 let clear_height = rect.height as usize;
308
309 for y in 0..clear_height {
310 let row_start = ((rect.y as usize + y) * dst_stride + rect.x as usize) * 4;
311 let row_end = row_start + clear_width * 4;
312 dst_data[row_start..row_end].fill(0);
313 }
314}
315
316fn copy_pixmap_to_atlas(
318 src: &Pixmap,
319 dst: &mut Pixmap,
320 dst_x: u16,
321 dst_y: u16,
322 width: u16,
323 height: u16,
324) {
325 let copy_width = width as usize;
326 let copy_height = height as usize;
327 let src_stride = src.width() as usize;
328 let dst_stride = dst.width() as usize;
329
330 let src_data = src.data_as_u8_slice();
331 let dst_data = dst.data_as_u8_slice_mut();
332
333 for y in 0..copy_height {
334 let src_row_start = y * src_stride * 4;
335 let src_row_end = src_row_start + copy_width * 4;
336 let dst_row_start = ((dst_y as usize + y) * dst_stride + dst_x as usize) * 4;
337 let dst_row_end = dst_row_start + copy_width * 4;
338
339 dst_data[dst_row_start..dst_row_end].copy_from_slice(&src_data[src_row_start..src_row_end]);
340 }
341}
342
343impl DrawSink for RenderContext {
344 #[inline]
345 fn set_transform(&mut self, t: Affine) {
346 Self::set_transform(self, t);
347 }
348
349 #[inline]
350 fn set_paint(&mut self, paint: glifo::AtlasPaint) {
351 Self::set_paint(self, paint);
352 }
353
354 #[inline]
355 fn set_paint_transform(&mut self, t: Affine) {
356 Self::set_paint_transform(self, t);
357 }
358
359 #[inline]
360 fn fill_path(&mut self, path: &BezPath) {
361 Self::fill_path(self, path);
362 }
363
364 #[inline]
365 fn fill_rect(&mut self, rect: &Rect) {
366 Self::fill_rect(self, rect);
367 }
368
369 #[inline]
370 fn push_clip_layer(&mut self, clip: &BezPath) {
371 Self::push_clip_layer(self, clip);
372 }
373
374 #[inline]
375 fn push_clip_path(&mut self, clip: &BezPath) {
376 Self::push_clip_path(self, clip);
377 }
378
379 #[inline]
380 fn push_blend_layer(&mut self, blend_mode: BlendMode) {
381 Self::push_blend_layer(self, blend_mode);
382 }
383
384 #[inline]
385 fn pop_layer(&mut self) {
386 Self::pop_layer(self);
387 }
388
389 #[inline]
390 fn pop_clip_path(&mut self) {
391 Self::pop_clip_path(self);
392 }
393
394 #[inline]
395 fn width(&self) -> u16 {
396 Self::width(self)
397 }
398
399 #[inline]
400 fn height(&self) -> u16 {
401 Self::height(self)
402 }
403}
404
405impl glifo::GlyphRenderer for RenderContext {
406 type SavedState = vello_common::render_state::RenderState;
407
408 #[inline]
409 fn save_state(&mut self) -> Self::SavedState {
410 self.save_current_state()
411 }
412
413 #[inline]
414 fn restore_state(&mut self, state: Self::SavedState) {
415 Self::restore_state(self, state);
416 }
417
418 #[inline]
419 fn stroke_path(&mut self, path: &BezPath) {
420 Self::stroke_path(self, path);
421 }
422
423 #[inline]
424 fn set_paint_image(&mut self, image: Image) {
425 self.set_paint(image);
426 }
427
428 #[inline]
429 fn set_tint(&mut self, tint: Option<vello_common::paint::Tint>) {
430 Self::set_tint(self, tint);
431 }
432
433 #[inline]
434 fn get_context_color(&self) -> AlphaColor<Srgb> {
435 let paint = self.paint().clone();
436 match paint {
437 PaintType::Solid(s) => s,
438 _ => BLACK,
439 }
440 }
441
442 #[inline]
443 fn current_paint(&self) -> &PaintType {
444 self.paint()
445 }
446
447 #[inline]
448 fn atlas_image_source(&self, atlas_slot: &AtlasSlot) -> ImageSource {
449 ImageSource::opaque_id(atlas_page_image_id(atlas_slot.page_index))
450 }
451
452 #[inline]
453 fn atlas_paint_transform(&self, atlas_slot: &AtlasSlot) -> Affine {
454 Affine::translate((-(atlas_slot.x as f64), -(atlas_slot.y as f64)))
455 }
456}
457
458#[cfg(debug_assertions)]
460#[allow(
461 dead_code,
462 unreachable_pub,
463 clippy::trivially_copy_pass_by_ref,
464 reason = "debug-only utilities called manually during development"
465)]
466mod debug {
467 use core::sync::atomic::{AtomicUsize, Ordering};
468
469 use crate::RenderContext;
470 use crate::kurbo::{Affine, Rect};
471 use crate::peniko;
472 use glifo::atlas::RasterMetrics;
473
474 static COLOR_INDEX: AtomicUsize = AtomicUsize::new(0);
475
476 const COLORS: [peniko::Color; 12] = [
479 peniko::Color::new([1.0, 0.0, 0.0, 0.5]), peniko::Color::new([0.0, 1.0, 0.0, 0.5]), peniko::Color::new([0.0, 0.0, 1.0, 0.5]), peniko::Color::new([1.0, 1.0, 0.0, 0.5]), peniko::Color::new([1.0, 0.0, 1.0, 0.5]), peniko::Color::new([0.0, 1.0, 1.0, 0.5]), peniko::Color::new([1.0, 0.5, 0.0, 0.5]), peniko::Color::new([0.5, 0.0, 1.0, 0.5]), peniko::Color::new([0.0, 1.0, 0.5, 0.5]), peniko::Color::new([1.0, 0.5, 0.5, 0.5]), peniko::Color::new([0.5, 1.0, 0.5, 0.5]), peniko::Color::new([0.5, 0.5, 1.0, 0.5]), ];
492
493 pub fn fill_glyph_bounds(renderer: &mut RenderContext, raster_metrics: &RasterMetrics) {
496 let idx = COLOR_INDEX.fetch_add(1, Ordering::Relaxed) % COLORS.len();
497 renderer.set_transform(Affine::IDENTITY);
498 renderer.set_paint(COLORS[idx]);
499 renderer.fill_rect(&Rect::new(
500 0.0,
501 0.0,
502 raster_metrics.width as f64,
503 raster_metrics.height as f64,
504 ));
505 }
506}