Merge branch 'graphics_improvements' into 'master'
Various graphics subsystem improvements See merge request redox-os/drivers!241
This commit is contained in:
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" }
|
||||
redox_syscall = "0.5"
|
||||
redox_syscall = { version = "0.5", features = ["std"] }
|
||||
libredox = "0.1.3"
|
||||
|
||||
common = { path = "../../common" }
|
||||
|
||||
@@ -96,11 +96,6 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
}
|
||||
}
|
||||
|
||||
VtEventKind::Deactivate => {
|
||||
log::info!("deactivate {}", vt_event.vt);
|
||||
// nothing to do :)
|
||||
}
|
||||
|
||||
VtEventKind::Resize => {
|
||||
log::warn!("driver-graphics: resize is not implemented yet")
|
||||
}
|
||||
|
||||
@@ -41,18 +41,26 @@ enum DisplayCommand {
|
||||
|
||||
pub struct Display {
|
||||
cmd_tx: Sender<DisplayCommand>,
|
||||
pub map: Arc<Mutex<DisplayMap>>,
|
||||
pub map: Arc<Mutex<Option<DisplayMap>>>,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub fn open_first_vt() -> io::Result<Self> {
|
||||
let input_handle = ConsumerHandle::for_vt(1)?;
|
||||
|
||||
let display_handle = LegacyGraphicsHandle::from_file(input_handle.open_display()?)?;
|
||||
|
||||
let map = Arc::new(Mutex::new(
|
||||
display_fd_map(display_handle).unwrap_or_else(|e| panic!("failed to map display: {e}")),
|
||||
));
|
||||
let map = match input_handle.open_display() {
|
||||
Ok(display) => {
|
||||
let display_handle = LegacyGraphicsHandle::from_file(display)?;
|
||||
Arc::new(Mutex::new(Some(
|
||||
display_fd_map(display_handle)
|
||||
.unwrap_or_else(|e| panic!("failed to map display: {e}")),
|
||||
)))
|
||||
}
|
||||
Err(err) => {
|
||||
println!("fbbootlogd: No display present yet: {err}");
|
||||
Arc::new(Mutex::new(None))
|
||||
}
|
||||
};
|
||||
|
||||
let map_clone = map.clone();
|
||||
std::thread::spawn(move || {
|
||||
@@ -68,7 +76,7 @@ impl Display {
|
||||
Ok(Self { cmd_tx, map })
|
||||
}
|
||||
|
||||
fn handle_input_events(map: Arc<Mutex<DisplayMap>>, input_handle: ConsumerHandle) {
|
||||
fn handle_input_events(map: Arc<Mutex<Option<DisplayMap>>>, input_handle: ConsumerHandle) {
|
||||
let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue");
|
||||
|
||||
user_data! {
|
||||
@@ -93,13 +101,17 @@ impl Display {
|
||||
Err(err) if err.errno() == ESTALE => {
|
||||
eprintln!("fbbootlogd: handoff requested");
|
||||
|
||||
let new_display_handle =
|
||||
LegacyGraphicsHandle::from_file(input_handle.open_display().unwrap())
|
||||
.unwrap();
|
||||
let new_display_handle = match input_handle.open_display() {
|
||||
Ok(display) => LegacyGraphicsHandle::from_file(display).unwrap(),
|
||||
Err(err) => {
|
||||
println!("fbbootlogd: No display present yet: {err}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
match display_fd_map(new_display_handle) {
|
||||
Ok(ok) => {
|
||||
*map.lock().unwrap() = ok;
|
||||
*map.lock().unwrap() = Some(ok);
|
||||
|
||||
eprintln!("fbbootlogd: handoff finished");
|
||||
}
|
||||
@@ -117,13 +129,17 @@ impl Display {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_sync_rect(map: Arc<Mutex<DisplayMap>>, cmd_rx: Receiver<DisplayCommand>) {
|
||||
fn handle_sync_rect(map: Arc<Mutex<Option<DisplayMap>>>, cmd_rx: Receiver<DisplayCommand>) {
|
||||
while let Ok(cmd) = cmd_rx.recv() {
|
||||
match cmd {
|
||||
DisplayCommand::SyncRects(sync_rects) => {
|
||||
// We may not hold this lock across the write call to avoid deadlocking if the
|
||||
// graphics driver tries to write to the bootlog.
|
||||
let display_handle = map.lock().unwrap().display_handle.clone();
|
||||
let display_handle = if let Some(map) = &*map.lock().unwrap() {
|
||||
map.display_handle.clone()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
display_handle.sync_rects(&sync_rects).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,19 +55,21 @@ impl Scheme for FbbootlogScheme {
|
||||
}
|
||||
|
||||
fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result<usize> {
|
||||
let mut map = self.display.map.lock().unwrap();
|
||||
let damage = self.text_screen.write(
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: map.inner.ptr_mut(),
|
||||
width: map.inner.width(),
|
||||
height: map.inner.height(),
|
||||
},
|
||||
buf,
|
||||
&mut VecDeque::new(),
|
||||
);
|
||||
drop(map);
|
||||
let mut map_guard = self.display.map.lock().unwrap();
|
||||
if let Some(map) = &mut *map_guard {
|
||||
let damage = self.text_screen.write(
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: map.inner.ptr_mut(),
|
||||
width: map.inner.width(),
|
||||
height: map.inner.height(),
|
||||
},
|
||||
buf,
|
||||
&mut VecDeque::new(),
|
||||
);
|
||||
drop(map_guard);
|
||||
|
||||
self.display.sync_rects(damage);
|
||||
self.display.sync_rects(damage);
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ use crate::scheme::FbAdapter;
|
||||
|
||||
mod framebuffer;
|
||||
mod scheme;
|
||||
mod screen;
|
||||
|
||||
fn main() {
|
||||
let mut spec = Vec::new();
|
||||
@@ -22,6 +21,11 @@ fn main() {
|
||||
spec.push(());
|
||||
}
|
||||
|
||||
if env::var("FRAMEBUFFER_WIDTH").is_err() {
|
||||
println!("vesad: No boot framebuffer");
|
||||
return;
|
||||
}
|
||||
|
||||
let width = usize::from_str_radix(
|
||||
&env::var("FRAMEBUFFER_WIDTH").expect("FRAMEBUFFER_WIDTH not set"),
|
||||
16,
|
||||
@@ -49,6 +53,7 @@ fn main() {
|
||||
);
|
||||
|
||||
if phys == 0 {
|
||||
println!("vesad: Boot framebuffer at address 0");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
use driver_graphics::GraphicsAdapter;
|
||||
use graphics_ipc::legacy::Damage;
|
||||
use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use crate::{framebuffer::FrameBuffer, screen::GraphicScreen};
|
||||
use driver_graphics::{GraphicsAdapter, Resource};
|
||||
use graphics_ipc::legacy::Damage;
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
|
||||
pub struct FbAdapter {
|
||||
pub framebuffers: Vec<FrameBuffer>,
|
||||
@@ -26,11 +31,11 @@ impl GraphicsAdapter for FbAdapter {
|
||||
}
|
||||
|
||||
fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 {
|
||||
resource.ptr()
|
||||
resource.ptr.as_ptr().cast::<u8>()
|
||||
}
|
||||
|
||||
fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) {
|
||||
resource.redraw(&mut self.framebuffers[display_id]);
|
||||
self.flush_resource(display_id, resource, None);
|
||||
}
|
||||
|
||||
fn flush_resource(
|
||||
@@ -42,7 +47,91 @@ impl GraphicsAdapter for FbAdapter {
|
||||
if let Some(damage) = damage {
|
||||
resource.sync(&mut self.framebuffers[display_id], damage)
|
||||
} else {
|
||||
resource.redraw(&mut self.framebuffers[display_id])
|
||||
let framebuffer: &mut FrameBuffer = &mut self.framebuffers[display_id];
|
||||
let width = resource.width.try_into().unwrap();
|
||||
let height = resource.height.try_into().unwrap();
|
||||
resource.sync(
|
||||
framebuffer,
|
||||
&[Damage {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
}],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GraphicScreen {
|
||||
width: usize,
|
||||
height: usize,
|
||||
ptr: NonNull<[u32]>,
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
fn new(width: usize, height: usize) -> GraphicScreen {
|
||||
let len = width * height;
|
||||
let layout = Self::layout(len);
|
||||
let ptr = unsafe { alloc::alloc_zeroed(layout) };
|
||||
let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len);
|
||||
let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
|
||||
GraphicScreen { width, height, ptr }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn layout(len: usize) -> Layout {
|
||||
// optimizes to an integer mul
|
||||
Layout::array::<u32>(len)
|
||||
.unwrap()
|
||||
.align_to(PAGE_SIZE)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GraphicScreen {
|
||||
fn drop(&mut self) {
|
||||
let layout = Self::layout(self.ptr.len());
|
||||
unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for GraphicScreen {
|
||||
fn width(&self) -> u32 {
|
||||
self.width as u32
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) {
|
||||
for sync_rect in sync_rects {
|
||||
let sync_rect = sync_rect.clip(
|
||||
self.width.try_into().unwrap(),
|
||||
self.height.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let start_x: usize = sync_rect.x.try_into().unwrap_or(0);
|
||||
let start_y: usize = sync_rect.y.try_into().unwrap_or(0);
|
||||
let w: usize = sync_rect.width.try_into().unwrap_or(0);
|
||||
let h: usize = sync_rect.height.try_into().unwrap_or(0);
|
||||
|
||||
let offscreen_ptr = self.ptr.as_ptr() as *mut u32;
|
||||
let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable
|
||||
|
||||
for row in start_y..start_y + h {
|
||||
unsafe {
|
||||
ptr::copy(
|
||||
offscreen_ptr.add(row * self.width + start_x),
|
||||
onscreen_ptr.add(row * framebuffer.stride + start_x),
|
||||
w,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::Resource;
|
||||
use graphics_ipc::legacy::Damage;
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
|
||||
pub struct GraphicScreen {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
ptr: NonNull<[u32]>,
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
pub fn new(width: usize, height: usize) -> GraphicScreen {
|
||||
let len = width * height;
|
||||
let layout = Self::layout(len);
|
||||
let ptr = unsafe { alloc::alloc_zeroed(layout) };
|
||||
let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len);
|
||||
let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
|
||||
GraphicScreen { width, height, ptr }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn layout(len: usize) -> Layout {
|
||||
// optimizes to an integer mul
|
||||
Layout::array::<u32>(len)
|
||||
.unwrap()
|
||||
.align_to(PAGE_SIZE)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GraphicScreen {
|
||||
fn drop(&mut self) {
|
||||
let layout = Self::layout(self.ptr.len());
|
||||
unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for GraphicScreen {
|
||||
fn width(&self) -> u32 {
|
||||
self.width as u32
|
||||
}
|
||||
|
||||
fn height(&self) -> u32 {
|
||||
self.height as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
pub fn ptr(&self) -> *mut u8 {
|
||||
self.ptr.as_ptr().cast::<u8>()
|
||||
}
|
||||
|
||||
pub fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) {
|
||||
for sync_rect in sync_rects {
|
||||
let sync_rect = sync_rect.clip(
|
||||
self.width.try_into().unwrap(),
|
||||
self.height.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let start_x: usize = sync_rect.x.try_into().unwrap_or(0);
|
||||
let start_y: usize = sync_rect.y.try_into().unwrap_or(0);
|
||||
let w: usize = sync_rect.width.try_into().unwrap_or(0);
|
||||
let h: usize = sync_rect.height.try_into().unwrap_or(0);
|
||||
|
||||
let end_y = start_y + h;
|
||||
|
||||
let row_pixel_count = w;
|
||||
|
||||
let mut offscreen_ptr = self.ptr.as_ptr() as *mut u32;
|
||||
let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable
|
||||
|
||||
unsafe {
|
||||
offscreen_ptr = offscreen_ptr.add(start_y * self.width + start_x);
|
||||
onscreen_ptr = onscreen_ptr.add(start_y * framebuffer.stride + start_x);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn redraw(&self, framebuffer: &mut FrameBuffer) {
|
||||
let width = self.width.try_into().unwrap();
|
||||
let height = self.height.try_into().unwrap();
|
||||
self.sync(
|
||||
framebuffer,
|
||||
&[Damage {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width,
|
||||
height,
|
||||
}],
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@ authors = ["Anhad Singh <andypython@protonmail.com>"]
|
||||
anyhow = "1.0.71"
|
||||
log = "0.4.19"
|
||||
redox-daemon = "0.1.2"
|
||||
redox_syscall = "0.5"
|
||||
redox_syscall = { version = "0.5", features = ["std"] }
|
||||
orbclient = "0.3.27"
|
||||
libredox = "0.1.3"
|
||||
|
||||
|
||||
+1
-3
@@ -32,8 +32,7 @@ impl ConsumerHandle {
|
||||
pub fn open_display(&self) -> Result<File, Error> {
|
||||
let mut buffer = [0; 1024];
|
||||
let fd = self.0.as_raw_fd();
|
||||
let written = libredox::call::fpath(fd as usize, &mut buffer)
|
||||
.expect("init: failed to get the path to the display device");
|
||||
let written = libredox::call::fpath(fd as usize, &mut buffer)?;
|
||||
|
||||
assert!(written <= buffer.len());
|
||||
|
||||
@@ -119,7 +118,6 @@ impl ControlHandle {
|
||||
#[repr(usize)]
|
||||
pub enum VtEventKind {
|
||||
Activate,
|
||||
Deactivate,
|
||||
Resize,
|
||||
}
|
||||
|
||||
|
||||
+16
-28
@@ -120,19 +120,6 @@ impl InputScheme {
|
||||
device,
|
||||
..
|
||||
} => {
|
||||
if let Some(active_vt) = self.active_vt {
|
||||
if &self.vts[&active_vt].display == &*device {
|
||||
pending.push(VtEvent {
|
||||
kind: VtEventKind::Deactivate,
|
||||
vt: self.active_vt.unwrap(),
|
||||
width: 0,
|
||||
height: 0,
|
||||
stride: 0,
|
||||
});
|
||||
*notified = false;
|
||||
}
|
||||
}
|
||||
|
||||
if &self.vts[&new_active].display == &*device {
|
||||
pending.push(VtEvent {
|
||||
kind: VtEventKind::Activate,
|
||||
@@ -420,23 +407,24 @@ impl Scheme for InputScheme {
|
||||
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
|
||||
assert!(handle.is_producer());
|
||||
|
||||
let active_vt = self.active_vt.unwrap();
|
||||
for handle in self.handles.values_mut() {
|
||||
match handle {
|
||||
Handle::Consumer {
|
||||
pending,
|
||||
notified,
|
||||
vt,
|
||||
..
|
||||
} => {
|
||||
if *vt != active_vt {
|
||||
continue;
|
||||
}
|
||||
if let Some(active_vt) = self.active_vt {
|
||||
for handle in self.handles.values_mut() {
|
||||
match handle {
|
||||
Handle::Consumer {
|
||||
pending,
|
||||
notified,
|
||||
vt,
|
||||
..
|
||||
} => {
|
||||
if *vt != active_vt {
|
||||
continue;
|
||||
}
|
||||
|
||||
pending.extend_from_slice(buf);
|
||||
*notified = false;
|
||||
pending.extend_from_slice(buf);
|
||||
*notified = false;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user