[RFC] [PATCH weston v2] Implement output transformations.

Kristian Høgsberg hoegsberg at gmail.com
Thu Aug 16 09:51:51 PDT 2012


On Thu, Aug 16, 2012 at 02:33:06AM -0600, Scott Moreau wrote:
> This patch allows rotation and mirroring outputs for x11 and drm backends.
> A new 'transform' key can be set in the [output] section. From the protocol:
> 
> "The flipped values correspond to an initial flip around a vertical axis
> followed by rotation."
> 
> The transform key can be one of the following 8 strings:

This is looking quite good now.  I hit a problem though where I
couldn't get the drm transform to work, and it turns out that we
reject the output section if there is no mode key.  Now that we have a
transform key, we should also accept something like just:

	[output]
	name=LVDS1
	transform=90

I'm also thinking that the output section parsing is now complex and
identical enough between x11 and drm that we should share it.  Let's
do that after we land this output transform patch though.

> normal
> 90
> 180
> 270
> flipped
> flipped-90
> flipped-180
> flipped-270
> 
> ---
> 
> Changed in v2:
> 
> - x11 output position corrected.
> - Fix usage of disable_planes.
> 
>  src/compositor-android.c |   3 +-
>  src/compositor-drm.c     |  79 ++++++++++++-----
>  src/compositor-wayland.c |   3 +-
>  src/compositor-x11.c     | 217 ++++++++++++++++++++++++++++++++++++-----------
>  src/compositor.c         | 113 +++++++++++++++++++++++-
>  src/compositor.h         |   2 +-
>  weston.ini               |   3 +
>  7 files changed, 341 insertions(+), 79 deletions(-)
> 
> diff --git a/src/compositor-android.c b/src/compositor-android.c
> index a9c45d2..b095262 100644
> --- a/src/compositor-android.c
> +++ b/src/compositor-android.c
> @@ -238,7 +238,8 @@ android_compositor_add_output(struct android_compositor *compositor,
>  	mm_width  = output->fb->width / output->fb->xdpi * 25.4f;
>  	mm_height = output->fb->height / output->fb->ydpi * 25.4f;
>  	weston_output_init(&output->base, &compositor->base,
> -			   0, 0, round(mm_width), round(mm_height));
> +			   0, 0, round(mm_width), round(mm_height),
> +			   WL_OUTPUT_TRANSFORM_NORMAL);
>  	wl_list_insert(compositor->base.output_list.prev, &output->base.link);
>  }
>  
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index 8c8c8c0..0911894 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -46,6 +46,7 @@
>  static int option_current_mode = 0;
>  static char *output_name;
>  static char *output_mode;
> +static char *output_transform;
>  static struct wl_list configured_output_list;
>  
>  enum output_config {
> @@ -60,6 +61,7 @@ enum output_config {
>  struct drm_configured_output {
>  	char *name;
>  	char *mode;
> +	uint32_t transform;
>  	int32_t width, height;
>  	drmModeModeInfo crtc_mode;
>  	enum output_config config;
> @@ -1528,7 +1530,8 @@ create_output_for_connector(struct drm_compositor *ec,
>  	}
>  
>  	weston_output_init(&output->base, &ec->base, x, y,
> -			   connector->mmWidth, connector->mmHeight);
> +			   connector->mmWidth, connector->mmHeight,
> +			   o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);
>  
>  	wl_list_insert(ec->base.output_list.prev, &output->base.link);
>  
> @@ -2066,14 +2069,6 @@ evdev_input_destroy(struct weston_seat *seat_base)
>  }
>  
>  static void
> -drm_free_configured_output(struct drm_configured_output *output)
> -{
> -	free(output->name);
> -	free(output->mode);
> -	free(output);
> -}

I'm not sure why this is in here... now we're leaking output->name and
output->mode.  Let's not change the memory management of this struct
as part of the output transform path.

> -
> -static void
>  drm_destroy(struct weston_compositor *ec)
>  {
>  	struct drm_compositor *d = (struct drm_compositor *) ec;
> @@ -2083,7 +2078,7 @@ drm_destroy(struct weston_compositor *ec)
>  	wl_list_for_each_safe(seat, next, &ec->seat_list, link)
>  		evdev_input_destroy(seat);
>  	wl_list_for_each_safe(o, n, &configured_output_list, link)
> -		drm_free_configured_output(o);
> +		free(o);
>  
>  	wl_event_source_remove(d->udev_drm_source);
>  	wl_event_source_remove(d->drm_source);
> @@ -2412,23 +2407,52 @@ check_for_modeline(struct drm_configured_output *output)
>  }
>  
>  static void
> +output_set_transform(struct drm_configured_output *output)
> +{
> +	if (!output_transform) {
> +		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +		return;
> +	}
> +
> +	if (!strcmp(output_transform, "normal"))
> +		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +	else if (!strcmp(output_transform, "90"))
> +		output->transform = WL_OUTPUT_TRANSFORM_90;
> +	else if (!strcmp(output_transform, "180"))
> +		output->transform = WL_OUTPUT_TRANSFORM_180;
> +	else if (!strcmp(output_transform, "270"))
> +		output->transform = WL_OUTPUT_TRANSFORM_270;
> +	else if (!strcmp(output_transform, "flipped"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
> +	else if (!strcmp(output_transform, "flipped-90"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
> +	else if (!strcmp(output_transform, "flipped-180"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
> +	else if (!strcmp(output_transform, "flipped-270"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
> +	else {
> +		weston_log("Invalid transform \"%s\" for output %s\n",
> +						output_transform, output_name);
> +		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +	}
> +}
> +
> +static void
>  output_section_done(void *data)
>  {
>  	struct drm_configured_output *output;
>  
>  	output = malloc(sizeof *output);
>  
> -	if (!output || !output_name || !output_mode) {
> -		free(output_name);
> -		output_name = NULL;
> -		free(output_mode);
> -		output_mode = NULL;
> -		return;
> -	}
> +	if (!output || !output_name || !output_mode)

This should be 

	(!output || !output_name || (!output_mode && !output_transform))

to allow output section with just a transform key.

> +		goto err_free;
> +
> +	if (output_name[0] == 'X')
> +		goto err_free;
>  
>  	output->config = OUTPUT_CONFIG_INVALID;
> -	output->name = output_name;
> -	output->mode = output_mode;
> +	output->name = strdup(output_name);
> +	output->mode = strdup(output_mode);
>  
>  	if (strcmp(output_mode, "off") == 0)
>  		output->config = OUTPUT_CONFIG_OFF;
> @@ -2441,13 +2465,21 @@ output_section_done(void *data)
>  	else if (check_for_modeline(output) == 0)
>  		output->config = OUTPUT_CONFIG_MODELINE;
>  
> -	if (output->config != OUTPUT_CONFIG_INVALID)
> -		wl_list_insert(&configured_output_list, &output->link);
> -	else {
> +	if (output->config == OUTPUT_CONFIG_INVALID) {
>  		weston_log("Invalid mode \"%s\" for output %s\n",
>  						output_mode, output_name);
> -		drm_free_configured_output(output);
> +		goto err_free;
>  	}
> +
> +	output_set_transform(output);
> +
> +	wl_list_insert(&configured_output_list, &output->link);
> +
> +err_free:
> +	free(output_name);
> +	output_name = NULL;
> +	free(output_mode);
> +	output_mode = NULL;
>  }
>  
>  WL_EXPORT struct weston_compositor *
> @@ -2471,6 +2503,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
>  	const struct config_key drm_config_keys[] = {
>  		{ "name", CONFIG_KEY_STRING, &output_name },
>  		{ "mode", CONFIG_KEY_STRING, &output_mode },
> +		{ "transform", CONFIG_KEY_STRING, &output_transform },
>  	};
>  
>  	const struct config_section config_section[] = {
> diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
> index 4fc77f1..84eaf6c 100644
> --- a/src/compositor-wayland.c
> +++ b/src/compositor-wayland.c
> @@ -395,7 +395,8 @@ wayland_compositor_create_output(struct wayland_compositor *c,
>  	wl_list_insert(&output->base.mode_list, &output->mode.link);
>  
>  	output->base.current = &output->mode;
> -	weston_output_init(&output->base, &c->base, 0, 0, width, height);
> +	weston_output_init(&output->base, &c->base, 0, 0, width, height,
> +						WL_OUTPUT_TRANSFORM_NORMAL);
>  
>  	output->base.border.top = c->border.top;
>  	output->base.border.bottom = c->border.bottom;
> diff --git a/src/compositor-x11.c b/src/compositor-x11.c
> index c02911d..1f22286 100644
> --- a/src/compositor-x11.c
> +++ b/src/compositor-x11.c
> @@ -52,6 +52,7 @@
>  
>  static char *output_name;
>  static char *output_mode;
> +static char *output_transform;
>  static int option_width;
>  static int option_height;
>  static int option_count;
> @@ -60,6 +61,7 @@ static struct wl_list configured_output_list;
>  struct x11_configured_output {
>  	char *name;
>  	int width, height;
> +	uint32_t transform;
>  	struct wl_list link;
>  };
>  
> @@ -474,9 +476,12 @@ x11_output_set_icon(struct x11_compositor *c,
>  static int
>  x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>  			     int width, int height, int fullscreen,
> -			     int no_input, const char *name)
> +			     int no_input, char *configured_name,
> +			     uint32_t transform)
>  {
> +	static const char name[] = "Weston Compositor";
>  	static const char class[] = "weston-1\0Weston Compositor";
> +	char title[32];
>  	struct x11_output *output;
>  	xcb_screen_iterator_t iter;
>  	struct wm_normal_hints normal_hints;
> @@ -488,6 +493,11 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>  		0
>  	};
>  
> +	if (configured_name)
> +		sprintf(title, "%s - %s", name, configured_name);
> +	else
> +		strcpy(title, name);
> +
>  	if (!no_input)
>  		values[0] |=
>  			XCB_EVENT_MASK_KEY_PRESS |
> @@ -517,7 +527,8 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>  	output->base.current = &output->mode;
>  	output->base.make = "xwayland";
>  	output->base.model = "none";
> -	weston_output_init(&output->base, &c->base, x, y, width, height);
> +	weston_output_init(&output->base, &c->base, x, y, width, height,
> +								transform);
>  
>  	values[1] = c->null_cursor;
>  	output->window = xcb_generate_id(c->conn);
> @@ -550,7 +561,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
>  	/* Set window name.  Don't bother with non-EWMH WMs. */
>  	xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
>  			    c->atom.net_wm_name, c->atom.utf8_string, 8,
> -			    strlen(name), name);
> +			    strlen(title), title);
>  	xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,
>  			    c->atom.wm_class, c->atom.string, 8,
>  			    sizeof class, class);
> @@ -739,6 +750,98 @@ x11_compositor_deliver_button_event(struct x11_compositor *c,
>  			      WL_POINTER_BUTTON_STATE_RELEASED);
>  }
>  
> +static void
> +x11_output_transform_coordinate(struct x11_output *x11_output,
> +						wl_fixed_t *x, wl_fixed_t *y)
> +{
> +	struct weston_output *output = &x11_output->base;
> +	wl_fixed_t tx, ty;
> +	wl_fixed_t width = wl_fixed_from_int(output->current->width - 1);
> +	wl_fixed_t height = wl_fixed_from_int(output->current->height - 1);
> +
> +	switch(output->transform) {
> +	case WL_OUTPUT_TRANSFORM_NORMAL:
> +	default:
> +		tx = *x;
> +		ty = *y;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_90:
> +		tx = *y;
> +		ty = height - *x;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_180:
> +		tx = width - *x;
> +		ty = height - *y;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_270:
> +		tx = width - *y;
> +		ty = *x;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_FLIPPED:
> +		tx = width - *x;
> +		ty = *y;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
> +		tx = width - *y;
> +		ty = height - *x;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
> +		tx = *x;
> +		ty = height - *y;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
> +		tx = *y;
> +		ty = *x;
> +		break;
> +	}

This looks much better now.

> +	tx += wl_fixed_from_int(output->x);
> +	ty += wl_fixed_from_int(output->y);
> +
> +	*x = tx;
> +	*y = ty;
> +}
> +
> +static void
> +x11_compositor_deliver_motion_event(struct x11_compositor *c,
> +					xcb_generic_event_t *event)
> +{
> +	struct x11_output *output;
> +	wl_fixed_t x, y;
> +	xcb_motion_notify_event_t *motion_notify =
> +			(xcb_motion_notify_event_t *) event;
> +
> +	if (!c->has_xkb)
> +		update_xkb_state_from_core(c, motion_notify->state);
> +	output = x11_compositor_find_output(c, motion_notify->event);
> +	x = wl_fixed_from_int(motion_notify->event_x);
> +	y = wl_fixed_from_int(motion_notify->event_y);
> +	x11_output_transform_coordinate(output, &x, &y);
> +
> +	notify_motion(&c->core_seat, weston_compositor_get_time(), x, y);
> +}
> +
> +static void
> +x11_compositor_deliver_enter_event(struct x11_compositor *c,
> +					xcb_generic_event_t *event)
> +{
> +	struct x11_output *output;
> +	wl_fixed_t x, y;
> +
> +	xcb_enter_notify_event_t *enter_notify =
> +			(xcb_enter_notify_event_t *) event;
> +	if (enter_notify->state >= Button1Mask)
> +		return;
> +	if (!c->has_xkb)
> +		update_xkb_state_from_core(c, enter_notify->state);
> +	output = x11_compositor_find_output(c, enter_notify->event);
> +	x = wl_fixed_from_int(enter_notify->event_x);
> +	y = wl_fixed_from_int(enter_notify->event_y);
> +	x11_output_transform_coordinate(output, &x, &y);
> +
> +	notify_pointer_focus(&c->core_seat, &output->base, x, y);
> +}
> +
>  static int
>  x11_compositor_next_event(struct x11_compositor *c,
>  			  xcb_generic_event_t **event, uint32_t mask)
> @@ -763,7 +866,6 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
>  	struct x11_output *output;
>  	xcb_generic_event_t *event, *prev;
>  	xcb_client_message_event_t *client_message;
> -	xcb_motion_notify_event_t *motion_notify;
>  	xcb_enter_notify_event_t *enter_notify;
>  	xcb_key_press_event_t *key_press, *key_release;
>  	xcb_keymap_notify_event_t *keymap_notify;
> @@ -772,7 +874,6 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
>  	xcb_atom_t atom;
>  	uint32_t *k;
>  	uint32_t i, set;
> -	wl_fixed_t x, y;
>  	int count;
>  
>  	prev = NULL;
> @@ -872,14 +973,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
>  			x11_compositor_deliver_button_event(c, event, 0);
>  			break;
>  		case XCB_MOTION_NOTIFY:
> -			motion_notify = (xcb_motion_notify_event_t *) event;
> -			if (!c->has_xkb)
> -				update_xkb_state_from_core(c, motion_notify->state);
> -			output = x11_compositor_find_output(c, motion_notify->event);
> -			x = wl_fixed_from_int(output->base.x + motion_notify->event_x);
> -			y = wl_fixed_from_int(output->base.y + motion_notify->event_y);
> -			notify_motion(&c->core_seat,
> -				      weston_compositor_get_time(), x, y);
> +			x11_compositor_deliver_motion_event(c, event);
>  			break;
>  
>  		case XCB_EXPOSE:
> @@ -889,17 +983,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
>  			break;
>  
>  		case XCB_ENTER_NOTIFY:
> -			enter_notify = (xcb_enter_notify_event_t *) event;
> -			if (enter_notify->state >= Button1Mask)
> -				break;
> -			if (!c->has_xkb)
> -				update_xkb_state_from_core(c, enter_notify->state);
> -			output = x11_compositor_find_output(c, enter_notify->event);
> -			x = wl_fixed_from_int(output->base.x + enter_notify->event_x);
> -			y = wl_fixed_from_int(output->base.y + enter_notify->event_y);
> -
> -			notify_pointer_focus(&c->core_seat,
> -					     &output->base, x, y);
> +			x11_compositor_deliver_enter_event(c, event);
>  			break;
>  
>  		case XCB_LEAVE_NOTIFY:
> @@ -1031,20 +1115,13 @@ x11_restore(struct weston_compositor *ec)
>  }
>  
>  static void
> -x11_free_configured_output(struct x11_configured_output *output)
> -{
> -	free(output->name);
> -	free(output);
> -}
> -

As for the drm backend, I'm not sure why we're changing this in this patch.

> -static void
>  x11_destroy(struct weston_compositor *ec)
>  {
>  	struct x11_compositor *compositor = (struct x11_compositor *)ec;
>  	struct x11_configured_output *o, *n;
>  
>  	wl_list_for_each_safe(o, n, &configured_output_list, link)
> -		x11_free_configured_output(o);
> +		free(o);
>  
>  	wl_event_source_remove(compositor->xcb_source);
>  	x11_input_destroy(compositor);
> @@ -1063,8 +1140,6 @@ x11_compositor_create(struct wl_display *display,
>  		      int no_input,
>  		      int argc, char *argv[], const char *config_file)
>  {
> -	static const char name[] = "Weston Compositor";
> -	char configured_name[32];
>  	struct x11_compositor *c;
>  	struct x11_configured_output *o;
>  	xcb_screen_iterator_t s;
> @@ -1117,16 +1192,27 @@ x11_compositor_create(struct wl_display *display,
>  	count = option_count ? option_count : 1;
>  
>  	wl_list_for_each(o, &configured_output_list, link) {
> -		sprintf(configured_name, "%s - %s", name, o->name);
>  		if (x11_compositor_create_output(c, x, 0,
> -						option_width ? option_width :
> +						option_width ? width :
>  						o->width,
> -						option_height ? option_height :
> +						option_height ? height :
>  						o->height,
>  						fullscreen, no_input,
> -						configured_name) < 0)
> +						o->name, o->transform) < 0)
>  			goto err_x11_input;
> -		x += option_width ? option_width : o->width;
> +
> +		switch(o->transform) {
> +		case WL_OUTPUT_TRANSFORM_90:
> +		case WL_OUTPUT_TRANSFORM_270:
> +		case WL_OUTPUT_TRANSFORM_FLIPPED_90:
> +		case WL_OUTPUT_TRANSFORM_FLIPPED_270:
> +			x += option_height ? option_height : o->height;
> +			break;
> +		default:		
> +			x += option_width ? option_width : o->width;
> +			break;
> +		}
> +

weston_output_init() should set up output->region so that it has the
right widht and height and is placed at the right location.  Then if
you get the extents of output->region, then x2, y1 is the coordinate
for the next output.

>  		output_count++;
>  		if (option_count && output_count >= option_count)
>  			break;
> @@ -1134,7 +1220,8 @@ x11_compositor_create(struct wl_display *display,
>  
>  	for (i = output_count; i < count; i++) {
>  		if (x11_compositor_create_output(c, x, 0, width, height,
> -						 fullscreen, no_input, name) < 0)
> +						 fullscreen, no_input, NULL,
> +						 WL_OUTPUT_TRANSFORM_NORMAL) < 0)
>  			goto err_x11_input;
>  		x += width;
>  	}
> @@ -1160,37 +1247,68 @@ err_free:
>  }
>  
>  static void
> +output_set_transform(struct x11_configured_output *output)
> +{
> +	if (!output_transform) {
> +		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +		return;
> +	}
> +
> +	if (!strcmp(output_transform, "normal"))
> +		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +	else if (!strcmp(output_transform, "90"))
> +		output->transform = WL_OUTPUT_TRANSFORM_90;
> +	else if (!strcmp(output_transform, "180"))
> +		output->transform = WL_OUTPUT_TRANSFORM_180;
> +	else if (!strcmp(output_transform, "270"))
> +		output->transform = WL_OUTPUT_TRANSFORM_270;
> +	else if (!strcmp(output_transform, "flipped"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
> +	else if (!strcmp(output_transform, "flipped-90"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
> +	else if (!strcmp(output_transform, "flipped-180"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
> +	else if (!strcmp(output_transform, "flipped-270"))
> +		output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
> +	else {
> +		weston_log("Invalid transform \"%s\" for output %s\n",
> +						output_transform, output_name);
> +		output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +	}
> +}
> +
> +static void
>  output_section_done(void *data)
>  {
>  	struct x11_configured_output *output;
>  
>  	output = malloc(sizeof *output);
>  
> -	if (!output || !output_name || !output_mode) {
> -		free(output_name);
> -		output_name = NULL;
> +	if (!output || !output_name || !output_mode)
>  		goto err_free;
> -	}
>  
> -	output->name = output_name;
> +	output->name = strdup(output_name);
>  
> -	if (output_name[0] != 'X') {
> -		x11_free_configured_output(output);
> +	if (output_name[0] != 'X')
>  		goto err_free;
> -	}
>  
>  	if (sscanf(output_mode, "%dx%d", &output->width, &output->height) != 2) {
>  		weston_log("Invalid mode \"%s\" for output %s\n",
>  						output_mode, output_name);
> -		x11_free_configured_output(output);
>  		goto err_free;
>  	}
>  
> +	output_set_transform(output);
> +
>  	wl_list_insert(configured_output_list.prev, &output->link);
>  
>  err_free:
> +	free(output_name);
> +	output_name = NULL;
>  	free(output_mode);
>  	output_mode = NULL;
> +	free(output_transform);
> +	output_transform = NULL;
>  }
>  
>  WL_EXPORT struct weston_compositor *
> @@ -1215,6 +1333,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],
>  	const struct config_key x11_config_keys[] = {
>  		{ "name", CONFIG_KEY_STRING, &output_name },
>  		{ "mode", CONFIG_KEY_STRING, &output_mode },
> +		{ "transform", CONFIG_KEY_STRING, &output_transform },
>  	};
>  
>  	const struct config_section config_section[] = {
> diff --git a/src/compositor.c b/src/compositor.c
> index 7370435..8e4cc21 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -1136,7 +1136,7 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
>  	struct weston_frame_callback *cb, *cnext;
>  	struct wl_list frame_callback_list;
>  	pixman_region32_t opaque, output_damage;
> -	int32_t width, height;
> +	int32_t width, height, temp;
>  
>  	weston_compositor_update_drag_surfaces(ec);
>  
> @@ -1144,6 +1144,20 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
>  		output->border.left + output->border.right;
>  	height = output->current->height +
>  		output->border.top + output->border.bottom;
> +
> +	switch(output->transform) {
> +	case WL_OUTPUT_TRANSFORM_90:
> +	case WL_OUTPUT_TRANSFORM_270:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
> +		temp = width;
> +		width = height;
> +		height = temp;
> +		break;
> +	default:
> +		break;
> +	}
> +

We shouldn't change output->current->width/height, so this swap
shouldn't be necessary.

>  	glViewport(0, 0, width, height);
>  
>  	/* Rebuild the surface list and update surface transforms up front. */
> @@ -2962,12 +2976,61 @@ weston_output_destroy(struct weston_output *output)
>  	wl_display_remove_global(c->wl_display, output->global);
>  }
>  
> +static void
> +weston_output_compute_transform(struct weston_output *output,
> +				struct weston_matrix *transform, int *flip)
> +{
> +	*flip = 1;
> +	weston_matrix_init(transform);
> +
> +	switch(output->transform) {
> +	case WL_OUTPUT_TRANSFORM_90:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
> +		transform->d[0] = 0;
> +		transform->d[1] = -1;
> +		transform->d[4] = 1;
> +		transform->d[5] = 0;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_180:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
> +		transform->d[0] = 1;
> +		transform->d[1] = 0;
> +		transform->d[4] = 0;
> +		transform->d[5] = -1;
> +		break;
> +	case WL_OUTPUT_TRANSFORM_270:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
> +		transform->d[0] = 0;
> +		transform->d[1] = 1;
> +		transform->d[4] = -1;
> +		transform->d[5] = 0;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	switch(output->transform) {
> +	case WL_OUTPUT_TRANSFORM_FLIPPED:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
> +	case WL_OUTPUT_TRANSFORM_180:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
> +		*flip = -1;
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
>  WL_EXPORT void
>  weston_output_update_matrix(struct weston_output *output)
>  {
>  	float magnification;
>  	struct weston_matrix camera;
>  	struct weston_matrix modelview;
> +	struct weston_matrix transform;
> +	int flip;
> +
> +	weston_output_compute_transform(output, &transform, &flip);

We can just incorporate the flip in the matrix and do this:

static void
weston_output_compute_transform(struct weston_output *output)
{
	struct weston_matrix transform;
	GLfloat flip;

	weston_matrix_init(&transform);

	switch(output->transform) {
	case WL_OUTPUT_TRANSFORM_FLIPPED:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		flip = -1;
		break;
	default:
		flip = 1;
		break;
	}

	switch(output->transform) {
	case WL_OUTPUT_TRANSFORM_NORMAL:
	case WL_OUTPUT_TRANSFORM_FLIPPED:
		transform.d[0] = flip;
		transform.d[1] = 0;
		transform.d[4] = 0;
		transform.d[5] = 1;
		break;
	case WL_OUTPUT_TRANSFORM_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
		transform.d[0] = 0;
		transform.d[1] = -flip;
		transform.d[4] = 1;
		transform.d[5] = 0;
		break;
	case WL_OUTPUT_TRANSFORM_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
		transform.d[0] = -flip;
		transform.d[1] = 0;
		transform.d[4] = 0;
		transform.d[5] = -1;
		break;
	case WL_OUTPUT_TRANSFORM_270:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		transform.d[0] = 0;
		transform.d[1] = flip;
		transform.d[4] = -1;
		transform.d[5] = 0;
		break;
	default:
		break;
	}

	weston_matrix_multiply(&output->matrix, &transform);
}


>  	weston_matrix_init(&output->matrix);
>  	weston_matrix_translate(&output->matrix,
> @@ -2975,9 +3038,12 @@ weston_output_update_matrix(struct weston_output *output)
>  				-(output->y + (output->border.bottom + output->current->height - output->border.top) / 2.0), 0);
>  
>  	weston_matrix_scale(&output->matrix,
> -			    2.0 / (output->current->width + output->border.left + output->border.right),
> +			    flip * 2.0 / (output->current->width + output->border.left + output->border.right),
>  			    -2.0 / (output->current->height + output->border.top + output->border.bottom), 1);
>  
> +	if (output->transform != WL_OUTPUT_TRANSFORM_NORMAL)
> +		weston_matrix_multiply(&output->matrix, &transform);
> +

and just always call weston_output_compute_transform() here.

>  	if (output->zoom.active) {
>  		magnification = 1 / (1 - output->zoom.spring_z.current);
>  		weston_matrix_init(&camera);
> @@ -2993,6 +3059,39 @@ weston_output_update_matrix(struct weston_output *output)
>  	output->dirty = 0;
>  }
>  
> +static void
> +weston_output_transform_init(struct weston_output *output,
> +					int *width, int *height,
> +					uint32_t transform)
> +{
> +	int temp_w, temp_h;
> +
> +	output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +
> +	switch(transform) {
> +	case WL_OUTPUT_TRANSFORM_90:
> +	case WL_OUTPUT_TRANSFORM_270:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
> +		/* Swap width and height */
> +		temp_w = output->current->height;
> +		temp_h = output->current->width;
> +		output->current->width = temp_w;
> +		output->current->height = temp_h;
> +		temp_w = *height;
> +		temp_h = *width;
> +		*width = temp_w;
> +		*height = temp_h;
> +	case WL_OUTPUT_TRANSFORM_180:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED:
> +	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
> +		output->transform = transform;
> +		break;
> +	default:
> +		break;
> +	}
> +}

We don't swap the mode width and height, they correspond to the widht
and height of the underlying mode, which doesn't change with rotation.
However, weston_output_move() needs to swap width and height when it
sets up output->region.

> +
>  WL_EXPORT void
>  weston_output_move(struct weston_output *output, int x, int y)
>  {
> @@ -3007,8 +3106,10 @@ weston_output_move(struct weston_output *output, int x, int y)
>  
>  WL_EXPORT void
>  weston_output_init(struct weston_output *output, struct weston_compositor *c,
> -		   int x, int y, int width, int height)
> +		   int x, int y, int width, int height, uint32_t transform)
>  {
> +	weston_output_transform_init(output, &width, &height, transform);
> +
>  	output->compositor = c;
>  	output->x = x;
>  	output->y = y;
> @@ -3019,7 +3120,11 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
>  	output->mm_width = width;
>  	output->mm_height = height;
>  	output->dirty = 1;
> -	output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
> +
> +	if (transform != WL_OUTPUT_TRANSFORM_NORMAL)
> +		output->disable_planes++;
> +
> +	output->transform = transform;
>  
>  	weston_output_init_zoom(output);
>  
> diff --git a/src/compositor.h b/src/compositor.h
> index 7a8058e..f856418 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -682,7 +682,7 @@ void
>  weston_output_move(struct weston_output *output, int x, int y);
>  void
>  weston_output_init(struct weston_output *output, struct weston_compositor *c,
> -		   int x, int y, int width, int height);
> +		   int x, int y, int width, int height, uint32_t transform);
>  void
>  weston_output_destroy(struct weston_output *output);
>  
> diff --git a/weston.ini b/weston.ini
> index 3fda31b..99d24dd 100644
> --- a/weston.ini
> +++ b/weston.ini
> @@ -37,11 +37,14 @@ duration=600
>  #[output]
>  #name=LVDS1
>  #mode=1680x1050
> +#transform=90
>  
>  #[output]
>  #name=VGA1
>  #mode=173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync
> +#transform=flipped
>  
>  #[output]
>  #name=X1
>  #mode=1024x768
> +#transform=flipped-270
> -- 
> 1.7.11.2
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list