@ -326,6 +326,7 @@ struct drm_mode {
enum drm_fb_type {
BUFFER_INVALID = 0 , /**< never used */
BUFFER_CLIENT , /**< directly sourced from client */
BUFFER_DMABUF , /**< imported from linux_dmabuf client */
BUFFER_PIXMAN_DUMB , /**< internal Pixman rendering */
BUFFER_GBM_SURFACE , /**< internal EGL rendering */
BUFFER_CURSOR , /**< internal cursor buffer */
@ -1038,6 +1039,155 @@ drm_fb_ref(struct drm_fb *fb)
return fb ;
}
static void
drm_fb_destroy_dmabuf ( struct drm_fb * fb )
{
/* We deliberately do not close the GEM handles here; GBM manages
* their lifetime through the BO . */
if ( fb - > bo )
gbm_bo_destroy ( fb - > bo ) ;
drm_fb_destroy ( fb ) ;
}
static struct drm_fb *
drm_fb_get_from_dmabuf ( struct linux_dmabuf_buffer * dmabuf ,
struct drm_backend * backend , bool is_opaque )
{
# ifdef HAVE_GBM_FD_IMPORT
struct drm_fb * fb ;
struct gbm_import_fd_data import_legacy = {
. width = dmabuf - > attributes . width ,
. height = dmabuf - > attributes . height ,
. format = dmabuf - > attributes . format ,
. stride = dmabuf - > attributes . stride [ 0 ] ,
. fd = dmabuf - > attributes . fd [ 0 ] ,
} ;
struct gbm_import_fd_modifier_data import_mod = {
. width = dmabuf - > attributes . width ,
. height = dmabuf - > attributes . height ,
. format = dmabuf - > attributes . format ,
. num_fds = dmabuf - > attributes . n_planes ,
. modifier = dmabuf - > attributes . modifier [ 0 ] ,
} ;
int i ;
/* XXX: TODO:
*
* Currently the buffer is rejected if any dmabuf attribute
* flag is set . This keeps us from passing an inverted /
* interlaced / bottom - first buffer ( or any other type that may
* be added in the future ) through to an overlay . Ultimately ,
* these types of buffers should be handled through buffer
* transforms and not as spot - checks requiring specific
* knowledge . */
if ( dmabuf - > attributes . flags )
return NULL ;
fb = zalloc ( sizeof * fb ) ;
if ( fb = = NULL )
return NULL ;
fb - > refcnt = 1 ;
fb - > type = BUFFER_DMABUF ;
static_assert ( ARRAY_LENGTH ( import_mod . fds ) = =
ARRAY_LENGTH ( dmabuf - > attributes . fd ) ,
" GBM and linux_dmabuf FD size must match " ) ;
static_assert ( sizeof ( import_mod . fds ) = = sizeof ( dmabuf - > attributes . fd ) ,
" GBM and linux_dmabuf FD size must match " ) ;
memcpy ( import_mod . fds , dmabuf - > attributes . fd , sizeof ( import_mod . fds ) ) ;
static_assert ( ARRAY_LENGTH ( import_mod . strides ) = =
ARRAY_LENGTH ( dmabuf - > attributes . stride ) ,
" GBM and linux_dmabuf stride size must match " ) ;
static_assert ( sizeof ( import_mod . strides ) = =
sizeof ( dmabuf - > attributes . stride ) ,
" GBM and linux_dmabuf stride size must match " ) ;
memcpy ( import_mod . strides , dmabuf - > attributes . stride ,
sizeof ( import_mod . strides ) ) ;
static_assert ( ARRAY_LENGTH ( import_mod . offsets ) = =
ARRAY_LENGTH ( dmabuf - > attributes . offset ) ,
" GBM and linux_dmabuf offset size must match " ) ;
static_assert ( sizeof ( import_mod . offsets ) = =
sizeof ( dmabuf - > attributes . offset ) ,
" GBM and linux_dmabuf offset size must match " ) ;
memcpy ( import_mod . offsets , dmabuf - > attributes . offset ,
sizeof ( import_mod . offsets ) ) ;
/* The legacy FD-import path does not allow us to supply modifiers,
* multiple planes , or buffer offsets . */
if ( dmabuf - > attributes . modifier [ 0 ] ! = DRM_FORMAT_MOD_INVALID | |
import_mod . num_fds > 1 | |
import_mod . offsets [ 0 ] > 0 ) {
fb - > bo = gbm_bo_import ( backend - > gbm , GBM_BO_IMPORT_FD_MODIFIER ,
& import_mod ,
GBM_BO_USE_SCANOUT ) ;
} else {
fb - > bo = gbm_bo_import ( backend - > gbm , GBM_BO_IMPORT_FD ,
& import_legacy ,
GBM_BO_USE_SCANOUT ) ;
}
if ( ! fb - > bo )
goto err_free ;
fb - > width = dmabuf - > attributes . width ;
fb - > height = dmabuf - > attributes . height ;
fb - > modifier = dmabuf - > attributes . modifier [ 0 ] ;
fb - > size = 0 ;
fb - > fd = backend - > drm . fd ;
static_assert ( ARRAY_LENGTH ( fb - > strides ) = =
ARRAY_LENGTH ( dmabuf - > attributes . stride ) ,
" drm_fb and dmabuf stride size must match " ) ;
static_assert ( sizeof ( fb - > strides ) = = sizeof ( dmabuf - > attributes . stride ) ,
" drm_fb and dmabuf stride size must match " ) ;
memcpy ( fb - > strides , dmabuf - > attributes . stride , sizeof ( fb - > strides ) ) ;
static_assert ( ARRAY_LENGTH ( fb - > offsets ) = =
ARRAY_LENGTH ( dmabuf - > attributes . offset ) ,
" drm_fb and dmabuf offset size must match " ) ;
static_assert ( sizeof ( fb - > offsets ) = = sizeof ( dmabuf - > attributes . offset ) ,
" drm_fb and dmabuf offset size must match " ) ;
memcpy ( fb - > offsets , dmabuf - > attributes . offset , sizeof ( fb - > offsets ) ) ;
fb - > format = pixel_format_get_info ( dmabuf - > attributes . format ) ;
if ( ! fb - > format ) {
weston_log ( " couldn't look up format info for 0x%lx \n " ,
( unsigned long ) dmabuf - > attributes . format ) ;
goto err_free ;
}
if ( is_opaque )
fb - > format = pixel_format_get_opaque_substitute ( fb - > format ) ;
if ( backend - > min_width > fb - > width | |
fb - > width > backend - > max_width | |
backend - > min_height > fb - > height | |
fb - > height > backend - > max_height ) {
weston_log ( " bo geometry out of bounds \n " ) ;
goto err_free ;
}
for ( i = 0 ; i < dmabuf - > attributes . n_planes ; i + + ) {
fb - > handles [ i ] = gbm_bo_get_handle_for_plane ( fb - > bo , i ) . u32 ;
if ( ! fb - > handles [ i ] )
goto err_free ;
}
if ( drm_fb_addfb ( fb ) ! = 0 ) {
weston_log ( " failed to create kms fb: %m \n " ) ;
goto err_free ;
}
return fb ;
err_free :
drm_fb_destroy_dmabuf ( fb ) ;
# endif
return NULL ;
}
static struct drm_fb *
drm_fb_get_from_bo ( struct gbm_bo * bo , struct drm_backend * backend ,
bool is_opaque , enum drm_fb_type type )
@ -1103,7 +1253,7 @@ static void
drm_fb_set_buffer ( struct drm_fb * fb , struct weston_buffer * buffer )
{
assert ( fb - > buffer_ref . buffer = = NULL ) ;
assert ( fb - > type = = BUFFER_CLIENT ) ;
assert ( fb - > type = = BUFFER_CLIENT | | fb - > type = = BUFFER_DMABUF ) ;
weston_buffer_reference ( & fb - > buffer_ref , buffer ) ;
}
@ -1128,6 +1278,9 @@ drm_fb_unref(struct drm_fb *fb)
case BUFFER_GBM_SURFACE :
gbm_surface_release_buffer ( fb - > gbm_surface , fb - > bo ) ;
break ;
case BUFFER_DMABUF :
drm_fb_destroy_dmabuf ( fb ) ;
break ;
default :
assert ( NULL ) ;
break ;
@ -1384,9 +1537,9 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
struct drm_output * output = state - > output ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
struct weston_buffer * buffer = ev - > surface - > buffer_ref . buffer ;
bool is_opaque = drm_view_is_opaque ( ev ) ;
struct linux_dmabuf_buffer * dmabuf ;
struct drm_fb * fb ;
struct gbm_bo * bo ;
/* Don't import buffers which span multiple outputs. */
if ( ev - > output_mask ! = ( 1u < < output - > base . id ) )
@ -1404,59 +1557,29 @@ drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev)
if ( wl_shm_buffer_get ( buffer - > resource ) )
return NULL ;
/* GBM is used for dmabuf import as well as from client wl_buffer. */
if ( ! b - > gbm )
return NULL ;
dmabuf = linux_dmabuf_buffer_get ( buffer - > resource ) ;
if ( dmabuf ) {
# ifdef HAVE_GBM_FD_IMPORT
/* XXX: TODO:
*
* Use AddFB2 directly , do not go via GBM .
* Add support for multiplanar formats .
* Both require refactoring in the DRM - backend to
* support a mix of gbm_bos and drmfbs .
*/
struct gbm_import_fd_data gbm_dmabuf = {
. fd = dmabuf - > attributes . fd [ 0 ] ,
. width = dmabuf - > attributes . width ,
. height = dmabuf - > attributes . height ,
. stride = dmabuf - > attributes . stride [ 0 ] ,
. format = dmabuf - > attributes . format
} ;
/* XXX: TODO:
*
* Currently the buffer is rejected if any dmabuf attribute
* flag is set . This keeps us from passing an inverted /
* interlaced / bottom - first buffer ( or any other type that may
* be added in the future ) through to an overlay . Ultimately ,
* these types of buffers should be handled through buffer
* transforms and not as spot - checks requiring specific
* knowledge . */
if ( dmabuf - > attributes . n_planes ! = 1 | |
dmabuf - > attributes . offset [ 0 ] ! = 0 | |
dmabuf - > attributes . flags )
return NULL ;
bo = gbm_bo_import ( b - > gbm , GBM_BO_IMPORT_FD , & gbm_dmabuf ,
GBM_BO_USE_SCANOUT ) ;
# else
fb = drm_fb_get_from_dmabuf ( dmabuf , b , is_opaque ) ;
if ( ! fb )
return NULL ;
# endif
} else {
struct gbm_bo * bo ;
bo = gbm_bo_import ( b - > gbm , GBM_BO_IMPORT_WL_BUFFER ,
buffer - > resource , GBM_BO_USE_SCANOUT ) ;
}
if ( ! bo )
return NULL ;
fb = drm_fb_get_from_bo ( bo , b , drm_view_ is_opaque( ev ) , BUFFER_CLIENT ) ;
fb = drm_fb_get_from_bo ( bo , b , is_opaque , BUFFER_CLIENT ) ;
if ( ! fb ) {
gbm_bo_destroy ( bo ) ;
return NULL ;
}
}
drm_fb_set_buffer ( fb , buffer ) ;
return fb ;