@ -47,51 +47,6 @@
# include "rpi-renderer.h"
# include "evdev.h"
/*
* Dispmanx API offers alpha - blended overlays for hardware compositing .
* The final composite consists of dispmanx elements , and their contents :
* the dispmanx resource assigned to the element . The elements may be
* scanned out directly , or composited to a temporary surface , depending on
* how the firmware decides to handle the scene . Updates to multiple elements
* may be queued in a single dispmanx update object , resulting in atomic and
* vblank synchronized display updates .
*
* To avoid tearing and display artifacts , the current dispmanx resource in a
* dispmanx element must not be touched . Therefore each element must be
* double - buffered , using two resources , the front and the back . The update
* sequence is :
* 0. the front resource is already in - use , the back resource is unused
* 1. write data into the back resource
* 2. submit an element update , back becomes in - use
* 3. swap back and front pointers ( both are in - use now )
* 4. wait for update_submit completion , the new back resource becomes unused
*
* A resource may be destroyed only , when the update removing the element has
* completed . Otherwise you risk showing an incomplete composition .
*
* The dispmanx element used as the native window for EGL does not need
* manually allocated resources , EGL does double - buffering internally .
* Unfortunately it also means , that we cannot alternate between two
* buffers like the DRM backend does , since we have no control over what
* resources EGL uses . We are forced to use EGL_BUFFER_PRESERVED as the
* EGL_SWAP_BEHAVIOR to avoid repainting the whole output every frame .
*
* We also cannot bundle eglSwapBuffers into our own display update , which
* means that Weston ' s primary plane updates and the overlay updates may
* happen unsynchronized .
*/
# ifndef ELEMENT_CHANGE_LAYER
/* copied from interface/vmcs_host/vc_vchi_dispmanx.h of userland.git */
# define ELEMENT_CHANGE_LAYER (1<<0)
# define ELEMENT_CHANGE_OPACITY (1<<1)
# define ELEMENT_CHANGE_DEST_RECT (1<<2)
# define ELEMENT_CHANGE_SRC_RECT (1<<3)
# define ELEMENT_CHANGE_MASK_RESOURCE (1<<4)
# define ELEMENT_CHANGE_TRANSFORM (1<<5)
# endif
/* Enabling this debugging incurs a significant performance hit */
#if 0
# define DBG(...) \
weston_log ( __VA_ARGS__ )
@ -99,40 +54,9 @@
# define DBG(...) do {} while (0)
# endif
/* If we had a fully featured vc_dispmanx_resource_write_data()... */
/*#define HAVE_RESOURCE_WRITE_DATA_RECT 1*/
struct rpi_compositor ;
struct rpi_output ;
struct rpi_resource {
DISPMANX_RESOURCE_HANDLE_T handle ;
int width ;
int height ; /* height of the image (valid pixel data) */
int stride ; /* bytes */
int buffer_height ; /* height of the buffer */
VC_IMAGE_TYPE_T ifmt ;
} ;
struct rpi_element {
struct wl_list link ;
struct weston_plane plane ;
struct rpi_output * output ;
DISPMANX_ELEMENT_HANDLE_T handle ;
int layer ;
int need_swap ;
int single_buffer ;
struct rpi_resource resources [ 2 ] ;
struct rpi_resource * front ;
struct rpi_resource * back ;
pixman_region32_t prev_damage ;
struct weston_surface * surface ;
struct wl_listener surface_destroy_listener ;
} ;
struct rpi_flippipe {
int readfd ;
int writefd ;
@ -148,9 +72,6 @@ struct rpi_output {
struct rpi_flippipe flippipe ;
DISPMANX_DISPLAY_HANDLE_T display ;
struct wl_list element_list ; /* struct rpi_element */
struct wl_list old_element_list ; /* struct rpi_element */
} ;
struct rpi_seat {
@ -169,7 +90,6 @@ struct rpi_compositor {
struct udev * udev ;
struct tty * tty ;
int max_planes ; /* per output, really */
int single_buffer ;
} ;
@ -191,425 +111,6 @@ to_rpi_compositor(struct weston_compositor *base)
return container_of ( base , struct rpi_compositor , base ) ;
}
static inline int
int_max ( int a , int b )
{
return a > b ? a : b ;
}
static void
rpi_resource_init ( struct rpi_resource * resource )
{
resource - > handle = DISPMANX_NO_HANDLE ;
}
static void
rpi_resource_release ( struct rpi_resource * resource )
{
if ( resource - > handle = = DISPMANX_NO_HANDLE )
return ;
vc_dispmanx_resource_delete ( resource - > handle ) ;
DBG ( " resource %p release \n " , resource ) ;
resource - > handle = DISPMANX_NO_HANDLE ;
}
static int
rpi_resource_realloc ( struct rpi_resource * resource , VC_IMAGE_TYPE_T ifmt ,
int width , int height , int stride , int buffer_height )
{
uint32_t dummy ;
if ( resource - > handle ! = DISPMANX_NO_HANDLE & &
resource - > width = = width & &
resource - > height = = height & &
resource - > stride = = stride & &
resource - > buffer_height = = buffer_height & &
resource - > ifmt = = ifmt )
return 0 ;
rpi_resource_release ( resource ) ;
/* NOTE: if stride is not a multiple of 16 pixels in bytes,
* the vc_image_ * functions may break . Dispmanx elements
* should be fine , though . Buffer_height probably has similar
* constraints , too .
*/
resource - > handle =
vc_dispmanx_resource_create ( ifmt ,
width | ( stride < < 16 ) ,
height | ( buffer_height < < 16 ) ,
& dummy ) ;
if ( resource - > handle = = DISPMANX_NO_HANDLE )
return - 1 ;
resource - > width = width ;
resource - > height = height ;
resource - > stride = stride ;
resource - > buffer_height = buffer_height ;
resource - > ifmt = ifmt ;
DBG ( " resource %p alloc \n " , resource ) ;
return 0 ;
}
static VC_IMAGE_TYPE_T
shm_buffer_get_vc_format ( struct wl_buffer * buffer )
{
switch ( wl_shm_buffer_get_format ( buffer ) ) {
case WL_SHM_FORMAT_XRGB8888 :
return VC_IMAGE_XRGB8888 ;
case WL_SHM_FORMAT_ARGB8888 :
return VC_IMAGE_ARGB8888 ;
default :
/* invalid format */
return VC_IMAGE_MIN ;
}
}
static int
rpi_resource_update ( struct rpi_resource * resource , struct wl_buffer * buffer ,
pixman_region32_t * region )
{
pixman_region32_t write_region ;
pixman_box32_t * r ;
VC_RECT_T rect ;
VC_IMAGE_TYPE_T ifmt ;
uint32_t * pixels ;
int width ;
int height ;
int stride ;
int ret ;
# ifdef HAVE_RESOURCE_WRITE_DATA_RECT
int n ;
# endif
if ( ! buffer )
return - 1 ;
ifmt = shm_buffer_get_vc_format ( buffer ) ;
width = wl_shm_buffer_get_width ( buffer ) ;
height = wl_shm_buffer_get_height ( buffer ) ;
stride = wl_shm_buffer_get_stride ( buffer ) ;
pixels = wl_shm_buffer_get_data ( buffer ) ;
if ( rpi_resource_realloc ( resource , ifmt , width , height ,
stride , height ) < 0 )
return - 1 ;
pixman_region32_init ( & write_region ) ;
pixman_region32_intersect_rect ( & write_region , region ,
0 , 0 , width , height ) ;
# ifdef HAVE_RESOURCE_WRITE_DATA_RECT
/* XXX: Can this do a format conversion, so that scanout does not have to? */
r = pixman_region32_rectangles ( & write_region , & n ) ;
while ( n - - ) {
vc_dispmanx_rect_set ( & rect , r [ n ] . x1 , r [ n ] . y1 ,
r [ n ] . x2 - r [ n ] . x1 , r [ n ] . y2 - r [ n ] . y1 ) ;
ret = vc_dispmanx_resource_write_data_rect ( resource - > handle ,
ifmt , stride ,
pixels , & rect ,
rect . x , rect . y ) ;
DBG ( " %s: %p %ux%u@%u,%u, ret %d \n " , __func__ , resource ,
rect . width , rect . height , rect . x , rect . y , ret ) ;
if ( ret )
break ;
}
# else
/* vc_dispmanx_resource_write_data() ignores ifmt,
* rect . x , rect . width , and uses stride only for computing
* the size of the transfer as rect . height * stride .
* Therefore we can only write rows starting at x = 0.
* To be able to write more than one scanline at a time ,
* the resource must have been created with the same stride
* as used here , and we must write full scanlines .
*/
r = pixman_region32_extents ( & write_region ) ;
vc_dispmanx_rect_set ( & rect , 0 , r - > y1 , width , r - > y2 - r - > y1 ) ;
ret = vc_dispmanx_resource_write_data ( resource - > handle , ifmt ,
stride , pixels , & rect ) ;
DBG ( " %s: %p %ux%u@%u,%u, ret %d \n " , __func__ , resource ,
width , r - > y2 - r - > y1 , 0 , r - > y1 , ret ) ;
# endif
pixman_region32_fini ( & write_region ) ;
return ret ? - 1 : 0 ;
}
static void
rpi_element_handle_surface_destroy ( struct wl_listener * listener , void * data )
{
struct rpi_element * element =
container_of ( listener , struct rpi_element ,
surface_destroy_listener ) ;
element - > surface = NULL ;
}
static struct rpi_element *
rpi_element_create ( struct rpi_output * output , struct weston_surface * surface )
{
struct rpi_element * element ;
element = calloc ( 1 , sizeof * element ) ;
if ( ! element )
return NULL ;
element - > output = output ;
element - > single_buffer = output - > single_buffer ;
element - > handle = DISPMANX_NO_HANDLE ;
rpi_resource_init ( & element - > resources [ 0 ] ) ;
rpi_resource_init ( & element - > resources [ 1 ] ) ;
element - > front = & element - > resources [ 0 ] ;
if ( element - > single_buffer ) {
element - > back = element - > front ;
} else {
element - > back = & element - > resources [ 1 ] ;
}
pixman_region32_init ( & element - > prev_damage ) ;
weston_plane_init ( & element - > plane , floor ( surface - > geometry . x ) ,
floor ( surface - > geometry . y ) ) ;
element - > surface = surface ;
element - > surface_destroy_listener . notify =
rpi_element_handle_surface_destroy ;
wl_signal_add ( & surface - > resource . destroy_signal ,
& element - > surface_destroy_listener ) ;
wl_list_insert ( output - > element_list . prev , & element - > link ) ;
return element ;
}
static void
rpi_element_destroy ( struct rpi_element * element )
{
struct weston_surface * surface = element - > surface ;
if ( surface ) {
if ( surface - > plane = = & element - > plane ) {
/* If a surface, that was on a plane, gets hidden,
* it will not appear in the repaint surface list ,
* is never considered in rpi_output_assign_planes ( ) ,
* and hence can stay assigned to this element ' s plane .
* We need to reassign it here .
*/
DBG ( " surface %p (%dx%d@%.1f,%.1f) to primary plane* \n " ,
surface ,
surface - > geometry . width , surface - > geometry . height ,
surface - > geometry . x , surface - > geometry . y ) ;
weston_surface_move_to_plane ( surface ,
& surface - > compositor - > primary_plane ) ;
}
wl_list_remove ( & element - > surface_destroy_listener . link ) ;
}
wl_list_remove ( & element - > link ) ;
weston_plane_release ( & element - > plane ) ;
if ( element - > handle ! = DISPMANX_NO_HANDLE )
weston_log ( " ERROR rpi: destroying on-screen element \n " ) ;
pixman_region32_fini ( & element - > prev_damage ) ;
rpi_resource_release ( & element - > resources [ 0 ] ) ;
rpi_resource_release ( & element - > resources [ 1 ] ) ;
DBG ( " element %p destroyed (%u) \n " , element , element - > handle ) ;
free ( element ) ;
}
static void
rpi_element_reuse ( struct rpi_element * element )
{
wl_list_remove ( & element - > link ) ;
wl_list_insert ( element - > output - > element_list . prev , & element - > link ) ;
}
static void
rpi_element_schedule_destroy ( struct rpi_element * element )
{
wl_list_remove ( & element - > link ) ;
wl_list_insert ( element - > output - > old_element_list . prev ,
& element - > link ) ;
}
static int
rpi_element_damage ( struct rpi_element * element , struct wl_buffer * buffer ,
pixman_region32_t * damage )
{
pixman_region32_t upload ;
int ret ;
if ( ! pixman_region32_not_empty ( damage ) )
return 0 ;
DBG ( " element %p update resource %p \n " , element , element - > back ) ;
if ( element - > single_buffer ) {
ret = rpi_resource_update ( element - > back , buffer , damage ) ;
} else {
pixman_region32_init ( & upload ) ;
pixman_region32_union ( & upload , & element - > prev_damage , damage ) ;
ret = rpi_resource_update ( element - > back , buffer , & upload ) ;
pixman_region32_fini ( & upload ) ;
}
pixman_region32_copy ( & element - > prev_damage , damage ) ;
element - > need_swap = 1 ;
return ret ;
}
static void
rpi_element_compute_rects ( struct rpi_element * element ,
VC_RECT_T * src_rect , VC_RECT_T * dst_rect )
{
struct weston_output * output = & element - > output - > base ;
int src_x , src_y ;
int dst_x , dst_y ;
int width , height ;
/* assume element->plane.{x,y} == element->surface->geometry.{x,y} */
src_x = 0 ;
src_y = 0 ;
width = element - > surface - > geometry . width ;
height = element - > surface - > geometry . height ;
dst_x = element - > plane . x - output - > x ;
dst_y = element - > plane . y - output - > y ;
if ( dst_x < 0 ) {
width + = dst_x ;
src_x - = dst_x ;
dst_x = 0 ;
}
if ( dst_y < 0 ) {
height + = dst_y ;
src_y - = dst_y ;
dst_y = 0 ;
}
width = int_max ( width , 0 ) ;
height = int_max ( height , 0 ) ;
/* src_rect is in 16.16, dst_rect is in 32.0 unsigned fixed point */
vc_dispmanx_rect_set ( src_rect , src_x < < 16 , src_y < < 16 ,
width < < 16 , height < < 16 ) ;
vc_dispmanx_rect_set ( dst_rect , dst_x , dst_y , width , height ) ;
}
static void
rpi_element_dmx_add ( struct rpi_element * element ,
DISPMANX_UPDATE_HANDLE_T update , int layer )
{
VC_DISPMANX_ALPHA_T alphasetup = {
DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_PREMULT ,
255 , /* opacity 0-255 */
0 /* mask resource handle */
} ;
VC_RECT_T dst_rect ;
VC_RECT_T src_rect ;
rpi_element_compute_rects ( element , & src_rect , & dst_rect ) ;
element - > handle = vc_dispmanx_element_add (
update ,
element - > output - > display ,
layer ,
& dst_rect ,
element - > back - > handle ,
& src_rect ,
DISPMANX_PROTECTION_NONE ,
& alphasetup ,
NULL /* clamp */ ,
DISPMANX_NO_ROTATE ) ;
DBG ( " element %p add %u \n " , element , element - > handle ) ;
}
static void
rpi_element_dmx_swap ( struct rpi_element * element ,
DISPMANX_UPDATE_HANDLE_T update )
{
VC_RECT_T rect ;
pixman_box32_t * r ;
/* XXX: skip, iff resource was not reallocated, and single-buffering */
vc_dispmanx_element_change_source ( update , element - > handle ,
element - > back - > handle ) ;
/* This is current damage now, after rpi_assign_plane() */
r = pixman_region32_extents ( & element - > prev_damage ) ;
vc_dispmanx_rect_set ( & rect , r - > x1 , r - > y1 ,
r - > x2 - r - > x1 , r - > y2 - r - > y1 ) ;
vc_dispmanx_element_modified ( update , element - > handle , & rect ) ;
DBG ( " element %p swap \n " , element ) ;
}
static void
rpi_element_dmx_move ( struct rpi_element * element ,
DISPMANX_UPDATE_HANDLE_T update , int layer )
{
VC_RECT_T dst_rect ;
VC_RECT_T src_rect ;
/* XXX: return early, if all attributes stay the same */
rpi_element_compute_rects ( element , & src_rect , & dst_rect ) ;
vc_dispmanx_element_change_attributes (
update ,
element - > handle ,
ELEMENT_CHANGE_LAYER |
ELEMENT_CHANGE_DEST_RECT |
ELEMENT_CHANGE_SRC_RECT ,
layer ,
255 ,
& dst_rect ,
& src_rect ,
DISPMANX_NO_HANDLE ,
VC_IMAGE_ROT0 ) ;
DBG ( " element %p move \n " , element ) ;
}
static int
rpi_element_update ( struct rpi_element * element ,
DISPMANX_UPDATE_HANDLE_T update , int layer )
{
struct rpi_resource * tmp ;
if ( element - > handle = = DISPMANX_NO_HANDLE ) {
/* need_swap is already true, see rpi_assign_plane() */
rpi_element_dmx_add ( element , update , layer ) ;
if ( element - > handle = = DISPMANX_NO_HANDLE )
weston_log ( " ERROR rpi: element_add() failed. \n " ) ;
} else {
if ( element - > need_swap )
rpi_element_dmx_swap ( element , update ) ;
rpi_element_dmx_move ( element , update , layer ) ;
}
element - > layer = layer ;
if ( element - > need_swap ) {
tmp = element - > front ;
element - > front = element - > back ;
element - > back = tmp ;
element - > need_swap = 0 ;
DBG ( " new back %p, new front %p \n " ,
element - > back , element - > front ) ;
}
return 0 ;
}
static uint64_t
rpi_get_current_time ( void )
{
@ -714,181 +215,6 @@ rpi_flippipe_release(struct rpi_flippipe *flippipe)
close ( flippipe - > writefd ) ;
}
static struct rpi_element *
find_rpi_element_from_surface ( struct weston_surface * surface )
{
struct wl_listener * listener ;
struct rpi_element * element ;
listener = wl_signal_get ( & surface - > resource . destroy_signal ,
rpi_element_handle_surface_destroy ) ;
if ( ! listener )
return NULL ;
element = container_of ( listener , struct rpi_element ,
surface_destroy_listener ) ;
if ( element - > surface ! = surface )
weston_log ( " ERROR rpi: sanity check failure in %s. \n " ,
__func__ ) ;
return element ;
}
static struct rpi_element *
rpi_assign_plane ( struct weston_surface * surface , struct rpi_output * output )
{
struct rpi_element * element ;
/* dispmanx elements cannot transform */
if ( surface - > transform . enabled ) {
/* XXX: inspect the transformation matrix, we might still
* be able to put it into an element ; scaling , additional
* translation ( window titlebar context menus ? )
*/
DBG ( " surface %p rejected: transform \n " , surface ) ;
return NULL ;
}
/* only shm surfaces supported */
if ( surface - > buffer_ref . buffer & &
! wl_buffer_is_shm ( surface - > buffer_ref . buffer ) ) {
DBG ( " surface %p rejected: not shm \n " , surface ) ;
return NULL ;
}
if ( surface - > buffer_transform ! = WL_OUTPUT_TRANSFORM_NORMAL ) {
DBG ( " surface %p rejected: unsupported buffer transform \n " ,
surface ) ;
return NULL ;
}
/* check if this surface previously belonged to an element */
element = find_rpi_element_from_surface ( surface ) ;
if ( element ) {
rpi_element_reuse ( element ) ;
element - > plane . x = floor ( surface - > geometry . x ) ;
element - > plane . y = floor ( surface - > geometry . y ) ;
DBG ( " surface %p reuse element %p \n " , surface , element ) ;
} else {
if ( ! surface - > buffer_ref . buffer ) {
DBG ( " surface %p rejected: no buffer \n " , surface ) ;
return NULL ;
}
element = rpi_element_create ( output , surface ) ;
DBG ( " element %p created \n " , element ) ;
}
if ( ! element ) {
DBG ( " surface %p rejected: no element \n " , surface ) ;
return NULL ;
}
return element ;
}
static void
rpi_output_assign_planes ( struct weston_output * base )
{
struct rpi_output * output = to_rpi_output ( base ) ;
struct rpi_compositor * compositor = output - > compositor ;
struct weston_surface * surface ;
pixman_region32_t overlap ;
pixman_region32_t surface_overlap ;
struct rpi_element * element ;
int n = 0 ;
/* Construct the list of rpi_elements to be used into
* output - > element_list , which is empty right now .
* Re - used elements are moved from old_element_list to
* element_list . */
DBG ( " %s \n " , __func__ ) ;
pixman_region32_init ( & overlap ) ;
wl_list_for_each ( surface , & compositor - > base . surface_list , link ) {
/* always, since all buffers are shm on rpi */
surface - > keep_buffer = 1 ;
pixman_region32_init ( & surface_overlap ) ;
pixman_region32_intersect ( & surface_overlap , & overlap ,
& surface - > transform . boundingbox ) ;
element = NULL ;
if ( ! pixman_region32_not_empty ( & surface_overlap ) & &
n < compositor - > max_planes )
element = rpi_assign_plane ( surface , output ) ;
if ( element ) {
weston_surface_move_to_plane ( surface , & element - > plane ) ;
DBG ( " surface %p (%dx%d@%.1f,%.1f) to element %p \n " ,
surface ,
surface - > geometry . width , surface - > geometry . height ,
surface - > geometry . x , surface - > geometry . y , element ) ;
/* weston_surface_move_to_plane() does full-surface
* damage , if the plane is new , so no need to force
* initial resource update .
*/
if ( rpi_element_damage ( element ,
surface - > buffer_ref . buffer ,
& surface - > damage ) < 0 ) {
rpi_element_schedule_destroy ( element ) ;
DBG ( " surface %p rejected: resource update failed \n " ,
surface ) ;
element = NULL ;
} else {
n + + ;
}
}
if ( ! element ) {
weston_surface_move_to_plane ( surface ,
& compositor - > base . primary_plane ) ;
DBG ( " surface %p (%dx%d@%.1f,%.1f) to primary plane \n " ,
surface ,
surface - > geometry . width , surface - > geometry . height ,
surface - > geometry . x , surface - > geometry . y ) ;
pixman_region32_union ( & overlap , & overlap ,
& surface - > transform . boundingbox ) ;
}
pixman_region32_fini ( & surface_overlap ) ;
}
pixman_region32_fini ( & overlap ) ;
}
static void
rpi_remove_elements ( struct wl_list * element_list ,
DISPMANX_UPDATE_HANDLE_T update )
{
struct rpi_element * element ;
wl_list_for_each ( element , element_list , link ) {
if ( element - > handle = = DISPMANX_NO_HANDLE )
continue ;
vc_dispmanx_element_remove ( update , element - > handle ) ;
DBG ( " element %p remove %u \n " , element , element - > handle ) ;
element - > handle = DISPMANX_NO_HANDLE ;
}
}
static void
rpi_output_destroy_old_elements ( struct rpi_output * output )
{
struct rpi_element * element , * tmp ;
wl_list_for_each_safe ( element , tmp , & output - > old_element_list , link ) {
if ( element - > handle ! = DISPMANX_NO_HANDLE )
continue ;
rpi_element_destroy ( element ) ;
}
}
static void
rpi_output_start_repaint_loop ( struct weston_output * output )
{
@ -904,9 +230,7 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
struct rpi_output * output = to_rpi_output ( base ) ;
struct rpi_compositor * compositor = output - > compositor ;
struct weston_plane * primary_plane = & compositor - > base . primary_plane ;
struct rpi_element * element ;
DISPMANX_UPDATE_HANDLE_T update ;
int layer = 10000 ;
DBG ( " frame update start \n " ) ;
@ -915,15 +239,6 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
*/
update = vc_dispmanx_update_start ( 1 ) ;
/* update all live elements */
wl_list_for_each ( element , & output - > element_list , link ) {
if ( rpi_element_update ( element , update , layer - - ) < 0 )
weston_log ( " ERROR rpi: element update failed. \n " ) ;
}
/* remove all unused elements */
rpi_remove_elements ( & output - > old_element_list , update ) ;
rpi_renderer_set_update_handle ( & output - > base , update ) ;
compositor - > base . renderer - > repaint_output ( & output - > base , damage ) ;
@ -933,17 +248,12 @@ rpi_output_repaint(struct weston_output *base, pixman_region32_t *damage)
/* schedule callback to rpi_output_update_complete() */
rpi_dispmanx_update_submit ( update , output ) ;
DBG ( " frame update submitted \n " ) ;
/* Move the list of elements into the old_element_list. */
wl_list_insert_list ( & output - > old_element_list , & output - > element_list ) ;
wl_list_init ( & output - > element_list ) ;
}
static void
rpi_output_update_complete ( struct rpi_output * output , uint64_t time )
{
DBG ( " frame update complete(% " PRIu64 " ) \n " , time ) ;
rpi_output_destroy_old_elements ( output ) ;
rpi_renderer_finish_frame ( & output - > base ) ;
weston_output_finish_frame ( & output - > base , time ) ;
}
@ -952,24 +262,11 @@ static void
rpi_output_destroy ( struct weston_output * base )
{
struct rpi_output * output = to_rpi_output ( base ) ;
DISPMANX_UPDATE_HANDLE_T update ;
struct rpi_element * element , * tmp ;
DBG ( " %s \n " , __func__ ) ;
update = vc_dispmanx_update_start ( 0 ) ;
rpi_remove_elements ( & output - > element_list , update ) ;
rpi_remove_elements ( & output - > old_element_list , update ) ;
vc_dispmanx_update_submit_sync ( update ) ;
rpi_renderer_output_destroy ( base ) ;
wl_list_for_each_safe ( element , tmp , & output - > element_list , link )
rpi_element_destroy ( element ) ;
wl_list_for_each_safe ( element , tmp , & output - > old_element_list , link )
rpi_element_destroy ( element ) ;
/* rpi_renderer_output_destroy() will schedule a removal of
* all Dispmanx Elements , and wait for the update to complete .
* Assuming updates are sequential , the wait should guarantee ,
@ -1033,8 +330,6 @@ rpi_output_create(struct rpi_compositor *compositor, uint32_t transform)
output - > compositor = compositor ;
output - > single_buffer = compositor - > single_buffer ;
wl_list_init ( & output - > element_list ) ;
wl_list_init ( & output - > old_element_list ) ;
if ( rpi_flippipe_init ( & output - > flippipe , output ) < 0 ) {
weston_log ( " Creating message pipe failed. \n " ) ;
@ -1433,7 +728,6 @@ switch_vt_binding(struct weston_seat *seat, uint32_t time, uint32_t key, void *d
struct rpi_parameters {
int tty ;
int max_planes ;
struct rpi_renderer_parameters renderer ;
uint32_t output_transform ;
} ;
@ -1473,11 +767,8 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
compositor - > base . focus = 1 ;
compositor - > prev_state = WESTON_COMPOSITOR_ACTIVE ;
compositor - > max_planes = int_max ( param - > max_planes , 0 ) ;
compositor - > single_buffer = param - > renderer . single_buffer ;
weston_log ( " Maximum number of additional Dispmanx planes: %d \n " ,
compositor - > max_planes ) ;
weston_log ( " Dispmanx planes are %s buffered. \n " ,
compositor - > single_buffer ? " single " : " double " ) ;
@ -1524,22 +815,6 @@ out_free:
return NULL ;
}
/*
* If you have a recent enough firmware in Raspberry Pi , that
* supports falling back to off - line hardware compositing , and
* you have enabled it with dispmanx_offline = 1 in / boot / config . txt ,
* then VideoCore should be able to handle almost 100 Dispmanx
* elements . Therefore use 80 as the default limit .
*
* If you don ' t have off - line compositing support , this would be
* better as something like 10. Failing on - line compositing may
* show up as visible glitches , HDMI blanking , or invisible surfaces .
*
* When the max - planes number is reached , rpi - backend will start
* to fall back to GLESv2 compositing .
*/
# define DEFAULT_MAX_PLANES 80
WL_EXPORT struct weston_compositor *
backend_init ( struct wl_display * display , int * argc , char * argv [ ] ,
int config_fd )
@ -1549,14 +824,12 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
struct rpi_parameters param = {
. tty = 0 , /* default to current tty */
. max_planes = DEFAULT_MAX_PLANES ,
. renderer . single_buffer = 0 ,
. output_transform = WL_OUTPUT_TRANSFORM_NORMAL ,
} ;
const struct weston_option rpi_options [ ] = {
{ WESTON_OPTION_INTEGER , " tty " , 0 , & param . tty } ,
{ WESTON_OPTION_INTEGER , " max-planes " , 0 , & param . max_planes } ,
{ WESTON_OPTION_BOOLEAN , " single-buffer " , 0 ,
& param . renderer . single_buffer } ,
{ WESTON_OPTION_STRING , " transform " , 0 , & transform } ,