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

Reply via email to