compositor: implement a stack of surface transformations

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 for 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@linux.intel.com>
Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
This commit is contained in:
Pekka Paalanen 2012-01-06 14:10:06 +02:00
parent 804e05185b
commit c61eca6002
3 changed files with 55 additions and 10 deletions

View File

@ -205,7 +205,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;
}
@ -504,7 +505,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];
@ -538,6 +541,34 @@ texture_transformed_surface(struct weston_surface *es)
return 1;
}
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);
}
WL_EXPORT void
weston_surface_draw(struct weston_surface *es, struct weston_output *output)
{
@ -584,12 +615,13 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output)
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);

View File

@ -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;
@ -234,13 +237,20 @@ struct weston_surface {
int32_t pitch;
struct wl_list link;
struct wl_list buffer_link;
struct weston_transform *transform;
struct weston_shader *shader;
GLfloat color[4];
uint32_t alpha;
uint32_t visual;
int overlapped;
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.

View File

@ -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();