veridian_kernel/graphics/
framebuffer.rs1use core::sync::atomic::{AtomicU64, Ordering};
9
10use spin::Mutex;
11
12use super::{Color, GraphicsContext, Rect};
13use crate::error::KernelError;
14
15#[repr(C)]
19#[derive(Debug, Clone, Copy)]
20pub struct FbInfo {
21 pub width: u32,
22 pub height: u32,
23 pub pitch: u32,
24 pub bpp: u32,
25 pub phys_addr: u64,
26 pub size: u64,
27 pub format: u32,
29 pub _reserved: u32,
30}
31
32pub struct Framebuffer {
34 width: u32,
35 height: u32,
36 pitch: u32,
37 bpp: u8,
38 buffer: Option<*mut u32>,
39 phys_addr: u64,
41 size: u64,
43 format: u32,
45}
46
47unsafe impl Send for Framebuffer {}
52unsafe impl Sync for Framebuffer {}
53
54impl Framebuffer {
55 pub const fn new() -> Self {
56 Self {
57 width: 0,
58 height: 0,
59 pitch: 0,
60 bpp: 32,
61 buffer: None,
62 phys_addr: 0,
63 size: 0,
64 format: 0,
65 }
66 }
67
68 pub fn configure(&mut self, width: u32, height: u32, buffer: *mut u32) {
69 self.width = width;
70 self.height = height;
71 self.pitch = width * 4;
72 self.buffer = Some(buffer);
73 self.size = (self.pitch as u64) * (height as u64);
74 }
75
76 pub fn configure_with_phys(
78 &mut self,
79 width: u32,
80 height: u32,
81 pitch: u32,
82 bpp: u8,
83 buffer: *mut u32,
84 phys_addr: u64,
85 format: u32,
86 ) {
87 self.width = width;
88 self.height = height;
89 self.pitch = pitch;
90 self.bpp = bpp;
91 self.buffer = Some(buffer);
92 self.phys_addr = phys_addr;
93 self.size = (pitch as u64) * (height as u64);
94 self.format = format;
95 }
96
97 pub fn width(&self) -> u32 {
98 self.width
99 }
100
101 pub fn height(&self) -> u32 {
102 self.height
103 }
104
105 pub fn pitch(&self) -> u32 {
106 self.pitch
107 }
108
109 pub fn phys_addr(&self) -> u64 {
110 self.phys_addr
111 }
112
113 pub fn size(&self) -> u64 {
114 self.size
115 }
116
117 pub fn get_info(&self) -> FbInfo {
119 FbInfo {
120 width: self.width,
121 height: self.height,
122 pitch: self.pitch,
123 bpp: self.bpp as u32,
124 phys_addr: self.phys_addr,
125 size: self.size,
126 format: self.format,
127 _reserved: 0,
128 }
129 }
130
131 pub fn buffer_ptr(&self) -> Option<*mut u32> {
133 self.buffer
134 }
135}
136
137impl Default for Framebuffer {
138 fn default() -> Self {
139 Self::new()
140 }
141}
142
143impl GraphicsContext for Framebuffer {
144 fn draw_pixel(&mut self, x: i32, y: i32, color: Color) {
145 if x < 0 || y < 0 || x >= self.width as i32 || y >= self.height as i32 {
146 return;
147 }
148
149 if let Some(buffer) = self.buffer {
150 unsafe {
155 let offset = (y as u32 * self.width + x as u32) as isize;
156 *buffer.offset(offset) = color.to_u32();
157 }
158 }
159 }
160
161 fn draw_rect(&mut self, rect: Rect, color: Color) {
162 for x in rect.x..(rect.x + rect.width as i32) {
164 self.draw_pixel(x, rect.y, color);
165 self.draw_pixel(x, rect.y + rect.height as i32 - 1, color);
166 }
167 for y in rect.y..(rect.y + rect.height as i32) {
169 self.draw_pixel(rect.x, y, color);
170 self.draw_pixel(rect.x + rect.width as i32 - 1, y, color);
171 }
172 }
173
174 fn fill_rect(&mut self, rect: Rect, color: Color) {
175 for y in rect.y..(rect.y + rect.height as i32) {
176 for x in rect.x..(rect.x + rect.width as i32) {
177 self.draw_pixel(x, y, color);
178 }
179 }
180 }
181
182 fn clear(&mut self, color: Color) {
183 self.fill_rect(
184 Rect {
185 x: 0,
186 y: 0,
187 width: self.width,
188 height: self.height,
189 },
190 color,
191 );
192 }
193}
194
195static FRAMEBUFFER: Mutex<Framebuffer> = Mutex::new(Framebuffer::new());
196
197pub fn with_framebuffer<R, F: FnOnce(&mut Framebuffer) -> R>(f: F) -> R {
199 f(&mut FRAMEBUFFER.lock())
200}
201
202static FB_PHYS_ADDR: AtomicU64 = AtomicU64::new(0);
205
206pub fn set_phys_addr(phys: u64) {
208 FB_PHYS_ADDR.store(phys, Ordering::Release);
209 FRAMEBUFFER.lock().phys_addr = phys;
210}
211
212pub fn get_phys_addr() -> u64 {
214 FB_PHYS_ADDR.load(Ordering::Acquire)
215}
216
217pub fn get_fb_info() -> Option<FbInfo> {
219 let fb = FRAMEBUFFER.lock();
220 if fb.width == 0 || fb.height == 0 {
221 return None;
222 }
223 Some(fb.get_info())
224}
225
226#[cfg_attr(target_arch = "aarch64", allow(unused_variables))]
228pub fn init() -> Result<(), KernelError> {
229 println!("[FB] Initializing framebuffer...");
230
231 let fb = FRAMEBUFFER.lock();
232
233 println!(
234 "[FB] Framebuffer initialized ({}x{}, phys=0x{:x})",
235 fb.width(),
236 fb.height(),
237 fb.phys_addr(),
238 );
239 Ok(())
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn test_framebuffer_create() {
248 let fb = Framebuffer::new();
249 assert_eq!(fb.width(), 0);
250 assert_eq!(fb.height(), 0);
251 }
252}