#![warn(rust_2018_idioms)] #[macro_use] extern crate slog; use glium::Surface as GliumSurface; use slog::Drain; use smithay::{ backend::{ drm::{ atomic::AtomicDrmDevice, common::fallback::{EitherError, FallbackDevice}, common::Error as DrmError, device_bind, egl::{EglDevice, EglSurface, Error as EglError}, eglstream::{ egl::EglStreamDeviceBackend, EglStreamDevice, EglStreamSurface, Error as EglStreamError, }, legacy::LegacyDrmDevice, Device, DeviceHandler, }, graphics::glium::GliumGraphicsBackend, }, reexports::{ calloop::EventLoop, drm::control::{connector::State as ConnectorState, crtc}, }, }; use std::{ fs::{File, OpenOptions}, io::Error as IoError, os::unix::io::{AsRawFd, RawFd}, rc::Rc, sync::Mutex, }; pub struct ClonableFile { file: File, } impl AsRawFd for ClonableFile { fn as_raw_fd(&self) -> RawFd { self.file.as_raw_fd() } } impl Clone for ClonableFile { fn clone(&self) -> Self { ClonableFile { file: self.file.try_clone().expect("Unable to clone file"), } } } 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 file = ClonableFile { file: options.open("/dev/dri/card1").expect("Failed to open card1"), }; let mut device = EglDevice::new( EglStreamDevice::new( FallbackDevice::, LegacyDrmDevice<_>>::new(file, true, log.clone()) .expect("Failed to initialize drm device"), log.clone(), ) .expect("Failed to initialize egl stream device"), log.clone(), ) .expect("Failed to initialize egl device"); // 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(&device, *conn).unwrap()) .find(|conn| conn.state() == ConnectorState::Connected) .unwrap(); println!("Conn: {:?}", connector_info.interface()); // Use the first encoder let encoder_info = Device::get_encoder_info(&device, connector_info.encoders()[0].expect("expected encoder")).unwrap(); // use the connected crtc if any let crtc = encoder_info .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() }); println!("Crtc {:?}", crtc); // Assuming we found a good connector and loaded the info into `connector_info` let mode = connector_info.modes()[0]; // Use first mode (usually highest resolution, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) println!("Mode: {:?}", mode); // Initialize the hardware backend let surface = device .create_surface(crtc, mode, &[connector_info.handle()]) .expect("Failed to create surface"); let backend: Rc> = Rc::new(surface.into()); device.set_handler(DrmHandlerImpl { surface: backend.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 let Err(smithay::backend::graphics::SwapBuffersError::ContextLost(err)) = backend.draw().finish() { println!("{}", err); return; }; } // Run event_loop.run(None, &mut (), |_| {}).unwrap(); } pub struct DrmHandlerImpl { surface: Rc< GliumGraphicsBackend< EglSurface< EglStreamSurface< FallbackDevice, LegacyDrmDevice>, >, >, >, >, } impl DeviceHandler for DrmHandlerImpl { type Device = EglDevice< EglStreamDeviceBackend, LegacyDrmDevice>>, EglStreamDevice, LegacyDrmDevice>>, >; fn vblank(&mut self, _crtc: crtc::Handle) { { println!("Vblank"); let mut frame = self.surface.draw(); frame.clear(None, Some((0.8, 0.8, 0.9, 1.0)), false, Some(1.0), None); if let Err(smithay::backend::graphics::SwapBuffersError::ContextLost(err)) = frame.finish() { panic!("Failed to swap: {}", err); } } } fn error(&mut self, error: EglError>>) { panic!("{:?}", error); } }