@ -12,6 +12,7 @@
# include "types/wlr_buffer.h"
# include "types/wlr_region.h"
# include "types/wlr_subcompositor.h"
# include "util/array.h"
# include "util/time.h"
# define COMPOSITOR_VERSION 6
@ -272,11 +273,42 @@ static void surface_update_damage(pixman_region32_t *buffer_damage,
}
}
static void * surface_synced_create_state ( struct wlr_surface_synced * synced ) {
void * state = calloc ( 1 , synced - > impl - > state_size ) ;
if ( state = = NULL ) {
return NULL ;
}
if ( synced - > impl - > init_state ) {
synced - > impl - > init_state ( state ) ;
}
return state ;
}
static void surface_synced_destroy_state ( struct wlr_surface_synced * synced ,
void * state ) {
if ( state = = NULL ) {
return ;
}
if ( synced - > impl - > finish_state ) {
synced - > impl - > finish_state ( state ) ;
}
free ( state ) ;
}
static void surface_synced_move_state ( struct wlr_surface_synced * synced ,
void * dst , void * src ) {
if ( synced - > impl - > move_state ) {
synced - > impl - > move_state ( dst , src ) ;
} else {
memcpy ( dst , src , synced - > impl - > state_size ) ;
}
}
/**
* Overwrite state with a copy of the next state , then clear the next state .
*/
static void surface_state_move ( struct wlr_surface_state * state ,
struct wlr_surface_state * next ) {
struct wlr_surface_state * next , struct wlr_surface * surface ) {
state - > width = next - > width ;
state - > height = next - > height ;
state - > buffer_width = next - > buffer_width ;
@ -331,6 +363,14 @@ static void surface_state_move(struct wlr_surface_state *state,
wl_list_init ( & next - > frame_callback_list ) ;
}
void * * state_synced = state - > synced . data ;
void * * next_synced = next - > synced . data ;
struct wlr_surface_synced * synced ;
wl_list_for_each ( synced , & surface - > synced , link ) {
surface_synced_move_state ( synced ,
state_synced [ synced - > index ] , next_synced [ synced - > index ] ) ;
}
state - > committed = next - > committed ;
next - > committed = 0 ;
@ -404,21 +444,44 @@ static void surface_update_input_region(struct wlr_surface *surface) {
0 , 0 , surface - > current . width , surface - > current . height ) ;
}
static void surface_state_init ( struct wlr_surface_state * state ) ;
static bool surface_state_init ( struct wlr_surface_state * state ,
struct wlr_surface * surface ) ;
static void surface_state_finish ( struct wlr_surface_state * state ) ;
static void surface_cache_pending ( struct wlr_surface * surface ) {
struct wlr_surface_state * cached = calloc ( 1 , sizeof ( * cached ) ) ;
if ( ! cached ) {
wl_resource_post_no_memory ( surface - > resource ) ;
return ;
goto error ;
}
if ( ! surface_state_init ( cached , surface ) ) {
goto error_cached ;
}
void * * cached_synced = cached - > synced . data ;
struct wlr_surface_synced * synced ;
wl_list_for_each ( synced , & surface - > synced , link ) {
void * synced_state = surface_synced_create_state ( synced ) ;
if ( synced_state = = NULL ) {
goto error_state ;
}
cached_synced [ synced - > index ] = synced_state ;
}
surface_state_init ( cached ) ;
surface_state_move ( cached , & surface - > pending ) ;
surface_state_move ( cached , & surface - > pending , surface ) ;
wl_list_insert ( surface - > cached . prev , & cached - > cached_state_link ) ;
surface - > pending . seq + + ;
return ;
error_state :
surface_state_finish ( cached ) ;
error_cached :
free ( cached ) ;
error :
wl_resource_post_no_memory ( surface - > resource ) ;
}
static void surface_commit_state ( struct wlr_surface * surface ,
@ -452,7 +515,7 @@ static void surface_commit_state(struct wlr_surface *surface,
surface - > previous . buffer_width = surface - > current . buffer_width ;
surface - > previous . buffer_height = surface - > current . buffer_height ;
surface_state_move ( & surface - > current , next );
surface_state_move ( & surface - > current , next , surface );
if ( invalid_buffer ) {
surface_apply_damage ( surface ) ;
@ -579,7 +642,8 @@ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) {
return wl_resource_get_user_data ( resource ) ;
}
static void surface_state_init ( struct wlr_surface_state * state ) {
static bool surface_state_init ( struct wlr_surface_state * state ,
struct wlr_surface * surface ) {
* state = ( struct wlr_surface_state ) {
. scale = 1 ,
. transform = WL_OUTPUT_TRANSFORM_NORMAL ,
@ -595,6 +659,10 @@ static void surface_state_init(struct wlr_surface_state *state) {
pixman_region32_init ( & state - > opaque ) ;
pixman_region32_init_rect ( & state - > input ,
INT32_MIN , INT32_MIN , UINT32_MAX , UINT32_MAX ) ;
wl_array_init ( & state - > synced ) ;
void * ptr = wl_array_add ( & state - > synced , surface - > synced_len * sizeof ( void * ) ) ;
return ptr ! = NULL ;
}
static void surface_state_finish ( struct wlr_surface_state * state ) {
@ -609,9 +677,18 @@ static void surface_state_finish(struct wlr_surface_state *state) {
pixman_region32_fini ( & state - > buffer_damage ) ;
pixman_region32_fini ( & state - > opaque ) ;
pixman_region32_fini ( & state - > input ) ;
wl_array_release ( & state - > synced ) ;
}
static void surface_state_destroy_cached ( struct wlr_surface_state * state ) {
static void surface_state_destroy_cached ( struct wlr_surface_state * state ,
struct wlr_surface * surface ) {
void * * synced_states = state - > synced . data ;
struct wlr_surface_synced * synced ;
wl_list_for_each ( synced , & surface - > synced , link ) {
surface_synced_destroy_state ( synced , synced_states [ synced - > index ] ) ;
}
surface_state_finish ( state ) ;
wl_list_remove ( & state - > cached_state_link ) ;
free ( state ) ;
@ -634,10 +711,11 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
wl_signal_emit_mutable ( & surface - > events . destroy , surface ) ;
wlr_addon_set_finish ( & surface - > addons ) ;
assert ( wl_list_empty ( & surface - > synced ) ) ;
struct wlr_surface_state * cached , * cached_tmp ;
wl_list_for_each_safe ( cached , cached_tmp , & surface - > cached , cached_state_link ) {
surface_state_destroy_cached ( cached );
surface_state_destroy_cached ( cached , surface );
}
wl_list_remove ( & surface - > renderer_destroy . link ) ;
@ -682,8 +760,8 @@ static struct wlr_surface *surface_create(struct wl_client *client,
surface - > renderer = renderer ;
surface_state_init ( & surface - > current );
surface_state_init ( & surface - > pending );
surface_state_init ( & surface - > current , surface );
surface_state_init ( & surface - > pending , surface );
surface - > pending . seq = 1 ;
wl_signal_init ( & surface - > events . client_commit ) ;
@ -699,6 +777,7 @@ static struct wlr_surface *surface_create(struct wl_client *client,
pixman_region32_init ( & surface - > opaque_region ) ;
pixman_region32_init ( & surface - > input_region ) ;
wlr_addon_set_init ( & surface - > addons ) ;
wl_list_init ( & surface - > synced ) ;
if ( renderer ! = NULL ) {
wl_signal_add ( & renderer - > events . destroy , & surface - > renderer_destroy ) ;
@ -860,7 +939,7 @@ void wlr_surface_unlock_cached(struct wlr_surface *surface, uint32_t seq) {
}
surface_commit_state ( surface , next ) ;
surface_state_destroy_cached ( next );
surface_state_destroy_cached ( next , surface );
}
}
@ -1258,3 +1337,125 @@ struct wlr_compositor *wlr_compositor_create(struct wl_display *display,
return compositor ;
}
static bool surface_state_add_synced ( struct wlr_surface_state * state , void * value ) {
void * * ptr = wl_array_add ( & state - > synced , sizeof ( void * ) ) ;
if ( ptr = = NULL ) {
return false ;
}
* ptr = value ;
return true ;
}
static void * surface_state_remove_synced ( struct wlr_surface_state * state ,
struct wlr_surface_synced * synced ) {
void * * synced_states = state - > synced . data ;
void * synced_state = synced_states [ synced - > index ] ;
array_remove_at ( & state - > synced , synced - > index * sizeof ( void * ) , sizeof ( void * ) ) ;
return synced_state ;
}
static void surface_state_remove_and_destroy_synced ( struct wlr_surface_state * state ,
struct wlr_surface_synced * synced ) {
void * synced_state = surface_state_remove_synced ( state , synced ) ;
surface_synced_destroy_state ( synced , synced_state ) ;
}
bool wlr_surface_synced_init ( struct wlr_surface_synced * synced ,
struct wlr_surface * surface , const struct wlr_surface_synced_impl * impl ,
void * pending , void * current ) {
assert ( impl - > state_size > 0 ) ;
struct wlr_surface_synced * other ;
wl_list_for_each ( other , & surface - > synced , link ) {
assert ( synced ! = other ) ;
}
memset ( pending , 0 , impl - > state_size ) ;
memset ( current , 0 , impl - > state_size ) ;
if ( impl - > init_state ) {
impl - > init_state ( pending ) ;
impl - > init_state ( current ) ;
}
if ( ! surface_state_add_synced ( & surface - > pending , pending ) ) {
goto error_init ;
}
if ( ! surface_state_add_synced ( & surface - > current , current ) ) {
goto error_pending ;
}
* synced = ( struct wlr_surface_synced ) {
. surface = surface ,
. impl = impl ,
. index = surface - > synced_len ,
} ;
struct wlr_surface_state * cached ;
wl_list_for_each ( cached , & surface - > cached , cached_state_link ) {
void * synced_state = surface_synced_create_state ( synced ) ;
if ( synced_state = = NULL | |
! surface_state_add_synced ( cached , synced_state ) ) {
surface_synced_destroy_state ( synced , synced_state ) ;
goto error_cached ;
}
}
wl_list_insert ( & surface - > synced , & synced - > link ) ;
surface - > synced_len + + ;
return true ;
error_cached : ;
struct wlr_surface_state * failed_at = cached ;
wl_list_for_each ( cached , & surface - > cached , cached_state_link ) {
if ( cached = = failed_at ) {
break ;
}
surface_state_remove_and_destroy_synced ( cached , synced ) ;
}
surface_state_remove_synced ( & surface - > current , synced ) ;
error_pending :
surface_state_remove_synced ( & surface - > pending , synced ) ;
error_init :
if ( synced - > impl - > finish_state ) {
synced - > impl - > finish_state ( pending ) ;
synced - > impl - > finish_state ( current ) ;
}
return false ;
}
void wlr_surface_synced_finish ( struct wlr_surface_synced * synced ) {
struct wlr_surface * surface = synced - > surface ;
bool found = false ;
struct wlr_surface_synced * other ;
wl_list_for_each ( other , & surface - > synced , link ) {
if ( other = = synced ) {
found = true ;
} else if ( other - > index > synced - > index ) {
other - > index - - ;
}
}
assert ( found ) ;
struct wlr_surface_state * cached ;
wl_list_for_each ( cached , & surface - > cached , cached_state_link ) {
surface_state_remove_and_destroy_synced ( cached , synced ) ;
}
void * pending = surface_state_remove_synced ( & surface - > pending , synced ) ;
void * current = surface_state_remove_synced ( & surface - > current , synced ) ;
if ( synced - > impl - > finish_state ) {
synced - > impl - > finish_state ( pending ) ;
synced - > impl - > finish_state ( current ) ;
}
wl_list_remove ( & synced - > link ) ;
synced - > surface - > synced_len - - ;
}
void * wlr_surface_synced_get_state ( struct wlr_surface_synced * synced ,
const struct wlr_surface_state * state ) {
void * * synced_states = state - > synced . data ;
return synced_states [ synced - > index ] ;
}