rlvgl_platform/
compositor.rs1use alloc::vec::Vec;
9use rlvgl_core::widget::Rect;
10
11#[derive(Debug, Clone, Copy)]
13struct FbRect {
14 x: u32,
15 y: u32,
16 w: u32,
17 h: u32,
18}
19
20struct SaveUnder {
22 region: FbRect,
23 pixels: Vec<u8>,
25}
26
27pub struct Compositor {
36 saves: Vec<(u32, SaveUnder)>,
38 pending_restore: Vec<SaveUnder>,
40 pending_pristine: Vec<(FbRect, u8)>,
42 pristine_addr: usize,
44 fb_width: u32,
46 fb_height: u32,
48 stride: usize,
50 next_id: u32,
52 last_pristine_regions: u16,
54 last_save_regions: u16,
56 last_restore_bytes: u32,
58 restore_seq: u32,
60}
61
62impl Compositor {
63 pub fn new(fb_width: u32, fb_height: u32, pristine_addr: u32) -> Self {
68 Self {
69 saves: Vec::new(),
70 pending_restore: Vec::new(),
71 pending_pristine: Vec::new(),
72 pristine_addr: pristine_addr as usize,
73 fb_width,
74 fb_height,
75 stride: (fb_width * 4) as usize,
76 next_id: 1,
77 last_pristine_regions: 0,
78 last_save_regions: 0,
79 last_restore_bytes: 0,
80 restore_seq: 0,
81 }
82 }
83
84 pub fn register_overlay(&mut self) -> u32 {
86 let id = self.next_id;
87 self.next_id += 1;
88 id
89 }
90
91 fn draw_to_fb(&self, draw_rect: Rect) -> FbRect {
93 let fb_x = (self.fb_width as i32 - draw_rect.y - draw_rect.height).max(0) as u32;
94 let fb_y = draw_rect.x.max(0) as u32;
95 let fb_w = (draw_rect.height as u32).min(self.fb_width.saturating_sub(fb_x));
96 let fb_h = (draw_rect.width as u32).min(self.fb_height.saturating_sub(fb_y));
97 FbRect {
98 x: fb_x,
99 y: fb_y,
100 w: fb_w,
101 h: fb_h,
102 }
103 }
104
105 pub unsafe fn save(&mut self, overlay_id: u32, draw_rect: Rect, front_buffer: *const u8) {
114 let fb = self.draw_to_fb(draw_rect);
115 if fb.w == 0 || fb.h == 0 {
116 return;
117 }
118 let stride = self.stride;
119 let mut pixels = Vec::with_capacity((fb.w * fb.h * 4) as usize);
120 for row in 0..fb.h {
121 let y = fb.y + row;
122 let off = y as usize * stride + fb.x as usize * 4;
123 let len = fb.w as usize * 4;
124 unsafe {
125 let src = core::slice::from_raw_parts(front_buffer.add(off), len);
126 pixels.extend_from_slice(src);
127 }
128 }
129 self.saves.retain(|(id, _)| *id != overlay_id);
131 self.saves
132 .push((overlay_id, SaveUnder { region: fb, pixels }));
133 }
134
135 pub fn mark_pristine_restore(&mut self, draw_rect: Rect) {
141 let fb = self.draw_to_fb(draw_rect);
142 if fb.w > 0 && fb.h > 0 {
143 self.pending_pristine.push((fb, 3));
145 }
146 }
147
148 pub fn mark_restore(&mut self, overlay_id: u32) {
153 if let Some(pos) = self.saves.iter().position(|(id, _)| *id == overlay_id) {
154 let (_, save) = self.saves.remove(pos);
155 self.pending_restore.push(save);
156 }
157 }
158
159 pub unsafe fn restore(&mut self, back_buffer: *mut u8) {
166 let stride = self.stride;
167 let mut pristine_regions = 0u16;
168 let mut save_regions = 0u16;
169 let mut restore_bytes = 0u32;
170
171 if self.pristine_addr != 0 {
173 let prist = self.pristine_addr as *const u8;
174 for (region, _) in &self.pending_pristine {
175 pristine_regions = pristine_regions.saturating_add(1);
176 for row in 0..region.h {
177 let y = region.y + row;
178 let off = y as usize * stride + region.x as usize * 4;
179 let len = region.w as usize * 4;
180 unsafe {
181 core::ptr::copy_nonoverlapping(prist.add(off), back_buffer.add(off), len);
182 }
183 restore_bytes = restore_bytes.saturating_add(len as u32);
184 }
185 }
186 }
187 for entry in &mut self.pending_pristine {
189 entry.1 = entry.1.saturating_sub(1);
190 }
191 self.pending_pristine.retain(|e| e.1 > 0);
192
193 for save in &self.pending_restore {
195 save_regions = save_regions.saturating_add(1);
196 let fb = &save.region;
197 let row_bytes = fb.w as usize * 4;
198 for row in 0..fb.h {
199 let y = fb.y + row;
200 let fb_off = y as usize * stride + fb.x as usize * 4;
201 let save_off = row as usize * row_bytes;
202 unsafe {
203 core::ptr::copy_nonoverlapping(
204 save.pixels.as_ptr().add(save_off),
205 back_buffer.add(fb_off),
206 row_bytes,
207 );
208 }
209 restore_bytes = restore_bytes.saturating_add(row_bytes as u32);
210 }
211 }
212 self.pending_restore.clear();
213 self.last_pristine_regions = pristine_regions;
214 self.last_save_regions = save_regions;
215 self.last_restore_bytes = restore_bytes;
216 self.restore_seq = self.restore_seq.wrapping_add(1);
217 }
218
219 pub fn has_pending(&self) -> bool {
221 !self.pending_restore.is_empty() || !self.pending_pristine.is_empty()
222 }
223
224 pub fn diag_counts(&self) -> u32 {
226 ((self.saves.len().min(0xFF) as u32) << 24)
227 | ((self.pending_restore.len().min(0xFF) as u32) << 16)
228 | ((self.pending_pristine.len().min(0xFF) as u32) << 8)
229 | ((self.last_pristine_regions.min(0x0F) as u32) << 4)
230 | (self.last_save_regions.min(0x0F) as u32)
231 }
232
233 pub fn diag_bytes(&self) -> u32 {
235 ((self.restore_seq & 0xFFFF) << 16) | (self.last_restore_bytes.min(0xFFFF))
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn draw_to_fb_transforms_correctly() {
245 let comp = Compositor::new(480, 800, 0);
246 let fb = comp.draw_to_fb(Rect {
247 x: 100,
248 y: 50,
249 width: 200,
250 height: 100,
251 });
252 assert_eq!((fb.x, fb.y, fb.w, fb.h), (330, 100, 100, 200));
254 }
255
256 #[test]
257 fn register_overlay_increments() {
258 let mut comp = Compositor::new(480, 800, 0);
259 assert_eq!(comp.register_overlay(), 1);
260 assert_eq!(comp.register_overlay(), 2);
261 }
262}