forma_render/cpu/
renderer.rs1use std::{
16 borrow::Cow,
17 cell::{RefCell, RefMut},
18 ops::Range,
19 rc::Rc,
20};
21
22use rustc_hash::FxHashMap;
23
24use crate::{
25 consts,
26 cpu::painter::{self, CachedTile, LayerProps},
27 styling::{Color, Props},
28 utils::{Order, SmallBitSet},
29 Composition, Layer,
30};
31
32use super::{
33 buffer::{layout::Layout, Buffer, BufferLayerCache},
34 Channel, Rasterizer,
35};
36
37#[derive(Clone, Debug, Eq, Hash, PartialEq)]
38pub struct Rect {
39 pub(crate) hor: Range<usize>,
40 pub(crate) vert: Range<usize>,
41}
42
43impl Rect {
44 pub fn new(horizontal: Range<usize>, vertical: Range<usize>) -> Self {
46 Self {
47 hor: horizontal.start / consts::cpu::TILE_WIDTH
48 ..(horizontal.end + consts::cpu::TILE_WIDTH - 1) / consts::cpu::TILE_WIDTH,
49 vert: vertical.start / consts::cpu::TILE_HEIGHT
50 ..(vertical.end + consts::cpu::TILE_HEIGHT - 1) / consts::cpu::TILE_HEIGHT,
51 }
52 }
53}
54
55#[derive(Debug, Default)]
56pub struct Renderer {
57 rasterizer: Rasterizer<{ consts::cpu::TILE_WIDTH }, { consts::cpu::TILE_HEIGHT }>,
58 buffers_with_caches: Rc<RefCell<SmallBitSet>>,
59}
60
61impl Renderer {
62 #[inline]
63 pub fn new() -> Self {
64 Self::default()
65 }
66
67 #[inline]
68 pub fn create_buffer_layer_cache(&mut self) -> Option<BufferLayerCache> {
69 self.buffers_with_caches
70 .borrow_mut()
71 .first_empty_slot()
72 .map(|id| BufferLayerCache::new(id, Rc::downgrade(&self.buffers_with_caches)))
73 }
74
75 pub fn render<L>(
76 &mut self,
77 composition: &mut Composition,
78 buffer: &mut Buffer<'_, '_, L>,
79 mut channels: [Channel; 4],
80 clear_color: Color,
81 crop: Option<Rect>,
82 ) where
83 L: Layout,
84 {
85 if clear_color.a == 1.0 {
88 channels = channels.map(|c| match c {
89 Channel::Alpha => Channel::One,
90 c => c,
91 });
92 }
93
94 if let Some(layer_cache) = buffer.layer_cache.as_ref() {
95 let tiles_len = buffer.layout.width_in_tiles() * buffer.layout.height_in_tiles();
96 let cache = &layer_cache.cache;
97
98 cache
99 .borrow_mut()
100 .tiles
101 .resize(tiles_len, CachedTile::default());
102
103 if cache.borrow().width != Some(buffer.layout.width())
104 || cache.borrow().height != Some(buffer.layout.height())
105 {
106 cache.borrow_mut().width = Some(buffer.layout.width());
107 cache.borrow_mut().height = Some(buffer.layout.height());
108
109 layer_cache.clear();
110 }
111 }
112
113 composition.compact_geom();
114 composition
115 .shared_state
116 .borrow_mut()
117 .props_interner
118 .compact();
119
120 let layers = &composition.layers;
121 let shared_state = &mut *composition.shared_state.borrow_mut();
122 let segment_buffer = &mut shared_state.segment_buffer;
123 let geom_id_to_order = &shared_state.geom_id_to_order;
124 let rasterizer = &mut self.rasterizer;
125
126 struct CompositionContext<'l> {
127 layers: &'l FxHashMap<Order, Layer>,
128 cache_id: Option<u8>,
129 }
130
131 impl LayerProps for CompositionContext<'_> {
132 #[inline]
133 fn get(&self, id: u32) -> Cow<'_, Props> {
134 Cow::Borrowed(
135 self.layers
136 .get(&Order::new(id).expect("PixelSegment layer_id cannot overflow Order"))
137 .map(|layer| &layer.props)
138 .expect(
139 "Layers outside of HashMap should not produce visible PixelSegments",
140 ),
141 )
142 }
143
144 #[inline]
145 fn is_unchanged(&self, id: u32) -> bool {
146 match self.cache_id {
147 None => false,
148 Some(cache_id) => self
149 .layers
150 .get(&Order::new(id).expect("PixelSegment layer_id cannot overflow Order"))
151 .map(|layer| layer.is_unchanged(cache_id))
152 .expect(
153 "Layers outside of HashMap should not produce visible PixelSegments",
154 ),
155 }
156 }
157 }
158
159 let context = CompositionContext {
160 layers,
161 cache_id: buffer.layer_cache.as_ref().map(|cache| cache.id),
162 };
163
164 let builder = segment_buffer
166 .take()
167 .expect("segment_buffer should not be None");
168
169 *segment_buffer = {
170 let lines = {
171 duration!("gfx", "SegmentBuffer::fill_cpu_view");
172 builder.fill_cpu_view(|id| {
173 geom_id_to_order
174 .get(&id)
175 .copied()
176 .flatten()
177 .and_then(|order| context.layers.get(&order))
178 .map(|layer| layer.inner.clone())
179 })
180 };
181
182 {
183 duration!("gfx", "Rasterizer::rasterize");
184 rasterizer.rasterize(&lines);
185 }
186 {
187 duration!("gfx", "Rasterizer::sort");
188 rasterizer.sort();
189 }
190
191 let previous_clear_color = buffer
192 .layer_cache
193 .as_ref()
194 .and_then(|layer_cache| layer_cache.cache.borrow().clear_color);
195
196 let cached_tiles = buffer.layer_cache.as_ref().map(|layer_cache| {
197 RefMut::map(layer_cache.cache.borrow_mut(), |cache| &mut cache.tiles)
198 });
199
200 {
201 duration!("gfx", "painter::for_each_row");
202 painter::for_each_row(
203 buffer.layout,
204 buffer.buffer,
205 channels,
206 buffer.flusher.as_deref(),
207 previous_clear_color,
208 cached_tiles,
209 rasterizer.segments(),
210 clear_color,
211 &crop,
212 &context,
213 );
214 }
215
216 Some(lines.recycle())
217 };
218
219 if let Some(buffer_layer_cache) = &buffer.layer_cache {
220 buffer_layer_cache.cache.borrow_mut().clear_color = Some(clear_color);
221
222 for layer in composition.layers.values_mut() {
223 layer.set_is_unchanged(buffer_layer_cache.id, layer.inner.is_enabled);
224 }
225 }
226 }
227}