@ -62,200 +62,155 @@ drm_propose_state_mode_to_string(enum drm_output_propose_state_mode mode)
return drm_output_propose_state_mode_as_string [ mode ] ;
return drm_output_propose_state_mode_as_string [ mode ] ;
}
}
static void
static struct drm_plane_state *
drm_output_add_zpos_plane ( struct drm_plane * plane , struct wl_list * planes )
drm_output_prepare_overlay_view ( struct drm_output_state * output_state ,
struct weston_view * ev ,
enum drm_output_propose_state_mode mode )
{
{
struct drm_backend * b = plane - > backend ;
struct drm_output * output = output_state - > output ;
struct drm_plane_zpos * h_plane ;
struct weston_compositor * ec = output - > base . compositor ;
struct drm_plane_zpos * plane_zpos ;
struct drm_backend * b = to_drm_backend ( ec ) ;
struct drm_plane * p ;
plane_zpos = zalloc ( sizeof ( * plane_zpos ) ) ;
struct drm_plane_state * state = NULL ;
if ( ! plane_zpos )
struct drm_fb * fb ;
return ;
unsigned int i ;
int ret ;
plane_zpos - > plane = plane ;
enum {
NO_PLANES ,
NO_PLANES_WITH_FORMAT ,
NO_PLANES_ACCEPTED ,
PLACED_ON_PLANE ,
} availability = NO_PLANES ;
drm_debug ( b , " \t \t \t \t [plane] plane %d added to candidate list \n " ,
assert ( ! b - > sprites_are_broken ) ;
plane - > plane_id ) ;
assert ( b - > atomic_modeset ) ;
if ( wl_list_empty ( planes ) ) {
fb = drm_fb_get_from_view ( output_state , ev ) ;
wl_list_insert ( planes , & plane_zpos - > link ) ;
if ( ! fb ) {
return ;
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
" couldn't get fb \n " , ev ) ;
return NULL ;
}
}
h_plane = wl_container_of ( planes - > next , h_plane , link ) ;
wl_list_for_each ( p , & b - > plane_list , link ) {
if ( h_plane - > plane - > zpos_max > = plane - > zpos_max ) {
if ( p - > type ! = WDRM_PLANE_TYPE_OVERLAY )
wl_list_insert ( planes - > prev , & plane_zpos - > link ) ;
continue ;
} else {
struct drm_plane_zpos * p_zpos = NULL ;
if ( wl_list_length ( planes ) = = 1 ) {
if ( ! drm_plane_is_available ( p , output ) )
wl_list_insert ( planes - > prev , & plane_zpos - > link ) ;
continue ;
return ;
}
wl_list_for_each ( p_zpos , planes , link ) {
state = drm_output_state_get_plane ( output_state , p ) ;
if ( p_zpo s- > plane - > zpos_max >
if ( state - > fb ) {
plane_zpos - > plane - > zpos_max )
state = NULL ;
break ;
continue ;
}
}
wl_list_insert ( p_zpos - > link . prev , & plane_zpos - > link ) ;
if ( availability = = NO_PLANES )
}
availability = NO_PLANES_WITH_FORMAT ;
}
static void
drm_output_destroy_zpos_plane ( struct drm_plane_zpos * plane_zpos )
{
wl_list_remove ( & plane_zpos - > link ) ;
free ( plane_zpos ) ;
}
static bool
drm_output_check_plane_has_view_assigned ( struct drm_plane * plane ,
struct drm_output_state * output_state )
{
struct drm_plane_state * ps ;
wl_list_for_each ( ps , & output_state - > plane_list , link ) {
if ( ps - > plane = = plane & & ps - > fb )
return true ;
}
return false ;
}
static bool
/* Check whether the format is supported */
drm_output_plane_has_valid_format ( struct drm_plane * plane ,
for ( i = 0 ; i < p - > count_formats ; i + + ) {
struct drm_output_state * state ,
unsigned int j ;
struct drm_fb * fb )
{
struct drm_backend * b = plane - > backend ;
unsigned int i ;
if ( ! fb )
if ( p - > formats [ i ] . format ! = fb - > format - > format )
return fals e;
continue ;
/* Check whether the format is supported */
if ( fb - > modifier = = DRM_FORMAT_MOD_INVALID )
for ( i = 0 ; i < plane - > count_formats ; i + + ) {
break ;
unsigned int j ;
if ( plane - > formats [ i ] . format ! = fb - > format - > format )
for ( j = 0 ; j < p - > formats [ i ] . count_modifiers ; j + + ) {
if ( p - > formats [ i ] . modifiers [ j ] = = fb - > modifier )
break ;
}
if ( j ! = p - > formats [ i ] . count_modifiers )
break ;
}
if ( i = = p - > count_formats ) {
drm_plane_state_put_back ( state ) ;
state = NULL ;
continue ;
continue ;
if ( fb - > modifier = = DRM_FORMAT_MOD_INVALID )
return true ;
for ( j = 0 ; j < plane - > formats [ i ] . count_modifiers ; j + + ) {
if ( plane - > formats [ i ] . modifiers [ j ] = = fb - > modifier )
return true ;
}
}
}
drm_debug ( b , " \t \t \t \t [%s] not placing view on %s: "
if ( availability = = NO_PLANES_WITH_FORMAT )
" no free %s planes matching format %s (0x%lx) "
availability = NO_PLANES_ACCEPTED ;
" modifier 0x%llx \n " ,
drm_output_get_plane_type_name ( plane ) ,
drm_output_get_plane_type_name ( plane ) ,
drm_output_get_plane_type_name ( plane ) ,
fb - > format - > drm_format_name ,
( unsigned long ) fb - > format ,
( unsigned long long ) fb - > modifier ) ;
return false ;
}
static bool
drm_output_plane_cursor_has_valid_format ( struct weston_view * ev )
{
struct wl_shm_buffer * shmbuf =
wl_shm_buffer_get ( ev - > surface - > buffer_ref . buffer - > resource ) ;
if ( shmbuf & & wl_shm_buffer_get_format ( shmbuf ) = = WL_SHM_FORMAT_ARGB8888 )
state - > ev = ev ;
return true ;
state - > output = output ;
if ( ! drm_plane_state_coords_for_view ( state , ev ) ) {
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
" unsuitable transform \n " , ev ) ;
drm_plane_state_put_back ( state ) ;
state = NULL ;
continue ;
}
return false ;
/* If the surface buffer has an in-fence fd, but the plane
}
* doesn ' t support fences , we can ' t place the buffer on this
* plane . */
if ( ev - > surface - > acquire_fence_fd > = 0 & &
p - > props [ WDRM_PLANE_IN_FENCE_FD ] . prop_id = = 0 ) {
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
" no in-fence support \n " , ev ) ;
drm_plane_state_put_back ( state ) ;
state = NULL ;
continue ;
}
static struct drm_plane_state *
/* We hold one reference for the lifetime of this function;
drm_output_prepare_overlay_view ( struct drm_plane * plane ,
* from calling drm_fb_get_from_view , to the out label where
struct drm_output_state * output_state ,
* we unconditionally drop the reference . So , we take another
struct weston_view * ev ,
* reference here to live within the state . */
enum drm_output_propose_state_mode mode ,
state - > fb = drm_fb_ref ( fb ) ;
struct drm_fb * fb , uint64_t zpos )
{
struct drm_output * output = output_state - > output ;
struct weston_compositor * ec = output - > base . compositor ;
struct drm_backend * b = to_drm_backend ( ec ) ;
struct drm_plane_state * state = NULL ;
int ret ;
assert ( ! b - > sprites_are_broken ) ;
state - > in_fence_fd = ev - > surface - > acquire_fence_fd ;
assert ( b - > atomic_modeset ) ;
if ( ! fb ) {
/* In planes-only mode, we don't have an incremental state to
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
* test against , so we just hope it ' ll work . */
" couldn't get fb \n " , ev ) ;
if ( mode = = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ) {
return NULL ;
drm_debug ( b , " \t \t \t \t [overlay] provisionally placing "
}
" view %p on overlay %lu in planes-only mode \n " ,
ev , ( unsigned long ) p - > plane_id ) ;
availability = PLACED_ON_PLANE ;
goto out ;
}
state = drm_output_state_get_plane ( output_state , plane ) ;
ret = drm_pending_state_test ( output_state - > pending_state ) ;
/* we can't have a 'pending' framebuffer as never set one before reaching here */
if ( ret = = 0 ) {
assert ( ! state - > fb ) ;
drm_debug ( b , " \t \t \t \t [overlay] provisionally placing "
" view %p on overlay %d in mixed mode \n " ,
ev , p - > plane_id ) ;
availability = PLACED_ON_PLANE ;
goto out ;
}
state - > ev = ev ;
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay %lu "
state - > output = output ;
" in mixed mode: kernel test failed \n " ,
ev , ( unsigned long ) p - > plane_id ) ;
if ( ! drm_plane_state_coords_for_view ( state , ev , zpos ) ) {
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
" unsuitable transform \n " , ev ) ;
drm_plane_state_put_back ( state ) ;
drm_plane_state_put_back ( state ) ;
state = NULL ;
state = NULL ;
goto out ;
}
}
/* If the surface buffer has an in-fence fd, but the plane
switch ( availability ) {
* doesn ' t support fences , we can ' t place the buffer on this
case NO_PLANES :
* plane . */
if ( ev - > surface - > acquire_fence_fd > = 0 & &
plane - > props [ WDRM_PLANE_IN_FENCE_FD ] . prop_id = = 0 ) {
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
" no in-fence support \n " , ev ) ;
" no free overlay planes \n " , ev ) ;
drm_plane_state_put_back ( state ) ;
break ;
state = NULL ;
case NO_PLANES_WITH_FORMAT :
goto out ;
drm_debug ( b , " \t \t \t \t [overlay] not placing view %p on overlay: "
}
" no free overlay planes matching format %s (0x%lx) "
" modifier 0x%llx \n " ,
/* We hold one reference for the lifetime of this function; from
ev , fb - > format - > drm_format_name ,
* calling drm_fb_get_from_view ( ) in drm_output_prepare_plane_view ( ) ,
( unsigned long ) fb - > format ,
* so , we take another reference here to live within the state . */
( unsigned long long ) fb - > modifier ) ;
state - > fb = drm_fb_ref ( fb ) ;
break ;
case NO_PLANES_ACCEPTED :
state - > in_fence_fd = ev - > surface - > acquire_fence_fd ;
case PLACED_ON_PLANE :
break ;
/* In planes-only mode, we don't have an incremental state to
* test against , so we just hope it ' ll work . */
if ( mode = = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ) {
drm_debug ( b , " \t \t \t [overlay] provisionally placing "
" view %p on overlay %lu in planes-only mode \n " ,
ev , ( unsigned long ) plane - > plane_id ) ;
goto out ;
}
ret = drm_pending_state_test ( output_state - > pending_state ) ;
if ( ret = = 0 ) {
drm_debug ( b , " \t \t \t [overlay] provisionally placing "
" view %p on overlay %d in mixed mode \n " ,
ev , plane - > plane_id ) ;
goto out ;
}
}
drm_debug ( b , " \t \t \t [overlay] not placing view %p on overlay %lu "
" in mixed mode: kernel test failed \n " ,
ev , ( unsigned long ) plane - > plane_id ) ;
drm_plane_state_put_back ( state ) ;
state = NULL ;
out :
out :
drm_fb_unref ( fb ) ;
return state ;
return state ;
}
}
@ -299,14 +254,14 @@ cursor_bo_update(struct drm_plane_state *plane_state, struct weston_view *ev)
static struct drm_plane_state *
static struct drm_plane_state *
drm_output_prepare_cursor_view ( struct drm_output_state * output_state ,
drm_output_prepare_cursor_view ( struct drm_output_state * output_state ,
struct weston_view * ev , uint64_t zpos )
struct weston_view * ev )
{
{
struct drm_output * output = output_state - > output ;
struct drm_output * output = output_state - > output ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
struct drm_plane * plane = output - > cursor_plane ;
struct drm_plane * plane = output - > cursor_plane ;
struct drm_plane_state * plane_state ;
struct drm_plane_state * plane_state ;
struct wl_shm_buffer * shmbuf ;
bool needs_update = false ;
bool needs_update = false ;
const char * p_name = drm_output_get_plane_type_name ( plane ) ;
assert ( ! b - > cursors_are_broken ) ;
assert ( ! b - > cursors_are_broken ) ;
@ -323,6 +278,24 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
if ( b - > gbm = = NULL )
if ( b - > gbm = = NULL )
return NULL ;
return NULL ;
if ( ev - > surface - > buffer_ref . buffer = = NULL ) {
drm_debug ( b , " \t \t \t \t [cursor] not assigning view %p to cursor plane "
" (no buffer available) \n " , ev ) ;
return NULL ;
}
shmbuf = wl_shm_buffer_get ( ev - > surface - > buffer_ref . buffer - > resource ) ;
if ( ! shmbuf ) {
drm_debug ( b , " \t \t \t \t [cursor] not assigning view %p to cursor plane "
" (buffer isn't SHM) \n " , ev ) ;
return NULL ;
}
if ( wl_shm_buffer_get_format ( shmbuf ) ! = WL_SHM_FORMAT_ARGB8888 ) {
drm_debug ( b , " \t \t \t \t [cursor] not assigning view %p to cursor plane "
" (format 0x%lx unsuitable) \n " ,
ev , ( unsigned long ) wl_shm_buffer_get_format ( shmbuf ) ) ;
return NULL ;
}
plane_state =
plane_state =
drm_output_state_get_plane ( output_state , output - > cursor_plane ) ;
drm_output_state_get_plane ( output_state , output - > cursor_plane ) ;
@ -332,20 +305,16 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
/* We can't scale with the legacy API, and we don't try to account for
/* We can't scale with the legacy API, and we don't try to account for
* simple cropping / translation in cursor_bo_update . */
* simple cropping / translation in cursor_bo_update . */
plane_state - > output = output ;
plane_state - > output = output ;
if ( ! drm_plane_state_coords_for_view ( plane_state , ev , zpos ) ) {
if ( ! drm_plane_state_coords_for_view ( plane_state , ev ) )
drm_debug ( b , " \t \t \t \t [%s] not placing view %p on %s: "
" unsuitable transform \n " , p_name , ev , p_name ) ;
goto err ;
goto err ;
}
if ( plane_state - > src_x ! = 0 | | plane_state - > src_y ! = 0 | |
if ( plane_state - > src_x ! = 0 | | plane_state - > src_y ! = 0 | |
plane_state - > src_w > ( unsigned ) b - > cursor_width < < 16 | |
plane_state - > src_w > ( unsigned ) b - > cursor_width < < 16 | |
plane_state - > src_h > ( unsigned ) b - > cursor_height < < 16 | |
plane_state - > src_h > ( unsigned ) b - > cursor_height < < 16 | |
plane_state - > src_w ! = plane_state - > dest_w < < 16 | |
plane_state - > src_w ! = plane_state - > dest_w < < 16 | |
plane_state - > src_h ! = plane_state - > dest_h < < 16 ) {
plane_state - > src_h ! = plane_state - > dest_h < < 16 ) {
drm_debug ( b , " \t \t \t \t [%s] not assigning view %p to %s plane "
drm_debug ( b , " \t \t \t \t [cursor] not assigning view %p to cursor plane "
" (positioning requires cropping or scaling) \n " ,
" (positioning requires cropping or scaling) \n " , ev ) ;
p_name , ev , p_name ) ;
goto err ;
goto err ;
}
}
@ -371,7 +340,7 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
drm_fb_ref ( output - > gbm_cursor_fb [ output - > current_cursor ] ) ;
drm_fb_ref ( output - > gbm_cursor_fb [ output - > current_cursor ] ) ;
if ( needs_update ) {
if ( needs_update ) {
drm_debug ( b , " \t \t \t \t [%s ] copying new content to cursor BO \n " , p_name ) ;
drm_debug ( b , " \t \t \t \t [cursor ] copying new content to cursor BO \n " ) ;
cursor_bo_update ( plane_state , ev ) ;
cursor_bo_update ( plane_state , ev ) ;
}
}
@ -384,8 +353,8 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
plane_state - > dest_w = b - > cursor_width ;
plane_state - > dest_w = b - > cursor_width ;
plane_state - > dest_h = b - > cursor_height ;
plane_state - > dest_h = b - > cursor_height ;
drm_debug ( b , " \t \t \t \t [%s ] provisionally assigned view %p to cursor \n " ,
drm_debug ( b , " \t \t \t \t [cursor ] provisionally assigned view %p to cursor \n " ,
p_name , ev ) ;
ev ) ;
return plane_state ;
return plane_state ;
@ -396,7 +365,7 @@ err:
# else
# else
static struct drm_plane_state *
static struct drm_plane_state *
drm_output_prepare_cursor_view ( struct drm_output_state * output_state ,
drm_output_prepare_cursor_view ( struct drm_output_state * output_state ,
struct weston_view * ev , uint64_t zpos )
struct weston_view * ev )
{
{
return NULL ;
return NULL ;
}
}
@ -405,14 +374,14 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state,
static struct drm_plane_state *
static struct drm_plane_state *
drm_output_prepare_scanout_view ( struct drm_output_state * output_state ,
drm_output_prepare_scanout_view ( struct drm_output_state * output_state ,
struct weston_view * ev ,
struct weston_view * ev ,
enum drm_output_propose_state_mode mode ,
enum drm_output_propose_state_mode mode )
struct drm_fb * fb , uint64_t zpos )
{
{
struct drm_output * output = output_state - > output ;
struct drm_output * output = output_state - > output ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
struct drm_plane * scanout_plane = output - > scanout_plane ;
struct drm_plane * scanout_plane = output - > scanout_plane ;
struct drm_plane_state * state ;
struct drm_plane_state * state ;
const char * p_name = drm_output_get_plane_type_name ( scanout_plane ) ;
struct drm_fb * fb ;
pixman_box32_t * extents ;
assert ( ! b - > sprites_are_broken ) ;
assert ( ! b - > sprites_are_broken ) ;
assert ( b - > atomic_modeset ) ;
assert ( b - > atomic_modeset ) ;
@ -420,25 +389,23 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state,
/* Check the view spans exactly the output size, calculated in the
/* Check the view spans exactly the output size, calculated in the
* logical co - ordinate space . */
* logical co - ordinate space . */
if ( ! weston_view_matches_output_entirely ( ev , & output - > base ) ) {
extents = pixman_region32_extents ( & ev - > transform . boundingbox ) ;
drm_debug ( b , " \t \t \t \t [%s] not placing view %p on %s: "
if ( extents - > x1 ! = output - > base . x | |
" view does not match output entirely \n " ,
extents - > y1 ! = output - > base . y | |
p_name , ev , p_name ) ;
extents - > x2 ! = output - > base . x + output - > base . width | |
extents - > y2 ! = output - > base . y + output - > base . height )
return NULL ;
return NULL ;
}
/* If the surface buffer has an in-fence fd, but the plane doesn't
/* If the surface buffer has an in-fence fd, but the plane doesn't
* support fences , we can ' t place the buffer on this plane . */
* support fences , we can ' t place the buffer on this plane . */
if ( ev - > surface - > acquire_fence_fd > = 0 & &
if ( ev - > surface - > acquire_fence_fd > = 0 & &
scanout_plane - > props [ WDRM_PLANE_IN_FENCE_FD ] . prop_id = = 0 ) {
scanout_plane - > props [ WDRM_PLANE_IN_FENCE_FD ] . prop_id = = 0 )
drm_debug ( b , " \t \t \t \t [%s] not placing view %p on %s: "
" no in-fence support \n " , p_name , ev , p_name ) ;
return NULL ;
return NULL ;
}
fb = drm_fb_get_from_view ( output_state , ev ) ;
if ( ! fb ) {
if ( ! fb ) {
drm_debug ( b , " \t \t \t \t [% s] not placing view %p on % s: "
drm_debug ( b , " \t \t \t \t [scanout ] not placing view %p on scanout : "
" couldn't get fb \n " , p_name , ev , p_name ) ;
" couldn't get fb \n " , ev ) ;
return NULL ;
return NULL ;
}
}
@ -450,24 +417,16 @@ drm_output_prepare_scanout_view(struct drm_output_state *output_state,
* and in the latter case , the view must have been marked as occluded ,
* and in the latter case , the view must have been marked as occluded ,
* meaning we should never have ended up here . */
* meaning we should never have ended up here . */
assert ( ! state - > fb ) ;
assert ( ! state - > fb ) ;
state - > fb = fb ;
/* take another reference here to live within the state */
state - > fb = drm_fb_ref ( fb ) ;
state - > ev = ev ;
state - > ev = ev ;
state - > output = output ;
state - > output = output ;
if ( ! drm_plane_state_coords_for_view ( state , ev , zpos ) ) {
if ( ! drm_plane_state_coords_for_view ( state , ev ) )
drm_debug ( b , " \t \t \t \t [%s] not placing view %p on %s: "
" unsuitable transform \n " , p_name , ev , p_name ) ;
goto err ;
goto err ;
}
if ( state - > dest_x ! = 0 | | state - > dest_y ! = 0 | |
if ( state - > dest_x ! = 0 | | state - > dest_y ! = 0 | |
state - > dest_w ! = ( unsigned ) output - > base . current_mode - > width | |
state - > dest_w ! = ( unsigned ) output - > base . current_mode - > width | |
state - > dest_h ! = ( unsigned ) output - > base . current_mode - > height ) {
state - > dest_h ! = ( unsigned ) output - > base . current_mode - > height )
drm_debug ( b , " \t \t \t \t [%s] not placing view %p on %s: "
" invalid plane state \n " , p_name , ev , p_name ) ;
goto err ;
goto err ;
}
state - > in_fence_fd = ev - > surface - > acquire_fence_fd ;
state - > in_fence_fd = ev - > surface - > acquire_fence_fd ;
@ -480,252 +439,6 @@ err:
return NULL ;
return NULL ;
}
}
static bool
drm_output_plane_view_has_valid_format ( struct drm_plane * plane ,
struct drm_output_state * state ,
struct weston_view * ev ,
struct drm_fb * fb )
{
/* depending on the type of the plane we have different requirements */
switch ( plane - > type ) {
case WDRM_PLANE_TYPE_CURSOR :
return drm_output_plane_cursor_has_valid_format ( ev ) ;
case WDRM_PLANE_TYPE_OVERLAY :
return drm_output_plane_has_valid_format ( plane , state , fb ) ;
case WDRM_PLANE_TYPE_PRIMARY :
return drm_output_plane_has_valid_format ( plane , state , fb ) ;
default :
assert ( 0 ) ;
return false ;
}
return false ;
}
static struct drm_plane_state *
drm_output_try_view_on_plane ( struct drm_plane * plane ,
struct drm_output_state * state ,
struct weston_view * ev ,
enum drm_output_propose_state_mode mode ,
struct drm_fb * fb , uint64_t zpos )
{
struct drm_backend * b = state - > pending_state - > backend ;
struct weston_output * wet_output = & state - > output - > base ;
bool view_matches_entire_output , scanout_has_view_assigned ;
struct drm_plane * scanout_plane = state - > output - > scanout_plane ;
struct drm_plane_state * ps = NULL ;
const char * p_name = drm_output_get_plane_type_name ( plane ) ;
enum {
NO_PLANES , /* generic err-handle */
NO_PLANES_ACCEPTED ,
PLACED_ON_PLANE ,
} availability = NO_PLANES ;
/* sanity checks in case we over/underflow zpos or pass incorrect
* values */
assert ( zpos < = plane - > zpos_max | |
zpos ! = DRM_PLANE_ZPOS_INVALID_PLANE ) ;
switch ( plane - > type ) {
case WDRM_PLANE_TYPE_CURSOR :
if ( b - > cursors_are_broken ) {
availability = NO_PLANES_ACCEPTED ;
goto out ;
}
ps = drm_output_prepare_cursor_view ( state , ev , zpos ) ;
if ( ps )
availability = PLACED_ON_PLANE ;
break ;
case WDRM_PLANE_TYPE_OVERLAY :
/* do not attempt to place it in the overlay if we don't have
* anything in the scanout / primary and the view doesn ' t cover
* the entire output */
view_matches_entire_output =
weston_view_matches_output_entirely ( ev , wet_output ) ;
scanout_has_view_assigned =
drm_output_check_plane_has_view_assigned ( scanout_plane ,
state ) ;
if ( view_matches_entire_output & & ! scanout_has_view_assigned ) {
availability = NO_PLANES_ACCEPTED ;
goto out ;
}
ps = drm_output_prepare_overlay_view ( plane , state , ev , mode ,
fb , zpos ) ;
if ( ps )
availability = PLACED_ON_PLANE ;
break ;
case WDRM_PLANE_TYPE_PRIMARY :
if ( mode ! = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ) {
availability = NO_PLANES_ACCEPTED ;
goto out ;
}
ps = drm_output_prepare_scanout_view ( state , ev , mode ,
fb , zpos ) ;
if ( ps )
availability = PLACED_ON_PLANE ;
break ;
default :
assert ( 0 ) ;
break ;
}
out :
switch ( availability ) {
case NO_PLANES :
/* set initial to this catch-all case, such that
* prepare_cursor / overlay / scanout ( ) should have / contain the
* reason for failling */
break ;
case NO_PLANES_ACCEPTED :
drm_debug ( b , " \t \t \t \t [plane] plane %d refusing to "
" place view %p in %s \n " ,
plane - > plane_id , ev , p_name ) ;
break ;
case PLACED_ON_PLANE :
break ;
}
return ps ;
}
static int
drm_output_check_zpos_plane_states ( struct drm_output_state * state )
{
struct drm_backend * b = state - > pending_state - > backend ;
struct drm_plane_state * ps ;
int ret = 0 ;
wl_list_for_each ( ps , & state - > plane_list , link ) {
struct wl_list * next_node = ps - > link . next ;
bool found_dup = false ;
/* find another plane with the same zpos value */
if ( next_node = = & state - > plane_list )
break ;
while ( next_node & & next_node ! = & state - > plane_list ) {
struct drm_plane_state * ps_next ;
ps_next = container_of ( next_node ,
struct drm_plane_state ,
link ) ;
if ( ps - > zpos = = ps_next - > zpos ) {
found_dup = true ;
break ;
}
next_node = next_node - > next ;
}
if ( found_dup ) {
ret = 1 ;
drm_debug ( b , " \t \t \t [plane] found duplicate zpos values \n " ) ;
break ;
}
}
return ret ;
}
static struct drm_plane_state *
drm_output_prepare_plane_view ( struct drm_output_state * state ,
struct weston_view * ev ,
enum drm_output_propose_state_mode mode ,
uint64_t current_lowest_zpos )
{
struct drm_output * output = state - > output ;
struct drm_backend * b = to_drm_backend ( output - > base . compositor ) ;
struct drm_plane_state * ps = NULL ;
struct drm_plane * plane ;
struct drm_plane_zpos * p_zpos , * p_zpos_next ;
struct wl_list zpos_candidate_list ;
struct drm_fb * fb ;
wl_list_init ( & zpos_candidate_list ) ;
/* check view for valid buffer, doesn't make sense to even try */
if ( ! weston_view_has_valid_buffer ( ev ) )
return ps ;
fb = drm_fb_get_from_view ( state , ev ) ;
/* assemble a list with possible candidates */
wl_list_for_each ( plane , & b - > plane_list , link ) {
if ( ! drm_plane_is_available ( plane , output ) )
continue ;
if ( drm_output_check_plane_has_view_assigned ( plane , state ) ) {
drm_debug ( b , " \t \t \t \t [plane] not adding plane %d to "
" candidate list: view already assigned "
" to a plane \n " , plane - > plane_id ) ;
continue ;
}
if ( plane - > zpos_min > = current_lowest_zpos ) {
drm_debug ( b , " \t \t \t \t [plane] not adding plane %d to "
" candidate list: minium zpos (% " PRIu64 " ) "
" plane's above current lowest zpos "
" (% " PRIu64 " ) \n " , plane - > plane_id ,
plane - > zpos_min , current_lowest_zpos ) ;
continue ;
}
if ( ! drm_output_plane_view_has_valid_format ( plane , state , ev , fb ) ) {
drm_debug ( b , " \t \t \t \t [plane] not adding plane %d to "
" candidate list: invalid pixel format \n " ,
plane - > plane_id ) ;
continue ;
}
drm_output_add_zpos_plane ( plane , & zpos_candidate_list ) ;
}
/* go over the potential candidate list and try to find a possible
* plane suitable for \ c ev ; start with the highest zpos value of a
* plane to maximize our chances , but do note we pass the zpos value
* based on current tracked value by \ c current_lowest_zpos_in_use */
while ( ! wl_list_empty ( & zpos_candidate_list ) ) {
struct drm_plane_zpos * head_p_zpos =
wl_container_of ( zpos_candidate_list . next ,
head_p_zpos , link ) ;
struct drm_plane * plane = head_p_zpos - > plane ;
const char * p_name = drm_output_get_plane_type_name ( plane ) ;
uint64_t zpos ;
if ( current_lowest_zpos = = DRM_PLANE_ZPOS_INVALID_PLANE )
zpos = plane - > zpos_max ;
else
zpos = MIN ( current_lowest_zpos - 1 , plane - > zpos_max ) ;
drm_debug ( b , " \t \t \t \t [plane] plane %d picked "
" from candidate list, type: %s \n " ,
plane - > plane_id , p_name ) ;
ps = drm_output_try_view_on_plane ( plane , state , ev ,
mode , fb , zpos ) ;
drm_output_destroy_zpos_plane ( head_p_zpos ) ;
if ( ps ) {
drm_debug ( b , " \t \t \t \t [view] view %p has been placed to "
" %s plane with computed zpos % " PRIu64 " \n " ,
ev , p_name , zpos ) ;
break ;
}
}
wl_list_for_each_safe ( p_zpos , p_zpos_next , & zpos_candidate_list , link )
drm_output_destroy_zpos_plane ( p_zpos ) ;
drm_fb_unref ( fb ) ;
return ps ;
}
static struct drm_output_state *
static struct drm_output_state *
drm_output_propose_state ( struct weston_output * output_base ,
drm_output_propose_state ( struct weston_output * output_base ,
struct drm_pending_state * pending_state ,
struct drm_pending_state * pending_state ,
@ -736,13 +449,10 @@ drm_output_propose_state(struct weston_output *output_base,
struct drm_output_state * state ;
struct drm_output_state * state ;
struct drm_plane_state * scanout_state = NULL ;
struct drm_plane_state * scanout_state = NULL ;
struct weston_view * ev ;
struct weston_view * ev ;
pixman_region32_t surface_overlap , renderer_region , occluded_region ;
pixman_region32_t surface_overlap , renderer_region , planes_region ;
bool planes_ok = ( mode ! = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY ) ;
pixman_region32_t occluded_region ;
bool renderer_ok = ( mode ! = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ) ;
bool renderer_ok = ( mode ! = DRM_OUTPUT_PROPOSE_STATE_PLANES_ONLY ) ;
int ret ;
int ret ;
uint64_t current_lowest_zpos = DRM_PLANE_ZPOS_INVALID_PLANE ;
assert ( ! output - > state_last ) ;
assert ( ! output - > state_last ) ;
state = drm_output_state_duplicate ( output - > state_cur ,
state = drm_output_state_duplicate ( output - > state_cur ,
@ -792,19 +502,20 @@ drm_output_propose_state(struct weston_output *output_base,
( unsigned long ) output - > base . id ) ;
( unsigned long ) output - > base . id ) ;
}
}
/* - renderer_region contains the total region which which will be
/*
* covered by the renderer
* Find a surface for each sprite in the output using some heuristics :
* - planes_region contains the total region which has been covered by
* 1 ) size
* hardware planes
* 2 ) frequency of update
* - occluded_region contains the total region which which will be
* 3 ) opacity ( though some hw might support alpha blending )
* covered by the renderer and hardware planes , where the view ' s
* 4 ) clipping ( this can be fixed with color keys )
* visible - and - opaque region is added in both cases ( the view ' s
*
* opaque region accumulates there for each view ) ; it is being used
* The idea is to save on blitting since this should save power .
* to skip the view , if it is completely occluded ; includes the
* If we can get a large video surface on the sprite for example ,
* situation where occluded_region covers entire output ' s region .
* the main display surface may not need to update at all , and
* the client buffer can be used directly for the sprite surface
* as we do for flipping full screen surfaces .
*/
*/
pixman_region32_init ( & renderer_region ) ;
pixman_region32_init ( & renderer_region ) ;
pixman_region32_init ( & planes_region ) ;
pixman_region32_init ( & occluded_region ) ;
pixman_region32_init ( & occluded_region ) ;
wl_list_for_each ( ev , & output_base - > compositor - > view_list , link ) {
wl_list_for_each ( ev , & output_base - > compositor - > view_list , link ) {
@ -812,6 +523,7 @@ drm_output_propose_state(struct weston_output *output_base,
bool force_renderer = false ;
bool force_renderer = false ;
pixman_region32_t clipped_view ;
pixman_region32_t clipped_view ;
bool totally_occluded = false ;
bool totally_occluded = false ;
bool overlay_occluded = false ;
drm_debug ( b , " \t \t \t [view] evaluating view %p for "
drm_debug ( b , " \t \t \t [view] evaluating view %p for "
" output %s (%lu) \n " ,
" output %s (%lu) \n " ,
@ -834,7 +546,7 @@ drm_output_propose_state(struct weston_output *output_base,
force_renderer = true ;
force_renderer = true ;
}
}
if ( ! weston_view_has_valid_buffer ( ev ) ) {
if ( ! ev - > surface - > buffer_ref . buffer ) {
drm_debug ( b , " \t \t \t \t [view] not assigning view %p to plane "
drm_debug ( b , " \t \t \t \t [view] not assigning view %p to plane "
" (no buffer available) \n " , ev ) ;
" (no buffer available) \n " , ev ) ;
force_renderer = true ;
force_renderer = true ;
@ -849,9 +561,6 @@ drm_output_propose_state(struct weston_output *output_base,
pixman_region32_init ( & surface_overlap ) ;
pixman_region32_init ( & surface_overlap ) ;
pixman_region32_subtract ( & surface_overlap , & clipped_view ,
pixman_region32_subtract ( & surface_overlap , & clipped_view ,
& occluded_region ) ;
& occluded_region ) ;
/* if the view is completely occluded then ignore that
* view ; includes the case where occluded_region covers
* the entire output */
totally_occluded = ! pixman_region32_not_empty ( & surface_overlap ) ;
totally_occluded = ! pixman_region32_not_empty ( & surface_overlap ) ;
if ( totally_occluded ) {
if ( totally_occluded ) {
drm_debug ( b , " \t \t \t \t [view] ignoring view %p "
drm_debug ( b , " \t \t \t \t [view] ignoring view %p "
@ -871,7 +580,6 @@ drm_output_propose_state(struct weston_output *output_base,
" (occluded by renderer views) \n " , ev ) ;
" (occluded by renderer views) \n " , ev ) ;
force_renderer = true ;
force_renderer = true ;
}
}
pixman_region32_fini ( & surface_overlap ) ;
/* In case of enforced mode of content-protection do not
/* In case of enforced mode of content-protection do not
* assign planes for a protected surface on an unsecured output .
* assign planes for a protected surface on an unsecured output .
@ -883,18 +591,51 @@ drm_output_propose_state(struct weston_output *output_base,
force_renderer = true ;
force_renderer = true ;
}
}
if ( ! force_renderer ) {
/* We do not control the stacking order of overlay planes;
drm_debug ( b , " \t \t \t [plane] started with zpos % " PRIu64 " \n " ,
* the scanout plane is strictly stacked bottom and the cursor
current_lowest_zpos ) ;
* plane top , but the ordering of overlay planes with respect
ps = drm_output_prepare_plane_view ( state , ev , mode ,
* to each other is undefined . Make sure we do not have two
current_lowest_zpos ) ;
* planes overlapping each other . */
pixman_region32_intersect ( & surface_overlap , & occluded_region ,
& clipped_view ) ;
if ( pixman_region32_not_empty ( & surface_overlap ) ) {
drm_debug ( b , " \t \t \t \t [view] not assigning view %p to plane "
" (occluded by other overlay planes) \n " , ev ) ;
overlay_occluded = true ;
}
}
pixman_region32_fini ( & surface_overlap ) ;
if ( ps ) {
/* The cursor plane is 'special' in the sense that we can still
current_lowest_zpos = ps - > zpos ;
* place it in the legacy API , and we gate that with a separate
drm_debug ( b , " \t \t \t [plane] next zpos to use % " PRIu64 " \n " ,
* cursors_are_broken flag . */
current_lowest_zpos ) ;
if ( ! force_renderer & & ! overlay_occluded & & ! b - > cursors_are_broken )
ps = drm_output_prepare_cursor_view ( state , ev ) ;
/* If sprites are disabled or the view is not fully opaque, we
* must put the view into the renderer - unless it has already
* been placed in the cursor plane , which can handle alpha . */
if ( ! ps & & ! planes_ok ) {
drm_debug ( b , " \t \t \t \t [view] not assigning view %p to plane "
" (precluded by mode) \n " , ev ) ;
force_renderer = true ;
}
if ( ! ps & & ! weston_view_is_opaque ( ev , & clipped_view ) ) {
drm_debug ( b , " \t \t \t \t [view] not assigning view %p to plane "
" (view not fully opaque) \n " , ev ) ;
force_renderer = true ;
}
/* Only try to place scanout surfaces in planes-only mode; in
* mixed mode , we have already failed to place a view on the
* scanout surface , forcing usage of the renderer on the
* scanout plane . */
if ( ! ps & & ! force_renderer & & ! renderer_ok )
ps = drm_output_prepare_scanout_view ( state , ev , mode ) ;
if ( ! ps & & ! overlay_occluded & & ! force_renderer )
ps = drm_output_prepare_overlay_view ( state , ev , mode ) ;
if ( ps ) {
/* If we have been assigned to an overlay or scanout
/* If we have been assigned to an overlay or scanout
* plane , add this area to the occluded region , so
* plane , add this area to the occluded region , so
* other views are known to be behind it . The cursor
* other views are known to be behind it . The cursor
@ -903,22 +644,10 @@ drm_output_propose_state(struct weston_output *output_base,
* be added to the renderer region nor the occluded
* be added to the renderer region nor the occluded
* region . */
* region . */
if ( ps - > plane - > type ! = WDRM_PLANE_TYPE_CURSOR ) {
if ( ps - > plane - > type ! = WDRM_PLANE_TYPE_CURSOR ) {
pixman_region32_union ( & planes_region ,
& planes_region ,
& clipped_view ) ;
if ( ! weston_view_is_opaque ( ev , & clipped_view ) )
pixman_region32_intersect ( & clipped_view ,
& clipped_view ,
& ev - > transform . opaque ) ;
/* the visible-and-opaque region of this view
* will occlude views underneath it */
pixman_region32_union ( & occluded_region ,
pixman_region32_union ( & occluded_region ,
& occluded_region ,
& occluded_region ,
& clipped_view ) ;
& clipped_view ) ;
pixman_region32_fini ( & clipped_view ) ;
pixman_region32_fini ( & clipped_view ) ;
}
}
continue ;
continue ;
}
}
@ -937,24 +666,9 @@ drm_output_propose_state(struct weston_output *output_base,
pixman_region32_union ( & renderer_region ,
pixman_region32_union ( & renderer_region ,
& renderer_region ,
& renderer_region ,
& clipped_view ) ;
& clipped_view ) ;
if ( ! weston_view_is_opaque ( ev , & clipped_view ) )
pixman_region32_intersect ( & clipped_view ,
& clipped_view ,
& ev - > transform . opaque ) ;
pixman_region32_union ( & occluded_region ,
& occluded_region ,
& clipped_view ) ;
pixman_region32_fini ( & clipped_view ) ;
pixman_region32_fini ( & clipped_view ) ;
drm_debug ( b , " \t \t \t \t [view] view %p will be placed "
" on the renderer \n " , ev ) ;
}
}
pixman_region32_fini ( & renderer_region ) ;
pixman_region32_fini ( & renderer_region ) ;
pixman_region32_fini ( & planes_region ) ;
pixman_region32_fini ( & occluded_region ) ;
pixman_region32_fini ( & occluded_region ) ;
/* In renderer-only mode, we can't test the state as we don't have a
/* In renderer-only mode, we can't test the state as we don't have a
@ -962,14 +676,6 @@ drm_output_propose_state(struct weston_output *output_base,
if ( mode = = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY )
if ( mode = = DRM_OUTPUT_PROPOSE_STATE_RENDERER_ONLY )
return state ;
return state ;
/* check if we have invalid zpos values, like duplicate(s) */
ret = drm_output_check_zpos_plane_states ( state ) ;
if ( ret ! = 0 ) {
drm_debug ( b , " \t \t [view] failing state generation: "
" zpos values are in-consistent \n " ) ;
goto err ;
}
/* Check to see if this state will actually work. */
/* Check to see if this state will actually work. */
ret = drm_pending_state_test ( state - > pending_state ) ;
ret = drm_pending_state_test ( state - > pending_state ) ;
if ( ret ! = 0 ) {
if ( ret ! = 0 ) {
@ -1058,7 +764,7 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data)
* to the buffer anyway , there is no side effects .
* to the buffer anyway , there is no side effects .
*/
*/
if ( b - > use_pixman | |
if ( b - > use_pixman | |
( weston_view_has_valid_buffer ( ev ) & &
( ev - > surface - > buffer_ref . buffer & &
( ! wl_shm_buffer_get ( ev - > surface - > buffer_ref . buffer - > resource ) | |
( ! wl_shm_buffer_get ( ev - > surface - > buffer_ref . buffer - > resource ) | |
( ev - > surface - > width < = b - > cursor_width & &
( ev - > surface - > width < = b - > cursor_width & &
ev - > surface - > height < = b - > cursor_height ) ) ) )
ev - > surface - > height < = b - > cursor_height ) ) ) )