forma/renderer/
cpu.rs
1use std::borrow::Cow;
6use std::cell::{RefCell, RefMut};
7use std::rc::Rc;
8
9use rustc_hash::FxHashMap;
10use surpass::layout::Layout;
11use surpass::painter::{self, CachedTile, Channel, Color, LayerProps, Props, Rect};
12use surpass::rasterizer::Rasterizer;
13use surpass::{Order, TILE_HEIGHT, TILE_WIDTH};
14
15use crate::buffer::{Buffer, BufferLayerCache};
16use crate::{Composition, Layer};
17
18use crate::small_bit_set::SmallBitSet;
19
20#[derive(Debug, Default)]
21pub struct CpuRenderer {
22 rasterizer: Rasterizer<TILE_WIDTH, TILE_HEIGHT>,
23 buffers_with_caches: Rc<RefCell<SmallBitSet>>,
24}
25
26impl CpuRenderer {
27 #[inline]
28 pub fn new() -> Self {
29 Self::default()
30 }
31
32 #[inline]
33 pub fn create_buffer_layer_cache(&mut self) -> Option<BufferLayerCache> {
34 self.buffers_with_caches
35 .borrow_mut()
36 .first_empty_slot()
37 .map(|id| BufferLayerCache::new(id, Rc::downgrade(&self.buffers_with_caches)))
38 }
39
40 pub fn render<L>(
41 &mut self,
42 composition: &mut Composition,
43 buffer: &mut Buffer<'_, '_, L>,
44 mut channels: [Channel; 4],
45 clear_color: Color,
46 crop: Option<Rect>,
47 ) where
48 L: Layout,
49 {
50 if clear_color.a == 1.0 {
53 channels = channels.map(|c| match c {
54 Channel::Alpha => Channel::One,
55 c => c,
56 });
57 }
58
59 if let Some(layer_cache) = buffer.layer_cache.as_ref() {
60 let tiles_len = buffer.layout.width_in_tiles() * buffer.layout.height_in_tiles();
61 let cache = &layer_cache.cache;
62
63 cache.borrow_mut().tiles.resize(tiles_len, CachedTile::default());
64
65 if cache.borrow().width != Some(buffer.layout.width())
66 || cache.borrow().height != Some(buffer.layout.height())
67 {
68 cache.borrow_mut().width = Some(buffer.layout.width());
69 cache.borrow_mut().height = Some(buffer.layout.height());
70
71 layer_cache.clear();
72 }
73 }
74
75 composition.compact_geom();
76 composition.shared_state.borrow_mut().props_interner.compact();
77
78 let layers = &composition.layers;
79 let shared_state = &mut *composition.shared_state.borrow_mut();
80 let lines_builder = &mut shared_state.lines_builder;
81 let geom_id_to_order = &shared_state.geom_id_to_order;
82 let rasterizer = &mut self.rasterizer;
83
84 struct CompositionContext<'l> {
85 layers: &'l FxHashMap<Order, Layer>,
86 cache_id: Option<u8>,
87 }
88
89 impl LayerProps for CompositionContext<'_> {
90 #[inline]
91 fn get(&self, id: u32) -> Cow<'_, Props> {
92 Cow::Borrowed(
93 self.layers
94 .get(&Order::new(id).expect("PixelSegment layer_id cannot overflow Order"))
95 .map(|layer| &layer.props)
96 .expect(
97 "Layers outside of HashMap should not produce visible PixelSegments",
98 ),
99 )
100 }
101
102 #[inline]
103 fn is_unchanged(&self, id: u32) -> bool {
104 match self.cache_id {
105 None => false,
106 Some(cache_id) => self
107 .layers
108 .get(&Order::new(id).expect("PixelSegment layer_id cannot overflow Order"))
109 .map(|layer| layer.is_unchanged(cache_id))
110 .expect(
111 "Layers outside of HashMap should not produce visible PixelSegments",
112 ),
113 }
114 }
115 }
116
117 let context = CompositionContext {
118 layers,
119 cache_id: buffer.layer_cache.as_ref().map(|cache| cache.id),
120 };
121
122 let builder = lines_builder.take().expect("lines_builder should not be None");
124
125 *lines_builder = {
126 let lines = {
127 duration!(c"gfx", c"LinesBuilder::build");
128 builder.build(|id| {
129 geom_id_to_order
130 .get(&id)
131 .copied()
132 .flatten()
133 .and_then(|order| context.layers.get(&order))
134 .map(|layer| layer.inner.clone())
135 })
136 };
137
138 {
139 duration!(c"gfx", c"Rasterizer::rasterize");
140 rasterizer.rasterize(&lines);
141 }
142 {
143 duration!(c"gfx", c"Rasterizer::sort");
144 rasterizer.sort();
145 }
146
147 let previous_clear_color = buffer
148 .layer_cache
149 .as_ref()
150 .and_then(|layer_cache| layer_cache.cache.borrow().clear_color);
151
152 let cached_tiles = buffer.layer_cache.as_ref().map(|layer_cache| {
153 RefMut::map(layer_cache.cache.borrow_mut(), |cache| &mut cache.tiles)
154 });
155
156 {
157 duration!(c"gfx", c"painter::for_each_row");
158 painter::for_each_row(
159 buffer.layout,
160 buffer.buffer,
161 channels,
162 buffer.flusher.as_deref(),
163 previous_clear_color,
164 cached_tiles,
165 rasterizer.segments(),
166 clear_color,
167 &crop,
168 &context,
169 );
170 }
171
172 Some(lines.unwrap())
173 };
174
175 if let Some(buffer_layer_cache) = &buffer.layer_cache {
176 buffer_layer_cache.cache.borrow_mut().clear_color = Some(clear_color);
177
178 for layer in composition.layers.values_mut() {
179 layer.set_is_unchanged(buffer_layer_cache.id, layer.inner.is_enabled);
180 }
181 }
182 }
183}