[PATCH weston 7/8] compositor-drm: Implement clone mode, refactor output into logical ones

Emmanuel Gil Peyrot emmanuel.peyrot at collabora.com
Mon May 2 21:40:16 UTC 2016


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.peyrot at 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



More information about the wayland-devel mailing list