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