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.zh...@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 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel