2017-09-13 20:51:35 +00:00
extern crate drm ;
#[ macro_use ]
extern crate glium ;
extern crate rand ;
#[ macro_use(define_roles) ]
extern crate smithay ;
extern crate wayland_server ;
#[ macro_use ]
extern crate slog ;
extern crate slog_async ;
extern crate slog_term ;
mod helpers ;
2018-01-05 19:04:46 +00:00
use drm ::Device as BasicDevice ;
2017-09-13 20:51:35 +00:00
use drm ::control ::{ Device as ControlDevice , ResourceInfo } ;
use drm ::control ::connector ::{ Info as ConnectorInfo , State as ConnectorState } ;
2017-10-01 17:21:12 +00:00
use drm ::control ::crtc ;
2017-09-17 20:37:54 +00:00
use drm ::control ::encoder ::Info as EncoderInfo ;
2017-09-27 20:44:08 +00:00
use drm ::result ::Error as DrmError ;
2018-01-05 19:04:46 +00:00
use glium ::{ Blend , Surface } ;
2018-01-07 21:30:38 +00:00
use helpers ::{ init_shell , Buffer , GliumDrawer , MyWindowMap , Roles , SurfaceData } ;
2017-09-20 15:09:37 +00:00
use slog ::{ Drain , Logger } ;
2017-09-20 17:48:58 +00:00
use smithay ::backend ::drm ::{ drm_device_bind , DrmBackend , DrmDevice , DrmHandler } ;
2017-09-13 20:51:35 +00:00
use smithay ::backend ::graphics ::egl ::EGLGraphicsBackend ;
2018-01-07 21:30:38 +00:00
use smithay ::backend ::graphics ::egl ::wayland ::{ EGLDisplay , EGLWaylandExtensions , Format } ;
2017-09-28 19:57:02 +00:00
use smithay ::wayland ::compositor ::{ CompositorToken , SubsurfaceRole , TraversalAction } ;
use smithay ::wayland ::compositor ::roles ::Role ;
use smithay ::wayland ::shm ::init_shm_global ;
2017-09-22 12:56:59 +00:00
use std ::cell ::RefCell ;
2018-01-05 19:04:46 +00:00
use std ::fs ::{ File , OpenOptions } ;
use std ::os ::unix ::io ::AsRawFd ;
2018-01-07 21:30:38 +00:00
use std ::os ::unix ::io ::RawFd ;
2017-09-22 12:56:59 +00:00
use std ::rc ::Rc ;
2017-09-14 20:32:53 +00:00
use std ::time ::Duration ;
2018-01-05 19:04:46 +00:00
#[ derive(Debug) ]
pub struct Card ( File ) ;
impl AsRawFd for Card {
fn as_raw_fd ( & self ) -> RawFd {
self . 0. as_raw_fd ( )
}
}
impl BasicDevice for Card { }
impl ControlDevice for Card { }
2017-09-13 20:51:35 +00:00
fn main ( ) {
// A logger facility, here we use the terminal for this example
let log = Logger ::root (
slog_async ::Async ::default ( slog_term ::term_full ( ) . fuse ( ) ) . fuse ( ) ,
o! ( ) ,
) ;
// Initialize the wayland server
let ( mut display , mut event_loop ) = wayland_server ::create_display ( ) ;
2017-09-14 21:20:48 +00:00
/*
* Initialize the drm backend
* /
2017-09-13 20:51:35 +00:00
// "Find" a suitable drm device
let mut options = OpenOptions ::new ( ) ;
options . read ( true ) ;
options . write ( true ) ;
2018-01-07 21:30:38 +00:00
let mut device = DrmDevice ::new (
Card ( options . clone ( ) . open ( " /dev/dri/card0 " ) . unwrap ( ) ) ,
log . clone ( ) ,
) . unwrap ( ) ;
2017-09-13 20:51:35 +00:00
// Get a set of all modesetting resource handles (excluding planes):
let res_handles = device . resource_handles ( ) . unwrap ( ) ;
// Use first connected connector
let connector_info = res_handles
. connectors ( )
. iter ( )
2018-01-07 21:30:38 +00:00
. map ( | conn | ConnectorInfo ::load_from_device ( & device , * conn ) . unwrap ( ) )
2017-09-13 20:51:35 +00:00
. find ( | conn | conn . connection_state ( ) = = ConnectorState ::Connected )
. unwrap ( ) ;
2017-09-17 20:37:54 +00:00
// Use the first encoder
let encoder_info = EncoderInfo ::load_from_device ( & 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 ( | |
2017-09-27 20:44:08 +00:00
* res_handles . filter_crtcs ( encoder_info . possible_crtcs ( ) )
2017-09-17 20:37:54 +00:00
. iter ( )
2017-09-27 20:44:08 +00:00
. next ( )
2017-09-17 20:37:54 +00:00
. unwrap ( ) ) ;
2017-09-13 20:51:35 +00:00
// 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.)
2018-01-05 19:04:46 +00:00
// Initialize the hardware backend
2018-01-07 21:30:38 +00:00
let renderer = GliumDrawer ::from (
device
. create_backend ( crtc , mode , vec! [ connector_info . handle ( ) ] )
. unwrap ( ) ,
) ;
2017-10-01 17:21:12 +00:00
{
/*
* Initialize glium
* /
2018-01-05 19:04:46 +00:00
let mut frame = renderer . draw ( ) ;
2017-10-01 17:21:12 +00:00
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
frame . finish ( ) . unwrap ( ) ;
}
2017-09-13 20:51:35 +00:00
2018-01-05 19:04:46 +00:00
let egl_display = Rc ::new ( RefCell ::new (
if let Ok ( egl_display ) = renderer . bind_wl_display ( & display ) {
info! ( log , " EGL hardware-acceleration enabled " ) ;
Some ( egl_display )
} else {
None
2018-01-07 21:30:38 +00:00
} ,
2018-01-05 19:04:46 +00:00
) ) ;
2017-09-13 20:51:35 +00:00
/*
2017-09-20 15:09:37 +00:00
* Initialize the globals
2017-09-13 20:51:35 +00:00
* /
2017-09-20 15:09:37 +00:00
init_shm_global ( & mut event_loop , vec! [ ] , log . clone ( ) ) ;
2017-09-13 20:51:35 +00:00
2018-01-07 21:30:38 +00:00
let ( compositor_token , _shell_state_token , window_map ) =
init_shell ( & mut event_loop , log . clone ( ) , egl_display . clone ( ) ) ;
2017-09-13 20:51:35 +00:00
/*
* Add a listening socket :
* /
let name = display . add_socket_auto ( ) . unwrap ( ) . into_string ( ) . unwrap ( ) ;
println! ( " Listening on socket: {} " , name ) ;
2017-09-14 21:20:48 +00:00
/*
* Register the DrmDevice on the EventLoop
* /
2017-09-20 15:09:37 +00:00
let _source = drm_device_bind (
& mut event_loop ,
2018-01-31 16:23:05 +00:00
device ,
2017-09-20 15:09:37 +00:00
DrmHandlerImpl {
compositor_token ,
2017-09-22 12:56:59 +00:00
window_map : window_map . clone ( ) ,
2018-01-05 19:04:46 +00:00
drawer : renderer ,
2017-09-20 15:09:37 +00:00
logger : log ,
} ,
) . unwrap ( ) ;
2017-09-13 20:51:35 +00:00
2017-09-22 12:56:59 +00:00
loop {
event_loop . dispatch ( Some ( 16 ) ) . unwrap ( ) ;
display . flush_clients ( ) ;
window_map . borrow_mut ( ) . refresh ( ) ;
}
2017-09-13 20:51:35 +00:00
}
pub struct DrmHandlerImpl {
2018-01-05 19:04:46 +00:00
compositor_token : CompositorToken < SurfaceData , Roles , Rc < RefCell < Option < EGLDisplay > > > > ,
2017-09-22 12:56:59 +00:00
window_map : Rc < RefCell < MyWindowMap > > ,
2018-01-05 19:04:46 +00:00
drawer : GliumDrawer < DrmBackend < Card > > ,
2017-09-13 20:51:35 +00:00
logger : ::slog ::Logger ,
}
2018-01-05 19:04:46 +00:00
impl DrmHandler < Card > for DrmHandlerImpl {
2018-01-07 21:30:38 +00:00
fn ready (
& mut self , _device : & mut DrmDevice < Card > , _crtc : crtc ::Handle , _frame : u32 , _duration : Duration
) {
2018-01-05 19:04:46 +00:00
let mut frame = self . drawer . draw ( ) ;
2017-09-13 20:51:35 +00:00
frame . clear_color ( 0.8 , 0.8 , 0.9 , 1.0 ) ;
// redraw the frame, in a simple but inneficient way
{
2018-01-05 19:04:46 +00:00
let screen_dimensions = self . drawer . get_framebuffer_dimensions ( ) ;
2017-09-22 12:56:59 +00:00
self . window_map
. borrow ( )
. with_windows_from_bottom_to_top ( | toplevel_surface , initial_place | {
if let Some ( wl_surface ) = toplevel_surface . get_surface ( ) {
// this surface is a root of a subsurface tree that needs to be drawn
self . compositor_token
. with_surface_tree_upward (
wl_surface ,
initial_place ,
| _surface , attributes , role , & ( mut x , mut y ) | {
2018-01-05 19:04:46 +00:00
// there is actually something to draw !
if attributes . user_data . texture . is_none ( ) {
let mut remove = false ;
match attributes . user_data . buffer {
Some ( Buffer ::Egl { ref images } ) = > {
match images . format {
Format ::RGB | Format ::RGBA = > {
2018-01-07 21:30:38 +00:00
attributes . user_data . texture =
self . drawer . texture_from_egl ( & images ) ;
}
2018-01-05 19:04:46 +00:00
_ = > {
// we don't handle the more complex formats here.
attributes . user_data . texture = None ;
remove = true ;
2018-01-07 21:30:38 +00:00
}
2018-01-05 19:04:46 +00:00
} ;
2018-01-07 21:30:38 +00:00
}
2018-01-05 19:04:46 +00:00
Some ( Buffer ::Shm { ref data , ref size } ) = > {
2018-01-07 21:30:38 +00:00
attributes . user_data . texture =
Some ( self . drawer . texture_from_mem ( data , * size ) ) ;
}
_ = > { }
2018-01-05 19:04:46 +00:00
}
if remove {
attributes . user_data . buffer = None ;
}
}
if let Some ( ref texture ) = attributes . user_data . texture {
2017-09-22 12:56:59 +00:00
if let Ok ( subdata ) = Role ::< SubsurfaceRole > ::data ( role ) {
x + = subdata . x ;
y + = subdata . y ;
}
2018-01-05 19:04:46 +00:00
info! ( self . logger , " Render window " ) ;
self . drawer . render_texture (
2017-09-22 12:56:59 +00:00
& mut frame ,
2018-01-05 19:04:46 +00:00
texture ,
match * attributes . user_data . buffer . as_ref ( ) . unwrap ( ) {
Buffer ::Egl { ref images } = > images . y_inverted ,
Buffer ::Shm { .. } = > false ,
} ,
match * attributes . user_data . buffer . as_ref ( ) . unwrap ( ) {
Buffer ::Egl { ref images } = > ( images . width , images . height ) ,
Buffer ::Shm { ref size , .. } = > * size ,
} ,
2017-09-22 12:56:59 +00:00
( x , y ) ,
screen_dimensions ,
2018-01-05 19:04:46 +00:00
Blend ::alpha_blending ( ) ,
2017-09-22 12:56:59 +00:00
) ;
TraversalAction ::DoChildren ( ( x , y ) )
} else {
// we are not display, so our children are neither
TraversalAction ::SkipChildren
2017-09-13 20:51:35 +00:00
}
2017-09-22 12:56:59 +00:00
} ,
)
. unwrap ( ) ;
}
} ) ;
2017-09-13 20:51:35 +00:00
}
frame . finish ( ) . unwrap ( ) ;
}
2018-01-07 21:30:38 +00:00
fn error ( & mut self , _device : & mut DrmDevice < Card > , error : DrmError ) {
2017-09-14 21:20:48 +00:00
panic! ( " {:?} " , error ) ;
2017-09-13 20:51:35 +00:00
}
}