strat9_kernel/hardware/video/
graphics_adapter.rs1use alloc::{boxed::Box, sync::Arc, vec::Vec};
25use core::fmt;
26use spin::RwLock;
27
28#[derive(Debug, Clone, Copy, Default)]
30pub struct Damage {
31 pub x: u32,
32 pub y: u32,
33 pub width: u32,
34 pub height: u32,
35}
36
37impl Damage {
38 pub fn full(width: u32, height: u32) -> Self {
40 Self {
41 x: 0,
42 y: 0,
43 width,
44 height,
45 }
46 }
47
48 pub fn is_valid(&self) -> bool {
50 self.width > 0 && self.height > 0
51 }
52
53 pub fn clip(&self, max_w: u32, max_h: u32) -> Self {
55 let x = self.x.min(max_w);
56 let y = self.y.min(max_h);
57 let w = self.width.min(max_w.saturating_sub(x));
58 let h = self.height.min(max_h.saturating_sub(y));
59 Self {
60 x,
61 y,
62 width: w,
63 height: h,
64 }
65 }
66}
67
68pub trait DisplayScreen: Send + Sync {
70 fn width(&self) -> u32;
72 fn height(&self) -> u32;
74 fn stride(&self) -> u32;
76 fn bpp(&self) -> u8;
78 fn pixels(&self) -> *const u8;
80 fn pixels_mut(&mut self) -> *mut u8;
82}
83
84pub trait GraphicsAdapter: Send + Sync {
86 type Screen: DisplayScreen;
88
89 fn display_count(&self) -> usize;
91
92 fn display_size(&self, display_id: usize) -> (u32, u32);
94
95 fn create_framebuffer(&self, width: u32, height: u32) -> Self::Screen;
97
98 fn update_plane(&self, display_id: usize, screen: &Self::Screen, damage: Damage);
102
103 fn supports_hw_cursor(&self) -> bool {
105 false
106 }
107}
108
109#[derive(Clone)]
115pub struct HeapScreen {
116 width: u32,
117 height: u32,
118 stride: u32,
119 bpp: u8,
120 data: Box<[u8]>,
121}
122
123impl fmt::Debug for HeapScreen {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f.debug_struct("HeapScreen")
126 .field("width", &self.width)
127 .field("height", &self.height)
128 .field("stride", &self.stride)
129 .field("bpp", &self.bpp)
130 .finish()
131 }
132}
133
134impl HeapScreen {
135 pub fn new(width: u32, height: u32, bpp: u8) -> Self {
137 let stride = width * (bpp as u32 / 8);
138 let size = (stride * height) as usize;
139 let data = alloc::vec![0u8; size].into_boxed_slice();
140 Self {
141 width,
142 height,
143 stride,
144 bpp,
145 data,
146 }
147 }
148}
149
150impl DisplayScreen for HeapScreen {
151 fn width(&self) -> u32 {
152 self.width
153 }
154 fn height(&self) -> u32 {
155 self.height
156 }
157 fn stride(&self) -> u32 {
158 self.stride
159 }
160 fn bpp(&self) -> u8 {
161 self.bpp
162 }
163 fn pixels(&self) -> *const u8 {
164 self.data.as_ptr()
165 }
166 fn pixels_mut(&mut self) -> *mut u8 {
167 self.data.as_mut_ptr()
168 }
169}
170
171pub struct SimpleDisplayAdapter {
173 fb_virt: usize,
175 fb_width: u32,
176 fb_height: u32,
177 fb_stride: u32,
178 fb_bpp: u8,
179 display_count: usize,
181}
182
183impl SimpleDisplayAdapter {
184 pub fn new(virt: usize, width: u32, height: u32, stride: u32, bpp: u8) -> Self {
186 Self {
187 fb_virt: virt,
188 fb_width: width,
189 fb_height: height,
190 fb_stride: stride,
191 fb_bpp: bpp,
192 display_count: 1,
193 }
194 }
195
196 pub fn from_framebuffer() -> Option<Self> {
198 let info = super::framebuffer::Framebuffer::info()?;
199 Some(Self::new(
200 info.base_virt,
201 info.width,
202 info.height,
203 info.stride,
204 info.format.bits_per_pixel,
205 ))
206 }
207}
208
209impl GraphicsAdapter for SimpleDisplayAdapter {
210 type Screen = HeapScreen;
211
212 fn display_count(&self) -> usize {
213 self.display_count
214 }
215
216 fn display_size(&self, display_id: usize) -> (u32, u32) {
217 if display_id < self.display_count {
218 (self.fb_width, self.fb_height)
219 } else {
220 (0, 0)
221 }
222 }
223
224 fn create_framebuffer(&self, width: u32, height: u32) -> HeapScreen {
225 HeapScreen::new(width, height, self.fb_bpp)
226 }
227
228 fn update_plane(&self, display_id: usize, screen: &HeapScreen, damage: Damage) {
229 if display_id >= self.display_count {
230 return;
231 }
232 if self.fb_virt == 0 {
233 return;
234 }
235
236 let damage = damage.clip(screen.width(), screen.height());
237 if !damage.is_valid() {
238 return;
239 }
240
241 let bpp = self.fb_bpp as usize;
242 let dst_stride = self.fb_stride as usize;
243 let src_stride = screen.stride() as usize;
244 let dst = self.fb_virt as *mut u8;
245 let src = screen.pixels();
246
247 if bpp == 32 {
248 let bytes_per_row = damage.width as usize * 4;
249 for row in 0..damage.height as usize {
250 let src_off = (damage.y as usize + row) * src_stride + damage.x as usize * 4;
251 let dst_off = (damage.y as usize + row) * dst_stride + damage.x as usize * 4;
252 unsafe {
253 core::ptr::copy_nonoverlapping(
254 src.add(src_off),
255 dst.add(dst_off),
256 bytes_per_row,
257 );
258 }
259 }
260 } else if bpp == 24 {
261 let bytes_per_row = damage.width as usize * 3;
262 for row in 0..damage.height as usize {
263 let src_off = (damage.y as usize + row) * src_stride + damage.x as usize * 3;
264 let dst_off = (damage.y as usize + row) * dst_stride + damage.x as usize * 3;
265 unsafe {
266 core::ptr::copy_nonoverlapping(
267 src.add(src_off),
268 dst.add(dst_off),
269 bytes_per_row,
270 );
271 }
272 }
273 }
274 }
275}
276
277static ADAPTERS: RwLock<Vec<Arc<dyn GraphicsAdapter<Screen = HeapScreen>>>> =
283 RwLock::new(Vec::new());
284
285pub fn total_display_count() -> usize {
287 ADAPTERS.read().iter().map(|a| a.display_count()).sum()
288}
289
290pub fn register_adapter(adapter: Arc<dyn GraphicsAdapter<Screen = HeapScreen>>) {
292 ADAPTERS.write().push(adapter);
293}
294
295pub fn get_adapter_for_display(
297 global_id: usize,
298) -> Option<(Arc<dyn GraphicsAdapter<Screen = HeapScreen>>, usize)> {
299 let adapters = ADAPTERS.read();
300 let mut remaining = global_id;
301 for adapter in adapters.iter() {
302 let count = adapter.display_count();
303 if remaining < count {
304 return Some((adapter.clone(), remaining));
305 }
306 remaining -= count;
307 }
308 None
309}