veridian_kernel/desktop/wayland/
compositor.rs1#![allow(dead_code)]
7
8use alloc::{collections::BTreeMap, vec, vec::Vec};
9
10use spin::RwLock;
11
12use super::{buffer, surface::Surface};
13use crate::{error::KernelError, graphics::PixelFormat};
14
15const DESKTOP_BG_COLOR: u32 = 0xFF2D_3436;
21
22pub struct Compositor {
30 surfaces: RwLock<BTreeMap<u32, Surface>>,
32 z_order: RwLock<Vec<u32>>,
34 back_buffer: RwLock<Vec<u32>>,
36 fb_width: core::sync::atomic::AtomicU32,
38 fb_height: core::sync::atomic::AtomicU32,
39 needs_composite: core::sync::atomic::AtomicBool,
41}
42
43impl Compositor {
44 pub fn new() -> Self {
47 Self {
48 surfaces: RwLock::new(BTreeMap::new()),
49 z_order: RwLock::new(Vec::new()),
50 back_buffer: RwLock::new(Vec::new()),
51 fb_width: core::sync::atomic::AtomicU32::new(0),
52 fb_height: core::sync::atomic::AtomicU32::new(0),
53 needs_composite: core::sync::atomic::AtomicBool::new(false),
54 }
55 }
56
57 pub fn set_output_size(&self, width: u32, height: u32) {
59 self.fb_width
60 .store(width, core::sync::atomic::Ordering::Release);
61 self.fb_height
62 .store(height, core::sync::atomic::Ordering::Release);
63 let pixel_count = (width as usize) * (height as usize);
64 *self.back_buffer.write() = vec![DESKTOP_BG_COLOR; pixel_count];
65 }
66
67 pub fn create_surface(&self, id: u32) -> Result<(), KernelError> {
69 let surface = Surface::new(id);
70 self.surfaces.write().insert(id, surface);
71 self.z_order.write().push(id);
72 Ok(())
73 }
74
75 pub fn create_surface_for_client(&self, id: u32, client_id: u32) -> Result<(), KernelError> {
77 let surface = Surface::with_client(id, client_id);
78 self.surfaces.write().insert(id, surface);
79 self.z_order.write().push(id);
80 Ok(())
81 }
82
83 pub fn destroy_surface(&self, id: u32) -> Result<(), KernelError> {
85 self.surfaces.write().remove(&id);
86 self.z_order.write().retain(|&sid| sid != id);
87 Ok(())
88 }
89
90 pub fn get_surface(&self, id: u32) -> Option<Surface> {
92 let surfaces = self.surfaces.read();
93 surfaces.get(&id).map(|s| Surface {
96 id: s.id,
97 committed: s.committed.clone(),
98 pending: s.pending.clone(),
99 position: s.position,
100 size: s.size,
101 dirty: s.dirty,
102 mapped: s.mapped,
103 client_id: s.client_id,
104 })
105 }
106
107 pub fn with_surface_mut<R, F: FnOnce(&mut Surface) -> R>(&self, id: u32, f: F) -> Option<R> {
109 let mut surfaces = self.surfaces.write();
110 surfaces.get_mut(&id).map(f)
111 }
112
113 pub fn raise_surface(&self, id: u32) {
115 let mut z = self.z_order.write();
116 z.retain(|&sid| sid != id);
117 z.push(id);
118 }
119
120 pub fn set_surface_position(&self, id: u32, x: i32, y: i32) {
122 if let Some(surface) = self.surfaces.write().get_mut(&id) {
123 surface.position = (x, y);
124 }
125 }
126
127 pub fn request_composite(&self) {
129 self.needs_composite
130 .store(true, core::sync::atomic::Ordering::Release);
131 }
132
133 pub fn composite(&self) -> Result<bool, KernelError> {
141 let fb_w_val = self.fb_width.load(core::sync::atomic::Ordering::Acquire);
142 let fb_h_val = self.fb_height.load(core::sync::atomic::Ordering::Acquire);
143 if fb_w_val == 0 || fb_h_val == 0 {
144 return Ok(false);
145 }
146
147 let z_order = self.z_order.read().clone();
148 let mut surfaces = self.surfaces.write();
149 let mut bb = self.back_buffer.write();
150
151 let fb_w = fb_w_val as usize;
152 let fb_h = fb_h_val as usize;
153
154 for pixel in bb.iter_mut() {
156 *pixel = DESKTOP_BG_COLOR;
157 }
158
159 let mut any_drawn = false;
160
161 for &sid in &z_order {
163 let surface = match surfaces.get(&sid) {
164 Some(s) => s,
165 None => continue,
166 };
167
168 if !surface.mapped || surface.size.0 == 0 || surface.size.1 == 0 {
169 continue;
170 }
171
172 let buf = match &surface.committed.buffer {
173 Some(b) => b,
174 None => continue,
175 };
176
177 let sx = surface.position.0;
180 let sy = surface.position.1;
181 let sw = buf.width as usize;
182 let sh = buf.height as usize;
183 let stride = buf.stride as usize;
184 let format = buf.format;
185 let pool_id = buf.pool_id;
186 let pool_buffer_id = buf.pool_buffer_id;
187
188 if pool_id == 0 {
189 continue;
190 }
191
192 let drew = buffer::with_pool(pool_id, |pool| {
193 let pixels = match pool.read_buffer_pixels(pool_buffer_id) {
194 Some(p) => p,
195 None => return false,
196 };
197
198 for row in 0..sh {
199 let dst_y = sy as isize + row as isize;
200 if dst_y < 0 || dst_y >= fb_h as isize {
201 continue;
202 }
203 let dst_y = dst_y as usize;
204
205 for col in 0..sw {
206 let dst_x = sx as isize + col as isize;
207 if dst_x < 0 || dst_x >= fb_w as isize {
208 continue;
209 }
210 let dst_x = dst_x as usize;
211
212 let src_off = row * stride + col * format.bpp() as usize;
213 if src_off + 3 >= pixels.len() {
214 break;
215 }
216
217 let dst_idx =
218 match dst_y.checked_mul(fb_w).and_then(|v| v.checked_add(dst_x)) {
219 Some(idx) if idx < bb.len() => idx,
220 _ => continue,
221 };
222
223 match format {
224 PixelFormat::Xrgb8888 => {
225 let b_val = pixels[src_off] as u32;
226 let g_val = pixels[src_off + 1] as u32;
227 let r_val = pixels[src_off + 2] as u32;
228 bb[dst_idx] = 0xFF00_0000 | (r_val << 16) | (g_val << 8) | b_val;
229 }
230 PixelFormat::Argb8888 => {
231 let b_src = pixels[src_off] as u32;
232 let g_src = pixels[src_off + 1] as u32;
233 let r_src = pixels[src_off + 2] as u32;
234 let a_src = pixels[src_off + 3] as u32;
235
236 if a_src == 255 {
237 bb[dst_idx] =
238 0xFF00_0000 | (r_src << 16) | (g_src << 8) | b_src;
239 } else if a_src > 0 {
240 let dst_pixel = bb[dst_idx];
241 let r_dst = (dst_pixel >> 16) & 0xFF;
242 let g_dst = (dst_pixel >> 8) & 0xFF;
243 let b_dst = dst_pixel & 0xFF;
244
245 let inv_a = 255 - a_src;
246 let r_out = (r_src * a_src + r_dst * inv_a) / 255;
247 let g_out = (g_src * a_src + g_dst * inv_a) / 255;
248 let b_out = (b_src * a_src + b_dst * inv_a) / 255;
249
250 bb[dst_idx] =
251 0xFF00_0000 | (r_out << 16) | (g_out << 8) | b_out;
252 }
253 }
254 PixelFormat::Rgb565 => {
255 if src_off + 1 < pixels.len() {
256 let raw = (pixels[src_off] as u16)
257 | ((pixels[src_off + 1] as u16) << 8);
258 let r5 = ((raw >> 11) & 0x1F) as u32;
259 let g6 = ((raw >> 5) & 0x3F) as u32;
260 let b5 = (raw & 0x1F) as u32;
261 let r8 = (r5 * 255 + 15) / 31;
262 let g8 = (g6 * 255 + 31) / 63;
263 let b8 = (b5 * 255 + 15) / 31;
264 bb[dst_idx] = 0xFF00_0000 | (r8 << 16) | (g8 << 8) | b8;
265 }
266 }
267 _ => {
269 if src_off + 2 < pixels.len() {
270 let b_val = pixels[src_off] as u32;
271 let g_val = pixels[src_off + 1] as u32;
272 let r_val = pixels[src_off + 2] as u32;
273 bb[dst_idx] =
274 0xFF00_0000 | (r_val << 16) | (g_val << 8) | b_val;
275 }
276 }
277 }
278 }
279 }
280 true
281 });
282 if drew == Some(true) {
283 any_drawn = true;
284 }
285 }
286
287 for surface in surfaces.values_mut() {
289 surface.clear_dirty();
290 }
291
292 self.needs_composite
293 .store(false, core::sync::atomic::Ordering::Release);
294
295 Ok(any_drawn)
296 }
297
298 pub fn back_buffer(&self) -> Vec<u32> {
300 self.back_buffer.read().clone()
301 }
302
303 pub fn with_back_buffer<R, F: FnOnce(&[u32]) -> R>(&self, f: F) -> R {
307 let bb = self.back_buffer.read();
308 f(&bb)
309 }
310
311 pub fn with_back_buffer_mut<R, F: FnOnce(&mut [u32]) -> R>(&self, f: F) -> R {
317 let mut bb = self.back_buffer.write();
318 f(&mut bb)
319 }
320
321 pub fn set_surface_mapped(&self, id: u32, mapped: bool) {
326 self.with_surface_mut(id, |surface| {
327 surface.mapped = mapped;
328 });
329 }
330
331 pub fn output_size(&self) -> (u32, u32) {
333 (
334 self.fb_width.load(core::sync::atomic::Ordering::Acquire),
335 self.fb_height.load(core::sync::atomic::Ordering::Acquire),
336 )
337 }
338
339 pub fn surface_count(&self) -> usize {
341 self.surfaces.read().len()
342 }
343}
344
345impl Default for Compositor {
346 fn default() -> Self {
347 Self::new()
348 }
349}
350
351pub fn render_shadow(
361 shadow_buffer: &mut [u32],
362 buf_width: u32,
363 width: u32,
364 height: u32,
365 radius: u32,
366 opacity: u8,
367) {
368 crate::desktop::animation::render_shadow(
369 shadow_buffer,
370 buf_width,
371 width,
372 height,
373 radius,
374 opacity,
375 );
376}
377
378pub fn alpha_blend(src: u32, dst: u32) -> u32 {
381 let src_a = (src >> 24) & 0xFF;
382 if src_a == 255 {
383 return src | 0xFF00_0000;
384 }
385 if src_a == 0 {
386 return dst;
387 }
388
389 let src_r = (src >> 16) & 0xFF;
390 let src_g = (src >> 8) & 0xFF;
391 let src_b = src & 0xFF;
392
393 let dst_r = (dst >> 16) & 0xFF;
394 let dst_g = (dst >> 8) & 0xFF;
395 let dst_b = dst & 0xFF;
396
397 let inv_a = 255 - src_a;
398 let r = (src_r * src_a + dst_r * inv_a) / 255;
399 let g = (src_g * src_a + dst_g * inv_a) / 255;
400 let b = (src_b * src_a + dst_b * inv_a) / 255;
401
402 0xFF00_0000 | (r << 16) | (g << 8) | b
403}
404
405pub fn apply_opacity(pixel: u32, opacity: u8) -> u32 {
409 if opacity == 255 {
410 return pixel;
411 }
412 let a = (pixel >> 24) & 0xFF;
413 let new_a = (a * opacity as u32) / 255;
414 (new_a << 24) | (pixel & 0x00FF_FFFF)
415}
416
417#[cfg(test)]
418mod tests {
419 use super::{super::buffer::Buffer, *};
420 use crate::graphics::PixelFormat;
421
422 #[test]
423 fn test_create_destroy_surface() {
424 let comp = Compositor::new();
425 comp.create_surface(1).unwrap();
426 assert_eq!(comp.surface_count(), 1);
427 comp.destroy_surface(1).unwrap();
428 assert_eq!(comp.surface_count(), 0);
429 }
430
431 #[test]
432 fn test_composite_empty() {
433 let comp = Compositor::new();
434 comp.set_output_size(64, 64);
435 let drawn = comp.composite().unwrap();
436 assert!(!drawn); let bb = comp.back_buffer();
439 assert_eq!(bb.len(), 64 * 64);
440 assert_eq!(bb[0], DESKTOP_BG_COLOR);
441 }
442
443 #[test]
444 fn test_z_order_raise() {
445 let comp = Compositor::new();
446 comp.create_surface(1).unwrap();
447 comp.create_surface(2).unwrap();
448 comp.create_surface(3).unwrap();
449
450 comp.raise_surface(1);
451 let z = comp.z_order.read().clone();
452 assert_eq!(z, vec![2, 3, 1]);
453 }
454}