Struct Card

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

Implementations§

Source§

impl Card

Source

pub fn open(path: &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 12)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    display_demo(&mut card).map_err(map_err)
34}
More examples
Hide additional examples
examples/properties.rs (line 10)
9fn main() -> std::io::Result<()> {
10    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
11
12    {
13        let name = card.driver_name().map_err(map_err)?;
14        let name = String::from_utf8_lossy(&name);
15        println!("Driver name: {name}");
16    }
17
18    if card
19        .get_device_cap(DeviceCap::DumbBuffer)
20        .map_err(map_err)?
21        == 0
22    {
23        return Err(std::io::Error::other(
24            "device does not support 'dumb buffers'",
25        ));
26    }
27
28    card.set_client_cap(ClientCap::UniversalPlanes, 1)
29        .map_err(map_err)?;
30    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
31
32    show_properties(&card).map_err(map_err)
33}
examples/modesetting-atomic.rs (line 12)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    card.set_client_cap(ClientCap::UniversalPlanes, 1)
34        .map_err(map_err)?;
35    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
36
37    display_demo(&mut card).map_err(map_err)
38}
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 16)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    display_demo(&mut card).map_err(map_err)
34}
More examples
Hide additional examples
examples/properties.rs (line 13)
9fn main() -> std::io::Result<()> {
10    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
11
12    {
13        let name = card.driver_name().map_err(map_err)?;
14        let name = String::from_utf8_lossy(&name);
15        println!("Driver name: {name}");
16    }
17
18    if card
19        .get_device_cap(DeviceCap::DumbBuffer)
20        .map_err(map_err)?
21        == 0
22    {
23        return Err(std::io::Error::other(
24            "device does not support 'dumb buffers'",
25        ));
26    }
27
28    card.set_client_cap(ClientCap::UniversalPlanes, 1)
29        .map_err(map_err)?;
30    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
31
32    show_properties(&card).map_err(map_err)
33}
examples/modesetting-atomic.rs (line 16)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    card.set_client_cap(ClientCap::UniversalPlanes, 1)
34        .map_err(map_err)?;
35    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
36
37    display_demo(&mut card).map_err(map_err)
38}
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 22)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    display_demo(&mut card).map_err(map_err)
34}
More examples
Hide additional examples
examples/properties.rs (line 19)
9fn main() -> std::io::Result<()> {
10    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
11
12    {
13        let name = card.driver_name().map_err(map_err)?;
14        let name = String::from_utf8_lossy(&name);
15        println!("Driver name: {name}");
16    }
17
18    if card
19        .get_device_cap(DeviceCap::DumbBuffer)
20        .map_err(map_err)?
21        == 0
22    {
23        return Err(std::io::Error::other(
24            "device does not support 'dumb buffers'",
25        ));
26    }
27
28    card.set_client_cap(ClientCap::UniversalPlanes, 1)
29        .map_err(map_err)?;
30    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
31
32    show_properties(&card).map_err(map_err)
33}
examples/modesetting-atomic.rs (line 22)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    card.set_client_cap(ClientCap::UniversalPlanes, 1)
34        .map_err(map_err)?;
35    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
36
37    display_demo(&mut card).map_err(map_err)
38}
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 28)
9fn main() -> std::io::Result<()> {
10    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
11
12    {
13        let name = card.driver_name().map_err(map_err)?;
14        let name = String::from_utf8_lossy(&name);
15        println!("Driver name: {name}");
16    }
17
18    if card
19        .get_device_cap(DeviceCap::DumbBuffer)
20        .map_err(map_err)?
21        == 0
22    {
23        return Err(std::io::Error::other(
24            "device does not support 'dumb buffers'",
25        ));
26    }
27
28    card.set_client_cap(ClientCap::UniversalPlanes, 1)
29        .map_err(map_err)?;
30    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
31
32    show_properties(&card).map_err(map_err)
33}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 33)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    card.set_client_cap(ClientCap::UniversalPlanes, 1)
34        .map_err(map_err)?;
35    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
36
37    display_demo(&mut card).map_err(map_err)
38}
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 13)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    display_demo(&mut card).map_err(map_err)
34}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 13)
11fn main() -> std::io::Result<()> {
12    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
13    card.become_master().map_err(map_err)?;
14
15    {
16        let name = card.driver_name().map_err(map_err)?;
17        let name = String::from_utf8_lossy(&name);
18        println!("Driver name: {name}");
19    }
20
21    if card
22        .get_device_cap(DeviceCap::DumbBuffer)
23        .map_err(map_err)?
24        == 0
25    {
26        return Err(std::io::Error::other(
27            "device does not support 'dumb buffers'",
28        ));
29    } else {
30        println!("Device supports 'dumb buffers'");
31    }
32
33    card.set_client_cap(ClientCap::UniversalPlanes, 1)
34        .map_err(map_err)?;
35    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;
36
37    display_demo(&mut card).map_err(map_err)
38}
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 150)
144fn property_meta<'a, 'card>(
145    prop_id: PropertyId,
146    prop_meta: &'a mut HashMap<u32, PropertyMeta>,
147    card: &Card,
148) -> Result<&'a PropertyMeta, Error> {
149    Ok(prop_meta.entry(prop_id.0).or_insert_with(|| {
150        card.property_meta(prop_id)
151            .map(|meta| {
152                let mut enum_names = BTreeMap::new();
153                for member in meta.enum_members().unwrap() {
154                    enum_names.insert(member.value(), member.name().to_string());
155                }
156                PropertyMeta {
157                    name: meta.name().to_string(),
158                    typ: meta.property_type(),
159                    immutable: meta.is_immutable(),
160                    values: meta.values().unwrap(),
161                    enum_names,
162                }
163            })
164            .unwrap_or(PropertyMeta {
165                name: String::from("<unknown>"),
166                typ: PropertyType::Unknown,
167                immutable: true,
168                values: Vec::new(),
169                enum_names: BTreeMap::new(),
170            })
171    }))
172}
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 90)
85fn show_object_property_list(
86    id: impl Into<ObjectId>,
87    prop_meta: &mut HashMap<u32, PropertyMeta>,
88    card: &Card,
89) -> Result<(), Error> {
90    let props = card.object_properties(id)?;
91    show_property_list(&props, prop_meta, card)?;
92    Ok(())
93}
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 269)
267    pub fn new(conn_id: ConnectorId, card: &linux_drm::Card) -> Result<Self, Error> {
268        let mut ret: Self = unsafe { core::mem::zeroed() };
269        card.each_object_property_meta(conn_id, |meta, _| ret.populate_from(meta))?;
270        Ok(ret)
271    }
272
273    pub fn populate_from<'card>(&mut self, from: linux_drm::modeset::ObjectPropMeta<'card>) {
274        match from.name() {
275            "CRTC_ID" => self.crtc_id = from.property_id(),
276            _ => {}
277        }
278    }
279}
280
281#[derive(Debug)]
282struct CrtcPropIds {
283    active: PropertyId,
284}
285
286impl CrtcPropIds {
287    pub fn new(crtc_id: CrtcId, card: &linux_drm::Card) -> Result<Self, Error> {
288        let mut ret: Self = unsafe { core::mem::zeroed() };
289        card.each_object_property_meta(linux_drm::modeset::ObjectId::Crtc(crtc_id), |meta, _| {
290            ret.populate_from(meta)
291        })?;
292        Ok(ret)
293    }
294
295    pub fn populate_from<'card>(&mut self, from: linux_drm::modeset::ObjectPropMeta<'card>) {
296        match from.name() {
297            "ACTIVE" => self.active = from.property_id(),
298            _ => {}
299        }
300    }
301}
302
303#[derive(Debug)]
304struct PlanePropIds {
305    typ: PropertyId,
306    fb_id: PropertyId,
307    crtc_id: PropertyId,
308    crtc_x: PropertyId,
309    crtc_y: PropertyId,
310    crtc_w: PropertyId,
311    crtc_h: PropertyId,
312    src_x: PropertyId,
313    src_y: PropertyId,
314    src_w: PropertyId,
315    src_h: PropertyId,
316}
317
318impl PlanePropIds {
319    pub fn new(plane_id: PlaneId, card: &linux_drm::Card) -> Result<Self, Error> {
320        let mut ret: Self = unsafe { core::mem::zeroed() };
321        card.each_object_property_meta(plane_id, |meta, _| ret.populate_from(meta))?;
322        Ok(ret)
323    }
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 88)
87fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
88    let resources = card.resources()?;
89    let mut outputs = Vec::<Output>::new();
90
91    for id in resources.connector_ids.iter().copied() {
92        let conn = card.connector_state(id)?;
93        if conn.connection_state != ConnectionState::Connected {
94            println!("ignoring unconnected connector {id:?}");
95            continue;
96        }
97        if conn.current_encoder_id.0 == 0 {
98            println!("ignoring encoderless connector {id:?}");
99            continue;
100        }
101        if conn.modes.len() == 0 {
102            println!("ignoring modeless connector {id:?}");
103            continue;
104        }
105
106        let output = prepare_output(card, conn, &resources)?;
107        outputs.push(output);
108    }
109
110    Ok(outputs)
111}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 162)
159fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
160    println!("preparing outputs");
161
162    let resources = card.resources()?;
163    let mut outputs = Vec::<Output>::new();
164
165    for id in resources.connector_ids.iter().copied() {
166        println!("preparing output for connector #{id:?}");
167
168        let conn = card.connector_state(id)?;
169        if conn.connection_state != ConnectionState::Connected {
170            println!("ignoring unconnected connector {id:?}");
171            continue;
172        }
173        if conn.current_encoder_id.0 == 0 {
174            println!("ignoring encoderless connector {id:?}");
175            continue;
176        }
177        if conn.modes.len() == 0 {
178            println!("ignoring modeless connector {id:?}");
179            continue;
180        }
181
182        let output = prepare_output(card, conn, &resources)?;
183        outputs.push(output);
184    }
185
186    Ok(outputs)
187}
examples/properties.rs (line 36)
35fn show_properties(card: &Card) -> Result<(), Error> {
36    let res = card.resources()?;
37
38    let mut prop_meta = HashMap::<u32, PropertyMeta>::new();
39
40    println!("");
41
42    for conn_id in res.connector_ids {
43        println!("Connector #{conn_id:?}:");
44        if let Err(e) = show_object_property_list(conn_id, &mut prop_meta, card) {
45            println!("  Error: {e:?}");
46        }
47        println!("");
48    }
49
50    for enc_id in res.encoder_ids {
51        println!("Encoder #{enc_id:?}:");
52        if let Err(e) = show_object_property_list(enc_id, &mut prop_meta, card) {
53            println!("  Error: {e:?}");
54        }
55        println!("");
56    }
57
58    for crtc_id in res.crtc_ids {
59        println!("CRTC #{crtc_id:?}:");
60        if let Err(e) = show_object_property_list(crtc_id, &mut prop_meta, card) {
61            println!("  Error: {e:?}");
62        }
63        println!("");
64    }
65
66    for fb_id in res.fb_ids {
67        println!("Framebuffer #{fb_id:?}:");
68        if let Err(e) = show_object_property_list(fb_id, &mut prop_meta, card) {
69            println!("  Error: {e:?}");
70        }
71        println!("");
72    }
73
74    for plane_id in res.plane_ids {
75        println!("Plane #{plane_id:?}:");
76        if let Err(e) = show_object_property_list(plane_id, &mut prop_meta, card) {
77            println!("  Error: {e:?}");
78        }
79        println!("");
80    }
81
82    Ok(())
83}
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 40)
36fn display_demo(card: &mut Card) -> Result<(), Error> {
37    let mut outputs = prepare_outputs(&card)?;
38    for output in &mut outputs {
39        println!("preparing output {output:#?}");
40        let conn = card.connector_state(output.conn_id)?;
41
42        let mode = &output.mode;
43        let mode_name = String::from_utf8_lossy(&mode.name);
44        println!(
45            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
46            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
47        );
48
49        let rows = output.db.height() as usize;
50        let pitch = output.db.pitch() as usize;
51        let data = output.db.buffer_mut();
52        for i in 0..rows {
53            if (i % 8) > 3 {
54                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
55                row.fill(0xff);
56            }
57        }
58
59        println!(
60            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
61            output.crtc_id,
62            output.db.framebuffer_id(),
63            conn.id
64        );
65        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
66        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
67    }
68
69    let mut evt_buf = vec![0_u8; 1024];
70    loop {
71        println!("waiting for events (send SIGINT to exit)");
72        for evt in card.read_events(&mut evt_buf)? {
73            println!("event {evt:?}");
74            match evt {
75                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
76                    // In a real program this would be a time place to draw the next frame
77                    // for the reported crtc.
78                }
79                _ => {
80                    // Ignore any unrecognized event types.
81                }
82            }
83        }
84    }
85}
86
87fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
88    let resources = card.resources()?;
89    let mut outputs = Vec::<Output>::new();
90
91    for id in resources.connector_ids.iter().copied() {
92        let conn = card.connector_state(id)?;
93        if conn.connection_state != ConnectionState::Connected {
94            println!("ignoring unconnected connector {id:?}");
95            continue;
96        }
97        if conn.current_encoder_id.0 == 0 {
98            println!("ignoring encoderless connector {id:?}");
99            continue;
100        }
101        if conn.modes.len() == 0 {
102            println!("ignoring modeless connector {id:?}");
103            continue;
104        }
105
106        let output = prepare_output(card, conn, &resources)?;
107        outputs.push(output);
108    }
109
110    Ok(outputs)
111}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 46)
40fn display_demo(card: &mut Card) -> Result<(), Error> {
41    let mut outputs = prepare_outputs(&card)?;
42    let mut req = linux_drm::modeset::AtomicRequest::new();
43
44    for output in &mut outputs {
45        println!("preparing output {output:#?}");
46        let conn = card.connector_state(output.conn_id)?;
47
48        let mode = &output.mode;
49        let mode_name = String::from_utf8_lossy(&mode.name);
50        println!(
51            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
52            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
53        );
54
55        let rows = output.db.height() as usize;
56        let pitch = output.db.pitch() as usize;
57        let data = output.db.buffer_mut();
58        for i in 0..rows {
59            if (i % 8) > 3 {
60                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
61                row.fill(0xff);
62            }
63        }
64
65        println!(
66            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connector {:?}",
67            output.crtc_id,
68            output.db.framebuffer_id(),
69            conn.id
70        );
71
72        req.set_property(
73            ObjectId::Connector(output.conn_id),
74            output.conn_prop_ids.crtc_id,
75            output.crtc_id,
76        );
77        req.set_property(
78            ObjectId::Crtc(output.crtc_id),
79            output.crtc_prop_ids.active,
80            true,
81        );
82        req.set_property(
83            ObjectId::Plane(output.plane_id),
84            output.plane_prop_ids.fb_id,
85            output.db.framebuffer_id(),
86        );
87        req.set_property(
88            ObjectId::Plane(output.plane_id),
89            output.plane_prop_ids.crtc_id,
90            output.crtc_id,
91        );
92        req.set_property(
93            ObjectId::Plane(output.plane_id),
94            output.plane_prop_ids.crtc_x,
95            0,
96        );
97        req.set_property(
98            ObjectId::Plane(output.plane_id),
99            output.plane_prop_ids.crtc_y,
100            0,
101        );
102        req.set_property(
103            ObjectId::Plane(output.plane_id),
104            output.plane_prop_ids.crtc_w,
105            output.db.width(),
106        );
107        req.set_property(
108            ObjectId::Plane(output.plane_id),
109            output.plane_prop_ids.crtc_h,
110            output.db.height(),
111        );
112        req.set_property(
113            ObjectId::Plane(output.plane_id),
114            output.plane_prop_ids.src_x,
115            0,
116        );
117        req.set_property(
118            ObjectId::Plane(output.plane_id),
119            output.plane_prop_ids.src_y,
120            0,
121        );
122        req.set_property(
123            ObjectId::Plane(output.plane_id),
124            output.plane_prop_ids.src_w,
125            (output.db.width() as u64) << 16,
126        );
127        req.set_property(
128            ObjectId::Plane(output.plane_id),
129            output.plane_prop_ids.src_h,
130            (output.db.height() as u64) << 16,
131        );
132    }
133
134    println!("atomic commit {req:#?}");
135    card.atomic_commit(
136        &req,
137        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
138        0,
139    )?;
140
141    let mut evt_buf = vec![0_u8; 1024];
142    loop {
143        println!("waiting for events (send SIGINT to exit)");
144        for evt in card.read_events(&mut evt_buf)? {
145            println!("event {evt:?}");
146            match evt {
147                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
148                    // In a real program this would be a time place to draw the next frame
149                    // for the reported crtc.
150                }
151                _ => {
152                    // Ignore any unrecognized event types.
153                }
154            }
155        }
156    }
157}
158
159fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
160    println!("preparing outputs");
161
162    let resources = card.resources()?;
163    let mut outputs = Vec::<Output>::new();
164
165    for id in resources.connector_ids.iter().copied() {
166        println!("preparing output for connector #{id:?}");
167
168        let conn = card.connector_state(id)?;
169        if conn.connection_state != ConnectionState::Connected {
170            println!("ignoring unconnected connector {id:?}");
171            continue;
172        }
173        if conn.current_encoder_id.0 == 0 {
174            println!("ignoring encoderless connector {id:?}");
175            continue;
176        }
177        if conn.modes.len() == 0 {
178            println!("ignoring modeless connector {id:?}");
179            continue;
180        }
181
182        let output = prepare_output(card, conn, &resources)?;
183        outputs.push(output);
184    }
185
186    Ok(outputs)
187}
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 127)
113fn prepare_output(
114    card: &Card,
115    conn: ConnectorState,
116    resources: &CardResources,
117) -> Result<Output, Error> {
118    if conn.current_encoder_id.0 == 0 {
119        // It could be reasonable to go hunting for a suitable encoder and
120        // CRTC to activate this connector, but for this simple example
121        // we'll just use whatever connectors are already producing some
122        // output and keep using whatever modes they are currently in.
123        return Err(Error::NotSupported);
124    }
125    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
126
127    let enc = card.encoder_state(conn.current_encoder_id)?;
128    let crtc_id = enc.current_crtc_id;
129    let crtc = card.crtc_state(crtc_id)?;
130    let mode = crtc.mode;
131    let db = card.create_dumb_buffer(DumbBufferRequest {
132        width: mode.hdisplay as u32,
133        height: mode.vdisplay as u32,
134        depth: 24,
135        bpp: 32,
136    })?;
137    Ok(Output {
138        conn_id: conn.id,
139        crtc_id,
140        mode,
141        db,
142    })
143}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 203)
189fn prepare_output(
190    card: &Card,
191    conn: ConnectorState,
192    resources: &CardResources,
193) -> Result<Output, Error> {
194    if conn.current_encoder_id.0 == 0 {
195        // It could be reasonable to go hunting for a suitable encoder and
196        // CRTC to activate this connector, but for this simple example
197        // we'll just use whatever connectors are already producing some
198        // output and keep using whatever modes they are currently in.
199        return Err(Error::NotSupported);
200    }
201    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
202
203    let enc = card.encoder_state(conn.current_encoder_id)?;
204    let crtc_id = enc.current_crtc_id;
205    let crtc = card.crtc_state(crtc_id)?;
206    let mode = crtc.mode;
207    let db = card.create_dumb_buffer(DumbBufferRequest {
208        width: mode.hdisplay as u32,
209        height: mode.vdisplay as u32,
210        depth: 24,
211        bpp: 32,
212    })?;
213
214    // We need to find the primary plane that's currently assigned to this CRTC.
215    // The following is not really a correct way to do it, but it'll work for
216    // now just to test if anything is working here at all. (This makes some
217    // assumptions about how the card is already configured which might not
218    // actually hold in practice.)
219    let mut chosen_plane_id: Option<PlaneId> = None;
220    for plane_id in resources.plane_ids.iter().copied() {
221        let plane = card.plane_state(plane_id)?;
222        if plane.crtc_id == crtc_id {
223            chosen_plane_id = Some(plane_id);
224            break;
225        }
226    }
227    let Some(chosen_plane_id) = chosen_plane_id else {
228        return Err(Error::NonExist);
229    };
230
231    println!("collecting properties");
232    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
233    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
234    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
235
236    println!("collected properties");
237    Ok(Output {
238        conn_id: conn.id,
239        conn_prop_ids,
240        crtc_id,
241        crtc_prop_ids,
242        plane_id: chosen_plane_id,
243        plane_prop_ids,
244        mode,
245        db,
246    })
247}
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 129)
113fn prepare_output(
114    card: &Card,
115    conn: ConnectorState,
116    resources: &CardResources,
117) -> Result<Output, Error> {
118    if conn.current_encoder_id.0 == 0 {
119        // It could be reasonable to go hunting for a suitable encoder and
120        // CRTC to activate this connector, but for this simple example
121        // we'll just use whatever connectors are already producing some
122        // output and keep using whatever modes they are currently in.
123        return Err(Error::NotSupported);
124    }
125    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
126
127    let enc = card.encoder_state(conn.current_encoder_id)?;
128    let crtc_id = enc.current_crtc_id;
129    let crtc = card.crtc_state(crtc_id)?;
130    let mode = crtc.mode;
131    let db = card.create_dumb_buffer(DumbBufferRequest {
132        width: mode.hdisplay as u32,
133        height: mode.vdisplay as u32,
134        depth: 24,
135        bpp: 32,
136    })?;
137    Ok(Output {
138        conn_id: conn.id,
139        crtc_id,
140        mode,
141        db,
142    })
143}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 205)
189fn prepare_output(
190    card: &Card,
191    conn: ConnectorState,
192    resources: &CardResources,
193) -> Result<Output, Error> {
194    if conn.current_encoder_id.0 == 0 {
195        // It could be reasonable to go hunting for a suitable encoder and
196        // CRTC to activate this connector, but for this simple example
197        // we'll just use whatever connectors are already producing some
198        // output and keep using whatever modes they are currently in.
199        return Err(Error::NotSupported);
200    }
201    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
202
203    let enc = card.encoder_state(conn.current_encoder_id)?;
204    let crtc_id = enc.current_crtc_id;
205    let crtc = card.crtc_state(crtc_id)?;
206    let mode = crtc.mode;
207    let db = card.create_dumb_buffer(DumbBufferRequest {
208        width: mode.hdisplay as u32,
209        height: mode.vdisplay as u32,
210        depth: 24,
211        bpp: 32,
212    })?;
213
214    // We need to find the primary plane that's currently assigned to this CRTC.
215    // The following is not really a correct way to do it, but it'll work for
216    // now just to test if anything is working here at all. (This makes some
217    // assumptions about how the card is already configured which might not
218    // actually hold in practice.)
219    let mut chosen_plane_id: Option<PlaneId> = None;
220    for plane_id in resources.plane_ids.iter().copied() {
221        let plane = card.plane_state(plane_id)?;
222        if plane.crtc_id == crtc_id {
223            chosen_plane_id = Some(plane_id);
224            break;
225        }
226    }
227    let Some(chosen_plane_id) = chosen_plane_id else {
228        return Err(Error::NonExist);
229    };
230
231    println!("collecting properties");
232    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
233    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
234    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
235
236    println!("collected properties");
237    Ok(Output {
238        conn_id: conn.id,
239        conn_prop_ids,
240        crtc_id,
241        crtc_prop_ids,
242        plane_id: chosen_plane_id,
243        plane_prop_ids,
244        mode,
245        db,
246    })
247}
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 221)
189fn prepare_output(
190    card: &Card,
191    conn: ConnectorState,
192    resources: &CardResources,
193) -> Result<Output, Error> {
194    if conn.current_encoder_id.0 == 0 {
195        // It could be reasonable to go hunting for a suitable encoder and
196        // CRTC to activate this connector, but for this simple example
197        // we'll just use whatever connectors are already producing some
198        // output and keep using whatever modes they are currently in.
199        return Err(Error::NotSupported);
200    }
201    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
202
203    let enc = card.encoder_state(conn.current_encoder_id)?;
204    let crtc_id = enc.current_crtc_id;
205    let crtc = card.crtc_state(crtc_id)?;
206    let mode = crtc.mode;
207    let db = card.create_dumb_buffer(DumbBufferRequest {
208        width: mode.hdisplay as u32,
209        height: mode.vdisplay as u32,
210        depth: 24,
211        bpp: 32,
212    })?;
213
214    // We need to find the primary plane that's currently assigned to this CRTC.
215    // The following is not really a correct way to do it, but it'll work for
216    // now just to test if anything is working here at all. (This makes some
217    // assumptions about how the card is already configured which might not
218    // actually hold in practice.)
219    let mut chosen_plane_id: Option<PlaneId> = None;
220    for plane_id in resources.plane_ids.iter().copied() {
221        let plane = card.plane_state(plane_id)?;
222        if plane.crtc_id == crtc_id {
223            chosen_plane_id = Some(plane_id);
224            break;
225        }
226    }
227    let Some(chosen_plane_id) = chosen_plane_id else {
228        return Err(Error::NonExist);
229    };
230
231    println!("collecting properties");
232    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
233    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
234    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
235
236    println!("collected properties");
237    Ok(Output {
238        conn_id: conn.id,
239        conn_prop_ids,
240        crtc_id,
241        crtc_prop_ids,
242        plane_id: chosen_plane_id,
243        plane_prop_ids,
244        mode,
245        db,
246    })
247}
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 135-139)
40fn display_demo(card: &mut Card) -> Result<(), Error> {
41    let mut outputs = prepare_outputs(&card)?;
42    let mut req = linux_drm::modeset::AtomicRequest::new();
43
44    for output in &mut outputs {
45        println!("preparing output {output:#?}");
46        let conn = card.connector_state(output.conn_id)?;
47
48        let mode = &output.mode;
49        let mode_name = String::from_utf8_lossy(&mode.name);
50        println!(
51            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
52            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
53        );
54
55        let rows = output.db.height() as usize;
56        let pitch = output.db.pitch() as usize;
57        let data = output.db.buffer_mut();
58        for i in 0..rows {
59            if (i % 8) > 3 {
60                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
61                row.fill(0xff);
62            }
63        }
64
65        println!(
66            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connector {:?}",
67            output.crtc_id,
68            output.db.framebuffer_id(),
69            conn.id
70        );
71
72        req.set_property(
73            ObjectId::Connector(output.conn_id),
74            output.conn_prop_ids.crtc_id,
75            output.crtc_id,
76        );
77        req.set_property(
78            ObjectId::Crtc(output.crtc_id),
79            output.crtc_prop_ids.active,
80            true,
81        );
82        req.set_property(
83            ObjectId::Plane(output.plane_id),
84            output.plane_prop_ids.fb_id,
85            output.db.framebuffer_id(),
86        );
87        req.set_property(
88            ObjectId::Plane(output.plane_id),
89            output.plane_prop_ids.crtc_id,
90            output.crtc_id,
91        );
92        req.set_property(
93            ObjectId::Plane(output.plane_id),
94            output.plane_prop_ids.crtc_x,
95            0,
96        );
97        req.set_property(
98            ObjectId::Plane(output.plane_id),
99            output.plane_prop_ids.crtc_y,
100            0,
101        );
102        req.set_property(
103            ObjectId::Plane(output.plane_id),
104            output.plane_prop_ids.crtc_w,
105            output.db.width(),
106        );
107        req.set_property(
108            ObjectId::Plane(output.plane_id),
109            output.plane_prop_ids.crtc_h,
110            output.db.height(),
111        );
112        req.set_property(
113            ObjectId::Plane(output.plane_id),
114            output.plane_prop_ids.src_x,
115            0,
116        );
117        req.set_property(
118            ObjectId::Plane(output.plane_id),
119            output.plane_prop_ids.src_y,
120            0,
121        );
122        req.set_property(
123            ObjectId::Plane(output.plane_id),
124            output.plane_prop_ids.src_w,
125            (output.db.width() as u64) << 16,
126        );
127        req.set_property(
128            ObjectId::Plane(output.plane_id),
129            output.plane_prop_ids.src_h,
130            (output.db.height() as u64) << 16,
131        );
132    }
133
134    println!("atomic commit {req:#?}");
135    card.atomic_commit(
136        &req,
137        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
138        0,
139    )?;
140
141    let mut evt_buf = vec![0_u8; 1024];
142    loop {
143        println!("waiting for events (send SIGINT to exit)");
144        for evt in card.read_events(&mut evt_buf)? {
145            println!("event {evt:?}");
146            match evt {
147                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
148                    // In a real program this would be a time place to draw the next frame
149                    // for the reported crtc.
150                }
151                _ => {
152                    // Ignore any unrecognized event types.
153                }
154            }
155        }
156    }
157}
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 65)
36fn display_demo(card: &mut Card) -> Result<(), Error> {
37    let mut outputs = prepare_outputs(&card)?;
38    for output in &mut outputs {
39        println!("preparing output {output:#?}");
40        let conn = card.connector_state(output.conn_id)?;
41
42        let mode = &output.mode;
43        let mode_name = String::from_utf8_lossy(&mode.name);
44        println!(
45            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
46            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
47        );
48
49        let rows = output.db.height() as usize;
50        let pitch = output.db.pitch() as usize;
51        let data = output.db.buffer_mut();
52        for i in 0..rows {
53            if (i % 8) > 3 {
54                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
55                row.fill(0xff);
56            }
57        }
58
59        println!(
60            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
61            output.crtc_id,
62            output.db.framebuffer_id(),
63            conn.id
64        );
65        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
66        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
67    }
68
69    let mut evt_buf = vec![0_u8; 1024];
70    loop {
71        println!("waiting for events (send SIGINT to exit)");
72        for evt in card.read_events(&mut evt_buf)? {
73            println!("event {evt:?}");
74            match evt {
75                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
76                    // In a real program this would be a time place to draw the next frame
77                    // for the reported crtc.
78                }
79                _ => {
80                    // Ignore any unrecognized event types.
81                }
82            }
83        }
84    }
85}
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 66)
36fn display_demo(card: &mut Card) -> Result<(), Error> {
37    let mut outputs = prepare_outputs(&card)?;
38    for output in &mut outputs {
39        println!("preparing output {output:#?}");
40        let conn = card.connector_state(output.conn_id)?;
41
42        let mode = &output.mode;
43        let mode_name = String::from_utf8_lossy(&mode.name);
44        println!(
45            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
46            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
47        );
48
49        let rows = output.db.height() as usize;
50        let pitch = output.db.pitch() as usize;
51        let data = output.db.buffer_mut();
52        for i in 0..rows {
53            if (i % 8) > 3 {
54                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
55                row.fill(0xff);
56            }
57        }
58
59        println!(
60            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
61            output.crtc_id,
62            output.db.framebuffer_id(),
63            conn.id
64        );
65        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
66        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
67    }
68
69    let mut evt_buf = vec![0_u8; 1024];
70    loop {
71        println!("waiting for events (send SIGINT to exit)");
72        for evt in card.read_events(&mut evt_buf)? {
73            println!("event {evt:?}");
74            match evt {
75                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
76                    // In a real program this would be a time place to draw the next frame
77                    // for the reported crtc.
78                }
79                _ => {
80                    // Ignore any unrecognized event types.
81                }
82            }
83        }
84    }
85}
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 131-136)
113fn prepare_output(
114    card: &Card,
115    conn: ConnectorState,
116    resources: &CardResources,
117) -> Result<Output, Error> {
118    if conn.current_encoder_id.0 == 0 {
119        // It could be reasonable to go hunting for a suitable encoder and
120        // CRTC to activate this connector, but for this simple example
121        // we'll just use whatever connectors are already producing some
122        // output and keep using whatever modes they are currently in.
123        return Err(Error::NotSupported);
124    }
125    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
126
127    let enc = card.encoder_state(conn.current_encoder_id)?;
128    let crtc_id = enc.current_crtc_id;
129    let crtc = card.crtc_state(crtc_id)?;
130    let mode = crtc.mode;
131    let db = card.create_dumb_buffer(DumbBufferRequest {
132        width: mode.hdisplay as u32,
133        height: mode.vdisplay as u32,
134        depth: 24,
135        bpp: 32,
136    })?;
137    Ok(Output {
138        conn_id: conn.id,
139        crtc_id,
140        mode,
141        db,
142    })
143}
More examples
Hide additional examples
examples/modesetting-atomic.rs (lines 207-212)
189fn prepare_output(
190    card: &Card,
191    conn: ConnectorState,
192    resources: &CardResources,
193) -> Result<Output, Error> {
194    if conn.current_encoder_id.0 == 0 {
195        // It could be reasonable to go hunting for a suitable encoder and
196        // CRTC to activate this connector, but for this simple example
197        // we'll just use whatever connectors are already producing some
198        // output and keep using whatever modes they are currently in.
199        return Err(Error::NotSupported);
200    }
201    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)
202
203    let enc = card.encoder_state(conn.current_encoder_id)?;
204    let crtc_id = enc.current_crtc_id;
205    let crtc = card.crtc_state(crtc_id)?;
206    let mode = crtc.mode;
207    let db = card.create_dumb_buffer(DumbBufferRequest {
208        width: mode.hdisplay as u32,
209        height: mode.vdisplay as u32,
210        depth: 24,
211        bpp: 32,
212    })?;
213
214    // We need to find the primary plane that's currently assigned to this CRTC.
215    // The following is not really a correct way to do it, but it'll work for
216    // now just to test if anything is working here at all. (This makes some
217    // assumptions about how the card is already configured which might not
218    // actually hold in practice.)
219    let mut chosen_plane_id: Option<PlaneId> = None;
220    for plane_id in resources.plane_ids.iter().copied() {
221        let plane = card.plane_state(plane_id)?;
222        if plane.crtc_id == crtc_id {
223            chosen_plane_id = Some(plane_id);
224            break;
225        }
226    }
227    let Some(chosen_plane_id) = chosen_plane_id else {
228        return Err(Error::NonExist);
229    };
230
231    println!("collecting properties");
232    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
233    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
234    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;
235
236    println!("collected properties");
237    Ok(Output {
238        conn_id: conn.id,
239        conn_prop_ids,
240        crtc_id,
241        crtc_prop_ids,
242        plane_id: chosen_plane_id,
243        plane_prop_ids,
244        mode,
245        db,
246    })
247}
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 72)
36fn display_demo(card: &mut Card) -> Result<(), Error> {
37    let mut outputs = prepare_outputs(&card)?;
38    for output in &mut outputs {
39        println!("preparing output {output:#?}");
40        let conn = card.connector_state(output.conn_id)?;
41
42        let mode = &output.mode;
43        let mode_name = String::from_utf8_lossy(&mode.name);
44        println!(
45            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
46            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
47        );
48
49        let rows = output.db.height() as usize;
50        let pitch = output.db.pitch() as usize;
51        let data = output.db.buffer_mut();
52        for i in 0..rows {
53            if (i % 8) > 3 {
54                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
55                row.fill(0xff);
56            }
57        }
58
59        println!(
60            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connection {:?}",
61            output.crtc_id,
62            output.db.framebuffer_id(),
63            conn.id
64        );
65        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
66        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
67    }
68
69    let mut evt_buf = vec![0_u8; 1024];
70    loop {
71        println!("waiting for events (send SIGINT to exit)");
72        for evt in card.read_events(&mut evt_buf)? {
73            println!("event {evt:?}");
74            match evt {
75                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
76                    // In a real program this would be a time place to draw the next frame
77                    // for the reported crtc.
78                }
79                _ => {
80                    // Ignore any unrecognized event types.
81                }
82            }
83        }
84    }
85}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 144)
40fn display_demo(card: &mut Card) -> Result<(), Error> {
41    let mut outputs = prepare_outputs(&card)?;
42    let mut req = linux_drm::modeset::AtomicRequest::new();
43
44    for output in &mut outputs {
45        println!("preparing output {output:#?}");
46        let conn = card.connector_state(output.conn_id)?;
47
48        let mode = &output.mode;
49        let mode_name = String::from_utf8_lossy(&mode.name);
50        println!(
51            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
52            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
53        );
54
55        let rows = output.db.height() as usize;
56        let pitch = output.db.pitch() as usize;
57        let data = output.db.buffer_mut();
58        for i in 0..rows {
59            if (i % 8) > 3 {
60                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
61                row.fill(0xff);
62            }
63        }
64
65        println!(
66            "configuring CRTC {:?} for framebuffer {:?} and mode {mode_name} on connector {:?}",
67            output.crtc_id,
68            output.db.framebuffer_id(),
69            conn.id
70        );
71
72        req.set_property(
73            ObjectId::Connector(output.conn_id),
74            output.conn_prop_ids.crtc_id,
75            output.crtc_id,
76        );
77        req.set_property(
78            ObjectId::Crtc(output.crtc_id),
79            output.crtc_prop_ids.active,
80            true,
81        );
82        req.set_property(
83            ObjectId::Plane(output.plane_id),
84            output.plane_prop_ids.fb_id,
85            output.db.framebuffer_id(),
86        );
87        req.set_property(
88            ObjectId::Plane(output.plane_id),
89            output.plane_prop_ids.crtc_id,
90            output.crtc_id,
91        );
92        req.set_property(
93            ObjectId::Plane(output.plane_id),
94            output.plane_prop_ids.crtc_x,
95            0,
96        );
97        req.set_property(
98            ObjectId::Plane(output.plane_id),
99            output.plane_prop_ids.crtc_y,
100            0,
101        );
102        req.set_property(
103            ObjectId::Plane(output.plane_id),
104            output.plane_prop_ids.crtc_w,
105            output.db.width(),
106        );
107        req.set_property(
108            ObjectId::Plane(output.plane_id),
109            output.plane_prop_ids.crtc_h,
110            output.db.height(),
111        );
112        req.set_property(
113            ObjectId::Plane(output.plane_id),
114            output.plane_prop_ids.src_x,
115            0,
116        );
117        req.set_property(
118            ObjectId::Plane(output.plane_id),
119            output.plane_prop_ids.src_y,
120            0,
121        );
122        req.set_property(
123            ObjectId::Plane(output.plane_id),
124            output.plane_prop_ids.src_w,
125            (output.db.width() as u64) << 16,
126        );
127        req.set_property(
128            ObjectId::Plane(output.plane_id),
129            output.plane_prop_ids.src_h,
130            (output.db.height() as u64) << 16,
131        );
132    }
133
134    println!("atomic commit {req:#?}");
135    card.atomic_commit(
136        &req,
137        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
138        0,
139    )?;
140
141    let mut evt_buf = vec![0_u8; 1024];
142    loop {
143        println!("waiting for events (send SIGINT to exit)");
144        for evt in card.read_events(&mut evt_buf)? {
145            println!("event {evt:?}");
146            match evt {
147                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
148                    // In a real program this would be a time place to draw the next frame
149                    // for the reported crtc.
150                }
151                _ => {
152                    // Ignore any unrecognized event types.
153                }
154            }
155        }
156    }
157}
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, 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.