@ -122,16 +122,6 @@ struct drm_backend {
int32_t cursor_width ;
int32_t cursor_height ;
/** Callback used to configure the outputs.
*
* This function will be called by the backend when a new DRM
* output needs to be configured .
*/
enum weston_drm_backend_output_mode
( * configure_output ) ( struct weston_compositor * compositor ,
bool use_current_mode ,
const char * name ,
struct weston_drm_backend_output_config * output_config ) ;
bool use_current_mode ;
} ;
@ -161,7 +151,8 @@ struct drm_edid {
} ;
struct drm_output {
struct weston_output base ;
struct weston_output base ;
drmModeConnector * connector ;
uint32_t crtc_id ;
int pipe ;
@ -176,6 +167,7 @@ struct drm_output {
int vblank_pending ;
int page_flip_pending ;
int destroy_pending ;
int disable_pending ;
struct gbm_surface * gbm_surface ;
struct gbm_bo * gbm_cursor_bo [ 2 ] ;
@ -681,7 +673,7 @@ drm_output_repaint(struct weston_output *output_base,
struct drm_mode * mode ;
int ret = 0 ;
if ( output - > destroy_pending )
if ( output - > disable_pending | | output - > d estroy_pending )
return - 1 ;
if ( ! output - > next )
@ -787,7 +779,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
. request . signal = 0 ,
} ;
if ( output - > destroy_pending )
if ( output - > disable_pending | | output - > d estroy_pending )
return ;
if ( ! output - > current ) {
@ -877,7 +869,7 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
}
static void
drm_output_destroy ( struct weston_output * output_ base) ;
drm_output_destroy ( struct weston_output * base ) ;
static void
page_flip_handler ( int fd , unsigned int frame ,
@ -904,6 +896,8 @@ page_flip_handler(int fd, unsigned int frame,
if ( output - > destroy_pending )
drm_output_destroy ( & output - > base ) ;
else if ( output - > disable_pending )
weston_output_disable ( & output - > base ) ;
else if ( ! output - > vblank_pending ) {
ts . tv_sec = sec ;
ts . tv_nsec = usec * 1000 ;
@ -1344,51 +1338,6 @@ drm_assign_planes(struct weston_output *output_base)
static void
drm_output_fini_pixman ( struct drm_output * output ) ;
static void
drm_output_destroy ( struct weston_output * output_base )
{
struct drm_output * output = to_drm_output ( output_base ) ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
drmModeCrtcPtr origcrtc = output - > original_crtc ;
if ( output - > page_flip_pending ) {
output - > destroy_pending = 1 ;
weston_log ( " destroy output while page flip pending \n " ) ;
return ;
}
if ( output - > backlight )
backlight_destroy ( output - > backlight ) ;
drmModeFreeProperty ( output - > dpms_prop ) ;
/* Turn off hardware cursor */
drmModeSetCursor ( b - > drm . fd , output - > crtc_id , 0 , 0 , 0 ) ;
/* Restore original CRTC state */
drmModeSetCrtc ( b - > drm . fd , origcrtc - > crtc_id , origcrtc - > buffer_id ,
origcrtc - > x , origcrtc - > y ,
& output - > connector_id , 1 , & origcrtc - > mode ) ;
drmModeFreeCrtc ( origcrtc ) ;
b - > crtc_allocator & = ~ ( 1 < < output - > crtc_id ) ;
b - > connector_allocator & = ~ ( 1 < < output - > connector_id ) ;
if ( b - > use_pixman ) {
drm_output_fini_pixman ( output ) ;
} else {
gl_renderer - > output_destroy ( output_base ) ;
gbm_surface_destroy ( output - > gbm_surface ) ;
}
weston_plane_release ( & output - > fb_plane ) ;
weston_plane_release ( & output - > cursor_plane ) ;
weston_output_destroy ( & output - > base ) ;
free ( output ) ;
}
/**
* Find the closest - matching mode for a given target
*
@ -2239,7 +2188,7 @@ static struct drm_mode *
drm_output_choose_initial_mode ( struct drm_backend * backend ,
struct drm_output * output ,
enum weston_drm_backend_output_mode mode ,
struct weston_drm_backend_output_config * config ,
const char * modeline ,
const drmModeModeInfo * current_mode )
{
struct drm_mode * preferred = NULL ;
@ -2247,21 +2196,21 @@ drm_output_choose_initial_mode(struct drm_backend *backend,
struct drm_mode * configured = NULL ;
struct drm_mode * best = NULL ;
struct drm_mode * drm_mode ;
drmModeModeInfo modeline ;
drmModeModeInfo drm_ modeline;
int32_t width = 0 ;
int32_t height = 0 ;
if ( mode = = WESTON_DRM_BACKEND_OUTPUT_PREFERRED & & config - > modeline ) {
if ( sscanf ( config - > modeline , " %dx%d " , & width , & height ) ! = 2 ) {
if ( mode = = WESTON_DRM_BACKEND_OUTPUT_PREFERRED & & modeline ) {
if ( sscanf ( modeline , " %dx%d " , & width , & height ) ! = 2 ) {
width = - 1 ;
if ( parse_modeline ( config - > modeline , & modeline ) = = 0 ) {
configured = drm_output_add_mode ( output , & modeline ) ;
if ( parse_modeline ( modeline , & drm_ modeline) = = 0 ) {
configured = drm_output_add_mode ( output , & drm_ modeline) ;
if ( ! configured )
return NULL ;
} else {
weston_log ( " Invalid modeline \" %s \" for output %s \n " ,
config - > modeline , output - > base . name ) ;
modeline , output - > base . name ) ;
}
}
}
@ -2330,109 +2279,104 @@ connector_get_current_mode(drmModeConnector *connector, int drm_fd,
return 0 ;
}
/**
* Create and configure a Weston output structure
*
* Given a DRM connector , create a matching drm_output structure and add it
* to Weston ' s output list .
*
* @ param b Weston backend structure structure
* @ param resources DRM resources for this device
* @ param connector DRM connector to use for this new output
* @ param x Horizontal offset to use into global co - ordinate space
* @ param y Vertical offset to use into global co - ordinate space
* @ param drm_device udev device pointer
* @ returns 0 on success , or - 1 on failure
*/
static int
create_output_for_connector ( struct drm_backend * b ,
drmModeRes * resources ,
drmModeConnector * connector ,
int x , int y , struct udev_device * drm_device )
drm_output_set_mode ( struct weston_output * base ,
enum weston_drm_backend_output_mode mode ,
const char * modeline )
{
struct drm_output * output ;
struct drm_mode * drm_mode , * next , * current ;
struct weston_mode * m ;
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
struct drm_mode * drm_mode , * next , * current ;
drmModeModeInfo crtc_mode ;
int i ;
enum weston_drm_backend_output_mode mode ;
struct weston_drm_backend_output_config config = { { 0 } } ;
i = find_crtc_for_connector ( b , resources , connector ) ;
if ( i < 0 ) {
weston_log ( " No usable crtc/encoder pair for connector. \n " ) ;
return - 1 ;
}
output = zalloc ( sizeof * output ) ;
if ( output = = NULL )
return - 1 ;
output - > base . subpixel = drm_subpixel_to_wayland ( connector - > subpixel ) ;
output - > base . name = make_connector_name ( connector ) ;
output - > base . make = " unknown " ;
output - > base . model = " unknown " ;
output - > base . serial_number = " unknown " ;
wl_list_init ( & output - > base . mode_list ) ;
mode = b - > configure_output ( b - > compositor , b - > use_current_mode ,
output - > base . name , & config ) ;
if ( parse_gbm_format ( config . gbm_format , b - > gbm_format , & output - > gbm_format ) = = - 1 )
output - > gbm_format = b - > gbm_format ;
setup_output_seat_constraint ( b , & output - > base ,
config . seat ? config . seat : " " ) ;
free ( config . seat ) ;
output - > crtc_id = resources - > crtcs [ i ] ;
output - > pipe = i ;
b - > crtc_allocator | = ( 1 < < output - > crtc_id ) ;
output - > connector_id = connector - > connector_id ;
b - > connector_allocator | = ( 1 < < output - > connector_id ) ;
output - > original_crtc = drmModeGetCrtc ( b - > drm . fd , output - > crtc_id ) ;
output - > dpms_prop = drm_get_prop ( b - > drm . fd , connector , " DPMS " ) ;
if ( connector_get_current_mode ( connector , b - > drm . fd , & crtc_mode ) < 0 )
if ( connector_get_current_mode ( output - > connector , b - > drm . fd , & crtc_mode ) < 0 )
goto err_free ;
for ( i = 0 ; i < connector - > count_modes ; i + + ) {
drm_mode = drm_output_add_mode ( output , & connector - > modes [ i ] ) ;
for ( i = 0 ; i < output - > connector - > count_modes ; i + + ) {
drm_mode = drm_output_add_mode ( output , & output - > connector - > modes [ i ] ) ;
if ( ! drm_mode )
goto err_free ;
}
if ( mode = = WESTON_DRM_BACKEND_OUTPUT_OFF ) {
weston_log ( " Disabling output %s \n " , output - > base . name ) ;
drmModeSetCrtc ( b - > drm . fd , output - > crtc_id ,
0 , 0 , 0 , 0 , 0 , NULL ) ;
goto err_free ;
}
current = drm_output_choose_initial_mode ( b , output , mode , & config ,
& crtc_mode ) ;
current = drm_output_choose_initial_mode ( b , output , mode , modeline , & crtc_mode ) ;
if ( ! current )
goto err_free ;
output - > base . current_mode = & current - > base ;
output - > base . current_mode - > flags | = WL_OUTPUT_MODE_CURRENT ;
weston_output_init ( & output - > base , b - > compositor , x , y ,
connector - > mmWidth , connector - > mmHeight ,
config . base . transform , config . base . scale ) ;
/* Set native_ fields, so weston_output_mode_switch_to_native() works */
output - > base . native_mode = output - > base . current_mode ;
output - > base . native_scale = output - > base . current_scale ;
output - > base . mm_width = output - > connector - > mmWidth ;
output - > base . mm_height = output - > connector - > mmHeight ;
return 0 ;
err_free :
drmModeFreeCrtc ( output - > original_crtc ) ;
output - > original_crtc = NULL ;
wl_list_for_each_safe ( drm_mode , next , & output - > base . mode_list ,
base . link ) {
wl_list_remove ( & drm_mode - > base . link ) ;
free ( drm_mode ) ;
}
return - 1 ;
}
static void
drm_output_set_gbm_format ( struct weston_output * base ,
const char * gbm_format )
{
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
if ( parse_gbm_format ( gbm_format , b - > gbm_format , & output - > gbm_format ) = = - 1 )
output - > gbm_format = b - > gbm_format ;
}
static void
drm_output_set_seat ( struct weston_output * base ,
const char * seat )
{
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
setup_output_seat_constraint ( b , & output - > base ,
seat ? seat : " " ) ;
}
static int
drm_output_enable ( struct weston_output * base )
{
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
struct weston_mode * m ;
output - > dpms_prop = drm_get_prop ( b - > drm . fd , output - > connector , " DPMS " ) ;
if ( b - > use_pixman ) {
if ( drm_output_init_pixman ( output , b ) < 0 ) {
weston_log ( " Failed to init output pixman state \n " ) ;
goto err_output ;
goto err_free ;
}
} else if ( drm_output_init_egl ( output , b ) < 0 ) {
weston_log ( " Failed to init output gl state \n " ) ;
goto err_output ;
goto err_free ;
}
output - > backlight = backlight_init ( drm_device ,
connector - > connector_type ) ;
if ( output - > backlight ) {
weston_log ( " Initialized backlight, device %s \n " ,
output - > backlight - > path ) ;
@ -2442,15 +2386,8 @@ create_output_for_connector(struct drm_backend *b,
weston_log ( " Failed to initialize backlight \n " ) ;
}
weston_compositor_add_output ( b - > compositor , & output - > base ) ;
find_and_parse_output_edid ( b , output , connector ) ;
if ( connector - > connector_type = = DRM_MODE_CONNECTOR_LVDS )
output - > base . connection_internal = 1 ;
output - > base . start_repaint_loop = drm_output_start_repaint_loop ;
output - > base . repaint = drm_output_repaint ;
output - > base . destroy = drm_output_destroy ;
output - > base . assign_planes = drm_assign_planes ;
output - > base . set_dpms = drm_set_dpms ;
output - > base . switch_mode = drm_output_switch_mode ;
@ -2458,6 +2395,12 @@ create_output_for_connector(struct drm_backend *b,
output - > base . gamma_size = output - > original_crtc - > gamma_size ;
output - > base . set_gamma = drm_output_set_gamma ;
output - > base . subpixel = drm_subpixel_to_wayland ( output - > connector - > subpixel ) ;
find_and_parse_output_edid ( b , output , output - > connector ) ;
if ( output - > connector - > connector_type = = DRM_MODE_CONNECTOR_LVDS )
output - > base . connection_internal = 1 ;
weston_plane_init ( & output - > cursor_plane , b - > compositor ,
INT32_MIN , INT32_MIN ) ;
weston_plane_init ( & output - > fb_plane , b - > compositor , 0 , 0 ) ;
@ -2475,31 +2418,155 @@ create_output_for_connector(struct drm_backend *b,
" , preferred " : " " ,
m - > flags & WL_OUTPUT_MODE_CURRENT ?
" , current " : " " ,
connector - > count_modes = = 0 ?
output - > connector - > count_modes = = 0 ?
" , built-in " : " " ) ;
/* Set native_ fields, so weston_output_mode_switch_to_native() works */
output - > base . native_mode = output - > base . current_mode ;
output - > base . native_scale = output - > base . current_scale ;
return 0 ;
err_output :
weston_output_destroy ( & output - > base ) ;
err_free :
wl_list_for_each_safe ( drm_mode , next , & output - > base . mode_list ,
base . link ) {
wl_list_remove ( & drm_mode - > base . link ) ;
free ( drm_mode ) ;
drmModeFreeProperty ( output - > dpms_prop ) ;
return - 1 ;
}
static void
drm_output_deinit ( struct weston_output * base )
{
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
if ( b - > use_pixman ) {
drm_output_fini_pixman ( output ) ;
} else {
gl_renderer - > output_destroy ( & output - > base ) ;
gbm_surface_destroy ( output - > gbm_surface ) ;
}
drmModeFreeCrtc ( output - > original_crtc ) ;
weston_plane_release ( & output - > fb_plane ) ;
weston_plane_release ( & output - > cursor_plane ) ;
drmModeFreeProperty ( output - > dpms_prop ) ;
/* Turn off hardware cursor */
drmModeSetCursor ( b - > drm . fd , output - > crtc_id , 0 , 0 , 0 ) ;
}
static void
drm_output_destroy ( struct weston_output * base )
{
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
drmModeCrtcPtr origcrtc = output - > original_crtc ;
if ( output - > page_flip_pending ) {
output - > destroy_pending = 1 ;
weston_log ( " destroy output while page flip pending \n " ) ;
return ;
}
if ( output - > base . enabled )
drm_output_deinit ( & output - > base ) ;
if ( origcrtc ) {
/* Restore original CRTC state */
drmModeSetCrtc ( b - > drm . fd , origcrtc - > crtc_id , origcrtc - > buffer_id ,
origcrtc - > x , origcrtc - > y ,
& output - > connector_id , 1 , & origcrtc - > mode ) ;
drmModeFreeCrtc ( origcrtc ) ;
}
weston_output_destroy ( & output - > base ) ;
drmModeFreeConnector ( output - > connector ) ;
if ( output - > backlight )
backlight_destroy ( output - > backlight ) ;
b - > crtc_allocator & = ~ ( 1 < < output - > crtc_id ) ;
b - > connector_allocator & = ~ ( 1 < < output - > connector_id ) ;
free ( output ) ;
free ( config . modeline ) ;
}
return - 1 ;
static int
drm_output_disable ( struct weston_output * base )
{
struct drm_output * output = to_drm_output ( base ) ;
struct drm_backend * b = to_drm_backend ( base - > compositor ) ;
if ( output - > page_flip_pending ) {
output - > disable_pending = 1 ;
return - 1 ;
}
if ( output - > base . enabled )
drm_output_deinit ( & output - > base ) ;
output - > disable_pending = 0 ;
weston_log ( " Disabling output %s \n " , output - > base . name ) ;
drmModeSetCrtc ( b - > drm . fd , output - > crtc_id ,
0 , 0 , 0 , 0 , 0 , NULL ) ;
return 0 ;
}
/**
* Create a Weston output structure
*
* Given a DRM connector , create a matching drm_output structure and add it
* to Weston ' s output list . It also takes ownership of the connector , which
* is released when output is destroyed .
*
* @ param b Weston backend structure
* @ param resources DRM resources for this device
* @ param connector DRM connector to use for this new output
* @ param drm_device udev device pointer
* @ returns 0 on success , or - 1 on failure
*/
static int
create_output_for_connector ( struct drm_backend * b ,
drmModeRes * resources ,
drmModeConnector * connector ,
struct udev_device * drm_device )
{
struct drm_output * output ;
int i ;
i = find_crtc_for_connector ( b , resources , connector ) ;
if ( i < 0 ) {
weston_log ( " No usable crtc/encoder pair for connector. \n " ) ;
return - 1 ;
}
output = zalloc ( sizeof * output ) ;
if ( output = = NULL )
return - 1 ;
output - > connector = connector ;
output - > crtc_id = resources - > crtcs [ i ] ;
output - > pipe = i ;
output - > connector_id = connector - > connector_id ;
output - > backlight = backlight_init ( drm_device ,
connector - > connector_type ) ;
output - > base . enable = drm_output_enable ;
output - > base . destroy = drm_output_destroy ;
output - > base . disable = drm_output_disable ;
output - > base . name = make_connector_name ( connector ) ;
output - > destroy_pending = 0 ;
output - > disable_pending = 0 ;
output - > original_crtc = NULL ;
b - > crtc_allocator | = ( 1 < < output - > crtc_id ) ;
b - > connector_allocator | = ( 1 < < output - > connector_id ) ;
weston_output_init_pending ( & output - > base , b - > compositor ) ;
weston_compositor_add_pending_output ( & output - > base , b - > compositor ) ;
return 0 ;
}
static void
@ -2578,7 +2645,6 @@ create_outputs(struct drm_backend *b, uint32_t option_connector,
drmModeConnector * connector ;
drmModeRes * resources ;
int i ;
int x = 0 , y = 0 ;
resources = drmModeGetResources ( b - > drm . fd ) ;
if ( ! resources ) {
@ -2610,21 +2676,17 @@ create_outputs(struct drm_backend *b, uint32_t option_connector,
( option_connector = = 0 | |
connector - > connector_id = = option_connector ) ) {
if ( create_output_for_connector ( b , resources ,
connector , x , y ,
drm_device ) < 0 ) {
connector , drm_device ) < 0 ) {
drmModeFreeConnector ( connector ) ;
continue ;
}
x + = container_of ( b - > compositor - > output_list . prev ,
struct weston_output ,
link ) - > width ;
} else {
drmModeFreeConnector ( connector ) ;
}
drmModeFreeConnector ( connector ) ;
}
if ( wl_list_empty ( & b - > compositor - > output_list ) )
if ( wl_list_empty ( & b - > compositor - > output_list ) & &
wl_list_empty ( & b - > compositor - > pending_output_list ) )
weston_log ( " No currently active connector found. \n " ) ;
drmModeFreeResources ( resources ) ;
@ -2638,7 +2700,6 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
drmModeConnector * connector ;
drmModeRes * resources ;
struct drm_output * output , * next ;
int x = 0 , y = 0 ;
uint32_t connected = 0 , disconnects = 0 ;
int i ;
@ -2664,23 +2725,13 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
connected | = ( 1 < < connector_id ) ;
if ( ! ( b - > connector_allocator & ( 1 < < connector_id ) ) ) {
struct weston_output * last =
container_of ( b - > compositor - > output_list . prev ,
struct weston_output , link ) ;
/* XXX: not yet needed, we die with 0 outputs */
if ( ! wl_list_empty ( & b - > compositor - > output_list ) )
x = last - > x + last - > width ;
else
x = 0 ;
y = 0 ;
create_output_for_connector ( b , resources ,
connector , x , y ,
drm_device ) ;
connector , drm_device ) ;
weston_log ( " connector %d connected \n " , connector_id ) ;
} else {
drmModeFreeConnector ( connector ) ;
}
drmModeFreeConnector ( connector ) ;
}
drmModeFreeResources ( resources ) ;
@ -2695,6 +2746,16 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device)
drm_output_destroy ( & output - > base ) ;
}
}
wl_list_for_each_safe ( output , next , & b - > compositor - > pending_output_list ,
base . link ) {
if ( disconnects & ( 1 < < output - > connector_id ) ) {
disconnects & = ~ ( 1 < < output - > connector_id ) ;
weston_log ( " connector %d disconnected \n " ,
output - > connector_id ) ;
drm_output_destroy ( & output - > base ) ;
}
}
}
}
@ -3078,6 +3139,12 @@ renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
switch_to_gl_renderer ( b ) ;
}
static const struct weston_drm_output_api api = {
drm_output_set_mode ,
drm_output_set_gbm_format ,
drm_output_set_seat ,
} ;
static struct drm_backend *
drm_backend_create ( struct weston_compositor * compositor ,
struct weston_drm_backend_config * config )
@ -3087,6 +3154,7 @@ drm_backend_create(struct weston_compositor *compositor,
struct wl_event_loop * loop ;
const char * path ;
const char * seat_id = default_seat ;
int ret ;
weston_log ( " initializing drm backend \n " ) ;
@ -3107,7 +3175,6 @@ drm_backend_create(struct weston_compositor *compositor,
b - > sprites_are_broken = 1 ;
b - > compositor = compositor ;
b - > use_pixman = config - > use_pixman ;
b - > configure_output = config - > configure_output ;
b - > use_current_mode = config - > use_current_mode ;
if ( parse_gbm_format ( config - > gbm_format , GBM_FORMAT_XRGB8888 , & b - > gbm_format ) < 0 )
@ -3230,6 +3297,14 @@ drm_backend_create(struct weston_compositor *compositor,
compositor - > backend = & b - > base ;
ret = weston_plugin_api_register ( compositor , WESTON_DRM_OUTPUT_API_NAME ,
& api , sizeof ( api ) ) ;
if ( ret < 0 ) {
weston_log ( " Failed to register output API. \n " ) ;
goto err_udev_monitor ;
}
return b ;
err_udev_monitor :