[PATCH 2/9] find primary output during drm_compositor_create in clone mode

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


the output with most width will be selected as primary output.
primary output occupy the first position in weston_compositor->output_list

if clone_output's height is larger than primary_output's height
clone_output's mode should be changed, otherwise the setting mode
for clone_output will fail. choose a nearest mode below primary_output's
mode.

Signed-off-by: Xiong Zhang <xiong.y.zhang at intel.com>
---
 src/compositor-drm.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 97 insertions(+), 3 deletions(-)

diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 1e2f3ab..8d16d29 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -1051,6 +1051,97 @@ drm_assign_planes(struct weston_output *output)
 	pixman_region32_fini(&overlap);
 }
 
+/* the output with maximum width is the primary output */
+static struct drm_output *
+choose_output(struct drm_output *primary,
+			struct drm_output *clone)
+{
+	if (clone->base.current->width > primary->base.current->width)
+		primary = clone;
+
+	return primary;
+}
+
+/*if clone_output's height > primary_output's height */
+/*clone_output's mode shoulde be changed, or else set mode for clone_output */
+/*will fail. Choose a nearest mode below primary_output's current_mode */
+static void
+adjust_clone_output_mode(struct drm_output *clone_output)
+{
+	struct drm_mode *mode, *choose_mode;
+	uint32_t multiple_delta, choose_delta;
+	struct weston_mode *current_mode;
+
+	choose_mode = NULL;
+	choose_delta = 0xffffffff;
+	current_mode = clone_output->base.compositor->primary_output->current;
+
+	wl_list_for_each(mode, &clone_output->base.mode_list, base.link) {
+		if (mode->mode_info.hdisplay <= current_mode->width &&
+			mode->mode_info.vdisplay <= current_mode->height) {
+			if (mode->mode_info.hdisplay == current_mode->width) {
+				choose_mode = mode;
+				break;
+			} else if (mode->mode_info.vdisplay == current_mode->height) {
+				choose_mode = mode;
+				break;
+			} else {
+				multiple_delta = (current_mode->width - mode->mode_info.hdisplay) *
+								(current_mode->height - mode->mode_info.vdisplay);
+				if (multiple_delta < choose_delta) {
+					choose_delta = multiple_delta;
+					choose_mode = mode;
+				}
+			}
+		}
+	}
+	if (!choose_mode) {
+		weston_log("clone mode fail in chooseing mode for clone output\n");
+		return;
+	}
+	clone_output->base.current->flags &= ~WL_OUTPUT_MODE_CURRENT;
+	clone_output->base.current = &choose_mode->base;
+	clone_output->base.current->flags |= WL_OUTPUT_MODE_CURRENT;
+}
+
+static int
+clone_output_need_adjust_mode(struct drm_output *clone_output)
+{
+	struct drm_output *primary_output;
+
+	primary_output = (struct drm_output *)clone_output->base.compositor->primary_output;
+	if (clone_output->base.current->height > primary_output->base.current->height ||
+		clone_output->base.current->width > primary_output->base.current->width)
+		return 1;
+	else
+		return 0;
+}
+
+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;
+
+	if (!ec->base.primary_output) {
+		ec->base.primary_output = &output->base;
+		return;
+	} else
+		origin_output = (struct drm_output *)ec->base.primary_output;
+
+	if (choose_output(origin_output, output) != origin_output) {
+		/* make sure primary output is the first in output_list when clone mode is enabled */
+		wl_list_remove(&output->base.link);
+		wl_list_insert(&ec->base.output_list, &output->base.link);
+		ec->base.primary_output = &output->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);
+	}
+}
+
 static void
 drm_output_fini_pixman(struct drm_output *output);
 
@@ -1939,6 +2030,8 @@ create_output_for_connector(struct drm_compositor *ec,
 	}
 
 	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)
@@ -2109,9 +2202,10 @@ create_outputs(struct drm_compositor *ec, uint32_t option_connector,
 				continue;
 			}
 
-			x += container_of(ec->base.output_list.prev,
-					  struct weston_output,
-					  link)->width;
+			if (ec->base.multiscreen_mode == WESTON_MULTISCREEN_EXTEND)
+				x += container_of(ec->base.output_list.prev,
+						  struct weston_output,
+						  link)->width;
 		}
 
 		drmModeFreeConnector(connector);
-- 
1.8.3.2



More information about the wayland-devel mailing list