Struct linux_drm::Card

source ·
pub struct Card { /* private fields */ }

Implementations§

source§

impl Card

source

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

Examples found in repository?
examples/properties.rs (line 10)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
fn main() -> std::io::Result<()> {
    let card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    show_properties(&card).map_err(map_err)
}
More examples
Hide additional examples
examples/modesetting.rs (line 14)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    //card.set_client_cap(ClientCap::UniversalPlanes, 1)
    //    .map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
examples/modesetting-atomic.rs (line 12)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
source

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

source

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

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>

source

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

source

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

Examples found in repository?
examples/properties.rs (line 13)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
fn main() -> std::io::Result<()> {
    let card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    show_properties(&card).map_err(map_err)
}
More examples
Hide additional examples
examples/modesetting.rs (line 18)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    //card.set_client_cap(ClientCap::UniversalPlanes, 1)
    //    .map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
examples/modesetting-atomic.rs (line 16)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
source

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

Examples found in repository?
examples/properties.rs (line 19)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
fn main() -> std::io::Result<()> {
    let card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    show_properties(&card).map_err(map_err)
}
More examples
Hide additional examples
examples/modesetting.rs (line 24)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    //card.set_client_cap(ClientCap::UniversalPlanes, 1)
    //    .map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
examples/modesetting-atomic.rs (line 22)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
source

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

source

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

Examples found in repository?
examples/properties.rs (line 28)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
fn main() -> std::io::Result<()> {
    let card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    show_properties(&card).map_err(map_err)
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 33)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
source

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

source

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

Examples found in repository?
examples/modesetting.rs (line 15)
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    //card.set_client_cap(ClientCap::UniversalPlanes, 1)
    //    .map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 13)
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() -> std::io::Result<()> {
    let mut card = Card::open(c"/dev/dri/card0").map_err(map_init_err)?;
    card.become_master().map_err(map_err)?;

    {
        let name = card.driver_name().map_err(map_err)?;
        let name = String::from_utf8_lossy(&name);
        println!("Driver name: {name}");
    }

    if card
        .get_device_cap(DeviceCap::DumbBuffer)
        .map_err(map_err)?
        == 0
    {
        return Err(std::io::Error::other(
            "device does not support 'dumb buffers'",
        ));
    } else {
        println!("Device supports 'dumb buffers'");
    }

    card.set_client_cap(ClientCap::UniversalPlanes, 1)
        .map_err(map_err)?;
    card.set_client_cap(ClientCap::Atomic, 1).map_err(map_err)?;

    display_demo(&mut card).map_err(map_err)
}
source

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

source

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

Examples found in repository?
examples/properties.rs (line 154)
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
fn property_meta<'a, 'card>(
    prop_id: u32,
    prop_meta: &'a mut HashMap<u32, PropertyMeta>,
    card: &Card,
) -> Result<&'a PropertyMeta, Error> {
    Ok(prop_meta.entry(prop_id).or_insert_with(|| {
        card.property_meta(prop_id)
            .map(|meta| {
                let mut enum_names = BTreeMap::new();
                for member in meta.enum_members().unwrap() {
                    enum_names.insert(member.value(), member.name().to_string());
                }
                PropertyMeta {
                    name: meta.name().to_string(),
                    typ: meta.property_type(),
                    immutable: meta.is_immutable(),
                    values: meta.values().unwrap(),
                    enum_names,
                }
            })
            .unwrap_or(PropertyMeta {
                name: String::from("<unknown>"),
                typ: PropertyType::Unknown,
                immutable: true,
                values: Vec::new(),
                enum_names: BTreeMap::new(),
            })
    }))
}
source

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

Examples found in repository?
examples/properties.rs (line 94)
89
90
91
92
93
94
95
96
97
fn show_object_property_list(
    id: ObjectId,
    prop_meta: &mut HashMap<u32, PropertyMeta>,
    card: &Card,
) -> Result<(), Error> {
    let props = card.object_properties(id)?;
    show_property_list(&props, prop_meta, card)?;
    Ok(())
}
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 (lines 269-272)
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
    pub fn new(conn_id: u32, card: &linux_drm::Card) -> Result<Self, Error> {
        let mut ret: Self = unsafe { core::mem::zeroed() };
        card.each_object_property_meta(
            linux_drm::modeset::ObjectId::Connector(conn_id),
            |meta, _| ret.populate_from(meta),
        )?;
        Ok(ret)
    }

    pub fn populate_from<'card>(&mut self, from: linux_drm::modeset::ObjectPropMeta<'card>) {
        match from.name() {
            "CRTC_ID" => self.crtc_id = from.property_id(),
            _ => {}
        }
    }
}

#[derive(Debug)]
struct CrtcPropIds {
    active: u32,
}

impl CrtcPropIds {
    pub fn new(crtc_id: u32, card: &linux_drm::Card) -> Result<Self, Error> {
        let mut ret: Self = unsafe { core::mem::zeroed() };
        card.each_object_property_meta(linux_drm::modeset::ObjectId::Crtc(crtc_id), |meta, _| {
            ret.populate_from(meta)
        })?;
        Ok(ret)
    }

    pub fn populate_from<'card>(&mut self, from: linux_drm::modeset::ObjectPropMeta<'card>) {
        match from.name() {
            "ACTIVE" => self.active = from.property_id(),
            _ => {}
        }
    }
}

#[derive(Debug)]
struct PlanePropIds {
    typ: u32,
    fb_id: u32,
    crtc_id: u32,
    crtc_x: u32,
    crtc_y: u32,
    crtc_w: u32,
    crtc_h: u32,
    src_x: u32,
    src_y: u32,
    src_w: u32,
    src_h: u32,
}

impl PlanePropIds {
    pub fn new(plane_id: u32, card: &linux_drm::Card) -> Result<Self, Error> {
        let mut ret: Self = unsafe { core::mem::zeroed() };
        card.each_object_property_meta(
            linux_drm::modeset::ObjectId::Plane(plane_id),
            |meta, _| ret.populate_from(meta),
        )?;
        Ok(ret)
    }
source

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

Examples found in repository?
examples/modesetting.rs (line 93)
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
    let resources = card.resources()?;
    let mut outputs = Vec::<Output>::new();

    for id in resources.connector_ids.iter().copied() {
        let conn = card.connector_state(id)?;
        if conn.connection_state != ConnectionState::Connected {
            println!("ignoring unconnected connector {id:?}");
            continue;
        }
        if conn.current_encoder_id == 0 {
            println!("ignoring encoderless connector {id:?}");
            continue;
        }
        if conn.modes.len() == 0 {
            println!("ignoring modeless connector {id:?}");
            continue;
        }

        let output = prepare_output(card, conn, &resources)?;
        outputs.push(output);
    }

    Ok(outputs)
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 162)
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
    println!("preparing outputs");

    let resources = card.resources()?;
    let mut outputs = Vec::<Output>::new();

    for id in resources.connector_ids.iter().copied() {
        println!("preparing output for connector #{id}");

        let conn = card.connector_state(id)?;
        if conn.connection_state != ConnectionState::Connected {
            println!("ignoring unconnected connector {id:?}");
            continue;
        }
        if conn.current_encoder_id == 0 {
            println!("ignoring encoderless connector {id:?}");
            continue;
        }
        if conn.modes.len() == 0 {
            println!("ignoring modeless connector {id:?}");
            continue;
        }

        let output = prepare_output(card, conn, &resources)?;
        outputs.push(output);
    }

    Ok(outputs)
}
examples/properties.rs (line 36)
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
fn show_properties(card: &Card) -> Result<(), Error> {
    let res = card.resources()?;

    let mut prop_meta = HashMap::<u32, PropertyMeta>::new();

    println!("");

    for conn_id in res.connector_ids {
        println!("Connector #{conn_id}:");
        if let Err(e) =
            show_object_property_list(ObjectId::Connector(conn_id), &mut prop_meta, card)
        {
            println!("  Error: {e:?}");
        }
        println!("");
    }

    for enc_id in res.encoder_ids {
        println!("Encoder #{enc_id}:");
        if let Err(e) = show_object_property_list(ObjectId::Encoder(enc_id), &mut prop_meta, card) {
            println!("  Error: {e:?}");
        }
        println!("");
    }

    for crtc_id in res.crtc_ids {
        println!("CRTC #{crtc_id}:");
        if let Err(e) = show_object_property_list(ObjectId::Crtc(crtc_id), &mut prop_meta, card) {
            println!("  Error: {e:?}");
        }
        println!("");
    }

    for fb_id in res.fb_ids {
        println!("Framebuffer #{fb_id}:");
        if let Err(e) =
            show_object_property_list(ObjectId::Framebuffer(fb_id), &mut prop_meta, card)
        {
            println!("  Error: {e:?}");
        }
        println!("");
    }

    for plane_id in res.plane_ids {
        println!("Plane #{plane_id}:");
        if let Err(e) = show_object_property_list(ObjectId::Plane(plane_id), &mut prop_meta, card) {
            println!("  Error: {e:?}");
        }
        println!("");
    }

    Ok(())
}
source

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

Examples found in repository?
examples/modesetting.rs (line 45)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connection {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );
        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
    }

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}

fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
    let resources = card.resources()?;
    let mut outputs = Vec::<Output>::new();

    for id in resources.connector_ids.iter().copied() {
        let conn = card.connector_state(id)?;
        if conn.connection_state != ConnectionState::Connected {
            println!("ignoring unconnected connector {id:?}");
            continue;
        }
        if conn.current_encoder_id == 0 {
            println!("ignoring encoderless connector {id:?}");
            continue;
        }
        if conn.modes.len() == 0 {
            println!("ignoring modeless connector {id:?}");
            continue;
        }

        let output = prepare_output(card, conn, &resources)?;
        outputs.push(output);
    }

    Ok(outputs)
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 46)
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    let mut req = linux_drm::modeset::AtomicRequest::new();

    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connector {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );

        req.set_property(
            ObjectId::Connector(output.conn_id),
            output.conn_prop_ids.crtc_id,
            output.crtc_id as u64,
        );
        req.set_property(
            ObjectId::Crtc(output.crtc_id),
            output.crtc_prop_ids.active,
            1_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.fb_id,
            output.db.framebuffer_id() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_id,
            output.crtc_id as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_x,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_y,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_w,
            output.db.width() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_h,
            output.db.height() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_x,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_y,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_w,
            (output.db.width() as u64) << 16,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_h,
            (output.db.height() as u64) << 16,
        );
    }

    println!("atomic commit {req:#?}");
    card.atomic_commit(
        req,
        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
        0,
    )?;

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}

fn prepare_outputs(card: &Card) -> Result<Vec<Output>, Error> {
    println!("preparing outputs");

    let resources = card.resources()?;
    let mut outputs = Vec::<Output>::new();

    for id in resources.connector_ids.iter().copied() {
        println!("preparing output for connector #{id}");

        let conn = card.connector_state(id)?;
        if conn.connection_state != ConnectionState::Connected {
            println!("ignoring unconnected connector {id:?}");
            continue;
        }
        if conn.current_encoder_id == 0 {
            println!("ignoring encoderless connector {id:?}");
            continue;
        }
        if conn.modes.len() == 0 {
            println!("ignoring modeless connector {id:?}");
            continue;
        }

        let output = prepare_output(card, conn, &resources)?;
        outputs.push(output);
    }

    Ok(outputs)
}
source

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

Examples found in repository?
examples/modesetting.rs (line 132)
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;
    Ok(Output {
        conn_id: conn.id,
        crtc_id,
        mode,
        db,
    })
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 203)
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;

    // We need to find the primary plane that's currently assigned to this CRTC.
    // The following is not really a correct way to do it, but it'll work for
    // now just to test if anything is working here at all. (This makes some
    // assumptions about how the card is already configured which might not
    // actually hold in practice.)
    let mut chosen_plane_id: Option<u32> = None;
    for plane_id in resources.plane_ids.iter().copied() {
        let plane = card.plane_state(plane_id)?;
        if plane.crtc_id == crtc_id {
            chosen_plane_id = Some(plane_id);
            break;
        }
    }
    let Some(chosen_plane_id) = chosen_plane_id else {
        return Err(Error::NonExist);
    };

    println!("collecting properties");
    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;

    println!("collected properties");
    Ok(Output {
        conn_id: conn.id,
        conn_prop_ids,
        crtc_id,
        crtc_prop_ids,
        plane_id: chosen_plane_id,
        plane_prop_ids,
        mode,
        db,
    })
}
source

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

Examples found in repository?
examples/modesetting.rs (line 134)
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;
    Ok(Output {
        conn_id: conn.id,
        crtc_id,
        mode,
        db,
    })
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 205)
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;

    // We need to find the primary plane that's currently assigned to this CRTC.
    // The following is not really a correct way to do it, but it'll work for
    // now just to test if anything is working here at all. (This makes some
    // assumptions about how the card is already configured which might not
    // actually hold in practice.)
    let mut chosen_plane_id: Option<u32> = None;
    for plane_id in resources.plane_ids.iter().copied() {
        let plane = card.plane_state(plane_id)?;
        if plane.crtc_id == crtc_id {
            chosen_plane_id = Some(plane_id);
            break;
        }
    }
    let Some(chosen_plane_id) = chosen_plane_id else {
        return Err(Error::NonExist);
    };

    println!("collecting properties");
    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;

    println!("collected properties");
    Ok(Output {
        conn_id: conn.id,
        conn_prop_ids,
        crtc_id,
        crtc_prop_ids,
        plane_id: chosen_plane_id,
        plane_prop_ids,
        mode,
        db,
    })
}
source

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

Examples found in repository?
examples/modesetting-atomic.rs (line 221)
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;

    // We need to find the primary plane that's currently assigned to this CRTC.
    // The following is not really a correct way to do it, but it'll work for
    // now just to test if anything is working here at all. (This makes some
    // assumptions about how the card is already configured which might not
    // actually hold in practice.)
    let mut chosen_plane_id: Option<u32> = None;
    for plane_id in resources.plane_ids.iter().copied() {
        let plane = card.plane_state(plane_id)?;
        if plane.crtc_id == crtc_id {
            chosen_plane_id = Some(plane_id);
            break;
        }
    }
    let Some(chosen_plane_id) = chosen_plane_id else {
        return Err(Error::NonExist);
    };

    println!("collecting properties");
    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;

    println!("collected properties");
    Ok(Output {
        conn_id: conn.id,
        conn_prop_ids,
        crtc_id,
        crtc_prop_ids,
        plane_id: chosen_plane_id,
        plane_prop_ids,
        mode,
        db,
    })
}
source

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

Examples found in repository?
examples/modesetting-atomic.rs (lines 135-139)
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    let mut req = linux_drm::modeset::AtomicRequest::new();

    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connector {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );

        req.set_property(
            ObjectId::Connector(output.conn_id),
            output.conn_prop_ids.crtc_id,
            output.crtc_id as u64,
        );
        req.set_property(
            ObjectId::Crtc(output.crtc_id),
            output.crtc_prop_ids.active,
            1_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.fb_id,
            output.db.framebuffer_id() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_id,
            output.crtc_id as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_x,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_y,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_w,
            output.db.width() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_h,
            output.db.height() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_x,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_y,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_w,
            (output.db.width() as u64) << 16,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_h,
            (output.db.height() as u64) << 16,
        );
    }

    println!("atomic commit {req:#?}");
    card.atomic_commit(
        req,
        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
        0,
    )?;

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}
source

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

source

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

Examples found in repository?
examples/modesetting.rs (line 70)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connection {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );
        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
    }

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}
source

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

Examples found in repository?
examples/modesetting.rs (line 71)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connection {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );
        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
    }

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}
source

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

Examples found in repository?
examples/modesetting.rs (lines 136-141)
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;
    Ok(Output {
        conn_id: conn.id,
        crtc_id,
        mode,
        db,
    })
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (lines 207-212)
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
fn prepare_output(
    card: &Card,
    conn: ConnectorState,
    resources: &CardResources,
) -> Result<Output, Error> {
    if conn.current_encoder_id == 0 {
        // It could be reasonable to go hunting for a suitable encoder and
        // CRTC to activate this connector, but for this simple example
        // we'll just use whatever connectors are already producing some
        // output and keep using whatever modes they are currently in.
        return Err(Error::NotSupported);
    }
    let _ = resources; // (don't actually need this when we're just using the already-selected encoder/crtc)

    let enc = card.encoder_state(conn.current_encoder_id)?;
    let crtc_id = enc.current_crtc_id;
    let crtc = card.crtc_state(crtc_id)?;
    let mode = crtc.mode;
    let db = card.create_dumb_buffer(DumbBufferRequest {
        width: mode.hdisplay as u32,
        height: mode.vdisplay as u32,
        depth: 24,
        bpp: 32,
    })?;

    // We need to find the primary plane that's currently assigned to this CRTC.
    // The following is not really a correct way to do it, but it'll work for
    // now just to test if anything is working here at all. (This makes some
    // assumptions about how the card is already configured which might not
    // actually hold in practice.)
    let mut chosen_plane_id: Option<u32> = None;
    for plane_id in resources.plane_ids.iter().copied() {
        let plane = card.plane_state(plane_id)?;
        if plane.crtc_id == crtc_id {
            chosen_plane_id = Some(plane_id);
            break;
        }
    }
    let Some(chosen_plane_id) = chosen_plane_id else {
        return Err(Error::NonExist);
    };

    println!("collecting properties");
    let conn_prop_ids = ConnectorPropIds::new(conn.id, card)?;
    let crtc_prop_ids = CrtcPropIds::new(crtc_id, card)?;
    let plane_prop_ids = PlanePropIds::new(chosen_plane_id, card)?;

    println!("collected properties");
    Ok(Output {
        conn_id: conn.id,
        conn_prop_ids,
        crtc_id,
        crtc_prop_ids,
        plane_id: chosen_plane_id,
        plane_prop_ids,
        mode,
        db,
    })
}
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 77)
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connection {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );
        card.set_crtc_dumb_buffer(output.crtc_id, &output.db, mode, &[output.conn_id])?;
        card.crtc_page_flip_dumb_buffer(output.crtc_id, &output.db, PageFlipFlags::EVENT)?;
    }

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}
More examples
Hide additional examples
examples/modesetting-atomic.rs (line 144)
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
fn display_demo(card: &mut Card) -> Result<(), Error> {
    let mut outputs = prepare_outputs(&card)?;
    let mut req = linux_drm::modeset::AtomicRequest::new();

    for output in &mut outputs {
        println!("preparing output {output:#?}");
        let conn = card.connector_state(output.conn_id)?;

        let mode = &output.mode;
        let mode_name = String::from_utf8_lossy(&mode.name);
        println!(
            "{:?} connector uses {mode_name} ({}x{}@{}Hz)",
            conn.connector_type, mode.hdisplay, mode.vdisplay, mode.vrefresh,
        );

        let rows = output.db.height() as usize;
        let pitch = output.db.pitch() as usize;
        let data = output.db.buffer_mut();
        for i in 0..rows {
            if (i % 8) > 3 {
                let row = &mut data[(i * pitch)..(i * pitch) + pitch];
                row.fill(0xff);
            }
        }

        println!(
            "configuring CRTC {} for framebuffer {} and mode {mode_name} on connector {}",
            output.crtc_id,
            output.db.framebuffer_id(),
            conn.id
        );

        req.set_property(
            ObjectId::Connector(output.conn_id),
            output.conn_prop_ids.crtc_id,
            output.crtc_id as u64,
        );
        req.set_property(
            ObjectId::Crtc(output.crtc_id),
            output.crtc_prop_ids.active,
            1_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.fb_id,
            output.db.framebuffer_id() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_id,
            output.crtc_id as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_x,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_y,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_w,
            output.db.width() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.crtc_h,
            output.db.height() as u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_x,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_y,
            0_u64,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_w,
            (output.db.width() as u64) << 16,
        );
        req.set_property(
            ObjectId::Plane(output.plane_id),
            output.plane_prop_ids.src_h,
            (output.db.height() as u64) << 16,
        );
    }

    println!("atomic commit {req:#?}");
    card.atomic_commit(
        req,
        AtomicCommitFlags::ALLOW_MODESET | AtomicCommitFlags::PAGE_FLIP_EVENT,
        0,
    )?;

    let mut evt_buf = vec![0_u8; 1024];
    loop {
        println!("waiting for events (send SIGINT to exit)");
        for evt in card.read_events(&mut evt_buf)? {
            println!("event {evt:?}");
            match evt {
                DrmEvent::Generic(GenericDrmEvent::FlipComplete(_)) => {
                    // In a real program this would be a time place to draw the next frame
                    // for the reported crtc.
                }
                _ => {
                    // Ignore any unrecognized event types.
                }
            }
        }
    }
}
source

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

source

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

source

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

source

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

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

§

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>,

§

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>,

§

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.