Introduces a “same-as” configuration option for each output, which
bypasses the rest of the output configuration (mode, scale, transform
and seat) and instead makes it a clone of the specified output.

This is implemented by splitting the drm_output struct into the
per-connector drm_output and the per-weston_output drm_logical_output,
with the latter containing one or more of the former in a wl_list.

I tested it on both i915 and etnaviv platforms, with various external
monitors and configurations, as well as hotplugging.

Signed-off-by: Emmanuel Gil Peyrot <emmanuel.pey...@collabora.com>
---
 src/compositor-drm.c | 794 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 477 insertions(+), 317 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 1edcaab..a0ed45f 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -157,8 +157,12 @@ struct drm_edid {
        char serial_number[13];
 };
 
+struct drm_logical_output;
+
 struct drm_output {
-       struct weston_output   base;
+       struct wl_list link;
+       struct drm_logical_output *base;
+       char *name;
 
        uint32_t crtc_id;
        int pipe;
@@ -166,13 +170,21 @@ struct drm_output {
        drmModeCrtcPtr original_crtc;
        struct drm_edid edid;
        drmModePropertyPtr dpms_prop;
-       uint32_t gbm_format;
 
-       enum dpms_enum dpms;
+       struct backlight *backlight;
 
        int vblank_pending;
        int page_flip_pending;
        int destroy_pending;
+};
+
+struct drm_logical_output {
+       struct weston_output   base;
+       struct wl_list output_list;
+
+       int page_flip_refcount;
+       uint32_t gbm_format;
+       enum dpms_enum dpms;
 
        struct gbm_surface *gbm_surface;
        struct gbm_bo *gbm_cursor_bo[2];
@@ -181,7 +193,6 @@ struct drm_output {
        struct weston_view *cursor_view;
        int current_cursor;
        struct drm_fb *current, *next;
-       struct backlight *backlight;
 
        struct drm_fb *dumb[2];
        pixman_image_t *image[2];
@@ -229,7 +240,7 @@ static struct gl_renderer_interface *gl_renderer;
 static const char default_seat[] = "seat0";
 
 static void
-drm_output_set_cursor(struct drm_output *output);
+drm_output_set_cursor(struct drm_logical_output *output);
 
 static void
 drm_output_update_msc(struct weston_output *output_base, unsigned int seq);
@@ -237,7 +248,7 @@ drm_output_update_msc(struct weston_output *output_base, 
unsigned int seq);
 static int
 drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
 {
-       struct weston_compositor *ec = output->base.compositor;
+       struct weston_compositor *ec = output->base->base.compositor;
        struct drm_backend *b =(struct drm_backend *)ec->backend;
        int crtc;
 
@@ -423,7 +434,7 @@ drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer 
*buffer)
 }
 
 static void
-drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
+drm_output_release_fb(struct drm_logical_output *output, struct drm_fb *fb)
 {
        if (!fb)
                return;
@@ -441,7 +452,7 @@ drm_output_release_fb(struct drm_output *output, struct 
drm_fb *fb)
 }
 
 static uint32_t
-drm_output_check_scanout_format(struct drm_output *output,
+drm_output_check_scanout_format(struct drm_logical_output *output,
                                struct weston_surface *es, struct gbm_bo *bo)
 {
        uint32_t format;
@@ -471,7 +482,7 @@ drm_output_check_scanout_format(struct drm_output *output,
 }
 
 static struct weston_plane *
-drm_output_prepare_scanout_view(struct drm_output *output,
+drm_output_prepare_scanout_view(struct drm_logical_output *output,
                                struct weston_view *ev)
 {
        struct weston_output *output_base = &output->base;
@@ -519,7 +530,8 @@ drm_output_prepare_scanout_view(struct drm_output *output,
 }
 
 static void
-drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
+drm_output_render_gl(struct drm_logical_output *output,
+                     pixman_region32_t *damage)
 {
        struct drm_backend *b =
                (struct drm_backend *)output->base.compositor->backend;
@@ -543,7 +555,8 @@ drm_output_render_gl(struct drm_output *output, 
pixman_region32_t *damage)
 }
 
 static void
-drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
+drm_output_render_pixman(struct drm_logical_output *output,
+                         pixman_region32_t *damage)
 {
        struct weston_compositor *ec = output->base.compositor;
        pixman_region32_t total_damage, previous_damage;
@@ -569,7 +582,7 @@ drm_output_render_pixman(struct drm_output *output, 
pixman_region32_t *damage)
 }
 
 static void
-drm_output_render(struct drm_output *output, pixman_region32_t *damage)
+drm_output_render(struct drm_logical_output *output, pixman_region32_t *damage)
 {
        struct weston_compositor *c = output->base.compositor;
        struct drm_backend *b = (struct drm_backend *)c->backend;
@@ -634,98 +647,117 @@ static int
 drm_output_repaint(struct weston_output *output_base,
                   pixman_region32_t *damage)
 {
-       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_logical_output *logical_output =
+               (struct drm_logical_output *)output_base;
+       struct drm_output *output;
        struct drm_backend *backend =
                (struct drm_backend *)output_base->compositor->backend;
        struct drm_sprite *s;
        struct drm_mode *mode;
        int ret = 0;
 
-       if (output->destroy_pending)
-               return -1;
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (output->destroy_pending)
+                       return -1;
+       }
 
-       if (!output->next)
-               drm_output_render(output, damage);
-       if (!output->next)
+       if (!logical_output->next)
+               drm_output_render(logical_output, damage);
+       if (!logical_output->next)
                return -1;
 
        mode = container_of(output_base->current_mode, struct drm_mode, base);
-       if (!output->current ||
-           output->current->stride != output->next->stride) {
-               ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
-                                    output->next->fb_id, 0, 0,
-                                    &output->connector_id, 1,
-                                    &mode->mode_info);
-               if (ret) {
-                       weston_log("set mode failed: %m\n");
-                       goto err_pageflip;
+       if (!logical_output->current ||
+           logical_output->current->stride != logical_output->next->stride) {
+               wl_list_for_each(output, &logical_output->output_list, link) {
+                       ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
+                                            logical_output->next->fb_id, 0, 0,
+                                            &output->connector_id, 1,
+                                            &mode->mode_info);
+                       if (ret) {
+                               weston_log("set mode failed: %m\n");
+                               goto err_pageflip;
+                       }
                }
                output_base->set_dpms(output_base, WESTON_DPMS_ON);
        }
 
-       if (drmModePageFlip(backend->drm.fd, output->crtc_id,
-                           output->next->fb_id,
-                           DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
-               weston_log("queueing pageflip failed: %m\n");
-               goto err_pageflip;
-       }
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (output->page_flip_pending)
+                       continue;
+               if (drmModePageFlip(backend->drm.fd, output->crtc_id,
+                                   logical_output->next->fb_id,
+                                   DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
+                       weston_log("queueing pageflip failed: %m\n");
+                       goto err_pageflip;
+               }
 
-       output->page_flip_pending = 1;
+               output->page_flip_pending = 1;
+               ++logical_output->page_flip_refcount;
+       }
 
        if (!backend->cursors_are_broken)
-               drm_output_set_cursor(output);
+               drm_output_set_cursor(logical_output);
 
-       /*
-        * Now, update all the sprite surfaces
-        */
-       wl_list_for_each(s, &backend->sprite_list, link) {
-               uint32_t flags = 0, fb_id = 0;
-               drmVBlank vbl = {
-                       .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
-                       .request.sequence = 1,
-               };
+       /* Sprite support is disabled on clone mode for now. */
+       if (wl_list_length(&logical_output->output_list) == 1) {
+               /* Fetches the only output present from the list */
+               wl_list_for_each(output, &logical_output->output_list, link);
 
-               if ((!s->current && !s->next) ||
-                   !drm_sprite_crtc_supported(output, s->possible_crtcs))
-                       continue;
+               /*
+                * Now, update all the sprite surfaces
+                */
+               wl_list_for_each(s, &backend->sprite_list, link) {
+                       uint32_t flags = 0, fb_id = 0;
+                       drmVBlank vbl = {
+                               .request.type = DRM_VBLANK_RELATIVE |
+                                               DRM_VBLANK_EVENT,
+                               .request.sequence = 1,
+                       };
+
+                       if ((!s->current && !s->next) ||
+                           !drm_sprite_crtc_supported(output,
+                                                      s->possible_crtcs))
+                               continue;
 
-               if (s->next && !backend->sprites_hidden)
-                       fb_id = s->next->fb_id;
+                       if (s->next && !backend->sprites_hidden)
+                               fb_id = s->next->fb_id;
 
-               ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
-                                     output->crtc_id, fb_id, flags,
-                                     s->dest_x, s->dest_y,
-                                     s->dest_w, s->dest_h,
-                                     s->src_x, s->src_y,
-                                     s->src_w, s->src_h);
-               if (ret)
-                       weston_log("setplane failed: %d: %s\n",
-                               ret, strerror(errno));
+                       ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
+                                             output->crtc_id, fb_id, flags,
+                                             s->dest_x, s->dest_y,
+                                             s->dest_w, s->dest_h,
+                                             s->src_x, s->src_y,
+                                             s->src_w, s->src_h);
+                       if (ret)
+                               weston_log("setplane failed: %d: %s\n",
+                                          ret, strerror(errno));
 
-               vbl.request.type |= drm_waitvblank_pipe(output);
+                       vbl.request.type |= drm_waitvblank_pipe(output);
 
-               /*
-                * Queue a vblank signal so we know when the surface
-                * becomes active on the display or has been replaced.
-                */
-               vbl.request.signal = (unsigned long)s;
-               ret = drmWaitVBlank(backend->drm.fd, &vbl);
-               if (ret) {
-                       weston_log("vblank event request failed: %d: %s\n",
-                               ret, strerror(errno));
-               }
+                       /*
+                        * Queue a vblank signal so we know when the surface
+                        * becomes active on the display or has been replaced.
+                        */
+                       vbl.request.signal = (unsigned long)s;
+                       ret = drmWaitVBlank(backend->drm.fd, &vbl);
+                       if (ret) {
+                               weston_log("vblank event request failed: %d:"
+                                          " %s\n", ret, strerror(errno));
+                       }
 
-               s->output = output;
-               output->vblank_pending = 1;
+                       s->output = output;
+                       output->vblank_pending = 1;
+               }
        }
 
        return 0;
 
 err_pageflip:
-       output->cursor_view = NULL;
-       if (output->next) {
-               drm_output_release_fb(output, output->next);
-               output->next = NULL;
+       logical_output->cursor_view = NULL;
+       if (logical_output->next) {
+               drm_output_release_fb(logical_output, logical_output->next);
+               logical_output->next = NULL;
        }
 
        return -1;
@@ -734,13 +766,16 @@ err_pageflip:
 static void
 drm_output_start_repaint_loop(struct weston_output *output_base)
 {
-       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_logical_output *logical_output =
+               (struct drm_logical_output *)output_base;
+       struct drm_output *output;
        struct drm_backend *backend = (struct drm_backend *)
                output_base->compositor->backend;
        uint32_t fb_id;
        struct timespec ts, tnow;
        struct timespec vbl2now;
        int64_t refresh_nsec;
+       long last_sec = 0, last_usec = 0;
        int ret;
        drmVBlank vbl = {
                .request.type = DRM_VBLANK_RELATIVE,
@@ -748,20 +783,32 @@ drm_output_start_repaint_loop(struct weston_output 
*output_base)
                .request.signal = 0,
        };
 
-       if (output->destroy_pending)
-               return;
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (output->destroy_pending)
+                       return;
+       }
 
-       if (!output->current) {
+       if (!logical_output->current) {
                /* We can't page flip if there's no mode set */
                goto finish_frame;
        }
 
        /* Try to get current msc and timestamp via instant query */
-       vbl.request.type |= drm_waitvblank_pipe(output);
-       ret = drmWaitVBlank(backend->drm.fd, &vbl);
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               vbl.request.type |= drm_waitvblank_pipe(output);
+               ret = drmWaitVBlank(backend->drm.fd, &vbl);
+               if (ret != 0)
+                       continue;
+               if (last_sec < vbl.reply.tval_sec ||
+                   (last_sec == vbl.reply.tval_sec &&
+                    last_usec < vbl.reply.tval_usec)) {
+                       last_sec = vbl.reply.tval_sec;
+                       last_usec = vbl.reply.tval_usec;
+               }
+       }
 
        /* Error ret or zero timestamp means failure to get valid timestamp */
-       if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
+       if (last_sec > 0 || last_usec > 0) {
                ts.tv_sec = vbl.reply.tval_sec;
                ts.tv_nsec = vbl.reply.tval_usec * 1000;
 
@@ -785,12 +832,15 @@ drm_output_start_repaint_loop(struct weston_output 
*output_base)
        /* Immediate query didn't provide valid timestamp.
         * Use pageflip fallback.
         */
-       fb_id = output->current->fb_id;
+       fb_id = logical_output->current->fb_id;
 
-       if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
-                           DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
-               weston_log("queueing pageflip failed: %m\n");
-               goto finish_frame;
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
+                                   DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
+                       weston_log("queueing pageflip failed: %m\n");
+                       goto finish_frame;
+               }
+               ++logical_output->page_flip_refcount;
        }
 
        return;
@@ -819,21 +869,22 @@ vblank_handler(int fd, unsigned int frame, unsigned int 
sec, unsigned int usec,
 {
        struct drm_sprite *s = (struct drm_sprite *)data;
        struct drm_output *output = s->output;
+       struct drm_logical_output *logical_output = output->base;
        struct timespec ts;
        uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
                         WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
 
-       drm_output_update_msc(&output->base, frame);
+       drm_output_update_msc(&logical_output->base, frame);
        output->vblank_pending = 0;
 
-       drm_output_release_fb(output, s->current);
+       drm_output_release_fb(logical_output, s->current);
        s->current = s->next;
        s->next = NULL;
 
        if (!output->page_flip_pending) {
                ts.tv_sec = sec;
                ts.tv_nsec = usec * 1000;
-               weston_output_finish_frame(&output->base, &ts, flags);
+               weston_output_finish_frame(&logical_output->base, &ts, flags);
        }
 }
 
@@ -845,35 +896,37 @@ page_flip_handler(int fd, unsigned int frame,
                  unsigned int sec, unsigned int usec, void *data)
 {
        struct drm_output *output = (struct drm_output *) data;
+       struct drm_logical_output *logical_output = output->base;
        struct timespec ts;
        uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
                         WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
                         WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
 
-       drm_output_update_msc(&output->base, frame);
+       drm_output_update_msc(&logical_output->base, frame);
 
        /* We don't set page_flip_pending on start_repaint_loop, in that case
         * we just want to page flip to the current buffer to get an accurate
         * timestamp */
-       if (output->page_flip_pending) {
-               drm_output_release_fb(output, output->current);
-               output->current = output->next;
-               output->next = NULL;
+       if (output->page_flip_pending &&
+           --logical_output->page_flip_refcount == 0) {
+               drm_output_release_fb(logical_output, logical_output->current);
+               logical_output->current = logical_output->next;
+               logical_output->next = NULL;
        }
 
        output->page_flip_pending = 0;
 
        if (output->destroy_pending)
-               drm_output_destroy(&output->base);
+               drm_output_destroy(&logical_output->base);
        else if (!output->vblank_pending) {
                ts.tv_sec = sec;
                ts.tv_nsec = usec * 1000;
-               weston_output_finish_frame(&output->base, &ts, flags);
+               weston_output_finish_frame(&logical_output->base, &ts, flags);
 
                /* We can't call this from frame_notify, because the output's
                 * repaint needed flag is cleared just after that */
-               if (output->recorder)
-                       weston_output_schedule_repaint(&output->base);
+               if (logical_output->recorder)
+                       weston_output_schedule_repaint(&logical_output->base);
        }
 }
 
@@ -914,14 +967,15 @@ drm_view_transform_supported(struct weston_view *ev)
 }
 
 static struct weston_plane *
-drm_output_prepare_overlay_view(struct drm_output *output,
+drm_output_prepare_overlay_view(struct drm_logical_output *logical_output,
                                struct weston_view *ev)
 {
-       struct weston_output *output_base = &output->base;
+       struct weston_output *output_base = &logical_output->base;
        struct weston_compositor *ec = output_base->compositor;
        struct drm_backend *b = (struct drm_backend *)ec->backend;
        struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
        struct wl_resource *buffer_resource;
+       struct drm_output *output;
        struct drm_sprite *s;
        struct linux_dmabuf_buffer *dmabuf;
        int found = 0;
@@ -959,8 +1013,14 @@ drm_output_prepare_overlay_view(struct drm_output *output,
        if (!drm_view_transform_supported(ev))
                return NULL;
 
+       if (wl_list_length(&logical_output->output_list) != 1)
+               return NULL;
+       /* Fetches the only output present from the list */
+       wl_list_for_each(output, &logical_output->output_list, link);
+
        wl_list_for_each(s, &b->sprite_list, link) {
-               if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
+               if (!drm_sprite_crtc_supported(output,
+                                              s->possible_crtcs))
                        continue;
 
                if (!s->next) {
@@ -1088,7 +1148,7 @@ drm_output_prepare_overlay_view(struct drm_output *output,
 }
 
 static struct weston_plane *
-drm_output_prepare_cursor_view(struct drm_output *output,
+drm_output_prepare_cursor_view(struct drm_logical_output *output,
                               struct weston_view *ev)
 {
        struct drm_backend *b =
@@ -1167,39 +1227,46 @@ cursor_bo_update(struct drm_backend *b, struct gbm_bo 
*bo,
 }
 
 static void
-drm_output_set_cursor(struct drm_output *output)
+drm_output_set_cursor(struct drm_logical_output *logical_output)
 {
-       struct weston_view *ev = output->cursor_view;
+       struct drm_output *output;
+       struct weston_plane *cursor_plane = &logical_output->cursor_plane;
+       struct weston_view *ev = logical_output->cursor_view;
        struct weston_buffer *buffer;
        struct drm_backend *b =
-               (struct drm_backend *) output->base.compositor->backend;
+               (struct drm_backend *) logical_output->base.compositor->backend;
        EGLint handle;
        struct gbm_bo *bo;
        float x, y;
 
-       output->cursor_view = NULL;
+       logical_output->cursor_view = NULL;
        if (ev == NULL) {
-               drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
-               output->cursor_plane.x = INT32_MIN;
-               output->cursor_plane.y = INT32_MIN;
+               wl_list_for_each(output, &logical_output->output_list, link)
+                       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+               cursor_plane->x = INT32_MIN;
+               cursor_plane->y = INT32_MIN;
                return;
        }
 
        buffer = ev->surface->buffer_ref.buffer;
 
        if (buffer &&
-           pixman_region32_not_empty(&output->cursor_plane.damage)) {
-               pixman_region32_fini(&output->cursor_plane.damage);
-               pixman_region32_init(&output->cursor_plane.damage);
-               output->current_cursor ^= 1;
-               bo = output->gbm_cursor_bo[output->current_cursor];
+           pixman_region32_not_empty(&cursor_plane->damage)) {
+               pixman_region32_fini(&cursor_plane->damage);
+               pixman_region32_init(&cursor_plane->damage);
+               logical_output->current_cursor ^= 1;
+               bo = logical_output->gbm_cursor_bo[
+                       logical_output->current_cursor];
 
                cursor_bo_update(b, bo, ev);
                handle = gbm_bo_get_handle(bo).s32;
-               if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
-                               b->cursor_width, b->cursor_height)) {
-                       weston_log("failed to set cursor: %m\n");
-                       b->cursors_are_broken = 1;
+               wl_list_for_each(output, &logical_output->output_list, link) {
+                       if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
+                                            b->cursor_width,
+                                            b->cursor_height)) {
+                               weston_log("failed to set cursor: %m\n");
+                               b->cursors_are_broken = 1;
+                       }
                }
        }
 
@@ -1208,17 +1275,20 @@ drm_output_set_cursor(struct drm_output *output)
        /* From global to output space, output transform is guaranteed to be
         * NORMAL by drm_output_prepare_cursor_view().
         */
-       x = (x - output->base.x) * output->base.current_scale;
-       y = (y - output->base.y) * output->base.current_scale;
-
-       if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
-               if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
-                       weston_log("failed to move cursor: %m\n");
-                       b->cursors_are_broken = 1;
+       x = (x - logical_output->base.x) * logical_output->base.current_scale;
+       y = (y - logical_output->base.y) * logical_output->base.current_scale;
+
+       if (cursor_plane->x != x || cursor_plane->y != y) {
+               wl_list_for_each(output, &logical_output->output_list, link) {
+                       if (drmModeMoveCursor(b->drm.fd, output->crtc_id,
+                                             x, y)) {
+                               weston_log("failed to move cursor: %m\n");
+                               b->cursors_are_broken = 1;
+                       }
                }
 
-               output->cursor_plane.x = x;
-               output->cursor_plane.y = y;
+               cursor_plane->x = x;
+               cursor_plane->y = y;
        }
 }
 
@@ -1227,7 +1297,8 @@ drm_assign_planes(struct weston_output *output_base)
 {
        struct drm_backend *b =
                (struct drm_backend *)output_base->compositor->backend;
-       struct drm_output *output = (struct drm_output *)output_base;
+       struct drm_logical_output *output =
+               (struct drm_logical_output *)output_base;
        struct weston_view *ev, *next;
        pixman_region32_t overlap, surface_overlap;
        struct weston_plane *primary, *next_plane;
@@ -1307,52 +1378,58 @@ drm_assign_planes(struct weston_output *output_base)
 }
 
 static void
-drm_output_fini_pixman(struct drm_output *output);
+drm_output_fini_pixman(struct drm_logical_output *output);
 
 static void
 drm_output_destroy(struct weston_output *output_base)
 {
-       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_logical_output *logical_output =
+               (struct drm_logical_output *)output_base;
+       struct drm_output *output;
        struct drm_backend *b =
                (struct drm_backend *)output_base->compositor->backend;
-       drmModeCrtcPtr origcrtc = output->original_crtc;
+       drmModeCrtcPtr origcrtc;
 
-       if (output->page_flip_pending) {
-               output->destroy_pending = 1;
-               weston_log("destroy output while page flip pending\n");
-               return;
-       }
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (output->page_flip_pending) {
+                       output->destroy_pending = 1;
+                       weston_log("destroy output while page flip pending\n");
+                       return;
+               }
 
-       if (output->backlight)
-               backlight_destroy(output->backlight);
+               if (output->backlight)
+                       backlight_destroy(output->backlight);
 
-       drmModeFreeProperty(output->dpms_prop);
+               drmModeFreeProperty(output->dpms_prop);
 
-       /* Turn off hardware cursor */
-       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+               /* Turn off hardware cursor */
+               drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
 
-       /* Restore original CRTC state */
-       drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
-                      origcrtc->x, origcrtc->y,
-                      &output->connector_id, 1, &origcrtc->mode);
-       drmModeFreeCrtc(origcrtc);
+               /* Restore original CRTC state */
+               origcrtc = output->original_crtc;
+               drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id,
+                              origcrtc->buffer_id,
+                              origcrtc->x, origcrtc->y,
+                              &output->connector_id, 1, &origcrtc->mode);
+               drmModeFreeCrtc(origcrtc);
 
-       b->crtc_allocator &= ~(1 << output->crtc_id);
-       b->connector_allocator &= ~(1 << output->connector_id);
+               b->crtc_allocator &= ~(1 << output->crtc_id);
+               b->connector_allocator &= ~(1 << output->connector_id);
+       }
 
        if (b->use_pixman) {
-               drm_output_fini_pixman(output);
+               drm_output_fini_pixman(logical_output);
        } else {
                gl_renderer->output_destroy(output_base);
-               gbm_surface_destroy(output->gbm_surface);
+               gbm_surface_destroy(logical_output->gbm_surface);
        }
 
-       weston_plane_release(&output->fb_plane);
-       weston_plane_release(&output->cursor_plane);
+       weston_plane_release(&logical_output->fb_plane);
+       weston_plane_release(&logical_output->cursor_plane);
 
-       weston_output_destroy(&output->base);
+       weston_output_destroy(output_base);
 
-       free(output);
+       free(logical_output);
 }
 
 /**
@@ -1367,7 +1444,7 @@ drm_output_destroy(struct weston_output *output_base)
  * @returns Pointer to a mode from the output's mode list
  */
 static struct drm_mode *
-choose_mode (struct weston_output *output_base, struct weston_mode 
*target_mode)
+choose_mode(struct weston_output *output_base, struct weston_mode *target_mode)
 {
        struct drm_mode *tmp_mode = NULL, *mode;
 
@@ -1392,14 +1469,17 @@ choose_mode (struct weston_output *output_base, struct 
weston_mode *target_mode)
 }
 
 static int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
+drm_output_init_egl(struct drm_logical_output *output, struct drm_backend *b);
 static int
-drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
+drm_output_init_pixman(struct drm_logical_output *output,
+                       struct drm_backend *b);
 
 static int
-drm_output_switch_mode(struct weston_output *output_base, struct weston_mode 
*mode)
+drm_output_switch_mode(struct weston_output *output_base,
+                       struct weston_mode *mode)
 {
-       struct drm_output *output;
+       struct drm_logical_output *output =
+               (struct drm_logical_output *)output_base;
        struct drm_mode *drm_mode;
        struct drm_backend *b;
 
@@ -1414,8 +1494,7 @@ drm_output_switch_mode(struct weston_output *output_base, 
struct weston_mode *mo
        }
 
        b = (struct drm_backend *)output_base->compositor->backend;
-       output = (struct drm_output *)output_base;
-       drm_mode = choose_mode(&output->base, mode);
+       drm_mode = choose_mode(output_base, mode);
 
        if (!drm_mode) {
                weston_log("%s, invalid resolution:%dx%d\n", __func__, 
mode->width, mode->height);
@@ -1444,7 +1523,7 @@ drm_output_switch_mode(struct weston_output *output_base, 
struct weston_mode *mo
                        return -1;
                }
        } else {
-               gl_renderer->output_destroy(&output->base);
+               gl_renderer->output_destroy(output_base);
                gbm_surface_destroy(output->gbm_surface);
 
                if (drm_output_init_egl(output, b) < 0) {
@@ -1704,21 +1783,25 @@ drm_get_backlight(struct drm_output *output)
 static void
 drm_set_backlight(struct weston_output *output_base, uint32_t value)
 {
-       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_logical_output *logical_output =
+               (struct drm_logical_output *)output_base;
+       struct drm_output *output;
        long max_brightness, new_brightness;
 
-       if (!output->backlight)
-               return;
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (!output->backlight)
+                       return;
 
-       if (value > 255)
-               return;
+               if (value > 255)
+                       return;
 
-       max_brightness = backlight_get_max_brightness(output->backlight);
+               max_brightness = 
backlight_get_max_brightness(output->backlight);
 
-       /* get denormalized value */
-       new_brightness = (value * max_brightness) / 255;
+               /* get denormalized value */
+               new_brightness = (value * max_brightness) / 255;
 
-       backlight_set_brightness(output->backlight, new_brightness);
+               backlight_set_brightness(output->backlight, new_brightness);
+       }
 }
 
 static drmModePropertyPtr
@@ -1744,23 +1827,28 @@ drm_get_prop(int fd, drmModeConnectorPtr connector, 
const char *name)
 static void
 drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
 {
-       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_logical_output *logical_output =
+               (struct drm_logical_output *)output_base;
        struct weston_compositor *ec = output_base->compositor;
        struct drm_backend *b = (struct drm_backend *)ec->backend;
+       struct drm_output *output;
        int ret;
 
-       if (!output->dpms_prop)
-               return;
+       wl_list_for_each(output, &logical_output->output_list, link) {
+               if (!output->dpms_prop)
+                       continue;
 
-       ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
-                                         output->dpms_prop->prop_id, level);
-       if (ret) {
-               weston_log("DRM: DPMS: failed property set for %s\n",
-                          output_base->name);
-               return;
+               ret = drmModeConnectorSetProperty(b->drm.fd,
+                                                 output->connector_id,
+                                                 output->dpms_prop->prop_id,
+                                                 level);
+               if (ret) {
+                       weston_log("DRM: DPMS: failed property set for %s\n",
+                                  output->name);
+                       continue;
+               }
        }
-
-       output->dpms = level;
+       logical_output->dpms = level;
 }
 
 static const char * const connector_type_names[] = {
@@ -1831,7 +1919,7 @@ find_crtc_for_connector(struct drm_backend *b,
 
 /* Init output state that depends on gl or gbm */
 static int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
+drm_output_init_egl(struct drm_logical_output *output, struct drm_backend *b)
 {
        EGLint format[2] = {
                output->gbm_format,
@@ -1883,7 +1971,8 @@ drm_output_init_egl(struct drm_output *output, struct 
drm_backend *b)
 }
 
 static int
-drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
+drm_output_init_pixman(struct drm_logical_output *output,
+                       struct drm_backend *b)
 {
        int w = output->base.current_mode->width;
        int h = output->base.current_mode->height;
@@ -1927,7 +2016,7 @@ err:
 }
 
 static void
-drm_output_fini_pixman(struct drm_output *output)
+drm_output_fini_pixman(struct drm_logical_output *output)
 {
        unsigned int i;
 
@@ -2073,11 +2162,11 @@ find_and_parse_output_edid(struct drm_backend *b,
                           output->edid.monitor_name,
                           output->edid.serial_number);
                if (output->edid.pnp_id[0] != '\0')
-                       output->base.make = output->edid.pnp_id;
+                       output->base->base.make = output->edid.pnp_id;
                if (output->edid.monitor_name[0] != '\0')
-                       output->base.model = output->edid.monitor_name;
+                       output->base->base.model = output->edid.monitor_name;
                if (output->edid.serial_number[0] != '\0')
-                       output->base.serial_number = output->edid.serial_number;
+                       output->base->base.serial_number = 
output->edid.serial_number;
        }
        drmModeFreePropertyBlob(edid_blob);
 }
@@ -2302,6 +2391,7 @@ create_output_for_connector(struct drm_backend *b,
                            drmModeConnector *connector,
                            int x, int y, struct udev_device *drm_device)
 {
+       struct drm_logical_output *logical_output = NULL;
        struct drm_output *output;
        struct drm_mode *drm_mode, *next, *current;
        struct weston_output *output_base;
@@ -2312,6 +2402,7 @@ create_output_for_connector(struct drm_backend *b,
        char *s, *name;
        enum output_config config;
        uint32_t transform;
+       bool is_clone = false;
 
        i = find_crtc_for_connector(b, resources, connector);
        if (i < 0) {
@@ -2321,20 +2412,32 @@ create_output_for_connector(struct drm_backend *b,
 
        name = make_connector_name(connector);
 
-       output = zalloc(sizeof *output);
-       if (output == NULL)
-               return -1;
-
-       output_base = &output->base;
-       output_base->subpixel = drm_subpixel_to_wayland(connector->subpixel);
-       output_base->name = name;
-       output_base->make = "unknown";
-       output_base->model = "unknown";
-       output_base->serial_number = "unknown";
-       wl_list_init(&output_base->mode_list);
-
        section = weston_config_get_section(b->compositor->config, "output", 
"name",
                                            name);
+
+       weston_config_section_get_string(section, "same-as", &s, "");
+       if (strcmp(s, "") != 0) {
+               struct drm_logical_output *temporary_logical_output = NULL;
+               wl_list_for_each(temporary_logical_output,
+                                &b->compositor->output_list, base.link) {
+                       if (strcmp(temporary_logical_output->base.name, s) == 
0) {
+                               logical_output = temporary_logical_output;
+                               break;
+                       }
+               }
+               if (logical_output == NULL)
+                       return -1;
+               is_clone = true;
+       } else {
+               logical_output = zalloc(sizeof *logical_output);
+               if (logical_output == NULL)
+                       return -1;
+               is_clone = false;
+       }
+       free(s);
+
+       output_base = &logical_output->base;
+
        weston_config_section_get_string(section, "mode", &s, "preferred");
        if (strcmp(s, "off") == 0)
                config = OUTPUT_CONFIG_OFF;
@@ -2352,21 +2455,42 @@ create_output_for_connector(struct drm_backend *b,
        }
        free(s);
 
-       weston_config_section_get_int(section, "scale", &scale, 1);
-       weston_config_section_get_string(section, "transform", &s, "normal");
-       if (weston_parse_transform(s, &transform) < 0)
-               weston_log("Invalid transform \"%s\" for output %s\n", s, name);
+       if (!is_clone) {
+               output_base->subpixel =
+                       drm_subpixel_to_wayland(connector->subpixel);
+               output_base->name = name;
+               output_base->make = "unknown";
+               output_base->model = "unknown";
+               output_base->serial_number = "unknown";
+               wl_list_init(&output_base->mode_list);
 
-       free(s);
+               weston_config_section_get_int(section, "scale", &scale, 1);
+               weston_config_section_get_string(section, "transform", &s,
+                                                "normal");
+               if (weston_parse_transform(s, &transform) < 0)
+                       weston_log("Invalid transform \"%s\" for output %s\n",
+                                  s, name);
 
-       if (get_gbm_format_from_section(section,
-                                       b->gbm_format,
-                                       &output->gbm_format) == -1)
-               output->gbm_format = b->gbm_format;
+               free(s);
 
-       weston_config_section_get_string(section, "seat", &s, "");
-       setup_output_seat_constraint(b, output_base, s);
-       free(s);
+               if (get_gbm_format_from_section(section,
+                                               b->gbm_format,
+                                               &logical_output->gbm_format) == 
-1)
+                       logical_output->gbm_format = b->gbm_format;
+
+               weston_config_section_get_string(section, "seat", &s, "");
+               setup_output_seat_constraint(b, output_base, s);
+               free(s);
+
+               wl_list_init(&logical_output->output_list);
+       }
+
+       output = zalloc(sizeof *output);
+       if (output == NULL)
+               return -1;
+
+       wl_list_insert(&logical_output->output_list, &output->link);
+       output->base = logical_output;
 
        output->crtc_id = resources->crtcs[i];
        output->pipe = i;
@@ -2377,15 +2501,6 @@ create_output_for_connector(struct drm_backend *b,
        output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
        output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
 
-       if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
-               goto err_free;
-
-       for (i = 0; i < connector->count_modes; i++) {
-               drm_mode = drm_output_add_mode(output_base, 
&connector->modes[i]);
-               if (!drm_mode)
-                       goto err_free;
-       }
-
        if (config == OUTPUT_CONFIG_OFF) {
                weston_log("Disabling output %s\n", name);
                drmModeSetCrtc(b->drm.fd, output->crtc_id,
@@ -2393,62 +2508,80 @@ create_output_for_connector(struct drm_backend *b,
                goto err_free;
        }
 
-       current = drm_output_choose_initial_mode(output_base, config,
-                                                width, height,
-                                                &crtc_mode, &modeline);
-       if (!current)
-               goto err_free;
-       output_base->current_mode = &current->base;
-       output_base->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
+       find_and_parse_output_edid(b, output, connector);
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+               output_base->connection_internal = 1;
 
-       weston_output_init(output_base, b->compositor, x, y,
-                          connector->mmWidth, connector->mmHeight,
-                          transform, scale);
+       if (!is_clone) {
+               if (connector_get_current_mode(connector, b->drm.fd, 
&crtc_mode) < 0)
+                       goto err_free;
 
-       if (b->use_pixman) {
-               if (drm_output_init_pixman(output, b) < 0) {
-                       weston_log("Failed to init output pixman state\n");
+               for (i = 0; i < connector->count_modes; i++) {
+                       drm_mode = drm_output_add_mode(output_base,
+                                                      &connector->modes[i]);
+                       if (!drm_mode)
+                               goto err_free;
+               }
+
+               current = drm_output_choose_initial_mode(output_base, config,
+                                                        width, height,
+                                                        &crtc_mode,
+                                                        &modeline);
+               if (!current)
+                       goto err_free;
+               output_base->current_mode = &current->base;
+               output_base->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
+
+               weston_output_init(output_base, b->compositor, x, y,
+                                  connector->mmWidth, connector->mmHeight,
+                                  transform, scale);
+
+               if (b->use_pixman) {
+                       if (drm_output_init_pixman(logical_output, b) < 0) {
+                               weston_log("Failed to init output pixman 
state\n");
+                               goto err_output;
+                       }
+               } else if (drm_output_init_egl(logical_output, b) < 0) {
+                       weston_log("Failed to init output gl state\n");
                        goto err_output;
                }
-       } else if (drm_output_init_egl(output, b) < 0) {
-               weston_log("Failed to init output gl state\n");
-               goto err_output;
-       }
-
-       output->backlight = backlight_init(drm_device,
-                                          connector->connector_type);
-       if (output->backlight) {
-               weston_log("Initialized backlight, device %s\n",
-                          output->backlight->path);
-               output_base->set_backlight = drm_set_backlight;
-               output_base->backlight_current = drm_get_backlight(output);
-       } else {
-               weston_log("Failed to initialize backlight\n");
-       }
 
-       weston_compositor_add_output(b->compositor, output_base);
+               output->backlight = backlight_init(drm_device,
+                                                  connector->connector_type);
+               if (output->backlight) {
+                       weston_log("Initialized backlight, device %s\n",
+                                  output->backlight->path);
+                       output_base->set_backlight = drm_set_backlight;
+                       output_base->backlight_current =
+                               drm_get_backlight(output);
+               } else {
+                       weston_log("Failed to initialize backlight\n");
+               }
 
-       find_and_parse_output_edid(b, output, connector);
-       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
-               output_base->connection_internal = 1;
+               weston_compositor_add_output(b->compositor, output_base);
 
-       output_base->start_repaint_loop = drm_output_start_repaint_loop;
-       output_base->repaint = drm_output_repaint;
-       output_base->destroy = drm_output_destroy;
-       output_base->assign_planes = drm_assign_planes;
-       output_base->set_dpms = drm_set_dpms;
-       output_base->switch_mode = drm_output_switch_mode;
+               output_base->start_repaint_loop = drm_output_start_repaint_loop;
+               output_base->repaint = drm_output_repaint;
+               output_base->destroy = drm_output_destroy;
+               output_base->assign_planes = drm_assign_planes;
+               output_base->set_dpms = drm_set_dpms;
+               output_base->switch_mode = drm_output_switch_mode;
 
-       output_base->gamma_size = output->original_crtc->gamma_size;
-       output_base->set_gamma = drm_output_set_gamma;
+               output_base->gamma_size = output->original_crtc->gamma_size;
+               output_base->set_gamma = drm_output_set_gamma;
 
-       weston_plane_init(&output->cursor_plane, b->compositor,
-                         INT32_MIN, INT32_MIN);
-       weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
+               weston_plane_init(&logical_output->cursor_plane, b->compositor,
+                                 INT32_MIN, INT32_MIN);
+               weston_plane_init(&logical_output->fb_plane, b->compositor,
+                                 0, 0);
 
-       weston_compositor_stack_plane(b->compositor, &output->cursor_plane, 
NULL);
-       weston_compositor_stack_plane(b->compositor, &output->fb_plane,
-                                     &b->compositor->primary_plane);
+               weston_compositor_stack_plane(b->compositor,
+                                             &logical_output->cursor_plane,
+                                             NULL);
+               weston_compositor_stack_plane(b->compositor,
+                                             &logical_output->fb_plane,
+                                             &b->compositor->primary_plane);
+       }
 
        weston_log("Output %s, (connector %d, crtc %d)\n", name,
                   output->connector_id, output->crtc_id);
@@ -2472,16 +2605,20 @@ err_output:
        weston_output_destroy(output_base);
 err_free:
        wl_list_for_each_safe(drm_mode, next, &output_base->mode_list,
-                                                       base.link) {
+                             base.link) {
                wl_list_remove(&drm_mode->base.link);
                free(drm_mode);
        }
 
+       wl_list_remove(&output->link);
        drmModeFreeCrtc(output->original_crtc);
        b->crtc_allocator &= ~(1 << output->crtc_id);
        b->connector_allocator &= ~(1 << output->connector_id);
        free(output);
 
+       if (!is_clone)
+               free(logical_output);
+
        return -1;
 }
 
@@ -2537,20 +2674,27 @@ static void
 destroy_sprites(struct drm_backend *backend)
 {
        struct drm_sprite *sprite, *next;
+       struct drm_logical_output *logical_output;
        struct drm_output *output;
 
-       output = container_of(backend->compositor->output_list.next,
-                             struct drm_output, base.link);
+       logical_output = container_of(backend->compositor->output_list.next,
+                                     struct drm_logical_output, base.link);
 
-       wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
-               drmModeSetPlane(backend->drm.fd,
-                               sprite->plane_id,
-                               output->crtc_id, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0);
-               drm_output_release_fb(output, sprite->current);
-               drm_output_release_fb(output, sprite->next);
-               weston_plane_release(&sprite->plane);
-               free(sprite);
+       /* Sprite support is disabled on clone mode for now. */
+       if (wl_list_length(&logical_output->output_list) == 1) {
+               /* Fetches the only output present from the list */
+               wl_list_for_each(output, &logical_output->output_list, link);
+
+               wl_list_for_each_safe(sprite, next, &backend->sprite_list, 
link) {
+                       drmModeSetPlane(backend->drm.fd,
+                                       sprite->plane_id,
+                                       output->crtc_id, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0);
+                       drm_output_release_fb(logical_output, sprite->current);
+                       drm_output_release_fb(logical_output, sprite->next);
+                       weston_plane_release(&sprite->plane);
+                       free(sprite);
+               }
        }
 }
 
@@ -2623,7 +2767,8 @@ update_outputs(struct drm_backend *b, struct udev_device 
*drm_device)
 {
        drmModeConnector *connector;
        drmModeRes *resources;
-       struct drm_output *output, *next;
+       struct drm_logical_output *logical_output, *next_logical_output;
+       struct drm_output *output, *next_output;
        int x = 0, y = 0;
        uint32_t connected = 0, disconnects = 0;
        int i;
@@ -2672,13 +2817,17 @@ update_outputs(struct drm_backend *b, struct 
udev_device *drm_device)
 
        disconnects = b->connector_allocator & ~connected;
        if (disconnects) {
-               wl_list_for_each_safe(output, next, &b->compositor->output_list,
-                                     base.link) {
-                       if (disconnects & (1 << output->connector_id)) {
-                               disconnects &= ~(1 << output->connector_id);
-                               weston_log("connector %d disconnected\n",
-                                      output->connector_id);
-                               drm_output_destroy(&output->base);
+               wl_list_for_each_safe(logical_output, next_logical_output,
+                                     &b->compositor->output_list, base.link) {
+                       wl_list_for_each_safe(output, next_output, 
&logical_output->output_list, link) {
+                               if (disconnects & (1 << output->connector_id)) {
+                                       disconnects &= ~(1 << 
output->connector_id);
+                                       weston_log("connector %d 
disconnected\n",
+                                              output->connector_id);
+                                       wl_list_remove(&output->link);
+                                       if 
(wl_list_empty(&logical_output->output_list))
+                                               
drm_output_destroy(&logical_output->base);
+                               }
                        }
                }
        }
@@ -2754,31 +2903,34 @@ drm_destroy(struct weston_compositor *ec)
 static void
 drm_backend_set_modes(struct drm_backend *backend)
 {
+       struct drm_logical_output *logical_output;
        struct drm_output *output;
        struct drm_mode *drm_mode;
        int ret;
 
-       wl_list_for_each(output, &backend->compositor->output_list, base.link) {
-               if (!output->current) {
+       wl_list_for_each(logical_output, &backend->compositor->output_list, 
base.link) {
+               if (!logical_output->current) {
                        /* If something that would cause the output to
                         * switch mode happened while in another vt, we
                         * might not have a current drm_fb. In that case,
                         * schedule a repaint and let drm_output_repaint
                         * handle setting the mode. */
-                       weston_output_schedule_repaint(&output->base);
+                       weston_output_schedule_repaint(&logical_output->base);
                        continue;
                }
 
-               drm_mode = (struct drm_mode *) output->base.current_mode;
-               ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
-                                    output->current->fb_id, 0, 0,
-                                    &output->connector_id, 1,
-                                    &drm_mode->mode_info);
-               if (ret < 0) {
-                       weston_log(
-                               "failed to set mode %dx%d for output at %d,%d: 
%m\n",
-                               drm_mode->base.width, drm_mode->base.height,
-                               output->base.x, output->base.y);
+               drm_mode = (struct drm_mode *)logical_output->base.current_mode;
+               wl_list_for_each(output, &logical_output->output_list, link) {
+                       ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
+                                            logical_output->current->fb_id, 0, 
0,
+                                            &output->connector_id, 1,
+                                            &drm_mode->mode_info);
+                       if (ret < 0) {
+                               weston_log(
+                                       "failed to set mode %dx%d for output at 
%d,%d: %m\n",
+                                       drm_mode->base.width, 
drm_mode->base.height,
+                                       logical_output->base.x, 
logical_output->base.y);
+                       }
                }
        }
 }
@@ -2789,6 +2941,7 @@ session_notify(struct wl_listener *listener, void *data)
        struct weston_compositor *compositor = data;
        struct drm_backend *b = (struct drm_backend *)compositor->backend;
        struct drm_sprite *sprite;
+       struct drm_logical_output *logical_output;
        struct drm_output *output;
 
        if (compositor->session_active) {
@@ -2812,19 +2965,26 @@ session_notify(struct wl_listener *listener, void *data)
                 * back, we schedule a repaint, which will process
                 * pending frame callbacks. */
 
-               wl_list_for_each(output, &compositor->output_list, base.link) {
-                       output->base.repaint_needed = 0;
-                       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+               wl_list_for_each(logical_output, &compositor->output_list, 
base.link) {
+                       logical_output->base.repaint_needed = 0;
+                       wl_list_for_each(output, &logical_output->output_list, 
link)
+                               drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 
0, 0);
                }
 
-               output = container_of(compositor->output_list.next,
-                                     struct drm_output, base.link);
+               logical_output = container_of(compositor->output_list.next,
+                                     struct drm_logical_output, base.link);
 
-               wl_list_for_each(sprite, &b->sprite_list, link)
-                       drmModeSetPlane(b->drm.fd,
-                                       sprite->plane_id,
-                                       output->crtc_id, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0, 0);
+               /* Sprite support is disabled on clone mode for now. */
+               if (wl_list_length(&logical_output->output_list) == 1) {
+                       /* Fetches the only output present from the list */
+                       wl_list_for_each(output, &logical_output->output_list, 
link);
+
+                       wl_list_for_each(sprite, &b->sprite_list, link)
+                               drmModeSetPlane(b->drm.fd,
+                                               sprite->plane_id,
+                                               output->crtc_id, 0, 0,
+                                               0, 0, 0, 0, 0, 0, 0, 0);
+               }
        };
 }
 
@@ -2907,7 +3067,7 @@ planes_binding(struct weston_keyboard *keyboard, uint32_t 
time, uint32_t key,
 
 #ifdef BUILD_VAAPI_RECORDER
 static void
-recorder_destroy(struct drm_output *output)
+recorder_destroy(struct drm_logical_output *output)
 {
        vaapi_recorder_destroy(output->recorder);
        output->recorder = NULL;
@@ -2921,11 +3081,11 @@ recorder_destroy(struct drm_output *output)
 static void
 recorder_frame_notify(struct wl_listener *listener, void *data)
 {
-       struct drm_output *output;
+       struct drm_logical_output *output;
        struct drm_backend *b;
        int fd, ret;
 
-       output = container_of(listener, struct drm_output,
+       output = container_of(listener, struct drm_logical_output,
                              recorder_frame_listener);
        b = (struct drm_backend *)output->base.compositor->backend;
 
@@ -2970,11 +3130,11 @@ recorder_binding(struct weston_keyboard *keyboard, 
uint32_t time, uint32_t key,
                 void *data)
 {
        struct drm_backend *b = data;
-       struct drm_output *output;
+       struct drm_logical_output *output;
        int width, height;
 
        output = container_of(b->compositor->output_list.next,
-                             struct drm_output, base.link);
+                             struct drm_logical_output, base.link);
 
        if (!output->recorder) {
                if (output->gbm_format != GBM_FORMAT_XRGB8888) {
@@ -3018,7 +3178,7 @@ recorder_binding(struct weston_keyboard *keyboard, 
uint32_t time, uint32_t key,
 static void
 switch_to_gl_renderer(struct drm_backend *b)
 {
-       struct drm_output *output;
+       struct drm_logical_output *output;
        bool dmabuf_support_inited;
 
        if (!b->use_pixman)
-- 
2.8.2

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to