[PATCH 7/9] compositor: Hot plug a output in clone mode
Xiong Zhang
xiong.y.zhang at intel.com
Thu Feb 13 23:17:42 PST 2014
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.zhang at 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
More information about the wayland-devel
mailing list