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
56 .current_pixels
57 .saturating_sub(width as u64 * height as u64);
58 self.current_targets = self.current_targets.saturating_sub(1);
59 }
60
61 pub fn reset(&mut self) {
63 self.current_pixels = 0;
64 self.current_targets = 0;
65 }
66
67 pub fn is_exhausted(&self) -> bool {
69 self.current_targets >= self.max_targets
70 }
71}
72
73#[cfg(test)]
74mod p1_27_offscreen_budget_tests {
75 use super::OffscreenBudget;
76
77 #[test]
78 fn default_budget_allows_allocation() {
79 let budget = OffscreenBudget::default();
80 assert!(budget.can_allocate(1920, 1080));
81 }
82
83 #[test]
84 fn mobile_budget_has_lower_limits() {
85 let budget = OffscreenBudget::mobile();
86 assert!(budget.can_allocate(1280, 720));
87 assert!(!budget.can_allocate(3840, 2160)); }
89
90 #[test]
91 fn budget_tracks_registration() {
92 let mut budget = OffscreenBudget::default();
93 budget.register(1920, 1080);
94 assert_eq!(budget.current_targets, 1);
95 assert_eq!(budget.current_pixels, 1920u64 * 1080);
96 }
97
98 #[test]
99 fn budget_enforces_max_targets() {
100 let mut budget = OffscreenBudget {
101 max_targets: 2,
102 max_total_pixels: u64::MAX,
103 current_pixels: 0,
104 current_targets: 0,
105 };
106 budget.register(100, 100);
107 budget.register(100, 100);
108 assert!(!budget.can_allocate(100, 100)); assert!(budget.is_exhausted());
110 }
111
112 #[test]
113 fn budget_enforces_pixel_limit() {
114 let mut budget = OffscreenBudget {
115 max_targets: 100,
116 max_total_pixels: 1000,
117 current_pixels: 0,
118 current_targets: 0,
119 };
120 assert!(budget.can_allocate(10, 10)); budget.register(10, 10);
122 assert!(!budget.can_allocate(100, 10)); }
124
125 #[test]
126 fn release_frees_budget() {
127 let mut budget = OffscreenBudget::default();
128 budget.register(1920, 1080);
129 budget.release(1920, 1080);
130 assert_eq!(budget.current_targets, 0);
131 assert_eq!(budget.current_pixels, 0);
132 }
133
134 #[test]
135 fn reset_clears_all() {
136 let mut budget = OffscreenBudget::default();
137 budget.register(1920, 1080);
138 budget.register(1280, 720);
139 budget.reset();
140 assert_eq!(budget.current_targets, 0);
141 assert_eq!(budget.current_pixels, 0);
142 }
143}