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 ::{
backend ::drm ::{
2020-04-15 21:26:38 +00:00
common ::Error ,
2018-12-13 17:48:54 +00:00
device_bind ,
2020-04-15 21:26:38 +00:00
legacy ::{ LegacyDrmDevice , LegacyDrmSurface } ,
2018-12-13 17:48:54 +00:00
Device , DeviceHandler , RawSurface , Surface ,
} ,
reexports ::{
2019-02-05 16:26:09 +00:00
calloop ::EventLoop ,
2018-12-15 20:20:08 +00:00
drm ::{
2020-04-07 13:15:29 +00:00
buffer ::format ::PixelFormat ,
2018-12-15 20:20:08 +00:00
control ::{
2020-04-12 20:35:24 +00:00
connector ::State as ConnectorState , crtc , dumbbuffer ::DumbBuffer , framebuffer ,
Device as ControlDevice ,
2018-12-15 20:20:08 +00:00
} ,
2018-12-13 17:48:54 +00:00
} ,
2018-12-05 21:44:30 +00:00
} ,
} ;
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 ) ;
2020-04-26 11:52:31 +00:00
let mut device = LegacyDrmDevice ::new ( options . open ( " /dev/dri/card0 " ) . unwrap ( ) , true , log . clone ( ) ) . unwrap ( ) ;
2018-12-05 21:44:30 +00:00
// 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 ( )
2020-04-07 13:15:29 +00:00
. map ( | conn | device . get_connector_info ( * conn ) . unwrap ( ) )
. 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 ( ) ;
2020-04-07 13:15:29 +00:00
let encoder_info = device . get_encoder_info ( 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
. 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 ( ) ;
2020-04-19 20:23:16 +00:00
surface . set_connectors ( & [ connector_info . handle ( ) ] ) . 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 ( ) ;
2020-04-10 15:01:49 +00:00
let front_buffer = device
. create_dumb_buffer ( ( w as u32 , h as u32 ) , PixelFormat ::XRGB8888 )
. unwrap ( ) ;
2020-04-07 13:15:29 +00:00
let front_framebuffer = device . add_framebuffer ( & front_buffer ) . unwrap ( ) ;
2020-04-10 15:01:49 +00:00
let back_buffer = device
. create_dumb_buffer ( ( w as u32 , h as u32 ) , PixelFormat ::XRGB8888 )
. unwrap ( ) ;
2020-04-07 13:15:29 +00:00
let back_framebuffer = device . add_framebuffer ( & back_buffer ) . unwrap ( ) ;
2018-12-05 21:44:30 +00:00
device . set_handler ( DrmHandlerImpl {
2020-04-07 13:15:29 +00:00
current : front_framebuffer ,
front : ( front_buffer , front_framebuffer ) ,
2018-12-05 21:44:30 +00:00
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 ( ) {
2020-04-07 13:15:29 +00:00
surface . commit ( front_framebuffer ) . unwrap ( ) ;
2018-12-05 21:44:30 +00:00
}
// Run
event_loop . run ( None , & mut ( ) , | _ | { } ) . unwrap ( ) ;
}
pub struct DrmHandlerImpl {
2020-04-07 13:15:29 +00:00
front : ( DumbBuffer , framebuffer ::Handle ) ,
back : ( DumbBuffer , framebuffer ::Handle ) ,
2018-12-05 21:44:30 +00:00
current : framebuffer ::Handle ,
surface : Rc < LegacyDrmSurface < File > > ,
}
impl DeviceHandler for DrmHandlerImpl {
type Device = LegacyDrmDevice < File > ;
fn vblank ( & mut self , _crtc : crtc ::Handle ) {
{
// Swap and map buffer
2020-04-07 13:15:29 +00:00
let mut mapping = if self . current = = self . front . 1 {
self . current = self . back . 1 ;
self . surface . map_dumb_buffer ( & mut self . back . 0 ) . unwrap ( )
2018-12-05 21:44:30 +00:00
} else {
2020-04-07 13:15:29 +00:00
self . current = self . front . 1 ;
self . surface . map_dumb_buffer ( & mut self . front . 0 ) . unwrap ( )
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
2018-12-15 20:58:43 +00:00
for x in mapping . as_mut ( ) {
2018-12-05 21:44:30 +00:00
* x = 128 ;
}
}
2020-04-07 13:15:29 +00:00
RawSurface ::page_flip ( & * self . surface , self . current ) . unwrap ( ) ;
2018-12-05 21:44:30 +00:00
}
fn error ( & mut self , error : Error ) {
panic! ( " {:?} " , error ) ;
}
}