Merge branch 'graphics_improvements' into 'master'
Various improvements to the graphics subsystem See merge request redox-os/drivers!276
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
#![feature(slice_as_array)]
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::mem::transmute;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -53,6 +54,7 @@ pub struct GraphicsScheme<T: GraphicsAdapter> {
|
||||
adapter: T,
|
||||
|
||||
scheme_name: String,
|
||||
disable_graphical_debug: Option<File>,
|
||||
socket: Socket,
|
||||
next_id: usize,
|
||||
handles: BTreeMap<usize, Handle<T>>,
|
||||
@@ -83,9 +85,15 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
assert!(scheme_name.starts_with("display"));
|
||||
let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme");
|
||||
|
||||
let disable_graphical_debug = Some(
|
||||
File::open("/scheme/debug/disable-graphical-debug")
|
||||
.expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"),
|
||||
);
|
||||
|
||||
GraphicsScheme {
|
||||
adapter,
|
||||
scheme_name,
|
||||
disable_graphical_debug,
|
||||
socket,
|
||||
next_id: 0,
|
||||
handles: BTreeMap::new(),
|
||||
@@ -111,6 +119,14 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
VtEventKind::Activate => {
|
||||
log::info!("activate {}", vt_event.vt);
|
||||
|
||||
// Disable the kernel graphical debug writing once switching vt's for the
|
||||
// first time. This way the kernel graphical debug remains enabled if the
|
||||
// userspace logging infrastructure doesn't start up because for example a
|
||||
// kernel panic happened prior to it starting up or logd crashed.
|
||||
if let Some(mut disable_graphical_debug) = self.disable_graphical_debug.take() {
|
||||
let _ = disable_graphical_debug.write(&[1]);
|
||||
}
|
||||
|
||||
self.active_vt = vt_event.vt;
|
||||
|
||||
let vt_state =
|
||||
@@ -480,6 +496,23 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
|
||||
Ok(size_of::<ipc::DumbFramebufferMapOffset>())
|
||||
}
|
||||
ipc::DESTROY_DUMB_FRAMEBUFFER => {
|
||||
if payload.len() < size_of::<ipc::DestroyDumbFramebuffer>() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let payload = unsafe {
|
||||
transmute::<
|
||||
&mut [u8; size_of::<ipc::DestroyDumbFramebuffer>()],
|
||||
&mut ipc::DestroyDumbFramebuffer,
|
||||
>(payload.as_mut_array().unwrap())
|
||||
};
|
||||
|
||||
if fbs.remove(&{ payload.fb_id }).is_none() {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
Ok(size_of::<ipc::DestroyDumbFramebuffer>())
|
||||
}
|
||||
ipc::UPDATE_PLANE => {
|
||||
if payload.len() < size_of::<ipc::UpdatePlane>() {
|
||||
return Err(Error::new(EINVAL));
|
||||
|
||||
@@ -95,6 +95,8 @@ impl FbbootlogScheme {
|
||||
},
|
||||
);
|
||||
|
||||
let _ = map.display_handle.destroy_dumb_framebuffer(map.fb);
|
||||
|
||||
map.fb = fb;
|
||||
map.inner = new_map;
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ impl Display {
|
||||
|
||||
/// Re-open the display after a handoff.
|
||||
pub fn reopen_for_handoff(&mut self) {
|
||||
let new_display_handle = Self::open_display(&self.input_handle).unwrap();
|
||||
let display_file = self.input_handle.open_display().unwrap();
|
||||
let new_display_handle = V1GraphicsHandle::from_file(display_file).unwrap();
|
||||
|
||||
eprintln!("fbcond: Opened new display");
|
||||
|
||||
@@ -49,12 +50,6 @@ impl Display {
|
||||
}
|
||||
}
|
||||
|
||||
fn open_display(input_handle: &ConsumerHandle) -> io::Result<V1GraphicsHandle> {
|
||||
let display_file = input_handle.open_display()?;
|
||||
|
||||
V1GraphicsHandle::from_file(display_file)
|
||||
}
|
||||
|
||||
pub fn sync_rect(&mut self, sync_rect: Damage) {
|
||||
if let Some(map) = &self.map {
|
||||
map.display_handle.sync_rect(sync_rect).unwrap();
|
||||
|
||||
@@ -11,6 +11,8 @@ pub use crate::common::DisplayMap;
|
||||
///
|
||||
/// The v1 graphics API only allows a single framebuffer for each VT, requires each display to be
|
||||
/// handled separately and doesn't support page flipping.
|
||||
///
|
||||
/// This API is stable. No breaking changes are allowed to be made without a version bump.
|
||||
pub struct V1GraphicsHandle {
|
||||
file: File,
|
||||
}
|
||||
|
||||
@@ -33,10 +33,13 @@ unsafe fn sys_call<T>(
|
||||
))
|
||||
}
|
||||
|
||||
/// A graphics handle using the (currently unstable) v2 graphics API.
|
||||
/// A graphics handle using the v2 graphics API.
|
||||
///
|
||||
/// The v2 graphics API allows creating framebuffers on the fly, using them for page flipping and
|
||||
/// handles all displays using a single fd.
|
||||
///
|
||||
/// This API is not yet stable. Do not depend on it outside of the drivers repo until it has been
|
||||
/// stabilized.
|
||||
pub struct V2GraphicsHandle {
|
||||
file: File,
|
||||
}
|
||||
@@ -121,6 +124,19 @@ impl V2GraphicsHandle {
|
||||
Ok(unsafe { DisplayMap::new(offscreen, width as usize, height as usize) })
|
||||
}
|
||||
|
||||
pub fn destroy_dumb_framebuffer(&self, id: usize) -> io::Result<usize> {
|
||||
let mut cmd = ipc::DestroyDumbFramebuffer { fb_id: id };
|
||||
unsafe {
|
||||
sys_call(
|
||||
&self.file,
|
||||
&mut cmd,
|
||||
0,
|
||||
&[ipc::DESTROY_DUMB_FRAMEBUFFER, 0, 0],
|
||||
)?;
|
||||
}
|
||||
Ok(cmd.fb_id)
|
||||
}
|
||||
|
||||
pub fn update_plane(&self, display_id: usize, fb_id: usize, damage: Damage) -> io::Result<()> {
|
||||
let mut cmd = ipc::UpdatePlane {
|
||||
display_id,
|
||||
@@ -169,7 +185,13 @@ pub mod ipc {
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
pub const UPDATE_PLANE: u64 = 5;
|
||||
pub const DESTROY_DUMB_FRAMEBUFFER: u64 = 5;
|
||||
#[repr(C, packed)]
|
||||
pub struct DestroyDumbFramebuffer {
|
||||
pub fb_id: usize,
|
||||
}
|
||||
|
||||
pub const UPDATE_PLANE: u64 = 6;
|
||||
#[repr(C, packed)]
|
||||
pub struct UpdatePlane {
|
||||
pub display_id: usize,
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
use std::ptr;
|
||||
|
||||
pub struct FrameBuffer {
|
||||
pub onscreen: *mut [u32],
|
||||
pub phys: usize,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub stride: usize,
|
||||
}
|
||||
|
||||
impl FrameBuffer {
|
||||
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;
|
||||
|
||||
let onscreen = ptr::slice_from_raw_parts_mut(virt, size);
|
||||
|
||||
Self {
|
||||
onscreen,
|
||||
phys,
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
(0, 10)
|
||||
};
|
||||
match usize::from_str_radix(&part[start..], radix) {
|
||||
Ok(ok) => Some(ok),
|
||||
Err(err) => {
|
||||
eprintln!("vesad: failed to parse '{}': {}", part, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut parts = var.split(',');
|
||||
let phys = parse_number(parts.next()?)?;
|
||||
let width = parse_number(parts.next()?)?;
|
||||
let height = parse_number(parts.next()?)?;
|
||||
let stride = parse_number(parts.next()?)?;
|
||||
Some(Self::new(phys, width, height, stride))
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,12 @@ extern crate syscall;
|
||||
|
||||
use driver_graphics::GraphicsScheme;
|
||||
use event::{user_data, EventQueue};
|
||||
use inputd::{DisplayHandle, VtEventKind};
|
||||
use inputd::DisplayHandle;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
use crate::scheme::FbAdapter;
|
||||
use crate::scheme::{FbAdapter, FrameBuffer};
|
||||
|
||||
mod framebuffer;
|
||||
mod scheme;
|
||||
|
||||
fn main() {
|
||||
@@ -105,11 +101,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>) -> ! {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut disable_graphical_debug = Some(
|
||||
File::open("/scheme/debug/disable-graphical-debug")
|
||||
.expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"),
|
||||
);
|
||||
|
||||
libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace");
|
||||
|
||||
daemon.ready().expect("failed to notify parent");
|
||||
@@ -125,16 +116,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec<FrameBuffer>) -> ! {
|
||||
.read_vt_event()
|
||||
.expect("vesad: failed to read display handle")
|
||||
{
|
||||
if let VtEventKind::Activate = vt_event.kind {
|
||||
// Disable the kernel graphical debug writing once switching vt's for the
|
||||
// first time. This way the kernel graphical debug remains enabled if the
|
||||
// userspace logging infrastructure doesn't start up because for example a
|
||||
// kernel panic happened prior to it starting up or logd crashed.
|
||||
if let Some(mut disable_graphical_debug) = disable_graphical_debug.take() {
|
||||
let _ = disable_graphical_debug.write(&[1]);
|
||||
}
|
||||
}
|
||||
|
||||
scheme.handle_vt_event(vt_event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapt
|
||||
use graphics_ipc::v1::Damage;
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
|
||||
pub struct FbAdapter {
|
||||
pub framebuffers: Vec<FrameBuffer>,
|
||||
}
|
||||
@@ -60,6 +58,64 @@ impl GraphicsAdapter for FbAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FrameBuffer {
|
||||
pub onscreen: *mut [u32],
|
||||
pub phys: usize,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub stride: usize,
|
||||
}
|
||||
|
||||
impl FrameBuffer {
|
||||
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;
|
||||
|
||||
let onscreen = ptr::slice_from_raw_parts_mut(virt, size);
|
||||
|
||||
Self {
|
||||
onscreen,
|
||||
phys,
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
} else {
|
||||
(0, 10)
|
||||
};
|
||||
match usize::from_str_radix(&part[start..], radix) {
|
||||
Ok(ok) => Some(ok),
|
||||
Err(err) => {
|
||||
eprintln!("vesad: failed to parse '{}': {}", part, err);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut parts = var.split(',');
|
||||
let phys = parse_number(parts.next()?)?;
|
||||
let width = parse_number(parts.next()?)?;
|
||||
let height = parse_number(parts.next()?)?;
|
||||
let stride = parse_number(parts.next()?)?;
|
||||
Some(Self::new(phys, width, height, stride))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GraphicScreen {
|
||||
width: usize,
|
||||
height: usize,
|
||||
|
||||
Reference in New Issue
Block a user