[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