DragonOS/kernel/src/libs/lib_ui/screen_manager.rs
linfeng 7c28051e8c
chore: update toolchain version to 2024-11-05 (#1031)
* chore: update toolchain version to 2024-11-05

* update dragon reach to e945c217b3

* update dog to 6f2c0c8f12

---------

Co-authored-by: longjin <longjin@DragonOS.org>
2024-11-11 21:29:15 +08:00

451 lines
15 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use core::{
fmt::Debug,
intrinsics::unlikely,
sync::atomic::{AtomicBool, AtomicU32, Ordering},
};
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
use system_error::SystemError;
use crate::{
driver::{
serial::serial8250::send_to_default_serial8250_port,
video::{has_video_refresh_manager, video_refresh_manager},
},
libs::{lib_ui::textui::textui_is_enable_put_to_window, rwlock::RwLock, spinlock::SpinLock},
mm::{mmio_buddy::MMIOSpaceGuard, VirtAddr},
};
use super::{
textui::{textui_disable_put_to_window, textui_enable_put_to_window},
textui_no_alloc::textui_init_no_alloc,
};
/// 全局的UI框架列表
pub static SCM_FRAMEWORK_LIST: SpinLock<LinkedList<Arc<dyn ScmUiFramework>>> =
SpinLock::new(LinkedList::new());
/// 当前在使用的UI框架
pub static CURRENT_FRAMEWORK: RwLock<Option<Arc<dyn ScmUiFramework>>> = RwLock::new(None);
/// 是否启用双缓冲
pub static SCM_DOUBLE_BUFFER_ENABLED: AtomicBool = AtomicBool::new(false);
bitflags! {
pub struct ScmBufferFlag:u8 {
// 帧缓冲区标志位
const SCM_BF_FB = 1 << 0; // 当前buffer是设备显存中的帧缓冲区
const SCM_BF_DB = 1 << 1; // 当前buffer是双缓冲
const SCM_BF_TEXT = 1 << 2; // 使用文本模式
const SCM_BF_PIXEL = 1 << 3; // 使用图像模式
}
}
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub enum ScmFramworkType {
Text,
Gui,
Unused,
}
#[derive(Debug, Clone)]
pub enum ScmBuffer {
DeviceBuffer(VirtAddr),
DoubleBuffer(Arc<SpinLock<Box<[u8]>>>),
}
#[derive(Debug, Clone)]
pub struct ScmBufferInfo {
width: u32, // 帧缓冲区宽度pixel或columns
height: u32, // 帧缓冲区高度pixel或lines
size: u32, // 帧缓冲区大小bytes
bit_depth: u32, // 像素点位深度
device_buffer_mmio_guard: Option<Arc<MMIOSpaceGuard>>,
pub buf: ScmBuffer,
flags: ScmBufferFlag, // 帧缓冲区标志位
}
#[allow(dead_code)]
impl ScmBufferInfo {
/// 创建新的帧缓冲区信息
///
/// ## 参数
///
/// - `buf_type` 帧缓冲区类型
///
/// ## 返回值
///
/// - `Result<Self, SystemError>` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码
pub fn new(mut buf_type: ScmBufferFlag) -> Result<Self, SystemError> {
if unlikely(!SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst)) {
let mut device_buffer = video_refresh_manager().device_buffer().clone();
buf_type.remove(ScmBufferFlag::SCM_BF_DB);
buf_type.insert(ScmBufferFlag::SCM_BF_FB);
device_buffer.flags = buf_type;
return Ok(device_buffer);
} else {
let device_buffer_guard = video_refresh_manager().device_buffer();
let buf_space: Arc<SpinLock<Box<[u8]>>> = Arc::new(SpinLock::new(
vec![0u8; (device_buffer_guard.size / 4) as usize].into_boxed_slice(),
));
assert!(buf_type.contains(ScmBufferFlag::SCM_BF_DB));
assert_eq!(
device_buffer_guard.size as usize,
buf_space.lock().len() * core::mem::size_of::<u8>()
);
// 创建双缓冲区
let buffer = Self {
width: device_buffer_guard.width,
height: device_buffer_guard.height,
size: device_buffer_guard.size,
bit_depth: device_buffer_guard.bit_depth,
flags: buf_type,
buf: ScmBuffer::DoubleBuffer(buf_space),
device_buffer_mmio_guard: None,
};
drop(device_buffer_guard);
return Ok(buffer);
}
}
pub unsafe fn set_device_buffer_mmio_guard(&mut self, guard: Arc<MMIOSpaceGuard>) {
self.device_buffer_mmio_guard = Some(guard);
}
pub unsafe fn new_device_buffer(
width: u32,
height: u32,
size: u32,
bit_depth: u32,
buf_type: ScmBufferFlag,
vaddr: VirtAddr,
mut device_buffer_mmio_guard: Option<MMIOSpaceGuard>,
) -> Result<Self, SystemError> {
let mmio_guard = device_buffer_mmio_guard.take().map(Arc::new);
let buffer = Self {
width,
height,
size,
bit_depth,
flags: buf_type,
buf: ScmBuffer::DeviceBuffer(vaddr),
device_buffer_mmio_guard: mmio_guard,
};
return Ok(buffer);
}
pub fn buf_size(&self) -> usize {
self.size as usize
}
pub fn bit_depth(&self) -> u32 {
self.bit_depth
}
pub fn height(&self) -> u32 {
self.height
}
pub fn width(&self) -> u32 {
self.width
}
pub fn is_double_buffer(&self) -> bool {
matches!(&self.buf, ScmBuffer::DoubleBuffer(_))
}
pub fn is_device_buffer(&self) -> bool {
matches!(&self.buf, ScmBuffer::DeviceBuffer(_))
}
pub fn copy_from_nonoverlapping(&mut self, src: &ScmBufferInfo) {
assert!(self.buf_size() == src.buf_size());
match &self.buf {
ScmBuffer::DeviceBuffer(vaddr) => {
let len = self.buf_size() / core::mem::size_of::<u32>();
let self_buf_guard =
unsafe { core::slice::from_raw_parts_mut(vaddr.data() as *mut u8, len) };
match &src.buf {
ScmBuffer::DeviceBuffer(vaddr) => {
let src_buf_guard =
unsafe { core::slice::from_raw_parts(vaddr.data() as *const u8, len) };
self_buf_guard.copy_from_slice(src_buf_guard);
}
ScmBuffer::DoubleBuffer(double_buffer) => {
let src_buf_guard = double_buffer.lock();
self_buf_guard.copy_from_slice(src_buf_guard.as_ref());
}
};
}
ScmBuffer::DoubleBuffer(double_buffer) => {
let mut double_buffer_guard = double_buffer.lock();
match &src.buf {
ScmBuffer::DeviceBuffer(vaddr) => {
let len = src.buf_size() / core::mem::size_of::<u8>();
double_buffer_guard.as_mut().copy_from_slice(unsafe {
core::slice::from_raw_parts(vaddr.data() as *const u8, len)
});
}
ScmBuffer::DoubleBuffer(double_buffer) => {
let x = double_buffer.lock();
double_buffer_guard.as_mut().copy_from_slice(x.as_ref());
}
};
}
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct ScmUiFrameworkId(u32);
impl ScmUiFrameworkId {
/// 分配一个新的框架id
pub fn new() -> Self {
static MAX_ID: AtomicU32 = AtomicU32::new(0);
return ScmUiFrameworkId(MAX_ID.fetch_add(1, Ordering::SeqCst));
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ScmUiFrameworkMetadata {
id: ScmUiFrameworkId,
name: String,
framework_type: ScmFramworkType,
pub buf_info: ScmBufferInfo,
}
impl ScmUiFrameworkMetadata {
pub fn new(name: String, framework_type: ScmFramworkType) -> Self {
match framework_type {
ScmFramworkType::Text => {
let result = ScmUiFrameworkMetadata {
id: ScmUiFrameworkId::new(),
name,
framework_type: ScmFramworkType::Text,
buf_info: ScmBufferInfo::new(
ScmBufferFlag::SCM_BF_TEXT | ScmBufferFlag::SCM_BF_DB,
)
.unwrap(),
};
return result;
}
ScmFramworkType::Gui => todo!(),
ScmFramworkType::Unused => todo!(),
}
}
pub fn buf_info(&self) -> ScmBufferInfo {
return self.buf_info.clone();
}
pub fn set_buf_info(&mut self, buf_info: ScmBufferInfo) {
self.buf_info = buf_info;
}
}
pub trait ScmUiFramework: Sync + Send + Debug {
// 安装ui框架的回调函数
fn install(&self) -> Result<i32, SystemError> {
return Err(SystemError::ENOSYS);
}
// 卸载ui框架的回调函数
#[allow(dead_code)]
fn uninstall(&self) -> Result<i32, SystemError> {
return Err(SystemError::ENOSYS);
}
// 启用ui框架的回调函数
fn enable(&self) -> Result<i32, SystemError> {
return Err(SystemError::ENOSYS);
}
// 禁用ui框架的回调函数
fn disable(&self) -> Result<i32, SystemError> {
return Err(SystemError::ENOSYS);
}
// 改变ui框架的帧缓冲区的回调函数
fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
return Err(SystemError::ENOSYS);
}
/// @brief 获取ScmUiFramework的元数据
/// @return 成功Ok(ScmUiFramework的元数据)
/// 失败Err(错误码)
fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
// 若文件系统没有实现此方法,则返回“不支持”
return Err(SystemError::ENOSYS);
}
}
/// 初始化屏幕控制模块
///
/// ## 调用时机
///
/// 该函数在内核启动的早期进行调用。调用时,内存管理模块尚未初始化。
pub fn scm_init(enable_put_to_window: bool) {
SCM_DOUBLE_BUFFER_ENABLED.store(false, Ordering::SeqCst); // 禁用双缓冲
if enable_put_to_window {
textui_enable_put_to_window();
} else {
textui_disable_put_to_window();
}
textui_init_no_alloc(enable_put_to_window);
send_to_default_serial8250_port("\nfinish_scm_init\n\0".as_bytes());
}
/// 启用某个ui框架将它的帧缓冲区渲染到屏幕上
/// ## 参数
///
/// - framework 要启动的ui框架
pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
// 获取信息
let metadata = framework.metadata()?;
// if metadata.buf_info.buf.is_null() {
// return Err(SystemError::EINVAL);
// }
let mut current_framework = CURRENT_FRAMEWORK.write();
if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) {
video_refresh_manager().set_refresh_target(&metadata.buf_info)?;
}
framework.enable()?;
current_framework.replace(framework);
return Ok(0);
}
/// 向屏幕管理器注册UI框架
///
/// ## 参数
/// - framework 框架结构体
pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
// 把ui框架加入链表
SCM_FRAMEWORK_LIST.lock().push_back(framework.clone());
// 调用ui框架的回调函数以安装ui框架并将其激活
framework.install()?;
// 如果当前还没有框架获得了屏幕的控制权,就让其拿去
if CURRENT_FRAMEWORK.read().is_none() {
return scm_framework_enable(framework);
}
return Ok(0);
}
/// 屏幕管理器启用双缓冲区
#[allow(dead_code)]
pub fn scm_enable_double_buffer() -> Result<i32, SystemError> {
if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) {
// 已经开启了双缓冲区了, 直接退出
return Ok(0);
}
let scm_list = SCM_FRAMEWORK_LIST.lock();
if scm_list.is_empty() {
// scm 框架链表为空
return Ok(0);
}
drop(scm_list);
SCM_DOUBLE_BUFFER_ENABLED.store(true, Ordering::SeqCst);
// 创建双缓冲区
let buf_info = ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
// 设置定时刷新的对象
video_refresh_manager()
.set_refresh_target(&buf_info)
.expect("set refresh target failed");
// 设置当前框架的帧缓冲区
CURRENT_FRAMEWORK
.write()
.as_ref()
.unwrap()
.change(buf_info)?;
// 遍历当前所有使用帧缓冲区的框架,更新为双缓冲区
for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
if !(*framework).metadata()?.buf_info.is_double_buffer() {
let new_buf_info =
ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
(*framework).change(new_buf_info)?;
}
}
// 通知显示驱动,启动双缓冲
video_refresh_manager().video_reinitialize(true)?;
return Ok(0);
}
/// 允许往窗口打印信息
pub fn scm_enable_put_to_window() {
// mm之前要继续往窗口打印信息时因为没有动态内存分配(textui并没有往scm注册)且使用的是textui,要直接修改textui里面的值
if CURRENT_FRAMEWORK.read().is_none() {
textui_enable_put_to_window();
} else {
let r = CURRENT_FRAMEWORK
.write()
.as_ref()
.unwrap()
.enable()
.unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
send_to_default_serial8250_port("scm_enable_put_to_window() failed.\n\0".as_bytes());
}
}
}
/// 禁止往窗口打印信息
pub fn scm_disable_put_to_window() {
// mm之前要停止往窗口打印信息时因为没有动态内存分配(rwlock与otion依然能用但是textui并没有往scm注册)且使用的是textui,要直接修改textui里面的值
if CURRENT_FRAMEWORK.read().is_none() {
textui_disable_put_to_window();
assert!(!textui_is_enable_put_to_window());
} else {
let r = CURRENT_FRAMEWORK
.write()
.as_ref()
.unwrap()
.disable()
.unwrap_or_else(|e| e.to_posix_errno());
if r.is_negative() {
send_to_default_serial8250_port("scm_disable_put_to_window() failed.\n\0".as_bytes());
}
}
}
/// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
#[inline(never)]
pub fn scm_reinit() -> Result<(), SystemError> {
#[cfg(target_arch = "x86_64")]
{
let r = true_scm_reinit();
if r.is_err() {
send_to_default_serial8250_port("scm reinit failed.\n\0".as_bytes());
}
return r;
}
#[cfg(not(target_arch = "x86_64"))]
{
return Ok(());
}
}
#[allow(dead_code)]
fn true_scm_reinit() -> Result<(), SystemError> {
if !has_video_refresh_manager() {
return Err(SystemError::ENODEV);
}
video_refresh_manager().video_reinitialize(false)?;
// 遍历当前所有使用帧缓冲区的框架,更新地址
let device_buffer = video_refresh_manager().device_buffer().clone();
for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
if framework.metadata()?.buf_info().is_device_buffer() {
framework.change(device_buffer.clone())?;
}
}
scm_enable_put_to_window();
return Ok(());
}