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