Merge branch 'various_graphics_cleanups' into 'master'

A variety of cleanups, soundness fixes and other changes to the graphics subsystem

See merge request redox-os/drivers!187
This commit is contained in:
Jeremy Soller
2024-07-19 23:22:01 +00:00
5 changed files with 85 additions and 101 deletions
+5 -6
View File
@@ -13,7 +13,7 @@ use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR};
// Keep synced with vesad
#[derive(Clone, Copy)]
#[repr(packed)]
#[repr(C, packed)]
pub struct SyncRect {
pub x: i32,
pub y: i32,
@@ -36,9 +36,8 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re
}
}
unsafe fn display_fd_unmap(image: *mut [u32], size: usize) {
// FIXME use image.len() instead of size once it is stable.
let _ = libredox::call::munmap(image as *mut (), size * 4);
unsafe fn display_fd_unmap(image: *mut [u32]) {
let _ = libredox::call::munmap(image as *mut (), image.len());
}
pub struct Display {
@@ -125,7 +124,7 @@ impl Display {
match display_fd_map(width, height, self.display_file.as_raw_fd() as usize) {
Ok(ok) => {
unsafe {
display_fd_unmap(self.offscreen, (self.width * self.height) as usize);
display_fd_unmap(self.offscreen);
}
self.offscreen = ok;
self.width = width;
@@ -154,7 +153,7 @@ impl Display {
impl Drop for Display {
fn drop(&mut self) {
unsafe {
display_fd_unmap(self.offscreen, self.width * self.height);
display_fd_unmap(self.offscreen);
}
}
}
+52 -17
View File
@@ -1,6 +1,9 @@
use std::{ptr, slice};
use std::ptr;
use syscall::PAGE_SIZE;
pub struct FrameBuffer {
pub onscreen: *mut [u32],
pub phys: usize,
pub width: usize,
pub height: usize,
@@ -8,8 +11,25 @@ pub struct FrameBuffer {
}
impl FrameBuffer {
pub fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self {
pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self {
let size = stride * height;
let virt = common::physmap(
phys,
size * 4,
common::Prot {
read: true,
write: true,
},
common::MemoryType::WriteCombining,
)
.expect("vesad: failed to map framebuffer") as *mut u32;
//TODO: should we clear the framebuffer here?
ptr::write_bytes(virt, 0, size);
let onscreen = ptr::slice_from_raw_parts_mut(virt, size);
Self {
onscreen,
phys,
width,
height,
@@ -17,7 +37,7 @@ impl FrameBuffer {
}
}
pub fn parse(var: &str) -> Option<Self> {
pub unsafe fn parse(var: &str) -> Option<Self> {
fn parse_number(part: &str) -> Option<usize> {
let (start, radix) = if part.starts_with("0x") {
(2, 16)
@@ -41,20 +61,35 @@ impl FrameBuffer {
Some(Self::new(phys, width, height, stride))
}
pub unsafe fn map(&mut self) -> syscall::Result<&'static mut [u32]> {
let size = self.stride * self.height;
let virt = common::physmap(
self.phys,
size * 4,
common::Prot {
read: true,
write: true,
},
common::MemoryType::WriteCombining,
)? as *mut u32;
//TODO: should we clear the framebuffer here?
ptr::write_bytes(virt, 0, size);
pub unsafe fn resize(&mut self, width: usize, height: usize, stride: usize) {
// Unmap old onscreen
unsafe {
let slice = self.onscreen;
libredox::call::munmap(slice.cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE))
.expect("vesad: failed to unmap framebuffer");
}
Ok(slice::from_raw_parts_mut(virt, size))
// Map new onscreen
self.onscreen = unsafe {
let size = stride * height;
let onscreen_ptr = common::physmap(
self.phys,
size * 4,
common::Prot {
read: true,
write: true,
},
common::MemoryType::WriteCombining,
)
.expect("vesad: failed to map framebuffer") as *mut u32;
ptr::write_bytes(onscreen_ptr, 0, size);
ptr::slice_from_raw_parts_mut(onscreen_ptr, size)
};
// Update size
self.width = width;
self.height = height;
self.stride = stride;
}
}
+2 -2
View File
@@ -54,12 +54,12 @@ fn main() {
return;
}
let mut framebuffers = vec![FrameBuffer::new(phys, width, height, stride)];
let mut framebuffers = vec![unsafe { FrameBuffer::new(phys, width, height, stride) }];
//TODO: ideal maximum number of outputs?
for i in 1..1024 {
match env::var(&format!("FRAMEBUFFER{}", i)) {
Ok(var) => match FrameBuffer::parse(&var) {
Ok(var) => match unsafe { FrameBuffer::parse(&var) } {
Some(fb) => {
println!(
"vesad: framebuffer {}: {}x{} stride {} at 0x{:X}",
+8 -55
View File
@@ -1,9 +1,7 @@
use std::collections::BTreeMap;
use std::{mem, ptr, slice, str};
use std::str;
use syscall::{
Error, EventFlags, MapFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK, PAGE_SIZE,
};
use syscall::{Error, EventFlags, MapFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK};
use crate::{framebuffer::FrameBuffer, screen::GraphicScreen};
@@ -29,7 +27,6 @@ pub struct Handle {
pub struct DisplayScheme {
framebuffers: Vec<FrameBuffer>,
onscreens: Vec<&'static mut [u32]>,
active: VtIndex,
pub vts: BTreeMap<VtIndex, BTreeMap<ScreenIndex, GraphicScreen>>,
next_id: usize,
@@ -38,14 +35,9 @@ pub struct DisplayScheme {
}
impl DisplayScheme {
pub fn new(mut framebuffers: Vec<FrameBuffer>, spec: &[()]) -> DisplayScheme {
pub fn new(framebuffers: Vec<FrameBuffer>, spec: &[()]) -> DisplayScheme {
let mut inputd_handle = inputd::Handle::new("vesa").unwrap();
let mut onscreens = Vec::new();
for fb in framebuffers.iter_mut() {
onscreens.push(unsafe { fb.map().expect("vesad: failed to map framebuffer") });
}
let mut vts = BTreeMap::<VtIndex, BTreeMap<ScreenIndex, GraphicScreen>>::new();
for &() in spec.iter() {
@@ -59,7 +51,6 @@ impl DisplayScheme {
DisplayScheme {
framebuffers,
onscreens,
active: VtIndex(1),
vts,
next_id: 0,
@@ -96,46 +87,17 @@ impl DisplayScheme {
fb_i, width, height, stride
);
// Unmap old onscreen
unsafe {
let slice = mem::take(&mut self.onscreens[fb_i]);
libredox::call::munmap(
slice.as_mut_ptr().cast(),
(slice.len() * 4).next_multiple_of(PAGE_SIZE),
)
.expect("vesad: failed to unmap framebuffer");
self.framebuffers[fb_i].resize(width, height, stride);
}
// Map new onscreen
self.onscreens[fb_i] = unsafe {
let size = stride * height;
let onscreen_ptr = common::physmap(
self.framebuffers[fb_i].phys,
size * 4,
common::Prot {
read: true,
write: true,
},
common::MemoryType::WriteCombining,
)
.expect("vesad: failed to map framebuffer") as *mut u32;
ptr::write_bytes(onscreen_ptr, 0, size);
slice::from_raw_parts_mut(onscreen_ptr, size)
};
// Update size
self.framebuffers[fb_i].width = width;
self.framebuffers[fb_i].height = height;
self.framebuffers[fb_i].stride = stride;
// Resize screens
for (vt_i, screens) in self.vts.iter_mut() {
for (screen_i, screen) in screens.iter_mut() {
if screen_i.0 == fb_i {
screen.resize(width, height);
if *vt_i == self.active {
screen.redraw(self.onscreens[fb_i], self.framebuffers[fb_i].stride);
screen.redraw(&mut self.framebuffers[screen_i.0]);
}
}
}
@@ -265,10 +227,7 @@ impl SchemeMut for DisplayScheme {
if let Some(screens) = self.vts.get_mut(&vt_i) {
if let Some(screen) = screens.get_mut(&screen_i) {
if vt_i == self.active {
screen.sync(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride,
);
screen.sync(&mut self.framebuffers[screen_i.0]);
}
return Ok(0);
}
@@ -307,10 +266,7 @@ impl SchemeMut for DisplayScheme {
if let Some(screens) = self.vts.get_mut(&vt_i) {
for (screen_i, screen) in screens.iter_mut() {
screen.redraw(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride,
);
screen.redraw(&mut self.framebuffers[screen_i.0]);
}
}
@@ -338,10 +294,7 @@ impl SchemeMut for DisplayScheme {
if let Some(screen) = screens.get_mut(&screen_i) {
let count = screen.write(buf)?;
if vt_i == self.active {
screen.sync(
self.onscreens[screen_i.0],
self.framebuffers[screen_i.0].stride,
);
screen.sync(&mut self.framebuffers[screen_i.0]);
}
Ok(count)
} else {
+18 -21
View File
@@ -6,10 +6,11 @@ use orbclient::{Event, ResizeEvent};
use syscall::error::*;
use crate::display::OffscreenBuffer;
use crate::framebuffer::FrameBuffer;
// Keep synced with orbital
#[derive(Clone, Copy)]
#[repr(packed)]
#[repr(C, packed)]
pub struct SyncRect {
pub x: i32,
pub y: i32,
@@ -52,11 +53,7 @@ impl GraphicScreen {
for _y in 0..cmp::min(height, self.height) {
unsafe {
ptr::copy(
old_ptr as *const u8,
new_ptr as *mut u8,
cmp::min(width, self.width) * 4,
);
ptr::copy(old_ptr, new_ptr, cmp::min(width, self.width));
if width > self.width {
ptr::write_bytes(
new_ptr.offset(self.width as isize),
@@ -134,7 +131,7 @@ impl GraphicScreen {
Ok(sync_rects.len() * mem::size_of::<SyncRect>())
}
pub fn sync(&mut self, onscreen: &mut [u32], stride: usize) {
pub fn sync(&mut self, framebuffer: &mut FrameBuffer) {
for sync_rect in self.sync_rects.drain(..) {
let x = sync_rect.x.try_into().unwrap_or(0);
let y = sync_rect.y.try_into().unwrap_or(0);
@@ -145,27 +142,27 @@ impl GraphicScreen {
let end_y = cmp::min(self.height, y + h);
let start_x = cmp::min(self.width, x);
let len = (cmp::min(self.width, x + w) - start_x) * 4;
let row_pixel_count = cmp::min(self.width, x + w) - start_x;
let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize;
let mut onscreen_ptr = onscreen.as_mut_ptr() as usize;
let mut offscreen_ptr = self.offscreen.as_mut_ptr();
let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable
offscreen_ptr += (y * self.width + start_x) * 4;
onscreen_ptr += (y * stride + start_x) * 4;
unsafe {
offscreen_ptr = offscreen_ptr.add(y * self.width + start_x);
onscreen_ptr = onscreen_ptr.add(y * framebuffer.stride + start_x);
let mut rows = end_y - start_y;
while rows > 0 {
unsafe {
ptr::copy(offscreen_ptr as *const u8, onscreen_ptr as *mut u8, len);
let mut rows = end_y - start_y;
while rows > 0 {
ptr::copy(offscreen_ptr, onscreen_ptr, row_pixel_count);
offscreen_ptr = offscreen_ptr.add(self.width);
onscreen_ptr = onscreen_ptr.add(framebuffer.stride);
rows -= 1;
}
offscreen_ptr += self.width * 4;
onscreen_ptr += stride * 4;
rows -= 1;
}
}
}
pub fn redraw(&mut self, onscreen: &mut [u32], stride: usize) {
pub fn redraw(&mut self, framebuffer: &mut FrameBuffer) {
let width = self.width.try_into().unwrap();
let height = self.height.try_into().unwrap();
self.sync_rects.push(SyncRect {
@@ -174,6 +171,6 @@ impl GraphicScreen {
w: width,
h: height,
});
self.sync(onscreen, stride);
self.sync(framebuffer);
}
}