diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index bbd2d4fdeb..59aea00469 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -4,7 +4,7 @@ use std::collections::{BTreeSet, VecDeque}; use std::convert::{TryFrom, TryInto}; use std::{cmp, ptr}; -use graphics_ipc::legacy::Damage; +use graphics_ipc::v1::Damage; use orbclient::FONT; pub struct DisplayMap { @@ -221,7 +221,7 @@ impl TextScreen { } else { damage.push(Damage { x: 0, - y: i32::try_from(change).unwrap() * 16, + y: u32::try_from(change).unwrap() * 16, width, height: 16, }); diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index c35b88bcd8..d3b8fe3777 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use std::io; -use graphics_ipc::legacy::Damage; +use graphics_ipc::v1::Damage; use inputd::{VtEvent, VtEventKind}; use libredox::errno::EOPNOTSUPP; use libredox::Fd; @@ -9,24 +9,23 @@ use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; pub trait GraphicsAdapter { - type Resource: Resource; + type Framebuffer: Framebuffer; fn displays(&self) -> Vec; fn display_size(&self, display_id: usize) -> (u32, u32); - fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource; - fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8; + fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer; + fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8; - fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource); - fn flush_resource( + fn update_plane( &mut self, display_id: usize, - resource: &Self::Resource, - damage: Option<&[Damage]>, + framebuffer: &Self::Framebuffer, + damage: &[Damage], ); } -pub trait Resource { +pub trait Framebuffer { fn width(&self) -> u32; fn height(&self) -> u32; } @@ -40,7 +39,7 @@ pub struct GraphicsScheme { handles: BTreeMap, active_vt: usize, - vts_res: HashMap>, + vts_fb: HashMap>, } enum Handle { @@ -59,7 +58,7 @@ impl GraphicsScheme { next_id: 0, handles: BTreeMap::new(), active_vt: 0, - vts_res: HashMap::new(), + vts_fb: HashMap::new(), } } @@ -81,16 +80,16 @@ impl GraphicsScheme { log::info!("activate {}", vt_event.vt); for display_id in self.adapter.displays() { - let resource = self - .vts_res + let framebuffer = self + .vts_fb .entry(vt_event.vt) .or_default() .entry(display_id) .or_insert_with(|| { let (width, height) = self.adapter.display_size(display_id); - self.adapter.create_resource(width, height) + self.adapter.create_dumb_framebuffer(width, height) }); - self.adapter.set_scanout(display_id, resource); + Self::update_whole_screen(&mut self.adapter, display_id, framebuffer); self.active_vt = vt_event.vt; } @@ -140,6 +139,19 @@ impl GraphicsScheme { Ok(()) } + + fn update_whole_screen(adapter: &mut T, screen: usize, framebuffer: &T::Framebuffer) { + adapter.update_plane( + screen, + framebuffer, + &[Damage { + x: 0, + y: 0, + width: framebuffer.width(), + height: framebuffer.height(), + }], + ); + } } impl Scheme for GraphicsScheme { @@ -160,13 +172,13 @@ impl Scheme for GraphicsScheme { return Err(Error::new(EINVAL)); } - self.vts_res + self.vts_fb .entry(vt) .or_default() .entry(id) .or_insert_with(|| { let (width, height) = self.adapter.display_size(id); - self.adapter.create_resource(width, height) + self.adapter.create_dumb_framebuffer(width, height) }); self.next_id += 1; @@ -177,12 +189,12 @@ impl Scheme for GraphicsScheme { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let resource = &self.vts_res[vt][screen]; + let framebuffer = &self.vts_fb[vt][screen]; let path = format!( "{}:{vt}.{screen}/{}/{}", self.scheme_name, - resource.width(), - resource.height() + framebuffer.width(), + framebuffer.height() ); buf[..path.len()].copy_from_slice(path.as_bytes()); Ok(path.len()) @@ -192,11 +204,11 @@ impl Scheme for GraphicsScheme { let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; if *vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will - // flush the resource on the next VT switch anyway + // flush the framebuffer on the next VT switch anyway return Ok(0); } - let resource = &self.vts_res[vt][screen]; - self.adapter.flush_resource(*screen, resource, None); + let framebuffer = &self.vts_fb[vt][screen]; + Self::update_whole_screen(&mut self.adapter, *screen, framebuffer); Ok(0) } @@ -216,11 +228,11 @@ impl Scheme for GraphicsScheme { if *vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will - // flush the resource on the next VT switch anyway + // flush the framebuffer on the next VT switch anyway return Ok(buf.len()); } - let resource = &self.vts_res[vt][screen]; + let framebuffer = &self.vts_fb[vt][screen]; let damage = unsafe { core::slice::from_raw_parts( @@ -229,7 +241,7 @@ impl Scheme for GraphicsScheme { ) }; - self.adapter.flush_resource(*screen, resource, Some(damage)); + self.adapter.update_plane(*screen, framebuffer, damage); Ok(buf.len()) } @@ -248,8 +260,8 @@ impl Scheme for GraphicsScheme { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); let handle = self.handles.get(&id).ok_or(Error::new(EINVAL))?; let Handle::Screen { vt, screen } = handle; - let resource = &self.vts_res[vt][screen]; - let ptr = T::map_resource(&mut self.adapter, resource); + let framebuffer = &self.vts_fb[vt][screen]; + let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); Ok(ptr as usize) } } diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index bd4d0c2e93..d276a24038 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,5 +1,5 @@ use event::{user_data, EventQueue}; -use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; +use graphics_ipc::v1::{Damage, V1GraphicsHandle}; use inputd::ConsumerHandle; use libredox::errno::ESTALE; use orbclient::Event; @@ -22,7 +22,7 @@ fn read_to_slice( } } -fn display_fd_map(display_handle: LegacyGraphicsHandle) -> io::Result { +fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; Ok(DisplayMap { display_handle: Arc::new(display_handle), @@ -31,8 +31,8 @@ fn display_fd_map(display_handle: LegacyGraphicsHandle) -> io::Result, - pub inner: graphics_ipc::legacy::DisplayMap, + display_handle: Arc, + pub inner: graphics_ipc::v1::DisplayMap, } enum DisplayCommand { @@ -50,7 +50,7 @@ impl Display { let map = match input_handle.open_display() { Ok(display) => { - let display_handle = LegacyGraphicsHandle::from_file(display)?; + let display_handle = V1GraphicsHandle::from_file(display)?; Arc::new(Mutex::new(Some( display_fd_map(display_handle) .unwrap_or_else(|e| panic!("failed to map display: {e}")), @@ -102,7 +102,7 @@ impl Display { eprintln!("fbbootlogd: handoff requested"); let new_display_handle = match input_handle.open_display() { - Ok(display) => LegacyGraphicsHandle::from_file(display).unwrap(), + Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), Err(err) => { println!("fbbootlogd: No display present yet: {err}"); continue; diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index b60b8e6674..45ee86d2ca 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,4 +1,4 @@ -use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; +use graphics_ipc::v1::{Damage, V1GraphicsHandle}; use inputd::ConsumerHandle; use std::io; @@ -8,8 +8,8 @@ pub struct Display { } pub struct DisplayMap { - display_handle: LegacyGraphicsHandle, - pub inner: graphics_ipc::legacy::DisplayMap, + display_handle: V1GraphicsHandle, + pub inner: graphics_ipc::v1::DisplayMap, } impl Display { @@ -63,10 +63,10 @@ impl Display { } } - fn open_display(input_handle: &ConsumerHandle) -> io::Result { + fn open_display(input_handle: &ConsumerHandle) -> io::Result { let display_file = input_handle.open_display()?; - LegacyGraphicsHandle::from_file(display_file) + V1GraphicsHandle::from_file(display_file) } pub fn sync_rects(&mut self, sync_rects: Vec) { diff --git a/graphics/graphics-ipc/src/lib.rs b/graphics/graphics-ipc/src/lib.rs index d0b036677b..a3a6d96c3f 100644 --- a/graphics/graphics-ipc/src/lib.rs +++ b/graphics/graphics-ipc/src/lib.rs @@ -1 +1 @@ -pub mod legacy; +pub mod v1; diff --git a/graphics/graphics-ipc/src/legacy.rs b/graphics/graphics-ipc/src/v1.rs similarity index 87% rename from graphics/graphics-ipc/src/legacy.rs rename to graphics/graphics-ipc/src/v1.rs index 2bfb4f2ce3..39226f2b31 100644 --- a/graphics/graphics-ipc/src/legacy.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -4,17 +4,17 @@ use std::{cmp, io, mem, ptr, slice}; use libredox::flag; -/// A graphics handle using the legacy graphics API. +/// A graphics handle using the v1 graphics API. /// -/// The legacy graphics API only allows a single framebuffer for each VT and supports neither page +/// The v1 graphics API only allows a single framebuffer for each VT and supports neither page /// flipping nor cursor planes. -pub struct LegacyGraphicsHandle { +pub struct V1GraphicsHandle { file: File, } -impl LegacyGraphicsHandle { +impl V1GraphicsHandle { pub fn from_file(file: File) -> io::Result { - Ok(LegacyGraphicsHandle { file }) + Ok(V1GraphicsHandle { file }) } pub fn map_display(&self) -> io::Result { @@ -111,18 +111,20 @@ impl Drop for DisplayMap { } // Keep synced with orbital's SyncRect +// Technically orbital uses i32 rather than u32, but values larger than i32::MAX +// would be a bug anyway. #[derive(Debug, Copy, Clone)] #[repr(packed)] pub struct Damage { - pub x: i32, - pub y: i32, - pub width: i32, - pub height: i32, + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, } impl Damage { #[must_use] - pub fn clip(mut self, width: i32, height: i32) -> Self { + pub fn clip(mut self, width: u32, height: u32) -> Self { // Clip damage self.x = cmp::min(self.x, width); if self.x + self.width > width { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 48c3b0940a..32e3a22436 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -2,8 +2,8 @@ use std::alloc::{self, Layout}; use std::convert::TryInto; use std::ptr::{self, NonNull}; -use driver_graphics::{GraphicsAdapter, Resource}; -use graphics_ipc::legacy::Damage; +use driver_graphics::{Framebuffer, GraphicsAdapter}; +use graphics_ipc::v1::Damage; use syscall::PAGE_SIZE; use crate::framebuffer::FrameBuffer; @@ -13,7 +13,7 @@ pub struct FbAdapter { } impl GraphicsAdapter for FbAdapter { - type Resource = GraphicScreen; + type Framebuffer = GraphicScreen; fn displays(&self) -> Vec { (0..self.framebuffers.len()).collect() @@ -26,40 +26,21 @@ impl GraphicsAdapter for FbAdapter { ) } - fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource { + fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { GraphicScreen::new(width as usize, height as usize) } - fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { - resource.ptr.as_ptr().cast::() + fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + framebuffer.ptr.as_ptr().cast::() } - fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { - self.flush_resource(display_id, resource, None); - } - - fn flush_resource( + fn update_plane( &mut self, display_id: usize, - resource: &Self::Resource, - damage: Option<&[Damage]>, + framebuffer: &Self::Framebuffer, + damage: &[Damage], ) { - if let Some(damage) = damage { - resource.sync(&mut self.framebuffers[display_id], damage) - } else { - let framebuffer: &mut FrameBuffer = &mut self.framebuffers[display_id]; - let width = resource.width.try_into().unwrap(); - let height = resource.height.try_into().unwrap(); - resource.sync( - framebuffer, - &[Damage { - x: 0, - y: 0, - width, - height, - }], - ); - } + framebuffer.sync(&mut self.framebuffers[display_id], damage) } } @@ -97,7 +78,7 @@ impl Drop for GraphicScreen { } } -impl Resource for GraphicScreen { +impl Framebuffer for GraphicScreen { fn width(&self) -> u32 { self.width as u32 } @@ -115,10 +96,10 @@ impl GraphicScreen { self.height.try_into().unwrap(), ); - let start_x: usize = sync_rect.x.try_into().unwrap_or(0); - let start_y: usize = sync_rect.y.try_into().unwrap_or(0); - let w: usize = sync_rect.width.try_into().unwrap_or(0); - let h: usize = sync_rect.height.try_into().unwrap_or(0); + let start_x: usize = sync_rect.x.try_into().unwrap(); + let start_y: usize = sync_rect.y.try_into().unwrap(); + let w: usize = sync_rect.width.try_into().unwrap(); + let h: usize = sync_rect.height.try_into().unwrap(); let offscreen_ptr = self.ptr.as_ptr() as *mut u32; let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 6b0b62f3fe..fa2a5da6f5 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -109,6 +109,9 @@ pub enum CommandTy { static_assertions::const_assert_eq!(core::mem::size_of::(), 4); +const VIRTIO_GPU_FLAG_FENCE: u32 = 1 << 0; +//const VIRTIO_GPU_FLAG_INFO_RING_IDX: u32 = 1 << 1; + #[derive(Debug)] #[repr(C)] pub struct ControlHeader { @@ -192,7 +195,7 @@ impl Default for GetDisplayInfo { static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. -#[derive(Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] #[repr(C)] pub struct ResourceId(u32); diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index d80f45bbb6..b6eda2e2b0 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; -use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource}; -use graphics_ipc::legacy::Damage; +use driver_graphics::{Framebuffer, GraphicsAdapter, GraphicsScheme}; +use graphics_ipc::v1::Damage; use inputd::DisplayHandle; use syscall::PAGE_SIZE; @@ -15,22 +15,22 @@ use crate::*; impl Into for Damage { fn into(self) -> GpuRect { GpuRect { - x: self.x as u32, - y: self.y as u32, - width: self.width as u32, - height: self.height as u32, + x: self.x, + y: self.y, + width: self.width, + height: self.height, } } } -pub struct VirtGpuResource { +pub struct VirtGpuFramebuffer { id: ResourceId, sgl: sgl::Sgl, width: u32, height: u32, } -impl Resource for VirtGpuResource { +impl Framebuffer for VirtGpuFramebuffer { fn width(&self) -> u32 { self.width } @@ -44,6 +44,7 @@ impl Resource for VirtGpuResource { pub struct Display { width: u32, height: u32, + active_resource: Option, } pub struct VirtGpuAdapter<'a> { @@ -65,11 +66,16 @@ impl VirtGpuAdapter<'_> { Ok(header) } - async fn flush_resource_inner(&self, flush: ResourceFlush) -> Result<(), Error> { - let header = self.send_request(Dma::new(flush)?).await?; - assert_eq!(header.ty, CommandTy::RespOkNodata); + async fn send_request_fenced(&self, request: Dma) -> Result, Error> { + let mut header = Dma::new(ControlHeader::default())?; + header.flags |= VIRTIO_GPU_FLAG_FENCE; + let command = ChainBuilder::new() + .chain(Buffer::new(&request)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); - Ok(()) + self.control_queue.send(command).await; + Ok(header) } async fn get_display_info(&self) -> Result, Error> { @@ -89,7 +95,7 @@ impl VirtGpuAdapter<'_> { } impl GraphicsAdapter for VirtGpuAdapter<'_> { - type Resource = VirtGpuResource; + type Framebuffer = VirtGpuFramebuffer; fn displays(&self) -> Vec { self.displays.iter().enumerate().map(|(i, _)| i).collect() @@ -102,7 +108,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { ) } - fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource { + fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { futures::executor::block_on(async { let bpp = 32; let fb_size = width as usize * height as usize * bpp / 8; @@ -151,7 +157,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { self.control_queue.send(command).await; assert_eq!(header.ty, CommandTy::RespOkNodata); - VirtGpuResource { + VirtGpuFramebuffer { id: res_id, sgl, width, @@ -160,39 +166,24 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { }) } - fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { - resource.sgl.as_ptr() + fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + framebuffer.sgl.as_ptr() } - fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { - futures::executor::block_on(async { - let scanout_request = Dma::new(SetScanout::new( - display_id as u32, - resource.id, - GpuRect::new(0, 0, resource.width, resource.height), - )) - .unwrap(); - let header = self.send_request(scanout_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - }); - - self.flush_resource(display_id, resource, None); - } - - fn flush_resource( + fn update_plane( &mut self, - _display_id: usize, - resource: &Self::Resource, - damage: Option<&[Damage]>, + display_id: usize, + framebuffer: &Self::Framebuffer, + damage: &[Damage], ) { futures::executor::block_on(async { let req = Dma::new(XferToHost2d::new( - resource.id, + framebuffer.id, GpuRect { x: 0, y: 0, - width: resource.width, - height: resource.height, + width: framebuffer.width, + height: framebuffer.height, }, 0, )) @@ -200,29 +191,26 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { let header = self.send_request(req).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); - if let Some(damage) = damage { - for damage in damage { - self.flush_resource_inner(ResourceFlush::new( - resource.id, - damage - .clip(resource.width as i32, resource.height as i32) - .into(), - )) - .await - .unwrap(); - } - } else { - self.flush_resource_inner(ResourceFlush::new( - resource.id, - GpuRect { - x: 0, - y: 0, - width: resource.width, - height: resource.height, - }, + // FIXME once we support resizing we also need to check that the current and target size match + if self.displays[display_id].active_resource != Some(framebuffer.id) { + let scanout_request = Dma::new(SetScanout::new( + display_id as u32, + framebuffer.id, + GpuRect::new(0, 0, framebuffer.width, framebuffer.height), )) - .await .unwrap(); + let header = self.send_request(scanout_request).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); + self.displays[display_id].active_resource = Some(framebuffer.id); + } + + for damage in damage { + let flush = ResourceFlush::new( + framebuffer.id, + damage.clip(framebuffer.width, framebuffer.height).into(), + ); + let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); } }); } @@ -261,11 +249,13 @@ impl<'a> GpuScheme { adapter.displays.push(Display { width: 640, height: 480, + active_resource: None, }); } else { adapter.displays.push(Display { width: info.rect.width, height: info.rect.height, + active_resource: None, }); } }