[PATCH 7/9] compositor: Hot plug a output in clone mode

Xiong Zhang xiong.y.zhang at intel.com
Thu Feb 13 23:17:42 PST 2014


If adding output is a slave output, this slave output share the fb
with master output.

If adding output is a master output, loop the output_list to find
its slave output. If it has slave output, this slave output will
change role from master to slave.

Signed-off-by: Xiong Zhang <xiong.y.zhang at intel.com>
---
 clients/desktop-shell.c |   2 +
 desktop-shell/shell.c   |  26 +++++++++++
 src/compositor-drm.c    | 120 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 147 insertions(+), 1 deletion(-)

diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index a0c6b6d..3389ad5 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -1232,6 +1232,8 @@ create_output(struct desktop *desktop, uint32_t id)
 	 * in which case we can't create the panel and background just yet */
 	if (desktop->shell)
 		output_init(output, desktop);
+
+	desktop->painted = 0;
 }
 
 static void
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 85987e5..096d618 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -59,6 +59,7 @@ struct focus_state {
 struct shell_output {
 	struct desktop_shell  *shell;
 	struct weston_output  *output;
+	uint32_t mark_dirty;
 	struct wl_listener    role_change_listener;
 	struct wl_listener    destroy_listener;
 	struct wl_list        link;
@@ -3853,12 +3854,24 @@ desktop_shell_set_grab_surface(struct wl_client *client,
 }
 
 static void
+shell_reposition_views_on_output_destroy(struct shell_output *shell_output);
+
+static void
 desktop_shell_desktop_ready(struct wl_client *client,
 			    struct wl_resource *resource)
 {
 	struct desktop_shell *shell = wl_resource_get_user_data(resource);
+	struct shell_output *shell_output;
 
 	shell_fade_startup(shell);
+
+	wl_list_for_each(shell_output, &shell->output_list, link) {
+		if (shell_output->mark_dirty == 0)
+			continue;
+
+		shell_reposition_views_on_output_destroy(shell_output);
+		shell_output->mark_dirty = 0;
+	}
 }
 
 static const struct desktop_shell_interface desktop_shell_implementation = {
@@ -5608,6 +5621,19 @@ handle_output_destroy(struct wl_listener *listener, void *data)
 static void
 handle_output_role_change(struct wl_listener *listener, void *data)
 {
+	struct shell_output *shell_output =
+		container_of(listener, struct shell_output,
+			     role_change_listener);
+	struct weston_output *output = (struct weston_output *)data;
+
+	/* Output change from master to slave. */
+	if (output->is_slave)
+		/* Mark views on this old master as dirty.
+		 * But we will use new master as target output,
+		 * At this point, new master doesn't have panel view
+		 * and background view. So the desktop shell doesn't ready.
+		 * So we delay the mark dirty work until desktop shell ready. */
+		shell_output->mark_dirty = 1;
 }
 
 static void
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 836f81d..037c142 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -809,6 +809,13 @@ page_flip_handler(int fd, unsigned int frame,
 	uint32_t msecs;
 
 	if (output->base.is_slave) {
+		/* This is a delayed page flip event, after this output
+		 * changed from master to slave. */
+		if (output->page_flip_count) {
+			output->page_flip_count--;
+			goto finish_frame;
+		}
+
 		master_output = (struct drm_output *)output->base.master_output;
 		master_output->page_flip_count--;
 		output->page_flip_pending = 0;
@@ -832,6 +839,7 @@ page_flip_handler(int fd, unsigned int frame,
 
 	output->page_flip_pending = 0;
 
+finish_frame:
 	if (output->destroy_pending)
 		drm_output_destroy(&output->base);
 	else if (!output->vblank_pending) {
@@ -2409,6 +2417,10 @@ drm_output_add_slave(struct drm_compositor *ec)
 				found = 1;
 				wl_list_insert(master_output->base.clone_output_list.prev,
 					       &clone_output->base.link);
+
+				if (master_output->current)
+					drm_output_set_mode(clone_output,
+						master_output->current->fb_id);
 			}
 
 			break;
@@ -2503,6 +2515,105 @@ drm_output_destroy_with_slave(struct drm_output *output)
 	wl_signal_emit(&new_master->role_change_signal, new_master);
 }
 
+/* First a slave output is discoveryed but associated master isn't found
+ * this slave output will be upgraded to master output;
+ * Second the master output is hot plugged, the original slave output
+ * should be downgraded to slave. */
+static void
+drm_output_master_to_slave(struct drm_output *output)
+{
+	struct weston_output *master, *slave, *next;
+
+	master = output->base.master_output;
+	wl_list_remove(&output->base.link);
+	wl_list_insert(master->clone_output_list.prev,
+		       &output->base.link);
+
+	/* release buffer */
+	drm_output_release_fb(output, output->current);
+	drm_output_release_fb(output, output->next);
+	output->current = output->next = NULL;
+
+	wl_list_for_each_safe(slave, next,
+			&output->base.clone_output_list, link){
+		slave->master_output = master;
+
+		if (!clone_output_need_adjust_mode(slave) ||
+		    adjust_clone_output_mode(slave) == 0) {
+			wl_list_remove(&slave->link);
+			wl_list_insert(master->clone_output_list.prev,
+				       &slave->link);
+		}
+	}
+
+	output->base.is_slave = 1;
+	wl_signal_emit(&output->base.role_change_signal, &output->base);
+}
+
+static void
+drm_output_add_master(struct drm_compositor *ec)
+{
+	struct drm_output *clone_output, *master_output, *next;
+	int rel_x = 0, first_found = 0;
+
+	master_output = container_of(ec->base.output_list.prev,
+				struct drm_output, base.link);
+
+	wl_list_for_each_safe(clone_output, next,
+			&ec->base.output_list, base.link) {
+		if (clone_output->base.master_output_name == NULL ||
+		    strncmp(clone_output->base.master_output_name,
+			    master_output->base.name,
+			    strlen(clone_output->base.master_output_name)) != 0) {
+			if (rel_x != 0)
+				weston_output_move(&clone_output->base,
+					   clone_output->base.x + rel_x,
+					   clone_output->base.y);
+
+			continue;
+		}
+
+		if (first_found == 0) {
+			rel_x = master_output->base.current_mode->width -
+				clone_output->base.current_mode->width;
+
+			clone_output->base.master_output = &master_output->base;
+
+			if (!clone_output_need_adjust_mode(&clone_output->base) ||
+			    adjust_clone_output_mode(&clone_output->base) == 0) {
+				wl_list_remove(&master_output->base.link);
+				wl_list_insert(clone_output->base.link.prev,
+					       &master_output->base.link);
+
+				weston_output_move(&master_output->base,
+						   clone_output->base.x,
+						   clone_output->base.y);
+
+				first_found = 1;
+				drm_output_master_to_slave(clone_output);
+			} else {
+				clone_output->base.master_output = NULL;
+				rel_x = 0;
+			}
+		} else {
+			rel_x -= clone_output->base.current_mode->width;
+
+			clone_output->base.master_output = &master_output->base;
+
+			if (!clone_output_need_adjust_mode(&clone_output->base) ||
+			    adjust_clone_output_mode(&clone_output->base) == 0) {
+				drm_output_master_to_slave(clone_output);
+			} else {
+				clone_output->base.master_output = NULL;
+				rel_x += clone_output->base.current_mode->width;
+			}
+		}
+
+		if (next == master_output)
+			break;
+	}
+}
+
 static int
 create_outputs(struct drm_compositor *ec, uint32_t option_connector,
 	       struct udev_device *drm_device)
@@ -2571,7 +2682,7 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 	drmModeRes *resources;
 	struct drm_output *output, *next;
 	uint32_t connected = 0, disconnects = 0;
-	int i;
+	int i, add_output = 0;
 	struct drm_output *clone_output, *found_output;
 
 	resources = drmModeGetResources(ec->drm.fd);
@@ -2598,6 +2709,7 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 		if (!(ec->connector_allocator & (1 << connector_id))) {
 			create_output_for_connector(ec, resources, connector,
 						    drm_device);
+			add_output = 1;
 			weston_log("connector %d connected\n", connector_id);
 
 		}
@@ -2605,6 +2717,12 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 	}
 	drmModeFreeResources(resources);
 
+	if (add_output) {
+		drm_output_add_slave(ec);
+		drm_output_add_master(ec);
+		weston_compositor_schedule_repaint(&ec->base);
+	}
+
 	disconnects = ec->connector_allocator & ~connected;
 	if (disconnects) {
 		wl_list_for_each_safe(output, next, &ec->base.output_list,
-- 
1.8.3.2



More information about the wayland-devel mailing list