diff --git a/Cargo.lock b/Cargo.lock index 14f7edff25..e1c8cb2f68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -719,6 +719,7 @@ version = "0.1.0" dependencies = [ "console-draw", "daemon", + "drm", "graphics-ipc", "inputd", "libredox", @@ -736,6 +737,7 @@ dependencies = [ "common", "console-draw", "daemon", + "drm", "graphics-ipc", "inputd", "libredox", @@ -925,6 +927,7 @@ version = "0.1.0" dependencies = [ "common", "drm", + "drm-fourcc", "libredox", "log", "redox-ioctl", diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index b6ae903346..25d54b3593 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -83,8 +83,8 @@ enum Handle { }, V2 { vt: usize, - next_id: usize, - fbs: HashMap>, + next_id: u32, + fbs: HashMap>, }, } @@ -463,6 +463,10 @@ impl SchemeSync for GraphicsScheme { id_index(i) | (1 << 13) } + fn dumb_buffer_id(i: u32) -> u32 { + id_index(i) | (1 << 14) + } + fn modeinfo_for_size(width: u32, height: u32) -> drm_sys::drm_mode_modeinfo { let mut modeinfo = drm_sys::drm_mode_modeinfo { // The actual visible display size @@ -596,6 +600,50 @@ impl SchemeSync for GraphicsScheme { data.set_handle(fb_handle_id(i)); Ok(0) }), + ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { + if data.bpp() != 32 { + return Err(Error::new(EINVAL)); + } + + let fb = self + .adapter + .create_dumb_framebuffer(data.width(), data.height()); + + *next_id += 1; + fbs.insert(*next_id, Arc::new(fb)); + data.set_handle(dumb_buffer_id(*next_id as u32)); + data.set_pitch(data.width() * 4); + data.set_size(u64::from(data.width()) * u64::from(data.height()) * 4); + Ok(0) + }), + ipc::MODE_MAP_DUMB => ipc::DrmModeMapDumb::with(payload, |mut data| { + if data.offset() != 0 { + return Err(Error::new(EINVAL)); + } + + let fb_id = id_index(data.handle()); + + if !fbs.contains_key(&fb_id) { + return Err(Error::new(EINVAL)); + } + + // FIXME use a better scheme for creating map offsets + assert!( + ((fbs[&fb_id].width() * fbs[&fb_id].height() * 4) as usize) + < MAP_FAKE_OFFSET_MULTIPLIER + ); + + data.set_offset((fb_id as usize * MAP_FAKE_OFFSET_MULTIPLIER) as u64); + + Ok(0) + }), + ipc::MODE_DESTROY_DUMB => ipc::DrmModeDestroyDumb::with(payload, |data| { + let fb_id = id_index(data.handle()); + if fbs.remove(&fb_id).is_none() { + return Err(Error::new(ENOENT)); + } + Ok(0) + }), ipc::MODE_GET_PLANE_RES => ipc::DrmModeGetPlaneRes::with(payload, |mut data| { let count = self.adapter.display_count(); let mut ids = Vec::with_capacity(count); @@ -634,70 +682,6 @@ impl SchemeSync for GraphicsScheme { data.set_modifier([0; 4]); Ok(0) }), - ipc::CREATE_DUMB_FRAMEBUFFER => { - if payload.len() < size_of::() { - return Err(Error::new(EINVAL)); - } - let payload = unsafe { - transmute::< - &mut [u8; size_of::()], - &mut ipc::CreateDumbFramebuffer, - >(payload.as_mut_array().unwrap()) - }; - - let fb = self - .adapter - .create_dumb_framebuffer(payload.width, payload.height); - - *next_id += 1; - fbs.insert(*next_id, Arc::new(fb)); - payload.fb_id = *next_id; - Ok(size_of::()) - } - ipc::DUMB_FRAMEBUFFER_MAP_OFFSET => { - if payload.len() < size_of::() { - return Err(Error::new(EINVAL)); - } - let payload = unsafe { - transmute::< - &mut [u8; size_of::()], - &mut ipc::DumbFramebufferMapOffset, - >(payload.as_mut_array().unwrap()) - }; - - let fb_id = payload.fb_id; - - if !fbs.contains_key(&fb_id) { - return Err(Error::new(EINVAL)); - } - - // FIXME use a better scheme for creating map offsets - assert!( - ((fbs[&fb_id].width() * fbs[&fb_id].height() * 4) as usize) - < MAP_FAKE_OFFSET_MULTIPLIER - ); - - payload.offset = fb_id * MAP_FAKE_OFFSET_MULTIPLIER; - - Ok(size_of::()) - } - ipc::DESTROY_DUMB_FRAMEBUFFER => { - if payload.len() < size_of::() { - return Err(Error::new(EINVAL)); - } - let payload = unsafe { - transmute::< - &mut [u8; size_of::()], - &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::UPDATE_PLANE => { if payload.len() < size_of::() { return Err(Error::new(EINVAL)); @@ -713,7 +697,7 @@ impl SchemeSync for GraphicsScheme { return Err(Error::new(EINVAL)); } - let Some(framebuffer) = fbs.get(&{ payload.fb_id }) else { + let Some(framebuffer) = fbs.get(&id_index(payload.fb_id)) else { return Err(Error::new(EINVAL)); }; @@ -747,7 +731,7 @@ impl SchemeSync for GraphicsScheme { next_id: _, fbs, } => ( - fbs.get(&(offset as usize / MAP_FAKE_OFFSET_MULTIPLIER)) + fbs.get(&((offset as usize / MAP_FAKE_OFFSET_MULTIPLIER) as u32)) .ok_or(Error::new(EINVAL)) .unwrap(), offset & (MAP_FAKE_OFFSET_MULTIPLIER as u64 - 1), diff --git a/drivers/graphics/fbbootlogd/Cargo.toml b/drivers/graphics/fbbootlogd/Cargo.toml index 44436d0f2c..0df28673a6 100644 --- a/drivers/graphics/fbbootlogd/Cargo.toml +++ b/drivers/graphics/fbbootlogd/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +drm = "0.14.1" orbclient = "0.3.27" ransid = "0.4" redox_event = "0.4" diff --git a/drivers/graphics/fbbootlogd/src/scheme.rs b/drivers/graphics/fbbootlogd/src/scheme.rs index 97caef7a87..3ea92547a3 100644 --- a/drivers/graphics/fbbootlogd/src/scheme.rs +++ b/drivers/graphics/fbbootlogd/src/scheme.rs @@ -1,7 +1,9 @@ use std::collections::VecDeque; -use std::{cmp, ptr}; +use std::{cmp, mem, ptr}; use console_draw::TextScreen; +use drm::buffer::Buffer; +use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; use graphics_ipc::v2::V2GraphicsHandle; use inputd::ConsumerHandle; use orbclient::{Event, EventOption}; @@ -12,8 +14,21 @@ use syscall::{Error, Result, EINVAL, ENOENT}; pub struct DisplayMap { display_handle: V2GraphicsHandle, - fb: usize, - inner: graphics_ipc::v1::DisplayMap, + 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 { @@ -55,24 +70,27 @@ impl FbbootlogScheme { let (width, height) = new_display_handle .display_size(new_display_handle.first_display().unwrap()) .unwrap(); - let fb = new_display_handle + let mut fb = new_display_handle .create_dumb_framebuffer(width, height) .unwrap(); - match new_display_handle.map_dumb_framebuffer(fb, width, height) { - Ok(display_map) => { - self.display_map = Some(DisplayMap { - display_handle: new_display_handle, - fb, - inner: display_map, - }); - - eprintln!("fbbootlogd: mapped display"); - } + let display_map = match new_display_handle.map_dumb_framebuffer(&mut fb) { + Ok(display_map) => unsafe { + mem::transmute::, DumbMapping<'static>>(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"); } pub fn handle_input(&mut self, ev: &Event) { @@ -127,11 +145,7 @@ impl FbbootlogScheme { return; }; let buffer_len = self.text_buffer.lines.len(); - let dmap = &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }; + 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; @@ -151,11 +165,15 @@ impl FbbootlogScheme { if i == buffer_len || yd + spare_lines * 16 > dmap.height { // render until end of screen damage.height = (dmap.height as u32) - damage.y; - map.display_handle.update_plane(0, map.fb, damage).unwrap(); + map.display_handle + .update_plane(0, u32::from(map.fb.handle()), damage) + .unwrap(); self.is_scrollback = i < buffer_len; break; } else { - map.display_handle.update_plane(0, map.fb, damage).unwrap(); + map.display_handle + .update_plane(0, u32::from(map.fb.handle()), damage) + .unwrap(); } } } @@ -169,45 +187,47 @@ impl FbbootlogScheme { Ok((width, height)) => (width, height), Err(err) => { eprintln!("fbbootlogd: failed to get display size: {}", err); - (map.inner.width() as u32, map.inner.height() as u32) + map.fb.size() } }; - if width as usize != map.inner.width() || height as usize != map.inner.height() { + if (width, height) != map.fb.size() { match map.display_handle.create_dumb_framebuffer(width, height) { - Ok(fb) => match map.display_handle.map_dumb_framebuffer(fb, width, height) { - Ok(mut new_map) => { - let count = new_map.ptr().len(); - unsafe { - ptr::write_bytes(new_map.ptr_mut() as *mut u32, 0, count); + Ok(mut fb) => { + let mut new_map = match map.display_handle.map_dumb_framebuffer(&mut fb) { + Ok(new_map) => unsafe { + mem::transmute::, DumbMapping<'static>>(new_map) + }, + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); + return; } + }; - text_screen.resize( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, - &mut console_draw::DisplayMap { - offscreen: new_map.ptr_mut(), - width: new_map.width(), - height: new_map.height(), - }, - ); + new_map.fill(0); - let _ = map.display_handle.destroy_dumb_framebuffer(map.fb); + 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, + }, + ); - map.fb = fb; - map.inner = new_map; + let old_fb = mem::replace(&mut map.fb, fb); + map.mapping = new_map; - eprintln!("fbbootlogd: mapped display"); - } - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - } - }, + let _ = map.display_handle.destroy_dumb_framebuffer(old_fb); + + eprintln!("fbbootlogd: mapped display"); + } Err(err) => { eprintln!("fbbootlogd: failed to create framebuffer: {}", err); + return; } } } @@ -267,17 +287,15 @@ impl SchemeSync for FbbootlogScheme { if !self.is_scrollback { let damage = self.text_screen.write( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, + unsafe { &mut map.console_map() }, buf, &mut VecDeque::new(), ); if let Some(map) = &self.display_map { - map.display_handle.update_plane(0, map.fb, damage).unwrap(); + map.display_handle + .update_plane(0, u32::from(map.fb.handle()), damage) + .unwrap(); } } } diff --git a/drivers/graphics/fbcond/Cargo.toml b/drivers/graphics/fbcond/Cargo.toml index a0a206da8f..6aed8031e7 100644 --- a/drivers/graphics/fbcond/Cargo.toml +++ b/drivers/graphics/fbcond/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +drm = "0.14.1" log = "0.4" orbclient = "0.3.27" ransid = "0.4" diff --git a/drivers/graphics/fbcond/src/display.rs b/drivers/graphics/fbcond/src/display.rs index 333bf2c1c9..0a4d7fb833 100644 --- a/drivers/graphics/fbcond/src/display.rs +++ b/drivers/graphics/fbcond/src/display.rs @@ -1,7 +1,9 @@ use console_draw::TextScreen; +use drm::buffer::Buffer; +use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; -use std::{io, ptr}; +use std::{io, mem, ptr}; pub struct Display { pub input_handle: ConsumerHandle, @@ -10,8 +12,21 @@ pub struct Display { pub struct DisplayMap { display_handle: V2GraphicsHandle, - fb: usize, - pub inner: graphics_ipc::v2::DisplayMap, + 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, + } + } } impl Display { @@ -36,28 +51,29 @@ impl Display { let (width, height) = new_display_handle .display_size(new_display_handle.first_display().unwrap()) .unwrap(); - let fb = new_display_handle + let mut fb = new_display_handle .create_dumb_framebuffer(width, height) .unwrap(); - match new_display_handle.map_dumb_framebuffer(fb, width, height) { - Ok(map) => { - log::debug!( - "fbcond: Mapped new display with size {}x{}", - map.width(), - map.height() - ); - - self.map = Some(DisplayMap { - display_handle: new_display_handle, - fb, - inner: map, - }); - } + let map = match new_display_handle.map_dumb_framebuffer(&mut fb) { + Ok(map) => unsafe { mem::transmute::, DumbMapping<'static>>(map) }, Err(err) => { log::error!("failed to map 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) { @@ -69,43 +85,44 @@ impl Display { Ok((width, height)) => (width, height), Err(err) => { log::error!("fbcond: failed to get display size: {}", err); - (map.inner.width() as u32, map.inner.height() as u32) + map.fb.size() } }; - if width as usize != map.inner.width() || height as usize != map.inner.height() { + if (width, height) != map.fb.size() { match map.display_handle.create_dumb_framebuffer(width, height) { - Ok(fb) => match map.display_handle.map_dumb_framebuffer(fb, width, height) { - Ok(mut new_map) => { - let count = new_map.ptr().len(); - unsafe { - ptr::write_bytes(new_map.ptr_mut() as *mut u32, 0, count); + Ok(mut fb) => { + let mut new_map = match map.display_handle.map_dumb_framebuffer(&mut fb) { + Ok(new_map) => unsafe { + mem::transmute::, DumbMapping<'static>>(new_map) + }, + Err(err) => { + eprintln!("fbcond: failed to open display: {}", err); + return; } + }; - text_screen.resize( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, - &mut console_draw::DisplayMap { - offscreen: new_map.ptr_mut(), - width: new_map.width(), - height: new_map.height(), - }, - ); + new_map.fill(0); - let _ = map.display_handle.destroy_dumb_framebuffer(map.fb); + 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, + }, + ); - map.fb = fb; - map.inner = new_map; + let old_fb = mem::replace(&mut map.fb, fb); + map.mapping = new_map; - log::debug!("fbcond: mapped display"); - } - Err(err) => { - log::error!("fbcond: failed to open display: {}", err); - } - }, + let _ = map.display_handle.destroy_dumb_framebuffer(old_fb); + + eprintln!("fbcond: mapped display"); + } Err(err) => { log::error!("fbcond: failed to create framebuffer: {}", err); } @@ -115,7 +132,9 @@ impl Display { pub fn sync_rect(&mut self, damage: Damage) { if let Some(map) = &self.map { - map.display_handle.update_plane(0, map.fb, damage).unwrap(); + map.display_handle + .update_plane(0, u32::from(map.fb.handle()), damage) + .unwrap(); } } } diff --git a/drivers/graphics/fbcond/src/text.rs b/drivers/graphics/fbcond/src/text.rs index 8cbd70b348..438af68912 100644 --- a/drivers/graphics/fbcond/src/text.rs +++ b/drivers/graphics/fbcond/src/text.rs @@ -124,15 +124,9 @@ impl TextScreen { if let Some(map) = &mut self.display.map { Display::handle_resize(map, &mut self.inner); - let damage = self.inner.write( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, - buf, - &mut self.input, - ); + let damage = self + .inner + .write(unsafe { &mut map.console_map() }, buf, &mut self.input); self.display.sync_rect(damage); } diff --git a/drivers/graphics/graphics-ipc/Cargo.toml b/drivers/graphics/graphics-ipc/Cargo.toml index 5ad5afd9a0..8e8d98503d 100644 --- a/drivers/graphics/graphics-ipc/Cargo.toml +++ b/drivers/graphics/graphics-ipc/Cargo.toml @@ -5,6 +5,7 @@ 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" } diff --git a/drivers/graphics/graphics-ipc/src/v2.rs b/drivers/graphics/graphics-ipc/src/v2.rs index 5ef667d27d..fb9c98b997 100644 --- a/drivers/graphics/graphics-ipc/src/v2.rs +++ b/drivers/graphics/graphics-ipc/src/v2.rs @@ -1,12 +1,13 @@ use std::fs::File; use std::os::fd::{AsFd, BorrowedFd}; use std::os::unix::io::AsRawFd; -use std::{io, mem, ptr}; +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 libredox::flag; +use drm_fourcc::DrmFourcc; pub use crate::common::{Damage, DisplayMap}; @@ -79,75 +80,22 @@ impl V2GraphicsHandle { Ok((u32::from(width), u32::from(height))) } - pub fn create_dumb_framebuffer(&self, width: u32, height: u32) -> io::Result { - let mut cmd = ipc::CreateDumbFramebuffer { - width, - height, - - fb_id: 0, - }; - unsafe { - sys_call( - &self.file, - &mut cmd, - 0, - &[ipc::CREATE_DUMB_FRAMEBUFFER, 0, 0], - )?; - } - Ok(cmd.fb_id) + pub fn create_dumb_framebuffer(&self, width: u32, height: u32) -> io::Result { + self.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) } - pub fn map_dumb_framebuffer( + pub fn map_dumb_framebuffer<'a>( &self, - id: usize, - width: u32, - height: u32, - ) -> io::Result { - let mut cmd = ipc::DumbFramebufferMapOffset { - fb_id: id, - offset: 0, - }; - unsafe { - sys_call( - &self.file, - &mut cmd, - 0, - &[ipc::DUMB_FRAMEBUFFER_MAP_OFFSET, 0, 0], - )?; - } - - let display_ptr = unsafe { - libredox::call::mmap(libredox::call::MmapArgs { - fd: self.file.as_raw_fd() as usize, - offset: cmd.offset as u64, - length: (width * height * 4) as usize, - 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 as usize * height as usize, - ); - - Ok(unsafe { DisplayMap::new(offscreen, width as usize, height as usize) }) + buffer: &'a mut DumbBuffer, + ) -> io::Result> { + self.map_dumb_buffer(buffer) } - pub fn destroy_dumb_framebuffer(&self, id: usize) -> io::Result { - 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 destroy_dumb_framebuffer(&self, buffer: DumbBuffer) -> io::Result<()> { + self.destroy_dumb_buffer(buffer) } - pub fn update_plane(&self, display_id: usize, fb_id: usize, damage: Damage) -> io::Result<()> { + pub fn update_plane(&self, display_id: usize, fb_id: u32, damage: Damage) -> io::Result<()> { let mut cmd = ipc::UpdatePlane { display_id, fb_id, @@ -166,34 +114,11 @@ pub mod ipc { pub use redox_ioctl::drm::*; // FIXME replace these with proper drm interfaces - pub const CREATE_DUMB_FRAMEBUFFER: u64 = 3; - #[repr(C, packed)] - pub struct CreateDumbFramebuffer { - pub width: u32, - pub height: u32, - - pub fb_id: usize, - } - - pub const DUMB_FRAMEBUFFER_MAP_OFFSET: u64 = 4; - #[repr(C, packed)] - pub struct DumbFramebufferMapOffset { - pub fb_id: usize, - - pub offset: usize, - } - - 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, - pub fb_id: usize, + pub fb_id: u32, pub damage: Damage, } }