Merge branch 'gpu_drm7' into 'main'

Mostly use drm ioctls in graphics_ipc::v2

See merge request redox-os/base!72
This commit is contained in:
Jeremy Soller
2025-12-18 06:33:29 -07:00
10 changed files with 477 additions and 355 deletions
Generated
+172 -12
View File
@@ -156,7 +156,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys",
"windows-sys 0.61.2",
]
[[package]]
@@ -167,7 +167,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys",
"windows-sys 0.61.2",
]
[[package]]
@@ -326,6 +326,26 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "bytemuck"
version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4"
dependencies = [
"bytemuck_derive",
]
[[package]]
name = "bytemuck_derive"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.111",
]
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -596,14 +616,42 @@ dependencies = [
"redox_syscall 0.6.0",
]
[[package]]
name = "drm"
version = "0.14.1"
source = "git+https://github.com/Smithay/drm-rs.git#c51297961755fa9eb3941fdd60bf2b69979cb403"
dependencies = [
"bitflags 2.10.0",
"bytemuck",
"bytemuck_derive",
"drm-ffi",
"drm-fourcc",
"libc",
"rustix",
]
[[package]]
name = "drm-ffi"
version = "0.9.0"
source = "git+https://github.com/Smithay/drm-rs.git#c51297961755fa9eb3941fdd60bf2b69979cb403"
dependencies = [
"drm-sys",
"rustix",
]
[[package]]
name = "drm-fourcc"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
[[package]]
name = "drm-sys"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c"
source = "git+https://github.com/Smithay/drm-rs.git#c51297961755fa9eb3941fdd60bf2b69979cb403"
dependencies = [
"libc",
"linux-raw-sys",
"linux-raw-sys 0.9.4",
]
[[package]]
@@ -640,6 +688,16 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
]
[[package]]
name = "executor"
version = "0.1.0"
@@ -661,6 +719,7 @@ version = "0.1.0"
dependencies = [
"console-draw",
"daemon",
"drm",
"graphics-ipc",
"inputd",
"libredox",
@@ -678,6 +737,7 @@ dependencies = [
"common",
"console-draw",
"daemon",
"drm",
"graphics-ipc",
"inputd",
"libredox",
@@ -813,7 +873,7 @@ dependencies = [
[[package]]
name = "generic-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3ebd43b4ceb77bfee2a9c155993ec2fb5843ad6b"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#13b93e0f901ea61358d80b4cd177601872ef830e"
[[package]]
name = "getrandom"
@@ -866,6 +926,8 @@ name = "graphics-ipc"
version = "0.1.0"
dependencies = [
"common",
"drm",
"drm-fourcc",
"libredox",
"log",
"redox-ioctl",
@@ -1103,9 +1165,15 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
version = "0.6.5"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "lived"
@@ -1619,7 +1687,7 @@ dependencies = [
[[package]]
name = "redox-ioctl"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/Ibuki.O/relibc.git?branch=replace-unlink-rmdir-with-unlinkat#daf01ee12975a5481d2c1302e19eab45013427f4"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#13b93e0f901ea61358d80b4cd177601872ef830e"
dependencies = [
"drm-sys",
"redox_syscall 0.6.0",
@@ -1637,16 +1705,23 @@ dependencies = [
"termion",
]
[[package]]
name = "redox-path"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
[[package]]
name = "redox-rt"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3ebd43b4ceb77bfee2a9c155993ec2fb5843ad6b"
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#13b93e0f901ea61358d80b4cd177601872ef830e"
dependencies = [
"bitflags 2.10.0",
"generic-rt",
"goblin",
"plain",
"redox_syscall 0.5.18",
"redox-path",
"redox_syscall 0.6.0",
]
[[package]]
@@ -1815,6 +1890,18 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "1.1.2"
source = "git+https://github.com/jackpot51/rustix.git?branch=redox-ioctl#e7e66bc77455251463336582c0b97df01054ccb8"
dependencies = [
"bitflags 2.10.0",
"errno",
"libc",
"linux-raw-sys 0.11.0",
"windows-sys 0.59.0",
]
[[package]]
name = "rustversion"
version = "1.0.22"
@@ -2510,7 +2597,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys",
"windows-sys 0.61.2",
]
[[package]]
@@ -2578,6 +2665,15 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.61.2"
@@ -2587,6 +2683,70 @@ dependencies = [
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.5.40"
+5
View File
@@ -76,6 +76,11 @@ exclude = ["bootstrap"]
libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox-0.2" }
orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" }
# Rustix doesn't support ioctls on Redox OS
rustix = { git = "https://github.com/jackpot51/rustix.git", branch = "redox-ioctl" }
drm = { git = "https://github.com/Smithay/drm-rs.git" }
drm-sys = { git = "https://github.com/Smithay/drm-rs.git" }
[patch."https://gitlab.redox-os.org/redox-os/relibc.git"]
#redox-rt = { path = "../../relibc/source/redox-rt" }
#redox-ioctl = { path = "../../relibc/source/redox-ioctl" }
+89 -99
View File
@@ -1,6 +1,7 @@
#![feature(slice_as_array)]
use std::collections::{BTreeMap, HashMap};
use std::ffi::c_char;
use std::fs::File;
use std::io::{self, Write};
use std::mem;
@@ -82,8 +83,8 @@ enum Handle<T: GraphicsAdapter> {
},
V2 {
vt: usize,
next_id: usize,
fbs: HashMap<usize, Arc<T::Framebuffer>>,
next_id: u32,
fbs: HashMap<u32, Arc<T::Framebuffer>>,
},
}
@@ -462,6 +463,44 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
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
hdisplay: width as u16,
vdisplay: height as u16,
// These are used to calculate the refresh rate
clock: 60 * width * height / 1000,
htotal: width as u16,
vtotal: height as u16,
vscan: 0,
vrefresh: 60,
type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER,
name: [0; 32],
// These only matter when modesetting physical display adapters. For
// those we should be able to parse the EDID blob.
hsync_start: width as u16,
hsync_end: width as u16,
hskew: 0,
vsync_start: height as u16,
vsync_end: height as u16,
flags: 0,
};
let name = format!("{width}x{height}").into_bytes();
for (to, from) in modeinfo.name.iter_mut().zip(name) {
*to = from as c_char;
}
modeinfo
}
match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::V1Screen { .. } => {
return Err(Error::new(EOPNOTSUPP));
@@ -543,7 +582,8 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| {
let i = id_index(data.connector_id());
let (width, height) = self.adapter.display_size(i as usize);
data.set_modes_ptr(&[]);
data.set_connection(1 /* connected */);
data.set_modes_ptr(&[modeinfo_for_size(width, height)]);
data.set_props_ptr(&[]);
data.set_prop_values_ptr(&[]);
data.set_encoders_ptr(&[enc_id(i)]);
@@ -560,6 +600,50 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
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);
@@ -598,100 +682,6 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
data.set_modifier([0; 4]);
Ok(0)
}),
ipc::DISPLAY_COUNT => {
if payload.len() < size_of::<ipc::DisplayCount>() {
return Err(Error::new(EINVAL));
}
let payload = unsafe {
transmute::<&mut [u8; size_of::<ipc::DisplayCount>()], &mut ipc::DisplayCount>(
payload.as_mut_array().unwrap(),
)
};
payload.count = self.adapter.display_count();
Ok(size_of::<ipc::DisplayCount>())
}
ipc::DISPLAY_SIZE => {
if payload.len() < size_of::<ipc::DisplaySize>() {
return Err(Error::new(EINVAL));
}
let payload = unsafe {
transmute::<&mut [u8; size_of::<ipc::DisplaySize>()], &mut ipc::DisplaySize>(
payload.as_mut_array().unwrap(),
)
};
let display_id = payload.display_id;
if display_id >= self.adapter.display_count() {
return Err(Error::new(EINVAL));
}
let (width, height) = self.adapter.display_size(display_id);
payload.width = width;
payload.height = height;
Ok(size_of::<ipc::DisplaySize>())
}
ipc::CREATE_DUMB_FRAMEBUFFER => {
if payload.len() < size_of::<ipc::CreateDumbFramebuffer>() {
return Err(Error::new(EINVAL));
}
let payload = unsafe {
transmute::<
&mut [u8; size_of::<ipc::CreateDumbFramebuffer>()],
&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::CreateDumbFramebuffer>())
}
ipc::DUMB_FRAMEBUFFER_MAP_OFFSET => {
if payload.len() < size_of::<ipc::DumbFramebufferMapOffset>() {
return Err(Error::new(EINVAL));
}
let payload = unsafe {
transmute::<
&mut [u8; size_of::<ipc::DumbFramebufferMapOffset>()],
&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::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));
@@ -707,7 +697,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
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));
};
@@ -741,7 +731,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
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),
+1
View File
@@ -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"
+82 -58
View File
@@ -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 {
@@ -52,25 +67,30 @@ impl FbbootlogScheme {
}
};
let (width, height) = new_display_handle.display_size(0).unwrap();
let fb = new_display_handle
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();
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<'_>, 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) {
@@ -125,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;
@@ -149,59 +165,69 @@ 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();
}
}
}
fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) {
let (width, height) = match map.display_handle.display_size(0) {
let (width, height) = match map
.display_handle
.first_display()
.and_then(|handle| map.display_handle.display_size(handle))
{
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<'_>, 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;
}
}
}
@@ -261,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();
}
}
}
+1
View File
@@ -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"
+82 -57
View File
@@ -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 {
@@ -33,73 +48,81 @@ impl Display {
log::debug!("fbcond: Opened new display");
let (width, height) = new_display_handle.display_size(0).unwrap();
let fb = new_display_handle
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();
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<'_>, DumbMapping<'static>>(map) },
Err(err) => {
log::error!("failed to map display: {}", err);
}
}
}
pub fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) {
let (width, height) = match map.display_handle.display_size(0) {
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)
return;
}
};
if width as usize != map.inner.width() || height as usize != map.inner.height() {
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),
Err(err) => {
log::error!("fbcond: failed to get display size: {}", err);
map.fb.size()
}
};
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<'_>, 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);
}
@@ -109,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();
}
}
}
+3 -9
View File
@@ -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);
}
+3 -1
View File
@@ -4,9 +4,11 @@ version = "0.1.0"
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/Ibuki.O/relibc.git", branch = "replace-unlink-rmdir-with-unlinkat" }
redox-ioctl = { git = "https://gitlab.redox-os.org/redox-os/relibc.git" }
redox_syscall = "0.6"
common = { path = "../../common" }
+39 -119
View File
@@ -1,8 +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 libredox::flag;
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};
@@ -44,100 +49,53 @@ pub struct V2GraphicsHandle {
file: File,
}
impl AsFd for V2GraphicsHandle {
fn as_fd(&self) -> BorrowedFd<'_> {
self.file.as_fd()
}
}
impl drm::Device for V2GraphicsHandle {}
impl drm::control::Device for V2GraphicsHandle {}
impl V2GraphicsHandle {
pub fn from_file(file: File) -> io::Result<Self> {
Ok(V2GraphicsHandle { file })
let handle = V2GraphicsHandle { file };
handle.set_client_capability(ClientCapability::CursorPlaneHotspot, true)?;
assert!(handle.get_driver_capability(DriverCapability::DumbBuffer)? == 1);
Ok(handle)
}
pub fn display_count(&self) -> io::Result<usize> {
let mut cmd = ipc::DisplayCount { count: 0 };
unsafe {
sys_call(&self.file, &mut cmd, 0, &[ipc::DISPLAY_COUNT, 0, 0])?;
pub fn first_display(&self) -> io::Result<connector::Handle> {
for &connector in self.resource_handles().unwrap().connectors() {
if self.get_connector(connector, true)?.state() == State::Connected {
return Ok(connector);
}
}
Ok(cmd.count)
Err(io::Error::other("no connected display"))
}
pub fn display_size(&self, id: usize) -> io::Result<(u32, u32)> {
let mut cmd = ipc::DisplaySize {
display_id: id,
width: 0,
height: 0,
};
unsafe {
sys_call(&self.file, &mut cmd, 0, &[ipc::DISPLAY_SIZE, 0, 0])?;
}
Ok((cmd.width, cmd.height))
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<usize> {
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<DumbBuffer> {
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<DisplayMap> {
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<DumbMapping<'a>> {
self.map_dumb_buffer(buffer)
}
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 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,
@@ -156,49 +114,11 @@ pub mod ipc {
pub use redox_ioctl::drm::*;
// FIXME replace these with proper drm interfaces
pub const DISPLAY_COUNT: u64 = 1;
#[repr(C, packed)]
pub struct DisplayCount {
pub count: usize,
}
pub const DISPLAY_SIZE: u64 = 2;
#[repr(C, packed)]
pub struct DisplaySize {
pub display_id: usize,
pub width: u32,
pub height: u32,
}
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,
}
}