@ -67,16 +67,27 @@ struct nested_region {
pixman_region32_t region ;
} ;
struct nested_buffer_reference {
struct nested_buffer * buffer ;
struct wl_listener destroy_listener ;
} ;
struct nested_buffer {
struct wl_resource * resource ;
struct wl_signal destroy_signal ;
struct wl_listener destroy_listener ;
uint32_t busy_count ;
} ;
struct nested_buffer_reference {
struct nested_buffer * buffer ;
struct wl_listener destroy_listener ;
/* A buffer in the parent compositor representing the same
* data . This is created on - demand when the subsurface
* renderer is used */
struct wl_buffer * parent_buffer ;
/* This reference is used to mark when the parent buffer has
* been attached to the subsurface . It will be unrefenced when
* we receive a buffer release event . That way we won ' t inform
* the client that the buffer is free until the parent
* compositor is also finished with it */
struct nested_buffer_reference parent_ref ;
} ;
struct nested_surface {
@ -110,6 +121,14 @@ struct nested_blit_surface {
cairo_surface_t * cairo_surface ;
} ;
/* Data used for the subsurface renderer */
struct nested_ss_surface {
struct widget * widget ;
struct wl_surface * surface ;
struct wl_subsurface * subsurface ;
struct wl_callback * frame_callback ;
} ;
struct nested_frame_callback {
struct wl_resource * resource ;
struct wl_list link ;
@ -124,6 +143,7 @@ struct nested_renderer {
} ;
static const struct nested_renderer nested_blit_renderer ;
static const struct nested_renderer nested_ss_renderer ;
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d ;
static PFNEGLCREATEIMAGEKHRPROC create_image ;
@ -131,6 +151,7 @@ static PFNEGLDESTROYIMAGEKHRPROC destroy_image;
static PFNEGLBINDWAYLANDDISPLAYWL bind_display ;
static PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display ;
static PFNEGLQUERYWAYLANDBUFFERWL query_buffer ;
static PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL create_wayland_buffer_from_image ;
static void
nested_buffer_destroy_handler ( struct wl_listener * listener , void * data )
@ -139,6 +160,10 @@ nested_buffer_destroy_handler(struct wl_listener *listener, void *data)
container_of ( listener , struct nested_buffer , destroy_listener ) ;
wl_signal_emit ( & buffer - > destroy_signal , buffer ) ;
if ( buffer - > parent_buffer )
wl_buffer_destroy ( buffer - > parent_buffer ) ;
free ( buffer ) ;
}
@ -538,6 +563,10 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
& surface - > pending . frame_callback_list ) ;
wl_list_init ( & surface - > pending . frame_callback_list ) ;
/* FIXME: For the subsurface renderer we don't need to
* actually redraw the window . However we do want to cause a
* commit because the subsurface is synchronized . Ideally we
* would just queue the commit */
window_schedule_redraw ( nested - > window ) ;
}
@ -694,6 +723,7 @@ nested_init_compositor(struct nested *nested)
{
const char * extensions ;
struct wl_event_loop * loop ;
int use_ss_renderer = 0 ;
int fd , ret ;
wl_list_init ( & nested - > surface_list ) ;
@ -732,7 +762,25 @@ nested_init_compositor(struct nested *nested)
return - 1 ;
}
if ( display_has_subcompositor ( nested - > display ) ) {
const char * func = " eglCreateWaylandBufferFromImageWL " ;
const char * ext = " EGL_WL_create_wayland_buffer_from_image " ;
if ( strstr ( extensions , ext ) ) {
create_wayland_buffer_from_image =
( void * ) eglGetProcAddress ( func ) ;
use_ss_renderer = 1 ;
}
}
if ( use_ss_renderer ) {
printf ( " Using subsurfaces to render client surfaces \n " ) ;
nested - > renderer = & nested_ss_renderer ;
} else {
printf ( " Using local compositing with blits to "
" render client surfaces \n " ) ;
nested - > renderer = & nested_blit_renderer ;
}
return 0 ;
}
@ -771,6 +819,8 @@ nested_destroy(struct nested *nested)
free ( nested ) ;
}
/*** blit renderer ***/
static void
blit_surface_init ( struct nested_surface * surface )
{
@ -889,6 +939,160 @@ nested_blit_renderer = {
. surface_attach = blit_surface_attach
} ;
/*** subsurface renderer ***/
static void
ss_surface_init ( struct nested_surface * surface )
{
struct nested * nested = surface - > nested ;
struct wl_compositor * compositor =
display_get_compositor ( nested - > display ) ;
struct nested_ss_surface * ss_surface =
zalloc ( sizeof * ss_surface ) ;
struct rectangle allocation ;
struct wl_region * region ;
ss_surface - > widget =
window_add_subsurface ( nested - > window ,
nested ,
SUBSURFACE_SYNCHRONIZED ) ;
ss_surface - > surface = widget_get_wl_surface ( ss_surface - > widget ) ;
ss_surface - > subsurface = widget_get_wl_subsurface ( ss_surface - > widget ) ;
/* The toy toolkit gets confused about the pointer position
* when it gets motion events for a subsurface so we ' ll just
* disable input on it */
region = wl_compositor_create_region ( compositor ) ;
wl_surface_set_input_region ( ss_surface - > surface , region ) ;
wl_region_destroy ( region ) ;
widget_get_allocation ( nested - > widget , & allocation ) ;
wl_subsurface_set_position ( ss_surface - > subsurface ,
allocation . x + 10 ,
allocation . y + 10 ) ;
surface - > renderer_data = ss_surface ;
}
static void
ss_surface_fini ( struct nested_surface * surface )
{
struct nested_ss_surface * ss_surface = surface - > renderer_data ;
widget_destroy ( ss_surface - > widget ) ;
if ( ss_surface - > frame_callback )
wl_callback_destroy ( ss_surface - > frame_callback ) ;
free ( ss_surface ) ;
}
static void
ss_render_clients ( struct nested * nested ,
cairo_t * cr )
{
/* The clients are composited by the parent compositor so we
* don ' t need to do anything here */
}
static void
ss_buffer_release ( void * data , struct wl_buffer * wl_buffer )
{
struct nested_buffer * buffer = data ;
nested_buffer_reference ( & buffer - > parent_ref , NULL ) ;
}
static struct wl_buffer_listener ss_buffer_listener = {
ss_buffer_release
} ;
static void
ss_frame_callback ( void * data , struct wl_callback * callback , uint32_t time )
{
struct nested_surface * surface = data ;
struct nested_ss_surface * ss_surface = surface - > renderer_data ;
flush_surface_frame_callback_list ( surface , time ) ;
if ( callback )
wl_callback_destroy ( callback ) ;
ss_surface - > frame_callback = NULL ;
}
static const struct wl_callback_listener ss_frame_listener = {
ss_frame_callback
} ;
static void
ss_surface_attach ( struct nested_surface * surface ,
struct nested_buffer * buffer )
{
struct nested * nested = surface - > nested ;
struct nested_ss_surface * ss_surface = surface - > renderer_data ;
struct wl_buffer * parent_buffer ;
const pixman_box32_t * rects ;
int n_rects , i ;
if ( buffer ) {
/* Create a representation of the buffer in the parent
* compositor if we haven ' t already */
if ( buffer - > parent_buffer = = NULL ) {
EGLDisplay * edpy = nested - > egl_display ;
EGLImageKHR image = surface - > image ;
buffer - > parent_buffer =
create_wayland_buffer_from_image ( edpy , image ) ;
wl_buffer_add_listener ( buffer - > parent_buffer ,
& ss_buffer_listener ,
buffer ) ;
}
parent_buffer = buffer - > parent_buffer ;
/* We'll take a reference to the buffer while the parent
* compositor is using it so that we won ' t report the release
* event until the parent has also finished with it */
nested_buffer_reference ( & buffer - > parent_ref , buffer ) ;
} else {
parent_buffer = NULL ;
}
wl_surface_attach ( ss_surface - > surface , parent_buffer , 0 , 0 ) ;
rects = pixman_region32_rectangles ( & surface - > pending . damage , & n_rects ) ;
for ( i = 0 ; i < n_rects ; i + + ) {
const pixman_box32_t * rect = rects + i ;
wl_surface_damage ( ss_surface - > surface ,
rect - > x1 ,
rect - > y1 ,
rect - > x2 - rect - > x1 ,
rect - > y2 - rect - > y1 ) ;
}
if ( ss_surface - > frame_callback )
wl_callback_destroy ( ss_surface - > frame_callback ) ;
ss_surface - > frame_callback = wl_surface_frame ( ss_surface - > surface ) ;
wl_callback_add_listener ( ss_surface - > frame_callback ,
& ss_frame_listener ,
surface ) ;
wl_surface_commit ( ss_surface - > surface ) ;
}
static const struct nested_renderer
nested_ss_renderer = {
. surface_init = ss_surface_init ,
. surface_fini = ss_surface_fini ,
. render_clients = ss_render_clients ,
. surface_attach = ss_surface_attach
} ;
int
main ( int argc , char * argv [ ] )
{