diff --git a/Cargo.toml b/Cargo.toml index da4bdb3..f08b880 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,9 @@ image = "0.17.0" error-chain = "0.11.0" lazy_static = "1.0.0" +[dev-dependencies] +slog-term = "2.3" + [build-dependencies] gl_generator = { version = "0.9", optional = true } diff --git a/examples/raw_drm.rs b/examples/raw_drm.rs new file mode 100644 index 0000000..ba14bff --- /dev/null +++ b/examples/raw_drm.rs @@ -0,0 +1,150 @@ +extern crate drm; +extern crate smithay; +#[macro_use] +extern crate slog; +extern crate slog_term; + +use drm::{buffer::PixelFormat, control::dumbbuffer::DumbBuffer}; +use slog::Drain; +use smithay::{ + backend::drm::{ + connector::{self, State as ConnectorState}, + crtc, device_bind, encoder, framebuffer, + legacy::{error::Error, LegacyDrmDevice, LegacyDrmSurface}, + ControlDevice, Device, DeviceHandler, RawSurface, ResourceInfo, Surface, + }, + wayland_server::calloop::EventLoop, +}; +use std::{ + fs::{File, OpenOptions}, + io::Error as IoError, + rc::Rc, + sync::Mutex, +}; + +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 = LegacyDrmDevice::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::resource_info::(&device, *conn).unwrap()) + .find(|conn| conn.connection_state() == ConnectorState::Connected) + .unwrap(); + + // Use the first encoder + let encoder_info = Device::resource_info::(&device, connector_info.encoders()[0]).unwrap(); + + // use the connected crtc if any + let crtc = encoder_info + .current_crtc() + // or use the first one that is compatible with the encoder + .unwrap_or_else(|| { + *res_handles + .filter_crtcs(encoder_info.possible_crtcs()) + .iter() + .next() + .unwrap() + }); + + // 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.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 = + DumbBuffer::create_from_device(&device, (w as u32, h as u32), PixelFormat::XRGB8888).unwrap(); + let front_framebuffer = device.create_framebuffer(&front_buffer).unwrap(); + let back_buffer = + DumbBuffer::create_from_device(&device, (w as u32, h as u32), PixelFormat::XRGB8888).unwrap(); + let back_framebuffer = device.create_framebuffer(&back_buffer).unwrap(); + + device.set_handler(DrmHandlerImpl { + current: front_framebuffer.handle(), + front: (front_buffer, front_framebuffer.clone()), + 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.handle()).unwrap(); + } + surface.page_flip(front_framebuffer.handle()).unwrap(); + + // Run + event_loop.run(None, &mut (), |_| {}).unwrap(); +} + +pub struct DrmHandlerImpl { + front: (DumbBuffer, framebuffer::Info), + back: (DumbBuffer, framebuffer::Info), + current: framebuffer::Handle, + surface: Rc>, +} + +impl DeviceHandler for DrmHandlerImpl { + type Device = LegacyDrmDevice; + + fn vblank(&mut self, _crtc: crtc::Handle) { + { + // Swap and map buffer + let mut mapping = if self.current == self.front.1.handle() { + self.current = self.back.1.handle(); + self.back.0.map(&*self.surface).unwrap() + } else { + self.current = self.front.1.handle(); + self.front.0.map(&*self.surface).unwrap() + }; + + // now we could render to the mapping via software rendering. + // this example just sets some grey color + + for mut x in mapping.as_mut() { + *x = 128; + } + } + self.surface.page_flip(self.current).unwrap(); + } + + fn error(&mut self, error: Error) { + panic!("{:?}", error); + } +} diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index d75932a..8a143b0 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -36,9 +36,11 @@ //! pub use drm::{ - Device as BasicDevice, buffer::Buffer, - control::{connector, crtc, framebuffer, Mode, ResourceHandles, ResourceInfo, Device as ControlDevice}, + control::{ + connector, crtc, encoder, framebuffer, Device as ControlDevice, Mode, ResourceHandles, ResourceInfo, + }, + Device as BasicDevice, }; pub use nix::libc::dev_t;