compositor: Implement buffer transformation
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Tue, 27 Nov 2012 15:03:42 +0000 (17:03 +0200)
committerKristian Høgsberg <krh@bitplanet.net>
Tue, 27 Nov 2012 16:29:31 +0000 (11:29 -0500)
Implement the wl_surface.set_buffer_transform request. This includes
tracking the double-buffered buffer transformation parameter and making
the gl renderer able to handle transformed buffers.

src/compositor.c
src/compositor.h
src/gl-renderer.c
src/shell.c

index 6eb0b8c..44cd4a8 100644 (file)
@@ -245,6 +245,8 @@ weston_surface_create(struct weston_compositor *compositor)
        pixman_region32_init(&surface->texture_damage);
 
        surface->buffer = NULL;
+       surface->buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
+       surface->pending.buffer_transform = surface->buffer_transform;
        surface->output = NULL;
        surface->plane = &compositor->primary_plane;
 
@@ -653,6 +655,34 @@ weston_surface_is_mapped(struct weston_surface *surface)
                return 0;
 }
 
+WL_EXPORT int32_t
+weston_surface_buffer_width(struct weston_surface *surface)
+{
+       switch (surface->buffer_transform) {
+       case WL_OUTPUT_TRANSFORM_90:
+       case WL_OUTPUT_TRANSFORM_270:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               return surface->buffer->height;
+       default:
+               return surface->buffer->width;
+       }
+}
+
+WL_EXPORT int32_t
+weston_surface_buffer_height(struct weston_surface *surface)
+{
+       switch (surface->buffer_transform) {
+       case WL_OUTPUT_TRANSFORM_90:
+       case WL_OUTPUT_TRANSFORM_270:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               return surface->buffer->width;
+       default:
+               return surface->buffer->height;
+       }
+}
+
 WL_EXPORT uint32_t
 weston_compositor_get_time(void)
 {
@@ -1237,6 +1267,31 @@ surface_set_input_region(struct wl_client *client,
        }
 }
 
+static int
+surface_pending_buffer_has_different_size(struct weston_surface *surface)
+{
+       int width, height;
+
+       switch (surface->pending.buffer_transform) {
+       case WL_OUTPUT_TRANSFORM_90:
+       case WL_OUTPUT_TRANSFORM_270:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               height = surface->pending.buffer->width;
+               width = surface->pending.buffer->height;
+               break;
+       default:
+               width = surface->pending.buffer->width;
+               height = surface->pending.buffer->height;
+       }
+
+       if (width == surface->geometry.width &&
+           height == surface->geometry.height)
+               return 0;
+       else
+               return 1;
+}
+
 static void
 surface_commit(struct wl_client *client, struct wl_resource *resource)
 {
@@ -1245,10 +1300,12 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
 
        if (surface->pending.sx || surface->pending.sy ||
            (surface->pending.buffer &&
-            (surface->pending.buffer->width != surface->geometry.width ||
-             surface->pending.buffer->height != surface->geometry.height)))
+            surface_pending_buffer_has_different_size(surface)))
                surface->geometry.dirty = 1;
 
+       /* wl_surface.set_buffer_rotation */
+       surface->buffer_transform = surface->pending.buffer_transform;
+
        /* wl_surface.attach */
        if (surface->pending.buffer || surface->pending.remove_contents)
                weston_surface_attach(surface, surface->pending.buffer);
@@ -1298,6 +1355,15 @@ surface_commit(struct wl_client *client, struct wl_resource *resource)
        weston_surface_schedule_repaint(surface);
 }
 
+static void
+surface_set_buffer_transform(struct wl_client *client,
+                            struct wl_resource *resource, int transform)
+{
+       struct weston_surface *surface = resource->data;
+
+       surface->pending.buffer_transform = transform;
+}
+
 static const struct wl_surface_interface surface_interface = {
        surface_destroy,
        surface_attach,
@@ -1305,7 +1371,8 @@ static const struct wl_surface_interface surface_interface = {
        surface_frame,
        surface_set_opaque_region,
        surface_set_input_region,
-       surface_commit
+       surface_commit,
+       surface_set_buffer_transform
 };
 
 static void
index e770664..9e6355d 100644 (file)
@@ -437,6 +437,7 @@ struct weston_surface {
 
        struct wl_buffer *buffer;
        struct wl_listener buffer_destroy_listener;
+       uint32_t buffer_transform;
 
        /* All the pending state, that wl_surface.commit will apply. */
        struct {
@@ -458,6 +459,9 @@ struct weston_surface {
 
                /* wl_surface.frame */
                struct wl_list frame_callback_list;
+
+               /* wl_surface.set_buffer_transform */
+               uint32_t buffer_transform;
        } pending;
 
        /*
@@ -495,6 +499,10 @@ void
 weston_surface_from_global_fixed(struct weston_surface *surface,
                                 wl_fixed_t x, wl_fixed_t y,
                                 wl_fixed_t *sx, wl_fixed_t *sy);
+int32_t
+weston_surface_buffer_width(struct weston_surface *surface);
+int32_t
+weston_surface_buffer_height(struct weston_surface *surface);
 
 void
 weston_spring_init(struct weston_spring *spring,
index 10477d3..c2fdaa3 100644 (file)
@@ -517,6 +517,47 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
        return n;
 }
 
+static void
+transform_texcoord(struct weston_surface *es, GLfloat sx, GLfloat sy,
+                  GLfloat *tx, GLfloat *ty)
+{
+       switch(es->buffer_transform) {
+       case WL_OUTPUT_TRANSFORM_NORMAL:
+       default:
+               *tx = sx;
+               *ty = sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+               *tx = 1.0 - sx;
+               *ty = sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_90:
+               *tx = 1.0 - sy;
+               *ty = sx;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+               *tx = 1.0 - sy;
+               *ty = 1.0 - sx;
+               break;
+       case WL_OUTPUT_TRANSFORM_180:
+               *tx = 1.0 - sx;
+               *ty = 1.0 - sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+               *tx = sx;
+               *ty = 1.0 - sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_270:
+               *tx = sy;
+               *ty = 1.0 - sx;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               *tx = sy;
+               *ty = sx;
+               break;
+       }
+}
+
 static int
 texture_region(struct weston_surface *es, pixman_region32_t *region,
                pixman_region32_t *surf_region)
@@ -543,7 +584,7 @@ texture_region(struct weston_surface *es, pixman_region32_t *region,
                pixman_box32_t *rect = &rects[i];
                for (j = 0; j < nsurf; j++) {
                        pixman_box32_t *surf_rect = &surf_rects[j];
-                       GLfloat sx, sy;
+                       GLfloat sx, sy, tx, ty;
                        GLfloat ex[8], ey[8];          /* edge points in screen space */
                        int n;
 
@@ -572,8 +613,12 @@ texture_region(struct weston_surface *es, pixman_region32_t *region,
                                *(v++) = ex[k];
                                *(v++) = ey[k];
                                /* texcoord: */
-                               *(v++) = sx * inv_width;
-                               *(v++) = sy * inv_height;
+                               transform_texcoord(es,
+                                                  sx * inv_width,
+                                                  sy * inv_height,
+                                                  &tx, &ty);
+                               *(v++) = tx;
+                               *(v++) = ty;
                        }
 
                        vtxcnt[nvtx++] = n;
@@ -1183,7 +1228,16 @@ gl_renderer_attach(struct weston_surface *es, struct wl_buffer *buffer)
                                                    gs->images[i]);
                }
 
-               es->pitch = buffer->width;
+               switch(es->buffer_transform) {
+               case WL_OUTPUT_TRANSFORM_90:
+               case WL_OUTPUT_TRANSFORM_270:
+               case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+               case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+                       es->pitch = buffer->height;
+                       break;
+               default:
+                       es->pitch = buffer->width;
+               }
        } else {
                weston_log("unhandled buffer type!\n");
        }
index 6bd89ec..89d7627 100644 (file)
@@ -2129,7 +2129,8 @@ configure_static_surface(struct weston_surface *es, struct weston_layer *layer)
        }
 
        weston_surface_configure(es, es->output->x, es->output->y,
-                                es->buffer->width, es->buffer->height);
+                                weston_surface_buffer_width(es),
+                                weston_surface_buffer_height(es));
 
        if (wl_list_empty(&es->layer_link)) {
                wl_list_insert(&layer->surface_list, &es->layer_link);
@@ -2815,12 +2816,14 @@ hide_input_panels(struct wl_listener *listener, void *data)
 static void
 center_on_output(struct weston_surface *surface, struct weston_output *output)
 {
-       float x = (output->width - surface->buffer->width) / 2;
-       float y = (output->height - surface->buffer->height) / 2;
+       int32_t width = weston_surface_buffer_width(surface);
+       int32_t height = weston_surface_buffer_height(surface);
+       float x, y;
 
-       weston_surface_configure(surface, output->x + x, output->y + y,
-                                surface->buffer->width,
-                                surface->buffer->height);
+       x = output->x + (output->width - width) / 2;
+       y = output->y + (output->height - height) / 2;
+
+       weston_surface_configure(surface, x, y, width, height);
 }
 
 static void
@@ -3029,6 +3032,8 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
 {
        struct shell_surface *shsurf = get_shell_surface(es);
        struct desktop_shell *shell = shsurf->shell;
+       int32_t width = weston_surface_buffer_width(es);
+       int32_t height = weston_surface_buffer_height(es);
        int type_changed = 0;
 
        if (shsurf->next_type != SHELL_SURFACE_NONE &&
@@ -3038,10 +3043,10 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
        }
 
        if (!weston_surface_is_mapped(es)) {
-               map(shell, es, es->buffer->width, es->buffer->height, sx, sy);
+               map(shell, es, width, height, sx, sy);
        } else if (type_changed || sx != 0 || sy != 0 ||
-                  es->geometry.width != es->buffer->width ||
-                  es->geometry.height != es->buffer->height) {
+                  es->geometry.width != width ||
+                  es->geometry.height != height) {
                float from_x, from_y;
                float to_x, to_y;
 
@@ -3050,7 +3055,7 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
                configure(shell, es,
                          es->geometry.x + to_x - from_x,
                          es->geometry.y + to_y - from_y,
-                         es->buffer->width, es->buffer->height);
+                         width, height);
        }
 }
 
@@ -3216,8 +3221,10 @@ static void
 input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
 {
        struct weston_mode *mode = surface->output->current;
-       float x = (mode->width - surface->buffer->width) / 2;
-       float y = mode->height - surface->buffer->height;
+       int32_t width = weston_surface_buffer_width(surface);
+       int32_t height = weston_surface_buffer_height(surface);
+       float x = (mode->width - width) / 2;
+       float y = mode->height - height;
 
        /* Don't map the input panel here, wait for
         * show_input_panels signal. */
@@ -3225,8 +3232,7 @@ input_panel_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
        weston_surface_configure(surface,
                                 surface->output->x + x,
                                 surface->output->y + y,
-                                surface->buffer->width,
-                                surface->buffer->height);
+                                width, height);
 }
 
 static void