/// Check the `util` module to see how the `Card` structure is implemented. pub mod utils; use crate::utils::*; use drm::control::{from_u32, RawResourceHandle}; pub fn main() { let card = Card::open_global(); // Enable all possible client capabilities for &cap in capabilities::CLIENT_CAP_ENUMS { if let Err(e) = card.set_client_capability(cap, true) { eprintln!("Unable to activate capability {:?}: {}", cap, e); return; } } run_repl(&card); } fn run_repl(card: &Card) { // Load a set of numbered images let images = [ images::load_image("1.png"), images::load_image("2.png"), images::load_image("3.png"), images::load_image("4.png"), ]; for image in &images { // Create the Dumbbuffer let fmt = drm::buffer::DrmFourcc::Xrgb8888; let mut db = card .create_dumb_buffer(image.dimensions(), fmt, 32) .unwrap(); // Create a Framebuffer to represent it let _fb = card.add_framebuffer(&db, 24, 32).unwrap(); // Load the image into the buffer { let mut mapping = card.map_dumb_buffer(&mut db).unwrap(); let buffer = mapping.as_mut(); for (img_px, map_px) in image.pixels().zip(buffer.chunks_exact_mut(4)) { // Assuming little endian, it's BGRA map_px[0] = img_px[0]; // Blue map_px[1] = img_px[1]; // Green map_px[2] = img_px[2]; // Red map_px[3] = img_px[3]; // Alpha } }; } // Using rustyline to create the interactive prompt. let editor_config = rustyline::config::Builder::new() .max_history_size(256) .unwrap() .completion_type(rustyline::config::CompletionType::List) .edit_mode(rustyline::config::EditMode::Vi) .auto_add_history(true) .build(); let mut kms_editor = rustyline::Editor::<(), _>::with_config(editor_config).unwrap(); let mut atomic_editor = rustyline::Editor::<(), _>::with_config(editor_config).unwrap(); for line in kms_editor.iter("KMS>> ").map(|x| x.unwrap()) { let args: Vec<_> = line.split_whitespace().collect(); match &args[..] { ["CreateAtomicSet"] => { for line in atomic_editor.iter("Atomic>> ").map(|x| x.unwrap()) { let args: Vec<_> = line.split_whitespace().collect(); match &args[..] { ["Quit"] => break, args => println!("{:?}", args), } } } // Destroying a framebuffer ["DestroyFramebuffer", handle] => { let handle: u32 = str::parse(handle).unwrap(); let handle: drm::control::framebuffer::Handle = from_u32(handle).unwrap(); if let Err(err) = card.destroy_framebuffer(handle) { println!("Unable to destroy framebuffer ({:?}): {}", handle, err); } } // Print out all resources ["GetResources"] => { let resources = card.resource_handles().unwrap(); println!("\tConnectors: {:?}", resources.connectors()); println!("\tEncoders: {:?}", resources.encoders()); println!("\tCRTCS: {:?}", resources.crtcs()); println!("\tFramebuffers: {:?}", resources.framebuffers()); let planes = card.plane_handles().unwrap(); println!("\tPlanes: {:?}", planes); } // Print out the values of a specific property ["GetProperty", handle] => { let handle: u32 = str::parse(handle).unwrap(); let handle: drm::control::property::Handle = from_u32(handle).unwrap(); let property = card.get_property(handle).unwrap(); println!("\tName: {:?}", property.name()); println!("\tMutable: {:?}", property.mutable()); println!("\tAtomic: {:?}", property.atomic()); println!("\tValue: {:#?}", property.value_type()); } // Get the property-value pairs of a single resource ["GetProperties", handle] => match HandleWithProperties::from_str(card, handle) { Ok(handle) => { let props = match handle { HandleWithProperties::Connector(handle) => { card.get_properties(handle).unwrap() } HandleWithProperties::CRTC(handle) => card.get_properties(handle).unwrap(), HandleWithProperties::Plane(handle) => card.get_properties(handle).unwrap(), }; for (id, val) in props.iter() { println!("\tProperty: {:?}\tValue: {:?}", id, val); } } Err(_) => println!("Unknown handle or handle has no properties"), }, // Set a property's value on a resource ["SetProperty", handle, property, value] => { let property: u32 = str::parse(property).unwrap(); let property: drm::control::property::Handle = from_u32(property).unwrap(); let value: u64 = str::parse(value).unwrap(); match HandleWithProperties::from_str(card, handle) { Ok(handle) => { match handle { HandleWithProperties::Connector(handle) => { println!("\t{:?}", card.set_property(handle, property, value)); } HandleWithProperties::CRTC(handle) => { println!("\t{:?}", card.set_property(handle, property, value)); } HandleWithProperties::Plane(handle) => { println!("\t{:?}", card.set_property(handle, property, value)); } }; } Err(_) => println!("Unknown handle or handle has no properties"), }; } ["GetModes", handle] => match HandleWithProperties::from_str(card, handle) { Ok(HandleWithProperties::Connector(handle)) => { let modes = card.get_modes(handle).unwrap(); for mode in modes { println!("\tName:\t{:?}", mode.name()); println!("\t\tSize:\t{:?}", mode.size()); println!("\t\tRefresh:\t{:?}", mode.vrefresh()); } } _ => println!("Unknown handle or handle is not a connector"), }, ["help"] => { println!("CreateAtomicSet"); println!("DestroyFramebuffer "); println!("GetResources"); println!("GetProperty "); println!("GetProperties "); println!("SetProperty "); println!("GetModes "); } ["quit"] => break, [] => (), _ => { println!("Unknown command"); } } } } #[allow(clippy::upper_case_acronyms)] enum HandleWithProperties { Connector(drm::control::connector::Handle), CRTC(drm::control::crtc::Handle), Plane(drm::control::plane::Handle), } impl HandleWithProperties { // This is a helper command that will take a string of a number and lookup // the corresponding resource. fn from_str(card: &Card, handle: &str) -> Result { let handle: u32 = str::parse(handle).unwrap(); let handle = RawResourceHandle::new(handle).unwrap(); let rhandles = card.resource_handles().unwrap(); for connector in rhandles.connectors().iter().map(|h| (*h).into()) { if handle == connector { return Ok(HandleWithProperties::Connector(handle.into())); } } for crtc in rhandles.crtcs().iter().map(|h| (*h).into()) { if handle == crtc { return Ok(HandleWithProperties::CRTC(handle.into())); } } let phandles = card.plane_handles().unwrap(); for plane in phandles.iter().map(|h| (*h).into()) { if handle == plane { return Ok(HandleWithProperties::Plane(handle.into())); } } Err(()) } }