1 /// Check the `util` module to see how the `Card` structure is implemented.
2 pub mod utils;
3 use crate::utils::*;
4 use drm::control::{from_u32, RawResourceHandle};
5
main()6 pub fn main() {
7 let card = Card::open_global();
8
9 // Enable all possible client capabilities
10 for &cap in capabilities::CLIENT_CAP_ENUMS {
11 if let Err(e) = card.set_client_capability(cap, true) {
12 eprintln!("Unable to activate capability {:?}: {}", cap, e);
13 return;
14 }
15 }
16
17 run_repl(&card);
18 }
19
run_repl(card: &Card)20 fn run_repl(card: &Card) {
21 // Load a set of numbered images
22 let images = [
23 images::load_image("1.png"),
24 images::load_image("2.png"),
25 images::load_image("3.png"),
26 images::load_image("4.png"),
27 ];
28
29 for image in &images {
30 // Create the Dumbbuffer
31 let fmt = drm::buffer::DrmFourcc::Xrgb8888;
32 let mut db = card
33 .create_dumb_buffer(image.dimensions(), fmt, 32)
34 .unwrap();
35
36 // Create a Framebuffer to represent it
37 let _fb = card.add_framebuffer(&db, 24, 32).unwrap();
38
39 // Load the image into the buffer
40 {
41 let mut mapping = card.map_dumb_buffer(&mut db).unwrap();
42 let buffer = mapping.as_mut();
43 for (img_px, map_px) in image.pixels().zip(buffer.chunks_exact_mut(4)) {
44 // Assuming little endian, it's BGRA
45 map_px[0] = img_px[0]; // Blue
46 map_px[1] = img_px[1]; // Green
47 map_px[2] = img_px[2]; // Red
48 map_px[3] = img_px[3]; // Alpha
49 }
50 };
51 }
52
53 // Using rustyline to create the interactive prompt.
54 let editor_config = rustyline::config::Builder::new()
55 .max_history_size(256)
56 .unwrap()
57 .completion_type(rustyline::config::CompletionType::List)
58 .edit_mode(rustyline::config::EditMode::Vi)
59 .auto_add_history(true)
60 .build();
61 let mut kms_editor = rustyline::Editor::<(), _>::with_config(editor_config).unwrap();
62 let mut atomic_editor = rustyline::Editor::<(), _>::with_config(editor_config).unwrap();
63
64 for line in kms_editor.iter("KMS>> ").map(|x| x.unwrap()) {
65 let args: Vec<_> = line.split_whitespace().collect();
66 match &args[..] {
67 ["CreateAtomicSet"] => {
68 for line in atomic_editor.iter("Atomic>> ").map(|x| x.unwrap()) {
69 let args: Vec<_> = line.split_whitespace().collect();
70 match &args[..] {
71 ["Quit"] => break,
72 args => println!("{:?}", args),
73 }
74 }
75 }
76 // Destroying a framebuffer
77 ["DestroyFramebuffer", handle] => {
78 let handle: u32 = str::parse(handle).unwrap();
79 let handle: drm::control::framebuffer::Handle = from_u32(handle).unwrap();
80 if let Err(err) = card.destroy_framebuffer(handle) {
81 println!("Unable to destroy framebuffer ({:?}): {}", handle, err);
82 }
83 }
84 // Print out all resources
85 ["GetResources"] => {
86 let resources = card.resource_handles().unwrap();
87 println!("\tConnectors: {:?}", resources.connectors());
88 println!("\tEncoders: {:?}", resources.encoders());
89 println!("\tCRTCS: {:?}", resources.crtcs());
90 println!("\tFramebuffers: {:?}", resources.framebuffers());
91 let planes = card.plane_handles().unwrap();
92 println!("\tPlanes: {:?}", planes);
93 }
94 // Print out the values of a specific property
95 ["GetProperty", handle] => {
96 let handle: u32 = str::parse(handle).unwrap();
97 let handle: drm::control::property::Handle = from_u32(handle).unwrap();
98 let property = card.get_property(handle).unwrap();
99 println!("\tName: {:?}", property.name());
100 println!("\tMutable: {:?}", property.mutable());
101 println!("\tAtomic: {:?}", property.atomic());
102 println!("\tValue: {:#?}", property.value_type());
103 }
104 // Get the property-value pairs of a single resource
105 ["GetProperties", handle] => match HandleWithProperties::from_str(card, handle) {
106 Ok(handle) => {
107 let props = match handle {
108 HandleWithProperties::Connector(handle) => {
109 card.get_properties(handle).unwrap()
110 }
111 HandleWithProperties::CRTC(handle) => card.get_properties(handle).unwrap(),
112 HandleWithProperties::Plane(handle) => card.get_properties(handle).unwrap(),
113 };
114 for (id, val) in props.iter() {
115 println!("\tProperty: {:?}\tValue: {:?}", id, val);
116 }
117 }
118 Err(_) => println!("Unknown handle or handle has no properties"),
119 },
120 // Set a property's value on a resource
121 ["SetProperty", handle, property, value] => {
122 let property: u32 = str::parse(property).unwrap();
123 let property: drm::control::property::Handle = from_u32(property).unwrap();
124 let value: u64 = str::parse(value).unwrap();
125
126 match HandleWithProperties::from_str(card, handle) {
127 Ok(handle) => {
128 match handle {
129 HandleWithProperties::Connector(handle) => {
130 println!("\t{:?}", card.set_property(handle, property, value));
131 }
132 HandleWithProperties::CRTC(handle) => {
133 println!("\t{:?}", card.set_property(handle, property, value));
134 }
135 HandleWithProperties::Plane(handle) => {
136 println!("\t{:?}", card.set_property(handle, property, value));
137 }
138 };
139 }
140 Err(_) => println!("Unknown handle or handle has no properties"),
141 };
142 }
143 ["GetModes", handle] => match HandleWithProperties::from_str(card, handle) {
144 Ok(HandleWithProperties::Connector(handle)) => {
145 let modes = card.get_modes(handle).unwrap();
146 for mode in modes {
147 println!("\tName:\t{:?}", mode.name());
148 println!("\t\tSize:\t{:?}", mode.size());
149 println!("\t\tRefresh:\t{:?}", mode.vrefresh());
150 }
151 }
152 _ => println!("Unknown handle or handle is not a connector"),
153 },
154 ["help"] => {
155 println!("CreateAtomicSet");
156 println!("DestroyFramebuffer <handle>");
157 println!("GetResources");
158 println!("GetProperty <handle>");
159 println!("GetProperties <handle>");
160 println!("SetProperty <handle> <poperty> <value>");
161 println!("GetModes <handle>");
162 }
163 ["quit"] => break,
164 [] => (),
165 _ => {
166 println!("Unknown command");
167 }
168 }
169 }
170 }
171
172 #[allow(clippy::upper_case_acronyms)]
173 enum HandleWithProperties {
174 Connector(drm::control::connector::Handle),
175 CRTC(drm::control::crtc::Handle),
176 Plane(drm::control::plane::Handle),
177 }
178
179 impl HandleWithProperties {
180 // This is a helper command that will take a string of a number and lookup
181 // the corresponding resource.
from_str(card: &Card, handle: &str) -> Result<Self, ()>182 fn from_str(card: &Card, handle: &str) -> Result<Self, ()> {
183 let handle: u32 = str::parse(handle).unwrap();
184 let handle = RawResourceHandle::new(handle).unwrap();
185
186 let rhandles = card.resource_handles().unwrap();
187 for connector in rhandles.connectors().iter().map(|h| (*h).into()) {
188 if handle == connector {
189 return Ok(HandleWithProperties::Connector(handle.into()));
190 }
191 }
192
193 for crtc in rhandles.crtcs().iter().map(|h| (*h).into()) {
194 if handle == crtc {
195 return Ok(HandleWithProperties::CRTC(handle.into()));
196 }
197 }
198
199 let phandles = card.plane_handles().unwrap();
200 for plane in phandles.iter().map(|h| (*h).into()) {
201 if handle == plane {
202 return Ok(HandleWithProperties::Plane(handle.into()));
203 }
204 }
205
206 Err(())
207 }
208 }
209