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