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

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

* 解决了内存未初始前字体显示的兼容性问题
* 支持绘制24位深和16位深显示缓冲区
This commit is contained in:
曾俊
2024-03-25 16:39:36 +08:00
committed by GitHub
parent 4256da7fb6
commit 2755467c79
9 changed files with 385 additions and 49 deletions

View File

@ -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::<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;
// // 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::<u8>().add((_pitch_index * count) as usize) as *mut u32
};
}
}
}
}

View File

@ -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),
}
}
}

View File

@ -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!()
}
}

View File

@ -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,
)
}