4c4ab2de44
With this virtio-gpud no longer has to support getting deactivated at any time to hand back control to vesad. This makes it much easier to add many new features that a proper graphics driver is supposed to support. Be aware that virtio-gpud waits for the vsync on every flush request. Fbcond and orbital are not really happy about this right now and when something changes multiple times within a single frame, flush requests queue up, causing the ui to hang until all flush requests are finished. It is still possible to switch to another VT though which won't hang.
204 lines
6.4 KiB
Rust
204 lines
6.4 KiB
Rust
#![feature(io_error_more)]
|
|
|
|
use event::EventQueue;
|
|
use orbclient::Event;
|
|
use std::fs::{File, OpenOptions};
|
|
use std::io::{ErrorKind, Read, Write};
|
|
use std::os::fd::AsRawFd;
|
|
use std::os::unix::fs::OpenOptionsExt;
|
|
use std::{env, io, mem, slice};
|
|
use syscall::{Packet, SchemeMut, EVENT_READ, O_NONBLOCK};
|
|
|
|
use crate::scheme::{FbconScheme, VtIndex};
|
|
|
|
mod display;
|
|
mod scheme;
|
|
mod text;
|
|
|
|
fn read_to_slice<R: Read, T: Copy>(mut r: R, buf: &mut [T]) -> io::Result<usize> {
|
|
unsafe {
|
|
r.read(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>())
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let vt_ids = env::args()
|
|
.skip(1)
|
|
.map(|arg| arg.parse().expect("invalid vt number"))
|
|
.collect::<Vec<_>>();
|
|
|
|
redox_daemon::Daemon::new(|daemon| inner(daemon, &vt_ids)).expect("failed to create daemon");
|
|
}
|
|
fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! {
|
|
let mut event_queue = EventQueue::new().expect("fbcond: failed to create event queue");
|
|
|
|
// FIXME listen for resize events from inputd and handle them
|
|
|
|
let mut socket = OpenOptions::new()
|
|
.write(true)
|
|
.create(true)
|
|
.truncate(true)
|
|
.custom_flags(O_NONBLOCK as i32)
|
|
.open(":fbcon")
|
|
.expect("fbcond: failed to create fbcon scheme");
|
|
event_queue
|
|
.subscribe(
|
|
socket.as_raw_fd().as_raw_fd() as usize,
|
|
VtIndex::SCHEMA_SENTINEL,
|
|
event::EventFlags::READ,
|
|
)
|
|
.expect("fbcond: failed to subscribe to scheme events");
|
|
|
|
let mut scheme = FbconScheme::new(vt_ids, &mut event_queue);
|
|
|
|
let mut inputd_control_handle = inputd::ControlHandle::new().unwrap();
|
|
|
|
// This is not possible for now as fbcond needs to open new displays at runtime for graphics
|
|
// driver handoff. In the future inputd may directly pass a handle to the display instead.
|
|
//libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace");
|
|
|
|
daemon.ready().expect("failed to notify parent");
|
|
|
|
inputd_control_handle.activate_vt(1).unwrap();
|
|
|
|
let mut blocked = Vec::new();
|
|
|
|
// Handle all events that could have happened before registering with the event queue.
|
|
handle_event(
|
|
&mut socket,
|
|
&mut scheme,
|
|
&mut blocked,
|
|
VtIndex::SCHEMA_SENTINEL,
|
|
);
|
|
for vt_i in scheme.vts.keys().copied().collect::<Vec<_>>() {
|
|
handle_event(&mut socket, &mut scheme, &mut blocked, vt_i);
|
|
}
|
|
|
|
for event in event_queue {
|
|
let event = event.expect("fbcond: failed to read event from event queue");
|
|
handle_event(&mut socket, &mut scheme, &mut blocked, event.user_data);
|
|
}
|
|
|
|
std::process::exit(0);
|
|
}
|
|
|
|
fn handle_event(
|
|
socket: &mut File,
|
|
scheme: &mut FbconScheme,
|
|
blocked: &mut Vec<Packet>,
|
|
event: VtIndex,
|
|
) {
|
|
match event {
|
|
VtIndex::SCHEMA_SENTINEL => {
|
|
loop {
|
|
let mut packet = Packet::default();
|
|
match socket.read(&mut packet) {
|
|
Ok(0) => break,
|
|
Err(err) if err.kind() == ErrorKind::WouldBlock => {
|
|
break;
|
|
}
|
|
Ok(_) => {}
|
|
Err(err) => {
|
|
panic!("fbcond: failed to read display scheme: {err}");
|
|
}
|
|
}
|
|
|
|
// If it is a read packet, and there is no data, block it. Otherwise, handle packet
|
|
if packet.a == syscall::number::SYS_READ
|
|
&& packet.d > 0
|
|
&& scheme.can_read(packet.b).is_none()
|
|
{
|
|
blocked.push(packet);
|
|
} else {
|
|
scheme.handle(&mut packet);
|
|
socket
|
|
.write(&packet)
|
|
.expect("fbcond: failed to write display scheme");
|
|
}
|
|
}
|
|
}
|
|
vt_i => {
|
|
let vt = scheme.vts.get_mut(&vt_i).unwrap();
|
|
|
|
let mut events = [Event::new(); 16];
|
|
loop {
|
|
match read_to_slice(&mut vt.display.input_handle, &mut events) {
|
|
Ok(0) => break,
|
|
Err(err) if err.kind() == ErrorKind::WouldBlock => {
|
|
break;
|
|
}
|
|
Err(err) if err.kind() == ErrorKind::StaleNetworkFileHandle => {
|
|
vt.handle_handoff();
|
|
}
|
|
|
|
Ok(count) => {
|
|
let events = &mut events[..count];
|
|
for event in events.iter_mut() {
|
|
vt.input(event)
|
|
}
|
|
}
|
|
Err(err) => {
|
|
panic!("fbcond: Error while reading events: {err}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If there are blocked readers, and data is available, handle them
|
|
{
|
|
let mut i = 0;
|
|
while i < blocked.len() {
|
|
if scheme.can_read(blocked[i].b).is_some() {
|
|
let mut packet = blocked.remove(i);
|
|
scheme.handle(&mut packet);
|
|
socket
|
|
.write(&packet)
|
|
.expect("fbcond: failed to write display scheme");
|
|
} else {
|
|
i += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (handle_id, handle) in scheme.handles.iter_mut() {
|
|
if !handle.events.contains(EVENT_READ) {
|
|
continue;
|
|
}
|
|
|
|
// Can't use scheme.can_read() because we borrow handles as mutable.
|
|
// (and because it'd treat O_NONBLOCK sockets differently)
|
|
let count = scheme
|
|
.vts
|
|
.get(&handle.vt_i)
|
|
.and_then(|console| console.can_read())
|
|
.unwrap_or(0);
|
|
|
|
if count > 0 {
|
|
if !handle.notified_read {
|
|
handle.notified_read = true;
|
|
let event_packet = Packet {
|
|
id: 0,
|
|
pid: 0,
|
|
uid: 0,
|
|
gid: 0,
|
|
a: syscall::number::SYS_FEVENT,
|
|
b: *handle_id,
|
|
c: EVENT_READ.bits(),
|
|
d: count,
|
|
};
|
|
|
|
socket
|
|
.write(&event_packet)
|
|
.expect("fbcond: failed to write display event");
|
|
}
|
|
} else {
|
|
handle.notified_read = false;
|
|
}
|
|
}
|
|
}
|