mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 00:24:41 +08:00
136 lines
4.1 KiB
Rust
136 lines
4.1 KiB
Rust
use crate::efi::{EfiGraphicsOutputProtocol, EfiGraphicsPixelFormat};
|
|
|
|
#[derive(Clone, Copy)]
|
|
pub struct Rgb {
|
|
pub red: u8,
|
|
pub green: u8,
|
|
pub blue: u8,
|
|
}
|
|
|
|
pub struct Framebuffer {
|
|
base: *mut u8,
|
|
width: usize,
|
|
height: usize,
|
|
stride: usize,
|
|
pixel_format: EfiGraphicsPixelFormat,
|
|
}
|
|
|
|
impl Framebuffer {
|
|
pub unsafe fn from_gop(gop: *mut EfiGraphicsOutputProtocol) -> Option<Self> {
|
|
let mode = unsafe { (*gop).mode };
|
|
if mode.is_null() {
|
|
return None;
|
|
}
|
|
|
|
let info = unsafe { (*mode).info };
|
|
if info.is_null() {
|
|
return None;
|
|
}
|
|
|
|
let pixel_format = unsafe { (*info).pixel_format };
|
|
if pixel_format != EfiGraphicsPixelFormat::RedGreenBlueReserved8BitPerColor
|
|
&& pixel_format != EfiGraphicsPixelFormat::BlueGreenRedReserved8BitPerColor
|
|
{
|
|
return None;
|
|
}
|
|
|
|
Some(Self {
|
|
base: unsafe { (*mode).frame_buffer_base as *mut u8 },
|
|
width: unsafe { (*info).horizontal_resolution as usize },
|
|
height: unsafe { (*info).vertical_resolution as usize },
|
|
stride: unsafe { (*info).pixels_per_scan_line as usize },
|
|
pixel_format,
|
|
})
|
|
}
|
|
|
|
pub fn width(&self) -> usize {
|
|
self.width
|
|
}
|
|
|
|
pub fn height(&self) -> usize {
|
|
self.height
|
|
}
|
|
|
|
pub fn clear(&mut self, color: Rgb) {
|
|
self.fill_rect(0, 0, self.width, self.height, color);
|
|
}
|
|
|
|
pub fn fill_rect(&mut self, x: usize, y: usize, width: usize, height: usize, color: Rgb) {
|
|
let end_x = x.saturating_add(width).min(self.width);
|
|
let end_y = y.saturating_add(height).min(self.height);
|
|
|
|
for py in y..end_y {
|
|
for px in x..end_x {
|
|
self.put_pixel(px, py, color);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn scroll_region_up(&mut self, top: usize, bottom: usize, pixels: usize, fill: Rgb) {
|
|
if pixels == 0 {
|
|
return;
|
|
}
|
|
|
|
let top = top.min(self.height);
|
|
let bottom = bottom.min(self.height);
|
|
if top >= bottom {
|
|
return;
|
|
}
|
|
|
|
if pixels >= bottom - top {
|
|
self.fill_rect(0, top, self.width, bottom - top, fill);
|
|
return;
|
|
}
|
|
|
|
for y in top..bottom {
|
|
for x in 0..self.width {
|
|
if y + pixels < bottom {
|
|
self.copy_pixel(x, y + pixels, x, y);
|
|
} else {
|
|
self.put_pixel(x, y, fill);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn put_pixel(&mut self, x: usize, y: usize, color: Rgb) {
|
|
if x >= self.width || y >= self.height {
|
|
return;
|
|
}
|
|
|
|
let offset = (y * self.stride + x) * 4;
|
|
unsafe {
|
|
let pixel = self.base.add(offset);
|
|
match self.pixel_format {
|
|
EfiGraphicsPixelFormat::RedGreenBlueReserved8BitPerColor => {
|
|
pixel.write_volatile(color.red);
|
|
pixel.add(1).write_volatile(color.green);
|
|
pixel.add(2).write_volatile(color.blue);
|
|
pixel.add(3).write_volatile(0);
|
|
}
|
|
EfiGraphicsPixelFormat::BlueGreenRedReserved8BitPerColor => {
|
|
pixel.write_volatile(color.blue);
|
|
pixel.add(1).write_volatile(color.green);
|
|
pixel.add(2).write_volatile(color.red);
|
|
pixel.add(3).write_volatile(0);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn copy_pixel(&mut self, source_x: usize, source_y: usize, target_x: usize, target_y: usize) {
|
|
let source_offset = (source_y * self.stride + source_x) * 4;
|
|
let target_offset = (target_y * self.stride + target_x) * 4;
|
|
|
|
unsafe {
|
|
let source = self.base.add(source_offset);
|
|
let target = self.base.add(target_offset);
|
|
target.write_volatile(source.read_volatile());
|
|
target.add(1).write_volatile(source.add(1).read_volatile());
|
|
target.add(2).write_volatile(source.add(2).read_volatile());
|
|
target.add(3).write_volatile(source.add(3).read_volatile());
|
|
}
|
|
}
|
|
}
|