pub struct Card { /* private fields */ }
Implementations§
source§impl Card
impl Card
sourcepub fn open(path: &CStr) -> Result<Self, InitError>
pub fn open(path: &CStr) -> Result<Self, InitError>
Examples found in repository?
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
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)
}
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)
}
pub fn from_file<D>(f: File<D>) -> Result<Self, InitError>
pub unsafe fn from_file_unchecked<D>(f: File<D>) -> Self
sourcepub fn fd(&self) -> int
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.
pub fn api_version(&self) -> Result<ApiVersion, Error>
pub fn read_driver_name<'a>( &self, into: &'a mut [u8], ) -> Result<&'a mut [u8], Error>
sourcepub fn driver_name(&self) -> Result<Vec<u8>, Error>
pub fn driver_name(&self) -> Result<Vec<u8>, Error>
Examples found in repository?
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
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)
}
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)
}
sourcepub fn get_device_cap(&self, capability: DeviceCap) -> Result<u64, Error>
pub fn get_device_cap(&self, capability: DeviceCap) -> Result<u64, Error>
Examples found in repository?
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
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)
}
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)
}
pub fn get_device_cap_raw(&self, capability: DrmCap) -> Result<u64, Error>
sourcepub fn set_client_cap(
&self,
capability: ClientCap,
value: u64,
) -> Result<(), Error>
pub fn set_client_cap( &self, capability: ClientCap, value: u64, ) -> Result<(), Error>
Examples found in repository?
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
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)
}
pub fn set_client_cap_raw( &self, capability: DrmClientCap, value: u64, ) -> Result<(), Error>
sourcepub fn become_master(&mut self) -> Result<(), Error>
pub fn become_master(&mut self) -> Result<(), Error>
Examples found in repository?
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
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)
}
pub fn drop_master(&mut self) -> Result<(), Error>
sourcepub fn property_meta(&self, prop_id: u32) -> Result<ObjectPropMeta<'_>, Error>
pub fn property_meta(&self, prop_id: u32) -> Result<ObjectPropMeta<'_>, Error>
Examples found in repository?
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(),
})
}))
}
sourcepub fn object_properties(
&self,
obj_id: impl Into<ObjectId>,
) -> Result<Vec<ModeProp>, Error>
pub fn object_properties( &self, obj_id: impl Into<ObjectId>, ) -> Result<Vec<ModeProp>, Error>
sourcepub fn each_object_property_meta(
&self,
obj_id: impl Into<ObjectId>,
f: impl FnMut(ObjectPropMeta<'_>, u64),
) -> Result<(), Error>
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?
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)
}
sourcepub fn resources(&self) -> Result<CardResources, Error>
pub fn resources(&self) -> Result<CardResources, Error>
Examples found in repository?
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
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)
}
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(())
}
sourcepub fn connector_state(
&self,
connector_id: u32,
) -> Result<ConnectorState, Error>
pub fn connector_state( &self, connector_id: u32, ) -> Result<ConnectorState, Error>
Examples found in repository?
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
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)
}
sourcepub fn encoder_state(&self, encoder_id: u32) -> Result<EncoderState, Error>
pub fn encoder_state(&self, encoder_id: u32) -> Result<EncoderState, Error>
Examples found in repository?
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
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,
})
}
sourcepub fn crtc_state(&self, crtc_id: u32) -> Result<CrtcState, Error>
pub fn crtc_state(&self, crtc_id: u32) -> Result<CrtcState, Error>
Examples found in repository?
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
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,
})
}
sourcepub fn plane_state(&self, plane_id: u32) -> Result<PlaneState, Error>
pub fn plane_state(&self, plane_id: u32) -> Result<PlaneState, Error>
Examples found in repository?
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,
})
}
sourcepub fn atomic_commit(
&mut self,
req: AtomicRequest,
flags: AtomicCommitFlags,
user_data: u64,
) -> Result<(), Error>
pub fn atomic_commit( &mut self, req: AtomicRequest, flags: AtomicCommitFlags, user_data: u64, ) -> Result<(), Error>
Examples found in repository?
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.
}
}
}
}
}
pub fn reset_crtc(&mut self, crtc_id: u32) -> Result<CrtcState, Error>
sourcepub fn set_crtc_dumb_buffer(
&mut self,
crtc_id: u32,
buf: &DumbBuffer,
mode: &ModeInfo,
conn_ids: &[u32],
) -> Result<CrtcState, Error>
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?
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.
}
}
}
}
}
sourcepub fn crtc_page_flip_dumb_buffer(
&mut self,
crtd_id: u32,
buf: &DumbBuffer,
flags: PageFlipFlags,
) -> Result<(), Error>
pub fn crtc_page_flip_dumb_buffer( &mut self, crtd_id: u32, buf: &DumbBuffer, flags: PageFlipFlags, ) -> Result<(), Error>
Examples found in repository?
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.
}
}
}
}
}
sourcepub fn create_dumb_buffer(
&self,
req: DumbBufferRequest,
) -> Result<DumbBuffer, Error>
pub fn create_dumb_buffer( &self, req: DumbBufferRequest, ) -> Result<DumbBuffer, Error>
Examples found in repository?
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
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,
})
}
sourcepub fn read_events_raw<'a>(
&self,
buf: &'a mut [u8],
) -> Result<impl Iterator<Item = &'a DrmEvent> + 'a, Error>
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.
sourcepub fn read_events<'a>(
&self,
buf: &'a mut [u8],
) -> Result<impl Iterator<Item = DrmEvent> + 'a, Error>
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?
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
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.
}
}
}
}
}