Merge branch 'misc_changes' into 'master'

graphics: Couple of misc changes

See merge request redox-os/drivers!215
This commit is contained in:
Jeremy Soller
2024-12-24 14:17:43 +00:00
7 changed files with 104 additions and 237 deletions
+16 -51
View File
@@ -1,18 +1,9 @@
use inputd::Damage;
use inputd::{ConsumerHandle, Damage};
use libredox::flag;
use std::fs::OpenOptions;
use std::mem;
use std::os::unix::fs::OpenOptionsExt;
use std::sync::mpsc::{self, Sender};
use std::sync::{Arc, Mutex};
use std::{
fs::File,
io,
os::fd::RawFd,
os::unix::io::{AsRawFd, FromRawFd},
slice,
};
use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR};
use std::{fs::File, io, os::unix::io::AsRawFd, slice};
fn display_fd_map(
width: usize,
@@ -60,34 +51,30 @@ impl Drop for DisplayMap {
enum DisplayCommand {
Resize { width: usize, height: usize },
ReopenForHandoff { display_path: String },
ReopenForHandoff,
SyncRects(Vec<Damage>),
}
pub struct Display {
pub input_handle: File,
pub input_handle: Arc<ConsumerHandle>,
cmd_tx: Sender<DisplayCommand>,
pub map: Arc<Mutex<DisplayMap>>,
}
impl Display {
pub fn open_vt(vt: usize) -> io::Result<Self> {
let mut input_handle = OpenOptions::new()
.read(true)
.custom_flags(O_NONBLOCK as i32)
.open(format!("/scheme/input/consumer/{vt}"))?;
let input_handle = Arc::new(ConsumerHandle::for_vt(vt)?);
let display_path = Self::display_path(&mut input_handle)?;
let (mut display_file, width, height) = Self::open_display(&display_path)?;
let (mut display_file, width, height) = Self::open_display(&input_handle)?;
let map = Arc::new(Mutex::new(
display_fd_map(width, height, &mut display_file)
.unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")),
.unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")),
));
let (cmd_tx, cmd_rx) = mpsc::channel();
let input_handle_clone = input_handle.clone();
let map_clone = map.clone();
std::thread::spawn(move || {
while let Ok(cmd) = cmd_rx.recv() {
@@ -105,20 +92,20 @@ impl Display {
}
}
}
DisplayCommand::ReopenForHandoff { display_path } => {
eprintln!("fbcond: Performing handoff for '{display_path}'");
DisplayCommand::ReopenForHandoff => {
eprintln!("fbcond: Performing handoff");
let (mut new_display_file, width, height) =
Self::open_display(&display_path).unwrap();
Self::open_display(&input_handle_clone).unwrap();
eprintln!("fbcond: Opened new display '{display_path}'");
eprintln!("fbcond: Opened new display for VT #{vt}");
match display_fd_map(width, height, &mut new_display_file) {
Ok(ok) => {
*map_clone.lock().unwrap() = ok;
display_file = new_display_file;
eprintln!("fbcond: Mapped new display '{display_path}'");
eprintln!("fbcond: Mapped new display for VT #{vt}");
}
Err(err) => {
eprintln!(
@@ -156,33 +143,11 @@ impl Display {
/// Warning: This must be called in a background thread to avoid a deadlock when the
/// graphics driver (indirectly) writes logs to fbcond.
pub fn reopen_for_handoff(&mut self) {
let display_path = Self::display_path(&mut self.input_handle).unwrap();
self.cmd_tx
.send(DisplayCommand::ReopenForHandoff { display_path })
.unwrap();
self.cmd_tx.send(DisplayCommand::ReopenForHandoff).unwrap();
}
fn display_path(input_handle: &mut File) -> io::Result<String> {
let mut buffer = [0; 1024];
let fd = input_handle.as_raw_fd();
let written = libredox::call::fpath(fd as usize, &mut buffer)
.expect("init: failed to get the path to the display device");
assert!(written <= buffer.len());
Ok(std::str::from_utf8(&buffer[..written])
.expect("init: display path UTF-8 check failed")
.to_owned())
}
fn open_display(display_path: &str) -> io::Result<(File, usize, usize)> {
let display_file =
libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0)
.map(|socket| unsafe { File::from_raw_fd(socket as RawFd) })
.unwrap_or_else(|err| {
panic!("failed to open display {}: {}", display_path, err);
});
fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> {
let display_file = input_handle.open_display()?;
let mut buf: [u8; 4096] = [0; 4096];
let count = libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf)
+13 -12
View File
@@ -1,12 +1,13 @@
#![feature(io_error_more)]
use event::EventQueue;
use libredox::errno::ESTALE;
use orbclient::Event;
use std::fs::{File, OpenOptions};
use std::io::{ErrorKind, Read, Write};
use std::os::fd::AsRawFd;
use std::os::fd::{AsRawFd, BorrowedFd};
use std::os::unix::fs::OpenOptionsExt;
use std::{env, io, mem, slice};
use std::{env, mem, slice};
use syscall::{Packet, SchemeMut, EVENT_READ, O_NONBLOCK};
use crate::scheme::{FbconScheme, VtIndex};
@@ -15,12 +16,15 @@ mod display;
mod scheme;
mod text;
fn read_to_slice<R: Read, T: Copy>(mut r: R, buf: &mut [T]) -> io::Result<usize> {
fn read_to_slice<T: Copy>(
file: BorrowedFd,
buf: &mut [T],
) -> Result<usize, libredox::error::Error> {
unsafe {
r.read(slice::from_raw_parts_mut(
buf.as_mut_ptr() as *mut u8,
buf.len() * mem::size_of::<T>(),
))
libredox::call::read(
file.as_raw_fd() as usize,
slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::<T>()),
)
.map(|count| count / mem::size_of::<T>())
}
}
@@ -126,12 +130,9 @@ fn handle_event(
let mut events = [Event::new(); 16];
loop {
match read_to_slice(&mut vt.display.input_handle, &mut events) {
match read_to_slice(vt.display.input_handle.inner(), &mut events) {
Ok(0) => break,
Err(err) if err.kind() == ErrorKind::WouldBlock => {
break;
}
Err(err) if err.kind() == ErrorKind::StaleNetworkFileHandle => {
Err(err) if err.errno() == ESTALE => {
vt.handle_handoff();
}
+1 -1
View File
@@ -46,7 +46,7 @@ impl FbconScheme {
let display = Display::open_vt(vt_i).expect("Failed to open display for vt");
event_queue
.subscribe(
display.input_handle.as_raw_fd().as_raw_fd() as usize,
display.input_handle.inner().as_raw_fd() as usize,
VtIndex(vt_i),
event::EventFlags::READ,
)
+9 -59
View File
@@ -3,12 +3,11 @@ extern crate orbclient;
extern crate syscall;
use event::{user_data, EventQueue};
use libredox::errno::{EAGAIN, EINTR};
use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2};
use libredox::errno::EAGAIN;
use redox_scheme::{RequestKind, SignalBehavior, Socket, V2};
use std::env;
use std::fs::File;
use std::os::fd::AsRawFd;
use syscall::EVENT_READ;
use crate::{framebuffer::FrameBuffer, scheme::DisplayScheme};
@@ -118,7 +117,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[(
inputd_control_handle.activate_vt(1).unwrap();
let mut blocked = Vec::new();
let all = [Source::Input, Source::Scheme];
for event in all
.into_iter()
@@ -148,66 +146,18 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>, spec: &[(
match request.kind() {
RequestKind::Call(call_request) => {
if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) {
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
} else {
blocked.push(call_request);
}
}
RequestKind::Cancellation(cancellation_request) => {
if let Some(i) = blocked.iter().position(|req| {
req.request().request_id() == cancellation_request.id
}) {
let blocked_req = blocked.remove(i);
let resp =
Response::new(&blocked_req, Err(syscall::Error::new(EINTR)));
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
}
socket
.write_response(
call_request.handle_scheme_mut(&mut scheme),
SignalBehavior::Restart,
)
.expect("vesad: failed to write display scheme");
}
RequestKind::Cancellation(_cancellation_request) => {}
RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => {
unreachable!()
}
}
// If there are blocked readers, try to handle them.
{
let mut i = 0;
while i < blocked.len() {
if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) {
socket
.write_response(resp, SignalBehavior::Restart)
.expect("vesad: failed to write display scheme");
blocked.remove(i);
} else {
i += 1;
}
}
}
for (handle_id, handle) in scheme.handles.iter_mut() {
if handle.notified_read || !handle.events.contains(EVENT_READ) {
continue;
}
let can_read = scheme
.vts
.get(&handle.vt)
.and_then(|screens| screens.get(&handle.screen))
.map_or(false, |screen| screen.can_read());
if can_read {
handle.notified_read = true;
socket
.post_fevent(*handle_id, EVENT_READ.bits())
.expect("vesad: failed to write display event");
} else {
handle.notified_read = false;
}
}
}
}
}
+22 -77
View File
@@ -2,8 +2,8 @@ use std::collections::BTreeMap;
use std::str;
use inputd::{VtEvent, VtEventKind};
use redox_scheme::SchemeBlockMut;
use syscall::{Error, EventFlags, MapFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK};
use redox_scheme::SchemeMut;
use syscall::{Error, MapFlags, Result, EBADF, EINVAL, ENOENT};
use crate::{framebuffer::FrameBuffer, screen::GraphicScreen};
@@ -17,10 +17,6 @@ pub struct ScreenIndex(usize);
pub struct Handle {
pub vt: VtIndex,
pub screen: ScreenIndex,
pub flags: usize,
pub events: EventFlags,
pub notified_read: bool,
}
pub struct DisplayScheme {
@@ -109,14 +105,8 @@ impl DisplayScheme {
}
}
impl SchemeBlockMut for DisplayScheme {
fn open(
&mut self,
path_str: &str,
flags: usize,
_uid: u32,
_gid: u32,
) -> Result<Option<usize>> {
impl SchemeMut for DisplayScheme {
fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
let mut parts = path_str.split('/');
let mut vt_screen = parts.next().unwrap_or("").split('.');
let vt_i = VtIndex(vt_screen.next().unwrap_or("").parse::<usize>().unwrap_or(1));
@@ -131,14 +121,10 @@ impl SchemeBlockMut for DisplayScheme {
Handle {
vt: vt_i,
screen: screen_i,
flags,
events: EventFlags::empty(),
notified_read: false,
},
);
Ok(Some(id))
Ok(id)
} else {
Err(Error::new(ENOENT))
}
@@ -147,7 +133,7 @@ impl SchemeBlockMut for DisplayScheme {
}
}
fn dup(&mut self, id: usize, buf: &[u8]) -> Result<Option<usize>> {
fn dup(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
if !buf.is_empty() {
return Err(Error::new(EINVAL));
}
@@ -163,22 +149,10 @@ impl SchemeBlockMut for DisplayScheme {
self.handles.insert(new_id, handle.clone());
Ok(Some(new_id))
Ok(new_id)
}
fn fevent(
&mut self,
id: usize,
flags: syscall::EventFlags,
) -> Result<Option<syscall::EventFlags>> {
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
handle.notified_read = false;
handle.events = flags;
Ok(Some(syscall::EventFlags::empty()))
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
let path_str = {
@@ -204,10 +178,10 @@ impl SchemeBlockMut for DisplayScheme {
i += 1;
}
Ok(Some(i))
Ok(i)
}
fn fsync(&mut self, id: usize) -> Result<Option<usize>> {
fn fsync(&mut self, id: usize) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Some(screens) = self.vts.get_mut(&handle.vt) {
@@ -215,7 +189,7 @@ impl SchemeBlockMut for DisplayScheme {
if handle.vt == self.active {
screen.redraw(&mut self.framebuffers[handle.screen.0]);
}
return Ok(Some(0));
return Ok(0);
}
}
@@ -225,47 +199,24 @@ impl SchemeBlockMut for DisplayScheme {
fn read(
&mut self,
id: usize,
buf: &mut [u8],
_buf: &mut [u8],
_offset: u64,
_fcntl_flags: u32,
) -> Result<Option<usize>> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
) -> Result<usize> {
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Some(screens) = self.vts.get_mut(&handle.vt) {
if let Some(screen) = screens.get_mut(&handle.screen) {
let nread = screen.read(buf)?;
if nread != 0 {
return Ok(Some(nread));
} else {
if handle.flags & O_NONBLOCK == O_NONBLOCK {
return Ok(Some(0));
} else {
return Ok(None);
}
}
}
}
Err(Error::new(EBADF))
Err(Error::new(EINVAL))
}
fn write(
&mut self,
id: usize,
buf: &[u8],
_offset: u64,
_fcntl_flags: u32,
) -> Result<Option<usize>> {
fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Some(screens) = self.vts.get_mut(&handle.vt) {
if let Some(screen) = screens.get_mut(&handle.screen) {
if handle.vt == self.active {
screen
.write(buf, Some(&mut self.framebuffers[handle.screen.0]))
.map(|count| Some(count))
screen.write(buf, Some(&mut self.framebuffers[handle.screen.0]))
} else {
screen.write(buf, None).map(|count| Some(count))
screen.write(buf, None)
}
} else {
Err(Error::new(EBADF))
@@ -275,23 +226,17 @@ impl SchemeBlockMut for DisplayScheme {
}
}
fn close(&mut self, id: usize) -> Result<Option<usize>> {
fn close(&mut self, id: usize) -> Result<usize> {
self.handles.remove(&id).ok_or(Error::new(EBADF))?;
Ok(Some(0))
Ok(0)
}
fn mmap_prep(
&mut self,
id: usize,
off: u64,
size: usize,
_flags: MapFlags,
) -> Result<Option<usize>> {
fn mmap_prep(&mut self, id: usize, off: u64, size: usize, _flags: MapFlags) -> Result<usize> {
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
if let Some(screens) = self.vts.get(&handle.vt) {
if let Some(screen) = screens.get(&handle.screen) {
if off as usize + size <= screen.offscreen.len() * 4 {
return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize));
return Ok(screen.offscreen.as_ptr() as usize + off as usize);
} else {
return Err(Error::new(EINVAL));
}
-35
View File
@@ -1,9 +1,7 @@
use std::collections::VecDeque;
use std::convert::TryInto;
use std::{cmp, mem, ptr, slice};
use inputd::Damage;
use orbclient::{Event, ResizeEvent};
use syscall::error::*;
use crate::display::OffscreenBuffer;
@@ -13,7 +11,6 @@ pub struct GraphicScreen {
pub width: usize,
pub height: usize,
pub offscreen: OffscreenBuffer,
pub input: VecDeque<Event>,
}
impl GraphicScreen {
@@ -22,7 +19,6 @@ impl GraphicScreen {
width,
height,
offscreen: OffscreenBuffer::new(width * height),
input: VecDeque::new(),
}
}
}
@@ -71,36 +67,6 @@ impl GraphicScreen {
} else {
println!("Display is already {}, {}", width, height);
};
self.input.push_back(
ResizeEvent {
width: width as u32,
height: height as u32,
}
.to_event(),
);
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let mut i = 0;
let event_buf = unsafe {
slice::from_raw_parts_mut(
buf.as_mut_ptr() as *mut Event,
buf.len() / mem::size_of::<Event>(),
)
};
while i < event_buf.len() && !self.input.is_empty() {
event_buf[i] = self.input.pop_front().unwrap();
i += 1;
}
Ok(i * mem::size_of::<Event>())
}
pub fn can_read(&self) -> bool {
!self.input.is_empty()
}
pub fn write(&mut self, buf: &[u8], framebuffer: Option<&mut FrameBuffer>) -> Result<usize> {
@@ -117,7 +83,6 @@ impl GraphicScreen {
Ok(sync_rects.len() * mem::size_of::<Damage>())
}
pub fn sync(&mut self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) {
for sync_rect in sync_rects {
let sync_rect = sync_rect.clip(
+43 -2
View File
@@ -1,10 +1,13 @@
#![feature(iter_next_chunk)]
use std::cmp;
use std::fs::File;
use std::fs::{File, OpenOptions};
use std::io::{Error, Read, Write};
use std::mem::size_of;
use std::os::fd::{AsFd, BorrowedFd};
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
use std::os::unix::fs::OpenOptionsExt;
use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR};
unsafe fn any_as_u8_slice<T: Sized>(p: &T) -> &[u8] {
std::slice::from_raw_parts((p as *const T) as *const u8, size_of::<T>())
@@ -14,6 +17,44 @@ unsafe fn any_as_u8_slice_mut<T: Sized>(p: &mut T) -> &mut [u8] {
std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::<T>())
}
pub struct ConsumerHandle(File);
impl ConsumerHandle {
pub fn for_vt(vt: usize) -> Result<Self, Error> {
let file = OpenOptions::new()
.read(true)
.custom_flags(O_NONBLOCK as i32)
.open(format!("/scheme/input/consumer/{vt}"))?;
Ok(Self(file))
}
pub fn inner(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
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");
assert!(written <= buffer.len());
let display_path = std::str::from_utf8(&buffer[..written])
.expect("init: display path UTF-8 check failed")
.to_owned();
let display_file =
libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0)
.map(|socket| unsafe { File::from_raw_fd(socket as RawFd) })
.unwrap_or_else(|err| {
panic!("failed to open display {}: {}", display_path, err);
});
Ok(display_file)
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct VtActivate {