xref: /DragonOS/kernel/src/libs/lib_ui/screen_manager.rs (revision f09a98329c4ec77010de86d126516310b407455a)
1 use core::{
2     fmt::Debug,
3     intrinsics::unlikely,
4     sync::atomic::{AtomicBool, AtomicU32, Ordering},
5 };
6 
7 use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
8 
9 use crate::{
10     driver::uart::uart::{c_uart_send_str, UartPort},
11     include::bindings::bindings::{
12         scm_buffer_info_t, video_frame_buffer_info, video_reinitialize, video_set_refresh_target,
13     },
14     libs::{rwlock::RwLock, spinlock::SpinLock},
15     mm::VirtAddr,
16     syscall::SystemError,
17 };
18 
19 use lazy_static::lazy_static;
20 
21 use super::textui_no_alloc::textui_init_no_alloc;
22 
23 lazy_static! {
24     /// 全局的UI框架列表
25     pub static ref SCM_FRAMEWORK_LIST: SpinLock<LinkedList<Arc<dyn ScmUiFramework>>> =
26         SpinLock::new(LinkedList::new());
27     /// 当前在使用的UI框架
28     pub static ref CURRENT_FRAMEWORK: RwLock<Option<Arc<dyn ScmUiFramework>>> = RwLock::new(None);
29 
30 }
31 
32 /// 是否启用双缓冲
33 pub static SCM_DOUBLE_BUFFER_ENABLED: AtomicBool = AtomicBool::new(false);
34 
35 bitflags! {
36   pub struct ScmBufferFlag:u8 {
37     // 帧缓冲区标志位
38        const SCM_BF_FB = 1 << 0; // 当前buffer是设备显存中的帧缓冲区
39        const SCM_BF_DB = 1 << 1; // 当前buffer是双缓冲
40        const SCM_BF_TEXT = 1 << 2; // 使用文本模式
41        const SCM_BF_PIXEL = 1 << 3; // 使用图像模式
42    }
43 }
44 #[derive(Clone, Debug)]
45 #[allow(dead_code)]
46 pub enum ScmFramworkType {
47     Text,
48     Gui,
49     Unused,
50 }
51 #[derive(Debug)]
52 pub enum ScmBuffer {
53     DeviceBuffer(Option<VirtAddr>),
54     DoubleBuffer(Option<Box<[u32]>>),
55 }
56 #[derive(Debug)]
57 pub struct ScmBufferInfo {
58     width: u32,     // 帧缓冲区宽度(pixel或columns)
59     height: u32,    // 帧缓冲区高度(pixel或lines)
60     size: u32,      // 帧缓冲区大小(bytes)
61     bit_depth: u32, // 像素点位深度
62     pub buf: ScmBuffer,
63     flags: ScmBufferFlag, // 帧缓冲区标志位
64 }
65 impl Clone for ScmBufferInfo {
66     fn clone(&self) -> Self {
67         match self.buf {
68             ScmBuffer::DeviceBuffer(_) => ScmBufferInfo {
69                 width: self.width,
70                 height: self.height,
71                 size: self.size,
72                 bit_depth: self.bit_depth,
73                 flags: self.flags,
74                 buf: ScmBuffer::DeviceBuffer(Option::None),
75             },
76             ScmBuffer::DoubleBuffer(_) => ScmBufferInfo {
77                 width: self.width,
78                 height: self.height,
79                 size: self.size,
80                 bit_depth: self.bit_depth,
81                 flags: self.flags,
82                 buf: ScmBuffer::DoubleBuffer(Option::None),
83             },
84         }
85     }
86 }
87 
88 impl ScmBufferInfo {
89     /// 创建新的帧缓冲区信息
90     ///
91     /// ## 参数
92     ///
93     /// - `buf_type` 帧缓冲区类型
94     ///
95     /// ## 返回值
96     ///
97     /// - `Result<Self, SystemError>` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码
98     pub fn new(buf_type: ScmBufferFlag) -> Result<Self, SystemError> {
99         if unlikely(SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == false) {
100             let buf_info = ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
101 
102             return Ok(buf_info);
103         } else {
104             // 创建双缓冲区
105             let mut frame_buffer_info: ScmBufferInfo =
106                 ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
107 
108             frame_buffer_info.flags = buf_type;
109             // 这里还是改成使用box来存储数组,如果直接用vec存储,在multiboot2_iter那里会报错,不知为何
110             frame_buffer_info.buf = ScmBuffer::DoubleBuffer(Some(
111                 Box::new(vec![
112                     0;
113                     unsafe { (video_frame_buffer_info.size / 4) as usize }
114                 ])
115                 .into_boxed_slice(),
116             ));
117 
118             return Ok(frame_buffer_info);
119         }
120     }
121 
122     // 重构了video后可以删除
123     fn vaddr(&mut self) -> VirtAddr {
124         match &self.buf {
125             ScmBuffer::DeviceBuffer(vaddr) => {
126                 if !vaddr.is_none() {
127                     vaddr.unwrap()
128                 } else {
129                     return VirtAddr::new(0);
130                 }
131             }
132             ScmBuffer::DoubleBuffer(buf) => {
133                 if !buf.is_none() {
134                     let address = self.buf().as_ptr();
135                     VirtAddr::new(address as usize)
136                 } else {
137                     return VirtAddr::new(0);
138                 }
139             }
140         }
141     }
142 
143     fn buf(&mut self) -> &mut [u32] {
144         let len = self.buf_size() / 4;
145         match &mut self.buf {
146             ScmBuffer::DoubleBuffer(buf) => match buf.as_mut() {
147                 Some(buf) => buf,
148                 None => panic!("Buffer is none"),
149             },
150             ScmBuffer::DeviceBuffer(vaddr) => match vaddr.as_mut() {
151                 Some(vaddr) => {
152                     let buf: &mut [u32] = unsafe {
153                         core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len as usize)
154                     };
155                     return buf;
156                 }
157                 None => panic!("Buffer is none"),
158             },
159         }
160     }
161     pub fn buf_size(&self) -> u32 {
162         self.size
163     }
164     pub fn buf_height(&self) -> u32 {
165         self.height
166     }
167     pub fn buf_width(&self) -> u32 {
168         self.width
169     }
170     pub fn is_double_buffer(&self) -> bool {
171         match &self.buf {
172             ScmBuffer::DoubleBuffer(_) => true,
173             _ => false,
174         }
175     }
176     pub fn is_device_buffer(&self) -> bool {
177         match &self.buf {
178             ScmBuffer::DeviceBuffer(_) => true,
179             _ => false,
180         }
181     }
182 }
183 
184 // 重构了video后可以删除
185 impl From<&scm_buffer_info_t> for ScmBufferInfo {
186     fn from(value: &scm_buffer_info_t) -> Self {
187         Self {
188             width: value.width,
189             height: value.height,
190             size: value.size,
191             bit_depth: value.bit_depth,
192             buf: ScmBuffer::DeviceBuffer(Some(VirtAddr::new(value.vaddr as usize))),
193             flags: ScmBufferFlag::from_bits_truncate(value.flags as u8),
194         }
195     }
196 }
197 impl Into<scm_buffer_info_t> for ScmBufferInfo {
198     fn into(mut self) -> scm_buffer_info_t {
199         let vaddr = self.vaddr();
200         scm_buffer_info_t {
201             width: self.width,
202             height: self.height,
203             size: self.size,
204             bit_depth: self.bit_depth,
205             vaddr: vaddr.data() as u64,
206             flags: self.flags.bits as u64,
207         }
208     }
209 }
210 #[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
211 pub struct ScmUiFrameworkId(u32);
212 
213 impl ScmUiFrameworkId {
214     /// 分配一个新的框架id
215     pub fn new() -> Self {
216         static MAX_ID: AtomicU32 = AtomicU32::new(0);
217         return ScmUiFrameworkId(MAX_ID.fetch_add(1, Ordering::SeqCst));
218     }
219 }
220 #[allow(dead_code)]
221 #[derive(Debug, Clone)]
222 pub struct ScmUiFrameworkMetadata {
223     id: ScmUiFrameworkId,
224     name: String,
225     framework_type: ScmFramworkType,
226     pub buf_info: ScmBufferInfo,
227 }
228 
229 impl ScmUiFrameworkMetadata {
230     pub fn new(name: String, framework_type: ScmFramworkType) -> Self {
231         match framework_type {
232             ScmFramworkType::Text => {
233                 let result = ScmUiFrameworkMetadata {
234                     id: ScmUiFrameworkId::new(),
235                     name,
236                     framework_type: ScmFramworkType::Text,
237                     buf_info: ScmBufferInfo::new(ScmBufferFlag::SCM_BF_TEXT).unwrap(),
238                 };
239 
240                 return result;
241             }
242             ScmFramworkType::Gui => todo!(),
243             ScmFramworkType::Unused => todo!(),
244         }
245     }
246     pub fn buf_info(&self) -> ScmBufferInfo {
247         return self.buf_info.clone();
248     }
249     pub fn set_buf_info(&mut self, buf_info: ScmBufferInfo) {
250         self.buf_info = buf_info;
251     }
252     pub fn buf_is_none(&self) -> bool {
253         match &self.buf_info.buf {
254             ScmBuffer::DeviceBuffer(vaddr) => {
255                 return vaddr.is_none();
256             }
257             ScmBuffer::DoubleBuffer(buf) => {
258                 return buf.is_none();
259             }
260         }
261     }
262     pub fn buf(&mut self) -> &mut [u32] {
263         if self.buf_is_none() {
264             panic!("buf is none");
265         }
266         self.buf_info.buf()
267     }
268 }
269 pub trait ScmUiFramework: Sync + Send + Debug {
270     // 安装ui框架的回调函数
271     fn install(&self) -> Result<i32, SystemError> {
272         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
273     }
274     // 卸载ui框架的回调函数
275     fn uninstall(&self) -> Result<i32, SystemError> {
276         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
277     }
278     // 启用ui框架的回调函数
279     fn enable(&self) -> Result<i32, SystemError> {
280         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
281     }
282     // 禁用ui框架的回调函数
283     fn disable(&self) -> Result<i32, SystemError> {
284         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
285     }
286     // 改变ui框架的帧缓冲区的回调函数
287     fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
288         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
289     }
290     /// @brief 获取ScmUiFramework的元数据
291     /// @return 成功:Ok(ScmUiFramework的元数据)
292     ///         失败:Err(错误码)
293     fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
294         // 若文件系统没有实现此方法,则返回“不支持”
295         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
296     }
297 }
298 
299 /// 初始化屏幕控制模块
300 ///
301 /// ## 调用时机
302 ///
303 /// 该函数在内核启动的早期进行调用。调用时,内存管理模块尚未初始化。
304 #[no_mangle]
305 pub extern "C" fn scm_init() {
306     SCM_DOUBLE_BUFFER_ENABLED.store(false, Ordering::SeqCst); // 禁用双缓冲
307 
308     textui_init_no_alloc();
309 
310     c_uart_send_str(UartPort::COM1.to_u16(), "\nfinish_scm_init\n\0".as_ptr());
311 }
312 
313 /// 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
314 /// ## 参数
315 ///
316 /// - framework 要启动的ui框架
317 
318 pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
319     // 获取信息
320     let metadata = framework.metadata()?;
321 
322     // if metadata.buf_info.buf.is_null() {
323     //     return Err(SystemError::EINVAL);
324     // }
325     let mut current_framework = CURRENT_FRAMEWORK.write();
326 
327     if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == true {
328         let buf: scm_buffer_info_t = metadata.buf_info.into();
329         let retval = unsafe { video_set_refresh_target(buf) };
330         if retval == 0 {
331             framework.enable()?;
332         }
333     } else {
334         framework.enable()?;
335     }
336 
337     current_framework.replace(framework);
338 
339     return Ok(0);
340 }
341 /// 向屏幕管理器注册UI框架
342 ///
343 /// ## 参数
344 /// - framework 框架结构体
345 
346 pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
347     // 把ui框架加入链表
348 
349     SCM_FRAMEWORK_LIST.lock().push_back(framework.clone());
350     // 调用ui框架的回调函数以安装ui框架,并将其激活
351     framework.install()?;
352 
353     // 如果当前还没有框架获得了屏幕的控制权,就让其拿去
354     if CURRENT_FRAMEWORK.read().is_none() {
355         return scm_framework_enable(framework);
356     }
357     return Ok(0);
358 }
359 
360 /// 允许双缓冲区
361 #[no_mangle]
362 pub extern "C" fn scm_enable_double_buffer() -> i32 {
363     let r = true_scm_enable_double_buffer().unwrap_or_else(|e| e.to_posix_errno());
364     if r.is_negative() {
365         c_uart_send_str(
366             UartPort::COM1.to_u16(),
367             "scm enable double buffer fail.\n\0".as_ptr(),
368         );
369     }
370 
371     return r;
372 }
373 fn true_scm_enable_double_buffer() -> Result<i32, SystemError> {
374     if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) {
375         // 已经开启了双缓冲区了, 直接退出
376         return Ok(0);
377     }
378     let scm_list = SCM_FRAMEWORK_LIST.lock();
379     if scm_list.is_empty() {
380         // scm 框架链表为空
381         return Ok(0);
382     }
383     drop(scm_list);
384     SCM_DOUBLE_BUFFER_ENABLED.store(true, Ordering::SeqCst);
385     // 创建双缓冲区
386     let mut buf_info = ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
387     let mut refresh_target_buf: scm_buffer_info_t = buf_info.clone().into();
388     // 重构video后进行修改
389     refresh_target_buf.vaddr = buf_info.vaddr().data() as u64;
390     CURRENT_FRAMEWORK
391         .write()
392         .as_ref()
393         .unwrap()
394         .change(buf_info)?;
395     // 设置定时刷新的对象
396     unsafe { video_set_refresh_target(refresh_target_buf) };
397     // 遍历当前所有使用帧缓冲区的框架,更新为双缓冲区
398     for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
399         if !(*framework).metadata()?.buf_info.is_double_buffer() {
400             let new_buf_info =
401                 ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
402             (*framework).change(new_buf_info)?;
403         }
404     }
405     // 通知显示驱动,启动双缓冲
406     unsafe { video_reinitialize(true) };
407 
408     return Ok(0);
409 }
410 /// 允许往窗口打印信息
411 #[no_mangle]
412 pub fn scm_enable_put_to_window() {
413     // mm之前要继续往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值
414     if CURRENT_FRAMEWORK.read().is_none() {
415         super::textui::ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
416     } else {
417         let r = CURRENT_FRAMEWORK
418             .write()
419             .as_ref()
420             .unwrap()
421             .enable()
422             .unwrap_or_else(|e| e.to_posix_errno());
423         if r.is_negative() {
424             c_uart_send_str(
425                 UartPort::COM1.to_u16(),
426                 "scm_enable_put_to_window() failed.\n\0".as_ptr(),
427             );
428         }
429     }
430 }
431 /// 禁止往窗口打印信息
432 #[no_mangle]
433 pub fn scm_disable_put_to_window() {
434     // mm之前要停止往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值
435     if CURRENT_FRAMEWORK.read().is_none() {
436         super::textui::ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
437         assert!(super::textui::ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst) == false);
438     } else {
439         let r = CURRENT_FRAMEWORK
440             .write()
441             .as_ref()
442             .unwrap()
443             .disable()
444             .unwrap_or_else(|e| e.to_posix_errno());
445         if r.is_negative() {
446             c_uart_send_str(
447                 UartPort::COM1.to_u16(),
448                 "scm_disable_put_to_window() failed.\n\0".as_ptr(),
449             );
450         }
451     }
452 }
453 /// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
454 #[no_mangle]
455 pub extern "C" fn scm_reinit() -> i32 {
456     let r = true_scm_reinit().unwrap_or_else(|e| e.to_posix_errno());
457     if r.is_negative() {
458         c_uart_send_str(UartPort::COM1.to_u16(), "scm reinit failed.\n\0".as_ptr());
459     }
460     return r;
461 }
462 fn true_scm_reinit() -> Result<i32, SystemError> {
463     unsafe { video_reinitialize(false) };
464 
465     // 遍历当前所有使用帧缓冲区的框架,更新地址
466     for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
467         if framework.metadata()?.buf_info().is_device_buffer() {
468             framework.change(unsafe { ScmBufferInfo::from(&video_frame_buffer_info) })?;
469         }
470     }
471 
472     scm_enable_put_to_window();
473 
474     return Ok(0);
475 }
476