cvkg_render_gpu/types/
budget.rs1#[derive(Clone, Debug)]
5pub struct OffscreenBudget {
6 pub max_targets: usize,
8 pub max_total_pixels: u64,
10 pub current_pixels: u64,
12 pub current_targets: usize,
14}
15
16impl Default for OffscreenBudget {
17 fn default() -> Self {
18 Self {
19 max_targets: 8,
20 max_total_pixels: 1920u64 * 1080 * 4,
22 current_pixels: 0,
23 current_targets: 0,
24 }
25 }
26}
27
28impl OffscreenBudget {
29 pub fn mobile() -> Self {
31 Self {
32 max_targets: 4,
33 max_total_pixels: 1280u64 * 720 * 2,
35 current_pixels: 0,
36 current_targets: 0,
37 }
38 }
39
40 pub fn can_allocate(&self, width: u32, height: u32) -> bool {
42 let pixels = width as u64 * height as u64;
43 self.current_targets < self.max_targets
44 && self.current_pixels + pixels <= self.max_total_pixels
45 }
46
47 pub fn register(&mut self, width: u32, height: u32) {
49 self.current_pixels += width as u64 * height as u64;
50 self.current_targets += 1;
51 }
52
53 pub fn release(&mut self, width: u32, height: u32) {
55 self.current_pixels = self.current_pixels.saturating_sub(width as u64 * height as u64);
56 self.current_targets = self.current_targets.saturating_sub(1);
57 }
58
59 pub fn reset(&mut self) {
61 self.current_pixels = 0;
62 self.current_targets = 0;
63 }
64
65 pub fn is_exhausted(&self) -> bool {
67 self.current_targets >= self.max_targets
68 }
69}
70
71#[cfg(test)]
72mod p1_27_offscreen_budget_tests {
73 use super::OffscreenBudget;
74
75 #[test]
76 fn default_budget_allows_allocation() {
77 let budget = OffscreenBudget::default();
78 assert!(budget.can_allocate(1920, 1080));
79 }
80
81 #[test]
82 fn mobile_budget_has_lower_limits() {
83 let budget = OffscreenBudget::mobile();
84 assert!(budget.can_allocate(1280, 720));
85 assert!(!budget.can_allocate(3840, 2160)); }
87
88 #[test]
89 fn budget_tracks_registration() {
90 let mut budget = OffscreenBudget::default();
91 budget.register(1920, 1080);
92 assert_eq!(budget.current_targets, 1);
93 assert_eq!(budget.current_pixels, 1920u64 * 1080);
94 }
95
96 #[test]
97 fn budget_enforces_max_targets() {
98 let mut budget = OffscreenBudget {
99 max_targets: 2,
100 max_total_pixels: u64::MAX,
101 current_pixels: 0,
102 current_targets: 0,
103 };
104 budget.register(100, 100);
105 budget.register(100, 100);
106 assert!(!budget.can_allocate(100, 100)); assert!(budget.is_exhausted());
108 }
109
110 #[test]
111 fn budget_enforces_pixel_limit() {
112 let mut budget = OffscreenBudget {
113 max_targets: 100,
114 max_total_pixels: 1000,
115 current_pixels: 0,
116 current_targets: 0,
117 };
118 assert!(budget.can_allocate(10, 10)); budget.register(10, 10);
120 assert!(!budget.can_allocate(100, 10)); }
122
123 #[test]
124 fn release_frees_budget() {
125 let mut budget = OffscreenBudget::default();
126 budget.register(1920, 1080);
127 budget.release(1920, 1080);
128 assert_eq!(budget.current_targets, 0);
129 assert_eq!(budget.current_pixels, 0);
130 }
131
132 #[test]
133 fn reset_clears_all() {
134 let mut budget = OffscreenBudget::default();
135 budget.register(1920, 1080);
136 budget.register(1280, 720);
137 budget.reset();
138 assert_eq!(budget.current_targets, 0);
139 assert_eq!(budget.current_pixels, 0);
140 }
141}