Merge branch 'gpu_drm15' into 'main'
drivers/graphics: Add framebuffer indirection to the DRM interface See merge request redox-os/base!154
This commit is contained in:
@@ -6,27 +6,31 @@ use std::{cmp, io, mem, ptr};
|
||||
|
||||
use drm::buffer::{Buffer, DrmFourcc};
|
||||
use drm::control::dumbbuffer::{DumbBuffer, DumbMapping};
|
||||
use drm::control::Device;
|
||||
use drm::control::{framebuffer, Device};
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v2::V2GraphicsHandle;
|
||||
use orbclient::FONT;
|
||||
|
||||
pub struct V2DisplayMap {
|
||||
pub display_handle: V2GraphicsHandle,
|
||||
pub fb: DumbBuffer,
|
||||
pub fb: framebuffer::Handle,
|
||||
pub buffer: 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 mut buffer =
|
||||
display_handle.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32)?;
|
||||
let fb = display_handle.add_framebuffer(&buffer, 24, 32)?;
|
||||
|
||||
let map = display_handle.map_dumb_buffer(&mut fb)?;
|
||||
let map = display_handle.map_dumb_buffer(&mut buffer)?;
|
||||
let map = unsafe { mem::transmute::<DumbMapping<'_>, DumbMapping<'static>>(map) };
|
||||
|
||||
Ok(Self {
|
||||
display_handle,
|
||||
fb,
|
||||
buffer,
|
||||
mapping: map,
|
||||
})
|
||||
}
|
||||
@@ -37,8 +41,8 @@ impl V2DisplayMap {
|
||||
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,
|
||||
width: self.buffer.size().0 as usize,
|
||||
height: self.buffer.size().1 as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,7 +328,7 @@ impl TextScreen {
|
||||
}
|
||||
}
|
||||
|
||||
let old_fb = mem::replace(&mut map.fb, new_fb);
|
||||
let old_fb = mem::replace(&mut map.buffer, new_fb);
|
||||
map.mapping = new_mapping;
|
||||
|
||||
let _ = map.display_handle.destroy_dumb_buffer(old_fb);
|
||||
|
||||
@@ -349,6 +349,67 @@ impl<T: GraphicsAdapter> GraphicsSchemeInner<T> {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn handle_cursor_update(
|
||||
&mut self,
|
||||
vt: usize,
|
||||
cursor_damage: &graphics_ipc::v2::ipc::UpdateCursor,
|
||||
) -> Result<()> {
|
||||
let vt_state = self.vts.get_mut(&vt).unwrap();
|
||||
|
||||
let Some(cursor_plane) = &mut vt_state.cursor_plane else {
|
||||
// Hardware cursor not supported
|
||||
return Err(Error::new(EINVAL));
|
||||
};
|
||||
|
||||
cursor_plane.x = cursor_damage.x;
|
||||
cursor_plane.y = cursor_damage.y;
|
||||
|
||||
if cursor_damage.header == 0 {
|
||||
if vt != self.active_vt {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.adapter.handle_cursor(cursor_plane, false);
|
||||
} else {
|
||||
cursor_plane.hot_x = cursor_damage.hot_x;
|
||||
cursor_plane.hot_y = cursor_damage.hot_y;
|
||||
|
||||
let w: i32 = cursor_damage.width;
|
||||
let h: i32 = cursor_damage.height;
|
||||
let cursor_image = cursor_damage.cursor_img_bytes;
|
||||
let cursor_ptr = self
|
||||
.adapter
|
||||
.map_cursor_framebuffer(&cursor_plane.framebuffer);
|
||||
|
||||
//Clear previous image from backing storage
|
||||
unsafe {
|
||||
core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4);
|
||||
}
|
||||
|
||||
//Write image to backing storage
|
||||
for row in 0..h {
|
||||
let start: usize = (w * row) as usize;
|
||||
let end: usize = (w * row + w) as usize;
|
||||
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
cursor_image[start..end].as_ptr(),
|
||||
cursor_ptr.cast::<u32>().offset(64 * row as isize),
|
||||
w as usize,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if vt != self.active_vt {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.adapter.handle_cursor(cursor_plane, true);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
const MAP_FAKE_OFFSET_MULTIPLIER: usize = 0x10_000_000;
|
||||
@@ -495,6 +556,14 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsSchemeInner<T> {
|
||||
) -> Result<usize> {
|
||||
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::V1Screen { vt, screen } => {
|
||||
if size_of_val(buf) == std::mem::size_of::<CursorDamage>() {
|
||||
let cursor_damage = unsafe { &*buf.as_ptr().cast::<CursorDamage>() };
|
||||
|
||||
self.handle_cursor_update(*vt, cursor_damage)?;
|
||||
|
||||
return Ok(buf.len());
|
||||
}
|
||||
|
||||
if *vt != self.active_vt {
|
||||
// This is a protection against background VT's spamming us with flush requests. We will
|
||||
// flush the framebuffer on the next VT switch anyway
|
||||
@@ -503,55 +572,6 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsSchemeInner<T> {
|
||||
|
||||
let vt_state = self.vts.get_mut(vt).unwrap();
|
||||
|
||||
if size_of_val(buf) == std::mem::size_of::<CursorDamage>() {
|
||||
let Some(cursor_plane) = &mut vt_state.cursor_plane else {
|
||||
// Hardware cursor not supported
|
||||
return Err(Error::new(EINVAL));
|
||||
};
|
||||
|
||||
let cursor_damage = unsafe { *buf.as_ptr().cast::<CursorDamage>() };
|
||||
|
||||
cursor_plane.x = cursor_damage.x;
|
||||
cursor_plane.y = cursor_damage.y;
|
||||
|
||||
if cursor_damage.header == 0 {
|
||||
self.adapter.handle_cursor(cursor_plane, false);
|
||||
} else {
|
||||
cursor_plane.hot_x = cursor_damage.hot_x;
|
||||
cursor_plane.hot_y = cursor_damage.hot_y;
|
||||
|
||||
let w: i32 = cursor_damage.width;
|
||||
let h: i32 = cursor_damage.height;
|
||||
let cursor_image = cursor_damage.cursor_img_bytes;
|
||||
let cursor_ptr = self
|
||||
.adapter
|
||||
.map_cursor_framebuffer(&cursor_plane.framebuffer);
|
||||
|
||||
//Clear previous image from backing storage
|
||||
unsafe {
|
||||
core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4);
|
||||
}
|
||||
|
||||
//Write image to backing storage
|
||||
for row in 0..h {
|
||||
let start: usize = (w * row) as usize;
|
||||
let end: usize = (w * row + w) as usize;
|
||||
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
cursor_image[start..end].as_ptr(),
|
||||
cursor_ptr.cast::<u32>().offset(64 * row as isize),
|
||||
w as usize,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.adapter.handle_cursor(cursor_plane, true);
|
||||
}
|
||||
|
||||
return Ok(buf.len());
|
||||
}
|
||||
|
||||
assert_eq!(buf.len(), std::mem::size_of::<Damage>());
|
||||
let damage = unsafe { *buf.as_ptr().cast::<Damage>() };
|
||||
|
||||
@@ -810,6 +830,10 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsSchemeInner<T> {
|
||||
data.set_handle(fb_handle_id(i));
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| {
|
||||
data.set_fb_id(fb_handle_id(id_index(data.handle())));
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| {
|
||||
if data.bpp() != 32 {
|
||||
return Err(Error::new(EINVAL));
|
||||
@@ -931,6 +955,20 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsSchemeInner<T> {
|
||||
|
||||
Ok(size_of::<ipc::UpdatePlane>())
|
||||
}
|
||||
ipc::UPDATE_CURSOR => {
|
||||
if payload.len() < size_of::<ipc::UpdateCursor>() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let payload = unsafe {
|
||||
transmute::<&mut [u8; size_of::<ipc::UpdateCursor>()], &mut ipc::UpdateCursor>(
|
||||
payload.as_mut_array().unwrap(),
|
||||
)
|
||||
};
|
||||
let vt = *vt;
|
||||
self.handle_cursor_update(vt, payload)?;
|
||||
|
||||
Ok(size_of::<ipc::UpdateCursor>())
|
||||
}
|
||||
_ => return Err(Error::new(EINVAL)),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ impl FbbootlogScheme {
|
||||
self.is_scrollback = true;
|
||||
self.scrollback_offset = cmp::min(
|
||||
self.scrollback_offset,
|
||||
buffer_len - map.fb.size().1 as usize / 16 + spare_lines,
|
||||
buffer_len - map.buffer.size().1 as usize / 16 + spare_lines,
|
||||
);
|
||||
let mut i = self.scrollback_offset;
|
||||
self.text_screen
|
||||
@@ -135,9 +135,9 @@ impl FbbootlogScheme {
|
||||
.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 > map.fb.size().1 as usize {
|
||||
if i == buffer_len || yd + spare_lines * 16 > map.buffer.size().1 as usize {
|
||||
// render until end of screen
|
||||
damage.height = map.fb.size().1 - damage.y;
|
||||
damage.height = map.buffer.size().1 - damage.y;
|
||||
total_damage = total_damage.merge(damage);
|
||||
self.is_scrollback = i < buffer_len;
|
||||
break;
|
||||
@@ -146,7 +146,7 @@ impl FbbootlogScheme {
|
||||
}
|
||||
}
|
||||
map.display_handle
|
||||
.update_plane(0, u32::from(map.fb.handle()), total_damage)
|
||||
.update_plane(0, u32::from(map.buffer.handle()), total_damage)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
@@ -157,11 +157,11 @@ impl FbbootlogScheme {
|
||||
Ok((width, height)) => (width.into(), height.into()),
|
||||
Err(err) => {
|
||||
eprintln!("fbbootlogd: failed to get display size: {}", err);
|
||||
map.fb.size()
|
||||
map.buffer.size()
|
||||
}
|
||||
};
|
||||
|
||||
if (width, height) != map.fb.size() {
|
||||
if (width, height) != map.buffer.size() {
|
||||
match text_screen.resize(map, width, height) {
|
||||
Ok(()) => eprintln!("fbbootlogd: mapped display"),
|
||||
Err(err) => {
|
||||
@@ -248,7 +248,7 @@ impl SchemeSync for FbbootlogScheme {
|
||||
|
||||
if let Some(map) = &self.display_map {
|
||||
map.display_handle
|
||||
.update_plane(0, u32::from(map.fb.handle()), damage)
|
||||
.update_plane(0, u32::from(map.buffer.handle()), damage)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ impl Display {
|
||||
Ok(map) => {
|
||||
log::debug!(
|
||||
"fbcond: Mapped new display with size {}x{}",
|
||||
map.fb.size().0,
|
||||
map.fb.size().1,
|
||||
map.buffer.size().0,
|
||||
map.buffer.size().1,
|
||||
);
|
||||
self.map = Some(map)
|
||||
}
|
||||
@@ -64,11 +64,11 @@ impl Display {
|
||||
Ok((width, height)) => (width.into(), height.into()),
|
||||
Err(err) => {
|
||||
log::error!("fbcond: failed to get display size: {}", err);
|
||||
map.fb.size()
|
||||
map.buffer.size()
|
||||
}
|
||||
};
|
||||
|
||||
if (width, height) != map.fb.size() {
|
||||
if (width, height) != map.buffer.size() {
|
||||
match text_screen.resize(map, width, height) {
|
||||
Ok(()) => eprintln!("fbcond: mapped display"),
|
||||
Err(err) => {
|
||||
@@ -82,7 +82,7 @@ impl Display {
|
||||
pub fn sync_rect(&mut self, damage: Damage) {
|
||||
if let Some(map) = &self.map {
|
||||
map.display_handle
|
||||
.update_plane(0, u32::from(map.fb.handle()), damage)
|
||||
.update_plane(0, u32::from(map.buffer.handle()), damage)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,2 @@
|
||||
pub use crate::common::Damage;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct CursorDamage {
|
||||
pub header: u32,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub hot_x: i32,
|
||||
pub hot_y: i32,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub cursor_img_bytes: [u32; 4096],
|
||||
}
|
||||
pub use crate::v2::ipc::UpdateCursor as CursorDamage;
|
||||
|
||||
@@ -69,11 +69,25 @@ pub mod ipc {
|
||||
pub use redox_ioctl::drm::*;
|
||||
|
||||
// FIXME replace these with proper drm interfaces
|
||||
pub const UPDATE_PLANE: u64 = 6;
|
||||
pub const UPDATE_PLANE: u64 = 0x12345670;
|
||||
#[repr(C, packed)]
|
||||
pub struct UpdatePlane {
|
||||
pub display_id: usize,
|
||||
pub fb_id: u32,
|
||||
pub damage: Damage,
|
||||
}
|
||||
|
||||
pub const UPDATE_CURSOR: u64 = 0x12345671;
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct UpdateCursor {
|
||||
pub header: u32,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub hot_x: i32,
|
||||
pub hot_y: i32,
|
||||
pub width: i32,
|
||||
pub height: i32,
|
||||
pub cursor_img_bytes: [u32; 4096],
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user