Re: [PATCH] Prevent zero sized wl_egl_window
On Wed, 12 Feb 2014 16:21:11 -0800 Sinclair Yeh sinclair@intel.com wrote: It is illegal to create or resize a window to zero (or negative) width and/or height. This patch prevents such a request from happening. --- src/egl/wayland/wayland-egl/wayland-egl.c | 6 ++ 1 file changed, 6 insertions(+) diff --git a/src/egl/wayland/wayland-egl/wayland-egl.c b/src/egl/wayland/wayland-egl/wayland-egl.c index 8bd49cf..ae78595 100644 --- a/src/egl/wayland/wayland-egl/wayland-egl.c +++ b/src/egl/wayland/wayland-egl/wayland-egl.c @@ -9,6 +9,9 @@ wl_egl_window_resize(struct wl_egl_window *egl_window, int width, int height, int dx, int dy) { + if (width = 0 || height = 0) + return; + The below seems fine, but I wonder if we could make this one cause an error to be returned later where we can, rather than silently ignoring. I'm not sure where or how, though. Surely drivers have maximum size limits, too, those must be catched somewhere already. egl_window-width = width; egl_window-height = height; egl_window-dx = dx; @@ -24,6 +27,9 @@ wl_egl_window_create(struct wl_surface *surface, { struct wl_egl_window *egl_window; + if (width = 0 || height = 0) + return NULL; + egl_window = malloc(sizeof *egl_window); if (!egl_window) return NULL; Thanks, pq ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH] Prevent zero sized wl_egl_window
The below seems fine, but I wonder if we could make this one cause an error to be returned later where we can, rather than silently ignoring. I'm not sure where or how, though. Would it make sense to change wl_egl_window_resize() so that it return a value? Either that, or it should be documented somewhere in the API spec that setting width/height =0 will be ignored. Surely drivers have maximum size limits, too, those must be catched somewhere already. egl_window-width = width; egl_window-height = height; egl_window-dx = dx; @@ -24,6 +27,9 @@ wl_egl_window_create(struct wl_surface *surface, { struct wl_egl_window *egl_window; + if (width = 0 || height = 0) + return NULL; + egl_window = malloc(sizeof *egl_window); if (!egl_window) return NULL; Thanks, pq ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH libinput] Add a customizable log handler
The previous log handler wasn't actually hooked up to anything. Add a public API for the log handler with priority filtering, defaulting to priority 'error' and stderr as output stream. And to keep the diff down and convenience up, provide a few simple wrappers for logging. The generic is log_msg(), but let's use log_info, log_error, etc. Signed-off-by: Peter Hutterer peter.hutte...@who-t.net --- src/libinput-private.h | 7 ++ src/libinput-util.c| 20 -- src/libinput.c | 62 ++ src/libinput.h | 76 ++ src/path.c | 4 +- test/Makefile.am | 7 +- test/log.c | 169 + 7 files changed, 322 insertions(+), 23 deletions(-) create mode 100644 test/log.c diff --git a/src/libinput-private.h b/src/libinput-private.h index 0d7de90..1fff7de 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -74,6 +74,13 @@ typedef void (*libinput_source_dispatch_t)(void *data); struct libinput_source; +#define log_debug(...) log_msg(LIBINPUT_LOG_PRIORITY_DEBUG, __VA_ARGS__) +#define log_info(...) log_msg(LIBINPUT_LOG_PRIORITY_INFO, __VA_ARGS__) +#define log_error(...) log_msg(LIBINPUT_LOG_PRIORITY_ERROR, __VA_ARGS__) + +void +log_msg(enum libinput_log_priority priority, const char *format, ...); + int libinput_init(struct libinput *libinput, const struct libinput_interface *interface, diff --git a/src/libinput-util.c b/src/libinput-util.c index a3534e1..eeb9786 100644 --- a/src/libinput-util.c +++ b/src/libinput-util.c @@ -35,26 +35,6 @@ #include libinput-util.h #include libinput-private.h -static FILE *g_log_file = NULL; - -void -set_logging_enabled(int enabled) -{ - g_log_file = enabled ? stdout : NULL; -} - -void -log_info(const char *format, ...) -{ - va_list ap; - - if (g_log_file) { - va_start(ap, format); - vfprintf(g_log_file, format, ap); - va_end(ap); - } -} - void list_init(struct list *list) { diff --git a/src/libinput.c b/src/libinput.c index cfce2c5..b4879af 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -78,6 +78,68 @@ struct libinput_event_touch { }; static void +libinput_default_log_func(enum libinput_log_priority priority, + void *data, + const char *format, va_list args) +{ + const char *prefix; + + switch(priority) { + case LIBINPUT_LOG_PRIORITY_DEBUG: prefix = debug; break; + case LIBINPUT_LOG_PRIORITY_INFO: prefix = info; break; + case LIBINPUT_LOG_PRIORITY_ERROR: prefix = error; break; + default: prefix=invalid priority; break; + } + + fprintf(stderr, libinput %s: , prefix); + vfprintf(stderr, format, args); +} + +struct log_data { + enum libinput_log_priority priority; + libinput_log_handler handler; + void *user_data; +}; + +static struct log_data log_data = { + .priority = LIBINPUT_LOG_PRIORITY_ERROR, + .handler = libinput_default_log_func, + .user_data = NULL, +}; + +void +log_msg(enum libinput_log_priority priority, const char *format, ...) +{ + va_list args; + + if (log_data.handler log_data.priority = priority) { + va_start(args, format); + log_data.handler(priority, log_data.user_data, format, args); + va_end(args); + } +} + +LIBINPUT_EXPORT void +libinput_log_set_priority(enum libinput_log_priority priority) +{ + log_data.priority = priority; +} + +LIBINPUT_EXPORT enum libinput_log_priority +libinput_log_get_priority(void) +{ + return log_data.priority; +} + +LIBINPUT_EXPORT void +libinput_log_set_handler(libinput_log_handler log_handler, +void *user_data) +{ + log_data.handler = log_handler; + log_data.user_data = user_data; +} + +static void libinput_post_event(struct libinput *libinput, struct libinput_event *event); diff --git a/src/libinput.h b/src/libinput.h index e87b2b7..6bf538a 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -42,6 +42,15 @@ typedef int32_t li_fixed_t; /** + * Log priority for internal logging messages. + */ +enum libinput_log_priority { + LIBINPUT_LOG_PRIORITY_DEBUG = 10, + LIBINPUT_LOG_PRIORITY_INFO = 20, + LIBINPUT_LOG_PRIORITY_ERROR = 30, +}; + +/** * @ingroup device * * Capabilities on a device. A device may have one or more capabilities @@ -875,6 +884,73 @@ void libinput_destroy(struct libinput *libinput); /** + * @ingroup base + * + * Set the global log priority. Messages with priorities equal to or + * higher than the argument will be printed to the current log handler. + * + * The default log priority is LIBINPUT_LOG_PRIORITY_ERROR. + * + * @param priority The minimum priority of log messages to print. + * + * @see libinput_log_set_handler + */ +void +libinput_log_set_priority(enum libinput_log_priority
[RFC v3] Fullscreen shell
This RFC is for the third version of my fullscreen shell implementation. The contents of this RFC are: * A new wl_fullscreen_shell protocol * A weston shell that provides wl_fullscreen_shell * Additions to the Wayland backend for Weston to take advantage of wl_fullscreen_shell * Additions to weston-simple-shm and weston-fullscreen to demonstrate the wl_fullscreen_shell protocol. This RFC improves the second version in a couple of ways: * Changes the possible presentation modes to allow more options for clients * Adds support in weston-fullscreen for fully testing wl_fullscreen_shell * Various bugfixes The previous version of this RFC can be found here: http://lists.freedesktop.org/archives/wayland-devel/2013-October/011626.html The original RFC can be found here: http://lists.freedesktop.org/archives/wayland-devel/2013-August/010720.html This RFC is primarily to provide a preview of the implementation, so I am not going to spam the list with patches. Instead, you can view it in its entirety on my github: https://github.com/jekstrand/weston/tree/fullscreen-shell-RFCv3 Immediately following this e-mail will be a fourth protocol-only RFC that contains substantial changes to the modesetting portion of the protocol. Feedback there is appreciated as well. Thanks, --Jason Ekstrand Jason Ekstrand (11): Add a fullscreen shell protocol Generate/build the fullscreen shell protocol files Add a signal for when a seat updates its capabilities Add a wl_fullscreen_shell implementation simple-shm: Add fullscreen shell support toytoolkit: Only require xdg_shell if the window is not custom Add wl_fullscreen_shell support to weston-fullscreen compositor-wayland: Add support for running on top of wl_fullscreen_shell compositor-wayland: Add a --sprawl option Automatically select the wayland backend if WAYLAND_SOCKET is set Properly handle running inside a compositor that does not provide keymaps Makefile.am | 32 +++ clients/fullscreen.c | 84 +- clients/simple-shm.c | 31 ++- clients/window.c | 2 +- configure.ac | 8 + protocol/fullscreen-shell.xml | 70 + src/compositor-wayland.c | 347 --- src/compositor.c | 3 +- src/compositor.h | 1 + src/fullscreen-shell.c| 626 ++ src/input.c | 2 + 11 files changed, 1145 insertions(+), 61 deletions(-) create mode 100644 protocol/fullscreen-shell.xml create mode 100644 src/fullscreen-shell.c -- 1.8.5.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[RFC v4] Fullscreen shell protocol
The following is yet another take on the fullscreen shell protocol. Previous versions more-or-less followed the approach taken in wl_shell. This version completely reworks the concept. In particular, the protocol is split into two use-cases. The first is that of a simple client that wants to present a surface or set of surfaces possibly with some scaling. This happens through the present_surface request which looks similar to that of wl_shell only without the modesetting. The second use-case is of a client that wants more control over the outputs. In this case, the client uses the present_surface_for_mode request to present the surface at a particular output mode. This request provides a more-or-less atomic modeset operation. If the compositor can satisfy the requested mode, then the mode is changed and the new surface is presented. Otherwise, the compositor harmlessly falls back to the previously presented surface and the client is informed that the switch failed. This way, the surface is either displayed correctly or not at all. Of course, a client is free to call present_surface_for_mode with the currently presented surface and hope for the best. However, this may result in strange behavior and there is no reliable fallback if the mode switch fails. In particular, I would like feedback on the modesetting portion of this protocol. This is particularly targetted at compositors that want to run inside weston or some other fullscreen compositor. In the next week or so, I will attempt to implement all this in weston and see how well it works. However, I would also like to know how well this will work for other compositors such as KWin or Hawaii. Thanks for your feedback, --Jason Ekstrand = Protocol follows: = protocol name=fullscreen_shell interface name=wl_fullscreen_shell version=1 description summary=Displays a single surface per output Displays a single surface per output. This interface provides a mechanism for a single client to display simple full-screen surfaces. While there technically may be multiple clients bound to this interface, only one of those clients should be shown at a time. To present a surface, the client uses either the present_surface or present_surface_for_mode requests. Presenting a surface takes effect on the next wl_surface.commit. See the individual requests for details about scaling and mode switches. The client can have at most one surface per output at any time. Requesting a surface be presented on an output that already has a surface replaces the previously presented surface. Presenting a null surface removes its content and effectively disables the output. Exactly what happens when an output is disabled is compositor-specific. The same surface may be presented multiple outputs simultaneously. /description enum name=present_method description summary=different method to set the surface fullscreen Hints to indicate to the compositor how to deal with a conflict between the dimensions of the surface and the dimensions of the output. The compositor is free to ignore this parameter. /description entry name=default value=0 summary=no preference, apply default policy/ entry name=center value=1 summary=center the surface on the output/ entry name=zoom value=2 summary=scale the surface, preserving aspect ratio, to the largest size that will fit on the output / entry name=zoom_crop value=3 summary=scale the surface, preserving aspect ratio, to fully fill the output cropping if needed / entry name=stretch value=4 summary=scale the surface to the size of the output ignoring aspect ratio / /enum request name=present_surface description summary=present surface for display Present a surface on the given output. If the output is null, the compositor will present the surface on whatever display (or displays) it thinks best. In particular, this may replace any or all surfaces currently presented so it should not be used in combination with placing surfaces on specific outputs. The method parameter is a hit to the compositor for how the surface is to be presented. In particular, it tells the compostior how to handle a size mismatch between the presented surface and the output. The compositor is free to ignore this parameter. The zoom, zoom_crop, and stretch methods imply a scaling operation on the surface. This will override any kind of output scaling, so the buffer_scale property of the surface is effectively ignored. /description arg name=surface type=object interface=wl_surface/ arg name=method type=uint/ arg name=output type=object interface=wl_output allow-null=true/ /request request
[PATCH 4/9] compositor: Add output-role_change_signal in clone mode
When a output change role between master and slave in clone mode, some work is needed, this signal is used to trigger this work. Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- desktop-shell/shell.c | 13 + src/compositor.c | 1 + src/compositor.h | 1 + 3 files changed, 15 insertions(+) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 3831804..1e4a255 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; + struct wl_listenerrole_change_listener; struct wl_listenerdestroy_listener; struct wl_listlink; }; @@ -5596,11 +5597,17 @@ handle_output_destroy(struct wl_listener *listener, void *data) shell_reposition_views_on_output_destroy(output_listener); wl_list_remove(output_listener-destroy_listener.link); + wl_list_remove(output_listener-role_change_listener.link); wl_list_remove(output_listener-link); free(output_listener); } static void +handle_output_role_change(struct wl_listener *listener, void *data) +{ +} + +static void create_shell_output(struct desktop_shell *shell, struct weston_output *output) { @@ -5615,6 +5622,11 @@ create_shell_output(struct desktop_shell *shell, shell_output-destroy_listener.notify = handle_output_destroy; wl_signal_add(output-destroy_signal, shell_output-destroy_listener); + + shell_output-role_change_listener.notify = handle_output_role_change; + wl_signal_add(output-role_change_signal, + shell_output-role_change_listener); + wl_list_insert(shell-output_list.prev, shell_output-link); } @@ -5697,6 +5709,7 @@ shell_destroy(struct wl_listener *listener, void *data) wl_list_for_each_safe(shell_output, tmp, shell-output_list, link) { wl_list_remove(shell_output-destroy_listener.link); + wl_list_remove(shell_output-role_change_listener.link); wl_list_remove(shell_output-link); free(shell_output); } diff --git a/src/compositor.c b/src/compositor.c index 2c30334..5c0f67d 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -3283,6 +3283,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c, wl_signal_init(output-destroy_signal); wl_list_init(output-animation_list); wl_list_init(output-resource_list); + wl_signal_init(output-role_change_signal); output-id = ffs(~output-compositor-output_id_pool) - 1; output-compositor-output_id_pool |= 1 output-id; diff --git a/src/compositor.h b/src/compositor.h index 549d83d..0938078 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -216,6 +216,7 @@ struct weston_output { char *master_output_name; struct weston_output *master_output; struct wl_list clone_output_list; + struct wl_signal role_change_signal; void (*start_repaint_loop)(struct weston_output *output); int (*repaint)(struct weston_output *output, -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 5/9] compositor: Output unplug in clone mode
If unplugged output is a slave output, no need to restore views. If unplugged output is a master output which doesn't have slave output related it, views will be restored the same as extend mode. If unplugged output is a master output which have slave output related it, one slave output will be upgraded to master output, moving output following unplugged output isn't necessay, views on unplugged output will be marked as dirty. Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- desktop-shell/shell.c | 13 ++- src/compositor-drm.c | 103 +++--- src/compositor.c | 15 ++-- src/compositor.h | 1 + 4 files changed, 122 insertions(+), 10 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 1e4a255..85987e5 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -5600,6 +5600,9 @@ handle_output_destroy(struct wl_listener *listener, void *data) wl_list_remove(output_listener-role_change_listener.link); wl_list_remove(output_listener-link); free(output_listener); + + /* Trigger compositor repaint */ + weston_compositor_schedule_repaint(output_listener-output-compositor); } static void @@ -5676,10 +5679,18 @@ setup_output_destroy_handler(struct weston_compositor *ec, struct desktop_shell *shell) { struct weston_output *output; + struct weston_output *clone_output; wl_list_init(shell-output_list); - wl_list_for_each(output, ec-output_list, link) + wl_list_for_each(output, ec-output_list, link) { create_shell_output(shell, output); + if (!output-is_slave) { + wl_list_for_each(clone_output, +output-clone_output_list, +link) + create_shell_output(shell, clone_output); + } + } shell-output_create_listener.notify = handle_output_create; wl_signal_add(ec-output_created_signal, diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 1d8c983..842710f 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -1217,6 +1217,8 @@ drm_assign_planes(struct weston_output *output) static void drm_output_fini_pixman(struct drm_output *output); +static void +drm_output_destroy_with_slave(struct drm_output *output); static void drm_output_destroy(struct weston_output *output_base) @@ -1259,6 +1261,15 @@ drm_output_destroy(struct weston_output *output_base) weston_plane_release(output-fb_plane); weston_plane_release(output-cursor_plane); + if (!output-base.is_slave + !wl_list_empty(output-base.clone_output_list)) { + drm_output_destroy_with_slave(output); + + /* One slave is upgraded to master, Don't move +* the following output.*/ + output_base.dont_move = 1; + } + weston_output_destroy(output-base); free(output); @@ -2420,6 +2431,73 @@ drm_output_add_slave(struct drm_compositor *ec) } } +/* The output with max width will be new_master. */ +static struct weston_output * +find_new_master(struct weston_output *master) +{ + struct weston_output *new_master, *output; + int32_t max_width = 0; + + new_master = NULL; + wl_list_for_each(output, master-clone_output_list, +link) { + if (output-current_mode-width max_width) { + max_width = output-current_mode-width; + new_master = output; + } + } + + return new_master; +} + +/* If a master is unplugged, a output will be chosen from + * master-clone_output_list to replace the unplugged master.*/ +static void +drm_output_destroy_with_slave(struct drm_output *output) +{ + struct weston_output *new_master, *tmp; + struct drm_output *clone_output, *next; + intoffset, move; + + new_master = find_new_master(output-base); + + /* When old master's width is different from new master's +* width, move the output following the old master. */ + offset = output-base.width - new_master-width; + if (offset != 0) { + move = 0; + wl_list_for_each(tmp, new_master-compositor-output_list, +link) { + if (move == 1) + weston_output_move(tmp, + tmp-x - offset, tmp-y); + + if (tmp == output-base) + move = 1; + } + } + + wl_list_remove(new_master-link); + wl_list_insert(output-base.link.prev, + new_master-link); + new_master-is_slave = 0; + + /* Link the remained clone output to new
[PATCH 2/9] compositor: Output repaint in clone mode
Because slave output doesn't in compositor-output_list, the output-repaint()is called from master output only. When master output repaint,all the slave output should repaint also. Slave output share fb with master output,when both slave and master have finished page flip, the fb obj can be released. Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- src/compositor-drm.c | 112 ++- src/compositor.c | 3 +- 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 6773226..ce85aec 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -155,6 +155,7 @@ struct drm_output { uint32_t transform; int scale, mm_width, mm_height; + uint32_t page_flip_count; struct gbm_surface *surface; struct gbm_bo *cursor_bo[2]; @@ -591,8 +592,9 @@ drm_output_repaint(struct weston_output *output_base, struct drm_sprite *s; struct drm_mode *mode; int ret = 0; + struct drm_output *clone_output; - if (output-destroy_pending) + if (output-destroy_pending || output-base.is_slave) return -1; if (!output-next) @@ -612,6 +614,25 @@ drm_output_repaint(struct weston_output *output_base, goto err_pageflip; } output_base-set_dpms(output_base, WESTON_DPMS_ON); + + wl_list_for_each(clone_output, output-base.clone_output_list, +base.link) { + mode = container_of(clone_output-base.current_mode, + struct drm_mode, base); + + ret = drmModeSetCrtc(compositor-drm.fd, +clone_output-crtc_id, +output-next-fb_id, 0, 0, +clone_output-connector_id, 1, +mode-mode_info); + if (ret) { + weston_log(set mode failed:%m\n); + goto err_pageflip; + } + + clone_output-base.set_dpms(clone_output-base, + WESTON_DPMS_ON); + } } if (drmModePageFlip(compositor-drm.fd, output-crtc_id, @@ -622,6 +643,23 @@ drm_output_repaint(struct weston_output *output_base, } output-page_flip_pending = 1; + output-page_flip_count++; + + /* clone output repaint*/ + wl_list_for_each(clone_output, output-base.clone_output_list, +base.link) { + if (drmModePageFlip(compositor-drm.fd, + clone_output-crtc_id, + output-next-fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + clone_output) 0) { + weston_log(queueing pageflip failed:%m\n); + goto err_pageflip; + } + + clone_output-page_flip_pending = 1; + output-page_flip_count++; + } drm_output_set_cursor(output); @@ -691,8 +729,9 @@ drm_output_start_repaint_loop(struct weston_output *output_base) uint32_t fb_id; uint32_t msec; struct timespec ts; + struct drm_output *clone_output; - if (output-destroy_pending) + if (output-destroy_pending || output-base.is_slave) return; if (!output-current) { @@ -707,6 +746,22 @@ drm_output_start_repaint_loop(struct weston_output *output_base) weston_log(queueing pageflip failed: %m\n); goto finish_frame; } + output-page_flip_count++; + + /* clone output repaint*/ + wl_list_for_each(clone_output, output-base.clone_output_list, +base.link) { + if (drmModePageFlip(compositor-drm.fd, + clone_output-crtc_id, + fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + clone_output) 0) { + weston_log(queueing pageflip failed:%m\n); + goto finish_frame; + } + + output-page_flip_count++; + } return; @@ -745,8 +800,22 @@ page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { struct drm_output *output = (struct drm_output *) data; + struct drm_output *master_output; uint32_t msecs; + if (output-base.is_slave) { + master_output = (struct drm_output *)output-base.master_output; + master_output-page_flip_count--; +
[PATCH 1/9] compositor-drm: Add per connector clone mode support
Add a clone option in output section of weston.ini Master output will be in compositor-output_list. Slave output won't be in compositor-output_list, while it is in master-clone_output_list. Slave output's current mode size should be smaller than master output's mode size, or else the mode setting for slave output will fail. So slave output's mode will be adjusted when it is necessary. Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- src/compositor-drm.c | 189 --- src/compositor.c | 15 +++- src/compositor.h | 5 ++ weston.ini.in| 2 + 4 files changed, 185 insertions(+), 26 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index e45f47d..6773226 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -87,6 +87,7 @@ struct drm_compositor { uint32_t connector_allocator; struct wl_listener session_listener; uint32_t format; + struct wl_list clone_output_list; /* we need these parameters in order to not fail drmModeAddFB2() * due to out of bounds dimensions, and then mistakenly set @@ -152,6 +153,9 @@ struct drm_output { int page_flip_pending; int destroy_pending; + uint32_t transform; + int scale, mm_width, mm_height; + struct gbm_surface *surface; struct gbm_bo *cursor_bo[2]; struct weston_plane cursor_plane; @@ -1856,7 +1860,7 @@ static int create_output_for_connector(struct drm_compositor *ec, drmModeRes *resources, drmModeConnector *connector, - int x, int y, struct udev_device *drm_device) + struct udev_device *drm_device) { struct drm_output *output; struct drm_mode *drm_mode, *next, *preferred, *current, *configured, *best; @@ -1870,6 +1874,8 @@ create_output_for_connector(struct drm_compositor *ec, const char *type_name; enum output_config config; uint32_t transform; + int x, y; + struct weston_output *prev = NULL; i = find_crtc_for_connector(ec, resources, connector); if (i 0) { @@ -1923,6 +1929,14 @@ create_output_for_connector(struct drm_compositor *ec, setup_output_seat_constraint(ec, output-base, s); free(s); + weston_config_section_get_string(section, clone, s, ); + if (strcmp(s, ) != 0) { + output-base.is_slave = 1; + output-base.master_output_name = strdup(s); + } + wl_list_init(output-base.clone_output_list); + free(s); + output-crtc_id = resources-crtcs[i]; output-pipe = i; ec-crtc_allocator |= (1 output-crtc_id); @@ -2009,9 +2023,27 @@ create_output_for_connector(struct drm_compositor *ec, output-base.current_mode-flags |= WL_OUTPUT_MODE_CURRENT; - weston_output_init(output-base, ec-base, x, y, - connector-mmWidth, connector-mmHeight, - transform, scale); + if (!output-base.is_slave) { + if (wl_list_empty(ec-base.output_list)) + x = 0; + else { + prev = container_of(ec-base.output_list.prev, + struct weston_output, + link); + x = prev-x + prev-width; + } + y = 0; + + weston_output_init(output-base, ec-base, x, y, + connector-mmWidth, connector-mmHeight, + transform, scale); + } else { + output-base.compositor = ec-base; + output-transform = transform; + output-scale = scale; + output-mm_width = connector-mmWidth; + output-mm_height = connector-mmHeight; + } if (ec-use_pixman) { if (drm_output_init_pixman(output, ec) 0) { @@ -2034,7 +2066,10 @@ 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 (!output-base.is_slave) + wl_list_insert(ec-base.output_list.prev, output-base.link); + else + wl_list_insert(ec-clone_output_list.prev, output-base.link); find_and_parse_output_edid(ec, output, connector); if (connector-connector_type == DRM_MODE_CONNECTOR_LVDS) @@ -2157,6 +2192,126 @@ destroy_sprites(struct drm_compositor *compositor) } } +/* Because slave and master output share the same frame buffer which + * is assigned according to master output's mode. If clone output's mode + * is larger than frame buffer's size, the mode setting for clone + * output will fail. Choosing a nearest mode below master output's mode */ +static int
[PATCH 3/9] compositor-drm: Deal with VT switch in clone mode
When system do VT switch, slave output should use master output's fb to restore mode. Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- src/compositor-drm.c | 38 +- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index ce85aec..1d8c983 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -2608,6 +2608,7 @@ drm_compositor_set_modes(struct drm_compositor *compositor) struct drm_output *output; struct drm_mode *drm_mode; int ret; + struct drm_output *clone_output; wl_list_for_each(output, compositor-base.output_list, base.link) { if (!output-current) { @@ -2628,9 +2629,33 @@ drm_compositor_set_modes(struct drm_compositor *compositor) if (ret 0) { weston_log( failed to set mode %dx%d for output at %d,%d: %m\n, - drm_mode-base.width, drm_mode-base.height, + drm_mode-base.width, drm_mode-base.height, output-base.x, output-base.y); } + + if (!output-base.is_slave) { + wl_list_for_each(clone_output, +output-base.clone_output_list, +base.link) { + drm_mode = (struct drm_mode *) + clone_output-base.current_mode; + ret = drmModeSetCrtc(compositor-drm.fd, +clone_output-crtc_id, +output-current-fb_id, +0, 0, + clone_output-connector_id, +1, +drm_mode-mode_info); + if (ret 0) { + weston_log(failed to set mode %dx%d + for output at %d,%d: %m\n, + drm_mode-base.width, + drm_mode-base.height, + clone_output-base.x, + clone_output-base.y); + } + } + } } } @@ -2641,6 +2666,7 @@ session_notify(struct wl_listener *listener, void *data) struct drm_compositor *ec = data; struct drm_sprite *sprite; struct drm_output *output; + struct drm_output *clone_output; if (ec-base.session_active) { weston_log(activating session\n); @@ -2666,6 +2692,16 @@ session_notify(struct wl_listener *listener, void *data) wl_list_for_each(output, ec-base.output_list, base.link) { output-base.repaint_needed = 0; drmModeSetCursor(ec-drm.fd, output-crtc_id, 0, 0, 0); + + if (!output-base.is_slave) { + wl_list_for_each(clone_output, + output-base.clone_output_list, +base.link) { + drmModeSetCursor(ec-drm.fd, +clone_output-crtc_id, +0, 0, 0); + } + } } output = container_of(ec-base.output_list.next, -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 6/9] compositor-drm: Abstract drm_output_set_mode()
Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- src/compositor-drm.c | 81 +++- 1 file changed, 29 insertions(+), 52 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 842710f..836f81d 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -583,6 +583,27 @@ drm_output_set_gamma(struct weston_output *output_base, } static int +drm_output_set_mode(struct drm_output *output, + uint32_t fb_id) +{ + struct drm_compositor *compositor = + (struct drm_compositor *)output-base.compositor; + struct drm_mode *mode; + int ret = 0; + + mode = container_of(output-base.current_mode, + struct drm_mode, base); + ret = drmModeSetCrtc(compositor-drm.fd, output-crtc_id, +fb_id, 0, 0, +output-connector_id, 1, +mode-mode_info); + if (ret) + weston_log(set mode failed:%m\n); + + return ret; +} + +static int drm_output_repaint(struct weston_output *output_base, pixman_region32_t *damage) { @@ -590,7 +611,6 @@ drm_output_repaint(struct weston_output *output_base, struct drm_compositor *compositor = (struct drm_compositor *) output-base.compositor; struct drm_sprite *s; - struct drm_mode *mode; int ret = 0; struct drm_output *clone_output; @@ -602,33 +622,18 @@ drm_output_repaint(struct weston_output *output_base, if (!output-next) return -1; - mode = container_of(output-base.current_mode, struct drm_mode, base); if (!output-current || output-current-stride != output-next-stride) { - ret = drmModeSetCrtc(compositor-drm.fd, output-crtc_id, -output-next-fb_id, 0, 0, -output-connector_id, 1, -mode-mode_info); - if (ret) { - weston_log(set mode failed: %m\n); + if (drm_output_set_mode(output, output-next-fb_id)) goto err_pageflip; - } + output_base-set_dpms(output_base, WESTON_DPMS_ON); wl_list_for_each(clone_output, output-base.clone_output_list, base.link) { - mode = container_of(clone_output-base.current_mode, - struct drm_mode, base); - - ret = drmModeSetCrtc(compositor-drm.fd, -clone_output-crtc_id, -output-next-fb_id, 0, 0, -clone_output-connector_id, 1, -mode-mode_info); - if (ret) { - weston_log(set mode failed:%m\n); + if (drm_output_set_mode(clone_output, + output-next-fb_id)) goto err_pageflip; - } clone_output-base.set_dpms(clone_output-base, WESTON_DPMS_ON); @@ -2699,8 +2704,6 @@ static void drm_compositor_set_modes(struct drm_compositor *compositor) { struct drm_output *output; - struct drm_mode *drm_mode; - int ret; struct drm_output *clone_output; wl_list_for_each(output, compositor-base.output_list, base.link) { @@ -2714,40 +2717,14 @@ drm_compositor_set_modes(struct drm_compositor *compositor) continue; } - drm_mode = (struct drm_mode *) output-base.current_mode; - ret = drmModeSetCrtc(compositor-drm.fd, output-crtc_id, -output-current-fb_id, 0, 0, -output-connector_id, 1, -drm_mode-mode_info); - if (ret 0) { - weston_log( - failed to set mode %dx%d for output at %d,%d: %m\n, - drm_mode-base.width, drm_mode-base.height, - output-base.x, output-base.y); - } + drm_output_set_mode(output, output-current-fb_id); if (!output-base.is_slave) { wl_list_for_each(clone_output, output-base.clone_output_list, -base.link) { - drm_mode = (struct drm_mode *) - clone_output-base.current_mode; - ret = drmModeSetCrtc(compositor-drm.fd, -
[PATCH 9/9] shell: set_fullscreen and set_maximized in clone mode
if the assigned output is slave, change the assigned output to associated master output Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- desktop-shell/shell.c | 11 --- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 2bc1856..0edefbd 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -2372,8 +2372,11 @@ shell_surface_set_fullscreen(struct wl_client *client, struct shell_surface *shsurf = wl_resource_get_user_data(resource); struct weston_output *output; - if (output_resource) + if (output_resource) { output = wl_resource_get_user_data(output_resource); + if (output-is_slave) + output = output-master_output; + } else output = NULL; @@ -2477,9 +2480,11 @@ shell_surface_set_maximized(struct wl_client *client, struct shell_surface *shsurf = wl_resource_get_user_data(resource); struct weston_output *output; - if (output_resource) + if (output_resource) { output = wl_resource_get_user_data(output_resource); - else + if (output-is_slave) + output = output-master_output; + } else output = NULL; shell_surface_set_parent(shsurf, NULL); -- 1.8.3.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 7/9] compositor: Hot plug a output in clone mode
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_listenerrole_change_listener; struct wl_listenerdestroy_listener; struct wl_listlink; @@ -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 + *
[PATCH 8/9] compositor: Handle background and panel surface in clone mode
The background and panel view of slave output can't exist on layer_list and view_list, otherwise panel is mess. When unplugging a master, one slave may become master, the slave's background and panel view should be moved to view_list. When plugging a master, one old master may become slave, the old master's background and panel view should be removed from view_list Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- desktop-shell/shell.c | 70 +-- 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 096d618..2bc1856 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -60,6 +60,8 @@ struct shell_output { struct desktop_shell *shell; struct weston_output *output; uint32_t mark_dirty; + struct weston_view*panel_view; + struct weston_view*background_view; struct wl_listenerrole_change_listener; struct wl_listenerdestroy_listener; struct wl_listlink; @@ -2066,15 +2068,16 @@ static int get_output_panel_height(struct desktop_shell *shell, struct weston_output *output) { - struct weston_view *view; + struct shell_output *shell_output; int panel_height = 0; if (!output) return 0; - wl_list_for_each(view, shell-panel_layer.view_list, layer_link) { - if (view-surface-output == output) { - panel_height = view-surface-height; + wl_list_for_each(shell_output, shell-output_list, link) { + if (shell_output-output == output) { + panel_height = + shell_output-panel_view-surface-height; break; } } @@ -3654,7 +3657,8 @@ configure_static_view(struct weston_view *ev, struct weston_layer *layer) weston_view_set_position(ev, ev-output-x, ev-output-y); - if (wl_list_empty(ev-layer_link)) { + if (wl_list_empty(ev-layer_link) + !ev-output-is_slave) { wl_list_insert(layer-view_list, ev-layer_link); weston_compositor_schedule_repaint(ev-surface-compositor); } @@ -3681,6 +3685,7 @@ desktop_shell_set_background(struct wl_client *client, struct weston_surface *surface = wl_resource_get_user_data(surface_resource); struct weston_view *view, *next; + struct shell_output *shell_output; if (surface-configure) { wl_resource_post_error(surface_resource, @@ -3697,6 +3702,12 @@ desktop_shell_set_background(struct wl_client *client, surface-configure_private = shell; surface-output = wl_resource_get_user_data(output_resource); view-output = surface-output; + + wl_list_for_each(shell_output, shell-output_list, link) { + if (shell_output-output == view-output) + shell_output-background_view = view; + } + desktop_shell_send_configure(resource, 0, surface_resource, surface-output-width, @@ -3724,6 +3735,7 @@ desktop_shell_set_panel(struct wl_client *client, struct weston_surface *surface = wl_resource_get_user_data(surface_resource); struct weston_view *view, *next; + struct shell_output *shell_output; if (surface-configure) { wl_resource_post_error(surface_resource, @@ -3740,6 +3752,12 @@ desktop_shell_set_panel(struct wl_client *client, surface-configure_private = shell; surface-output = wl_resource_get_user_data(output_resource); view-output = surface-output; + + wl_list_for_each(shell_output, shell-output_list, link) { + if (shell_output-output == view-output) + shell_output-panel_view = view; + } + desktop_shell_send_configure(resource, 0, surface_resource, surface-output-width, @@ -5625,15 +5643,30 @@ handle_output_role_change(struct wl_listener *listener, void *data) container_of(listener, struct shell_output, role_change_listener); struct weston_output *output = (struct weston_output *)data; + struct desktop_shell *shell = shell_output-shell; /* Output change from master to slave. */ - if (output-is_slave) + if (output-is_slave) { + wl_list_remove(shell_output-background_view-layer_link); + wl_list_init(shell_output-background_view-layer_link); + wl_list_remove(shell_output-panel_view-layer_link); + wl_list_init(shell_output-panel_view-layer_link); + /* Mark views on this old master as dirty. * But we will use new master as
Re: [RFC v4] Fullscreen shell protocol
Hi Jason On Thu, 13 Feb 2014 22:37:53 -0600 Jason Ekstrand ja...@jlekstrand.net wrote: The following is yet another take on the fullscreen shell protocol. Previous versions more-or-less followed the approach taken in wl_shell. This version completely reworks the concept. In particular, the protocol is split into two use-cases. The first is that of a simple client that wants to present a surface or set of surfaces possibly with some scaling. This happens through the present_surface request which looks similar to that of wl_shell only without the modesetting. The second use-case is of a client that wants more control over the outputs. In this case, the client uses the present_surface_for_mode request to present the surface at a particular output mode. This request provides a more-or-less atomic modeset operation. If the compositor can satisfy the requested mode, then the mode is changed and the new surface is presented. Otherwise, the compositor harmlessly falls back to the previously presented surface and the client is informed that the switch failed. This way, the surface is either displayed correctly or not at all. Of course, a client is free to call present_surface_for_mode with the currently presented surface and hope for the best. However, this may result in strange behavior and there is no reliable fallback if the mode switch fails. In particular, I would like feedback on the modesetting portion of this protocol. This is particularly targetted at compositors that want to run inside weston or some other fullscreen compositor. In the next week or so, I will attempt to implement all this in weston and see how well it works. However, I would also like to know how well this will work for other compositors such as KWin or Hawaii. Thanks for your feedback, --Jason Ekstrand = Protocol follows: = protocol name=fullscreen_shell interface name=wl_fullscreen_shell version=1 This interface should have a destructor request IMO. It's not stricly required, but I think it would be consistent (I think all global interfaces need an explicit destructor request) and more future-proof. description summary=Displays a single surface per output Displays a single surface per output. This interface provides a mechanism for a single client to display simple full-screen surfaces. While there technically may be multiple clients bound to this interface, only one of those clients should be shown at a time. To present a surface, the client uses either the present_surface or present_surface_for_mode requests. Presenting a surface takes effect on the next wl_surface.commit. See the individual requests for details about scaling and mode switches. The client can have at most one surface per output at any time. Requesting a surface be presented on an output that already has a surface replaces the previously presented surface. Presenting a null surface removes its content and effectively disables the output. Exactly what happens when an output is disabled is compositor-specific. The same surface may be presented multiple outputs simultaneously. If the same surface is presented on multiple outputs, should the client have a way to say which output is to be considered the surface's main output, where e.g. presentation feedback is synced to? Maybe also note explicitly, that once a surface has been presented on an output, it stays on that output until explicitly removed, or output is unplugged? So that simple attach+damage+commit can be used to update the content, if that is the intention. /description enum name=present_method description summary=different method to set the surface fullscreen Hints to indicate to the compositor how to deal with a conflict between the dimensions of the surface and the dimensions of the output. The compositor is free to ignore this parameter. /description entry name=default value=0 summary=no preference, apply default policy/ entry name=center value=1 summary=center the surface on the output/ entry name=zoom value=2 summary=scale the surface, preserving aspect ratio, to the largest size that will fit on the output / entry name=zoom_crop value=3 summary=scale the surface, preserving aspect ratio, to fully fill the output cropping if needed / entry name=stretch value=4 summary=scale the surface to the size of the output ignoring aspect ratio / /enum request name=present_surface description summary=present surface for display Present a surface on the given output. If the output is null, the compositor will present the surface on whatever display (or displays) it thinks best. In particular, this may replace any or all surfaces currently presented so it should not be used
Re: [PATCH 2/9] compositor: Output repaint in clone mode
On Fri, 14 Feb 2014 15:17:37 +0800 Xiong Zhang xiong.y.zh...@intel.com wrote: Because slave output doesn't in compositor-output_list, the output-repaint()is called from master output only. When master output repaint,all the slave output should repaint also. Slave output share fb with master output,when both slave and master have finished page flip, the fb obj can be released. Hi, ok, so core's finish_frame will be called when all flips of a master output and its slaves have completed. If the refresh rates of these outputs are different, I think it means that the perceived frame rate (the frequency at which finish_frame is called) will fluctuate over time. That will have very interesting consequences for presentation prediction and feedback. OTOH, the future will bring dynamically varied refresh rate monitors, so client's should be prepared for fluctuations in the apparent vblank frequency anyway. I'm not claiming your patch creates a problem, I think we can cope with it, but it will be interesting nevertheless. Just pointing out we should keep this in mind. We may need to tweak finish_frame calling logic a bit, so that it gets the flip completion timestamp of the master output, and not whatever output was the last one. But that will only be a concern when the presentation extension lands. I think... unless we care about the timestamp carried by the frame callbacks. Thanks, pq Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- src/compositor-drm.c | 112 ++- src/compositor.c | 3 +- 2 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 6773226..ce85aec 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -155,6 +155,7 @@ struct drm_output { uint32_t transform; int scale, mm_width, mm_height; + uint32_t page_flip_count; struct gbm_surface *surface; struct gbm_bo *cursor_bo[2]; @@ -591,8 +592,9 @@ drm_output_repaint(struct weston_output *output_base, struct drm_sprite *s; struct drm_mode *mode; int ret = 0; + struct drm_output *clone_output; - if (output-destroy_pending) + if (output-destroy_pending || output-base.is_slave) return -1; if (!output-next) @@ -612,6 +614,25 @@ drm_output_repaint(struct weston_output *output_base, goto err_pageflip; } output_base-set_dpms(output_base, WESTON_DPMS_ON); + + wl_list_for_each(clone_output, output-base.clone_output_list, + base.link) { + mode = container_of(clone_output-base.current_mode, + struct drm_mode, base); + + ret = drmModeSetCrtc(compositor-drm.fd, + clone_output-crtc_id, + output-next-fb_id, 0, 0, + clone_output-connector_id, 1, + mode-mode_info); + if (ret) { + weston_log(set mode failed:%m\n); + goto err_pageflip; + } + + clone_output-base.set_dpms(clone_output-base, + WESTON_DPMS_ON); + } } if (drmModePageFlip(compositor-drm.fd, output-crtc_id, @@ -622,6 +643,23 @@ drm_output_repaint(struct weston_output *output_base, } output-page_flip_pending = 1; + output-page_flip_count++; + + /* clone output repaint*/ + wl_list_for_each(clone_output, output-base.clone_output_list, + base.link) { + if (drmModePageFlip(compositor-drm.fd, + clone_output-crtc_id, + output-next-fb_id, + DRM_MODE_PAGE_FLIP_EVENT, + clone_output) 0) { + weston_log(queueing pageflip failed:%m\n); + goto err_pageflip; + } + + clone_output-page_flip_pending = 1; + output-page_flip_count++; + } drm_output_set_cursor(output); @@ -691,8 +729,9 @@ drm_output_start_repaint_loop(struct weston_output *output_base) uint32_t fb_id; uint32_t msec; struct timespec ts; + struct drm_output *clone_output; - if (output-destroy_pending) + if (output-destroy_pending || output-base.is_slave) return; if (!output-current) { @@ -707,6 +746,22 @@ drm_output_start_repaint_loop(struct weston_output *output_base) weston_log(queueing pageflip failed: %m\n); goto finish_frame; } + output-page_flip_count++; + +
Re: [PATCH 5/9] compositor: Output unplug in clone mode
On Fri, 14 Feb 2014 15:17:40 +0800 Xiong Zhang xiong.y.zh...@intel.com wrote: If unplugged output is a slave output, no need to restore views. If unplugged output is a master output which doesn't have slave output related it, views will be restored the same as extend mode. If unplugged output is a master output which have slave output related it, one slave output will be upgraded to master output, moving output following unplugged output isn't necessay, views on unplugged output will be marked as dirty. Signed-off-by: Xiong Zhang xiong.y.zh...@intel.com --- desktop-shell/shell.c | 13 ++- src/compositor-drm.c | 103 +++--- src/compositor.c | 15 ++-- src/compositor.h | 1 + 4 files changed, 122 insertions(+), 10 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 1e4a255..85987e5 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -5600,6 +5600,9 @@ handle_output_destroy(struct wl_listener *listener, void *data) wl_list_remove(output_listener-role_change_listener.link); wl_list_remove(output_listener-link); free(output_listener); + + /* Trigger compositor repaint */ + weston_compositor_schedule_repaint(output_listener-output-compositor); } static void @@ -5676,10 +5679,18 @@ setup_output_destroy_handler(struct weston_compositor *ec, struct desktop_shell *shell) { struct weston_output *output; + struct weston_output *clone_output; wl_list_init(shell-output_list); - wl_list_for_each(output, ec-output_list, link) + wl_list_for_each(output, ec-output_list, link) { create_shell_output(shell, output); + if (!output-is_slave) { + wl_list_for_each(clone_output, + output-clone_output_list, + link) + create_shell_output(shell, clone_output); + } + } shell-output_create_listener.notify = handle_output_create; wl_signal_add(ec-output_created_signal, diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 1d8c983..842710f 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -1217,6 +1217,8 @@ drm_assign_planes(struct weston_output *output) static void drm_output_fini_pixman(struct drm_output *output); +static void +drm_output_destroy_with_slave(struct drm_output *output); static void drm_output_destroy(struct weston_output *output_base) @@ -1259,6 +1261,15 @@ drm_output_destroy(struct weston_output *output_base) weston_plane_release(output-fb_plane); weston_plane_release(output-cursor_plane); + if (!output-base.is_slave + !wl_list_empty(output-base.clone_output_list)) { + drm_output_destroy_with_slave(output); + + /* One slave is upgraded to master, Don't move + * the following output.*/ + output_base.dont_move = 1; + } + weston_output_destroy(output-base); free(output); @@ -2420,6 +2431,73 @@ drm_output_add_slave(struct drm_compositor *ec) } } +/* The output with max width will be new_master. */ +static struct weston_output * +find_new_master(struct weston_output *master) +{ + struct weston_output *new_master, *output; + int32_t max_width = 0; + + new_master = NULL; + wl_list_for_each(output, master-clone_output_list, + link) { + if (output-current_mode-width max_width) { + max_width = output-current_mode-width; + new_master = output; + } + } + + return new_master; +} + +/* If a master is unplugged, a output will be chosen from + * master-clone_output_list to replace the unplugged master.*/ +static void +drm_output_destroy_with_slave(struct drm_output *output) +{ + struct weston_output *new_master, *tmp; + struct drm_output *clone_output, *next; + intoffset, move; + + new_master = find_new_master(output-base); + + /* When old master's width is different from new master's + * width, move the output following the old master. */ + offset = output-base.width - new_master-width; + if (offset != 0) { + move = 0; + wl_list_for_each(tmp, new_master-compositor-output_list, + link) { + if (move == 1) + weston_output_move(tmp, + tmp-x - offset, tmp-y); + + if (tmp == output-base) + move = 1; + } + } + + wl_list_remove(new_master-link); + wl_list_insert(output-base.link.prev, +