1#![allow(dead_code)]
11
12use alloc::vec::Vec;
13
14use spin::Mutex;
15
16const MAX_DAMAGE_RECTS: usize = 32;
23
24const MAX_SURFACES: usize = 256;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub(crate) struct DamageRect {
34 pub x: i32,
35 pub y: i32,
36 pub width: u32,
37 pub height: u32,
38}
39
40impl DamageRect {
41 pub(crate) fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
43 Self {
44 x,
45 y,
46 width,
47 height,
48 }
49 }
50
51 #[inline]
53 pub(crate) fn right(&self) -> i32 {
54 self.x.saturating_add(self.width as i32)
55 }
56
57 #[inline]
59 pub(crate) fn bottom(&self) -> i32 {
60 self.y.saturating_add(self.height as i32)
61 }
62
63 #[inline]
65 pub(crate) fn area(&self) -> u64 {
66 self.width as u64 * self.height as u64
67 }
68
69 #[inline]
71 pub(crate) fn is_empty(&self) -> bool {
72 self.width == 0 || self.height == 0
73 }
74
75 #[inline]
77 fn overlaps(&self, other: &DamageRect) -> bool {
78 self.x < other.right()
79 && other.x < self.right()
80 && self.y < other.bottom()
81 && other.y < self.bottom()
82 }
83
84 #[inline]
86 fn touches(&self, other: &DamageRect) -> bool {
87 self.x <= other.right()
88 && other.x <= self.right()
89 && self.y <= other.bottom()
90 && other.y <= self.bottom()
91 }
92
93 fn union(&self, other: &DamageRect) -> DamageRect {
95 let x = self.x.min(other.x);
96 let y = self.y.min(other.y);
97 let r = self.right().max(other.right());
98 let b = self.bottom().max(other.bottom());
99 DamageRect {
100 x,
101 y,
102 width: (r - x) as u32,
103 height: (b - y) as u32,
104 }
105 }
106
107 fn intersect(&self, other: &DamageRect) -> DamageRect {
109 let x = self.x.max(other.x);
110 let y = self.y.max(other.y);
111 let r = self.right().min(other.right());
112 let b = self.bottom().min(other.bottom());
113 if r <= x || b <= y {
114 DamageRect::new(0, 0, 0, 0)
115 } else {
116 DamageRect::new(x, y, (r - x) as u32, (b - y) as u32)
117 }
118 }
119
120 pub(crate) fn clamp_to(&self, bounds: &DamageRect) -> DamageRect {
122 self.intersect(bounds)
123 }
124}
125
126#[derive(Debug, Clone)]
132struct SurfaceDamage {
133 surface_id: u64,
134 rects: Vec<DamageRect>,
135 surface_width: u32,
137 surface_height: u32,
138 full_damage: bool,
140}
141
142impl SurfaceDamage {
143 fn new(surface_id: u64, width: u32, height: u32) -> Self {
144 Self {
145 surface_id,
146 rects: Vec::new(),
147 surface_width: width,
148 surface_height: height,
149 full_damage: false,
150 }
151 }
152
153 fn clear(&mut self) {
154 self.rects.clear();
155 self.full_damage = false;
156 }
157
158 fn has_damage(&self) -> bool {
159 self.full_damage || !self.rects.is_empty()
160 }
161
162 fn mark_full(&mut self) {
164 self.rects.clear();
165 self.rects.push(DamageRect::new(
166 0,
167 0,
168 self.surface_width,
169 self.surface_height,
170 ));
171 self.full_damage = true;
172 }
173
174 fn add(&mut self, rect: DamageRect) {
175 if self.full_damage {
176 return; }
178 if rect.is_empty() {
179 return;
180 }
181 self.rects.push(rect);
182 if self.rects.len() > MAX_DAMAGE_RECTS {
183 self.mark_full();
184 }
185 }
186}
187
188pub(crate) struct DamageTracker {
194 surfaces: Vec<SurfaceDamage>,
195 screen_damage: Vec<DamageRect>,
198}
199
200impl DamageTracker {
201 pub(crate) fn new() -> Self {
203 Self {
204 surfaces: Vec::new(),
205 screen_damage: Vec::new(),
206 }
207 }
208
209 pub(crate) fn register_surface(&mut self, surface_id: u64, width: u32, height: u32) {
213 if self.find(surface_id).is_none() && self.surfaces.len() < MAX_SURFACES {
214 self.surfaces
215 .push(SurfaceDamage::new(surface_id, width, height));
216 }
217 }
218
219 pub(crate) fn unregister_surface(&mut self, surface_id: u64) {
221 self.surfaces.retain(|s| s.surface_id != surface_id);
222 }
223
224 pub(crate) fn resize_surface(&mut self, surface_id: u64, width: u32, height: u32) {
226 if let Some(s) = self.find_mut(surface_id) {
227 s.surface_width = width;
228 s.surface_height = height;
229 s.mark_full();
231 }
232 }
233
234 pub(crate) fn add_damage(&mut self, surface_id: u64, rect: DamageRect) {
238 if let Some(s) = self.find_mut(surface_id) {
239 s.add(rect);
240 }
241 }
242
243 pub(crate) fn add_full_damage(&mut self, surface_id: u64) {
245 if let Some(s) = self.find_mut(surface_id) {
246 s.mark_full();
247 }
248 }
249
250 pub(crate) fn get_damage(&self, surface_id: u64) -> &[DamageRect] {
254 match self.find(surface_id) {
255 Some(s) => &s.rects,
256 None => &[],
257 }
258 }
259
260 pub(crate) fn has_damage(&self, surface_id: u64) -> bool {
262 self.find(surface_id).is_some_and(|s| s.has_damage())
263 }
264
265 pub(crate) fn has_any_damage(&self) -> bool {
267 self.surfaces.iter().any(|s| s.has_damage())
268 }
269
270 pub(crate) fn merge_damage(rects: &[DamageRect]) -> Vec<DamageRect> {
277 if rects.is_empty() {
278 return Vec::new();
279 }
280 let mut merged: Vec<DamageRect> = rects.to_vec();
281
282 loop {
283 let mut changed = false;
284 let mut i = 0;
285 while i < merged.len() {
286 let mut j = i + 1;
287 while j < merged.len() {
288 if merged[i].touches(&merged[j]) {
289 let union = merged[i].union(&merged[j]);
293 let sum_area = merged[i].area().saturating_add(merged[j].area());
294 let union_area = union.area();
295 if union_area <= sum_area.saturating_mul(2) {
296 merged[i] = union;
297 merged.swap_remove(j);
298 changed = true;
299 continue; }
301 }
302 j += 1;
303 }
304 i += 1;
305 }
306 if !changed {
307 break;
308 }
309 }
310
311 merged
312 }
313
314 pub(crate) fn get_merged_damage(&self, surface_id: u64) -> Vec<DamageRect> {
316 let rects = self.get_damage(surface_id);
317 Self::merge_damage(rects)
318 }
319
320 pub(crate) fn compute_screen_damage(
325 &mut self,
326 surface_positions: &[(u64, i32, i32)], ) -> Vec<DamageRect> {
328 let mut all_rects: Vec<DamageRect> = Vec::new();
329
330 for &(sid, sx, sy) in surface_positions {
331 if let Some(s) = self.find(sid) {
332 for r in &s.rects {
333 all_rects.push(DamageRect::new(
334 r.x.saturating_add(sx),
335 r.y.saturating_add(sy),
336 r.width,
337 r.height,
338 ));
339 }
340 }
341 }
342
343 Self::merge_damage(&all_rects)
344 }
345
346 pub(crate) fn clear_damage(&mut self, surface_id: u64) {
350 if let Some(s) = self.find_mut(surface_id) {
351 s.clear();
352 }
353 }
354
355 pub(crate) fn clear_all(&mut self) {
357 for s in &mut self.surfaces {
358 s.clear();
359 }
360 self.screen_damage.clear();
361 }
362
363 fn find(&self, surface_id: u64) -> Option<&SurfaceDamage> {
366 self.surfaces.iter().find(|s| s.surface_id == surface_id)
367 }
368
369 fn find_mut(&mut self, surface_id: u64) -> Option<&mut SurfaceDamage> {
370 self.surfaces
371 .iter_mut()
372 .find(|s| s.surface_id == surface_id)
373 }
374}
375
376static DAMAGE_TRACKER: Mutex<Option<DamageTracker>> = Mutex::new(None);
381
382pub(crate) fn init() {
384 let mut guard = DAMAGE_TRACKER.lock();
385 if guard.is_none() {
386 *guard = Some(DamageTracker::new());
387 }
388}
389
390pub(crate) fn with_tracker<R, F: FnOnce(&mut DamageTracker) -> R>(f: F) -> Option<R> {
392 DAMAGE_TRACKER.lock().as_mut().map(f)
393}
394
395#[cfg(test)]
400mod tests {
401 use super::*;
402
403 #[test]
404 fn test_damage_rect_new() {
405 let r = DamageRect::new(10, 20, 100, 200);
406 assert_eq!(r.x, 10);
407 assert_eq!(r.y, 20);
408 assert_eq!(r.width, 100);
409 assert_eq!(r.height, 200);
410 }
411
412 #[test]
413 fn test_damage_rect_edges() {
414 let r = DamageRect::new(10, 20, 100, 50);
415 assert_eq!(r.right(), 110);
416 assert_eq!(r.bottom(), 70);
417 }
418
419 #[test]
420 fn test_damage_rect_area() {
421 let r = DamageRect::new(0, 0, 100, 200);
422 assert_eq!(r.area(), 20_000);
423 }
424
425 #[test]
426 fn test_damage_rect_empty() {
427 assert!(DamageRect::new(0, 0, 0, 100).is_empty());
428 assert!(DamageRect::new(0, 0, 100, 0).is_empty());
429 assert!(!DamageRect::new(0, 0, 1, 1).is_empty());
430 }
431
432 #[test]
433 fn test_damage_rect_overlap() {
434 let a = DamageRect::new(0, 0, 100, 100);
435 let b = DamageRect::new(50, 50, 100, 100);
436 assert!(a.overlaps(&b));
437 assert!(b.overlaps(&a));
438
439 let c = DamageRect::new(200, 200, 10, 10);
440 assert!(!a.overlaps(&c));
441 }
442
443 #[test]
444 fn test_damage_rect_touches() {
445 let a = DamageRect::new(0, 0, 100, 100);
447 let b = DamageRect::new(100, 0, 100, 100);
448 assert!(a.touches(&b));
449 assert!(!a.overlaps(&b)); let c = DamageRect::new(101, 0, 100, 100);
453 assert!(!a.touches(&c));
454 }
455
456 #[test]
457 fn test_damage_rect_union() {
458 let a = DamageRect::new(10, 20, 100, 50);
459 let b = DamageRect::new(50, 30, 200, 80);
460 let u = a.union(&b);
461 assert_eq!(u.x, 10);
462 assert_eq!(u.y, 20);
463 assert_eq!(u.right(), 250);
464 assert_eq!(u.bottom(), 110);
465 assert_eq!(u.width, 240);
466 assert_eq!(u.height, 90);
467 }
468
469 #[test]
470 fn test_damage_rect_intersect() {
471 let a = DamageRect::new(0, 0, 100, 100);
472 let b = DamageRect::new(50, 50, 100, 100);
473 let i = a.intersect(&b);
474 assert_eq!(i.x, 50);
475 assert_eq!(i.y, 50);
476 assert_eq!(i.width, 50);
477 assert_eq!(i.height, 50);
478
479 let c = DamageRect::new(200, 200, 10, 10);
481 let empty = a.intersect(&c);
482 assert!(empty.is_empty());
483 }
484
485 #[test]
486 fn test_damage_rect_clamp() {
487 let r = DamageRect::new(-10, -10, 50, 50);
488 let bounds = DamageRect::new(0, 0, 1920, 1080);
489 let clamped = r.clamp_to(&bounds);
490 assert_eq!(clamped.x, 0);
491 assert_eq!(clamped.y, 0);
492 assert_eq!(clamped.width, 40);
493 assert_eq!(clamped.height, 40);
494 }
495
496 #[test]
497 fn test_tracker_register_and_damage() {
498 let mut tracker = DamageTracker::new();
499 tracker.register_surface(1, 800, 600);
500 assert!(!tracker.has_damage(1));
501
502 tracker.add_damage(1, DamageRect::new(0, 0, 100, 100));
503 assert!(tracker.has_damage(1));
504 assert_eq!(tracker.get_damage(1).len(), 1);
505 }
506
507 #[test]
508 fn test_tracker_clear_damage() {
509 let mut tracker = DamageTracker::new();
510 tracker.register_surface(1, 800, 600);
511 tracker.add_damage(1, DamageRect::new(0, 0, 50, 50));
512 tracker.clear_damage(1);
513 assert!(!tracker.has_damage(1));
514 assert_eq!(tracker.get_damage(1).len(), 0);
515 }
516
517 #[test]
518 fn test_tracker_full_damage_fallback() {
519 let mut tracker = DamageTracker::new();
520 tracker.register_surface(1, 800, 600);
521 for i in 0..MAX_DAMAGE_RECTS + 5 {
523 tracker.add_damage(1, DamageRect::new(i as i32 * 10, 0, 5, 5));
524 }
525 assert!(tracker.has_damage(1));
527 let rects = tracker.get_damage(1);
528 assert_eq!(rects.len(), 1);
529 assert_eq!(rects[0].width, 800);
530 assert_eq!(rects[0].height, 600);
531 }
532
533 #[test]
534 fn test_tracker_unregister() {
535 let mut tracker = DamageTracker::new();
536 tracker.register_surface(42, 640, 480);
537 tracker.add_damage(42, DamageRect::new(0, 0, 10, 10));
538 tracker.unregister_surface(42);
539 assert!(!tracker.has_damage(42));
540 assert_eq!(tracker.get_damage(42).len(), 0);
541 }
542
543 #[test]
544 fn test_tracker_resize_marks_full() {
545 let mut tracker = DamageTracker::new();
546 tracker.register_surface(1, 800, 600);
547 tracker.resize_surface(1, 1920, 1080);
548 assert!(tracker.has_damage(1));
549 let rects = tracker.get_damage(1);
550 assert_eq!(rects.len(), 1);
551 assert_eq!(rects[0].width, 1920);
552 assert_eq!(rects[0].height, 1080);
553 }
554
555 #[test]
556 fn test_merge_overlapping() {
557 let rects = vec![
558 DamageRect::new(0, 0, 100, 100),
559 DamageRect::new(50, 50, 100, 100),
560 ];
561 let merged = DamageTracker::merge_damage(&rects);
562 assert_eq!(merged.len(), 1);
563 assert_eq!(merged[0].x, 0);
564 assert_eq!(merged[0].y, 0);
565 assert_eq!(merged[0].width, 150);
566 assert_eq!(merged[0].height, 150);
567 }
568
569 #[test]
570 fn test_merge_non_overlapping() {
571 let rects = vec![
572 DamageRect::new(0, 0, 10, 10),
573 DamageRect::new(500, 500, 10, 10),
574 ];
575 let merged = DamageTracker::merge_damage(&rects);
576 assert_eq!(merged.len(), 2);
578 }
579
580 #[test]
581 fn test_merge_empty() {
582 let merged = DamageTracker::merge_damage(&[]);
583 assert!(merged.is_empty());
584 }
585
586 #[test]
587 fn test_merge_adjacent() {
588 let rects = vec![
589 DamageRect::new(0, 0, 100, 100),
590 DamageRect::new(100, 0, 100, 100),
591 ];
592 let merged = DamageTracker::merge_damage(&rects);
593 assert_eq!(merged.len(), 1);
594 assert_eq!(merged[0].width, 200);
595 }
596
597 #[test]
598 fn test_has_any_damage() {
599 let mut tracker = DamageTracker::new();
600 tracker.register_surface(1, 100, 100);
601 tracker.register_surface(2, 100, 100);
602 assert!(!tracker.has_any_damage());
603
604 tracker.add_damage(2, DamageRect::new(0, 0, 10, 10));
605 assert!(tracker.has_any_damage());
606 }
607
608 #[test]
609 fn test_clear_all() {
610 let mut tracker = DamageTracker::new();
611 tracker.register_surface(1, 100, 100);
612 tracker.register_surface(2, 100, 100);
613 tracker.add_damage(1, DamageRect::new(0, 0, 10, 10));
614 tracker.add_damage(2, DamageRect::new(0, 0, 10, 10));
615 tracker.clear_all();
616 assert!(!tracker.has_any_damage());
617 }
618
619 #[test]
620 fn test_empty_rect_not_added() {
621 let mut tracker = DamageTracker::new();
622 tracker.register_surface(1, 800, 600);
623 tracker.add_damage(1, DamageRect::new(0, 0, 0, 0));
624 assert!(!tracker.has_damage(1));
625 }
626
627 #[test]
628 fn test_compute_screen_damage() {
629 let mut tracker = DamageTracker::new();
630 tracker.register_surface(1, 200, 200);
631 tracker.register_surface(2, 200, 200);
632
633 tracker.add_damage(1, DamageRect::new(0, 0, 50, 50));
634 tracker.add_damage(2, DamageRect::new(10, 10, 30, 30));
635
636 let positions = vec![(1, 100, 100), (2, 300, 300)];
637 let screen = tracker.compute_screen_damage(&positions);
638 assert_eq!(screen.len(), 2);
640 }
641
642 #[test]
643 fn test_damage_to_unregistered_surface() {
644 let mut tracker = DamageTracker::new();
645 tracker.add_damage(999, DamageRect::new(0, 0, 10, 10));
647 assert!(!tracker.has_damage(999));
648 }
649}