Struct Card

Source
pub struct Card { /* private fields */ }

Implementations§

Source§

impl Card

Source

pub fn open(path: impl AsRef<CStr>) -> Result<Self, InitError>

Open the file at the given path and attempt to use it as a DRM card file descriptor.

Returns result::InitError::NotDrmCard if the opened file does not support the DRM_IOCTL_VERSION ioctl request.

Examples found in repository?
examples/modesetting.rs (line 19)
17fn main() -> std::io::Result<()> {
18    let card_path = card_path();
19    let mut card = Card::open(card_path).map_err(map_init_err)?;
20    card.become_master().map_err(map_err)?;
21
22    {
23        let name = card.driver_name().map_err(map_err)?;
24        let name = String::from_utf8_lossy(&name);
25        println!("Driver name: {name}");
26    }
27
28    if card
29        .get_device_cap(DeviceCap::DumbBuffer)
30        .map_err(map_err)?
31        == 0
32    {
33        return Err(std::io::Error::other(
34            "device does not support 'dumb buffers'",
35        ));
36    } else {
37        println!("Device supports 'dumb buffers'");
38    }
39
40    display_demo(&mut card).map_err(map_err)
41}
More examples
Hide additional examples
examples/properties.rs (line 16)
14fn main() -> std::io::Result<()> {
15    let card_path = card_path();
16    let mut card = Card::open(card_path).map_err(map_init_err)?;
17
18    {
19        let name = card.driver_name().map_err(map_err)?;
20        let name = String::from_utf8_lossy(&name);
21        println!("Driver name: {name}");
22    }
23
24    if card
25        .get_device_cap(DeviceCap::DumbBuffer)
26        .map_err(map_err)?
27        == 0
28    {
29        return Err(std::io::Error::other(
30            "device does not support 'dumb buffers'",
31        ));
32    }
33
34    card.set_client_cap(ClientCap::UniversalPlanes, 1)
35        .map_err(map_err)?;
36    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
37
38    show_properties(&card).map_err(map_err)
39}
examples/modesetting-atomic.rs (line 18)
16fn main() -> std::io::Result<()> {
17    let card_path = card_path();
18    let mut card = Card::open(card_path).map_err(map_init_err)?;
19    card.become_master().map_err(map_err)?;
20
21    {
22        let name = card.driver_name().map_err(map_err)?;
23        let name = String::from_utf8_lossy(&name);
24        println!("Driver name: {name}");
25    }
26
27    if card
28        .get_device_cap(DeviceCap::DumbBuffer)
29        .map_err(map_err)?
30        == 0
31    {
32        return Err(std::io::Error::other(
33            "device does not support 'dumb buffers'",
34        ));
35    } else {
36        println!("Device supports 'dumb buffers'");
37    }
38
39    card.set_client_cap(ClientCap::UniversalPlanes, 1)
40        .map_err(map_err)?;
41    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
42
43    display_demo(&mut card).map_err(map_err)
44}
Source

pub fn from_file<D>(f: File<D>) -> Result<Self, InitError>

Attempt to use the given file as a DRM card device.

Returns result::InitError::NotDrmCard if the opened file does not support the DRM_IOCTL_VERSION ioctl request.

Source

pub unsafe fn from_file_unchecked<D>(f: File<D>) -> Self

Wraps the given file in Card without checking whether it supports any DRM card ioctl requests.

Source

pub fn fd(&self) -> int

Get the open file descriptor for the card.

Interacting with this file descriptor outside of the Card abstraction may cause the abstraction to malfunction. It’s exposed primarily so it can be used with system functions like poll to wait for events on multiple file descriptors at once.

Source

pub fn api_version(&self) -> Result<ApiVersion, Error>

Determine the DRM API version supported by this device.

Source

pub fn read_driver_name<'a>( &self, into: &'a mut [u8], ) -> Result<&'a mut [u8], Error>

Read the driver name into the given slice.

Source

pub fn driver_name(&self) -> Result<Vec<u8>, Error>

Read the driver name into a vector.

Examples found in repository?
examples/modesetting.rs (line 23)
17fn main() -> std::io::Result<()> {
18    let card_path = card_path();
19    let mut card = Card::open(card_path).map_err(map_init_err)?;
20    card.become_master().map_err(map_err)?;
21
22    {
23        let name = card.driver_name().map_err(map_err)?;
24        let name = String::from_utf8_lossy(&name);
25        println!("Driver name: {name}");
26    }
27
28    if card
29        .get_device_cap(DeviceCap::DumbBuffer)
30        .map_err(map_err)?
31        == 0
32    {
33        return Err(std::io::Error::other(
34            "device does not support 'dumb buffers'",
35        ));
36    } else {
37        println!("Device supports 'dumb buffers'");
38    }
39
40    display_demo(&mut card).map_err(map_err)
41}
More examples
Hide additional examples
examples/properties.rs (line 19)
14fn main() -> std::io::Result<()> {
15    let card_path = card_path();
16    let mut card = Card::open(card_path).map_err(map_init_err)?;
17
18    {
19        let name = card.driver_name().map_err(map_err)?;
20        let name = String::from_utf8_lossy(&name);
21        println!("Driver name: {name}");
22    }
23
24    if card
25        .get_device_cap(DeviceCap::DumbBuffer)
26        .map_err(map_err)?
27        == 0
28    {
29        return Err(std::io::Error::other(
30            "device does not support 'dumb buffers'",
31        ));
32    }
33
34    card.set_client_cap(ClientCap::UniversalPlanes, 1)
35        .map_err(map_err)?;
36    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
37
38    show_properties(&card).map_err(map_err)
39}
examples/modesetting-atomic.rs (line 22)
16fn main() -> std::io::Result<()> {
17    let card_path = card_path();
18    let mut card = Card::open(card_path).map_err(map_init_err)?;
19    card.become_master().map_err(map_err)?;
20
21    {
22        let name = card.driver_name().map_err(map_err)?;
23        let name = String::from_utf8_lossy(&name);
24        println!("Driver name: {name}");
25    }
26
27    if card
28        .get_device_cap(DeviceCap::DumbBuffer)
29        .map_err(map_err)?
30        == 0
31    {
32        return Err(std::io::Error::other(
33            "device does not support 'dumb buffers'",
34        ));
35    } else {
36        println!("Device supports 'dumb buffers'");
37    }
38
39    card.set_client_cap(ClientCap::UniversalPlanes, 1)
40        .map_err(map_err)?;
41    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
42
43    display_demo(&mut card).map_err(map_err)
44}
Source

pub fn get_device_cap(&self, capability: DeviceCap) -> Result<u64, Error>

Read a device capability value.

Examples found in repository?
examples/modesetting.rs (line 29)
17fn main() -> std::io::Result<()> {
18    let card_path = card_path();
19    let mut card = Card::open(card_path).map_err(map_init_err)?;
20    card.become_master().map_err(map_err)?;
21
22    {
23        let name = card.driver_name().map_err(map_err)?;
24        let name = String::from_utf8_lossy(&name);
25        println!("Driver name: {name}");
26    }
27
28    if card
29        .get_device_cap(DeviceCap::DumbBuffer)
30        .map_err(map_err)?
31        == 0
32    {
33        return Err(std::io::Error::other(
34            "device does not support 'dumb buffers'",
35        ));
36    } else {
37        println!("Device supports 'dumb buffers'");
38    }
39
40    display_demo(&mut card).map_err(map_err)
41}
More examples
Hide additional examples
examples/properties.rs (line 25)
14fn main() -> std::io::Result<()> {
15    let card_path = card_path();
16    let mut card = Card::open(card_path).map_err(map_init_err)?;
17
18    {
19        let name = card.driver_name().map_err(map_err)?;
20        let name = String::from_utf8_lossy(&name);
21        println!("Driver name: {name}");
22    }
23
24    if card
25        .get_device_cap(DeviceCap::DumbBuffer)
26        .map_err(map_err)?
27        == 0
28    {
29        return Err(std::io::Error::other(
30            "device does not support 'dumb buffers'",
31        ));
32    }
33
34    card.set_client_cap(ClientCap::UniversalPlanes, 1)
35        .map_err(map_err)?;
36    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
37
38    show_properties(&card).map_err(map_err)
39}
examples/modesetting-atomic.rs (line 28)
16fn main() -> std::io::Result<()> {
17    let card_path = card_path();
18    let mut card = Card::open(card_path).map_err(map_init_err)?;
19    card.become_master().map_err(map_err)?;
20
21    {
22        let name = card.driver_name().map_err(map_err)?;
23        let name = String::from_utf8_lossy(&name);
24        println!("Driver name: {name}");
25    }
26
27    if card
28        .get_device_cap(DeviceCap::DumbBuffer)
29        .map_err(map_err)?
30        == 0
31    {
32        return Err(std::io::Error::other(
33            "device does not support 'dumb buffers'",
34        ));
35    } else {
36        println!("Device supports 'dumb buffers'");
37    }
38
39    card.set_client_cap(ClientCap::UniversalPlanes, 1)
40        .map_err(map_err)?;
41    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
42
43    display_demo(&mut card).map_err(map_err)
44}
Source

pub fn get_device_cap_raw(&self, capability: DrmCap) -> Result<u64, Error>

Read a device capability value using a raw capability number.

Source

pub fn set_client_cap( &mut self, capability: ClientCap, value: u64, ) -> Result<(), Error>

Read a device capability value using a raw capability number.

Examples found in repository?
examples/properties.rs (line 34)
14fn main() -> std::io::Result<()> {
15    let card_path = card_path();
16    let mut card = Card::open(card_path).map_err(map_init_err)?;
17
18    {
19        let name = card.driver_name().map_err(map_err)?;
20        let name = String::from_utf8_lossy(&name);
21        println!("Driver name: {name}");
22    }
23
24    if card
25        .get_device_cap(DeviceCap::DumbBuffer)
26        .map_err(map_err)?
27        == 0
28    {
29        return Err(std::io::Error::other(
30            "device does not support 'dumb buffers'",
31        ));
32    }
33
34    card.set_client_cap(ClientCap::UniversalPlanes, 1)
35        .map_err(map_err)?;
36    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
37
38    show_properties(&card).map_err(map_err)
39}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 39)
16fn main() -> std::io::Result<()> {
17    let card_path = card_path();
18    let mut card = Card::open(card_path).map_err(map_init_err)?;
19    card.become_master().map_err(map_err)?;
20
21    {
22        let name = card.driver_name().map_err(map_err)?;
23        let name = String::from_utf8_lossy(&name);
24        println!("Driver name: {name}");
25    }
26
27    if card
28        .get_device_cap(DeviceCap::DumbBuffer)
29        .map_err(map_err)?
30        == 0
31    {
32        return Err(std::io::Error::other(
33            "device does not support 'dumb buffers'",
34        ));
35    } else {
36        println!("Device supports 'dumb buffers'");
37    }
38
39    card.set_client_cap(ClientCap::UniversalPlanes, 1)
40        .map_err(map_err)?;
41    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
42
43    display_demo(&mut card).map_err(map_err)
44}
Source

pub fn set_client_cap_raw( &mut self, capability: DrmClientCap, value: u64, ) -> Result<(), Error>

Attempt to set a client capability, which might then change the behavior of other device functions.

Source

pub fn become_master(&mut self) -> Result<(), Error>

Attempt to become the “master” of this device, which is required for modesetting.

Examples found in repository?
examples/modesetting.rs (line 20)
17fn main() -> std::io::Result<()> {
18    let card_path = card_path();
19    let mut card = Card::open(card_path).map_err(map_init_err)?;
20    card.become_master().map_err(map_err)?;
21
22    {
23        let name = card.driver_name().map_err(map_err)?;
24        let name = String::from_utf8_lossy(&name);
25        println!("Driver name: {name}");
26    }
27
28    if card
29        .get_device_cap(DeviceCap::DumbBuffer)
30        .map_err(map_err)?
31        == 0
32    {
33        return Err(std::io::Error::other(
34            "device does not support 'dumb buffers'",
35        ));
36    } else {
37        println!("Device supports 'dumb buffers'");
38    }
39
40    display_demo(&mut card).map_err(map_err)
41}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 19)
16fn main() -> std::io::Result<()> {
17    let card_path = card_path();
18    let mut card = Card::open(card_path).map_err(map_init_err)?;
19    card.become_master().map_err(map_err)?;
20
21    {
22        let name = card.driver_name().map_err(map_err)?;
23        let name = String::from_utf8_lossy(&name);
24        println!("Driver name: {name}");
25    }
26
27    if card
28        .get_device_cap(DeviceCap::DumbBuffer)
29        .map_err(map_err)?
30        == 0
31    {
32        return Err(std::io::Error::other(
33            "device does not support 'dumb buffers'",
34        ));
35    } else {
36        println!("Device supports 'dumb buffers'");
37    }
38
39    card.set_client_cap(ClientCap::UniversalPlanes, 1)
40        .map_err(map_err)?;
41    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
42
43    display_demo(&mut card).map_err(map_err)
44}
Source

pub fn drop_master(&mut self) -> Result<(), Error>

Release the “master” status of this device, thus allowing other processes to claim it.

Source

pub fn property_meta( &self, prop_id: PropertyId, ) -> Result<ObjectPropMeta<'_>, Error>

Get metadata about a DRM property using its id.

Property ids are assigned dynamically and so must be detected at runtime.

Examples found in repository?
examples/properties.rs (line 170)
164fn property_meta<'a, 'card>(
165    prop_id: PropertyId,
166    prop_meta: &'a mut HashMap<u32, PropertyMeta>,
167    card: &Card,
168) -> Result<&'a PropertyMeta, Error> {
169    Ok(prop_meta.entry(prop_id.0).or_insert_with(|| {
170        card.property_meta(prop_id)
171            .map(|meta| {
172                let mut enum_names = BTreeMap::new();
173                for member in meta.enum_members().unwrap() {
174                    enum_names.insert(member.value(), member.name().to_string());
175                }
176                PropertyMeta {
177                    name: meta.name().to_string(),
178                    typ: meta.property_type(),
179                    immutable: meta.is_immutable(),
180                    values: meta.values().unwrap(),
181                    enum_names,
182                }
183            })
184            .unwrap_or(PropertyMeta {
185                name: String::from("<unknown>"),
186                typ: PropertyType::Unknown,
187                immutable: true,
188                values: Vec::new(),
189                enum_names: BTreeMap::new(),
190            })
191    }))
192}
Source

pub fn object_properties( &self, obj_id: impl Into<ObjectId>, ) -> Result<Vec<ModeProp>, Error>

Get the properties of the specified object in their raw form.

Use either Self::property_meta or Self::each_object_property_meta to discover the name and type information for each property id.

Examples found in repository?
examples/properties.rs (line 110)
105fn show_object_property_list(
106    id: impl Into<ObjectId>,
107    prop_meta: &mut HashMap<u32, PropertyMeta>,
108    card: &Card,
109) -> Result<(), Error> {
110    let props = card.object_properties(id)?;
111    show_property_list(&props, prop_meta, card)?;
112    Ok(())
113}
Source

pub fn each_object_property_meta( &self, obj_id: impl Into<ObjectId>, f: impl FnMut(ObjectPropMeta<'_>, u64), ) -> Result<(), Error>

Call f with the metadata for each property of the object with the given id.

This is intended for use by callers that want to build a lookup table of property ids for later use in efficiently setting those properties. Pass a closure that mutates the lookup table only for the subset of properties that are interesting.

Examples found in repository?
examples/modesetting-atomic.rs (line 289)
287    pub fn new(conn_id: ConnectorId, card: &linux_drm::Card) -> Result<Self, Error> {
288        let mut ret: Self = unsafe { core::mem::zeroed() };
289        card.each_object_property_meta(conn_id, |meta, _| ret.populate_from(meta))?;
290        Ok(ret)
291    }
292
293    pub fn populate_from<'card>(&mut self, from: linux_drm::modeset::ObjectPropMeta<'card>) {
294        match from.name() {
295            "CRTC_ID" => self.crtc_id = from.property_id(),
296            _ => {}
297        }
298    }
299}
300
301#[derive(Debug)]
302struct CrtcPropIds {
303    active: PropertyId,
304}
305
306impl CrtcPropIds {
307    pub fn new(crtc_id: CrtcId, card: &linux_drm::Card) -> Result<Self, Error> {
308        let mut ret: Self = unsafe { core::mem::zeroed() };
309        card.each_object_property_meta(linux_drm::modeset::ObjectId::Crtc(crtc_id), |meta, _| {
310            ret.populate_from(meta)
311        })?;
312        Ok(ret)
313    }
314
315    pub fn populate_from<'card>(&mut self, from: linux_drm::modeset::ObjectPropMeta<'card>) {
316        match from.name() {
317            "ACTIVE" => self.active = from.property_id(),
318            _ => {}
319        }
320    }
321}
322
323#[derive(Debug)]
324struct PlanePropIds {
325    typ: PropertyId,
326    fb_id: PropertyId,
327    crtc_id: PropertyId,
328    crtc_x: PropertyId,
329    crtc_y: PropertyId,
330    crtc_w: PropertyId,
331    crtc_h: PropertyId,
332    src_x: PropertyId,
333    src_y: PropertyId,
334    src_w: PropertyId,
335    src_h: PropertyId,
336}
337
338impl PlanePropIds {
339    pub fn new(plane_id: PlaneId, card: &linux_drm::Card) -> Result<Self, Error> {
340        let mut ret: Self = unsafe { core::mem::zeroed() };
341        card.each_object_property_meta(plane_id, |meta, _| ret.populate_from(meta))?;
342        Ok(ret)
343    }
Source

pub fn resources(&self) -> Result<CardResources, Error>

Read information about the modesetting resources available for this device.

The result includes ids for the available connectors, encoders, CRTCs, planes, and framebuffers.

Examples found in repository?
examples/modesetting.rs (line 109)
108fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
109    let resources = card.resources()?;
110    let mut outputs = Vec::<Output>::new();
111
112    for id in resources.connector_ids.iter().copied() {
113        let conn = card.connector_state(id)?;
114        if conn.connection_state != ConnectionState::Connected {
115            println!("ignoring unconnected connector {id:?}");
116            continue;
117        }
118        if conn.current_encoder_id.0 == 0 {
119            println!("ignoring encoderless connector {id:?}");
120            continue;
121        }
122        if conn.modes.len() == 0 {
123            println!("ignoring modeless connector {id:?}");
124            continue;
125        }
126
127        let output = prepare_output(card, conn, &resources)?;
128        outputs.push(output);
129    }
130
131    Ok(outputs)
132}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 182)
179fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
180    println!("preparing outputs");
181
182    let resources = card.resources()?;
183    let mut outputs = Vec::<Output>::new();
184
185    for id in resources.connector_ids.iter().copied() {
186        println!("preparing output for connector #{id:?}");
187
188        let conn = card.connector_state(id)?;
189        if conn.connection_state != ConnectionState::Connected {
190            println!("ignoring unconnected connector {id:?}");
191            continue;
192        }
193        if conn.current_encoder_id.0 == 0 {
194            println!("ignoring encoderless connector {id:?}");
195            continue;
196        }
197        if conn.modes.len() == 0 {
198            println!("ignoring modeless connector {id:?}");
199            continue;
200        }
201
202        let output = prepare_output(card, conn, &resources)?;
203        outputs.push(output);
204    }
205
206    Ok(outputs)
207}
examples/properties.rs (line 56)
55fn show_properties(card: &Card) -> Result<(), Error> {
56    let res = card.resources()?;
57
58    let mut prop_meta = HashMap::<u32, PropertyMeta>::new();
59
60    println!("");
61
62    for conn_id in res.connector_ids {
63        println!("Connector #{conn_id:?}:");
64        if let Err(e) = show_object_property_list(conn_id, &mut prop_meta, card) {
65            println!("  Error: {e:?}");
66        }
67        println!("");
68    }
69
70    for enc_id in res.encoder_ids {
71        println!("Encoder #{enc_id:?}:");
72        if let Err(e) = show_object_property_list(enc_id, &mut prop_meta, card) {
73            println!("  Error: {e:?}");
74        }
75        println!("");
76    }
77
78    for crtc_id in res.crtc_ids {
79        println!("CRTC #{crtc_id:?}:");
80        if let Err(e) = show_object_property_list(crtc_id, &mut prop_meta, card) {
81            println!("  Error: {e:?}");
82        }
83        println!("");
84    }
85
86    for fb_id in res.fb_ids {
87        println!("Framebuffer #{fb_id:?}:");
88        if let Err(e) = show_object_property_list(fb_id, &mut prop_meta, card) {
89            println!("  Error: {e:?}");
90        }
91        println!("");
92    }
93
94    for plane_id in res.plane_ids {
95        println!("Plane #{plane_id:?}:");
96        if let Err(e) = show_object_property_list(plane_id, &mut prop_meta, card) {
97            println!("  Error: {e:?}");
98        }
99        println!("");
100    }
101
102    Ok(())
103}
Source

pub fn connector_state( &self, connector_id: ConnectorId, ) -> Result<ConnectorState, Error>

Read current state information for the connector with the given id.

Examples found in repository?
examples/modesetting.rs (line 61)
57fn display_demo(card: &mut Card) -> Result<(), Error> {
58    let mut outputs = prepare_outputs(&card)?;
59    for output in &mut outputs {
60        println!("preparing output {output:#?}");
61        let conn = card.connector_state(output.conn_id)?;
62
63        let mode = &output.mode;
64        let mode_name = String::from_utf8_lossy(&mode.name);
65        println!(
66            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
67            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
68        );
69
70        let rows = output.db.height() as usize;
71        let pitch = output.db.pitch() as usize;
72        let data = output.db.buffer_mut();
73        for i in 0..rows {
74            if (i % 8) > 3 {
75                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
76                row.fill(0xff);
77            }
78        }
79
80        println!(
81            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
82            output.crtc_id,
83            output.db.framebuffer_id(),
84            conn.id
85        );
86        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
87        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
88    }
89
90    let mut evt_buf = vec![0_u8; 1024];
91    loop {
92        println!("waiting for events (send SIGINT to exit)");
93        for evt in card.read_events(&mut evt_buf)? {
94            println!("event {evt:?}");
95            match evt {
96                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
97                    // In a real program this would be a time place to draw the next frame
98                    // for the reported crtc.
99                }
100                _ => {
101                    // Ignore any unrecognized event types.
102                }
103            }
104        }
105    }
106}
107
108fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
109    let resources = card.resources()?;
110    let mut outputs = Vec::<Output>::new();
111
112    for id in resources.connector_ids.iter().copied() {
113        let conn = card.connector_state(id)?;
114        if conn.connection_state != ConnectionState::Connected {
115            println!("ignoring unconnected connector {id:?}");
116            continue;
117        }
118        if conn.current_encoder_id.0 == 0 {
119            println!("ignoring encoderless connector {id:?}");
120            continue;
121        }
122        if conn.modes.len() == 0 {
123            println!("ignoring modeless connector {id:?}");
124            continue;
125        }
126
127        let output = prepare_output(card, conn, &resources)?;
128        outputs.push(output);
129    }
130
131    Ok(outputs)
132}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 66)
60fn display_demo(card: &mut Card) -> Result<(), Error> {
61    let mut outputs = prepare_outputs(&card)?;
62    let mut req = linux_drm::modeset::AtomicRequest::new();
63
64    for output in &mut outputs {
65        println!("preparing output {output:#?}");
66        let conn = card.connector_state(output.conn_id)?;
67
68        let mode = &output.mode;
69        let mode_name = String::from_utf8_lossy(&mode.name);
70        println!(
71            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
72            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
73        );
74
75        let rows = output.db.height() as usize;
76        let pitch = output.db.pitch() as usize;
77        let data = output.db.buffer_mut();
78        for i in 0..rows {
79            if (i % 8) > 3 {
80                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
81                row.fill(0xff);
82            }
83        }
84
85        println!(
86            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connector {:?}",
87            output.crtc_id,
88            output.db.framebuffer_id(),
89            conn.id
90        );
91
92        req.set_property(
93            ObjectId::Connector(output.conn_id),
94            output.conn_prop_ids.crtc_id,
95            output.crtc_id,
96        );
97        req.set_property(
98            ObjectId::Crtc(output.crtc_id),
99            output.crtc_prop_ids.active,
100            true,
101        );
102        req.set_property(
103            ObjectId::Plane(output.plane_id),
104            output.plane_prop_ids.fb_id,
105            output.db.framebuffer_id(),
106        );
107        req.set_property(
108            ObjectId::Plane(output.plane_id),
109            output.plane_prop_ids.crtc_id,
110            output.crtc_id,
111        );
112        req.set_property(
113            ObjectId::Plane(output.plane_id),
114            output.plane_prop_ids.crtc_x,
115            0,
116        );
117        req.set_property(
118            ObjectId::Plane(output.plane_id),
119            output.plane_prop_ids.crtc_y,
120            0,
121        );
122        req.set_property(
123            ObjectId::Plane(output.plane_id),
124            output.plane_prop_ids.crtc_w,
125            output.db.width(),
126        );
127        req.set_property(
128            ObjectId::Plane(output.plane_id),
129            output.plane_prop_ids.crtc_h,
130            output.db.height(),
131        );
132        req.set_property(
133            ObjectId::Plane(output.plane_id),
134            output.plane_prop_ids.src_x,
135            0,
136        );
137        req.set_property(
138            ObjectId::Plane(output.plane_id),
139            output.plane_prop_ids.src_y,
140            0,
141        );
142        req.set_property(
143            ObjectId::Plane(output.plane_id),
144            output.plane_prop_ids.src_w,
145            (output.db.width() as u64) << 16,
146        );
147        req.set_property(
148            ObjectId::Plane(output.plane_id),
149            output.plane_prop_ids.src_h,
150            (output.db.height() as u64) << 16,
151        );
152    }
153
154    println!("atomic commit {req:#?}");
155    card.atomic_commit(
156        &req,
157        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
158        0,
159    )?;
160
161    let mut evt_buf = vec![0_u8; 1024];
162    loop {
163        println!("waiting for events (send SIGINT to exit)");
164        for evt in card.read_events(&mut evt_buf)? {
165            println!("event {evt:?}");
166            match evt {
167                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
168                    // In a real program this would be a time place to draw the next frame
169                    // for the reported crtc.
170                }
171                _ => {
172                    // Ignore any unrecognized event types.
173                }
174            }
175        }
176    }
177}
178
179fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
180    println!("preparing outputs");
181
182    let resources = card.resources()?;
183    let mut outputs = Vec::<Output>::new();
184
185    for id in resources.connector_ids.iter().copied() {
186        println!("preparing output for connector #{id:?}");
187
188        let conn = card.connector_state(id)?;
189        if conn.connection_state != ConnectionState::Connected {
190            println!("ignoring unconnected connector {id:?}");
191            continue;
192        }
193        if conn.current_encoder_id.0 == 0 {
194            println!("ignoring encoderless connector {id:?}");
195            continue;
196        }
197        if conn.modes.len() == 0 {
198            println!("ignoring modeless connector {id:?}");
199            continue;
200        }
201
202        let output = prepare_output(card, conn, &resources)?;
203        outputs.push(output);
204    }
205
206    Ok(outputs)
207}
Source

pub fn encoder_state( &self, encoder_id: EncoderId, ) -> Result<EncoderState, Error>

Read current state information for the encoder with the given id.

Examples found in repository?
examples/modesetting.rs (line 148)
134fn prepare_output(
135    card: &Card,
136    conn: ConnectorState,
137    resources: &CardResources,
138) -> Result<Output, Error> {
139    if conn.current_encoder_id.0 == 0 {
140        // It could be reasonable to go hunting for a suitable encoder and
141        // CRTC to activate this connector, but for this simple example
142        // we'll just use whatever connectors are already producing some
143        // output and keep using whatever modes they are currently in.
144        return Err(Error::NotSupported);
145    }
146    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
147
148    let enc = card.encoder_state(conn.current_encoder_id)?;
149    let crtc_id = enc.current_crtc_id;
150    let crtc = card.crtc_state(crtc_id)?;
151    let mode = crtc.mode;
152    let db = card.create_dumb_buffer(DumbBufferRequest {
153        width: mode.hdisplay as u32,
154        height: mode.vdisplay as u32,
155        depth: 24,
156        bpp: 32,
157    })?;
158    Ok(Output {
159        conn_id: conn.id,
160        crtc_id,
161        mode,
162        db,
163    })
164}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 223)
209fn prepare_output(
210    card: &Card,
211    conn: ConnectorState,
212    resources: &CardResources,
213) -> Result<Output, Error> {
214    if conn.current_encoder_id.0 == 0 {
215        // It could be reasonable to go hunting for a suitable encoder and
216        // CRTC to activate this connector, but for this simple example
217        // we'll just use whatever connectors are already producing some
218        // output and keep using whatever modes they are currently in.
219        return Err(Error::NotSupported);
220    }
221    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
222
223    let enc = card.encoder_state(conn.current_encoder_id)?;
224    let crtc_id = enc.current_crtc_id;
225    let crtc = card.crtc_state(crtc_id)?;
226    let mode = crtc.mode;
227    let db = card.create_dumb_buffer(DumbBufferRequest {
228        width: mode.hdisplay as u32,
229        height: mode.vdisplay as u32,
230        depth: 24,
231        bpp: 32,
232    })?;
233
234    // We need to find the primary plane that's currently assigned to this CRTC.
235    // The following is not really a correct way to do it, but it'll work for
236    // now just to test if anything is working here at all. (This makes some
237    // assumptions about how the card is already configured which might not
238    // actually hold in practice.)
239    let mut chosen_plane_id: Option<PlaneId> = None;
240    for plane_id in resources.plane_ids.iter().copied() {
241        let plane = card.plane_state(plane_id)?;
242        if plane.crtc_id == crtc_id {
243            chosen_plane_id = Some(plane_id);
244            break;
245        }
246    }
247    let Some(chosen_plane_id) = chosen_plane_id else {
248        return Err(Error::NonExist);
249    };
250
251    println!("collecting properties");
252    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
253    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
254    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
255
256    println!("collected properties");
257    Ok(Output {
258        conn_id: conn.id,
259        conn_prop_ids,
260        crtc_id,
261        crtc_prop_ids,
262        plane_id: chosen_plane_id,
263        plane_prop_ids,
264        mode,
265        db,
266    })
267}
Source

pub fn crtc_state(&self, crtc_id: CrtcId) -> Result<CrtcState, Error>

Read current state information for the CRTC with the given id.

Examples found in repository?
examples/modesetting.rs (line 150)
134fn prepare_output(
135    card: &Card,
136    conn: ConnectorState,
137    resources: &CardResources,
138) -> Result<Output, Error> {
139    if conn.current_encoder_id.0 == 0 {
140        // It could be reasonable to go hunting for a suitable encoder and
141        // CRTC to activate this connector, but for this simple example
142        // we'll just use whatever connectors are already producing some
143        // output and keep using whatever modes they are currently in.
144        return Err(Error::NotSupported);
145    }
146    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
147
148    let enc = card.encoder_state(conn.current_encoder_id)?;
149    let crtc_id = enc.current_crtc_id;
150    let crtc = card.crtc_state(crtc_id)?;
151    let mode = crtc.mode;
152    let db = card.create_dumb_buffer(DumbBufferRequest {
153        width: mode.hdisplay as u32,
154        height: mode.vdisplay as u32,
155        depth: 24,
156        bpp: 32,
157    })?;
158    Ok(Output {
159        conn_id: conn.id,
160        crtc_id,
161        mode,
162        db,
163    })
164}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 225)
209fn prepare_output(
210    card: &Card,
211    conn: ConnectorState,
212    resources: &CardResources,
213) -> Result<Output, Error> {
214    if conn.current_encoder_id.0 == 0 {
215        // It could be reasonable to go hunting for a suitable encoder and
216        // CRTC to activate this connector, but for this simple example
217        // we'll just use whatever connectors are already producing some
218        // output and keep using whatever modes they are currently in.
219        return Err(Error::NotSupported);
220    }
221    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
222
223    let enc = card.encoder_state(conn.current_encoder_id)?;
224    let crtc_id = enc.current_crtc_id;
225    let crtc = card.crtc_state(crtc_id)?;
226    let mode = crtc.mode;
227    let db = card.create_dumb_buffer(DumbBufferRequest {
228        width: mode.hdisplay as u32,
229        height: mode.vdisplay as u32,
230        depth: 24,
231        bpp: 32,
232    })?;
233
234    // We need to find the primary plane that's currently assigned to this CRTC.
235    // The following is not really a correct way to do it, but it'll work for
236    // now just to test if anything is working here at all. (This makes some
237    // assumptions about how the card is already configured which might not
238    // actually hold in practice.)
239    let mut chosen_plane_id: Option<PlaneId> = None;
240    for plane_id in resources.plane_ids.iter().copied() {
241        let plane = card.plane_state(plane_id)?;
242        if plane.crtc_id == crtc_id {
243            chosen_plane_id = Some(plane_id);
244            break;
245        }
246    }
247    let Some(chosen_plane_id) = chosen_plane_id else {
248        return Err(Error::NonExist);
249    };
250
251    println!("collecting properties");
252    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
253    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
254    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
255
256    println!("collected properties");
257    Ok(Output {
258        conn_id: conn.id,
259        conn_prop_ids,
260        crtc_id,
261        crtc_prop_ids,
262        plane_id: chosen_plane_id,
263        plane_prop_ids,
264        mode,
265        db,
266    })
267}
Source

pub fn plane_state(&self, plane_id: PlaneId) -> Result<PlaneState, Error>

Read current state information for the plane with the given id.

Examples found in repository?
examples/modesetting-atomic.rs (line 241)
209fn prepare_output(
210    card: &Card,
211    conn: ConnectorState,
212    resources: &CardResources,
213) -> Result<Output, Error> {
214    if conn.current_encoder_id.0 == 0 {
215        // It could be reasonable to go hunting for a suitable encoder and
216        // CRTC to activate this connector, but for this simple example
217        // we'll just use whatever connectors are already producing some
218        // output and keep using whatever modes they are currently in.
219        return Err(Error::NotSupported);
220    }
221    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
222
223    let enc = card.encoder_state(conn.current_encoder_id)?;
224    let crtc_id = enc.current_crtc_id;
225    let crtc = card.crtc_state(crtc_id)?;
226    let mode = crtc.mode;
227    let db = card.create_dumb_buffer(DumbBufferRequest {
228        width: mode.hdisplay as u32,
229        height: mode.vdisplay as u32,
230        depth: 24,
231        bpp: 32,
232    })?;
233
234    // We need to find the primary plane that's currently assigned to this CRTC.
235    // The following is not really a correct way to do it, but it'll work for
236    // now just to test if anything is working here at all. (This makes some
237    // assumptions about how the card is already configured which might not
238    // actually hold in practice.)
239    let mut chosen_plane_id: Option<PlaneId> = None;
240    for plane_id in resources.plane_ids.iter().copied() {
241        let plane = card.plane_state(plane_id)?;
242        if plane.crtc_id == crtc_id {
243            chosen_plane_id = Some(plane_id);
244            break;
245        }
246    }
247    let Some(chosen_plane_id) = chosen_plane_id else {
248        return Err(Error::NonExist);
249    };
250
251    println!("collecting properties");
252    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
253    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
254    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
255
256    println!("collected properties");
257    Ok(Output {
258        conn_id: conn.id,
259        conn_prop_ids,
260        crtc_id,
261        crtc_prop_ids,
262        plane_id: chosen_plane_id,
263        plane_prop_ids,
264        mode,
265        db,
266    })
267}
Source

pub fn atomic_commit( &mut self, req: &AtomicRequest, flags: AtomicCommitFlags, user_data: u64, ) -> Result<(), Error>

Attempt to commit an atomic modesetting request.

Callers which intend to perform frequent modesetting, such as modesetting on every frame for double buffering, are encouraged to retain their modeset::AtomicRequest object and reset it to use again on a subsequent request if that request will involve a similar set of objects and properties, to minimize the need for reallocating the backing storage for the request on every frame.

Examples found in repository?
examples/modesetting-atomic.rs (lines 155-159)
60fn display_demo(card: &mut Card) -> Result<(), Error> {
61    let mut outputs = prepare_outputs(&card)?;
62    let mut req = linux_drm::modeset::AtomicRequest::new();
63
64    for output in &mut outputs {
65        println!("preparing output {output:#?}");
66        let conn = card.connector_state(output.conn_id)?;
67
68        let mode = &output.mode;
69        let mode_name = String::from_utf8_lossy(&mode.name);
70        println!(
71            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
72            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
73        );
74
75        let rows = output.db.height() as usize;
76        let pitch = output.db.pitch() as usize;
77        let data = output.db.buffer_mut();
78        for i in 0..rows {
79            if (i % 8) > 3 {
80                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
81                row.fill(0xff);
82            }
83        }
84
85        println!(
86            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connector {:?}",
87            output.crtc_id,
88            output.db.framebuffer_id(),
89            conn.id
90        );
91
92        req.set_property(
93            ObjectId::Connector(output.conn_id),
94            output.conn_prop_ids.crtc_id,
95            output.crtc_id,
96        );
97        req.set_property(
98            ObjectId::Crtc(output.crtc_id),
99            output.crtc_prop_ids.active,
100            true,
101        );
102        req.set_property(
103            ObjectId::Plane(output.plane_id),
104            output.plane_prop_ids.fb_id,
105            output.db.framebuffer_id(),
106        );
107        req.set_property(
108            ObjectId::Plane(output.plane_id),
109            output.plane_prop_ids.crtc_id,
110            output.crtc_id,
111        );
112        req.set_property(
113            ObjectId::Plane(output.plane_id),
114            output.plane_prop_ids.crtc_x,
115            0,
116        );
117        req.set_property(
118            ObjectId::Plane(output.plane_id),
119            output.plane_prop_ids.crtc_y,
120            0,
121        );
122        req.set_property(
123            ObjectId::Plane(output.plane_id),
124            output.plane_prop_ids.crtc_w,
125            output.db.width(),
126        );
127        req.set_property(
128            ObjectId::Plane(output.plane_id),
129            output.plane_prop_ids.crtc_h,
130            output.db.height(),
131        );
132        req.set_property(
133            ObjectId::Plane(output.plane_id),
134            output.plane_prop_ids.src_x,
135            0,
136        );
137        req.set_property(
138            ObjectId::Plane(output.plane_id),
139            output.plane_prop_ids.src_y,
140            0,
141        );
142        req.set_property(
143            ObjectId::Plane(output.plane_id),
144            output.plane_prop_ids.src_w,
145            (output.db.width() as u64) << 16,
146        );
147        req.set_property(
148            ObjectId::Plane(output.plane_id),
149            output.plane_prop_ids.src_h,
150            (output.db.height() as u64) << 16,
151        );
152    }
153
154    println!("atomic commit {req:#?}");
155    card.atomic_commit(
156        &req,
157        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
158        0,
159    )?;
160
161    let mut evt_buf = vec![0_u8; 1024];
162    loop {
163        println!("waiting for events (send SIGINT to exit)");
164        for evt in card.read_events(&mut evt_buf)? {
165            println!("event {evt:?}");
166            match evt {
167                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
168                    // In a real program this would be a time place to draw the next frame
169                    // for the reported crtc.
170                }
171                _ => {
172                    // Ignore any unrecognized event types.
173                }
174            }
175        }
176    }
177}
Source

pub fn new_property_blob<'card, 'content>( &'card self, content: &'content [u8], ) -> Result<BlobHandle, Error>

Send the given content to the kernel as a property blob, ready to use for assignment to a blob-typed object property.

The returned modeset::BlobHandle must remain live long enough to be assigned to the target property. The blob object in the kernel will be destroyed when the blob handle is dropped.

Source

pub fn reset_crtc(&mut self, crtc_id: u32) -> Result<CrtcState, Error>

Reset the given CRTC to its default (zeroed) settings.

Source

pub fn set_crtc_dumb_buffer( &mut self, crtc_id: CrtcId, buf: &DumbBuffer, mode: &ModeInfo, conn_ids: &[ConnectorId], ) -> Result<CrtcState, Error>

Set the given CRTC to display the image from the given “dumb buffer”, used for software rendering.

Examples found in repository?
examples/modesetting.rs (line 86)
57fn display_demo(card: &mut Card) -> Result<(), Error> {
58    let mut outputs = prepare_outputs(&card)?;
59    for output in &mut outputs {
60        println!("preparing output {output:#?}");
61        let conn = card.connector_state(output.conn_id)?;
62
63        let mode = &output.mode;
64        let mode_name = String::from_utf8_lossy(&mode.name);
65        println!(
66            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
67            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
68        );
69
70        let rows = output.db.height() as usize;
71        let pitch = output.db.pitch() as usize;
72        let data = output.db.buffer_mut();
73        for i in 0..rows {
74            if (i % 8) > 3 {
75                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
76                row.fill(0xff);
77            }
78        }
79
80        println!(
81            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
82            output.crtc_id,
83            output.db.framebuffer_id(),
84            conn.id
85        );
86        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
87        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
88    }
89
90    let mut evt_buf = vec![0_u8; 1024];
91    loop {
92        println!("waiting for events (send SIGINT to exit)");
93        for evt in card.read_events(&mut evt_buf)? {
94            println!("event {evt:?}");
95            match evt {
96                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
97                    // In a real program this would be a time place to draw the next frame
98                    // for the reported crtc.
99                }
100                _ => {
101                    // Ignore any unrecognized event types.
102                }
103            }
104        }
105    }
106}
Source

pub fn crtc_page_flip_dumb_buffer( &mut self, crtd_id: CrtcId, buf: &DumbBuffer, flags: PageFlipFlags, ) -> Result<(), Error>

Use a page-flipping request to change the given CRTC to display the image from the given “dumb buffer”.

Examples found in repository?
examples/modesetting.rs (line 87)
57fn display_demo(card: &mut Card) -> Result<(), Error> {
58    let mut outputs = prepare_outputs(&card)?;
59    for output in &mut outputs {
60        println!("preparing output {output:#?}");
61        let conn = card.connector_state(output.conn_id)?;
62
63        let mode = &output.mode;
64        let mode_name = String::from_utf8_lossy(&mode.name);
65        println!(
66            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
67            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
68        );
69
70        let rows = output.db.height() as usize;
71        let pitch = output.db.pitch() as usize;
72        let data = output.db.buffer_mut();
73        for i in 0..rows {
74            if (i % 8) > 3 {
75                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
76                row.fill(0xff);
77            }
78        }
79
80        println!(
81            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
82            output.crtc_id,
83            output.db.framebuffer_id(),
84            conn.id
85        );
86        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
87        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
88    }
89
90    let mut evt_buf = vec![0_u8; 1024];
91    loop {
92        println!("waiting for events (send SIGINT to exit)");
93        for evt in card.read_events(&mut evt_buf)? {
94            println!("event {evt:?}");
95            match evt {
96                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
97                    // In a real program this would be a time place to draw the next frame
98                    // for the reported crtc.
99                }
100                _ => {
101                    // Ignore any unrecognized event types.
102                }
103            }
104        }
105    }
106}
Source

pub fn create_dumb_buffer( &self, req: DumbBufferRequest, ) -> Result<DumbBuffer, Error>

Create a new “dumb buffer” that can be used for portable (hardware-agnostic) software rendering.

Examples found in repository?
examples/modesetting.rs (lines 152-157)
134fn prepare_output(
135    card: &Card,
136    conn: ConnectorState,
137    resources: &CardResources,
138) -> Result<Output, Error> {
139    if conn.current_encoder_id.0 == 0 {
140        // It could be reasonable to go hunting for a suitable encoder and
141        // CRTC to activate this connector, but for this simple example
142        // we'll just use whatever connectors are already producing some
143        // output and keep using whatever modes they are currently in.
144        return Err(Error::NotSupported);
145    }
146    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
147
148    let enc = card.encoder_state(conn.current_encoder_id)?;
149    let crtc_id = enc.current_crtc_id;
150    let crtc = card.crtc_state(crtc_id)?;
151    let mode = crtc.mode;
152    let db = card.create_dumb_buffer(DumbBufferRequest {
153        width: mode.hdisplay as u32,
154        height: mode.vdisplay as u32,
155        depth: 24,
156        bpp: 32,
157    })?;
158    Ok(Output {
159        conn_id: conn.id,
160        crtc_id,
161        mode,
162        db,
163    })
164}
More examples
Hide additional examples
examples/modesetting-atomic.rs (lines 227-232)
209fn prepare_output(
210    card: &Card,
211    conn: ConnectorState,
212    resources: &CardResources,
213) -> Result<Output, Error> {
214    if conn.current_encoder_id.0 == 0 {
215        // It could be reasonable to go hunting for a suitable encoder and
216        // CRTC to activate this connector, but for this simple example
217        // we'll just use whatever connectors are already producing some
218        // output and keep using whatever modes they are currently in.
219        return Err(Error::NotSupported);
220    }
221    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
222
223    let enc = card.encoder_state(conn.current_encoder_id)?;
224    let crtc_id = enc.current_crtc_id;
225    let crtc = card.crtc_state(crtc_id)?;
226    let mode = crtc.mode;
227    let db = card.create_dumb_buffer(DumbBufferRequest {
228        width: mode.hdisplay as u32,
229        height: mode.vdisplay as u32,
230        depth: 24,
231        bpp: 32,
232    })?;
233
234    // We need to find the primary plane that's currently assigned to this CRTC.
235    // The following is not really a correct way to do it, but it'll work for
236    // now just to test if anything is working here at all. (This makes some
237    // assumptions about how the card is already configured which might not
238    // actually hold in practice.)
239    let mut chosen_plane_id: Option<PlaneId> = None;
240    for plane_id in resources.plane_ids.iter().copied() {
241        let plane = card.plane_state(plane_id)?;
242        if plane.crtc_id == crtc_id {
243            chosen_plane_id = Some(plane_id);
244            break;
245        }
246    }
247    let Some(chosen_plane_id) = chosen_plane_id else {
248        return Err(Error::NonExist);
249    };
250
251    println!("collecting properties");
252    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
253    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
254    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
255
256    println!("collected properties");
257    Ok(Output {
258        conn_id: conn.id,
259        conn_prop_ids,
260        crtc_id,
261        crtc_prop_ids,
262        plane_id: chosen_plane_id,
263        plane_prop_ids,
264        mode,
265        db,
266    })
267}
Source

pub fn read_events_raw<'a>( &self, buf: &'a mut [u8], ) -> Result<impl Iterator<Item = &'a DrmEvent> + 'a, Error>

Read raw events from the card’s file descriptor.

DRM deals with events by having clients read from the card file descriptor, at which point the driver writes as many whole pending events as will fit into the given buffer. To give callers control over the buffer size, this function takes a preallocated mutable buffer to use for the temporary storage and then interprets the data one event at a time as the resulting iterator is used. The buffer should be at least large enough to contain one instance of the largest event type the kernel might return.

If this function returns successfully then the caller must read the resulting iterator until it produces None, or otherwise any unread events will be lost.

All objects returned from the iterator are views into portions of the provided buffer.

Source

pub fn read_events<'a>( &self, buf: &'a mut [u8], ) -> Result<impl Iterator<Item = DrmEvent> + 'a, Error>

Read events from the card’s file descriptor.

If this function returns successfully then the caller must read the resulting iterator until it produces None, or otherwise any unread events will be lost.

This uses buf in the same way as Self::read_events_raw, but instead of returning direct references to parts of the buffer it copies the event data into owned objects that can therefore outlive the buffer. This is really just a convenience wrapper around passing the Self::read_events_raw results through event::DrmEvent::from_raw.

Unlike Self::read_events_raw, this function’s iterator will sometimes perform dynamic allocations to capture the bodies of events with unrecognized types.

Examples found in repository?
examples/modesetting.rs (line 93)
57fn display_demo(card: &mut Card) -> Result<(), Error> {
58    let mut outputs = prepare_outputs(&card)?;
59    for output in &mut outputs {
60        println!("preparing output {output:#?}");
61        let conn = card.connector_state(output.conn_id)?;
62
63        let mode = &output.mode;
64        let mode_name = String::from_utf8_lossy(&mode.name);
65        println!(
66            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
67            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
68        );
69
70        let rows = output.db.height() as usize;
71        let pitch = output.db.pitch() as usize;
72        let data = output.db.buffer_mut();
73        for i in 0..rows {
74            if (i % 8) > 3 {
75                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
76                row.fill(0xff);
77            }
78        }
79
80        println!(
81            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
82            output.crtc_id,
83            output.db.framebuffer_id(),
84            conn.id
85        );
86        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
87        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
88    }
89
90    let mut evt_buf = vec![0_u8; 1024];
91    loop {
92        println!("waiting for events (send SIGINT to exit)");
93        for evt in card.read_events(&mut evt_buf)? {
94            println!("event {evt:?}");
95            match evt {
96                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
97                    // In a real program this would be a time place to draw the next frame
98                    // for the reported crtc.
99                }
100                _ => {
101                    // Ignore any unrecognized event types.
102                }
103            }
104        }
105    }
106}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 164)
60fn display_demo(card: &mut Card) -> Result<(), Error> {
61    let mut outputs = prepare_outputs(&card)?;
62    let mut req = linux_drm::modeset::AtomicRequest::new();
63
64    for output in &mut outputs {
65        println!("preparing output {output:#?}");
66        let conn = card.connector_state(output.conn_id)?;
67
68        let mode = &output.mode;
69        let mode_name = String::from_utf8_lossy(&mode.name);
70        println!(
71            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
72            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
73        );
74
75        let rows = output.db.height() as usize;
76        let pitch = output.db.pitch() as usize;
77        let data = output.db.buffer_mut();
78        for i in 0..rows {
79            if (i % 8) > 3 {
80                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
81                row.fill(0xff);
82            }
83        }
84
85        println!(
86            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connector {:?}",
87            output.crtc_id,
88            output.db.framebuffer_id(),
89            conn.id
90        );
91
92        req.set_property(
93            ObjectId::Connector(output.conn_id),
94            output.conn_prop_ids.crtc_id,
95            output.crtc_id,
96        );
97        req.set_property(
98            ObjectId::Crtc(output.crtc_id),
99            output.crtc_prop_ids.active,
100            true,
101        );
102        req.set_property(
103            ObjectId::Plane(output.plane_id),
104            output.plane_prop_ids.fb_id,
105            output.db.framebuffer_id(),
106        );
107        req.set_property(
108            ObjectId::Plane(output.plane_id),
109            output.plane_prop_ids.crtc_id,
110            output.crtc_id,
111        );
112        req.set_property(
113            ObjectId::Plane(output.plane_id),
114            output.plane_prop_ids.crtc_x,
115            0,
116        );
117        req.set_property(
118            ObjectId::Plane(output.plane_id),
119            output.plane_prop_ids.crtc_y,
120            0,
121        );
122        req.set_property(
123            ObjectId::Plane(output.plane_id),
124            output.plane_prop_ids.crtc_w,
125            output.db.width(),
126        );
127        req.set_property(
128            ObjectId::Plane(output.plane_id),
129            output.plane_prop_ids.crtc_h,
130            output.db.height(),
131        );
132        req.set_property(
133            ObjectId::Plane(output.plane_id),
134            output.plane_prop_ids.src_x,
135            0,
136        );
137        req.set_property(
138            ObjectId::Plane(output.plane_id),
139            output.plane_prop_ids.src_y,
140            0,
141        );
142        req.set_property(
143            ObjectId::Plane(output.plane_id),
144            output.plane_prop_ids.src_w,
145            (output.db.width() as u64) << 16,
146        );
147        req.set_property(
148            ObjectId::Plane(output.plane_id),
149            output.plane_prop_ids.src_h,
150            (output.db.height() as u64) << 16,
151        );
152    }
153
154    println!("atomic commit {req:#?}");
155    card.atomic_commit(
156        &req,
157        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
158        0,
159    )?;
160
161    let mut evt_buf = vec![0_u8; 1024];
162    loop {
163        println!("waiting for events (send SIGINT to exit)");
164        for evt in card.read_events(&mut evt_buf)? {
165            println!("event {evt:?}");
166            match evt {
167                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
168                    // In a real program this would be a time place to draw the next frame
169                    // for the reported crtc.
170                }
171                _ => {
172                    // Ignore any unrecognized event types.
173                }
174            }
175        }
176    }
177}
Source

pub fn close(self) -> Result<()>

Close the filehandle underlying the card object.

Source

pub fn take_file(self) -> Result<File<DrmCardDevice>>

Take the file from underneath this card object without closing it.

Source

pub fn borrow_file(&self) -> &File<DrmCardDevice>

Borrow the file object that this card object wraps.

Source

pub fn ioctl<'a, Req: IoctlReq<'a, DrmCardDevice> + Copy>( &'a self, request: Req, arg: Req::ExtArg, ) -> Result<Req::Result>

Perform a direct ioctl request to the underlying card device filehandle.

Trait Implementations§

Source§

impl Debug for Card

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<D> TryFrom<File<D>> for Card

Source§

type Error = InitError

The type returned in the event of a conversion error.
Source§

fn try_from(value: File<D>) -> Result<Self, InitError>

Performs the conversion.

Auto Trait Implementations§

§

impl Freeze for Card

§

impl RefUnwindSafe for Card

§

impl Send for Card

§

impl Sync for Card

§

impl Unpin for Card

§

impl UnwindSafe for Card

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointee for T

Source§

type Metadata = ()

The metadata type for pointers and references to this type.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.