| /// 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 <handle>"); |
| println!("GetResources"); |
| println!("GetProperty <handle>"); |
| println!("GetProperties <handle>"); |
| println!("SetProperty <handle> <poperty> <value>"); |
| println!("GetModes <handle>"); |
| } |
| ["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<Self, ()> { |
| 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(()) |
| } |
| } |