<br><br><div class="gmail_quote">On Thu, Aug 16, 2012 at 10:51 AM, Kristian Høgsberg <span dir="ltr"><<a href="mailto:hoegsberg@gmail.com" target="_blank">hoegsberg@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">On Thu, Aug 16, 2012 at 02:33:06AM -0600, Scott Moreau wrote:<br>
> This patch allows rotation and mirroring outputs for x11 and drm backends.<br>
> A new 'transform' key can be set in the [output] section. From the protocol:<br>
><br>
> "The flipped values correspond to an initial flip around a vertical axis<br>
> followed by rotation."<br>
><br>
> The transform key can be one of the following 8 strings:<br></div></blockquote><div><br>Hi Kristian,<br><br>Thanks for looking this over.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">
<br>
</div>This is looking quite good now.  I hit a problem though where I<br>
couldn't get the drm transform to work, and it turns out that we<br>
reject the output section if there is no mode key.  Now that we have a<br>
transform key, we should also accept something like just:<br>
<br>
        [output]<br>
        name=LVDS1<br>
        transform=90<br></blockquote><div><br>Yes this is a bug, fixed by your suggestion below.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
I'm also thinking that the output section parsing is now complex and<br>
identical enough between x11 and drm that we should share it.  Let's<br>
do that after we land this output transform patch though.<br>
<div><div class="h5"><br>
> normal<br>
> 90<br>
> 180<br>
> 270<br>
> flipped<br>
> flipped-90<br>
> flipped-180<br>
> flipped-270<br>
><br>
> ---<br>
><br>
> Changed in v2:<br>
><br>
> - x11 output position corrected.<br>
> - Fix usage of disable_planes.<br>
><br>
>  src/compositor-android.c |   3 +-<br>
>  src/compositor-drm.c     |  79 ++++++++++++-----<br>
>  src/compositor-wayland.c |   3 +-<br>
>  src/compositor-x11.c     | 217 ++++++++++++++++++++++++++++++++++++-----------<br>
>  src/compositor.c         | 113 +++++++++++++++++++++++-<br>
>  src/compositor.h         |   2 +-<br>
>  weston.ini               |   3 +<br>
>  7 files changed, 341 insertions(+), 79 deletions(-)<br>
><br>
> diff --git a/src/compositor-android.c b/src/compositor-android.c<br>
> index a9c45d2..b095262 100644<br>
> --- a/src/compositor-android.c<br>
> +++ b/src/compositor-android.c<br>
> @@ -238,7 +238,8 @@ android_compositor_add_output(struct android_compositor *compositor,<br>
>       mm_width  = output->fb->width / output->fb->xdpi * 25.4f;<br>
>       mm_height = output->fb->height / output->fb->ydpi * 25.4f;<br>
>       weston_output_init(&output->base, &compositor->base,<br>
> -                        0, 0, round(mm_width), round(mm_height));<br>
> +                        0, 0, round(mm_width), round(mm_height),<br>
> +                        WL_OUTPUT_TRANSFORM_NORMAL);<br>
>       wl_list_insert(compositor->base.output_list.prev, &output->base.link);<br>
>  }<br>
><br>
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c<br>
> index 8c8c8c0..0911894 100644<br>
> --- a/src/compositor-drm.c<br>
> +++ b/src/compositor-drm.c<br>
> @@ -46,6 +46,7 @@<br>
>  static int option_current_mode = 0;<br>
>  static char *output_name;<br>
>  static char *output_mode;<br>
> +static char *output_transform;<br>
>  static struct wl_list configured_output_list;<br>
><br>
>  enum output_config {<br>
> @@ -60,6 +61,7 @@ enum output_config {<br>
>  struct drm_configured_output {<br>
>       char *name;<br>
>       char *mode;<br>
> +     uint32_t transform;<br>
>       int32_t width, height;<br>
>       drmModeModeInfo crtc_mode;<br>
>       enum output_config config;<br>
> @@ -1528,7 +1530,8 @@ create_output_for_connector(struct drm_compositor *ec,<br>
>       }<br>
><br>
>       weston_output_init(&output->base, &ec->base, x, y,<br>
> -                        connector->mmWidth, connector->mmHeight);<br>
> +                        connector->mmWidth, connector->mmHeight,<br>
> +                        o ? o->transform : WL_OUTPUT_TRANSFORM_NORMAL);<br>
><br>
>       wl_list_insert(ec->base.output_list.prev, &output->base.link);<br>
><br>
> @@ -2066,14 +2069,6 @@ evdev_input_destroy(struct weston_seat *seat_base)<br>
>  }<br>
><br>
>  static void<br>
> -drm_free_configured_output(struct drm_configured_output *output)<br>
> -{<br>
> -     free(output->name);<br>
> -     free(output->mode);<br>
> -     free(output);<br>
> -}<br>
<br>
</div></div>I'm not sure why this is in here... now we're leaking output->name and<br>
output->mode.  Let's not change the memory management of this struct<br>
as part of the output transform path.<br></blockquote><div><br>Yes, this should go in a separate patch. The idea is that we use strdup() on strings instead of storing the pointer, and always free all global string variables in output_section_done(). This eliminates the need for a separate free function.<br>
 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> -<br>
> -static void<br>
>  drm_destroy(struct weston_compositor *ec)<br>
>  {<br>
>       struct drm_compositor *d = (struct drm_compositor *) ec;<br>
> @@ -2083,7 +2078,7 @@ drm_destroy(struct weston_compositor *ec)<br>
>       wl_list_for_each_safe(seat, next, &ec->seat_list, link)<br>
>               evdev_input_destroy(seat);<br>
>       wl_list_for_each_safe(o, n, &configured_output_list, link)<br>
> -             drm_free_configured_output(o);<br>
> +             free(o);<br>
><br>
>       wl_event_source_remove(d->udev_drm_source);<br>
>       wl_event_source_remove(d->drm_source);<br>
> @@ -2412,23 +2407,52 @@ check_for_modeline(struct drm_configured_output *output)<br>
>  }<br>
><br>
>  static void<br>
> +output_set_transform(struct drm_configured_output *output)<br>
> +{<br>
> +     if (!output_transform) {<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +             return;<br>
> +     }<br>
> +<br>
> +     if (!strcmp(output_transform, "normal"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +     else if (!strcmp(output_transform, "90"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_90;<br>
> +     else if (!strcmp(output_transform, "180"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_180;<br>
> +     else if (!strcmp(output_transform, "270"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_270;<br>
> +     else if (!strcmp(output_transform, "flipped"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;<br>
> +     else if (!strcmp(output_transform, "flipped-90"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;<br>
> +     else if (!strcmp(output_transform, "flipped-180"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;<br>
> +     else if (!strcmp(output_transform, "flipped-270"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;<br>
> +     else {<br>
> +             weston_log("Invalid transform \"%s\" for output %s\n",<br>
> +                                             output_transform, output_name);<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +     }<br>
> +}<br>
> +<br>
> +static void<br>
>  output_section_done(void *data)<br>
>  {<br>
>       struct drm_configured_output *output;<br>
><br>
>       output = malloc(sizeof *output);<br>
><br>
> -     if (!output || !output_name || !output_mode) {<br>
> -             free(output_name);<br>
> -             output_name = NULL;<br>
> -             free(output_mode);<br>
> -             output_mode = NULL;<br>
> -             return;<br>
> -     }<br>
> +     if (!output || !output_name || !output_mode)<br>
<br>
</div></div>This should be<br>
<br>
        (!output || !output_name || (!output_mode && !output_transform))<br>
<br>
to allow output section with just a transform key.<br></blockquote><div><br>Yep.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +             goto err_free;<br>
> +<br>
> +     if (output_name[0] == 'X')<br>
> +             goto err_free;<br>
><br>
>       output->config = OUTPUT_CONFIG_INVALID;<br>
> -     output->name = output_name;<br>
> -     output->mode = output_mode;<br>
> +     output->name = strdup(output_name);<br>
> +     output->mode = strdup(output_mode);<br>
><br>
>       if (strcmp(output_mode, "off") == 0)<br>
>               output->config = OUTPUT_CONFIG_OFF;<br>
> @@ -2441,13 +2465,21 @@ output_section_done(void *data)<br>
>       else if (check_for_modeline(output) == 0)<br>
>               output->config = OUTPUT_CONFIG_MODELINE;<br>
><br>
> -     if (output->config != OUTPUT_CONFIG_INVALID)<br>
> -             wl_list_insert(&configured_output_list, &output->link);<br>
> -     else {<br>
> +     if (output->config == OUTPUT_CONFIG_INVALID) {<br>
>               weston_log("Invalid mode \"%s\" for output %s\n",<br>
>                                               output_mode, output_name);<br>
> -             drm_free_configured_output(output);<br>
> +             goto err_free;<br>
>       }<br>
> +<br>
> +     output_set_transform(output);<br>
> +<br>
> +     wl_list_insert(&configured_output_list, &output->link);<br>
> +<br>
> +err_free:<br>
> +     free(output_name);<br>
> +     output_name = NULL;<br>
> +     free(output_mode);<br>
> +     output_mode = NULL;<br>
>  }<br>
><br>
>  WL_EXPORT struct weston_compositor *<br>
> @@ -2471,6 +2503,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],<br>
>       const struct config_key drm_config_keys[] = {<br>
>               { "name", CONFIG_KEY_STRING, &output_name },<br>
>               { "mode", CONFIG_KEY_STRING, &output_mode },<br>
> +             { "transform", CONFIG_KEY_STRING, &output_transform },<br>
>       };<br>
><br>
>       const struct config_section config_section[] = {<br>
> diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c<br>
> index 4fc77f1..84eaf6c 100644<br>
> --- a/src/compositor-wayland.c<br>
> +++ b/src/compositor-wayland.c<br>
> @@ -395,7 +395,8 @@ wayland_compositor_create_output(struct wayland_compositor *c,<br>
>       wl_list_insert(&output->base.mode_list, &output->mode.link);<br>
><br>
>       output->base.current = &output->mode;<br>
> -     weston_output_init(&output->base, &c->base, 0, 0, width, height);<br>
> +     weston_output_init(&output->base, &c->base, 0, 0, width, height,<br>
> +                                             WL_OUTPUT_TRANSFORM_NORMAL);<br>
><br>
>       output->base.border.top = c->border.top;<br>
>       output->base.border.bottom = c->border.bottom;<br>
> diff --git a/src/compositor-x11.c b/src/compositor-x11.c<br>
> index c02911d..1f22286 100644<br>
> --- a/src/compositor-x11.c<br>
> +++ b/src/compositor-x11.c<br>
> @@ -52,6 +52,7 @@<br>
><br>
>  static char *output_name;<br>
>  static char *output_mode;<br>
> +static char *output_transform;<br>
>  static int option_width;<br>
>  static int option_height;<br>
>  static int option_count;<br>
> @@ -60,6 +61,7 @@ static struct wl_list configured_output_list;<br>
>  struct x11_configured_output {<br>
>       char *name;<br>
>       int width, height;<br>
> +     uint32_t transform;<br>
>       struct wl_list link;<br>
>  };<br>
><br>
> @@ -474,9 +476,12 @@ x11_output_set_icon(struct x11_compositor *c,<br>
>  static int<br>
>  x11_compositor_create_output(struct x11_compositor *c, int x, int y,<br>
>                            int width, int height, int fullscreen,<br>
> -                          int no_input, const char *name)<br>
> +                          int no_input, char *configured_name,<br>
> +                          uint32_t transform)<br>
>  {<br>
> +     static const char name[] = "Weston Compositor";<br>
>       static const char class[] = "weston-1\0Weston Compositor";<br>
> +     char title[32];<br>
>       struct x11_output *output;<br>
>       xcb_screen_iterator_t iter;<br>
>       struct wm_normal_hints normal_hints;<br>
> @@ -488,6 +493,11 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,<br>
>               0<br>
>       };<br>
><br>
> +     if (configured_name)<br>
> +             sprintf(title, "%s - %s", name, configured_name);<br>
> +     else<br>
> +             strcpy(title, name);<br>
> +<br>
>       if (!no_input)<br>
>               values[0] |=<br>
>                       XCB_EVENT_MASK_KEY_PRESS |<br>
> @@ -517,7 +527,8 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,<br>
>       output->base.current = &output->mode;<br>
>       output->base.make = "xwayland";<br>
>       output->base.model = "none";<br>
> -     weston_output_init(&output->base, &c->base, x, y, width, height);<br>
> +     weston_output_init(&output->base, &c->base, x, y, width, height,<br>
> +                                                             transform);<br>
><br>
>       values[1] = c->null_cursor;<br>
>       output->window = xcb_generate_id(c->conn);<br>
> @@ -550,7 +561,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,<br>
>       /* Set window name.  Don't bother with non-EWMH WMs. */<br>
>       xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,<br>
>                           c->atom.net_wm_name, c->atom.utf8_string, 8,<br>
> -                         strlen(name), name);<br>
> +                         strlen(title), title);<br>
>       xcb_change_property(c->conn, XCB_PROP_MODE_REPLACE, output->window,<br>
>                           c->atom.wm_class, c->atom.string, 8,<br>
>                           sizeof class, class);<br>
> @@ -739,6 +750,98 @@ x11_compositor_deliver_button_event(struct x11_compositor *c,<br>
>                             WL_POINTER_BUTTON_STATE_RELEASED);<br>
>  }<br>
><br>
> +static void<br>
> +x11_output_transform_coordinate(struct x11_output *x11_output,<br>
> +                                             wl_fixed_t *x, wl_fixed_t *y)<br>
> +{<br>
> +     struct weston_output *output = &x11_output->base;<br>
> +     wl_fixed_t tx, ty;<br>
> +     wl_fixed_t width = wl_fixed_from_int(output->current->width - 1);<br>
> +     wl_fixed_t height = wl_fixed_from_int(output->current->height - 1);<br>
> +<br>
> +     switch(output->transform) {<br>
> +     case WL_OUTPUT_TRANSFORM_NORMAL:<br>
> +     default:<br>
> +             tx = *x;<br>
> +             ty = *y;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_90:<br>
> +             tx = *y;<br>
> +             ty = height - *x;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_180:<br>
> +             tx = width - *x;<br>
> +             ty = height - *y;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_270:<br>
> +             tx = width - *y;<br>
> +             ty = *x;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED:<br>
> +             tx = width - *x;<br>
> +             ty = *y;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
> +             tx = width - *y;<br>
> +             ty = height - *x;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_180:<br>
> +             tx = *x;<br>
> +             ty = height - *y;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
> +             tx = *y;<br>
> +             ty = *x;<br>
> +             break;<br>
> +     }<br>
<br>
</div></div>This looks much better now.<br>
<div><div class="h5"><br>
> +     tx += wl_fixed_from_int(output->x);<br>
> +     ty += wl_fixed_from_int(output->y);<br>
> +<br>
> +     *x = tx;<br>
> +     *y = ty;<br>
> +}<br>
> +<br>
> +static void<br>
> +x11_compositor_deliver_motion_event(struct x11_compositor *c,<br>
> +                                     xcb_generic_event_t *event)<br>
> +{<br>
> +     struct x11_output *output;<br>
> +     wl_fixed_t x, y;<br>
> +     xcb_motion_notify_event_t *motion_notify =<br>
> +                     (xcb_motion_notify_event_t *) event;<br>
> +<br>
> +     if (!c->has_xkb)<br>
> +             update_xkb_state_from_core(c, motion_notify->state);<br>
> +     output = x11_compositor_find_output(c, motion_notify->event);<br>
> +     x = wl_fixed_from_int(motion_notify->event_x);<br>
> +     y = wl_fixed_from_int(motion_notify->event_y);<br>
> +     x11_output_transform_coordinate(output, &x, &y);<br>
> +<br>
> +     notify_motion(&c->core_seat, weston_compositor_get_time(), x, y);<br>
> +}<br>
> +<br>
> +static void<br>
> +x11_compositor_deliver_enter_event(struct x11_compositor *c,<br>
> +                                     xcb_generic_event_t *event)<br>
> +{<br>
> +     struct x11_output *output;<br>
> +     wl_fixed_t x, y;<br>
> +<br>
> +     xcb_enter_notify_event_t *enter_notify =<br>
> +                     (xcb_enter_notify_event_t *) event;<br>
> +     if (enter_notify->state >= Button1Mask)<br>
> +             return;<br>
> +     if (!c->has_xkb)<br>
> +             update_xkb_state_from_core(c, enter_notify->state);<br>
> +     output = x11_compositor_find_output(c, enter_notify->event);<br>
> +     x = wl_fixed_from_int(enter_notify->event_x);<br>
> +     y = wl_fixed_from_int(enter_notify->event_y);<br>
> +     x11_output_transform_coordinate(output, &x, &y);<br>
> +<br>
> +     notify_pointer_focus(&c->core_seat, &output->base, x, y);<br>
> +}<br>
> +<br>
>  static int<br>
>  x11_compositor_next_event(struct x11_compositor *c,<br>
>                         xcb_generic_event_t **event, uint32_t mask)<br>
> @@ -763,7 +866,6 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)<br>
>       struct x11_output *output;<br>
>       xcb_generic_event_t *event, *prev;<br>
>       xcb_client_message_event_t *client_message;<br>
> -     xcb_motion_notify_event_t *motion_notify;<br>
>       xcb_enter_notify_event_t *enter_notify;<br>
>       xcb_key_press_event_t *key_press, *key_release;<br>
>       xcb_keymap_notify_event_t *keymap_notify;<br>
> @@ -772,7 +874,6 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)<br>
>       xcb_atom_t atom;<br>
>       uint32_t *k;<br>
>       uint32_t i, set;<br>
> -     wl_fixed_t x, y;<br>
>       int count;<br>
><br>
>       prev = NULL;<br>
> @@ -872,14 +973,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)<br>
>                       x11_compositor_deliver_button_event(c, event, 0);<br>
>                       break;<br>
>               case XCB_MOTION_NOTIFY:<br>
> -                     motion_notify = (xcb_motion_notify_event_t *) event;<br>
> -                     if (!c->has_xkb)<br>
> -                             update_xkb_state_from_core(c, motion_notify->state);<br>
> -                     output = x11_compositor_find_output(c, motion_notify->event);<br>
> -                     x = wl_fixed_from_int(output->base.x + motion_notify->event_x);<br>
> -                     y = wl_fixed_from_int(output->base.y + motion_notify->event_y);<br>
> -                     notify_motion(&c->core_seat,<br>
> -                                   weston_compositor_get_time(), x, y);<br>
> +                     x11_compositor_deliver_motion_event(c, event);<br>
>                       break;<br>
><br>
>               case XCB_EXPOSE:<br>
> @@ -889,17 +983,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)<br>
>                       break;<br>
><br>
>               case XCB_ENTER_NOTIFY:<br>
> -                     enter_notify = (xcb_enter_notify_event_t *) event;<br>
> -                     if (enter_notify->state >= Button1Mask)<br>
> -                             break;<br>
> -                     if (!c->has_xkb)<br>
> -                             update_xkb_state_from_core(c, enter_notify->state);<br>
> -                     output = x11_compositor_find_output(c, enter_notify->event);<br>
> -                     x = wl_fixed_from_int(output->base.x + enter_notify->event_x);<br>
> -                     y = wl_fixed_from_int(output->base.y + enter_notify->event_y);<br>
> -<br>
> -                     notify_pointer_focus(&c->core_seat,<br>
> -                                          &output->base, x, y);<br>
> +                     x11_compositor_deliver_enter_event(c, event);<br>
>                       break;<br>
><br>
>               case XCB_LEAVE_NOTIFY:<br>
> @@ -1031,20 +1115,13 @@ x11_restore(struct weston_compositor *ec)<br>
>  }<br>
><br>
>  static void<br>
> -x11_free_configured_output(struct x11_configured_output *output)<br>
> -{<br>
> -     free(output->name);<br>
> -     free(output);<br>
> -}<br>
> -<br>
<br>
</div></div>As for the drm backend, I'm not sure why we're changing this in this patch.<br>
<div><div class="h5"><br>
> -static void<br>
>  x11_destroy(struct weston_compositor *ec)<br>
>  {<br>
>       struct x11_compositor *compositor = (struct x11_compositor *)ec;<br>
>       struct x11_configured_output *o, *n;<br>
><br>
>       wl_list_for_each_safe(o, n, &configured_output_list, link)<br>
> -             x11_free_configured_output(o);<br>
> +             free(o);<br>
><br>
>       wl_event_source_remove(compositor->xcb_source);<br>
>       x11_input_destroy(compositor);<br>
> @@ -1063,8 +1140,6 @@ x11_compositor_create(struct wl_display *display,<br>
>                     int no_input,<br>
>                     int argc, char *argv[], const char *config_file)<br>
>  {<br>
> -     static const char name[] = "Weston Compositor";<br>
> -     char configured_name[32];<br>
>       struct x11_compositor *c;<br>
>       struct x11_configured_output *o;<br>
>       xcb_screen_iterator_t s;<br>
> @@ -1117,16 +1192,27 @@ x11_compositor_create(struct wl_display *display,<br>
>       count = option_count ? option_count : 1;<br>
><br>
>       wl_list_for_each(o, &configured_output_list, link) {<br>
> -             sprintf(configured_name, "%s - %s", name, o->name);<br>
>               if (x11_compositor_create_output(c, x, 0,<br>
> -                                             option_width ? option_width :<br>
> +                                             option_width ? width :<br>
>                                               o->width,<br>
> -                                             option_height ? option_height :<br>
> +                                             option_height ? height :<br>
>                                               o->height,<br>
>                                               fullscreen, no_input,<br>
> -                                             configured_name) < 0)<br>
> +                                             o->name, o->transform) < 0)<br>
>                       goto err_x11_input;<br>
> -             x += option_width ? option_width : o->width;<br>
> +<br>
> +             switch(o->transform) {<br>
> +             case WL_OUTPUT_TRANSFORM_90:<br>
> +             case WL_OUTPUT_TRANSFORM_270:<br>
> +             case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
> +             case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
> +                     x += option_height ? option_height : o->height;<br>
> +                     break;<br>
> +             default:<br>
> +                     x += option_width ? option_width : o->width;<br>
> +                     break;<br>
> +             }<br>
> +<br>
<br>
</div></div>weston_output_init() should set up output->region so that it has the<br>
right widht and height and is placed at the right location.  Then if<br>
you get the extents of output->region, then x2, y1 is the coordinate<br>
for the next output.<br></blockquote><div><br>Yes, this is a good idea. We can probably use something like<br><br>        x += (container_of(c->base.output_list.prev,<br>                struct weston_output, link))->region.extents.x2;<br>
 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
>               output_count++;<br>
>               if (option_count && output_count >= option_count)<br>
>                       break;<br>
> @@ -1134,7 +1220,8 @@ x11_compositor_create(struct wl_display *display,<br>
><br>
>       for (i = output_count; i < count; i++) {<br>
>               if (x11_compositor_create_output(c, x, 0, width, height,<br>
> -                                              fullscreen, no_input, name) < 0)<br>
> +                                              fullscreen, no_input, NULL,<br>
> +                                              WL_OUTPUT_TRANSFORM_NORMAL) < 0)<br>
>                       goto err_x11_input;<br>
>               x += width;<br>
>       }<br>
> @@ -1160,37 +1247,68 @@ err_free:<br>
>  }<br>
><br>
>  static void<br>
> +output_set_transform(struct x11_configured_output *output)<br>
> +{<br>
> +     if (!output_transform) {<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +             return;<br>
> +     }<br>
> +<br>
> +     if (!strcmp(output_transform, "normal"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +     else if (!strcmp(output_transform, "90"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_90;<br>
> +     else if (!strcmp(output_transform, "180"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_180;<br>
> +     else if (!strcmp(output_transform, "270"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_270;<br>
> +     else if (!strcmp(output_transform, "flipped"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;<br>
> +     else if (!strcmp(output_transform, "flipped-90"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;<br>
> +     else if (!strcmp(output_transform, "flipped-180"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;<br>
> +     else if (!strcmp(output_transform, "flipped-270"))<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;<br>
> +     else {<br>
> +             weston_log("Invalid transform \"%s\" for output %s\n",<br>
> +                                             output_transform, output_name);<br>
> +             output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +     }<br>
> +}<br>
> +<br>
> +static void<br>
>  output_section_done(void *data)<br>
>  {<br>
>       struct x11_configured_output *output;<br>
><br>
>       output = malloc(sizeof *output);<br>
><br>
> -     if (!output || !output_name || !output_mode) {<br>
> -             free(output_name);<br>
> -             output_name = NULL;<br>
> +     if (!output || !output_name || !output_mode)<br>
>               goto err_free;<br>
> -     }<br>
><br>
> -     output->name = output_name;<br>
> +     output->name = strdup(output_name);<br>
><br>
> -     if (output_name[0] != 'X') {<br>
> -             x11_free_configured_output(output);<br>
> +     if (output_name[0] != 'X')<br>
>               goto err_free;<br>
> -     }<br>
><br>
>       if (sscanf(output_mode, "%dx%d", &output->width, &output->height) != 2) {<br>
>               weston_log("Invalid mode \"%s\" for output %s\n",<br>
>                                               output_mode, output_name);<br>
> -             x11_free_configured_output(output);<br>
>               goto err_free;<br>
>       }<br>
><br>
> +     output_set_transform(output);<br>
> +<br>
>       wl_list_insert(configured_output_list.prev, &output->link);<br>
><br>
>  err_free:<br>
> +     free(output_name);<br>
> +     output_name = NULL;<br>
>       free(output_mode);<br>
>       output_mode = NULL;<br>
> +     free(output_transform);<br>
> +     output_transform = NULL;<br>
>  }<br>
><br>
>  WL_EXPORT struct weston_compositor *<br>
> @@ -1215,6 +1333,7 @@ backend_init(struct wl_display *display, int argc, char *argv[],<br>
>       const struct config_key x11_config_keys[] = {<br>
>               { "name", CONFIG_KEY_STRING, &output_name },<br>
>               { "mode", CONFIG_KEY_STRING, &output_mode },<br>
> +             { "transform", CONFIG_KEY_STRING, &output_transform },<br>
>       };<br>
><br>
>       const struct config_section config_section[] = {<br>
> diff --git a/src/compositor.c b/src/compositor.c<br>
> index 7370435..8e4cc21 100644<br>
> --- a/src/compositor.c<br>
> +++ b/src/compositor.c<br>
> @@ -1136,7 +1136,7 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)<br>
>       struct weston_frame_callback *cb, *cnext;<br>
>       struct wl_list frame_callback_list;<br>
>       pixman_region32_t opaque, output_damage;<br>
> -     int32_t width, height;<br>
> +     int32_t width, height, temp;<br>
><br>
>       weston_compositor_update_drag_surfaces(ec);<br>
><br>
> @@ -1144,6 +1144,20 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)<br>
>               output->border.left + output->border.right;<br>
>       height = output->current->height +<br>
>               output->border.top + output->border.bottom;<br>
> +<br>
> +     switch(output->transform) {<br>
> +     case WL_OUTPUT_TRANSFORM_90:<br>
> +     case WL_OUTPUT_TRANSFORM_270:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
> +             temp = width;<br>
> +             width = height;<br>
> +             height = temp;<br>
> +             break;<br>
> +     default:<br>
> +             break;<br>
> +     }<br>
> +<br>
<br>
</div></div>We shouldn't change output->current->width/height, so this swap<br>
shouldn't be necessary.<br>
<div><div class="h5"><br>
>       glViewport(0, 0, width, height);<br>
><br>
>       /* Rebuild the surface list and update surface transforms up front. */<br>
> @@ -2962,12 +2976,61 @@ weston_output_destroy(struct weston_output *output)<br>
>       wl_display_remove_global(c->wl_display, output->global);<br>
>  }<br>
><br>
> +static void<br>
> +weston_output_compute_transform(struct weston_output *output,<br>
> +                             struct weston_matrix *transform, int *flip)<br>
> +{<br>
> +     *flip = 1;<br>
> +     weston_matrix_init(transform);<br>
> +<br>
> +     switch(output->transform) {<br>
> +     case WL_OUTPUT_TRANSFORM_90:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
> +             transform->d[0] = 0;<br>
> +             transform->d[1] = -1;<br>
> +             transform->d[4] = 1;<br>
> +             transform->d[5] = 0;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_180:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_180:<br>
> +             transform->d[0] = 1;<br>
> +             transform->d[1] = 0;<br>
> +             transform->d[4] = 0;<br>
> +             transform->d[5] = -1;<br>
> +             break;<br>
> +     case WL_OUTPUT_TRANSFORM_270:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
> +             transform->d[0] = 0;<br>
> +             transform->d[1] = 1;<br>
> +             transform->d[4] = -1;<br>
> +             transform->d[5] = 0;<br>
> +             break;<br>
> +     default:<br>
> +             break;<br>
> +     }<br>
> +<br>
> +     switch(output->transform) {<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
> +     case WL_OUTPUT_TRANSFORM_180:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
> +             *flip = -1;<br>
> +             break;<br>
> +     default:<br>
> +             break;<br>
> +     }<br>
> +}<br>
> +<br>
>  WL_EXPORT void<br>
>  weston_output_update_matrix(struct weston_output *output)<br>
>  {<br>
>       float magnification;<br>
>       struct weston_matrix camera;<br>
>       struct weston_matrix modelview;<br>
> +     struct weston_matrix transform;<br>
> +     int flip;<br>
> +<br>
> +     weston_output_compute_transform(output, &transform, &flip);<br>
<br>
</div></div>We can just incorporate the flip in the matrix and do this:<br>
<br>
static void<br>
weston_output_compute_transform(struct weston_output *output)<br>
{<br>
        struct weston_matrix transform;<br>
        GLfloat flip;<br>
<br>
        weston_matrix_init(&transform);<br>
<br>
        switch(output->transform) {<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED_180:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
                flip = -1;<br>
                break;<br>
        default:<br>
                flip = 1;<br>
                break;<br>
        }<br>
<br>
        switch(output->transform) {<br>
        case WL_OUTPUT_TRANSFORM_NORMAL:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED:<br>
                transform.d[0] = flip;<br>
                transform.d[1] = 0;<br>
                transform.d[4] = 0;<br>
                transform.d[5] = 1;<br>
                break;<br>
        case WL_OUTPUT_TRANSFORM_90:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
                transform.d[0] = 0;<br>
                transform.d[1] = -flip;<br>
                transform.d[4] = 1;<br>
                transform.d[5] = 0;<br>
                break;<br>
        case WL_OUTPUT_TRANSFORM_180:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED_180:<br>
                transform.d[0] = -flip;<br>
                transform.d[1] = 0;<br>
                transform.d[4] = 0;<br>
                transform.d[5] = -1;<br>
                break;<br>
        case WL_OUTPUT_TRANSFORM_270:<br>
        case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
                transform.d[0] = 0;<br>
                transform.d[1] = flip;<br>
                transform.d[4] = -1;<br>
                transform.d[5] = 0;<br>
                break;<br>
        default:<br>
                break;<br>
        }<br>
<br>
        weston_matrix_multiply(&output->matrix, &transform);<br>
<div class="im">}<br>
<br>
<br>
>       weston_matrix_init(&output->matrix);<br>
>       weston_matrix_translate(&output->matrix,<br>
> @@ -2975,9 +3038,12 @@ weston_output_update_matrix(struct weston_output *output)<br>
>                               -(output->y + (output->border.bottom + output->current->height - output->border.top) / 2.0), 0);<br>
><br>
>       weston_matrix_scale(&output->matrix,<br>
> -                         2.0 / (output->current->width + output->border.left + output->border.right),<br>
> +                         flip * 2.0 / (output->current->width + output->border.left + output->border.right),<br>
>                           -2.0 / (output->current->height + output->border.top + output->border.bottom), 1);<br>
><br>
> +     if (output->transform != WL_OUTPUT_TRANSFORM_NORMAL)<br>
> +             weston_matrix_multiply(&output->matrix, &transform);<br>
> +<br>
<br>
</div>and just always call weston_output_compute_transform() here.<br></blockquote><div><br>Yes, looks like that should work.<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div><div class="h5"><br>
>       if (output->zoom.active) {<br>
>               magnification = 1 / (1 - output->zoom.spring_z.current);<br>
>               weston_matrix_init(&camera);<br>
> @@ -2993,6 +3059,39 @@ weston_output_update_matrix(struct weston_output *output)<br>
>       output->dirty = 0;<br>
>  }<br>
><br>
> +static void<br>
> +weston_output_transform_init(struct weston_output *output,<br>
> +                                     int *width, int *height,<br>
> +                                     uint32_t transform)<br>
> +{<br>
> +     int temp_w, temp_h;<br>
> +<br>
> +     output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +<br>
> +     switch(transform) {<br>
> +     case WL_OUTPUT_TRANSFORM_90:<br>
> +     case WL_OUTPUT_TRANSFORM_270:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_90:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_270:<br>
> +             /* Swap width and height */<br>
> +             temp_w = output->current->height;<br>
> +             temp_h = output->current->width;<br>
> +             output->current->width = temp_w;<br>
> +             output->current->height = temp_h;<br>
> +             temp_w = *height;<br>
> +             temp_h = *width;<br>
> +             *width = temp_w;<br>
> +             *height = temp_h;<br>
> +     case WL_OUTPUT_TRANSFORM_180:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED:<br>
> +     case WL_OUTPUT_TRANSFORM_FLIPPED_180:<br>
> +             output->transform = transform;<br>
> +             break;<br>
> +     default:<br>
> +             break;<br>
> +     }<br>
> +}<br>
<br>
</div></div>We don't swap the mode width and height, they correspond to the widht<br>
and height of the underlying mode, which doesn't change with rotation.<br>
However, weston_output_move() needs to swap width and height when it<br>
sets up output->region.<br></blockquote><div><br>I see what you mean about the mode width/height. Unfortunately without this 'hack', I'm not sure peicing everything else together will be straightforward. I tried a few different things after adding output->width/height as you suggested but I couldn't seem to get it working right. It will take some more careful debugging. Other areas that will need attention are zoom and screenshot but we can fix those in follow up patches.<br>
 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> +<br>
>  WL_EXPORT void<br>
>  weston_output_move(struct weston_output *output, int x, int y)<br>
>  {<br>
> @@ -3007,8 +3106,10 @@ weston_output_move(struct weston_output *output, int x, int y)<br>
><br>
>  WL_EXPORT void<br>
>  weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
> -                int x, int y, int width, int height)<br>
> +                int x, int y, int width, int height, uint32_t transform)<br>
>  {<br>
> +     weston_output_transform_init(output, &width, &height, transform);<br>
> +<br>
>       output->compositor = c;<br>
>       output->x = x;<br>
>       output->y = y;<br>
> @@ -3019,7 +3120,11 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
>       output->mm_width = width;<br>
>       output->mm_height = height;<br>
>       output->dirty = 1;<br>
> -     output->transform = WL_OUTPUT_TRANSFORM_NORMAL;<br>
> +<br>
> +     if (transform != WL_OUTPUT_TRANSFORM_NORMAL)<br>
> +             output->disable_planes++;<br>
> +<br>
> +     output->transform = transform;<br>
><br>
>       weston_output_init_zoom(output);<br>
><br>
> diff --git a/src/compositor.h b/src/compositor.h<br>
> index 7a8058e..f856418 100644<br>
> --- a/src/compositor.h<br>
> +++ b/src/compositor.h<br>
> @@ -682,7 +682,7 @@ void<br>
>  weston_output_move(struct weston_output *output, int x, int y);<br>
>  void<br>
>  weston_output_init(struct weston_output *output, struct weston_compositor *c,<br>
> -                int x, int y, int width, int height);<br>
> +                int x, int y, int width, int height, uint32_t transform);<br>
>  void<br>
>  weston_output_destroy(struct weston_output *output);<br>
><br>
> diff --git a/weston.ini b/weston.ini<br>
> index 3fda31b..99d24dd 100644<br>
> --- a/weston.ini<br>
> +++ b/weston.ini<br>
> @@ -37,11 +37,14 @@ duration=600<br>
>  #[output]<br>
>  #name=LVDS1<br>
>  #mode=1680x1050<br>
> +#transform=90<br>
><br>
>  #[output]<br>
>  #name=VGA1<br>
>  #mode=173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync<br>
> +#transform=flipped<br>
><br>
>  #[output]<br>
>  #name=X1<br>
>  #mode=1024x768<br>
> +#transform=flipped-270<br>
> --<br>
> 1.7.11.2<br>
><br>
</div></div>> _______________________________________________<br>
> wayland-devel mailing list<br>
> <a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</blockquote></div><br>