[PATCH 6/9] hot plug add a output in clone mode

Xiong Zhang xiong.y.zhang at intel.com
Tue Sep 17 20:51:01 PDT 2013


if added output used as primary output, old primary output's fb should
be freed and recreated so that when this old primary output is used as priamry
output again in future, it has a clean state;
if added output is used as clone output, adjust it mode necessary and
set it mode

At the same time, all surface should be dirty, so that all client can
get frame callback and request repaint.

Signed-off-by: Xiong Zhang <xiong.y.zhang at intel.com>
---
 src/compositor-drm.c | 93 +++++++++++++++++++++++++++++++++++++++-------------
 src/compositor.c     | 10 ++++++
 src/compositor.h     |  2 ++
 3 files changed, 82 insertions(+), 23 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index a9d2ab5..0aa105a 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -1219,10 +1219,43 @@ clone_output_need_adjust_mode(struct drm_output *clone_output)
 }
 
 static void
+drm_output_fini_pixman(struct drm_output *output);
+static int
+drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
+static int
+drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
+
+static void
+drm_output_recreate_fb(struct drm_output *output)
+{
+	struct drm_compositor *ec = (struct drm_compositor *)output->base.compositor;
+
+	drm_output_release_fb(output, output->current);
+	drm_output_release_fb(output, output->next);
+	output->current = output->next = NULL;
+
+	if (ec->use_pixman) {
+		drm_output_fini_pixman(output);
+		if (drm_output_init_pixman(output, ec) < 0) {
+			weston_log("failed to restore a clean pixman state");
+			return;
+		}
+	} else {
+		gl_renderer_output_destroy(&output->base);
+		gbm_surface_destroy(output->surface);
+		if (drm_output_init_egl(output, ec) < 0) {
+			weston_log("failed to restore a clean egl state");
+			return;
+		}
+	}
+}
+
+static void
 clone_mode_add_output(struct drm_output *output)
 {
 	struct drm_compositor *ec = (struct drm_compositor *)output->base.compositor;
 	struct drm_output *origin_output;
+	struct drm_mode *mode;
 
 	if (!ec->base.primary_output) {
 		ec->base.primary_output = &output->base;
@@ -1235,18 +1268,36 @@ clone_mode_add_output(struct drm_output *output)
 		wl_list_remove(&output->base.link);
 		wl_list_insert(&ec->base.output_list, &output->base.link);
 		ec->base.primary_output = &output->base;
+
+		/*origin_output will be used as clone_output, whether need to change mode*/
+		if (clone_output_need_adjust_mode(origin_output))
+			adjust_clone_output_mode(origin_output);
+		/*if added output will be used as primary output, the origin primary output's fb should be freed*/
+		drm_output_recreate_fb(origin_output);
+		/*dirty all surface, so that app can get frame calllback and repaint*/
+		weston_compositor_dirty_all_surface(&ec->base);
 	} else {
 		/* added output used as clone output, set it mode here */
 		if (clone_output_need_adjust_mode(output))
 			/*new added output need to adjust mode*/
 			adjust_clone_output_mode(output);
+
+		/* added output used as clone output, set it mode here */
+		if (origin_output->current) {
+			mode = container_of(output->base.current, struct drm_mode, base);
+			if (drmModeSetCrtc(ec->drm.fd, output->crtc_id,
+					origin_output->current->fb_id, 0, 0,
+					&output->connector_id, 1,
+					&mode->mode_info) < 0) {
+				weston_log("set added output mode failed: %m\n");
+				return;
+			}
+			output->base.set_dpms(&output->base, WESTON_DPMS_ON);
+		}
 	}
 }
 
 static void
-drm_output_fini_pixman(struct drm_output *output);
-
-static void
 drm_output_destroy(struct weston_output *output_base)
 {
 	struct drm_output *output = (struct drm_output *) output_base;
@@ -1313,11 +1364,6 @@ choose_mode (struct drm_output *output, struct weston_mode *target_mode)
 }
 
 static int
-drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec);
-static int
-drm_output_init_pixman(struct drm_output *output, struct drm_compositor *c);
-
-static int
 drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
 {
 	struct drm_output *output;
@@ -2109,16 +2155,6 @@ create_output_for_connector(struct drm_compositor *ec,
 			   connector->mmWidth, connector->mmHeight,
 			   transform, scale);
 
-	if (ec->use_pixman) {
-		if (drm_output_init_pixman(output, ec) < 0) {
-			weston_log("Failed to init output pixman state\n");
-			goto err_output;
-		}
-	} else if (drm_output_init_egl(output, ec) < 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) {
@@ -2130,10 +2166,6 @@ create_output_for_connector(struct drm_compositor *ec,
 		weston_log("Failed to initialize backlight\n");
 	}
 
-	wl_list_insert(ec->base.output_list.prev, &output->base.link);
-	if (ec->base.multiscreen_mode == WESTON_MULTISCREEN_CLONE)
-		clone_mode_add_output(output);
-
 	find_and_parse_output_edid(ec, output, connector);
 	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
 		output->base.connection_internal = 1;
@@ -2156,6 +2188,20 @@ create_output_for_connector(struct drm_compositor *ec,
 	weston_compositor_stack_plane(&ec->base, &output->fb_plane,
 				      &ec->base.primary_plane);
 
+	wl_list_insert(ec->base.output_list.prev, &output->base.link);
+	if (ec->base.multiscreen_mode == WESTON_MULTISCREEN_CLONE)
+		clone_mode_add_output(output);
+
+	if (ec->use_pixman) {
+		if (drm_output_init_pixman(output, ec) < 0) {
+			weston_log("Failed to init output pixman state\n");
+			goto err_output;
+		}
+	} else if (drm_output_init_egl(output, ec) < 0) {
+		weston_log("Failed to init output gl state\n");
+		goto err_output;
+	}
+
 	weston_log("Output %s, (connector %d, crtc %d)\n",
 		   output->base.name, output->connector_id, output->crtc_id);
 	wl_list_for_each(m, &output->base.mode_list, link)
@@ -2361,7 +2407,8 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
 					     struct weston_output, link);
 
 			/* XXX: not yet needed, we die with 0 outputs */
-			if (!wl_list_empty(&ec->base.output_list))
+			if ((!wl_list_empty(&ec->base.output_list)) &&
+					(ec->base.multiscreen_mode != WESTON_MULTISCREEN_CLONE))
 				x = last->x + last->width;
 			else
 				x = 0;
diff --git a/src/compositor.c b/src/compositor.c
index 5d927fd..966598f 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -748,6 +748,16 @@ weston_surface_geometry_dirty(struct weston_surface *surface)
 }
 
 WL_EXPORT void
+weston_compositor_dirty_all_surface(struct weston_compositor *compositor)
+{
+	struct weston_surface *surface;
+
+	wl_list_for_each(surface, &compositor->surface_list, link) {
+		weston_surface_geometry_dirty(surface);
+	}
+}
+
+WL_EXPORT void
 weston_surface_to_global_fixed(struct weston_surface *surface,
 			       wl_fixed_t sx, wl_fixed_t sy,
 			       wl_fixed_t *x, wl_fixed_t *y)
diff --git a/src/compositor.h b/src/compositor.h
index a3171f0..51f5c1b 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -830,6 +830,8 @@ weston_surface_update_transform(struct weston_surface *surface);
 
 void
 weston_surface_geometry_dirty(struct weston_surface *surface);
+void
+weston_compositor_dirty_all_surface(struct weston_compositor *compositor);
 
 void
 weston_surface_to_global_fixed(struct weston_surface *surface,
-- 
1.8.3.2



More information about the wayland-devel mailing list