Bläddra i källkod

支持绘制24位深和16位深显示缓冲区 (#640)

* 修复了初始化时显示,边界条件的一个bug

* 解决了内存未初始前字体显示的兼容性问题
* 支持绘制24位深和16位深显示缓冲区
曾俊 11 månader sedan
förälder
incheckning
2755467c79

+ 36 - 20
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;
-
-        // // TODO:这里是需要计算的,但是目前用不到,先直接写
-        // let bswapmask = 0;
+        let mut dst = _dst1.as_ptr::<u32>();
+        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;
 
-        // let dst2 = dst1;
-
-        // // 一行一行画
-        // for i in image.height..0 {
-        //     let dst = dst1;
+                dst = dst.add(1);
+            }
 
-        //     if start_index > 0 {
-        //         let start_mask = !(!(0 as u32) << start_index);
-        //     }
-        // }
+            if full {
+                count += 1;
+                dst = unsafe {
+                    _dst1.as_ptr::<u8>().add((_pitch_index * count) as usize) as *mut u32
+                };
+            }
+        }
     }
 }
 

+ 172 - 0
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<PixelLineStatus, PixelLineStatus> {
+        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<Self::Item> {
+        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),
+        }
+    }
+}

+ 98 - 1
kernel/src/driver/video/fbdev/vesafb.rs

@@ -424,7 +424,30 @@ impl FrameBufferOps for VesaFb {
                     }
                 }
             }
-            _ => todo!(),
+            16 => {
+                let base = screen_base.as_ptr::<u16>();
+
+                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::<u16>();
+                let mut src = src.as_ptr::<u16>();
+                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<u16> = 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<u32> = 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!()
             }
         }

+ 4 - 4
kernel/src/driver/video/mod.rs

@@ -34,7 +34,7 @@ pub fn video_refresh_manager() -> &'static VideoRefreshManager {
 ///管理显示刷新变量的结构体
 pub struct VideoRefreshManager {
     device_buffer: RwLock<ScmBufferInfo>,
-    refresh_target: RwLock<Option<Arc<SpinLock<Box<[u32]>>>>>,
+    refresh_target: RwLock<Option<Arc<SpinLock<Box<[u8]>>>>>,
     running: AtomicBool,
 }
 
@@ -150,7 +150,7 @@ impl VideoRefreshManager {
     }
     #[allow(clippy::type_complexity)]
     #[allow(dead_code)]
-    pub fn refresh_target(&self) -> RwLockReadGuard<'_, Option<Arc<SpinLock<Box<[u32]>>>>> {
+    pub fn refresh_target(&self) -> RwLockReadGuard<'_, Option<Arc<SpinLock<Box<[u8]>>>>> {
         let x = self.refresh_target.read();
 
         return x;
@@ -254,7 +254,7 @@ impl TimerFunction for VideoRefreshExecutor {
             }
         };
 
-        let mut refresh_target: Option<RwLockReadGuard<'_, Option<Arc<SpinLock<Box<[u32]>>>>>> =
+        let mut refresh_target: Option<RwLockReadGuard<'_, Option<Arc<SpinLock<Box<[u8]>>>>>> =
             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,
                 )
             }

+ 1 - 1
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);
 }

+ 1 - 0
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;
 

+ 8 - 8
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<SpinLock<Box<[u32]>>>),
+    DoubleBuffer(Arc<SpinLock<Box<[u8]>>>),
 }
 
 #[derive(Debug, Clone)]
@@ -81,15 +81,15 @@ impl ScmBufferInfo {
         } else {
             let device_buffer_guard = video_refresh_manager().device_buffer();
 
-            let buf_space: Arc<SpinLock<Box<[u32]>>> = Arc::new(SpinLock::new(
-                vec![0u32; (device_buffer_guard.size / 4) as usize].into_boxed_slice(),
+            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::<u32>()
+                buf_space.lock().len() * core::mem::size_of::<u8>()
             );
 
             // 创建双缓冲区
@@ -155,11 +155,11 @@ impl ScmBufferInfo {
             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 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::<u32>();
+                        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 u32, len)
+                            core::slice::from_raw_parts(vaddr.data() as *const u8, len)
                         });
                     }
                     ScmBuffer::DoubleBuffer(double_buffer) => {

+ 64 - 14
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<SpinLockGuard<'a, Box<[u32]>>>,
+    buf: Option<&'a mut [u8]>,
+
+    guard: Option<SpinLockGuard<'a, Box<[u8]>>>,
+
+    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 {

+ 1 - 1
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码表中的空字符,表示字符串的结尾