1 mod utils;
2 use crate::utils::*;
3 
4 use drm::control::Device as ControlDevice;
5 use drm::Device as BasicDevice;
6 
7 use drm::buffer::DrmFourcc;
8 
9 use drm::control::{self, atomic, connector, crtc, property, AtomicCommitFlags};
10 
main()11 pub fn main() {
12     let card = Card::open_global();
13 
14     card.set_client_capability(drm::ClientCapability::UniversalPlanes, true)
15         .expect("Unable to request UniversalPlanes capability");
16     card.set_client_capability(drm::ClientCapability::Atomic, true)
17         .expect("Unable to request Atomic capability");
18 
19     // Load the information.
20     let res = card
21         .resource_handles()
22         .expect("Could not load normal resource ids.");
23     let coninfo: Vec<connector::Info> = res
24         .connectors()
25         .iter()
26         .flat_map(|con| card.get_connector(*con, true))
27         .collect();
28     let crtcinfo: Vec<crtc::Info> = res
29         .crtcs()
30         .iter()
31         .flat_map(|crtc| card.get_crtc(*crtc))
32         .collect();
33 
34     // Filter each connector until we find one that's connected.
35     let con = coninfo
36         .iter()
37         .find(|&i| i.state() == connector::State::Connected)
38         .expect("No connected connectors");
39 
40     // Get the first (usually best) mode
41     let &mode = con.modes().first().expect("No modes found on connector");
42 
43     let (disp_width, disp_height) = mode.size();
44 
45     // Find a crtc and FB
46     let crtc = crtcinfo.first().expect("No crtcs found");
47 
48     // Select the pixel format
49     let fmt = DrmFourcc::Xrgb8888;
50 
51     // Create a DB
52     // If buffer resolution is above display resolution, a ENOSPC (not enough GPU memory) error may
53     // occur
54     let mut db = card
55         .create_dumb_buffer((disp_width.into(), disp_height.into()), fmt, 32)
56         .expect("Could not create dumb buffer");
57 
58     // Map it and grey it out.
59     {
60         let mut map = card
61             .map_dumb_buffer(&mut db)
62             .expect("Could not map dumbbuffer");
63         for b in map.as_mut() {
64             *b = 128;
65         }
66     }
67 
68     // Create an FB:
69     let fb = card
70         .add_framebuffer(&db, 24, 32)
71         .expect("Could not create FB");
72 
73     let planes = card.plane_handles().expect("Could not list planes");
74     let (better_planes, compatible_planes): (
75         Vec<control::plane::Handle>,
76         Vec<control::plane::Handle>,
77     ) = planes
78         .iter()
79         .filter(|&&plane| {
80             card.get_plane(plane)
81                 .map(|plane_info| {
82                     let compatible_crtcs = res.filter_crtcs(plane_info.possible_crtcs());
83                     compatible_crtcs.contains(&crtc.handle())
84                 })
85                 .unwrap_or(false)
86         })
87         .partition(|&&plane| {
88             if let Ok(props) = card.get_properties(plane) {
89                 for (&id, &val) in props.iter() {
90                     if let Ok(info) = card.get_property(id) {
91                         if info.name().to_str().map(|x| x == "type").unwrap_or(false) {
92                             return val == (drm::control::PlaneType::Primary as u32).into();
93                         }
94                     }
95                 }
96             }
97             false
98         });
99     let plane = *better_planes.first().unwrap_or(&compatible_planes[0]);
100 
101     println!("{:#?}", mode);
102     println!("{:#?}", fb);
103     println!("{:#?}", db);
104     println!("{:#?}", plane);
105 
106     let con_props = card
107         .get_properties(con.handle())
108         .expect("Could not get props of connector")
109         .as_hashmap(&card)
110         .expect("Could not get a prop from connector");
111     let crtc_props = card
112         .get_properties(crtc.handle())
113         .expect("Could not get props of crtc")
114         .as_hashmap(&card)
115         .expect("Could not get a prop from crtc");
116     let plane_props = card
117         .get_properties(plane)
118         .expect("Could not get props of plane")
119         .as_hashmap(&card)
120         .expect("Could not get a prop from plane");
121 
122     let mut atomic_req = atomic::AtomicModeReq::new();
123     atomic_req.add_property(
124         con.handle(),
125         con_props["CRTC_ID"].handle(),
126         property::Value::CRTC(Some(crtc.handle())),
127     );
128     let blob = card
129         .create_property_blob(&mode)
130         .expect("Failed to create blob");
131     atomic_req.add_property(crtc.handle(), crtc_props["MODE_ID"].handle(), blob);
132     atomic_req.add_property(
133         crtc.handle(),
134         crtc_props["ACTIVE"].handle(),
135         property::Value::Boolean(true),
136     );
137     atomic_req.add_property(
138         plane,
139         plane_props["FB_ID"].handle(),
140         property::Value::Framebuffer(Some(fb)),
141     );
142     atomic_req.add_property(
143         plane,
144         plane_props["CRTC_ID"].handle(),
145         property::Value::CRTC(Some(crtc.handle())),
146     );
147     atomic_req.add_property(
148         plane,
149         plane_props["SRC_X"].handle(),
150         property::Value::UnsignedRange(0),
151     );
152     atomic_req.add_property(
153         plane,
154         plane_props["SRC_Y"].handle(),
155         property::Value::UnsignedRange(0),
156     );
157     atomic_req.add_property(
158         plane,
159         plane_props["SRC_W"].handle(),
160         property::Value::UnsignedRange((mode.size().0 as u64) << 16),
161     );
162     atomic_req.add_property(
163         plane,
164         plane_props["SRC_H"].handle(),
165         property::Value::UnsignedRange((mode.size().1 as u64) << 16),
166     );
167     atomic_req.add_property(
168         plane,
169         plane_props["CRTC_X"].handle(),
170         property::Value::SignedRange(0),
171     );
172     atomic_req.add_property(
173         plane,
174         plane_props["CRTC_Y"].handle(),
175         property::Value::SignedRange(0),
176     );
177     atomic_req.add_property(
178         plane,
179         plane_props["CRTC_W"].handle(),
180         property::Value::UnsignedRange(mode.size().0 as u64),
181     );
182     atomic_req.add_property(
183         plane,
184         plane_props["CRTC_H"].handle(),
185         property::Value::UnsignedRange(mode.size().1 as u64),
186     );
187 
188     // Set the crtc
189     // On many setups, this requires root access.
190     card.atomic_commit(AtomicCommitFlags::ALLOW_MODESET, atomic_req)
191         .expect("Failed to set mode");
192 
193     let five_seconds = ::std::time::Duration::from_millis(5000);
194     ::std::thread::sleep(five_seconds);
195 
196     card.destroy_framebuffer(fb).unwrap();
197     card.destroy_dumb_buffer(db).unwrap();
198 }
199