mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
* chore: update toolchain version to 2024-11-05 * update dragon reach to e945c217b3 * update dog to 6f2c0c8f12 --------- Co-authored-by: longjin <longjin@DragonOS.org>
451 lines
15 KiB
Rust
451 lines
15 KiB
Rust
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(());
|
||
}
|