mod utils; use crate::utils::*; use drm::control::Device as ControlDevice; use drm::Device as BasicDevice; use drm::buffer::DrmFourcc; use drm::control::{self, atomic, connector, crtc, property, AtomicCommitFlags}; pub fn main() { let card = Card::open_global(); card.set_client_capability(drm::ClientCapability::UniversalPlanes, true) .expect("Unable to request UniversalPlanes capability"); card.set_client_capability(drm::ClientCapability::Atomic, true) .expect("Unable to request Atomic capability"); // Load the information. let res = card .resource_handles() .expect("Could not load normal resource ids."); let coninfo: Vec = res .connectors() .iter() .flat_map(|con| card.get_connector(*con, true)) .collect(); let crtcinfo: Vec = res .crtcs() .iter() .flat_map(|crtc| card.get_crtc(*crtc)) .collect(); // Filter each connector until we find one that's connected. let con = coninfo .iter() .find(|&i| i.state() == connector::State::Connected) .expect("No connected connectors"); // Get the first (usually best) mode let &mode = con.modes().first().expect("No modes found on connector"); let (disp_width, disp_height) = mode.size(); // Find a crtc and FB let crtc = crtcinfo.first().expect("No crtcs found"); // Select the pixel format let fmt = DrmFourcc::Xrgb8888; // Create a DB // If buffer resolution is above display resolution, a ENOSPC (not enough GPU memory) error may // occur let mut db = card .create_dumb_buffer((disp_width.into(), disp_height.into()), fmt, 32) .expect("Could not create dumb buffer"); // Map it and grey it out. { let mut map = card .map_dumb_buffer(&mut db) .expect("Could not map dumbbuffer"); for b in map.as_mut() { *b = 128; } } // Create an FB: let fb = card .add_framebuffer(&db, 24, 32) .expect("Could not create FB"); let planes = card.plane_handles().expect("Could not list planes"); let (better_planes, compatible_planes): ( Vec, Vec, ) = planes .iter() .filter(|&&plane| { card.get_plane(plane) .map(|plane_info| { let compatible_crtcs = res.filter_crtcs(plane_info.possible_crtcs()); compatible_crtcs.contains(&crtc.handle()) }) .unwrap_or(false) }) .partition(|&&plane| { if let Ok(props) = card.get_properties(plane) { for (&id, &val) in props.iter() { if let Ok(info) = card.get_property(id) { if info.name().to_str().map(|x| x == "type").unwrap_or(false) { return val == (drm::control::PlaneType::Primary as u32).into(); } } } } false }); let plane = *better_planes.first().unwrap_or(&compatible_planes[0]); println!("{:#?}", mode); println!("{:#?}", fb); println!("{:#?}", db); println!("{:#?}", plane); let con_props = card .get_properties(con.handle()) .expect("Could not get props of connector") .as_hashmap(&card) .expect("Could not get a prop from connector"); let crtc_props = card .get_properties(crtc.handle()) .expect("Could not get props of crtc") .as_hashmap(&card) .expect("Could not get a prop from crtc"); let plane_props = card .get_properties(plane) .expect("Could not get props of plane") .as_hashmap(&card) .expect("Could not get a prop from plane"); let mut atomic_req = atomic::AtomicModeReq::new(); atomic_req.add_property( con.handle(), con_props["CRTC_ID"].handle(), property::Value::CRTC(Some(crtc.handle())), ); let blob = card .create_property_blob(&mode) .expect("Failed to create blob"); atomic_req.add_property(crtc.handle(), crtc_props["MODE_ID"].handle(), blob); atomic_req.add_property( crtc.handle(), crtc_props["ACTIVE"].handle(), property::Value::Boolean(true), ); atomic_req.add_property( plane, plane_props["FB_ID"].handle(), property::Value::Framebuffer(Some(fb)), ); atomic_req.add_property( plane, plane_props["CRTC_ID"].handle(), property::Value::CRTC(Some(crtc.handle())), ); atomic_req.add_property( plane, plane_props["SRC_X"].handle(), property::Value::UnsignedRange(0), ); atomic_req.add_property( plane, plane_props["SRC_Y"].handle(), property::Value::UnsignedRange(0), ); atomic_req.add_property( plane, plane_props["SRC_W"].handle(), property::Value::UnsignedRange((mode.size().0 as u64) << 16), ); atomic_req.add_property( plane, plane_props["SRC_H"].handle(), property::Value::UnsignedRange((mode.size().1 as u64) << 16), ); atomic_req.add_property( plane, plane_props["CRTC_X"].handle(), property::Value::SignedRange(0), ); atomic_req.add_property( plane, plane_props["CRTC_Y"].handle(), property::Value::SignedRange(0), ); atomic_req.add_property( plane, plane_props["CRTC_W"].handle(), property::Value::UnsignedRange(mode.size().0 as u64), ); atomic_req.add_property( plane, plane_props["CRTC_H"].handle(), property::Value::UnsignedRange(mode.size().1 as u64), ); // Set the crtc // On many setups, this requires root access. card.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, atomic_req) .expect("Failed to set mode"); let five_seconds = ::std::time::Duration::from_millis(5000); ::std::thread::sleep(five_seconds); card.destroy_framebuffer(fb).unwrap(); card.destroy_dumb_buffer(db).unwrap(); }