From 0e4452e02a1036e7c85059762cd7b5f5aede1eaa Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 1 Feb 2012 11:31:31 +0200 Subject: [PATCH 1/7] configure: add libpng to client libs http://lists.freedesktop.org/archives/wayland-devel/2012-January/001975.html reports a linking problem: /usr/bin/ld: libtoytoolkit.a(cairo-util.o): undefined reference to symbol 'png_set_filler@@PNG12_0' /usr/bin/ld: note: 'png_set_filler@@PNG12_0' is defined in DSO /usr/lib/i386-linux-gnu/libpng12.so.0 so try adding it to the linker command line /usr/lib/i386-linux-gnu/libpng12.so.0: could not read symbols: Invalid operation collect2: ld returned 1 exit status make[3]: [weston-terminal] Error 1 (ignored) A similar problem is diagnosed here: http://lists.fedoraproject.org/pipermail/devel/2010-March/133601.html As some distros are shipping linkers, that do not resolve symbols from implicitly linked libraries, check and link libpng explicitly. Cc: nerdopolis Signed-off-by: Pekka Paalanen --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7bc9881c..550bb3c8 100644 --- a/configure.ac +++ b/configure.ac @@ -117,7 +117,7 @@ AM_CONDITIONAL(BUILD_CLIENTS, test x$enable_clients == xyes) if test x$enable_clients == xyes; then AC_DEFINE([BUILD_CLIENTS], [1], [Build the Wayland clients]) - PKG_CHECK_MODULES(CLIENT, [wayland-client wayland-egl egl >= 7.10 cairo >= 1.10.0 gdk-pixbuf-2.0 glib-2.0 gobject-2.0 gio-2.0 xkbcommon]) + PKG_CHECK_MODULES(CLIENT, [wayland-client wayland-egl egl >= 7.10 cairo >= 1.10.0 gdk-pixbuf-2.0 glib-2.0 gobject-2.0 gio-2.0 xkbcommon libpng]) PKG_CHECK_MODULES(POPPLER, [poppler-glib], [have_poppler=yes], [have_poppler=no]) From f55f544e4fe1abc5224afda4a96355e6665391cc Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 2 Feb 2012 16:49:05 +0200 Subject: [PATCH 2/7] compositor: fix and simplify shader uniform handling The uniform location variables should be signed, according to the OpenGL ES 2 specification. Moreover, GL_NONE, i.e. 0, is not an invalid nor special location; it is actually used as a valid uniform location. Change struct weston_shader uniform members to signed. Stop using 0 for identifying a non-existing uniform, use -1 instead. Furthermore, as the spec says a) glGetUniformLocation() will return -1 for non-active/existing uniforms, and b) glUniform*() function will simply ignore all calls with location -1, we can simplify the code. We don't have to avoid locating uniforms that don't exist, and we don't need to test for them in weston_surface_draw() either. Remove the micro-optimisation that avoids setting 'alpha' uniform if it has not changed, in the name of simplification. Unify shader creation by dropping init_solid_shader(), and calling weston_shader_init() instead. The downside is that we compile the vertex shader twice at startup now. Signed-off-by: Pekka Paalanen --- src/compositor.c | 57 +++++++----------------------------------------- src/compositor.h | 11 +++++----- 2 files changed, 13 insertions(+), 55 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 1fe90cd0..3a26424d 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -704,21 +704,11 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output) glUniformMatrix4fv(es->shader->proj_uniform, 1, GL_FALSE, output->matrix.d); - - if (es->shader->tex_uniform != GL_NONE) - glUniform1i(es->shader->tex_uniform, 0); - - if (es->shader->color_uniform != GL_NONE) - glUniform4fv(es->shader->color_uniform,1, es->color); - - if (es->shader->alpha_uniform && es->alpha != ec->current_alpha) { - glUniform1f(es->shader->alpha_uniform, es->alpha / 255.0); - ec->current_alpha = es->alpha; - } - - if (es->shader->texwidth_uniform != GL_NONE) - glUniform1f(es->shader->texwidth_uniform, - (GLfloat)es->geometry.width / es->pitch); + glUniform1i(es->shader->tex_uniform, 0); + glUniform4fv(es->shader->color_uniform, 1, es->color); + glUniform1f(es->shader->alpha_uniform, es->alpha / 255.0); + glUniform1f(es->shader->texwidth_uniform, + (GLfloat)es->geometry.width / es->pitch); if (es->transform.enabled) filter = GL_LINEAR; @@ -1849,43 +1839,13 @@ weston_shader_init(struct weston_shader *shader, shader->proj_uniform = glGetUniformLocation(shader->program, "proj"); shader->tex_uniform = glGetUniformLocation(shader->program, "tex"); shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha"); + shader->color_uniform = glGetUniformLocation(shader->program, "color"); shader->texwidth_uniform = glGetUniformLocation(shader->program, "texwidth"); return 0; } -static int -init_solid_shader(struct weston_shader *shader, - GLuint vertex_shader, const char *fragment_source) -{ - GLint status; - char msg[512]; - - shader->vertex_shader = vertex_shader; - shader->fragment_shader = - compile_shader(GL_FRAGMENT_SHADER, fragment_source); - - shader->program = glCreateProgram(); - glAttachShader(shader->program, shader->vertex_shader); - glAttachShader(shader->program, shader->fragment_shader); - glBindAttribLocation(shader->program, 0, "position"); - glBindAttribLocation(shader->program, 1, "texcoord"); - - glLinkProgram(shader->program); - glGetProgramiv(shader->program, GL_LINK_STATUS, &status); - if (!status) { - glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg); - fprintf(stderr, "link info: %s\n", msg); - return -1; - } - - shader->proj_uniform = glGetUniformLocation(shader->program, "proj"); - shader->color_uniform = glGetUniformLocation(shader->program, "color"); - - return 0; -} - WL_EXPORT void weston_output_destroy(struct weston_output *output) { @@ -2060,9 +2020,8 @@ weston_compositor_init(struct weston_compositor *ec, struct wl_display *display) if (weston_shader_init(&ec->texture_shader, vertex_shader, texture_fragment_shader) < 0) return -1; - if (init_solid_shader(&ec->solid_shader, - ec->texture_shader.vertex_shader, - solid_fragment_shader) < 0) + if (weston_shader_init(&ec->solid_shader, + vertex_shader, solid_fragment_shader) < 0) return -1; loop = wl_display_get_event_loop(ec->wl_display); diff --git a/src/compositor.h b/src/compositor.h index 4bc4ba26..5d12d437 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -99,11 +99,11 @@ enum weston_visual { struct weston_shader { GLuint program; GLuint vertex_shader, fragment_shader; - GLuint proj_uniform; - GLuint tex_uniform; - GLuint alpha_uniform; - GLuint color_uniform; - GLuint texwidth_uniform; + GLint proj_uniform; + GLint tex_uniform; + GLint alpha_uniform; + GLint color_uniform; + GLint texwidth_uniform; }; struct weston_animation { @@ -148,7 +148,6 @@ struct weston_compositor { EGLContext context; EGLConfig config; GLuint fbo; - uint32_t current_alpha; struct weston_shader texture_shader; struct weston_shader solid_shader; struct weston_shader *current_shader; From c7b45f68e629dd5f92f10411f97bfa862a7baf5e Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 6 Feb 2012 12:16:07 +0200 Subject: [PATCH 3/7] compositor: clear surface damage on draw Commit a0d6dc4f26c95ae08ffff7d5f1ee7c1f53bdf545 lost one line of code in the refactoring, and so did not reset the surface damage on repaint anymore. This causes damage to only accumulate, leading to a full display redraw every cycle and hiding damage tracking issues. Put the damage clear back. Signed-off-by: Pekka Paalanen --- src/compositor.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compositor.c b/src/compositor.c index 3a26424d..6b15a543 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -681,6 +681,9 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output) &output->region); pixman_region32_intersect(&repaint, &repaint, &es->damage); + /* Clear damage, assume outputs do not overlap. */ + pixman_region32_subtract(&es->damage, &es->damage, &output->region); + if (!pixman_region32_not_empty(&repaint)) goto out; From ddae03cf9bd0012b96be834a3e4797dfe2f1be6f Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 6 Feb 2012 14:54:20 +0200 Subject: [PATCH 4/7] compositor: q&d solution for surface drift When a transformed (rotated) surface is continuously resized from its top-left corner, its location will drift. This is due to accumulating rounding errors in transforming an offset from surface-local to global coordinates in surface_attach(). Diminish the drift down to unobservable level by changing the weston_surface global position from integer to float. The offset transformation is now done without rounding. To preserve the precision, wl_shell::configure() interface must use floats, and so does weston_surface_configure(), too. The con of this patch is that it adds inconsistency to the surface position coordinates: sometimes they are floats, sometimes integers. --- src/compositor.c | 36 +++++++++++++++++++++++------------- src/compositor.h | 6 +++--- src/shell.c | 2 +- src/tablet-shell.c | 2 +- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index 6b15a543..bd5d2e79 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -311,12 +311,10 @@ weston_surface_update_transform(struct weston_surface *surface) &surface->transform.boundingbox); } -WL_EXPORT void -weston_surface_to_global(struct weston_surface *surface, - int32_t sx, int32_t sy, int32_t *x, int32_t *y) +static void +surface_to_global_float(struct weston_surface *surface, + int32_t sx, int32_t sy, GLfloat *x, GLfloat *y) { - weston_surface_update_transform(surface); - if (surface->transform.enabled) { struct weston_vector v = { { sx, sy, 0.0f, 1.0f } }; @@ -331,14 +329,27 @@ weston_surface_to_global(struct weston_surface *surface, return; } - *x = floorf(v.f[0] / v.f[3]); - *y = floorf(v.f[1] / v.f[3]); + *x = v.f[0] / v.f[3]; + *y = v.f[1] / v.f[3]; } else { *x = sx + surface->geometry.x; *y = sy + surface->geometry.y; } } +WL_EXPORT void +weston_surface_to_global(struct weston_surface *surface, + int32_t sx, int32_t sy, int32_t *x, int32_t *y) +{ + GLfloat xf, yf; + + weston_surface_update_transform(surface); + + surface_to_global_float(surface, sx, sy, &xf, &yf); + *x = floorf(xf); + *y = floorf(yf); +} + static void surface_from_global_float(struct weston_surface *surface, int32_t x, int32_t y, GLfloat *sx, GLfloat *sy) @@ -449,7 +460,7 @@ weston_surface_flush_damage(struct weston_surface *surface) WL_EXPORT void weston_surface_configure(struct weston_surface *surface, - int x, int y, int width, int height) + GLfloat x, GLfloat y, int width, int height) { weston_surface_damage_below(surface); @@ -1100,12 +1111,11 @@ surface_attach(struct wl_client *client, } else if (sx != 0 || sy != 0 || es->geometry.width != buffer->width || es->geometry.height != buffer->height) { - int32_t from_x, from_y; - int32_t to_x, to_y; + GLfloat from_x, from_y; + GLfloat to_x, to_y; - /* FIXME: this has serious cumulating rounding errors */ - weston_surface_to_global(es, 0, 0, &from_x, &from_y); - weston_surface_to_global(es, sx, sy, &to_x, &to_y); + surface_to_global_float(es, 0, 0, &from_x, &from_y); + surface_to_global_float(es, sx, sy, &to_x, &to_y); shell->configure(shell, es, es->geometry.x + to_x - from_x, es->geometry.y + to_y - from_y, diff --git a/src/compositor.h b/src/compositor.h index 5d12d437..4495412a 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -128,7 +128,7 @@ struct weston_shell { int32_t width, int32_t height); void (*configure)(struct weston_shell *shell, struct weston_surface *surface, - int32_t x, int32_t y, int32_t width, int32_t height); + GLfloat x, GLfloat y, int32_t width, int32_t height); void (*destroy)(struct weston_shell *shell); }; @@ -228,7 +228,7 @@ struct weston_surface { * That includes the transformations referenced from the list. */ struct { - int32_t x, y; /* surface translation on display */ + GLfloat x, y; /* surface translation on display */ int32_t width, height; /* struct weston_transform */ @@ -372,7 +372,7 @@ weston_surface_create(struct weston_compositor *compositor); void weston_surface_configure(struct weston_surface *surface, - int x, int y, int width, int height); + GLfloat x, GLfloat y, int width, int height); void weston_surface_assign_output(struct weston_surface *surface); diff --git a/src/shell.c b/src/shell.c index d15c8e2d..78120ef5 100644 --- a/src/shell.c +++ b/src/shell.c @@ -1397,7 +1397,7 @@ map(struct weston_shell *base, static void configure(struct weston_shell *base, struct weston_surface *surface, - int32_t x, int32_t y, int32_t width, int32_t height) + GLfloat x, GLfloat y, int32_t width, int32_t height) { struct wl_shell *shell = container_of(base, struct wl_shell, shell); int do_configure = !shell->locked; diff --git a/src/tablet-shell.c b/src/tablet-shell.c index 14ac8895..bcaba161 100644 --- a/src/tablet-shell.c +++ b/src/tablet-shell.c @@ -141,7 +141,7 @@ tablet_shell_map(struct weston_shell *base, struct weston_surface *surface, static void tablet_shell_configure(struct weston_shell *base, struct weston_surface *surface, - int32_t x, int32_t y, + GLfloat x, GLfloat y, int32_t width, int32_t height) { weston_surface_configure(surface, x, y, width, height); From 9f9aa1be50e2b4350dcae1bbfd84a1eddf3bb9ca Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Mon, 6 Feb 2012 16:26:57 +0200 Subject: [PATCH 5/7] compositor: fix transformed opaque surface repainting Computing the real maximal opaque screen aligned rectangle of a transformed surface is hard. Let's drop the opaque optimisation instead. Signed-off-by: Pekka Paalanen --- src/compositor.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compositor.c b/src/compositor.c index bd5d2e79..a74ac30b 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -474,7 +474,8 @@ weston_surface_configure(struct weston_surface *surface, weston_surface_damage(surface); pixman_region32_fini(&surface->opaque); - if (surface->visual == WESTON_RGB_VISUAL) + if (surface->visual == WESTON_RGB_VISUAL && + surface->transform.enabled == 0) pixman_region32_init_rect(&surface->opaque, surface->geometry.x, surface->geometry.y, From 44ab69cfa38bb6d6f0f3e9f8a2658b355f65d67b Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 7 Feb 2012 13:18:00 +0200 Subject: [PATCH 6/7] compositor: add weston_surface transformation doc Signed-off-by: Pekka Paalanen --- src/compositor.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/compositor.h b/src/compositor.h index 4495412a..79449ad9 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -208,6 +208,31 @@ enum weston_output_flags { WL_OUTPUT_FLIPPED = 0x01 }; +/* Using weston_surface transformations + * + * To add a transformation to a surface, create a struct weston_transform, and + * add it to the list surface->geometry.transformation_list. Whenever you + * change the list, anything under surface->geometry, or anything in the + * weston_transforms linked into the list, you must set + * surface->geometry.dirty = 1. + * + * The order in the list defines the order of transformations. Let the list + * contain the transformation matrices M1, ..., Mn as head to tail. The + * transformation is applied to surface-local coordinate vector p as + * P = Mn * ... * M2 * M1 * p + * to produce the global coordinate vector P. The total transform + * Mn * ... * M2 * M1 + * is cached in surface->transform.matrix, and the inverse of it in + * surface->transform.inverse. + * + * The list always contains surface->transform.position transformation, which + * is the translation by surface->geometry.x and y. + * + * If you want to apply a transformation in local coordinates, add your + * weston_transform to the head of the list. If you want to apply a + * transformation in global coordinates, add it to the tail of the list. + */ + struct weston_surface { struct wl_surface surface; struct weston_compositor *compositor; From 938269af211f1ac48c7539fd7feab8e53703ade8 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Tue, 7 Feb 2012 14:19:01 +0200 Subject: [PATCH 7/7] compositor: simple menu transform Transform a menu popup the same as its parent surface. The parent's transformation is snapshotted at the popup map() time, and does not follow further parent motion. Signed-off-by: Pekka Paalanen --- src/shell.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/shell.c b/src/shell.c index 78120ef5..53b192c2 100644 --- a/src/shell.c +++ b/src/shell.c @@ -103,6 +103,7 @@ struct shell_surface { struct wl_grab grab; uint32_t time; int32_t x, y; + struct weston_transform parent_transform; int32_t initial_up; } popup; @@ -521,8 +522,22 @@ shell_map_popup(struct shell_surface *shsurf, uint32_t time) shsurf->popup.grab.interface = &popup_grab_interface; device = es->compositor->input_device; - es->geometry.x = shsurf->parent->surface->geometry.x + shsurf->popup.x; - es->geometry.y = shsurf->parent->surface->geometry.y + shsurf->popup.y; + weston_surface_update_transform(parent); + if (parent->transform.enabled) { + shsurf->popup.parent_transform.matrix = + parent->transform.matrix; + } else { + /* construct x, y translation matrix */ + weston_matrix_init(&shsurf->popup.parent_transform.matrix); + shsurf->popup.parent_transform.matrix.d[12] = + parent->geometry.x; + shsurf->popup.parent_transform.matrix.d[13] = + parent->geometry.y; + } + wl_list_insert(es->geometry.transformation_list.prev, + &shsurf->popup.parent_transform.link); + es->geometry.x = shsurf->popup.x; + es->geometry.y = shsurf->popup.y; es->geometry.dirty = 1; shsurf->popup.grab.input_device = device;