examples: add raw_atomic_drm
This commit is contained in:
parent
df097b835e
commit
9127502066
|
@ -0,0 +1,183 @@
|
|||
#![warn(rust_2018_idioms)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
|
||||
use slog::Drain;
|
||||
use smithay::{
|
||||
backend::drm::{
|
||||
atomic::{AtomicDrmDevice, AtomicDrmSurface},
|
||||
common::Error,
|
||||
device_bind, Device, DeviceHandler, RawSurface, Surface,
|
||||
},
|
||||
reexports::{
|
||||
calloop::EventLoop,
|
||||
drm::{
|
||||
buffer::format::PixelFormat,
|
||||
control::{
|
||||
connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer, property,
|
||||
Device as ControlDevice, ResourceHandle,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io::Error as IoError,
|
||||
rc::Rc,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
fn get_property_by_name<'a, D: ControlDevice, T: ResourceHandle>(
|
||||
dev: &'a D,
|
||||
handle: T,
|
||||
name: &'static str,
|
||||
) -> Option<(property::ValueType, property::RawValue)> {
|
||||
let props = dev.get_properties(handle).expect("Could not get props");
|
||||
let (ids, vals) = props.as_props_and_values();
|
||||
for (&id, &val) in ids.iter().zip(vals.iter()) {
|
||||
let info = dev.get_property(id).unwrap();
|
||||
if info.name().to_str().map(|x| x == name).unwrap_or(false) {
|
||||
let val_ty = info.value_type();
|
||||
return Some((val_ty, val));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let log = slog::Logger::root(Mutex::new(slog_term::term_full().fuse()).fuse(), o!());
|
||||
|
||||
/*
|
||||
* Initialize the drm backend
|
||||
*/
|
||||
|
||||
// "Find" a suitable drm device
|
||||
let mut options = OpenOptions::new();
|
||||
options.read(true);
|
||||
options.write(true);
|
||||
let mut device = AtomicDrmDevice::new(options.open("/dev/dri/card0").unwrap(), log.clone()).unwrap();
|
||||
|
||||
// Get a set of all modesetting resource handles (excluding planes):
|
||||
let res_handles = Device::resource_handles(&device).unwrap();
|
||||
|
||||
// Use first connected connector
|
||||
let connector_info = res_handles
|
||||
.connectors()
|
||||
.iter()
|
||||
.map(|conn| device.get_connector_info(*conn).unwrap())
|
||||
.find(|conn| conn.state() == ConnectorState::Connected)
|
||||
.unwrap();
|
||||
|
||||
// use the connected crtc if any
|
||||
let (val_ty, raw) = get_property_by_name(&device, connector_info.handle(), "CRTC_ID").unwrap();
|
||||
let crtc = match val_ty.convert_value(raw) {
|
||||
property::Value::CRTC(Some(handle)) => handle,
|
||||
property::Value::CRTC(None) => {
|
||||
// Use the first encoder
|
||||
let encoder = connector_info
|
||||
.encoders()
|
||||
.iter()
|
||||
.filter_map(|&e| e)
|
||||
.next()
|
||||
.unwrap();
|
||||
let encoder_info = device.get_encoder_info(encoder).unwrap();
|
||||
|
||||
*res_handles
|
||||
.filter_crtcs(encoder_info.possible_crtcs())
|
||||
.iter()
|
||||
.next()
|
||||
.unwrap()
|
||||
}
|
||||
_ => unreachable!("CRTC_ID does not return another property type"),
|
||||
};
|
||||
|
||||
// Assuming we found a good connector and loaded the info into `connector_info`
|
||||
let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)
|
||||
|
||||
// Initialize the hardware backend
|
||||
let surface = Rc::new(device.create_surface(crtc).unwrap());
|
||||
surface.set_connectors(&[connector_info.handle()]).unwrap();
|
||||
surface.use_mode(Some(mode)).unwrap();
|
||||
|
||||
for conn in surface.current_connectors().into_iter() {
|
||||
if conn != connector_info.handle() {
|
||||
surface.remove_connector(conn).unwrap();
|
||||
}
|
||||
}
|
||||
surface.add_connector(connector_info.handle()).unwrap();
|
||||
|
||||
/*
|
||||
* Lets create buffers and framebuffers.
|
||||
* We use drm-rs DumbBuffers, because they always work and require little to no setup.
|
||||
* But they are very slow, this is just for demonstration purposes.
|
||||
*/
|
||||
let (w, h) = mode.size();
|
||||
let front_buffer = device
|
||||
.create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
|
||||
.unwrap();
|
||||
let front_framebuffer = device.add_framebuffer(&front_buffer).unwrap();
|
||||
let back_buffer = device
|
||||
.create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
|
||||
.unwrap();
|
||||
let back_framebuffer = device.add_framebuffer(&back_buffer).unwrap();
|
||||
|
||||
device.set_handler(DrmHandlerImpl {
|
||||
current: front_framebuffer,
|
||||
front: (front_buffer, front_framebuffer),
|
||||
back: (back_buffer, back_framebuffer),
|
||||
surface: surface.clone(),
|
||||
});
|
||||
|
||||
/*
|
||||
* Register the DrmDevice on the EventLoop
|
||||
*/
|
||||
let mut event_loop = EventLoop::<()>::new().unwrap();
|
||||
let _source = device_bind(&event_loop.handle(), device)
|
||||
.map_err(|err| -> IoError { err.into() })
|
||||
.unwrap();
|
||||
|
||||
// Start rendering
|
||||
if surface.commit_pending() {
|
||||
surface.commit(front_framebuffer).unwrap();
|
||||
}
|
||||
|
||||
// Run
|
||||
event_loop.run(None, &mut (), |_| {}).unwrap();
|
||||
}
|
||||
|
||||
pub struct DrmHandlerImpl {
|
||||
front: (DumbBuffer, framebuffer::Handle),
|
||||
back: (DumbBuffer, framebuffer::Handle),
|
||||
current: framebuffer::Handle,
|
||||
surface: Rc<AtomicDrmSurface<File>>,
|
||||
}
|
||||
|
||||
impl DeviceHandler for DrmHandlerImpl {
|
||||
type Device = AtomicDrmDevice<File>;
|
||||
|
||||
fn vblank(&mut self, _crtc: crtc::Handle) {
|
||||
{
|
||||
// Swap and map buffer
|
||||
let mut mapping = if self.current == self.front.1 {
|
||||
self.current = self.back.1;
|
||||
self.surface.map_dumb_buffer(&mut self.back.0).unwrap()
|
||||
} else {
|
||||
self.current = self.front.1;
|
||||
self.surface.map_dumb_buffer(&mut self.front.0).unwrap()
|
||||
};
|
||||
|
||||
// now we could render to the mapping via software rendering.
|
||||
// this example just sets some grey color
|
||||
|
||||
for x in mapping.as_mut() {
|
||||
*x = 128;
|
||||
}
|
||||
}
|
||||
RawSurface::page_flip(&*self.surface, self.current).unwrap();
|
||||
}
|
||||
|
||||
fn error(&mut self, error: Error) {
|
||||
panic!("{:?}", error);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue