examples: fix raw_drm

This commit is contained in:
Victor Brekenfeld 2021-04-28 22:09:21 +02:00
parent 0661ebebb8
commit 05f11cffeb
3 changed files with 58 additions and 229 deletions

View File

@ -20,6 +20,7 @@ drm = { version = "^0.4.0-alpha1", git = "https://github.com/drakulix/drm-rs", b
drm-ffi = { version = "^0.4.0-alpha1", git = "https://github.com/drakulix/drm-rs", branch = "next", optional = true } drm-ffi = { version = "^0.4.0-alpha1", git = "https://github.com/drakulix/drm-rs", branch = "next", optional = true }
gbm = { version = "^0.6.0", git = "https://github.com/drakulix/gbm.rs", branch = "develop", optional = true, default-features = false, features = ["drm-support"] } gbm = { version = "^0.6.0", git = "https://github.com/drakulix/gbm.rs", branch = "develop", optional = true, default-features = false, features = ["drm-support"] }
input = { version = "0.5", default-features = false, optional = true } input = { version = "0.5", default-features = false, optional = true }
image = { version = "0.23.14", default-features = false, optional = true }
lazy_static = "1" lazy_static = "1"
libc = "0.2.70" libc = "0.2.70"
libloading = "0.7.0" libloading = "0.7.0"
@ -62,9 +63,5 @@ xwayland = ["wayland_frontend"]
test_all_features = ["default"] test_all_features = ["default"]
[[example]] [[example]]
name = "raw_legacy_drm" name = "raw_drm"
required-features = ["backend_drm"]
[[example]]
name = "raw_atomic_drm"
required-features = ["backend_drm"] required-features = ["backend_drm"]

View File

@ -1,182 +0,0 @@
#![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<D: ControlDevice, T: ResourceHandle>(
dev: &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(), true, 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())[0]
}
_ => 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, mode, &[connector_info.handle()])
.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);
}
}

View File

@ -5,18 +5,20 @@ extern crate slog;
use slog::Drain; use slog::Drain;
use smithay::{ use smithay::{
backend::drm::{ backend::{
common::Error, allocator::{Format, Fourcc, Modifier, Swapchain, Slot, dumb::DumbBuffer},
drm::{
DrmError,
DrmDevice, DrmSurface,
DeviceHandler,
device_bind, device_bind,
legacy::{LegacyDrmDevice, LegacyDrmSurface}, }
Device, DeviceHandler, RawSurface,
}, },
reexports::{ reexports::{
calloop::EventLoop, calloop::EventLoop,
drm::{ drm::{
buffer::format::PixelFormat,
control::{ control::{
connector::State as ConnectorState, crtc, dumbbuffer::DumbBuffer, framebuffer, connector::State as ConnectorState, crtc, framebuffer,
Device as ControlDevice, Device as ControlDevice,
}, },
}, },
@ -24,11 +26,23 @@ use smithay::{
}; };
use std::{ use std::{
fs::{File, OpenOptions}, fs::{File, OpenOptions},
os::unix::io::{AsRawFd, RawFd},
io::Error as IoError, io::Error as IoError,
rc::Rc, rc::Rc,
sync::Mutex, sync::Mutex,
}; };
#[derive(Clone)]
struct FdWrapper {
file: Rc<File>,
}
impl AsRawFd for FdWrapper {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
fn main() { fn main() {
let log = slog::Logger::root(Mutex::new(slog_term::term_full().fuse()).fuse(), o!()); let log = slog::Logger::root(Mutex::new(slog_term::term_full().fuse()).fuse(), o!());
@ -40,17 +54,19 @@ fn main() {
let mut options = OpenOptions::new(); let mut options = OpenOptions::new();
options.read(true); options.read(true);
options.write(true); options.write(true);
let fd = FdWrapper { file: Rc::new(options.open("/dev/dri/card0").unwrap()) };
let mut device = let mut device =
LegacyDrmDevice::new(options.open("/dev/dri/card0").unwrap(), true, log.clone()).unwrap(); DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
// Get a set of all modesetting resource handles (excluding planes): // Get a set of all modesetting resource handles (excluding planes):
let res_handles = Device::resource_handles(&device).unwrap(); let res_handles = ControlDevice::resource_handles(&device).unwrap();
// Use first connected connector // Use first connected connector
let connector_info = res_handles let connector_info = res_handles
.connectors() .connectors()
.iter() .iter()
.map(|conn| device.get_connector_info(*conn).unwrap()) .map(|conn| device.get_connector(*conn).unwrap())
.find(|conn| conn.state() == ConnectorState::Connected) .find(|conn| conn.state() == ConnectorState::Connected)
.unwrap(); .unwrap();
@ -61,7 +77,7 @@ fn main() {
.filter_map(|&e| e) .filter_map(|&e| e)
.next() .next()
.unwrap(); .unwrap();
let encoder_info = device.get_encoder_info(encoder).unwrap(); let encoder_info = device.get_encoder(encoder).unwrap();
// use the connected crtc if any // use the connected crtc if any
let crtc = encoder_info let crtc = encoder_info
@ -72,10 +88,13 @@ fn main() {
// Assuming we found a good connector and loaded the info into `connector_info` // 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.) 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.)
// We just use one plane, the primary one
let plane = device.planes(&crtc).unwrap().primary;
// Initialize the hardware backend // Initialize the hardware backend
let surface = Rc::new( let surface = Rc::new(
device device
.create_surface(crtc, mode, &[connector_info.handle()]) .create_surface(crtc, plane, mode, &[connector_info.handle()])
.unwrap(), .unwrap(),
); );
@ -85,19 +104,16 @@ fn main() {
* But they are very slow, this is just for demonstration purposes. * But they are very slow, this is just for demonstration purposes.
*/ */
let (w, h) = mode.size(); let (w, h) = mode.size();
let front_buffer = device let allocator = DrmDevice::new(fd, false, log.clone()).unwrap();
.create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888) let mut swapchain = Swapchain::new(allocator, w.into(), h.into(), Format { code: Fourcc::Argb8888, modifier: Modifier::Invalid });
.unwrap(); let first_buffer: Slot<DumbBuffer<FdWrapper>, _> = swapchain.acquire().unwrap().unwrap();
let front_framebuffer = device.add_framebuffer(&front_buffer).unwrap(); let framebuffer = surface.add_framebuffer(&first_buffer.handle, 32, 32).unwrap();
let back_buffer = device first_buffer.set_userdata(framebuffer);
.create_dumb_buffer((w as u32, h as u32), PixelFormat::XRGB8888)
.unwrap();
let back_framebuffer = device.add_framebuffer(&back_buffer).unwrap();
// Get the device as an allocator into the
device.set_handler(DrmHandlerImpl { device.set_handler(DrmHandlerImpl {
current: front_framebuffer, swapchain,
front: (front_buffer, front_framebuffer), current: first_buffer,
back: (back_buffer, back_framebuffer),
surface: surface.clone(), surface: surface.clone(),
}); });
@ -110,46 +126,44 @@ fn main() {
.unwrap(); .unwrap();
// Start rendering // Start rendering
if surface.commit_pending() { surface.commit(framebuffer, true).unwrap();
surface.commit(front_framebuffer).unwrap();
}
// Run // Run
event_loop.run(None, &mut (), |_| {}).unwrap(); event_loop.run(None, &mut (), |_| {}).unwrap();
} }
pub struct DrmHandlerImpl { pub struct DrmHandlerImpl {
front: (DumbBuffer, framebuffer::Handle), swapchain: Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle, DumbBuffer<FdWrapper>>,
back: (DumbBuffer, framebuffer::Handle), current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>,
current: framebuffer::Handle, surface: Rc<DrmSurface<FdWrapper>>,
surface: Rc<LegacyDrmSurface<File>>,
} }
impl DeviceHandler for DrmHandlerImpl { impl DeviceHandler for DrmHandlerImpl {
type Device = LegacyDrmDevice<File>;
fn vblank(&mut self, _crtc: crtc::Handle) { fn vblank(&mut self, _crtc: crtc::Handle) {
{ {
// Swap and map buffer // Next buffer
let mut mapping = if self.current == self.front.1 { let next = self.swapchain.acquire().unwrap().unwrap();
self.current = self.back.1; if next.userdata().is_none() {
self.surface.map_dumb_buffer(&mut self.back.0).unwrap() let fb = self.surface.add_framebuffer(&next.handle, 32, 32).unwrap();
} else { next.set_userdata(fb);
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. // now we could render to the mapping via software rendering.
// this example just sets some grey color // this example just sets some grey color
let mut db = next.handle;
let mut mapping = self.surface.map_dumb_buffer(&mut db).unwrap();
for x in mapping.as_mut() { for x in mapping.as_mut() {
*x = 128; *x = 128;
} }
} self.current = next;
RawSurface::page_flip(&*self.surface, self.current).unwrap();
} }
fn error(&mut self, error: Error) { let fb = self.current.userdata().unwrap();
self.surface.page_flip(fb, true).unwrap();
}
fn error(&mut self, error: DrmError) {
panic!("{:?}", error); panic!("{:?}", error);
} }
} }