smithay/examples/raw_drm.rs

174 lines
5.2 KiB
Rust
Raw Normal View History

2018-12-15 20:58:43 +00:00
#![warn(rust_2018_idioms)]
2018-12-05 21:44:30 +00:00
#[macro_use]
extern crate slog;
use slog::Drain;
use smithay::{
2021-04-28 20:09:21 +00:00
backend::{
allocator::{dumb::DumbBuffer, Fourcc, Slot, Swapchain},
drm::{DrmDevice, DrmEvent, DrmSurface},
2018-12-13 17:48:54 +00:00
},
reexports::{
2019-02-05 16:26:09 +00:00
calloop::EventLoop,
2021-04-28 22:32:47 +00:00
drm::control::{connector::State as ConnectorState, crtc, framebuffer, Device as ControlDevice},
2018-12-05 21:44:30 +00:00
},
};
use std::{
fs::{File, OpenOptions},
2021-04-28 22:32:47 +00:00
os::unix::io::{AsRawFd, RawFd},
2018-12-05 21:44:30 +00:00
rc::Rc,
sync::Mutex,
};
2021-04-28 20:09:21 +00:00
#[derive(Clone)]
struct FdWrapper {
file: Rc<File>,
}
impl AsRawFd for FdWrapper {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
2018-12-05 21:44:30 +00:00
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);
2021-04-28 22:32:47 +00:00
let fd = FdWrapper {
file: Rc::new(options.open("/dev/dri/card0").unwrap()),
};
2021-04-28 20:09:21 +00:00
let device = DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
2018-12-05 21:44:30 +00:00
// Get a set of all modesetting resource handles (excluding planes):
2021-04-28 20:09:21 +00:00
let res_handles = ControlDevice::resource_handles(&device).unwrap();
2018-12-05 21:44:30 +00:00
// Use first connected connector
let connector_info = res_handles
.connectors()
.iter()
2021-04-28 20:09:21 +00:00
.map(|conn| device.get_connector(*conn).unwrap())
2020-04-07 13:15:29 +00:00
.find(|conn| conn.state() == ConnectorState::Connected)
2018-12-05 21:44:30 +00:00
.unwrap();
// Use the first encoder
2020-04-10 15:01:49 +00:00
let encoder = connector_info
.encoders()
.iter()
.filter_map(|&e| e)
.next()
.unwrap();
2021-04-28 20:09:21 +00:00
let encoder_info = device.get_encoder(encoder).unwrap();
2018-12-05 21:44:30 +00:00
// use the connected crtc if any
let crtc = encoder_info
2020-04-07 13:15:29 +00:00
.crtc()
2018-12-05 21:44:30 +00:00
// or use the first one that is compatible with the encoder
2020-09-14 22:49:10 +00:00
.unwrap_or_else(|| res_handles.filter_crtcs(encoder_info.possible_crtcs())[0]);
2018-12-05 21:44:30 +00:00
// 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
2020-04-30 17:03:02 +00:00
let surface = Rc::new(
device
.create_surface(crtc, mode, &[connector_info.handle()])
2020-04-30 17:03:02 +00:00
.unwrap(),
);
2018-12-05 21:44:30 +00:00
/*
* 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();
2021-04-28 20:09:21 +00:00
let allocator = DrmDevice::new(fd, false, log.clone()).unwrap();
let mods = surface
.supported_formats(surface.plane())
.expect("Unable to readout formats for surface")
.iter()
2021-06-09 20:12:35 +00:00
.filter_map(|format| {
if format.code == Fourcc::Argb8888 {
Some(format.modifier)
} else {
None
}
})
.collect::<Vec<_>>();
2021-06-09 20:12:35 +00:00
let mut swapchain = Swapchain::new(allocator, w.into(), h.into(), Fourcc::Argb8888, mods);
2021-04-28 20:09:21 +00:00
let first_buffer: Slot<DumbBuffer<FdWrapper>, _> = swapchain.acquire().unwrap().unwrap();
2021-04-30 15:21:35 +00:00
let framebuffer = surface.add_framebuffer(first_buffer.handle(), 32, 32).unwrap();
2021-05-23 13:13:04 +00:00
*first_buffer.userdata() = Some(framebuffer);
2018-12-05 21:44:30 +00:00
2021-04-28 22:32:47 +00:00
// Get the device as an allocator into the
let mut vblank_handler = VBlankHandler {
2021-04-28 20:09:21 +00:00
swapchain,
current: first_buffer,
2018-12-05 21:44:30 +00:00
surface: surface.clone(),
};
2018-12-05 21:44:30 +00:00
/*
* Register the DrmDevice on the EventLoop
*/
let mut event_loop = EventLoop::<()>::try_new().unwrap();
event_loop
.handle()
.insert_source(device, move |event, _: &mut (), _: &mut ()| match event {
DrmEvent::VBlank(crtc) => vblank_handler.vblank(crtc),
DrmEvent::Error(e) => panic!("{}", e),
})
2018-12-05 21:44:30 +00:00
.unwrap();
// Start rendering
2021-05-26 17:12:45 +00:00
surface
.commit([(framebuffer, surface.plane())].iter(), true)
.unwrap();
2018-12-05 21:44:30 +00:00
// Run
event_loop.run(None, &mut (), |_| {}).unwrap();
}
pub struct VBlankHandler {
2021-05-15 16:17:43 +00:00
swapchain: Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle>,
2021-04-28 20:09:21 +00:00
current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>,
surface: Rc<DrmSurface<FdWrapper>>,
2018-12-05 21:44:30 +00:00
}
impl VBlankHandler {
2018-12-05 21:44:30 +00:00
fn vblank(&mut self, _crtc: crtc::Handle) {
{
2021-04-28 20:09:21 +00:00
// Next buffer
let next = self.swapchain.acquire().unwrap().unwrap();
if next.userdata().is_none() {
2021-04-30 15:21:35 +00:00
let fb = self.surface.add_framebuffer(next.handle(), 32, 32).unwrap();
2021-05-23 13:13:04 +00:00
*next.userdata() = Some(fb);
2021-04-28 20:09:21 +00:00
}
2018-12-05 21:44:30 +00:00
// now we could render to the mapping via software rendering.
// this example just sets some grey color
2021-04-30 15:21:35 +00:00
{
let mut db = *next.handle();
let mut mapping = self.surface.map_dumb_buffer(&mut db).unwrap();
for x in mapping.as_mut() {
*x = 128;
}
2018-12-05 21:44:30 +00:00
}
2021-04-28 20:09:21 +00:00
self.current = next;
2018-12-05 21:44:30 +00:00
}
2021-04-28 20:09:21 +00:00
let fb = self.current.userdata().unwrap();
2021-05-26 17:12:45 +00:00
self.surface
.page_flip([(fb, self.surface.plane())].iter(), true)
.unwrap();
2018-12-05 21:44:30 +00:00
}
}