[PATCH] compositor: implement a stack of surface transformations

Pekka Paalanen ppaalanen at gmail.com
Fri Jan 6 04:23:01 PST 2012


Having at most one transformation object attached to a surface is not
enough anymore. If we have a surface that needs to be scaled to
fullscreen, and then we have the zoom animation, we already need two
transformations combined.

Implement support multiple transformations by adding a transformation
list. The final transformation is the ordered composite of those in the
list. To avoid traversing the list every single time, add a dirty flag,
and cache the final transformation.

The existing transformation users (only zoom) are converted.

Note: surface drawing should honour all kinds of transformations, but
not damage region code nor input event translating code take
transformations into account, AFAICT. Therefore anything but translation
will probably behave badly until they are fixed.

Cc: Juan Zhao <juan.j.zhao at linux.intel.com>
Signed-off-by: Pekka Paalanen <ppaalanen at gmail.com>
---
 src/compositor.c |   47 ++++++++++++++++++++++++++++++++++++++++-------
 src/compositor.h |   12 +++++++++++-
 src/util.c       |    9 ++++++---
 3 files changed, 57 insertions(+), 11 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 2627987..4d332d0 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -238,7 +238,8 @@ weston_surface_create(struct weston_compositor *compositor,
 
 	surface->buffer_destroy_listener.func = surface_handle_buffer_destroy;
 
-	surface->transform = NULL;
+	wl_list_init(&surface->transform.list);
+	surface->transform.dirty = 1;
 
 	return surface;
 }
@@ -487,7 +488,9 @@ transform_vertex(struct weston_surface *surface,
 	t.f[2] = 0.0;
 	t.f[3] = 1.0;
 
-	weston_matrix_transform(&surface->transform->matrix, &t);
+	weston_matrix_transform(&surface->transform.cached.matrix, &t);
+
+	/* XXX: assumes last row of matrix is [0 0 * 1] */
 
 	r[ 0] = t.f[0];
 	r[ 1] = t.f[1];
@@ -522,6 +525,34 @@ texture_transformed_surface(struct weston_surface *es)
 }
 
 static void
+weston_surface_update_transform(struct weston_surface *surface)
+{
+	struct weston_matrix *matrix = &surface->transform.cached.matrix;
+	struct weston_matrix *inverse = &surface->transform.cached.inverse;
+	struct weston_transform *tform;
+
+	if (!surface->transform.dirty)
+		return;
+
+	surface->transform.dirty = 0;
+
+	if (wl_list_empty(&surface->transform.list)) {
+		surface->transform.enabled = 0;
+		return;
+	}
+
+	surface->transform.enabled = 1;
+
+	weston_matrix_init(matrix);
+	wl_list_for_each(tform, &surface->transform.list, link)
+		weston_matrix_multiply(matrix, &tform->matrix);
+
+	weston_matrix_init(inverse);
+	wl_list_for_each_reverse(tform, &surface->transform.list, link)
+		weston_matrix_multiply(inverse, &tform->inverse);
+}
+
+static void
 weston_surface_draw(struct weston_surface *es,
 		  struct weston_output *output, pixman_region32_t *clip)
 {
@@ -560,12 +591,13 @@ weston_surface_draw(struct weston_surface *es,
 		ec->current_alpha = es->alpha;
 	}
 
-	if (es->transform == NULL) {
-		filter = GL_NEAREST;
-		n = texture_region(es, &repaint);
-	} else {
+	weston_surface_update_transform(es);
+	if (es->transform.enabled) {
 		filter = GL_LINEAR;
 		n = texture_transformed_surface(es);
+	} else {
+		filter = GL_NEAREST;
+		n = texture_region(es, &repaint);
 	}
 
 	glBindTexture(GL_TEXTURE_2D, es->texture);
@@ -668,7 +700,8 @@ fade_output(struct weston_output *output,
 	surface.width = output->current->width;
 	surface.height = output->current->height;
 	surface.texture = GL_NONE;
-	surface.transform = NULL;
+	wl_list_init(&surface.transform.list);
+	surface.transform.dirty = 1;
 	surface.alpha = compositor->current_alpha;
 
 	if (tint <= 1.0)
diff --git a/src/compositor.h b/src/compositor.h
index f6c87da..dfee97c 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -43,6 +43,8 @@ struct weston_vector {
 void
 weston_matrix_init(struct weston_matrix *matrix);
 void
+weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n);
+void
 weston_matrix_scale(struct weston_matrix *matrix, GLfloat x, GLfloat y, GLfloat z);
 void
 weston_matrix_translate(struct weston_matrix *matrix,
@@ -53,6 +55,7 @@ weston_matrix_transform(struct weston_matrix *matrix, struct weston_vector *v);
 struct weston_transform {
 	struct weston_matrix matrix;
 	struct weston_matrix inverse;
+	struct wl_list link;
 };
 
 struct weston_surface;
@@ -256,10 +259,17 @@ struct weston_surface {
 	int32_t pitch;
 	struct wl_list link;
 	struct wl_list buffer_link;
-	struct weston_transform *transform;
 	uint32_t alpha;
 	uint32_t visual;
 
+	struct {
+		struct wl_list list;
+		int dirty;
+
+		struct weston_transform cached;
+		int enabled;
+	} transform;
+
 	/*
 	 * Which output to vsync this surface to.
 	 * Used to determine, whether to send or queue frame events.
diff --git a/src/util.c b/src/util.c
index 99dc09e..4faa8b4 100644
--- a/src/util.c
+++ b/src/util.c
@@ -37,7 +37,7 @@ weston_matrix_init(struct weston_matrix *matrix)
 	memcpy(matrix, &identity, sizeof identity);
 }
 
-static void
+WL_EXPORT void
 weston_matrix_multiply(struct weston_matrix *m, const struct weston_matrix *n)
 {
 	struct weston_matrix tmp;
@@ -162,7 +162,8 @@ weston_zoom_destroy(struct weston_zoom *zoom)
 {
 	wl_list_remove(&zoom->animation.link);
 	wl_list_remove(&zoom->listener.link);
-	zoom->surface->transform = NULL;
+	wl_list_remove(&zoom->transform.link);
+	zoom->surface->transform.dirty = 1;
 	if (zoom->done)
 		zoom->done(zoom, zoom->data);
 	free(zoom);
@@ -212,6 +213,8 @@ weston_zoom_frame(struct weston_animation *animation,
 	weston_matrix_init(&zoom->transform.inverse);
 	weston_matrix_scale(&zoom->transform.inverse, scale, scale, scale);
 
+	zoom->surface->transform.dirty = 1;
+
 	weston_compositor_damage_all(es->compositor);
 }
 
@@ -230,7 +233,7 @@ weston_zoom_run(struct weston_surface *surface, GLfloat start, GLfloat stop,
 	zoom->data = data;
 	zoom->start = start;
 	zoom->stop = stop;
-	surface->transform = &zoom->transform;
+	wl_list_insert(&surface->transform.list, &zoom->transform.link);
 	weston_spring_init(&zoom->spring, 200.0, 0.0, 1.0);
 	zoom->spring.friction = 700;
 	zoom->spring.timestamp = weston_compositor_get_time();
-- 
1.7.3.4



More information about the wayland-devel mailing list