@ -46,9 +46,11 @@
# include <sys/types.h>
# include <unistd.h>
# include <libweston/matrix.h>
# include "shared/helpers.h"
# include "shared/platform.h"
# include "shared/weston-egl-ext.h"
# include "shared/xalloc.h"
struct window ;
struct seat ;
@ -73,6 +75,8 @@ struct display {
} egl ;
struct window * window ;
struct wl_list output_list ; /* struct output::link */
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage ;
} ;
@ -82,7 +86,13 @@ struct geometry {
struct window {
struct display * display ;
struct geometry buffer_size , window_size ;
struct geometry window_size ;
struct geometry logical_size ;
struct geometry buffer_size ;
int32_t buffer_scale ;
enum wl_output_transform buffer_transform ;
bool needs_buffer_geometry_update ;
struct {
GLuint rotation_uniform ;
GLuint pos ;
@ -97,6 +107,22 @@ struct window {
EGLSurface egl_surface ;
int fullscreen , maximized , opaque , buffer_bpp , frame_sync , delay ;
bool wait_for_configure ;
struct wl_list window_output_list ; /* struct window_output::link */
} ;
struct output {
struct display * display ;
struct wl_output * wl_output ;
uint32_t name ;
struct wl_list link ; /* struct display::output_list */
enum wl_output_transform transform ;
int32_t scale ;
} ;
struct window_output {
struct output * output ;
struct wl_list link ; /* struct window::window_output_list */
} ;
static const char * vert_shader_text =
@ -347,16 +373,13 @@ handle_toplevel_configure(void *data, struct xdg_toplevel *toplevel,
window - > window_size . width = width ;
window - > window_size . height = height ;
}
window - > buffer _size. width = width ;
window - > buffer _size. height = height ;
window - > logical _size. width = width ;
window - > logical _size. height = height ;
} else if ( ! window - > fullscreen & & ! window - > maximized ) {
window - > buffer _size = window - > window_size ;
window - > logical _size = window - > window_size ;
}
if ( window - > native )
wl_egl_window_resize ( window - > native ,
window - > buffer_size . width ,
window - > buffer_size . height , 0 , 0 ) ;
window - > needs_buffer_geometry_update = true ;
}
static void
@ -370,12 +393,80 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_toplevel_close ,
} ;
static void
add_window_output ( struct window * window , struct wl_output * wl_output )
{
struct output * output ;
struct output * output_found = NULL ;
struct window_output * window_output ;
wl_list_for_each ( output , & window - > display - > output_list , link ) {
if ( output - > wl_output = = wl_output ) {
output_found = output ;
break ;
}
}
if ( ! output_found )
return ;
window_output = xmalloc ( sizeof * window_output ) ;
window_output - > output = output_found ;
wl_list_insert ( window - > window_output_list . prev , & window_output - > link ) ;
window - > needs_buffer_geometry_update = true ;
}
static void
destroy_window_output ( struct window * window , struct wl_output * wl_output )
{
struct window_output * window_output ;
struct window_output * window_output_found = NULL ;
wl_list_for_each ( window_output , & window - > window_output_list , link ) {
if ( window_output - > output - > wl_output = = wl_output ) {
window_output_found = window_output ;
break ;
}
}
if ( window_output_found ) {
wl_list_remove ( & window_output_found - > link ) ;
free ( window_output_found ) ;
window - > needs_buffer_geometry_update = true ;
}
}
static void
surface_enter ( void * data ,
struct wl_surface * wl_surface , struct wl_output * wl_output )
{
struct window * window = data ;
add_window_output ( window , wl_output ) ;
}
static void
surface_leave ( void * data ,
struct wl_surface * wl_surface , struct wl_output * wl_output )
{
struct window * window = data ;
destroy_window_output ( window , wl_output ) ;
}
static const struct wl_surface_listener surface_listener = {
surface_enter ,
surface_leave
} ;
static void
create_surface ( struct window * window )
{
struct display * display = window - > display ;
window - > surface = wl_compositor_create_surface ( display - > compositor ) ;
wl_surface_add_listener ( window - > surface , & surface_listener , window ) ;
window - > xdg_surface = xdg_wm_base_get_xdg_surface ( display - > wm_base ,
window - > surface ) ;
@ -422,6 +513,90 @@ destroy_surface(struct window *window)
wl_surface_destroy ( window - > surface ) ;
}
static int32_t
compute_buffer_scale ( struct window * window )
{
struct window_output * window_output ;
int32_t scale = 1 ;
wl_list_for_each ( window_output , & window - > window_output_list , link ) {
if ( window_output - > output - > scale > scale )
scale = window_output - > output - > scale ;
}
return scale ;
}
static enum wl_output_transform
compute_buffer_transform ( struct window * window )
{
struct window_output * window_output ;
enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL ;
wl_list_for_each ( window_output , & window - > window_output_list , link ) {
/* If the surface spans over multiple outputs the optimal
* transform value can be ambiguous . Thus just return the value
* from the oldest entered output .
*/
transform = window_output - > output - > transform ;
break ;
}
return transform ;
}
static void
update_buffer_geometry ( struct window * window )
{
enum wl_output_transform new_buffer_transform ;
int32_t new_buffer_scale ;
struct geometry new_buffer_size ;
new_buffer_transform = compute_buffer_transform ( window ) ;
if ( window - > buffer_transform ! = new_buffer_transform ) {
window - > buffer_transform = new_buffer_transform ;
wl_surface_set_buffer_transform ( window - > surface ,
window - > buffer_transform ) ;
}
new_buffer_scale = compute_buffer_scale ( window ) ;
if ( window - > buffer_scale ! = new_buffer_scale ) {
window - > buffer_scale = new_buffer_scale ;
wl_surface_set_buffer_scale ( window - > surface ,
window - > buffer_scale ) ;
}
switch ( window - > buffer_transform ) {
case WL_OUTPUT_TRANSFORM_NORMAL :
case WL_OUTPUT_TRANSFORM_180 :
case WL_OUTPUT_TRANSFORM_FLIPPED :
case WL_OUTPUT_TRANSFORM_FLIPPED_180 :
new_buffer_size . width = window - > logical_size . width ;
new_buffer_size . height = window - > logical_size . height ;
break ;
case WL_OUTPUT_TRANSFORM_90 :
case WL_OUTPUT_TRANSFORM_270 :
case WL_OUTPUT_TRANSFORM_FLIPPED_90 :
case WL_OUTPUT_TRANSFORM_FLIPPED_270 :
new_buffer_size . width = window - > logical_size . height ;
new_buffer_size . height = window - > logical_size . width ;
break ;
}
new_buffer_size . width * = window - > buffer_scale ;
new_buffer_size . height * = window - > buffer_scale ;
if ( window - > buffer_size . width ! = new_buffer_size . width | |
window - > buffer_size . height ! = new_buffer_size . height ) {
window - > buffer_size = new_buffer_size ;
wl_egl_window_resize ( window - > native ,
window - > buffer_size . width ,
window - > buffer_size . height , 0 , 0 ) ;
}
window - > needs_buffer_geometry_update = false ;
}
static void
redraw ( struct window * window )
{
@ -437,18 +612,16 @@ redraw(struct window *window)
{ 0 , 0 , 1 }
} ;
GLfloat angle ;
GLfloat rotation [ 4 ] [ 4 ] = {
{ 1 , 0 , 0 , 0 } ,
{ 0 , 1 , 0 , 0 } ,
{ 0 , 0 , 1 , 0 } ,
{ 0 , 0 , 0 , 1 }
} ;
struct weston_matrix rotation ;
static const uint32_t speed_div = 5 , benchmark_interval = 5 ;
struct wl_region * region ;
EGLint rect [ 4 ] ;
EGLint buffer_age = 0 ;
struct timeval tv ;
if ( window - > needs_buffer_geometry_update )
update_buffer_geometry ( window ) ;
gettimeofday ( & tv , NULL ) ;
uint32_t time = tv . tv_sec * 1000 + tv . tv_usec / 1000 ;
if ( window - > frames = = 0 )
@ -462,11 +635,42 @@ redraw(struct window *window)
window - > frames = 0 ;
}
angle = ( time / speed_div ) % 360 * M_PI / 180.0 ;
rotation [ 0 ] [ 0 ] = cos ( angle ) ;
rotation [ 0 ] [ 2 ] = sin ( angle ) ;
rotation [ 2 ] [ 0 ] = - sin ( angle ) ;
rotation [ 2 ] [ 2 ] = cos ( angle ) ;
weston_matrix_init ( & rotation ) ;
angle = ( ( time - window - > benchmark_time ) / speed_div ) % 360 * M_PI / 180.0 ;
rotation . d [ 0 ] = cos ( angle ) ;
rotation . d [ 2 ] = sin ( angle ) ;
rotation . d [ 8 ] = - sin ( angle ) ;
rotation . d [ 10 ] = cos ( angle ) ;
switch ( window - > buffer_transform ) {
case WL_OUTPUT_TRANSFORM_FLIPPED :
case WL_OUTPUT_TRANSFORM_FLIPPED_90 :
case WL_OUTPUT_TRANSFORM_FLIPPED_180 :
case WL_OUTPUT_TRANSFORM_FLIPPED_270 :
weston_matrix_scale ( & rotation , - 1 , 1 , 1 ) ;
break ;
default :
break ;
}
switch ( window - > buffer_transform ) {
default :
case WL_OUTPUT_TRANSFORM_NORMAL :
case WL_OUTPUT_TRANSFORM_FLIPPED :
break ;
case WL_OUTPUT_TRANSFORM_90 :
case WL_OUTPUT_TRANSFORM_FLIPPED_90 :
weston_matrix_rotate_xy ( & rotation , 0 , 1 ) ;
break ;
case WL_OUTPUT_TRANSFORM_180 :
case WL_OUTPUT_TRANSFORM_FLIPPED_180 :
weston_matrix_rotate_xy ( & rotation , - 1 , 0 ) ;
break ;
case WL_OUTPUT_TRANSFORM_270 :
case WL_OUTPUT_TRANSFORM_FLIPPED_270 :
weston_matrix_rotate_xy ( & rotation , 0 , - 1 ) ;
break ;
}
if ( display - > swap_buffers_with_damage )
eglQuerySurface ( display - > egl . dpy , window - > egl_surface ,
@ -475,7 +679,7 @@ redraw(struct window *window)
glViewport ( 0 , 0 , window - > buffer_size . width , window - > buffer_size . height ) ;
glUniformMatrix4fv ( window - > gl . rotation_uniform , 1 , GL_FALSE ,
( GLfloat * ) rotation ) ;
( GLfloat * ) rotation . d ) ;
if ( window - > opaque | | window - > fullscreen )
glClearColor ( 0.0 , 0.0 , 0.0 , 1 ) ;
@ -732,6 +936,92 @@ static const struct xdg_wm_base_listener wm_base_listener = {
xdg_wm_base_ping ,
} ;
static void
display_handle_geometry ( void * data ,
struct wl_output * wl_output ,
int32_t x , int32_t y ,
int32_t physical_width ,
int32_t physical_height ,
int32_t subpixel ,
const char * make ,
const char * model ,
int32_t transform )
{
struct output * output = data ;
output - > transform = transform ;
output - > display - > window - > needs_buffer_geometry_update = true ;
}
static void
display_handle_mode ( void * data ,
struct wl_output * wl_output ,
uint32_t flags ,
int32_t width ,
int32_t height ,
int32_t refresh )
{
}
static void
display_handle_done ( void * data ,
struct wl_output * wl_output )
{
}
static void
display_handle_scale ( void * data ,
struct wl_output * wl_output ,
int32_t scale )
{
struct output * output = data ;
output - > scale = scale ;
output - > display - > window - > needs_buffer_geometry_update = true ;
}
static const struct wl_output_listener output_listener = {
display_handle_geometry ,
display_handle_mode ,
display_handle_done ,
display_handle_scale
} ;
static void
display_add_output ( struct display * d , uint32_t name )
{
struct output * output ;
output = xzalloc ( sizeof * output ) ;
output - > display = d ;
output - > scale = 1 ;
output - > wl_output =
wl_registry_bind ( d - > registry , name , & wl_output_interface , 2 ) ;
output - > name = name ;
wl_list_insert ( d - > output_list . prev , & output - > link ) ;
wl_output_add_listener ( output - > wl_output , & output_listener , output ) ;
}
static void
display_destroy_output ( struct display * d , struct output * output )
{
destroy_window_output ( d - > window , output - > wl_output ) ;
wl_output_destroy ( output - > wl_output ) ;
wl_list_remove ( & output - > link ) ;
free ( output ) ;
}
static void
display_destroy_outputs ( struct display * d )
{
struct output * tmp ;
struct output * output ;
wl_list_for_each_safe ( output , tmp , & d - > output_list , link )
display_destroy_output ( d , output ) ;
}
static void
registry_handle_global ( void * data , struct wl_registry * registry ,
uint32_t name , const char * interface , uint32_t version )
@ -765,6 +1055,8 @@ registry_handle_global(void *data, struct wl_registry *registry,
fprintf ( stderr , " unable to load default left pointer \n " ) ;
// TODO: abort ?
}
} else if ( strcmp ( interface , " wl_output " ) = = 0 & & version > = 2 ) {
display_add_output ( d , name ) ;
}
}
@ -772,6 +1064,15 @@ static void
registry_handle_global_remove ( void * data , struct wl_registry * registry ,
uint32_t name )
{
struct display * d = data ;
struct output * output ;
wl_list_for_each ( output , & d - > output_list , link ) {
if ( output - > name = = name ) {
display_destroy_output ( d , output ) ;
break ;
}
}
}
static const struct wl_registry_listener registry_listener = {
@ -813,10 +1114,16 @@ main(int argc, char **argv)
window . buffer_size . width = 250 ;
window . buffer_size . height = 250 ;
window . window_size = window . buffer_size ;
window . buffer_scale = 1 ;
window . buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL ;
window . needs_buffer_geometry_update = false ;
window . buffer_bpp = 0 ;
window . frame_sync = 1 ;
window . delay = 0 ;
wl_list_init ( & display . output_list ) ;
wl_list_init ( & window . window_output_list ) ;
for ( i = 1 ; i < argc ; i + + ) {
if ( strcmp ( " -d " , argv [ i ] ) = = 0 & & i + 1 < argc )
window . delay = atoi ( argv [ + + i ] ) ;
@ -884,6 +1191,8 @@ main(int argc, char **argv)
wl_surface_destroy ( display . cursor_surface ) ;
out_no_xdg_shell :
display_destroy_outputs ( & display ) ;
if ( display . cursor_theme )
wl_cursor_theme_destroy ( display . cursor_theme ) ;