examples: fix raw_drm
This commit is contained in:
parent
0661ebebb8
commit
05f11cffeb
|
@ -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"]
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue