DragonOS/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs
LoGin b5b571e026
修复内核的clippy检查报错 (#637)
修复内核的clippy检查报错
---------

Co-authored-by: Samuel Dai <947309196@qq.com>
Co-authored-by: Donkey Kane <109840258+xiaolin2004@users.noreply.github.com>
Co-authored-by: themildwind <107623059+themildwind@users.noreply.github.com>
Co-authored-by: GnoCiYeH <heyicong@dragonos.org>
Co-authored-by: MemoryShore <105195940+MemoryShore@users.noreply.github.com>
Co-authored-by: 曾俊 <110876916+ZZJJWarth@users.noreply.github.com>
Co-authored-by: sun5etop <146408999+sun5etop@users.noreply.github.com>
Co-authored-by: hmt <114841534+1037827920@users.noreply.github.com>
Co-authored-by: laokengwt <143977175+laokengwt@users.noreply.github.com>
Co-authored-by: TTaq <103996388+TTaq@users.noreply.github.com>
Co-authored-by: Jomo <2512364506@qq.com>
Co-authored-by: Samuel Dai <samuka007@qq.com>
Co-authored-by: sspphh <112558065+sspphh@users.noreply.github.com>
2024-03-22 23:26:39 +08:00

813 lines
26 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 alloc::{sync::Arc, vec::Vec};
use system_error::SystemError;
use crate::{
driver::{
tty::{
console::ConsoleSwitch,
virtual_terminal::{
virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
Color,
},
},
video::fbdev::base::{
CopyAreaData, FbCursor, FbCursorSetMode, FbImage, FbVisual, FillRectData, FillRectROP,
FrameBuffer, ScrollMode, FRAME_BUFFER_SET,
},
},
libs::{
font::FontDesc,
spinlock::{SpinLock, SpinLockGuard},
},
};
use super::{FbConAttr, FrameBufferConsole, FrameBufferConsoleData};
#[derive(Debug)]
pub struct BlittingFbConsole {
fb: SpinLock<Option<Arc<dyn FrameBuffer>>>,
fbcon_data: SpinLock<FrameBufferConsoleData>,
}
unsafe impl Send for BlittingFbConsole {}
unsafe impl Sync for BlittingFbConsole {}
impl BlittingFbConsole {
pub fn new() -> Result<Self, SystemError> {
Ok(Self {
fb: SpinLock::new(None),
fbcon_data: SpinLock::new(FrameBufferConsoleData::default()),
})
}
pub fn fb(&self) -> Arc<dyn FrameBuffer> {
self.fb.lock().clone().unwrap()
}
pub fn get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u32 {
let fb_info = self.fb();
let mut color = 0;
let depth = fb_info.color_depth();
if depth != 1 {
if is_fg {
let fg_shift = if vc_data.hi_font_mask != 0 { 9 } else { 8 };
color = (c as u32 >> fg_shift) & 0x0f
} else {
let bg_shift = if vc_data.hi_font_mask != 0 { 13 } else { 12 };
color = (c as u32 >> bg_shift) & 0x0f
}
}
match depth {
1 => {
let col = self.mono_color();
let fg;
let bg;
if fb_info.current_fb_fix().visual != FbVisual::Mono01 {
fg = col;
bg = 0;
} else {
fg = 0;
bg = col;
}
color = if is_fg { fg } else { bg };
}
2 => {
/*
颜色深度为2即16色
将16色的颜色值映射到4色的灰度
其中颜色0映射为黑色颜色1到6映射为白色
颜色7到8映射为灰色其他颜色映射为强烈的白色。
*/
if (1..=6).contains(&color) {
// 白色
color = 2;
} else if (7..=8).contains(&color) {
// 灰色
color = 1;
} else {
// 强白
color = 3;
}
}
3 => {
/*
颜色深度为3即256色仅保留颜色的低3位即颜色 0 到 7
*/
color &= 7;
}
_ => {}
}
color
}
/// ## 计算单色调的函数
pub fn mono_color(&self) -> u32 {
let fb_info = self.fb();
let mut max_len = fb_info
.current_fb_var()
.green
.length
.max(fb_info.current_fb_var().red.length);
max_len = max_len.max(fb_info.current_fb_var().blue.length);
return (!(0xfff << max_len)) & 0xff;
}
pub fn bit_put_string(
&self,
vc_data: &VirtualConsoleData,
buf: &[u16],
attr: FbConAttr,
cnt: u32,
cellsize: u32,
image: &mut FbImage,
) {
let charmask = if vc_data.hi_font_mask != 0 {
0x1ff
} else {
0xff
};
let mut offset;
let image_line_byte = image.width as usize / 8;
let byte_width = vc_data.font.width as usize / 8;
let font_height = vc_data.font.height as usize;
// let mut char_offset = 0;
for (char_offset, char_item) in buf.iter().enumerate().take(cnt as usize) {
// 在字符表中的index
let ch = char_item & charmask;
// 计算出在font表中的偏移量
let font_offset = ch as usize * cellsize as usize;
let font_offset_end = font_offset + cellsize as usize;
// 设置image的data
let src = &vc_data.font.data[font_offset..font_offset_end];
let mut dst = vec![0; src.len()];
dst.copy_from_slice(src);
if !attr.is_empty() {
attr.update_attr(&mut dst, src, vc_data)
}
offset = char_offset * byte_width;
let mut dst_offset = 0;
for _ in 0..font_height {
let dst_offset_next = dst_offset + byte_width;
image.data[offset..offset + byte_width]
.copy_from_slice(&dst[dst_offset..dst_offset_next]);
offset += image_line_byte;
dst_offset = dst_offset_next;
}
}
self.fb().fb_image_blit(image);
}
}
impl ConsoleSwitch for BlittingFbConsole {
fn con_init(
&self,
vc_data: &mut VirtualConsoleData,
init: bool,
) -> Result<(), system_error::SystemError> {
let fb_set_guard = FRAME_BUFFER_SET.read();
let fb = fb_set_guard.get(vc_data.index);
if fb.is_none() {
return Err(SystemError::EINVAL);
}
let fb = fb.unwrap();
if fb.is_none() {
panic!(
"The Framebuffer with FbID {} has not been initialized yet.",
vc_data.index
)
}
let fb = fb.as_ref().unwrap().clone();
if init {
// 初始化字体
let var = fb.current_fb_var();
let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0);
vc_data.font.data = font.data.to_vec();
vc_data.font.width = font.width;
vc_data.font.height = font.height;
vc_data.font.count = font.char_count;
} else {
kwarn!("The frontend Framebuffer is not implemented");
}
vc_data.color_mode = fb.color_depth() != 1;
vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
if vc_data.font.count == 256 {
// ascii
vc_data.hi_font_mask = 0;
} else {
vc_data.hi_font_mask = 0x100;
if vc_data.color_mode {
vc_data.complement_mask <<= 1;
}
}
// TODO: 考虑rotate
if init {
vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize;
vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize;
vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols;
let new_size = vc_data.cols * vc_data.rows;
vc_data.screen_buf.resize(new_size, 0);
} else {
unimplemented!("Resize is not supported at the moment!");
}
// 初始化fb
*self.fb.lock() = Some(fb);
Ok(())
}
fn con_deinit(&self) -> Result<(), system_error::SystemError> {
todo!()
}
fn con_clear(
&self,
vc_data: &mut VirtualConsoleData,
sy: usize,
sx: usize,
height: usize,
width: usize,
) -> Result<(), system_error::SystemError> {
let fb_data = self.fbcon_data();
if height == 0 || width == 0 {
return Ok(());
}
let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize;
if sy < y_break && sy + height > y_break {
// 分两次clear
let b = y_break - sy;
let _ = self.clear(
vc_data,
fb_data.display.real_y(sy as u32),
sx as u32,
b as u32,
width as u32,
);
let _ = self.clear(
vc_data,
fb_data.display.real_y((sy + b) as u32),
sx as u32,
(height - b) as u32,
width as u32,
);
} else {
let _ = self.clear(
vc_data,
fb_data.display.real_y(sy as u32),
sx as u32,
height as u32,
width as u32,
);
}
Ok(())
}
fn con_putc(
&self,
vc_data: &VirtualConsoleData,
ch: u16,
xpos: u32,
ypos: u32,
) -> Result<(), system_error::SystemError> {
self.con_putcs(vc_data, &[ch], 1, ypos, xpos)
}
fn con_putcs(
&self,
vc_data: &VirtualConsoleData,
buf: &[u16],
count: usize,
ypos: u32,
xpos: u32,
) -> Result<(), SystemError> {
if count == 0 {
return Ok(());
}
let fbcon_data = self.fbcon_data();
let c = buf[0];
self.put_string(
vc_data,
buf,
count as u32,
fbcon_data.display.real_y(ypos),
xpos,
self.get_color(vc_data, c, true),
self.get_color(vc_data, c, false),
)
}
fn con_getxy(
&self,
vc_data: &VirtualConsoleData,
pos: usize,
) -> Result<(usize, usize, usize), SystemError> {
if pos < vc_data.screen_buf.len() {
let x = pos % vc_data.cols;
let y = pos / vc_data.cols;
let mut next_line_start = pos + (vc_data.cols - x);
if next_line_start >= vc_data.screen_buf.len() {
next_line_start = 0
}
return Ok((next_line_start, x, y));
} else {
return Ok((0, 0, 0));
}
}
#[allow(clippy::if_same_then_else)]
fn con_cursor(
&self,
vc_data: &VirtualConsoleData,
op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation,
) {
let mut fbcon_data = self.fbcon_data();
let c = vc_data.screen_buf[vc_data.pos];
if vc_data.cursor_type.contains(VcCursor::CUR_SW) {
// 取消硬光标Timer但是现在没有硬光标先写在这
} else {
// 添加硬光标Timer
}
fbcon_data.cursor_flash = op != CursorOperation::Erase;
drop(fbcon_data);
self.cursor(
vc_data,
op,
self.get_color(vc_data, c, true),
self.get_color(vc_data, c, false),
);
}
fn con_set_palette(
&self,
vc_data: &VirtualConsoleData,
color_table: &[u8],
) -> Result<(), SystemError> {
let fb_info = self.fb();
let depth = fb_info.color_depth();
let mut palette = Vec::new();
palette.resize(16, Color::default());
if depth > 3 {
let vc_palette = &vc_data.palette;
for i in 0..16 {
let idx = color_table[i];
let col = palette.get_mut(idx as usize).unwrap();
col.red = (vc_palette[i].red << 8) | vc_palette[i].red;
col.green = (vc_palette[i].green << 8) | vc_palette[i].green;
col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue;
}
} else {
todo!()
}
self.fb().set_color_map(palette)?;
Ok(())
}
#[inline(never)]
fn con_scroll(
&self,
vc_data: &mut VirtualConsoleData,
top: usize,
bottom: usize,
dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir,
mut count: usize,
) -> bool {
self.con_cursor(vc_data, CursorOperation::Erase);
let fbcon_data = self.fbcon_data();
let scroll_mode = fbcon_data.display.scroll_mode;
drop(fbcon_data);
match dir {
ScrollDir::Up => {
if count > vc_data.rows {
count = vc_data.rows;
}
match scroll_mode {
ScrollMode::Move => {
let start = top * vc_data.cols;
let end = bottom * vc_data.cols;
vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
let _ = self.bmove(
vc_data,
top as i32,
0,
top as i32 - count as i32,
0,
(bottom - top) as u32,
vc_data.cols as u32,
);
let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
let offset = vc_data.cols * (bottom - count);
for i in
vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
{
*i = vc_data.erase_char;
}
return true;
}
ScrollMode::PanMove => todo!(),
ScrollMode::WrapMove => todo!(),
ScrollMode::Redraw => {
let start = top * vc_data.cols;
let end = bottom * vc_data.cols;
vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols];
for line in top..(bottom - count) {
let mut start = line * vc_data.cols;
let end = start + vc_data.cols;
let mut offset = start;
let mut attr = 1;
let mut x = 0;
while offset < end {
let c = data[offset];
if attr != c & 0xff00 {
// 属性变化,输出完上一个的并且更新属性
attr = c & 0xff00;
let count = offset - start;
let _ = self.con_putcs(
vc_data,
&data[start..offset],
count,
line as u32,
x,
);
start = offset;
x += count as u32;
}
offset += 1;
}
let _ = self.con_putcs(
vc_data,
&data[start..offset],
offset - start,
line as u32,
x,
);
}
let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
let offset = vc_data.cols * (bottom - count);
for i in
vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
{
*i = vc_data.erase_char;
}
return true;
}
ScrollMode::PanRedraw => todo!(),
}
}
ScrollDir::Down => {
if count > vc_data.rows {
count = vc_data.rows;
}
match scroll_mode {
ScrollMode::Move => {
let start = top * vc_data.cols;
let end = bottom * vc_data.cols;
vc_data.screen_buf[start..end].rotate_right(count * vc_data.cols);
let _ = self.bmove(
vc_data,
top as i32,
0,
top as i32 + count as i32,
0,
(bottom - top - count) as u32,
vc_data.cols as u32,
);
let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
let offset = vc_data.cols * count;
for i in vc_data.screen_buf[start..(start + offset)].iter_mut() {
*i = vc_data.erase_char;
}
return true;
}
ScrollMode::PanMove => todo!(),
ScrollMode::WrapMove => todo!(),
ScrollMode::Redraw => {
// self.scroll_redraw(
// vc_data,
// bottom - 1,
// bottom - top - count,
// count * vc_data.cols,
// false,
// );
let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
let offset = vc_data.cols * top;
for i in
vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
{
*i = vc_data.erase_char;
}
return true;
}
ScrollMode::PanRedraw => todo!(),
}
}
}
}
}
impl FrameBufferConsole for BlittingFbConsole {
fn bmove(
&self,
vc_data: &VirtualConsoleData,
sy: i32,
sx: i32,
dy: i32,
dx: i32,
height: u32,
width: u32,
) -> Result<(), SystemError> {
let area = CopyAreaData::new(
dx * vc_data.font.width as i32,
dy * vc_data.font.height as i32,
width * vc_data.font.width,
height * vc_data.font.height,
sx * vc_data.font.width as i32,
sy * vc_data.font.height as i32,
);
self.fb().fb_copyarea(area);
Ok(())
}
fn clear(
&self,
vc_data: &VirtualConsoleData,
sy: u32,
sx: u32,
height: u32,
width: u32,
) -> Result<(), SystemError> {
let region = FillRectData::new(
sx * vc_data.font.width,
sy * vc_data.font.height,
width * vc_data.font.width,
height * vc_data.font.height,
self.get_color(vc_data, vc_data.erase_char, false),
FillRectROP::Copy,
);
self.fb().fb_fillrect(region)?;
Ok(())
}
fn put_string(
&self,
vc_data: &VirtualConsoleData,
data: &[u16],
mut count: u32,
y: u32,
x: u32,
fg: u32,
bg: u32,
) -> Result<(), SystemError> {
// 向上取整
let width = (vc_data.font.width + 7) / 8;
let cellsize = width * vc_data.font.height;
let fb_info = self.fb();
// 一次能输出的最大字数,避免帧缓冲区溢出
let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize;
let attr = FbConAttr::get_attr(data[0], fb_info.color_depth());
let mut image = FbImage {
x: x * vc_data.font.width,
y: y * vc_data.font.height,
width: 0,
height: vc_data.font.height,
fg,
bg,
depth: 1,
data: Default::default(),
};
image.data.resize(cellsize as usize * count as usize, 0);
while count > 0 {
let cnt = count.min(max_cnt);
image.width = vc_data.font.width * cnt;
self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image);
image.x += cnt * vc_data.font.width;
count -= cnt;
}
Ok(())
}
fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> {
self.fbcon_data.lock()
}
fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) {
let mut fbcon_data = self.fbcon_data();
let fb_info = self.fb();
let mut cursor = FbCursor::default();
let charmask = if vc_data.hi_font_mask != 0 {
0x1ff
} else {
0xff
};
// 向上取整
let w = (vc_data.font.width + 7) / 8;
let y = fbcon_data.display.real_y(vc_data.state.y as u32);
let c = vc_data.screen_buf[vc_data.pos];
let attr = FbConAttr::get_attr(c, fb_info.color_depth());
let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize);
if fbcon_data.cursor_state.image.data != vc_data.font.data[char_offset..]
|| fbcon_data.cursor_reset
{
fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec();
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE);
}
if !attr.is_empty() {
fbcon_data
.cursor_data
.resize(w as usize * vc_data.font.height as usize, 0);
attr.update_attr(
&mut fbcon_data.cursor_data,
&vc_data.font.data[char_offset..],
vc_data,
);
}
if fbcon_data.cursor_state.image.fg != fg
|| fbcon_data.cursor_state.image.bg != bg
|| fbcon_data.cursor_reset
{
fbcon_data.cursor_state.image.fg = fg;
fbcon_data.cursor_state.image.bg = bg;
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP);
}
if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32)
|| fbcon_data.cursor_state.image.y != (vc_data.font.height * y)
|| fbcon_data.cursor_reset
{
fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32;
fbcon_data.cursor_state.image.y = vc_data.font.height * y;
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS);
}
if fbcon_data.cursor_state.image.height != vc_data.font.height
|| fbcon_data.cursor_state.image.width != vc_data.font.width
|| fbcon_data.cursor_reset
{
fbcon_data.cursor_state.image.height = vc_data.font.height;
fbcon_data.cursor_state.image.width = vc_data.font.width;
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE);
}
if fbcon_data.cursor_state.hot_x > 0
|| fbcon_data.cursor_state.hot_y > 0
|| fbcon_data.cursor_reset
{
fbcon_data.cursor_state.hot_x = 0;
cursor.hot_y = 0;
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT);
}
if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE)
|| vc_data.cursor_type != fbcon_data.display.cursor_shape
|| fbcon_data.cursor_state.mask.is_empty()
|| fbcon_data.cursor_reset
{
fbcon_data.display.cursor_shape = vc_data.cursor_type;
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE);
let cur_height;
match fbcon_data.display.cursor_shape.cursor_size() {
VcCursor::CUR_NONE => {
cur_height = 0;
}
VcCursor::CUR_UNDERLINE => {
if vc_data.font.height < 10 {
cur_height = 1;
} else {
cur_height = 2;
}
}
VcCursor::CUR_LOWER_THIRD => {
cur_height = vc_data.font.height / 3;
}
VcCursor::CUR_LOWER_HALF => {
cur_height = vc_data.font.height >> 1;
}
VcCursor::CUR_TWO_THIRDS => {
cur_height = (vc_data.font.height << 1) / 3;
}
_ => {
cur_height = vc_data.font.height;
}
}
// 表示空白部分
let mut size = (vc_data.font.height - cur_height) * w;
while size > 0 {
size -= 1;
fbcon_data.cursor_state.mask.push(0x00);
}
size = cur_height * w;
// 表示光标显示部分
while size > 0 {
size -= 1;
fbcon_data.cursor_state.mask.push(0xff);
}
}
match op {
CursorOperation::Erase => {
fbcon_data.cursor_state.enable = false;
}
_ => {
fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW);
}
}
if !attr.is_empty() {
cursor.image.data = fbcon_data.cursor_data.clone();
} else {
cursor.image.data = vc_data.font.data
[char_offset..char_offset + (w as usize * vc_data.font.height as usize)]
.to_vec();
}
cursor.image.fg = fbcon_data.cursor_state.image.fg;
cursor.image.bg = fbcon_data.cursor_state.image.bg;
cursor.image.x = fbcon_data.cursor_state.image.x;
cursor.image.y = fbcon_data.cursor_state.image.y;
cursor.image.height = fbcon_data.cursor_state.image.height;
cursor.image.width = fbcon_data.cursor_state.image.width;
cursor.hot_x = fbcon_data.cursor_state.hot_x;
cursor.hot_y = fbcon_data.cursor_state.hot_y;
cursor.mask = fbcon_data.cursor_state.mask.clone();
cursor.enable = fbcon_data.cursor_state.enable;
cursor.image.depth = 1;
cursor.rop = true;
if fb_info.fb_cursor(&cursor).is_err() {
let _ = fb_info.soft_cursor(cursor);
}
fbcon_data.cursor_reset = false;
}
}