From 2755467c790d6510fa97cbf052ce8e91ad1372c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=BE=E4=BF=8A?= <110876916+ZZJJWarth@users.noreply.github.com> Date: Mon, 25 Mar 2024 16:39:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=BB=98=E5=88=B624=E4=BD=8D?= =?UTF-8?q?=E6=B7=B1=E5=92=8C16=E4=BD=8D=E6=B7=B1=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E7=BC=93=E5=86=B2=E5=8C=BA=20(#640)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复了初始化时显示,边界条件的一个bug * 解决了内存未初始前字体显示的兼容性问题 * 支持绘制24位深和16位深显示缓冲区 --- kernel/src/driver/video/fbdev/base/mod.rs | 56 ++++-- .../driver/video/fbdev/base/render_helper.rs | 172 ++++++++++++++++++ kernel/src/driver/video/fbdev/vesafb.rs | 99 +++++++++- kernel/src/driver/video/mod.rs | 8 +- kernel/src/lib.rs | 2 +- kernel/src/libs/lib_ui/font/mod.rs | 1 + kernel/src/libs/lib_ui/screen_manager.rs | 16 +- kernel/src/libs/lib_ui/textui.rs | 78 ++++++-- kernel/src/libs/lib_ui/textui_no_alloc.rs | 2 +- 9 files changed, 385 insertions(+), 49 deletions(-) create mode 100644 kernel/src/driver/video/fbdev/base/render_helper.rs diff --git a/kernel/src/driver/video/fbdev/base/mod.rs b/kernel/src/driver/video/fbdev/base/mod.rs index 41dacf85..e20b0871 100644 --- a/kernel/src/driver/video/fbdev/base/mod.rs +++ b/kernel/src/driver/video/fbdev/base/mod.rs @@ -8,7 +8,10 @@ use crate::{ mm::{ucontext::LockedVMA, PhysAddr, VirtAddr}, }; -use self::fbmem::{FbDevice, FrameBufferManager}; +use self::{ + fbmem::{FbDevice, FrameBufferManager}, + render_helper::{BitIter, EndianPattern}, +}; const COLOR_TABLE_8: &[u32] = &[ 0x00000000, 0xff000000, 0x00ff0000, 0xffff0000, 0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00, @@ -23,7 +26,7 @@ pub mod fbcon; pub mod fbmem; pub mod fbsysfs; pub mod modedb; - +pub mod render_helper; // 帧缓冲区id int_like!(FbId, u32); @@ -106,7 +109,14 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { { unsafe { self.fast_imageblit(image, dst1, fg, bg) } } else { - self.slow_imageblit(image, dst1, fg, bg, start_index, pitch_index) + self.slow_imageblit( + image, + dst1, + fg, + bg, + bitstart / 4, + self.current_fb_fix().line_length, + ) } } else { todo!("color image blit todo"); @@ -246,25 +256,31 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device { _start_index: u32, _pitch_index: u32, ) { - todo!(); - // let bpp = self.current_fb_var().bits_per_pixel; - // let pitch = self.current_fb_fix().line_length; - // let null_bits = 32 - bpp; - // let spitch = (image.width + 7) / 8; + let mut dst = _dst1.as_ptr::(); + let mut count = 0; + let iter = BitIter::new( + _fg, + _bg, + EndianPattern::Big, + EndianPattern::Little, + self.current_fb_var().bits_per_pixel / 8, + _image.data.iter(), + _image.width, + ); + for (content, full) in iter { + unsafe { + *dst = content; - // // TODO:这里是需要计算的,但是目前用不到,先直接写 - // let bswapmask = 0; + dst = dst.add(1); + } - // let dst2 = dst1; - - // // 一行一行画 - // for i in image.height..0 { - // let dst = dst1; - - // if start_index > 0 { - // let start_mask = !(!(0 as u32) << start_index); - // } - // } + if full { + count += 1; + dst = unsafe { + _dst1.as_ptr::().add((_pitch_index * count) as usize) as *mut u32 + }; + } + } } } diff --git a/kernel/src/driver/video/fbdev/base/render_helper.rs b/kernel/src/driver/video/fbdev/base/render_helper.rs new file mode 100644 index 00000000..0ce9f80a --- /dev/null +++ b/kernel/src/driver/video/fbdev/base/render_helper.rs @@ -0,0 +1,172 @@ +use core::slice::Iter; + +pub struct BitIter<'a> { + fgcolor: u32, + bkcolor: u32, + _color_pattern: EndianPattern, + _dst_pattern: EndianPattern, + src: Iter<'a, u8>, + read_mask: u8, + byte_per_pixel: u32, + buffer: u32, + current: u8, + left_byte: u32, + done: bool, + consumed_bit: u32, + image_width: u32, +} + +impl<'a> BitIter<'a> { + pub fn new( + fgcolor: u32, + bkcolor: u32, + dst_pattern: EndianPattern, + color_pattern: EndianPattern, + byte_per_pixel: u32, + src: Iter<'a, u8>, + image_width: u32, + ) -> Self { + let mut fgcolor = fgcolor; + let mut bkcolor = bkcolor; + if dst_pattern != color_pattern { + fgcolor = Self::reverse(fgcolor, byte_per_pixel); + bkcolor = Self::reverse(bkcolor, byte_per_pixel); + } + + let mut ans = Self { + fgcolor, + bkcolor, + _color_pattern: color_pattern, + _dst_pattern: dst_pattern, + src, + read_mask: 0b10000000, + byte_per_pixel, + buffer: 0, + current: 0, + left_byte: 0, + done: false, + consumed_bit: 0, + image_width, + }; + ans.current = *ans.src.next().unwrap(); + return ans; + } + + fn reverse(num: u32, byte_per_pixel: u32) -> u32 { + let mask = 0x000000ff; + let mut ans = 0; + let mut num = num; + for _ in 0..3 { + ans |= mask & num; + ans <<= 8; + num >>= 8; + } + ans |= mask & num; + ans >>= (4 - byte_per_pixel) * 8; + return ans; + } + + fn move_mask(&mut self) -> bool { + self.consumed_bit += 1; + self.read_mask >>= 1; + if self.read_mask == 0b000000000 { + self.read_mask = 0b10000000; + self.current = match self.src.next() { + Some(x) => *x, + None => { + return false; + } + }; + return true; + } else { + return true; + } + } + + fn full_buffer(&mut self) -> Result { + let same_endian = if self._dst_pattern == self._color_pattern { + 1 + } else { + -1 + }; + let mut color = self.read_bit() << (self.left_byte << 3); + let mut buffer_pointer = if self._dst_pattern == self._color_pattern { + 0 + } else { + 3 + }; + let mask = 0x000000ff << ((self.byte_per_pixel - 1) << 3); + let mut temp; + // while buffer_pointer >= 0 && buffer_pointer <= 3 { + while (0..=3).contains(&buffer_pointer) { + if self.consumed_bit >= self.image_width { + self.consumed_bit = 0; + return Ok(PixelLineStatus::Full(self.buffer)); + } + temp = color & mask; + color <<= 8; + temp <<= (4 - self.byte_per_pixel) * 8; + temp >>= buffer_pointer * 8; + self.buffer |= temp; + buffer_pointer += same_endian; + self.left_byte += 1; + if self.left_byte >= self.byte_per_pixel { + self.left_byte = 0; + if !self.move_mask() { + return Err(PixelLineStatus::Full(self.buffer)); + } + color = self.read_bit(); + } + } + if self.consumed_bit >= self.image_width { + self.consumed_bit = 0; + return Ok(PixelLineStatus::Full(self.buffer)); + } + return Ok(PixelLineStatus::NotFull(self.buffer)); + } + + fn read_bit(&self) -> u32 { + match self.read_mask & self.current { + 0 => self.bkcolor, + _ => self.fgcolor, + } + } +} + +impl Iterator for BitIter<'_> { + type Item = (u32, bool); + fn next(&mut self) -> Option { + if self.done { + return None; + } + match self.full_buffer() { + Ok(x) => { + self.buffer = 0; + return Some(x.unwarp()); + } + Err(x) => { + self.done = true; + return Some(x.unwarp()); + } + } + } +} +#[derive(PartialEq, PartialOrd)] +pub enum EndianPattern { + Big, + Little, +} + +pub enum PixelLineStatus { + Full(u32), + NotFull(u32), +} + +impl PixelLineStatus { + pub fn unwarp(self) -> (u32, bool) { + match self { + PixelLineStatus::Full(x) => (x, true), + PixelLineStatus::NotFull(x) => (x, false), + } + } +} diff --git a/kernel/src/driver/video/fbdev/vesafb.rs b/kernel/src/driver/video/fbdev/vesafb.rs index 572bced3..819b2ff9 100644 --- a/kernel/src/driver/video/fbdev/vesafb.rs +++ b/kernel/src/driver/video/fbdev/vesafb.rs @@ -424,7 +424,30 @@ impl FrameBufferOps for VesaFb { } } } - _ => todo!(), + 16 => { + let base = screen_base.as_ptr::(); + + for y in rect.dy..(rect.dy + rect.height) { + for x in rect.dx..(rect.dx + rect.width) { + unsafe { *base.add((y * line_offset + x) as usize) = 0x0000 }; + } + } + } + 24 => { + let base = screen_base.as_ptr::<[u8; 3]>(); + + for y in rect.dy..(rect.dy + rect.height) { + for x in rect.dx..(rect.dx + rect.width) { + unsafe { *base.add((y * line_offset + x) as usize) = [0, 0, 0] }; + } + } + } + _ => { + send_to_default_serial8250_port( + format!("unsupported bit depth:{}!\n\0", bpp).as_bytes(), + ); + todo!() + } } Ok(()) @@ -565,7 +588,81 @@ impl FrameBufferOps for VesaFb { } } } + 2 => { + let mut dst = dst.as_ptr::(); + let mut src = src.as_ptr::(); + let line_offset = var.xres as usize; + + if s_real_x > d_real_x { + // 如果src在dst下方,则可以直接拷贝不会出现指针覆盖 + unsafe { + for _ in 0..visiable_h { + core::ptr::copy(src, dst, visiable_w as usize); + src = src.add(line_offset); + dst = dst.add(visiable_w as usize); + } + } + } else { + let mut tmp: Vec = vec![0; size]; + let mut tmp_ptr = tmp.as_mut_ptr(); + + // 这里是一个可以优化的点,现在为了避免指针拷贝时覆盖,统一先拷贝进入buf再拷贝到dst + unsafe { + for _ in 0..visiable_h { + core::ptr::copy(src, tmp_ptr, visiable_w as usize); + src = src.add(line_offset); + tmp_ptr = tmp_ptr.add(visiable_w as usize); + } + + tmp_ptr = tmp_ptr.sub(size); + for _ in 0..visiable_h { + core::ptr::copy(tmp_ptr, dst, visiable_w as usize); + dst = dst.add(line_offset); + tmp_ptr = tmp_ptr.add(visiable_w as usize); + } + } + } + } + 3 => { + let mut dst = dst.as_ptr::<[u8; 3]>(); + let mut src = src.as_ptr::<[u8; 3]>(); + let line_offset = var.xres as usize; + + if s_real_x > d_real_x { + // 如果src在dst下方,则可以直接拷贝不会出现指针覆盖 + unsafe { + for _ in 0..visiable_h { + core::ptr::copy(src, dst, visiable_w as usize); + src = src.add(line_offset); + dst = dst.add(visiable_w as usize); + } + } + } else { + let mut tmp: Vec = vec![0; size]; + let mut tmp_ptr = tmp.as_mut_ptr() as *mut [u8; 3]; + + // 这里是一个可以优化的点,现在为了避免指针拷贝时覆盖,统一先拷贝进入buf再拷贝到dst + unsafe { + for _ in 0..visiable_h { + core::ptr::copy(src, tmp_ptr, visiable_w as usize); + src = src.add(line_offset); + tmp_ptr = tmp_ptr.add(visiable_w as usize); + } + + tmp_ptr = tmp_ptr.sub(size); + for _ in 0..visiable_h { + core::ptr::copy(tmp_ptr, dst, visiable_w as usize); + dst = dst.add(line_offset); + tmp_ptr = tmp_ptr.add(visiable_w as usize); + } + } + } + } + _ => { + send_to_default_serial8250_port( + format!("bytes_per_pixel:{}\n\0", bytes_per_pixel).as_bytes(), + ); todo!() } } diff --git a/kernel/src/driver/video/mod.rs b/kernel/src/driver/video/mod.rs index 7cc95b50..12f76516 100644 --- a/kernel/src/driver/video/mod.rs +++ b/kernel/src/driver/video/mod.rs @@ -34,7 +34,7 @@ pub fn video_refresh_manager() -> &'static VideoRefreshManager { ///管理显示刷新变量的结构体 pub struct VideoRefreshManager { device_buffer: RwLock, - refresh_target: RwLock>>>>, + refresh_target: RwLock>>>>, running: AtomicBool, } @@ -150,7 +150,7 @@ impl VideoRefreshManager { } #[allow(clippy::type_complexity)] #[allow(dead_code)] - pub fn refresh_target(&self) -> RwLockReadGuard<'_, Option>>>> { + pub fn refresh_target(&self) -> RwLockReadGuard<'_, Option>>>> { let x = self.refresh_target.read(); return x; @@ -254,7 +254,7 @@ impl TimerFunction for VideoRefreshExecutor { } }; - let mut refresh_target: Option>>>>> = + let mut refresh_target: Option>>>>> = None; const TRY_TIMES: i32 = 2; for i in 0..TRY_TIMES { @@ -288,7 +288,7 @@ impl TimerFunction for VideoRefreshExecutor { let mut target_guard = target_guard.unwrap(); unsafe { p.copy_from_nonoverlapping( - target_guard.as_mut_ptr() as *mut u8, + target_guard.as_mut_ptr(), manager.device_buffer().buf_size() as usize, ) } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 778f00c3..71a7a4ff 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -144,6 +144,6 @@ pub fn panic(info: &PanicInfo) -> ! { }; } - println!("Current PCB:\n\t{:?}", *(ProcessManager::current_pcb())); + println!("Current PCB:\n\t{:?}", (ProcessManager::current_pcb())); ProcessManager::exit(usize::MAX); } diff --git a/kernel/src/libs/lib_ui/font/mod.rs b/kernel/src/libs/lib_ui/font/mod.rs index c1129eeb..4efd478b 100644 --- a/kernel/src/libs/lib_ui/font/mod.rs +++ b/kernel/src/libs/lib_ui/font/mod.rs @@ -45,6 +45,7 @@ impl<'a> BitmapFont<'a> { #[inline(always)] pub fn char_map(&self, character: char) -> &'a [u8] { + //获得ASCII的index let index = self.glyph_mapping.index(character); let pos = index * self.bytes_per_char; diff --git a/kernel/src/libs/lib_ui/screen_manager.rs b/kernel/src/libs/lib_ui/screen_manager.rs index 0640cdba..13516f66 100644 --- a/kernel/src/libs/lib_ui/screen_manager.rs +++ b/kernel/src/libs/lib_ui/screen_manager.rs @@ -47,7 +47,7 @@ pub enum ScmFramworkType { #[derive(Debug, Clone)] pub enum ScmBuffer { DeviceBuffer(VirtAddr), - DoubleBuffer(Arc>>), + DoubleBuffer(Arc>>), } #[derive(Debug, Clone)] @@ -81,15 +81,15 @@ impl ScmBufferInfo { } else { let device_buffer_guard = video_refresh_manager().device_buffer(); - let buf_space: Arc>> = Arc::new(SpinLock::new( - vec![0u32; (device_buffer_guard.size / 4) as usize].into_boxed_slice(), + let buf_space: Arc>> = 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::() + buf_space.lock().len() * core::mem::size_of::() ); // 创建双缓冲区 @@ -155,11 +155,11 @@ impl ScmBufferInfo { ScmBuffer::DeviceBuffer(vaddr) => { let len = self.buf_size() / core::mem::size_of::(); let self_buf_guard = - unsafe { core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len) }; + 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 u32, len) }; + 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) => { @@ -173,9 +173,9 @@ impl ScmBufferInfo { let mut double_buffer_guard = double_buffer.lock(); match &src.buf { ScmBuffer::DeviceBuffer(vaddr) => { - let len = src.buf_size() / core::mem::size_of::(); + let len = src.buf_size() / core::mem::size_of::(); double_buffer_guard.as_mut().copy_from_slice(unsafe { - core::slice::from_raw_parts(vaddr.data() as *const u32, len) + core::slice::from_raw_parts(vaddr.data() as *const u8, len) }); } ScmBuffer::DoubleBuffer(double_buffer) => { diff --git a/kernel/src/libs/lib_ui/textui.rs b/kernel/src/libs/lib_ui/textui.rs index 2a894c38..f445dfbc 100644 --- a/kernel/src/libs/lib_ui/textui.rs +++ b/kernel/src/libs/lib_ui/textui.rs @@ -17,6 +17,7 @@ use core::{ fmt::Debug, intrinsics::unlikely, ops::{Add, AddAssign, Sub}, + ptr::copy_nonoverlapping, sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering}, }; use system_error::SystemError; @@ -295,36 +296,41 @@ pub struct TextuiCharChromatic { #[derive(Debug)] pub struct TextuiBuf<'a> { - buf: Option<&'a mut [u32]>, - guard: Option>>, + buf: Option<&'a mut [u8]>, + + guard: Option>>, + + bit_depth: u32, } impl TextuiBuf<'_> { pub fn new(buf: &mut ScmBufferInfo) -> TextuiBuf { let len = buf.buf_size() / 4; - + let depth = video_refresh_manager().device_buffer().bit_depth(); match &buf.buf { ScmBuffer::DeviceBuffer(vaddr) => { return TextuiBuf { buf: Some(unsafe { - core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len) + core::slice::from_raw_parts_mut(vaddr.data() as *mut u8, len) }), guard: None, + bit_depth: depth, }; } ScmBuffer::DoubleBuffer(double_buffer) => { - let guard: SpinLockGuard<'_, Box<[u32]>> = double_buffer.lock(); + let guard: SpinLockGuard<'_, Box<[u8]>> = double_buffer.lock(); return TextuiBuf { buf: None, guard: Some(guard), + bit_depth: depth, }; } } } - pub fn buf_mut(&mut self) -> &mut [u32] { + pub fn buf_mut(&mut self) -> &mut [u8] { if let Some(buf) = &mut self.buf { return buf; } else { @@ -332,8 +338,34 @@ impl TextuiBuf<'_> { } } pub fn put_color_in_pixel(&mut self, color: u32, index: usize) { - let buf: &mut [u32] = self.buf_mut(); - buf[index] = color; + let index = index as isize; + match self.bit_depth { + 32 => { + let buf = self.buf_mut().as_mut_ptr() as *mut u32; + unsafe { + *buf.offset(index) = color; + } + } + 24 => { + let buf = self.buf_mut().as_mut_ptr(); + unsafe { + copy_nonoverlapping(&color as *const u32 as *const u8, buf.offset(index * 3), 3) + }; + } + 16 => { + let buf = self.buf_mut().as_mut_ptr(); + unsafe { + copy_nonoverlapping( + &color as *const u32 as *const u8, + buf.offset(index * 2), + 2, + ); + }; + } + _ => { + panic!("不支持的位深度!") + } + } } pub fn get_index_of_next_line(now_index: usize) -> usize { textui_framework().metadata.read().buf_info().width() as usize + now_index @@ -430,8 +462,10 @@ impl TextuiCharChromatic { let id_y: u32 = lineid.into(); let y: u32 = id_y * TEXTUI_CHAR_HEIGHT; - + let buf_depth = video_refresh_manager().device_buffer().bit_depth(); let buf_width = video_refresh_manager().device_buffer().width(); + let byte_num_of_depth = (buf_depth / 8) as usize; + // 找到输入缓冲区的起始地址位置 let buf_start = if let ScmBuffer::DeviceBuffer(vaddr) = video_refresh_manager().device_buffer().buf { @@ -446,19 +480,35 @@ impl TextuiCharChromatic { for i in 0..TEXTUI_CHAR_HEIGHT { // 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x) - let mut addr: *mut u32 = - (buf_start + buf_width as usize * 4 * (y as usize + i as usize) + 4 * x as usize) - .data() as *mut u32; + let mut addr: *mut u8 = (buf_start + + buf_width as usize * byte_num_of_depth * (y as usize + i as usize) + + byte_num_of_depth * x as usize) + .data() as *mut u8; testbit = 1 << (TEXTUI_CHAR_WIDTH + 1); for _j in 0..TEXTUI_CHAR_WIDTH { + //该循环是渲染一行像素 //从左往右逐个测试相应位 testbit >>= 1; if (font.0[i as usize] & testbit as u8) != 0 { - unsafe { *addr = self.frcolor.into() }; // 字,显示前景色 + let color: u32 = self.frcolor.into(); + unsafe { + copy_nonoverlapping( + &color as *const u32 as *const u8, + addr, + byte_num_of_depth, + ) + }; // 字,显示前景色 } else { - unsafe { *addr = self.bkcolor.into() }; // 背景色 + let color: u32 = self.bkcolor.into(); + unsafe { + copy_nonoverlapping( + &color as *const u32 as *const u8, + addr, + byte_num_of_depth, + ) + }; } unsafe { diff --git a/kernel/src/libs/lib_ui/textui_no_alloc.rs b/kernel/src/libs/lib_ui/textui_no_alloc.rs index e507fc8b..42a425b6 100644 --- a/kernel/src/libs/lib_ui/textui_no_alloc.rs +++ b/kernel/src/libs/lib_ui/textui_no_alloc.rs @@ -36,7 +36,7 @@ pub fn no_init_textui_putchar_window( bkcolor: FontColor, is_put_to_window: bool, ) -> Result<(), SystemError> { - if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) > TRUE_LINE_NUM.load(Ordering::SeqCst) { + if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) >= TRUE_LINE_NUM.load(Ordering::SeqCst) { NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst); } //字符'\0'代表ASCII码表中的空字符,表示字符串的结尾