1 use std::{fs::File, io::{Seek, SeekFrom, Write}, sync::{Arc, RwLock}}; 2 3 use starry_client::base::renderer::Renderer; 4 5 use crate::base::rect::Rect; 6 7 use super::{starry_server, window_manager::window_manager, SCREEN_WIDTH}; 8 9 static mut COMPOSITOR: Option<Arc<Compositor>> = None; 10 11 /// 获得合成渲染器实例 12 pub fn compositor() -> Option<Arc<Compositor>> { 13 unsafe { COMPOSITOR.clone() } 14 } 15 16 #[allow(dead_code)] 17 /// 合成渲染器 18 pub struct Compositor { 19 /// 数据锁 20 data: RwLock<CompositorData>, 21 } 22 23 pub struct CompositorData { 24 /// 待重绘的窗口 25 redraws: Vec<Rect>, 26 27 fb_file: File, 28 } 29 30 #[allow(dead_code)] 31 impl Compositor { 32 /// 创建合成渲染器 33 pub fn new() { 34 let compositor = Compositor { 35 data: RwLock::new(CompositorData { 36 redraws: Vec::new(), 37 fb_file: File::open("/dev/fb0").expect("[Error] Unable to open framebuffer"), 38 }), 39 }; 40 41 unsafe { 42 COMPOSITOR = Some(Arc::new(compositor)); 43 } 44 45 // println!("[Init] Compositor created successfully!"); 46 } 47 48 /// TODO 49 /// 重绘所有请求的窗口 50 pub fn redraw_all(&self) { 51 // println!("[Info] Compositor begin redraw_all..."); 52 let window_manager = window_manager().unwrap(); 53 let server = starry_server().unwrap(); 54 let cursor_rect = window_manager.cursor_rect(); 55 56 // 对窗口排序 57 window_manager.rezbuffer(); 58 59 let mut window_manager_guard = window_manager.data.write().unwrap(); 60 let mut compositor_guard = self.data.write().unwrap(); 61 let mut server_guard = server.data.write().unwrap(); 62 63 let mut total_redraw_rect_opt: Option<Rect> = None; 64 for original_rect in compositor_guard.redraws.drain(..) { 65 66 // 更新重绘的总矩形区域 67 if !original_rect.is_empty() { 68 total_redraw_rect_opt = match total_redraw_rect_opt { 69 Some(total_redraw) => Some(total_redraw.container(&original_rect)), 70 None => Some(original_rect), 71 } 72 } 73 74 let mut cursors = server_guard.cursors.clone(); 75 // 遍历所有显示窗口 76 for display in server_guard.displays.iter_mut() { 77 let rect = original_rect.intersection(&display.screen_rect()); 78 if !rect.is_empty() { 79 // TODO: 填充默认颜色 80 81 // 倒序渲染所有窗口 82 let len = window_manager_guard.zbuffer.len(); 83 for index in (0..len).rev() { 84 let entry = window_manager_guard.zbuffer.get(index).unwrap(); 85 let _id = entry.0; 86 let index = entry.2; 87 if let Some(window) = window_manager_guard.windows.get_mut(&index) { 88 // TODO: 渲染窗口标题 89 90 // 渲染窗体 91 window.draw(display, &rect); 92 } 93 } 94 } 95 96 let cursor_intersect = rect.intersection(&cursor_rect); 97 if !cursor_intersect.is_empty() { 98 if let Some(cursor) = 99 cursors.get_mut(&window_manager_guard.cursor_i) 100 { 101 display.roi(&cursor_intersect).blend(&cursor.roi( 102 &cursor_intersect.offset(-cursor_rect.left(), -cursor_rect.top()), 103 )); 104 } 105 } 106 } 107 } 108 109 // println!("[Info] Compositor calculate total redraw rect done!"); 110 111 // TODO 112 let mut fb = &compositor_guard.fb_file; 113 114 if let Some(total_redraw_rect) = total_redraw_rect_opt { 115 for display in server_guard.displays.iter_mut() { 116 let display_redraw = total_redraw_rect.intersection(&display.screen_rect()); 117 if !display_redraw.is_empty() { 118 for y in 0..display_redraw.height() { 119 for x in 0..display_redraw.width() { 120 let pixel = display.image.get_pixel(x + display_redraw.left() - display.x, y + display_redraw.top() - display.y); 121 let offset = (((y + display_redraw.top()) * SCREEN_WIDTH as i32) + x + display_redraw.left()) * 4; 122 fb.seek(SeekFrom::Start(offset as u64)).expect("Unable to seek framebuffer"); 123 fb.write_all(&pixel.to_bgra_bytes()).expect("Unable to write framebuffer"); 124 } 125 } 126 } 127 } 128 } 129 } 130 131 /// 窗口请求重绘 132 pub fn request_redraw(&self, rect: Rect) { 133 // println!("[Info] Compositor request redraw rect {:?}", rect); 134 let mut guard = self.data.write().unwrap(); 135 let mut push = true; 136 137 for rect in guard.redraws.iter_mut() { 138 let container = rect.container(&rect); 139 if container.area() <= rect.area() + rect.area() { 140 *rect = container; 141 push = false; 142 } 143 } 144 145 if push { 146 guard.redraws.push(rect); 147 } 148 } 149 } 150