Merge branch 'misc_graphics_changes' into 'main'
Misc graphics subsystem changes See merge request redox-os/base!74
This commit is contained in:
Generated
+1
-1
@@ -469,6 +469,7 @@ dependencies = [
|
||||
name = "console-draw"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"drm",
|
||||
"graphics-ipc",
|
||||
"orbclient",
|
||||
"ransid",
|
||||
@@ -956,7 +957,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"drm",
|
||||
"drm-fourcc",
|
||||
"libredox",
|
||||
"log",
|
||||
"redox-ioctl",
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
drm = "0.14"
|
||||
orbclient = "0.3.27"
|
||||
ransid = "0.4"
|
||||
|
||||
|
||||
@@ -2,15 +2,51 @@ extern crate ransid;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::{cmp, ptr};
|
||||
use std::{cmp, io, mem, ptr};
|
||||
|
||||
use drm::buffer::{Buffer, DrmFourcc};
|
||||
use drm::control::dumbbuffer::{DumbBuffer, DumbMapping};
|
||||
use drm::control::Device;
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v2::V2GraphicsHandle;
|
||||
use orbclient::FONT;
|
||||
|
||||
pub struct DisplayMap {
|
||||
pub offscreen: *mut [u32],
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub struct V2DisplayMap {
|
||||
pub display_handle: V2GraphicsHandle,
|
||||
pub fb: DumbBuffer,
|
||||
mapping: DumbMapping<'static>,
|
||||
}
|
||||
|
||||
impl V2DisplayMap {
|
||||
pub fn new(display_handle: V2GraphicsHandle, width: u32, height: u32) -> io::Result<Self> {
|
||||
let mut fb = display_handle.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32)?;
|
||||
|
||||
let map = display_handle.map_dumb_buffer(&mut fb)?;
|
||||
let map = unsafe { mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(map) };
|
||||
|
||||
Ok(Self {
|
||||
display_handle,
|
||||
fb,
|
||||
mapping: map,
|
||||
})
|
||||
}
|
||||
|
||||
unsafe fn console_map(&mut self) -> DisplayMap {
|
||||
DisplayMap {
|
||||
offscreen: ptr::slice_from_raw_parts_mut(
|
||||
self.mapping.as_mut_ptr() as *mut u32,
|
||||
self.mapping.len() / 4,
|
||||
),
|
||||
width: self.fb.size().0 as usize,
|
||||
height: self.fb.size().1 as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct DisplayMap {
|
||||
offscreen: *mut [u32],
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
pub struct TextScreen {
|
||||
@@ -116,7 +152,14 @@ impl TextScreen {
|
||||
}
|
||||
|
||||
impl TextScreen {
|
||||
pub fn write(&mut self, map: &mut DisplayMap, buf: &[u8], input: &mut VecDeque<u8>) -> Damage {
|
||||
pub fn write(
|
||||
&mut self,
|
||||
map: &mut V2DisplayMap,
|
||||
buf: &[u8],
|
||||
input: &mut VecDeque<u8>,
|
||||
) -> Damage {
|
||||
let map = unsafe { &mut map.console_map() };
|
||||
|
||||
let mut min_changed = map.height;
|
||||
let mut max_changed = 0;
|
||||
let mut line_changed = |line| {
|
||||
@@ -227,7 +270,7 @@ impl TextScreen {
|
||||
damage
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, old_map: &mut DisplayMap, new_map: &mut DisplayMap) {
|
||||
pub fn resize(&mut self, map: &mut V2DisplayMap, width: u32, height: u32) -> io::Result<()> {
|
||||
// FIXME fold row when target is narrower and maybe unfold when it is wider
|
||||
fn copy_row(
|
||||
old_map: &mut DisplayMap,
|
||||
@@ -244,20 +287,49 @@ impl TextScreen {
|
||||
}
|
||||
}
|
||||
|
||||
if new_map.height >= old_map.height {
|
||||
for row in 0..old_map.height {
|
||||
copy_row(old_map, new_map, row, row);
|
||||
}
|
||||
} else {
|
||||
let deleted_rows = (old_map.height - new_map.height).div_ceil(16);
|
||||
for row in 0..new_map.height {
|
||||
if row + (deleted_rows + 1) * 16 >= old_map.height {
|
||||
break;
|
||||
let mut new_fb =
|
||||
map.display_handle
|
||||
.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32)?;
|
||||
|
||||
let new_mapping = map.display_handle.map_dumb_buffer(&mut new_fb)?;
|
||||
let mut new_mapping =
|
||||
unsafe { mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(new_mapping) };
|
||||
|
||||
new_mapping.fill(0);
|
||||
|
||||
{
|
||||
let old_map = unsafe { &mut map.console_map() };
|
||||
let new_map = &mut DisplayMap {
|
||||
offscreen: ptr::slice_from_raw_parts_mut(
|
||||
new_mapping.as_mut_ptr() as *mut u32,
|
||||
new_mapping.len() / 4,
|
||||
),
|
||||
width: new_fb.size().0 as usize,
|
||||
height: new_fb.size().1 as usize,
|
||||
};
|
||||
|
||||
if new_map.height >= old_map.height {
|
||||
for row in 0..old_map.height {
|
||||
copy_row(old_map, new_map, row, row);
|
||||
}
|
||||
copy_row(old_map, new_map, row + deleted_rows * 16, row);
|
||||
} else {
|
||||
let deleted_rows = (old_map.height - new_map.height).div_ceil(16);
|
||||
for row in 0..new_map.height {
|
||||
if row + (deleted_rows + 1) * 16 >= old_map.height {
|
||||
break;
|
||||
}
|
||||
copy_row(old_map, new_map, row + deleted_rows * 16, row);
|
||||
}
|
||||
self.console.state.y = self.console.state.y.saturating_sub(deleted_rows);
|
||||
}
|
||||
self.console.state.y = self.console.state.y.saturating_sub(deleted_rows);
|
||||
}
|
||||
|
||||
let old_fb = mem::replace(&mut map.fb, new_fb);
|
||||
map.mapping = new_mapping;
|
||||
|
||||
let _ = map.display_handle.destroy_dumb_buffer(old_fb);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ use std::mem;
|
||||
use std::mem::transmute;
|
||||
use std::sync::Arc;
|
||||
|
||||
use graphics_ipc::v1::{CursorDamage, Damage};
|
||||
use graphics_ipc::v1::CursorDamage;
|
||||
use graphics_ipc::v2::Damage;
|
||||
use inputd::{VtEvent, VtEventKind};
|
||||
use libredox::Fd;
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::cmp;
|
||||
use std::collections::VecDeque;
|
||||
use std::{cmp, mem, ptr};
|
||||
|
||||
use console_draw::TextScreen;
|
||||
use console_draw::{TextScreen, V2DisplayMap};
|
||||
use drm::buffer::Buffer;
|
||||
use drm::control::dumbbuffer::{DumbBuffer, DumbMapping};
|
||||
use graphics_ipc::v2::V2GraphicsHandle;
|
||||
use drm::control::Device;
|
||||
use graphics_ipc::v2::{Damage, V2GraphicsHandle};
|
||||
use inputd::ConsumerHandle;
|
||||
use orbclient::{Event, EventOption};
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
@@ -12,28 +12,9 @@ use redox_scheme::{CallerCtx, OpenResult};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{Error, Result, EINVAL, ENOENT};
|
||||
|
||||
pub struct DisplayMap {
|
||||
display_handle: V2GraphicsHandle,
|
||||
fb: DumbBuffer,
|
||||
mapping: DumbMapping<'static>,
|
||||
}
|
||||
|
||||
impl DisplayMap {
|
||||
unsafe fn console_map(&mut self) -> console_draw::DisplayMap {
|
||||
console_draw::DisplayMap {
|
||||
offscreen: ptr::slice_from_raw_parts_mut(
|
||||
self.mapping.as_mut_ptr() as *mut u32,
|
||||
self.mapping.len() / 4,
|
||||
),
|
||||
width: self.fb.size().0 as usize,
|
||||
height: self.fb.size().1 as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FbbootlogScheme {
|
||||
pub input_handle: ConsumerHandle,
|
||||
display_map: Option<DisplayMap>,
|
||||
display_map: Option<V2DisplayMap>,
|
||||
text_screen: console_draw::TextScreen,
|
||||
text_buffer: console_draw::TextBuffer,
|
||||
is_scrollback: bool,
|
||||
@@ -68,28 +49,19 @@ impl FbbootlogScheme {
|
||||
};
|
||||
|
||||
let (width, height) = new_display_handle
|
||||
.display_size(new_display_handle.first_display().unwrap())
|
||||
.unwrap();
|
||||
let mut fb = new_display_handle
|
||||
.create_dumb_framebuffer(width, height)
|
||||
.unwrap();
|
||||
.get_connector(new_display_handle.first_display().unwrap(), true)
|
||||
.unwrap()
|
||||
.modes()[0]
|
||||
.size();
|
||||
|
||||
let display_map = match new_display_handle.map_dumb_framebuffer(&mut fb) {
|
||||
Ok(display_map) => unsafe {
|
||||
mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(display_map)
|
||||
},
|
||||
match V2DisplayMap::new(new_display_handle, width.into(), height.into()) {
|
||||
Ok(display_map) => self.display_map = Some(display_map),
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to open display: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.display_map = Some(DisplayMap {
|
||||
display_handle: new_display_handle,
|
||||
mapping: display_map,
|
||||
fb,
|
||||
});
|
||||
|
||||
eprintln!("fbbootlogd: mapped display");
|
||||
}
|
||||
|
||||
@@ -145,46 +117,44 @@ impl FbbootlogScheme {
|
||||
return;
|
||||
};
|
||||
let buffer_len = self.text_buffer.lines.len();
|
||||
let dmap = unsafe { &mut map.console_map() };
|
||||
// for both extra space on wrapping text and a scrollback indicator
|
||||
let spare_lines = 3;
|
||||
self.is_scrollback = true;
|
||||
self.scrollback_offset = cmp::min(
|
||||
self.scrollback_offset,
|
||||
buffer_len - dmap.height / 16 + spare_lines,
|
||||
buffer_len - map.fb.size().1 as usize / 16 + spare_lines,
|
||||
);
|
||||
let mut i = self.scrollback_offset;
|
||||
self.text_screen
|
||||
.write(dmap, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new());
|
||||
.write(map, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new());
|
||||
|
||||
let mut total_damage = Damage::NONE;
|
||||
while i < buffer_len {
|
||||
let mut damage =
|
||||
self.text_screen
|
||||
.write(dmap, &self.text_buffer.lines[i][..], &mut VecDeque::new());
|
||||
.write(map, &self.text_buffer.lines[i][..], &mut VecDeque::new());
|
||||
i += 1;
|
||||
let yd = (damage.y + damage.height) as usize;
|
||||
if i == buffer_len || yd + spare_lines * 16 > dmap.height {
|
||||
if i == buffer_len || yd + spare_lines * 16 > map.fb.size().1 as usize {
|
||||
// render until end of screen
|
||||
damage.height = (dmap.height as u32) - damage.y;
|
||||
map.display_handle
|
||||
.update_plane(0, u32::from(map.fb.handle()), damage)
|
||||
.unwrap();
|
||||
damage.height = map.fb.size().1 - damage.y;
|
||||
total_damage = total_damage.merge(damage);
|
||||
self.is_scrollback = i < buffer_len;
|
||||
break;
|
||||
} else {
|
||||
map.display_handle
|
||||
.update_plane(0, u32::from(map.fb.handle()), damage)
|
||||
.unwrap();
|
||||
total_damage = total_damage.merge(damage);
|
||||
}
|
||||
}
|
||||
map.display_handle
|
||||
.update_plane(0, u32::from(map.fb.handle()), total_damage)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) {
|
||||
let (width, height) = match map
|
||||
.display_handle
|
||||
.first_display()
|
||||
.and_then(|handle| map.display_handle.display_size(handle))
|
||||
{
|
||||
Ok((width, height)) => (width, height),
|
||||
fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) {
|
||||
let (width, height) = match map.display_handle.first_display().and_then(|handle| {
|
||||
Ok(map.display_handle.get_connector(handle, true)?.modes()[0].size())
|
||||
}) {
|
||||
Ok((width, height)) => (width.into(), height.into()),
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to get display size: {}", err);
|
||||
map.fb.size()
|
||||
@@ -192,41 +162,10 @@ impl FbbootlogScheme {
|
||||
};
|
||||
|
||||
if (width, height) != map.fb.size() {
|
||||
match map.display_handle.create_dumb_framebuffer(width, height) {
|
||||
Ok(mut fb) => {
|
||||
let mut new_map = match map.display_handle.map_dumb_framebuffer(&mut fb) {
|
||||
Ok(new_map) => unsafe {
|
||||
mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(new_map)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to open display: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
new_map.fill(0);
|
||||
|
||||
text_screen.resize(
|
||||
unsafe { &mut map.console_map() },
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: ptr::slice_from_raw_parts_mut(
|
||||
new_map.as_mut_ptr() as *mut u32,
|
||||
new_map.len() / 4,
|
||||
),
|
||||
width: fb.size().0 as usize,
|
||||
height: fb.size().1 as usize,
|
||||
},
|
||||
);
|
||||
|
||||
let old_fb = mem::replace(&mut map.fb, fb);
|
||||
map.mapping = new_map;
|
||||
|
||||
let _ = map.display_handle.destroy_dumb_framebuffer(old_fb);
|
||||
|
||||
eprintln!("fbbootlogd: mapped display");
|
||||
}
|
||||
match text_screen.resize(map, width, height) {
|
||||
Ok(()) => eprintln!("fbbootlogd: mapped display"),
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to create framebuffer: {}", err);
|
||||
eprintln!("fbbootlogd: failed to create or map framebuffer: {}", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -286,11 +225,7 @@ impl SchemeSync for FbbootlogScheme {
|
||||
self.text_buffer.write(buf);
|
||||
|
||||
if !self.is_scrollback {
|
||||
let damage = self.text_screen.write(
|
||||
unsafe { &mut map.console_map() },
|
||||
buf,
|
||||
&mut VecDeque::new(),
|
||||
);
|
||||
let damage = self.text_screen.write(map, buf, &mut VecDeque::new());
|
||||
|
||||
if let Some(map) = &self.display_map {
|
||||
map.display_handle
|
||||
|
||||
@@ -1,32 +1,13 @@
|
||||
use console_draw::TextScreen;
|
||||
use console_draw::{TextScreen, V2DisplayMap};
|
||||
use drm::buffer::Buffer;
|
||||
use drm::control::dumbbuffer::{DumbBuffer, DumbMapping};
|
||||
use drm::control::Device;
|
||||
use graphics_ipc::v2::{Damage, V2GraphicsHandle};
|
||||
use inputd::ConsumerHandle;
|
||||
use std::{io, mem, ptr};
|
||||
use std::io;
|
||||
|
||||
pub struct Display {
|
||||
pub input_handle: ConsumerHandle,
|
||||
pub map: Option<DisplayMap>,
|
||||
}
|
||||
|
||||
pub struct DisplayMap {
|
||||
display_handle: V2GraphicsHandle,
|
||||
fb: DumbBuffer,
|
||||
mapping: DumbMapping<'static>,
|
||||
}
|
||||
|
||||
impl DisplayMap {
|
||||
pub unsafe fn console_map(&mut self) -> console_draw::DisplayMap {
|
||||
console_draw::DisplayMap {
|
||||
offscreen: ptr::slice_from_raw_parts_mut(
|
||||
self.mapping.as_mut_ptr() as *mut u32,
|
||||
self.mapping.len() / 4,
|
||||
),
|
||||
width: self.fb.size().0 as usize,
|
||||
height: self.fb.size().1 as usize,
|
||||
}
|
||||
}
|
||||
pub map: Option<V2DisplayMap>,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
@@ -49,40 +30,32 @@ impl Display {
|
||||
log::debug!("fbcond: Opened new display");
|
||||
|
||||
let (width, height) = new_display_handle
|
||||
.display_size(new_display_handle.first_display().unwrap())
|
||||
.unwrap();
|
||||
let mut fb = new_display_handle
|
||||
.create_dumb_framebuffer(width, height)
|
||||
.unwrap();
|
||||
.get_connector(new_display_handle.first_display().unwrap(), true)
|
||||
.unwrap()
|
||||
.modes()[0]
|
||||
.size();
|
||||
|
||||
let map = match new_display_handle.map_dumb_framebuffer(&mut fb) {
|
||||
Ok(map) => unsafe { mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(map) },
|
||||
match V2DisplayMap::new(new_display_handle, width.into(), height.into()) {
|
||||
Ok(map) => {
|
||||
log::debug!(
|
||||
"fbcond: Mapped new display with size {}x{}",
|
||||
map.fb.size().0,
|
||||
map.fb.size().1,
|
||||
);
|
||||
self.map = Some(map)
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!("failed to map display: {}", err);
|
||||
eprintln!("fbcond: failed to open display: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
log::debug!(
|
||||
"fbcond: Mapped new display with size {}x{}",
|
||||
fb.size().0,
|
||||
fb.size().1,
|
||||
);
|
||||
|
||||
self.map = Some(DisplayMap {
|
||||
display_handle: new_display_handle,
|
||||
fb,
|
||||
mapping: map,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) {
|
||||
let (width, height) = match map
|
||||
.display_handle
|
||||
.first_display()
|
||||
.and_then(|handle| map.display_handle.display_size(handle))
|
||||
{
|
||||
Ok((width, height)) => (width, height),
|
||||
pub fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) {
|
||||
let (width, height) = match map.display_handle.first_display().and_then(|handle| {
|
||||
Ok(map.display_handle.get_connector(handle, true)?.modes()[0].size())
|
||||
}) {
|
||||
Ok((width, height)) => (width.into(), height.into()),
|
||||
Err(err) => {
|
||||
log::error!("fbcond: failed to get display size: {}", err);
|
||||
map.fb.size()
|
||||
@@ -90,41 +63,11 @@ impl Display {
|
||||
};
|
||||
|
||||
if (width, height) != map.fb.size() {
|
||||
match map.display_handle.create_dumb_framebuffer(width, height) {
|
||||
Ok(mut fb) => {
|
||||
let mut new_map = match map.display_handle.map_dumb_framebuffer(&mut fb) {
|
||||
Ok(new_map) => unsafe {
|
||||
mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(new_map)
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("fbcond: failed to open display: {}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
new_map.fill(0);
|
||||
|
||||
text_screen.resize(
|
||||
unsafe { &mut map.console_map() },
|
||||
&mut console_draw::DisplayMap {
|
||||
offscreen: ptr::slice_from_raw_parts_mut(
|
||||
new_map.as_mut_ptr() as *mut u32,
|
||||
new_map.len() / 4,
|
||||
),
|
||||
width: fb.size().0 as usize,
|
||||
height: fb.size().1 as usize,
|
||||
},
|
||||
);
|
||||
|
||||
let old_fb = mem::replace(&mut map.fb, fb);
|
||||
map.mapping = new_map;
|
||||
|
||||
let _ = map.display_handle.destroy_dumb_framebuffer(old_fb);
|
||||
|
||||
eprintln!("fbcond: mapped display");
|
||||
}
|
||||
match text_screen.resize(map, width, height) {
|
||||
Ok(()) => eprintln!("fbcond: mapped display"),
|
||||
Err(err) => {
|
||||
log::error!("fbcond: failed to create framebuffer: {}", err);
|
||||
eprintln!("fbcond: failed to create or map framebuffer: {}", err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,9 +124,7 @@ impl TextScreen {
|
||||
if let Some(map) = &mut self.display.map {
|
||||
Display::handle_resize(map, &mut self.inner);
|
||||
|
||||
let damage = self
|
||||
.inner
|
||||
.write(unsafe { &mut map.console_map() }, buf, &mut self.input);
|
||||
let damage = self.inner.write(map, buf, &mut self.input);
|
||||
|
||||
self.display.sync_rect(damage);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
drm = "0.14"
|
||||
drm-fourcc = "2.2.0"
|
||||
log = "0.4"
|
||||
libredox = "0.1.3"
|
||||
redox-ioctl = { git = "https://gitlab.redox-os.org/redox-os/relibc.git" }
|
||||
|
||||
@@ -13,6 +13,35 @@ pub struct Damage {
|
||||
}
|
||||
|
||||
impl Damage {
|
||||
pub const NONE: Self = Damage {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
|
||||
pub fn merge(self, other: Self) -> Self {
|
||||
if self.width == 0 || self.height == 0 {
|
||||
return other;
|
||||
}
|
||||
|
||||
if other.width == 0 || other.height == 0 {
|
||||
return self;
|
||||
}
|
||||
|
||||
let x = cmp::min(self.x, other.x);
|
||||
let y = cmp::min(self.y, other.y);
|
||||
let x2 = cmp::max(self.x + self.width, other.x + other.width);
|
||||
let y2 = cmp::max(self.y + self.height, other.y + other.height);
|
||||
|
||||
Damage {
|
||||
x,
|
||||
y,
|
||||
width: x2 - x,
|
||||
height: y2 - y,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn clip(mut self, width: u32, height: u32) -> Self {
|
||||
// Clip damage
|
||||
@@ -30,46 +59,3 @@ impl Damage {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DisplayMap {
|
||||
offscreen: *mut [u32],
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
impl DisplayMap {
|
||||
pub(crate) unsafe fn new(offscreen: *mut [u32], width: usize, height: usize) -> Self {
|
||||
DisplayMap {
|
||||
offscreen,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptr(&self) -> *const [u32] {
|
||||
self.offscreen
|
||||
}
|
||||
|
||||
pub fn ptr_mut(&mut self) -> *mut [u32] {
|
||||
self.offscreen
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for DisplayMap {}
|
||||
unsafe impl Sync for DisplayMap {}
|
||||
|
||||
impl Drop for DisplayMap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = libredox::call::munmap(self.offscreen as *mut (), self.offscreen.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +1,4 @@
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::{io, mem, ptr, slice};
|
||||
|
||||
use libredox::flag;
|
||||
|
||||
pub use crate::common::Damage;
|
||||
pub use crate::common::DisplayMap;
|
||||
|
||||
/// A graphics handle using the v1 graphics API.
|
||||
///
|
||||
/// 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,
|
||||
}
|
||||
|
||||
impl V1GraphicsHandle {
|
||||
pub fn from_file(file: File) -> io::Result<Self> {
|
||||
Ok(V1GraphicsHandle { file })
|
||||
}
|
||||
|
||||
pub fn map_display(&self) -> io::Result<DisplayMap> {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let count =
|
||||
libredox::call::fpath(self.file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| {
|
||||
panic!("Could not read display path with fpath(): {e}");
|
||||
});
|
||||
|
||||
let url =
|
||||
String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String");
|
||||
let path = url.split(':').nth(1).expect("Could not get path from url");
|
||||
|
||||
let mut path_parts = path.split('/').skip(1);
|
||||
let width = path_parts
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.parse::<usize>()
|
||||
.unwrap_or(0);
|
||||
let height = path_parts
|
||||
.next()
|
||||
.unwrap_or("")
|
||||
.parse::<usize>()
|
||||
.unwrap_or(0);
|
||||
|
||||
let display_ptr = unsafe {
|
||||
libredox::call::mmap(libredox::call::MmapArgs {
|
||||
fd: self.file.as_raw_fd() as usize,
|
||||
offset: 0,
|
||||
length: (width * height * 4),
|
||||
prot: flag::PROT_READ | flag::PROT_WRITE,
|
||||
flags: flag::MAP_SHARED,
|
||||
addr: core::ptr::null_mut(),
|
||||
})?
|
||||
};
|
||||
let offscreen = ptr::slice_from_raw_parts_mut(display_ptr as *mut u32, width * height);
|
||||
|
||||
Ok(unsafe { DisplayMap::new(offscreen, width, height) })
|
||||
}
|
||||
|
||||
pub fn sync_full_screen(&self) -> io::Result<()> {
|
||||
libredox::call::fsync(self.file.as_raw_fd() as usize)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync_rect(&self, sync_rect: Damage) -> io::Result<()> {
|
||||
libredox::call::write(self.file.as_raw_fd() as usize, unsafe {
|
||||
slice::from_raw_parts(
|
||||
ptr::addr_of!(sync_rect).cast::<u8>(),
|
||||
mem::size_of::<Damage>(),
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
|
||||
@@ -4,12 +4,10 @@ use std::os::unix::io::AsRawFd;
|
||||
use std::{io, mem};
|
||||
|
||||
use drm::control::connector::{self, State};
|
||||
use drm::control::dumbbuffer::{DumbBuffer, DumbMapping};
|
||||
use drm::control::Device as _;
|
||||
use drm::{ClientCapability, Device as _, DriverCapability};
|
||||
use drm_fourcc::DrmFourcc;
|
||||
|
||||
pub use crate::common::{Damage, DisplayMap};
|
||||
pub use crate::common::Damage;
|
||||
|
||||
extern "C" {
|
||||
fn redox_sys_call_v0(
|
||||
@@ -75,26 +73,6 @@ impl V2GraphicsHandle {
|
||||
Err(io::Error::other("no connected display"))
|
||||
}
|
||||
|
||||
pub fn display_size(&self, handle: connector::Handle) -> io::Result<(u32, u32)> {
|
||||
let (width, height) = self.get_connector(handle, true)?.modes()[0].size();
|
||||
Ok((u32::from(width), u32::from(height)))
|
||||
}
|
||||
|
||||
pub fn create_dumb_framebuffer(&self, width: u32, height: u32) -> io::Result<DumbBuffer> {
|
||||
self.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32)
|
||||
}
|
||||
|
||||
pub fn map_dumb_framebuffer<'a>(
|
||||
&self,
|
||||
buffer: &'a mut DumbBuffer,
|
||||
) -> io::Result<DumbMapping<'a>> {
|
||||
self.map_dumb_buffer(buffer)
|
||||
}
|
||||
|
||||
pub fn destroy_dumb_framebuffer(&self, buffer: DumbBuffer) -> io::Result<()> {
|
||||
self.destroy_dumb_buffer(buffer)
|
||||
}
|
||||
|
||||
pub fn update_plane(&self, display_id: usize, fb_id: u32, damage: Damage) -> io::Result<()> {
|
||||
let mut cmd = ipc::UpdatePlane {
|
||||
display_id,
|
||||
|
||||
Reference in New Issue
Block a user