[PATCH weston 1/3] compositor: Implement buffer transformation

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Tue Nov 27 07:03:42 PST 2012


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  |   73 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/compositor.h  |    8 ++++++
 src/gl-renderer.c |   62 ++++++++++++++++++++++++++++++++++++++++++---
 src/shell.c       |   34 +++++++++++++++----------
 4 files changed, 156 insertions(+), 21 deletions(-)

diff --git a/src/compositor.c b/src/compositor.c
index 6eb0b8c..44cd4a8 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -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
diff --git a/src/compositor.h b/src/compositor.h
index e770664..9e6355d 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -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,
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 249efbc..5824765 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -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");
 	}
diff --git a/src/shell.c b/src/shell.c
index 6bd89ec..89d7627 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -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
-- 
1.7.10.4



More information about the wayland-devel mailing list