[weston v2 6/8] xwm: Ignore configure request while the user is resizing
We don't want the application to fight with the user when manually resizing a window. v2: Re-enable sync when a new resize operation is started Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index a0ff6b62..1f3bcdac 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -173,6 +173,7 @@ struct weston_wm_window { int delete_window; int maximized_vert; int maximized_horz; + int resizing; int64_t sync_request_serial; int configure_pending; int sync_disabled; @@ -701,6 +702,11 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev return; } + if (window->frame && window->resizing) { + wm_log("Ignore configure request while resizing window\n"); + return; + } + if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH) window->width = configure_request->width; if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT) @@ -1671,9 +1677,13 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window, case _NET_WM_MOVERESIZE_SIZE_BOTTOM: case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: case _NET_WM_MOVERESIZE_SIZE_LEFT: + if (!window->resizing) + window->sync_disabled = 0; + window->resizing = 1; xwayland_interface->resize(window->shsurf, pointer, map[detail]); break; case _NET_WM_MOVERESIZE_CANCEL: + window->resizing = 0; break; } } @@ -2106,6 +2116,10 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) WL_POINTER_BUTTON_STATE_RELEASED; button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT; + if (window->resizing && button_id == BTN_LEFT && + button_state == WL_POINTER_BUTTON_STATE_PRESSED) + window->resizing = 0; + if (button_state == WL_POINTER_BUTTON_STATE_PRESSED) { if (button->time - window->last_button_time <= DOUBLE_CLICK_PERIOD) { double_click = 1; @@ -2143,8 +2157,12 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) } if (frame_status(window->frame) & FRAME_STATUS_RESIZE) { - if (pointer && weston_wm_window_is_resizable(window)) + if (pointer && weston_wm_window_is_resizable(window)) { + if (!window->resizing) + window->sync_disabled = 0; + window->resizing = 1; xwayland_interface->resize(window->shsurf, pointer, location); + } frame_status_clear(window->frame, FRAME_STATUS_RESIZE); } -- 2.13.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston v2 8/8] xwm: Use Pango to draw title string if available
If Weston is built with Pango, use it to render the title for X11 applications and Weston toy toolkit clients. It allows us to ellipsize the title when there isn't enough space to show the whole string. Signed-off-by: Louis-Francis Ratté-Boulianne --- Makefile.am | 2 ++ configure.ac| 3 +++ shared/cairo-util.c | 60 - 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 9d99c694..13097b73 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1136,12 +1136,14 @@ libshared_cairo_la_CFLAGS = \ $(COMPOSITOR_CFLAGS)\ $(PIXMAN_CFLAGS)\ $(CAIRO_CFLAGS) \ + $(PANGO_CFLAGS) \ $(PNG_CFLAGS) \ $(WEBP_CFLAGS) libshared_cairo_la_LIBADD =\ $(PIXMAN_LIBS) \ $(CAIRO_LIBS) \ + $(PANGO_LIBS) \ $(PNG_LIBS) \ $(WEBP_LIBS)\ $(JPEG_LIBS) diff --git a/configure.ac b/configure.ac index 77012dcc..48ab5546 100644 --- a/configure.ac +++ b/configure.ac @@ -447,6 +447,9 @@ if test x$enable_weston_launch = xyes; then fi AM_CONDITIONAL(HAVE_PANGO, test "x$have_pango" = "xyes") +if test "x$have_pango" = "xyes"; then + AC_DEFINE([HAVE_PANGO], [1], [Have pango])] +fi AM_CONDITIONAL(HAVE_CAIRO_GLESV2, [test "x$have_cairo_egl" = "xyes" -a "x$cairo_modules" = "xcairo-glesv2" -a "x$enable_egl" = "xyes"]) diff --git a/shared/cairo-util.c b/shared/cairo-util.c index fd8cc7ce..d71e0ed4 100644 --- a/shared/cairo-util.c +++ b/shared/cairo-util.c @@ -39,6 +39,10 @@ #include "image-loader.h" #include "config-parser.h" +#ifdef HAVE_PANGO +#include +#endif + void surface_flush_device(cairo_surface_t *surface) { @@ -451,14 +455,42 @@ theme_destroy(struct theme *t) free(t); } +#ifdef HAVE_PANGO +static PangoLayout * +create_layout(cairo_t *cr, const char *title) +{ + PangoLayout *layout; + PangoFontDescription *desc; + + layout = pango_cairo_create_layout(cr); + pango_layout_set_text(layout, title, -1); + desc = pango_font_description_from_string("Sans Bold 10"); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + pango_layout_set_auto_dir (layout, FALSE); + pango_layout_set_single_paragraph_mode (layout, TRUE); + pango_layout_set_width (layout, -1); + + return layout; +} +#endif + +#ifdef HAVE_PANGO +#define SHOW_TEXT(cr) \ + pango_cairo_show_layout(cr, title_layout) +#else +#define SHOW_TEXT(cr) \ + cairo_show_text(cr, title) +#endif + void theme_render_frame(struct theme *t, cairo_t *cr, int width, int height, const char *title, cairo_rectangle_int_t *title_rect, struct wl_list *buttons, uint32_t flags) { - cairo_text_extents_t extents; - cairo_font_extents_t font_extents; cairo_surface_t *source; int x, y, margin, top_margin; int text_width, text_height; @@ -497,6 +529,23 @@ theme_render_frame(struct theme *t, title_rect->width, title_rect->height); cairo_clip(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + +#ifdef HAVE_PANGO + PangoLayout *title_layout; + PangoRectangle logical; + + title_layout = create_layout(cr, title); + + pango_layout_get_pixel_extents (title_layout, NULL, &logical); + text_width = MIN(title_rect->width, logical.width); + text_height = logical.height; + if (text_width < logical.width) + pango_layout_set_width (title_layout, text_width * PANGO_SCALE); + +#else + cairo_text_extents_t extents; + cairo_font_extents_t font_extents; + cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); @@ -505,6 +554,7 @@ theme_render_frame(struct theme *t, cairo_font_extents (cr, &font_extents); text_width = extents.width; text_height = font_extents.descent - font_extents.ascent; +#endif x = (width - text_width) / 2; y = margin + (t->titlebar_height - text_height)
[weston v2 3/8] xwm: Don't resize windows if the application have these hints
If the minimum and maximum size hints are equal, that means the application doesn't want the window manager to allow resizing. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 26 -- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 4b84b24e..c70938c4 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -973,6 +973,15 @@ weston_wm_window_set_net_wm_state(struct weston_wm_window *window) i, property); } +static inline bool +weston_wm_window_is_resizable(struct weston_wm_window *window) +{ + return (window->size_hints.min_width <= 0 || + window->size_hints.min_height <= 0 || + window->size_hints.min_width != window->size_hints.max_width || + window->size_hints.min_height != window->size_hints.max_height); +} + static void weston_wm_window_create_frame(struct weston_wm_window *window) { @@ -981,7 +990,8 @@ weston_wm_window_create_frame(struct weston_wm_window *window) int x, y, width, height; int buttons = FRAME_BUTTON_CLOSE; - if (window->decorate & MWM_DECOR_MAXIMIZE) + if (window->decorate & MWM_DECOR_MAXIMIZE && + weston_wm_window_is_resizable(window)) buttons |= FRAME_BUTTON_MAXIMIZE; window->frame = frame_create(window->wm->theme, @@ -2133,7 +2143,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) } if (frame_status(window->frame) & FRAME_STATUS_RESIZE) { - if (pointer) + if (pointer && weston_wm_window_is_resizable(window)) xwayland_interface->resize(window->shsurf, pointer, location); frame_status_clear(window->frame, FRAME_STATUS_RESIZE); } @@ -2174,8 +2184,10 @@ weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event) if (frame_status(window->frame) & FRAME_STATUS_REPAINT) weston_wm_window_schedule_repaint(window); - cursor = get_cursor_for_location(location); - weston_wm_window_set_cursor(wm, window->frame_id, cursor); + if (weston_wm_window_is_resizable(window)) { + cursor = get_cursor_for_location(location); + weston_wm_window_set_cursor(wm, window->frame_id, cursor); + } } static void @@ -2195,8 +2207,10 @@ weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event) if (frame_status(window->frame) & FRAME_STATUS_REPAINT) weston_wm_window_schedule_repaint(window); - cursor = get_cursor_for_location(location); - weston_wm_window_set_cursor(wm, window->frame_id, cursor); + if (weston_wm_window_is_resizable(window)) { + cursor = get_cursor_for_location(location); + weston_wm_window_set_cursor(wm, window->frame_id, cursor); + } } static void -- 2.13.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston v2 4/8] xwm: Only send configure a window if the new size is different
If we configure a window with the same size and wait for the sync alarm to go off, the resizing is gonna block. The event is only handled is the size actually changed. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index c70938c4..3cc6fa24 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -2780,6 +2780,7 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height) struct weston_wm_window *window = get_wm_window(surface); struct weston_wm *wm = window->wm; struct theme *t = window->wm->theme; + int new_width, new_height; int vborder, hborder; if (window->decorate && !window->fullscreen) { @@ -2791,14 +2792,20 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height) } if (width > hborder) - window->width = width - hborder; + new_width = width - hborder; else - window->width = 1; + new_width = 1; if (height > vborder) - window->height = height - vborder; + new_height = height - vborder; else - window->height = 1; + new_height = 1; + + if (window->width == new_width && window->height == new_height) + return; + + window->width = new_width; + window->height = new_height; if (window->frame) frame_resize_inside(window->frame, window->width, window->height); -- 2.13.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston v2 7/8] xwm: Deal with title in a smarter way when there isn't enough space
The title in X11 windows and Wayland application using Weston toy toolkit were placing the title in a very naive fashion. It was only try to center the string in the title bar. This patch: * Makes sure the title isn't renderer underneath buttons; * Move the title to the left if the titlebar isn't large enough; * Clip the end of the title if needed. Signed-off-by: Louis-Francis Ratté-Boulianne --- shared/cairo-util.c | 26 +++--- shared/cairo-util.h | 4 ++-- shared/frame.c | 10 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/shared/cairo-util.c b/shared/cairo-util.c index 21fcbea5..fd8cc7ce 100644 --- a/shared/cairo-util.c +++ b/shared/cairo-util.c @@ -454,13 +454,14 @@ theme_destroy(struct theme *t) void theme_render_frame(struct theme *t, cairo_t *cr, int width, int height, - const char *title, struct wl_list *buttons, - uint32_t flags) + const char *title, cairo_rectangle_int_t *title_rect, + struct wl_list *buttons, uint32_t flags) { cairo_text_extents_t extents; cairo_font_extents_t font_extents; cairo_surface_t *source; int x, y, margin, top_margin; + int text_width, text_height; cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, 0, 0, 0); @@ -491,11 +492,10 @@ theme_render_frame(struct theme *t, t->width, top_margin); if (title || !wl_list_empty(buttons)) { - cairo_rectangle (cr, margin + t->width, margin, -width - (margin + t->width) * 2, -t->titlebar_height - t->width); - cairo_clip(cr); + cairo_rectangle (cr, title_rect->x, title_rect->y, +title_rect->width, title_rect->height); + cairo_clip(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, @@ -503,11 +503,15 @@ theme_render_frame(struct theme *t, cairo_set_font_size(cr, 14); cairo_text_extents(cr, title, &extents); cairo_font_extents (cr, &font_extents); - x = (width - extents.width) / 2; - y = margin + - (t->titlebar_height - -font_extents.ascent - font_extents.descent) / 2 + - font_extents.ascent; + text_width = extents.width; + text_height = font_extents.descent - font_extents.ascent; + + x = (width - text_width) / 2; + y = margin + (t->titlebar_height - text_height) / 2; + if (x < title_rect->x) + x = title_rect->x; + else if (x + text_width > (title_rect->x + title_rect->width)) + x = (title_rect->x + title_rect->width) - text_width; if (flags & THEME_FRAME_ACTIVE) { cairo_move_to(cr, x + 1, y + 1); diff --git a/shared/cairo-util.h b/shared/cairo-util.h index 84cf005e..9481e58c 100644 --- a/shared/cairo-util.h +++ b/shared/cairo-util.h @@ -75,8 +75,8 @@ theme_set_background_source(struct theme *t, cairo_t *cr, uint32_t flags); void theme_render_frame(struct theme *t, cairo_t *cr, int width, int height, - const char *title, struct wl_list *buttons, - uint32_t flags); + const char *title, cairo_rectangle_int_t *title_rect, + struct wl_list *buttons, uint32_t flags); enum theme_location { THEME_LOCATION_INTERIOR = 0, diff --git a/shared/frame.c b/shared/frame.c index eb0cd77a..5ca7e08b 100644 --- a/shared/frame.c +++ b/shared/frame.c @@ -98,6 +98,8 @@ struct frame { int opaque_margin; int geometry_dirty; + cairo_rectangle_int_t title_rect; + uint32_t status; struct wl_list buttons; @@ -532,6 +534,11 @@ frame_refresh_geometry(struct frame *frame) } } + frame->title_rect.x = x_l; + frame->title_rect.y = y; + frame->title_rect.width = x_r - x_l; + frame->title_rect.height = titlebar_height; + frame->geometry_dirty = 0; } @@ -938,7 +945,8 @@ frame_repaint(struct frame *frame, cairo_t *cr) cairo_save(cr); theme_render_frame(frame->theme, cr, frame->width, frame->height, - frame->title, &frame->buttons, flags); + frame->title, &frame->title_rect, + &frame->buttons, flags); cairo_restore(cr); wl_list_for_each(button, &frame->buttons, link) -- 2
[weston v2 1/8] xwm: Implement _NET_WM_SYNC_REQUEST protocol
v2: Remove some useless checks and don't be too verbose Signed-off-by: Louis-Francis Ratté-Boulianne fixup: Implement _NET_WM_SYNC_REQUEST --- configure.ac | 2 +- xwayland/window-manager.c | 207 +++--- xwayland/xwayland.h | 5 ++ 3 files changed, 201 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index c287fac6..77012dcc 100644 --- a/configure.ac +++ b/configure.ac @@ -163,7 +163,7 @@ AC_ARG_ENABLE(xwayland-test, [ --enable-xwayland-test],, AM_CONDITIONAL(ENABLE_XWAYLAND, test x$enable_xwayland = xyes) AM_CONDITIONAL(ENABLE_XWAYLAND_TEST, test x$enable_xwayland = xyes -a x$enable_xwayland_test = xyes) if test x$enable_xwayland = xyes; then - PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcb-composite xcursor cairo-xcb) + PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcb-composite xcb-sync xcursor cairo-xcb) AC_DEFINE([BUILD_XWAYLAND], [1], [Build the X server launcher]) AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH], diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 3e8c4c7c..149d7fe4 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -43,6 +43,7 @@ #include "compositor.h" #include "xwayland.h" #include "xwayland-internal-interface.h" +#include "wayland-server-core.h" #include "cairo-util.h" #include "hash.h" @@ -136,6 +137,8 @@ struct weston_wm_window { struct weston_wm *wm; xcb_window_t id; xcb_window_t frame_id; + xcb_sync_alarm_t sync_request_alarm; + xcb_sync_counter_t sync_request_counter; struct frame *frame; cairo_surface_t *cairo_surface; uint32_t surface_id; @@ -144,6 +147,7 @@ struct weston_wm_window { struct wl_listener surface_destroy_listener; struct wl_event_source *repaint_source; struct wl_event_source *configure_source; + struct wl_event_source *sync_request_timer; int properties_dirty; int pid; char *machine; @@ -167,6 +171,10 @@ struct weston_wm_window { int delete_window; int maximized_vert; int maximized_horz; + int64_t sync_request_serial; + int configure_pending; + int sync_disabled; + int wait_redraw; struct wm_size_hints size_hints; struct motif_wm_hints motif_hints; struct wl_list link; @@ -179,6 +187,9 @@ static void weston_wm_set_net_active_window(struct weston_wm *wm, xcb_window_t window); static void +weston_wm_window_configure(void *data); + +static void weston_wm_window_schedule_repaint(struct weston_wm_window *window); static int @@ -472,6 +483,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) }, { wm->atom.net_wm_name,XCB_ATOM_STRING, F(name) }, { wm->atom.net_wm_pid, XCB_ATOM_CARDINAL, F(pid) }, + { wm->atom.net_wm_sync_request_counter,XCB_SYNC_COUNTER, F(sync_request_counter) }, { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS,NULL }, { wm->atom.wm_client_machine, XCB_ATOM_WM_CLIENT_MACHINE, F(machine) }, }; @@ -482,6 +494,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) void *p; uint32_t *xid; xcb_atom_t *atom; + xcb_sync_counter_t *counter; uint32_t i; char name[1024]; @@ -537,6 +550,10 @@ weston_wm_window_read_properties(struct weston_wm_window *window) atom = xcb_get_property_value(reply); *(xcb_atom_t *) p = *atom; break; + case XCB_SYNC_COUNTER: + counter = xcb_get_property_value(reply); + *(xcb_sync_counter_t *) p = *counter; + break; case TYPE_WM_PROTOCOLS: atom = xcb_get_property_value(reply); for (i = 0; i < reply->value_len; i++) @@ -674,11 +691,6 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev uint32_t mask, values[16]; int x, y, width, height, i = 0; - wm_log("XCB_CONFIGURE_REQUEST (window %d) %d,%d @ %dx%d\n", - configure_request->window, - configure_request->x, configure_request->y, - configure_request->width, configure_request->height); - if (!wm_lookup_window(wm, configure_request->window, &window)) return; @@ -1045,6 +1057,81 @@ weston_wm_window_set_virtual_desktop(struct weston_wm_window *window, } static void +weston_wm_window_create_sync_alarm(struct weston_wm_window *window) +{ + struct west
[weston v2 5/8] xwm: Make sure we respect the window's size hints
Don't just ignore the minimal and maximal sizes requested by the application. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 3cc6fa24..a0ff6b62 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -2801,6 +2801,20 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height) else new_height = 1; + /* Make sure we respect the window's size hints */ + if (window->size_hints.min_width > 0 && + new_width < window->size_hints.min_width) + new_width = window->size_hints.min_width; + if (window->size_hints.min_height > 0 && + new_height < window->size_hints.min_height) + new_height = window->size_hints.min_height; + if (window->size_hints.max_width > 0 && + new_width > window->size_hints.max_width) + new_width = window->size_hints.max_width; + if (window->size_hints.max_height > 0 && + new_height > window->size_hints.max_height) + new_height = window->size_hints.max_height; + if (window->width == new_width && window->height == new_height) return; -- 2.13.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston v2 2/8] xwm: Maximize windows when double-clicking on title bar
Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 26 -- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 149d7fe4..4b84b24e 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -165,6 +165,8 @@ struct weston_wm_window { struct weston_output_weak_ref legacy_fullscreen_output; int saved_width, saved_height; int decorate; + uint32_t last_button_time; + int did_double; int override_redirect; int fullscreen; int has_alpha; @@ -2060,6 +2062,7 @@ weston_wm_window_close(struct weston_wm_window *window, xcb_timestamp_t time) } } +#define DOUBLE_CLICK_PERIOD 250 static void weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) { @@ -2072,6 +2075,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) enum theme_location location; enum wl_pointer_button_state button_state; uint32_t button_id; + uint32_t double_click = 0; wm_log("XCB_BUTTON_%s (detail %d)\n", button->response_type == XCB_BUTTON_PRESS ? @@ -2092,6 +2096,19 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) WL_POINTER_BUTTON_STATE_RELEASED; button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT; + if (button_state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button->time - window->last_button_time <= DOUBLE_CLICK_PERIOD) { + double_click = 1; + window->did_double = 1; + } else + window->did_double = 0; + + window->last_button_time = button->time; + } else if (window->did_double == 1) { + double_click = 1; + window->did_double = 0; + } + /* Make sure we're looking at the right location. The frame * could have received a motion event from a pointer from a * different wl_seat, but under X it looks like our core @@ -2099,8 +2116,13 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) * location before deciding what to do. */ location = frame_pointer_motion(window->frame, NULL, button->event_x, button->event_y); - location = frame_pointer_button(window->frame, NULL, - button_id, button_state); + if (double_click) + location = frame_double_click(window->frame, NULL, + button_id, button_state); + else + location = frame_pointer_button(window->frame, NULL, + button_id, button_state); + if (frame_status(window->frame) & FRAME_STATUS_REPAINT) weston_wm_window_schedule_repaint(window); -- 2.13.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston v2 0/8] Implement NET_WM_SYNC_REQUEST basic support
Hi, This patchset implements NET_WM_SYNC_REQUEST protocol for throtting X11 window resizes in Weston's XWM. We wait for the window to be drawn (by setting an alarm on the sync counter) before configuring the window again. I also did some small fixes the Xwayland window manager as to better respect size hints from X11 applications and to display the title more elegantly when there isn't enough space available. The first sumission was a while back: https://lists.freedesktop.org/archives/wayland-devel/2017-April/033859.html Changes compared to previous patches are: - Remove some useless checks - Be less verbose when resizing with debug log enabled - Re-enable the sync extension when a new resize operation is started instead of just disabling it forever when something times out. Louis-Francis Ratté-Boulianne (8): xwm: Implement _NET_WM_SYNC_REQUEST protocol xwm: Maximize windows when double-clicking on title bar xwm: Don't resize windows if the application have these hints xwm: Only send configure a window if the new size is different xwm: Make sure we respect the window's size hints xwm: Ignore configure request while the user is resizing xwm: Deal with title in a smarter way when there isn't enough space xwm: Use Pango to draw title string if available Makefile.am | 2 + configure.ac | 5 +- shared/cairo-util.c | 86 ++--- shared/cairo-util.h | 4 +- shared/frame.c| 10 +- xwayland/window-manager.c | 306 ++ xwayland/xwayland.h | 5 + 7 files changed, 374 insertions(+), 44 deletions(-) -- 2.13.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston 8/8] xwm: Use Pango to draw title string if available
If Weston is built with Pango, use it to render the title for X11 applications and Weston toy toolkit clients. It allows us to ellipsize the title when there isn't enough space to show the whole string. Signed-off-by: Louis-Francis Ratté-Boulianne --- Makefile.am | 2 ++ configure.ac| 3 +++ shared/cairo-util.c | 60 - 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 7ee613ba..44af3d19 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1122,12 +1122,14 @@ libshared_cairo_la_CFLAGS = \ $(COMPOSITOR_CFLAGS)\ $(PIXMAN_CFLAGS)\ $(CAIRO_CFLAGS) \ + $(PANGO_CFLAGS) \ $(PNG_CFLAGS) \ $(WEBP_CFLAGS) libshared_cairo_la_LIBADD =\ $(PIXMAN_LIBS) \ $(CAIRO_LIBS) \ + $(PANGO_LIBS) \ $(PNG_LIBS) \ $(WEBP_LIBS)\ $(JPEG_LIBS) diff --git a/configure.ac b/configure.ac index eebeba9d..eeadfeed 100644 --- a/configure.ac +++ b/configure.ac @@ -443,6 +443,9 @@ if test x$enable_weston_launch = xyes; then fi AM_CONDITIONAL(HAVE_PANGO, test "x$have_pango" = "xyes") +if test "x$have_pango" = "xyes"; then + AC_DEFINE([HAVE_PANGO], [1], [Have pango])] +fi AM_CONDITIONAL(HAVE_CAIRO_GLESV2, [test "x$have_cairo_egl" = "xyes" -a "x$cairo_modules" = "xcairo-glesv2" -a "x$enable_egl" = "xyes"]) diff --git a/shared/cairo-util.c b/shared/cairo-util.c index fd8cc7ce..d71e0ed4 100644 --- a/shared/cairo-util.c +++ b/shared/cairo-util.c @@ -39,6 +39,10 @@ #include "image-loader.h" #include "config-parser.h" +#ifdef HAVE_PANGO +#include +#endif + void surface_flush_device(cairo_surface_t *surface) { @@ -451,14 +455,42 @@ theme_destroy(struct theme *t) free(t); } +#ifdef HAVE_PANGO +static PangoLayout * +create_layout(cairo_t *cr, const char *title) +{ + PangoLayout *layout; + PangoFontDescription *desc; + + layout = pango_cairo_create_layout(cr); + pango_layout_set_text(layout, title, -1); + desc = pango_font_description_from_string("Sans Bold 10"); + pango_layout_set_font_description(layout, desc); + pango_font_description_free(desc); + pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); + pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT); + pango_layout_set_auto_dir (layout, FALSE); + pango_layout_set_single_paragraph_mode (layout, TRUE); + pango_layout_set_width (layout, -1); + + return layout; +} +#endif + +#ifdef HAVE_PANGO +#define SHOW_TEXT(cr) \ + pango_cairo_show_layout(cr, title_layout) +#else +#define SHOW_TEXT(cr) \ + cairo_show_text(cr, title) +#endif + void theme_render_frame(struct theme *t, cairo_t *cr, int width, int height, const char *title, cairo_rectangle_int_t *title_rect, struct wl_list *buttons, uint32_t flags) { - cairo_text_extents_t extents; - cairo_font_extents_t font_extents; cairo_surface_t *source; int x, y, margin, top_margin; int text_width, text_height; @@ -497,6 +529,23 @@ theme_render_frame(struct theme *t, title_rect->width, title_rect->height); cairo_clip(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + +#ifdef HAVE_PANGO + PangoLayout *title_layout; + PangoRectangle logical; + + title_layout = create_layout(cr, title); + + pango_layout_get_pixel_extents (title_layout, NULL, &logical); + text_width = MIN(title_rect->width, logical.width); + text_height = logical.height; + if (text_width < logical.width) + pango_layout_set_width (title_layout, text_width * PANGO_SCALE); + +#else + cairo_text_extents_t extents; + cairo_font_extents_t font_extents; + cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); @@ -505,6 +554,7 @@ theme_render_frame(struct theme *t, cairo_font_extents (cr, &font_extents); text_width = extents.width; text_height = font_extents.descent - font_extents.ascent; +#endif x = (width - text_width) / 2; y = margin + (t->titlebar_height - text_height)
[weston 7/8] xwm: Deal with title in a smarter way when there isn't enough space
The title in X11 windows and Wayland application using Weston toy toolkit were placing the title in a very naive fashion. It was only try to center the string in the title bar. This patch: * Makes sure the title isn't renderer underneath buttons; * Move the title to the left if the titlebar isn't large enough; * Clip the end of the title if needed. Signed-off-by: Louis-Francis Ratté-Boulianne --- shared/cairo-util.c | 26 +++--- shared/cairo-util.h | 4 ++-- shared/frame.c | 10 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/shared/cairo-util.c b/shared/cairo-util.c index 21fcbea5..fd8cc7ce 100644 --- a/shared/cairo-util.c +++ b/shared/cairo-util.c @@ -454,13 +454,14 @@ theme_destroy(struct theme *t) void theme_render_frame(struct theme *t, cairo_t *cr, int width, int height, - const char *title, struct wl_list *buttons, - uint32_t flags) + const char *title, cairo_rectangle_int_t *title_rect, + struct wl_list *buttons, uint32_t flags) { cairo_text_extents_t extents; cairo_font_extents_t font_extents; cairo_surface_t *source; int x, y, margin, top_margin; + int text_width, text_height; cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(cr, 0, 0, 0, 0); @@ -491,11 +492,10 @@ theme_render_frame(struct theme *t, t->width, top_margin); if (title || !wl_list_empty(buttons)) { - cairo_rectangle (cr, margin + t->width, margin, -width - (margin + t->width) * 2, -t->titlebar_height - t->width); - cairo_clip(cr); + cairo_rectangle (cr, title_rect->x, title_rect->y, +title_rect->width, title_rect->height); + cairo_clip(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, @@ -503,11 +503,15 @@ theme_render_frame(struct theme *t, cairo_set_font_size(cr, 14); cairo_text_extents(cr, title, &extents); cairo_font_extents (cr, &font_extents); - x = (width - extents.width) / 2; - y = margin + - (t->titlebar_height - -font_extents.ascent - font_extents.descent) / 2 + - font_extents.ascent; + text_width = extents.width; + text_height = font_extents.descent - font_extents.ascent; + + x = (width - text_width) / 2; + y = margin + (t->titlebar_height - text_height) / 2; + if (x < title_rect->x) + x = title_rect->x; + else if (x + text_width > (title_rect->x + title_rect->width)) + x = (title_rect->x + title_rect->width) - text_width; if (flags & THEME_FRAME_ACTIVE) { cairo_move_to(cr, x + 1, y + 1); diff --git a/shared/cairo-util.h b/shared/cairo-util.h index 84cf005e..9481e58c 100644 --- a/shared/cairo-util.h +++ b/shared/cairo-util.h @@ -75,8 +75,8 @@ theme_set_background_source(struct theme *t, cairo_t *cr, uint32_t flags); void theme_render_frame(struct theme *t, cairo_t *cr, int width, int height, - const char *title, struct wl_list *buttons, - uint32_t flags); + const char *title, cairo_rectangle_int_t *title_rect, + struct wl_list *buttons, uint32_t flags); enum theme_location { THEME_LOCATION_INTERIOR = 0, diff --git a/shared/frame.c b/shared/frame.c index eb0cd77a..5ca7e08b 100644 --- a/shared/frame.c +++ b/shared/frame.c @@ -98,6 +98,8 @@ struct frame { int opaque_margin; int geometry_dirty; + cairo_rectangle_int_t title_rect; + uint32_t status; struct wl_list buttons; @@ -532,6 +534,11 @@ frame_refresh_geometry(struct frame *frame) } } + frame->title_rect.x = x_l; + frame->title_rect.y = y; + frame->title_rect.width = x_r - x_l; + frame->title_rect.height = titlebar_height; + frame->geometry_dirty = 0; } @@ -938,7 +945,8 @@ frame_repaint(struct frame *frame, cairo_t *cr) cairo_save(cr); theme_render_frame(frame->theme, cr, frame->width, frame->height, - frame->title, &frame->buttons, flags); + frame->title, &frame->title_rect, + &frame->buttons, flags); cairo_restore(cr); wl_list_for_each(button, &frame->buttons, link) -- 2
[weston 6/8] xwm: Ignore configure request while the user is resizing
We don't want the application to fight with the user when manually resizing a window. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 16 +++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index bea3cc68..3ee76027 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -173,6 +173,7 @@ struct weston_wm_window { int delete_window; int maximized_vert; int maximized_horz; + int resizing; int64_t sync_request_serial; int configure_pending; int sync_disabled; @@ -701,6 +702,11 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev return; } + if (window->frame && window->resizing) { + wm_log("Ignore configure request while resizing window\n"); + return; + } + if (configure_request->value_mask & XCB_CONFIG_WINDOW_WIDTH) window->width = configure_request->width; if (configure_request->value_mask & XCB_CONFIG_WINDOW_HEIGHT) @@ -1672,9 +1678,11 @@ weston_wm_window_handle_moveresize(struct weston_wm_window *window, case _NET_WM_MOVERESIZE_SIZE_BOTTOM: case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT: case _NET_WM_MOVERESIZE_SIZE_LEFT: + window->resizing = 1; xwayland_interface->resize(window->shsurf, pointer, map[detail]); break; case _NET_WM_MOVERESIZE_CANCEL: + window->resizing = 0; break; } } @@ -2110,6 +2118,10 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) WL_POINTER_BUTTON_STATE_RELEASED; button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT; + if (window->resizing && button_id == BTN_LEFT && + button_state == WL_POINTER_BUTTON_STATE_PRESSED) + window->resizing = 0; + if (button_state == WL_POINTER_BUTTON_STATE_PRESSED) { if (button->time - window->last_button_time <= DOUBLE_CLICK_PERIOD) { double_click = 1; @@ -2147,8 +2159,10 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) } if (frame_status(window->frame) & FRAME_STATUS_RESIZE) { - if (pointer && weston_wm_window_is_resizable(window)) + if (pointer && weston_wm_window_is_resizable(window)) { + window->resizing = 1; xwayland_interface->resize(window->shsurf, pointer, location); + } frame_status_clear(window->frame, FRAME_STATUS_RESIZE); } -- 2.12.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston 1/8] xwm: Implement _NET_WM_SYNC_REQUEST protocol
Implement NET_WM_SYNC_REQUEST protocol for throtting X11 window resizes in Weston's XWM. We wait for the window to be drawn (by setting an alarm on the sync counter) before configuring the window again. Signed-off-by: Louis-Francis Ratté-Boulianne --- configure.ac | 2 +- xwayland/window-manager.c | 220 +++--- xwayland/xwayland.h | 5 ++ 3 files changed, 214 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 6cc9f26e..eebeba9d 100644 --- a/configure.ac +++ b/configure.ac @@ -165,7 +165,7 @@ AC_ARG_ENABLE(xwayland-test, [ --enable-xwayland-test],, AM_CONDITIONAL(ENABLE_XWAYLAND, test x$enable_xwayland = xyes) AM_CONDITIONAL(ENABLE_XWAYLAND_TEST, test x$enable_xwayland = xyes -a x$enable_xwayland_test = xyes) if test x$enable_xwayland = xyes; then - PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcb-composite xcursor cairo-xcb) + PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcb-composite xcb-sync xcursor cairo-xcb) AC_DEFINE([BUILD_XWAYLAND], [1], [Build the X server launcher]) AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH], diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 26080759..a067f741 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -43,6 +43,7 @@ #include "compositor.h" #include "xwayland.h" #include "xwayland-internal-interface.h" +#include "wayland-server-core.h" #include "cairo-util.h" #include "hash.h" @@ -136,6 +137,8 @@ struct weston_wm_window { struct weston_wm *wm; xcb_window_t id; xcb_window_t frame_id; + xcb_sync_alarm_t sync_request_alarm; + xcb_sync_counter_t sync_request_counter; struct frame *frame; cairo_surface_t *cairo_surface; uint32_t surface_id; @@ -144,6 +147,7 @@ struct weston_wm_window { struct wl_listener surface_destroy_listener; struct wl_event_source *repaint_source; struct wl_event_source *configure_source; + struct wl_event_source *sync_request_timer; int properties_dirty; int pid; char *machine; @@ -167,6 +171,10 @@ struct weston_wm_window { int delete_window; int maximized_vert; int maximized_horz; + int64_t sync_request_serial; + int configure_pending; + int sync_disabled; + int wait_redraw; struct wm_size_hints size_hints; struct motif_wm_hints motif_hints; struct wl_list link; @@ -179,6 +187,9 @@ static void weston_wm_set_net_active_window(struct weston_wm *wm, xcb_window_t window); static void +weston_wm_window_configure(void *data); + +static void weston_wm_window_schedule_repaint(struct weston_wm_window *window); static int @@ -472,6 +483,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) }, { wm->atom.net_wm_name,XCB_ATOM_STRING, F(name) }, { wm->atom.net_wm_pid, XCB_ATOM_CARDINAL, F(pid) }, + { wm->atom.net_wm_sync_request_counter,XCB_SYNC_COUNTER, F(sync_request_counter) }, { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS,NULL }, { wm->atom.wm_client_machine, XCB_ATOM_WM_CLIENT_MACHINE, F(machine) }, }; @@ -482,6 +494,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) void *p; uint32_t *xid; xcb_atom_t *atom; + xcb_sync_counter_t *counter; uint32_t i; char name[1024]; @@ -537,6 +550,10 @@ weston_wm_window_read_properties(struct weston_wm_window *window) atom = xcb_get_property_value(reply); *(xcb_atom_t *) p = *atom; break; + case XCB_SYNC_COUNTER: + counter = xcb_get_property_value(reply); + *(xcb_sync_counter_t *) p = *counter; + break; case TYPE_WM_PROTOCOLS: atom = xcb_get_property_value(reply); for (i = 0; i < reply->value_len; i++) @@ -674,11 +691,6 @@ weston_wm_handle_configure_request(struct weston_wm *wm, xcb_generic_event_t *ev uint32_t mask, values[16]; int x, y, width, height, i = 0; - wm_log("XCB_CONFIGURE_REQUEST (window %d) %d,%d @ %dx%d\n", - configure_request->window, - configure_request->x, configure_request->y, - configure_request->width, configure_request->height); - if (!wm_lookup_window(wm, configure_request->window, &window)) return; @@ -1036,6 +1048,91 @@ weston_wm_window_set_virtual_desktop(struct weston_wm_window *window, } stat
[weston 3/8] xwm: Don't resize windows if the application have these hints
If the minimum and maximum size hints are equal, that means the application doesn't want the window manager to allow resizing. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 26 -- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 02a7c252..b78175b3 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -964,6 +964,15 @@ weston_wm_window_set_net_wm_state(struct weston_wm_window *window) i, property); } +static inline bool +weston_wm_window_is_resizable(struct weston_wm_window *window) +{ + return (window->size_hints.min_width <= 0 || + window->size_hints.min_height <= 0 || + window->size_hints.min_width != window->size_hints.max_width || + window->size_hints.min_height != window->size_hints.max_height); +} + static void weston_wm_window_create_frame(struct weston_wm_window *window) { @@ -972,7 +981,8 @@ weston_wm_window_create_frame(struct weston_wm_window *window) int x, y, width, height; int buttons = FRAME_BUTTON_CLOSE; - if (window->decorate & MWM_DECOR_MAXIMIZE) + if (window->decorate & MWM_DECOR_MAXIMIZE && + weston_wm_window_is_resizable(window)) buttons |= FRAME_BUTTON_MAXIMIZE; window->frame = frame_create(window->wm->theme, @@ -2137,7 +2147,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) } if (frame_status(window->frame) & FRAME_STATUS_RESIZE) { - if (pointer) + if (pointer && weston_wm_window_is_resizable(window)) xwayland_interface->resize(window->shsurf, pointer, location); frame_status_clear(window->frame, FRAME_STATUS_RESIZE); } @@ -2178,8 +2188,10 @@ weston_wm_handle_motion(struct weston_wm *wm, xcb_generic_event_t *event) if (frame_status(window->frame) & FRAME_STATUS_REPAINT) weston_wm_window_schedule_repaint(window); - cursor = get_cursor_for_location(location); - weston_wm_window_set_cursor(wm, window->frame_id, cursor); + if (weston_wm_window_is_resizable(window)) { + cursor = get_cursor_for_location(location); + weston_wm_window_set_cursor(wm, window->frame_id, cursor); + } } static void @@ -2199,8 +2211,10 @@ weston_wm_handle_enter(struct weston_wm *wm, xcb_generic_event_t *event) if (frame_status(window->frame) & FRAME_STATUS_REPAINT) weston_wm_window_schedule_repaint(window); - cursor = get_cursor_for_location(location); - weston_wm_window_set_cursor(wm, window->frame_id, cursor); + if (weston_wm_window_is_resizable(window)) { + cursor = get_cursor_for_location(location); + weston_wm_window_set_cursor(wm, window->frame_id, cursor); + } } static void -- 2.12.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston 4/8] xwm: Only send configure a window if the new size is different
If we configure a window with the same size and wait for the sync alarm to go off, the resizing is gonna block. The event is only handled is the size actually changed. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 15 +++ 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index b78175b3..8048594e 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -2778,6 +2778,7 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height) struct weston_wm_window *window = get_wm_window(surface); struct weston_wm *wm = window->wm; struct theme *t = window->wm->theme; + int new_width, new_height; int vborder, hborder; if (window->decorate && !window->fullscreen) { @@ -2789,14 +2790,20 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height) } if (width > hborder) - window->width = width - hborder; + new_width = width - hborder; else - window->width = 1; + new_width = 1; if (height > vborder) - window->height = height - vborder; + new_height = height - vborder; else - window->height = 1; + new_height = 1; + + if (window->width == new_width && window->height == new_height) + return; + + window->width = new_width; + window->height = new_height; if (window->frame) frame_resize_inside(window->frame, window->width, window->height); -- 2.12.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston 5/8] xwm: Make sure we respect the window's size hints
Don't just ignore the minimal and maximal sizes requested by the application. Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 14 ++ 1 file changed, 14 insertions(+) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 8048594e..bea3cc68 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -2799,6 +2799,20 @@ send_configure(struct weston_surface *surface, int32_t width, int32_t height) else new_height = 1; + /* Make sure we respect the window's size hints */ + if (window->size_hints.min_width > 0 && + new_width < window->size_hints.min_width) + new_width = window->size_hints.min_width; + if (window->size_hints.min_height > 0 && + new_height < window->size_hints.min_height) + new_height = window->size_hints.min_height; + if (window->size_hints.max_width > 0 && + new_width > window->size_hints.max_width) + new_width = window->size_hints.max_width; + if (window->size_hints.max_height > 0 && + new_height > window->size_hints.max_height) + new_height = window->size_hints.max_height; + if (window->width == new_width && window->height == new_height) return; -- 2.12.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston 0/8] Implement NET_WM_SYNC_REQUEST basic support
Implement NET_WM_SYNC_REQUEST protocol for throtting X11 window resizes in Weston's XWM. We wait for the window to be drawn (by setting an alarm on the sync counter) before configuring the window again. I also did some small fixes the Xwayland window manager as to better respect size hints from X11 applications and to display the title more elegantly when there isn't enough space available. Louis-Francis Ratté-Boulianne (8): xwm: Implement _NET_WM_SYNC_REQUEST protocol xwm: Maximize windows when double-clicking on title bar xwm: Don't resize windows if the application have these xwm: Only send configure a window if the new size is xwm: Make sure we respect the window's size hints xwm: Ignore configure request while the user is resizing xwm: Deal with title in a smarter way when there isn't xwm: Use Pango to draw title string if available ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[weston 2/8] xwm: Maximize windows when double-clicking on title bar
Signed-off-by: Louis-Francis Ratté-Boulianne --- xwayland/window-manager.c | 26 -- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index a067f741..02a7c252 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -165,6 +165,8 @@ struct weston_wm_window { struct weston_output_weak_ref legacy_fullscreen_output; int saved_width, saved_height; int decorate; + uint32_t last_button_time; + int did_double; int override_redirect; int fullscreen; int has_alpha; @@ -2064,6 +2066,7 @@ weston_wm_window_close(struct weston_wm_window *window, xcb_timestamp_t time) } } +#define DOUBLE_CLICK_PERIOD 250 static void weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) { @@ -2076,6 +2079,7 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) enum theme_location location; enum wl_pointer_button_state button_state; uint32_t button_id; + uint32_t double_click = 0; wm_log("XCB_BUTTON_%s (detail %d)\n", button->response_type == XCB_BUTTON_PRESS ? @@ -2096,6 +2100,19 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) WL_POINTER_BUTTON_STATE_RELEASED; button_id = button->detail == 1 ? BTN_LEFT : BTN_RIGHT; + if (button_state == WL_POINTER_BUTTON_STATE_PRESSED) { + if (button->time - window->last_button_time <= DOUBLE_CLICK_PERIOD) { + double_click = 1; + window->did_double = 1; + } else + window->did_double = 0; + + window->last_button_time = button->time; + } else if (window->did_double == 1) { + double_click = 1; + window->did_double = 0; + } + /* Make sure we're looking at the right location. The frame * could have received a motion event from a pointer from a * different wl_seat, but under X it looks like our core @@ -2103,8 +2120,13 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) * location before deciding what to do. */ location = frame_pointer_motion(window->frame, NULL, button->event_x, button->event_y); - location = frame_pointer_button(window->frame, NULL, - button_id, button_state); + if (double_click) + location = frame_double_click(window->frame, NULL, + button_id, button_state); + else + location = frame_pointer_button(window->frame, NULL, + button_id, button_state); + if (frame_status(window->frame) & FRAME_STATUS_REPAINT) weston_wm_window_schedule_repaint(window); -- 2.12.2 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [weston, v3, 3/3] libweston-desktop/xwayland: react to geometry changes
On Wed, 2017-01-18 at 15:37 +0200, Pekka Paalanen wrote: > From: Pekka Paalanen > > Fix up the window position whenever the geometry info changes. > > If the window geometry changes, we want to keep the input-responding > content anchored to top-left. It is done by manipulating the dx,dy > arguments originating from a wl_surface.attach request. > > Signed-off-by: Pekka Paalanen Reviewed-by: Louis-Francis Ratté-Boulianne > --- > libweston-desktop/xwayland.c | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/libweston-desktop/xwayland.c b/libweston- > desktop/xwayland.c > index b984385..4f4b453 100644 > --- a/libweston-desktop/xwayland.c > +++ b/libweston-desktop/xwayland.c > @@ -131,12 +131,19 @@ > weston_desktop_xwayland_surface_committed(struct > weston_desktop_surface *dsurfac > int32_t sx, int32_t sy) > { > struct weston_desktop_xwayland_surface *surface = user_data; > + struct weston_geometry oldgeom; > + > + assert(dsurface == surface->surface); > > #ifdef WM_DEBUG > weston_log("%s: xwayland surface %p\n", __func__, surface); > #endif > > if (surface->has_next_geometry) { > + oldgeom = > weston_desktop_surface_get_geometry(surface->surface); > + sx -= surface->next_geometry.x - oldgeom.x; > + sy -= surface->next_geometry.y - oldgeom.x; > + > surface->has_next_geometry = false; > weston_desktop_surface_set_geometry(surface- > >surface, > surface- > >next_geometry); ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [weston,v3,2/3] xwm: use _XWAYLAND_ALLOW_COMMITS
On Wed, 2017-01-18 at 15:37 +0200, Pekka Paalanen wrote: > From: Pekka Paalanen > > This patch uses the new feature proposed for Xwayland in the patch > series https://patchwork.freedesktop.org/series/16610/ . > > When the frame window is created, immediately forbid Xwayland commits > on > it. This prevents commits before the decorations have been drawn and > the > initial pending state has been set. Commits are enabled right after > drawing and setting. > > This ensures that the decorations are fully drawn when a window is > mapped. This also solves the initial commit/pending race, but the > race > is on again after mapping. > > If Xwayland does not implement the needed support, we are just > setting a > window property with no effect. > > This patch is the final piece for solving T7622, excluding the > _NET_WM_SYNC_REQUEST handling. > > Task: https://phabricator.freedesktop.org/T7622 > Signed-off-by: Pekka Paalanen It seems to fix the race just fine. Reviewed-by: Louis-Francis Ratté-Boulianne > --- > xwayland/window-manager.c | 40 > ++-- > xwayland/xwayland.h | 1 + > 2 files changed, 39 insertions(+), 2 deletions(-) > > diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c > index ac875a3..2608075 100644 > --- a/xwayland/window-manager.c > +++ b/xwayland/window-manager.c > @@ -873,6 +873,37 @@ weston_wm_window_activate(struct wl_listener > *listener, void *data) > > } > > +/** Control Xwayland wl_surface.commit behaviour > + * > + * This function sets the "_XWAYLAND_ALLOW_COMMITS" property of the > frame window > + * (not the content window!) to \p allow. > + * > + * If the property is set to \c true, Xwayland will commit whenever > it likes. > + * If the property is set to \c false, Xwayland will not commit. > + * If the property is not set at all, Xwayland assumes it is \c > true. > + * > + * \param window The XWM window to control. > + * \param allow Whether Xwayland is allowed to wl_surface.commit for > the window. > + */ > +static void > +weston_wm_window_set_allow_commits(struct weston_wm_window *window, > bool allow) > +{ > + struct weston_wm *wm = window->wm; > + uint32_t property[1]; > + > + assert(window->frame_id != XCB_WINDOW_NONE); > + > + property[0] = allow ? 1 : 0; > + > + xcb_change_property(wm->conn, > + XCB_PROP_MODE_REPLACE, > + window->frame_id, > + wm->atom.allow_commits, > + XCB_ATOM_CARDINAL, > + 32, /* format */ > + 1, property); > +} > + > #define ICCCM_WITHDRAWN_STATE0 > #define ICCCM_NORMAL_STATE 1 > #define ICCCM_ICONIC_STATE 3 > @@ -1048,6 +1079,7 @@ weston_wm_handle_map_request(struct weston_wm > *wm, xcb_generic_event_t *event) > window->width, window->height, > window->map_request_x, window->map_request_y); > > + weston_wm_window_set_allow_commits(window, false); > weston_wm_window_set_wm_state(window, ICCCM_NORMAL_STATE); > weston_wm_window_set_net_wm_state(window); > weston_wm_window_set_virtual_desktop(window, 0); > @@ -2220,6 +2252,7 @@ weston_wm_get_resources(struct weston_wm *wm) > { "XdndFinished", F(atom.xdnd_finished) }, > { "XdndTypeList", F(atom.xdnd_type_list) }, > { "XdndActionCopy", F(atom.xdnd_action_copy) > }, > + { "_XWAYLAND_ALLOW_COMMITS",F(atom.allow_com > mits) }, > { "WL_SURFACE_ID", F(atom.wl_surface_id) } > }; > #undef F > @@ -2741,10 +2774,13 @@ xserver_map_shell_surface(struct > weston_wm_window *window, > } > } > > - if (window->frame_id == XCB_WINDOW_NONE) > + if (window->frame_id == XCB_WINDOW_NONE) { > weston_wm_window_set_pending_state_OR(window); > - else > + } else { > weston_wm_window_set_pending_state(window); > + weston_wm_window_set_allow_commits(window, true); > + xcb_flush(wm->conn); > + } > } > > const struct weston_xwayland_surface_api surface_api = { > diff --git a/xwayland/xwayland.h b/xwayland/xwayland.h > index b1225f5..ca75f5b 100644 > --- a/xwayland/xwayland.h > +++ b/xwayland/xwayland.h > @@ -154,6 +154,7 @@ struct weston_wm { > xcb_atom_t xdnd_type_list; > xcb_atom_t xdnd_action_copy; > xcb_atom_t wl_surface_id; > + xcb_atom_t allow_commits; > } atom; > }; > ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [weston,v3,1/3] xwm: do not draw decor twice on map
On Wed, 2017-01-18 at 15:37 +0200, Pekka Paalanen wrote: > From: Pekka Paalanen > > Normal windows enter the MapRequest handler, which schedules drawing > the > decorations. Then Xwayland realizes the window, which ends with a > call > to xserver_map_shell_surface(). The decorations are already drawn, no > need to draw them a second time. However, MapRequest handler could > not > set the pending state because the weston_surface did not exist at the > time, because it gets created only when Xwayland realizes the window, > which happens after XWM has forwarded the MapWindow in MapRequest > handler. Therefore set the pending state explicitly at the end. > Scheduling had it done much later anyway. > > Now that the pending state is set much earlier, it seems to be more > likely that it gets set before Xwayland's first commit is handled. > This > means that -geometry command line option of X11 apps already takes > the > geometry (decorations) into account. I do not think it is reliable > yet, > though. > > There is still the race between Xwayland committing and XWM setting > the > pending state assuming the very next commit latches it in > appropriately. > The race exists not because of Wayland, but because WL_SURFACE_ID > comes > via X11, and could be processed after wl_compositor.create_surface > and > wl_surface.commit. That commit/pending race is solved by a following > patch. > > For override-redirect windows weston_wm_window_schedule_repaint() > reduced into a call to weston_wm_window_set_pending_state_OR(), so we > can just call that directly. It should not matter that the call is > moved > to the end of the function. > > Signed-off-by: Pekka Paalanen Reviewed-by: Louis-Francis Ratté-Boulianne > --- > xwayland/window-manager.c | 7 +-- > 1 file changed, 5 insertions(+), 2 deletions(-) > > diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c > index d40d56e..ac875a3 100644 > --- a/xwayland/window-manager.c > +++ b/xwayland/window-manager.c > @@ -2681,8 +2681,6 @@ xserver_map_shell_surface(struct > weston_wm_window *window, > wl_signal_add(&window->surface->destroy_signal, > &window->surface_destroy_listener); > > - weston_wm_window_schedule_repaint(window); > - > if (!xwayland_interface) > return; > > @@ -2742,6 +2740,11 @@ xserver_map_shell_surface(struct > weston_wm_window *window, > xwayland_interface->set_toplevel(window- > >shsurf); > } > } > + > + if (window->frame_id == XCB_WINDOW_NONE) > + weston_wm_window_set_pending_state_OR(window); > + else > + weston_wm_window_set_pending_state(window); > } > > const struct weston_xwayland_surface_api surface_api = { ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 7/7] clients: add simple-dmabuf client
From: George Kiagiadakis Signed-off-by: George Kiagiadakis Signed-off-by: Louis-Francis Ratté-Boulianne --- .gitignore | 1 + Makefile.am | 15 ++ clients/simple-dmabuf.c | 578 configure.ac| 9 + 4 files changed, 603 insertions(+) create mode 100644 clients/simple-dmabuf.c diff --git a/.gitignore b/.gitignore index 2aaeac9..9dbfb9f 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ weston-nested-client weston-presentation-shm weston-resizor weston-scaler +weston-simple-dmabuf weston-simple-egl weston-simple-shm weston-simple-touch diff --git a/Makefile.am b/Makefile.am index 16f5d13..06f6ec6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -453,6 +453,21 @@ weston_simple_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_CLIENT_CFLAGS) weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm endif +if BUILD_SIMPLE_INTEL_DMABUF_CLIENT +demo_clients += weston-simple-dmabuf +weston_simple_dmabuf_SOURCES = clients/simple-dmabuf.c +nodist_weston_simple_dmabuf_SOURCES = \ + protocol/xdg-shell-protocol.c \ + protocol/xdg-shell-client-protocol.h\ + protocol/fullscreen-shell-protocol.c\ + protocol/fullscreen-shell-client-protocol.h \ + protocol/linux-dmabuf-protocol.c \ + protocol/linux-dmabuf-client-protocol.h +weston_simple_dmabuf_CFLAGS = $(AM_CFLAGS) $(SIMPLE_DMABUF_CLIENT_CFLAGS) +weston_simple_dmabuf_LDADD = $(SIMPLE_DMABUF_CLIENT_LIBS) libshared.la +BUILT_SOURCES += protocol/linux-dmabuf-client-protocol.h +endif + noinst_LTLIBRARIES += libtoytoolkit.la libtoytoolkit_la_SOURCES = \ diff --git a/clients/simple-dmabuf.c b/clients/simple-dmabuf.c new file mode 100644 index 000..4635d47 --- /dev/null +++ b/clients/simple-dmabuf.c @@ -0,0 +1,578 @@ +/* + * Copyright © 2011 Benjamin Franzke + * Copyright © 2010 Intel Corporation + * Copyright © 2014 Collabora Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "xdg-shell-client-protocol.h" +#include "fullscreen-shell-client-protocol.h" +#include "linux-dmabuf-client-protocol.h" + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct xdg_shell *shell; + struct _wl_fullscreen_shell *fshell; + struct zlinux_dmabuf *dmabuf; + int xrgb_format_found; +}; + +struct buffer { + struct wl_buffer *buffer; + struct zlinux_dmabuf_create_feedback *feedback; + int busy; + + int drm_fd; + + drm_intel_bufmgr *bufmgr; + drm_intel_bo *bo; + + uint32_t gem_handle; + int dmabuf_fd; + uint8_t *mmap; + + int width; + int height; + int bpp; + unsigned long stride; +}; + +struct window { + struct display *display; + int width, height; + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct buffer buffers[2]; + struct buffer *prev_buffer; + struct wl_callback *callback; +}; + +static int running = 1; + +static void +buffer_release(void *data, struct wl_buffer *buffer) +{ + struct buffer *mybuf = data; + + mybuf->busy = 0; +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +static int +drm_connect(struct buffer *my_buf) +{ + /* This won't work with card0 as we need to be authenticated; instead, +* boot with drm.rnodes=1 and use that. */ + my_buf->drm_fd = open("/dev/dri/renderD128", O_RDWR); + if (my_buf-&g
[PATCH 4/7] compositor-x11: init linux_dmabuf support
From: Pekka Paalanen --- src/compositor-x11.c | 5 + 1 file changed, 5 insertions(+) diff --git a/src/compositor-x11.c b/src/compositor-x11.c index a760f33..7b15ba9 100644 --- a/src/compositor-x11.c +++ b/src/compositor-x11.c @@ -51,6 +51,7 @@ #include "pixman-renderer.h" #include "../shared/config-parser.h" #include "../shared/image-loader.h" +#include "linux-dmabuf.h" #define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10) @@ -1587,6 +1588,10 @@ x11_compositor_create(struct wl_display *display, x11_compositor_handle_event, c); wl_event_source_check(c->xcb_source); + /* XXX: check that dmabuf import is available in renderer */ + if (linux_dmabuf_setup(&c->base) < 0) + weston_log("Error: initializing dmabuf support failed.\n"); + return &c->base; err_x11_input: -- 2.1.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/7] protocol: add linux_dmabuf extension RFCv1
From: Pekka Paalanen An experimental (hence the 'z' prefix) linux_dmabuf Wayland protocol extension for creating dmabuf-based wl_buffers in a generic manner. This does not include proper dmabuf metadata negotiation because there is no way to communicate all dmabuf constraints from the compositor to a client before-hand. The client has to create a wl_buffer wrapping one or more dmabuf buffers and then listen at the feedback object returned to know if the operation was successful. Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne --- Makefile.am | 7 +- protocol/linux-dmabuf.xml | 224 ++ 2 files changed, 229 insertions(+), 2 deletions(-) create mode 100644 protocol/linux-dmabuf.xml diff --git a/Makefile.am b/Makefile.am index 494266d..0462fdd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -91,7 +91,9 @@ nodist_weston_SOURCES = \ protocol/presentation_timing-protocol.c \ protocol/presentation_timing-server-protocol.h \ protocol/scaler-protocol.c \ - protocol/scaler-server-protocol.h + protocol/scaler-server-protocol.h \ + protocol/linux-dmabuf-protocol.c\ + protocol/linux-dmabuf-server-protocol.h BUILT_SOURCES += $(nodist_weston_SOURCES) @@ -1101,7 +1103,8 @@ EXTRA_DIST += \ protocol/presentation_timing.xml\ protocol/scaler.xml \ protocol/ivi-application.xml\ - protocol/ivi-hmi-controller.xml + protocol/ivi-hmi-controller.xml \ + protocol/linux-dmabuf.xml man_MANS = weston.1 weston.ini.5 diff --git a/protocol/linux-dmabuf.xml b/protocol/linux-dmabuf.xml new file mode 100644 index 000..c48121c --- /dev/null +++ b/protocol/linux-dmabuf.xml @@ -0,0 +1,224 @@ + + + + +Copyright © 2014 Collabora, Ltd. + +Permission to use, copy, modify, distribute, and sell this +software and its documentation for any purpose is hereby granted +without fee, provided that the above copyright notice appear in +all copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the name of +the copyright holders not be used in advertising or publicity +pertaining to distribution of the software without specific, +written prior permission. The copyright holders make no +representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied +warranty. + +THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN +AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + + + + + Following the interfaces from: + https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt + + This interface offers a way to create generic dmabuf-based + wl_buffers. Immediately after a client binds to this interface, + the set of supported formats is sent with 'format' events. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +This temporary object is used to collect multiple dmabuf handles +into a single batch. + + + + + + +The result of the operation will be returned via the provided +zlinux_dmabuf_create_feedback object. + +The dmabuf_batch object must be destroyed immediately after +after this request. + +Any errors in importing the set of dmabufs can be delivered as +protocol errors immediately or later. + + + + + + + + + + +This event advertises one buffer format that the server support. +All the supported formats advertised once when the client +binds to this interface. A roundtrip after binding guarantees, +that the client has
[PATCH 5/7] compositor-drm: init linux_dmabuf support
From: Pekka Paalanen --- src/compositor-drm.c | 5 + 1 file changed, 5 insertions(+) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 9b4d4dc..44fc912 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -50,6 +50,7 @@ #include "libinput-seat.h" #include "launcher-util.h" #include "vaapi-recorder.h" +#include "linux-dmabuf.h" #ifndef DRM_CAP_TIMESTAMP_MONOTONIC #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 @@ -2881,6 +2882,10 @@ drm_compositor_create(struct wl_display *display, weston_compositor_add_debug_binding(&ec->base, KEY_W, renderer_switch_binding, ec); + /* XXX: check that dmabuf import is available in renderer */ + if (linux_dmabuf_setup(&ec->base) < 0) + weston_log("Error: initializing dmabuf support failed.\n"); + return &ec->base; err_udev_monitor: -- 2.1.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/7] Generic dmabuf protocol RFCv1
This serie of patches by Pekka and George contains an experimental implementation of "zlinux_dmabuf" protocol. See these links for more information about the design and failed previous attempts: http://lists.freedesktop.org/archives/wayland-devel/2014-June/015362.html https://bugs.freedesktop.org/show_bug.cgi?id=83881 This protocol allows clients to wrap a dmabuf into a wl_buffer, and push that into the compositor for display. The compositor then uses GBM to import that wl_buffer as a bo for compositing with GL (via EGLImage) or direct scanout as a DRM FB object. Note that a round-trip is needed when creating the buffer because there is no way to communicate all dmabuf constraints from the compositor to a client before-hand. They are simply too complicated and changing to be described in a Wayland protocol extension. In fact, there are existing APIs like EGL (the dmabuf import extension) that are based on trial-and-error rather than knowing the constraints before-hand. However, the protocol design is far far away from complete. Even the kernel developers are still discussing, how cross-device support for dmabufs should work, and what is the proper information split between the kernel and the user space. How do you communicate, or even describe, things like tiling formats. But, we should start from somewhere, and this patch is pushing the user space part forward a bit. The extension is especially useful for video players and this pipeline has been demonstrated to work with GStreamer: http://cgit.collabora.com/git/user/gkiagia/gst-plugins-bad.git/commit/?h=inteldmabufupload&id=727732c6de87949278cd53436ba2c430956cd8f9 George Kiagiadakis (1): clients: add simple-dmabuf client Pekka Paalanen (6): protocol: add linux_dmabuf extension RFCv1 dmabuf: implement linux_dmabuf extension gl-renderer: add dmabuf import compositor-x11: init linux_dmabuf support compositor-drm: init linux_dmabuf support compositor-drm: dmabuf GBM import .gitignore| 1 + Makefile.am | 24 +- clients/simple-dmabuf.c | 578 ++ configure.ac | 9 + protocol/linux-dmabuf.xml | 224 ++ src/compositor-drm.c | 31 ++- src/compositor-x11.c | 5 + src/gl-renderer.c | 103 + src/linux-dmabuf.c| 322 ++ src/linux-dmabuf.h| 45 10 files changed, 1336 insertions(+), 6 deletions(-) create mode 100644 clients/simple-dmabuf.c create mode 100644 protocol/linux-dmabuf.xml create mode 100644 src/linux-dmabuf.c create mode 100644 src/linux-dmabuf.h -- 2.1.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 6/7] compositor-drm: dmabuf GBM import
From: Pekka Paalanen --- src/compositor-drm.c | 26 ++ 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 44fc912..d3e8b34 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -839,7 +839,9 @@ drm_output_prepare_overlay_view(struct weston_output *output_base, struct weston_compositor *ec = output_base->compositor; struct drm_compositor *c =(struct drm_compositor *) ec; struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport; + struct wl_resource *buffer_resource; struct drm_sprite *s; + struct linux_dmabuf_buffer *dmabuf; int found = 0; struct gbm_bo *bo; pixman_region32_t dest_rect, src_rect; @@ -864,11 +866,12 @@ drm_output_prepare_overlay_view(struct weston_output *output_base, if (ev->surface->buffer_ref.buffer == NULL) return NULL; + buffer_resource = ev->surface->buffer_ref.buffer->resource; if (ev->alpha != 1.0f) return NULL; - if (wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource)) + if (wl_shm_buffer_get(buffer_resource)) return NULL; if (!drm_view_transform_supported(ev)) @@ -888,9 +891,24 @@ drm_output_prepare_overlay_view(struct weston_output *output_base, if (!found) return NULL; - bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER, - ev->surface->buffer_ref.buffer->resource, - GBM_BO_USE_SCANOUT); + if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) { + struct gbm_import_fd_data gbm_dmabuf = { + .fd = dmabuf->dmabuf_fd[0], + .width = dmabuf->width, + .height = dmabuf->height, + .stride = dmabuf->stride[0], + .format = dmabuf->format + }; + + if (dmabuf->n_planes != 1 || dmabuf->offset[0] != 0) + return NULL; + + bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf, + GBM_BO_USE_SCANOUT); + } else { + bo = gbm_bo_import(c->gbm, GBM_BO_IMPORT_WL_BUFFER, + buffer_resource, GBM_BO_USE_SCANOUT); + } if (!bo) return NULL; -- 2.1.0 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 3/7] gl-renderer: add dmabuf import
From: Pekka Paalanen Squashed with: gl-renderer: error if dmabuf exposed unsupported gl_renderer: always use GL_TEXTURE_EXTERNAL_OES with dmabuf --- src/gl-renderer.c | 103 ++ 1 file changed, 103 insertions(+) diff --git a/src/gl-renderer.c b/src/gl-renderer.c index bb46acd..bb4e409 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -35,6 +35,8 @@ #include "gl-renderer.h" #include "vertex-clipping.h" +#include "linux-dmabuf.h" +#include "linux-dmabuf-server-protocol.h" #include #include "weston-egl-ext.h" @@ -149,6 +151,8 @@ struct gl_renderer { int has_configless_context; + int has_dmabuf_import; + struct gl_shader texture_shader_rgba; struct gl_shader texture_shader_rgbx; struct gl_shader texture_shader_egl_external; @@ -1305,12 +1309,104 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer, } static void +gl_renderer_attach_dmabuf(struct weston_surface *surface, + struct weston_buffer *buffer, + struct linux_dmabuf_buffer *dmabuf) +{ +#ifdef EGL_EXT_image_dma_buf_import + struct gl_renderer *gr = get_renderer(surface->compositor); + struct gl_surface_state *gs = get_surface_state(surface); + EGLint attribs[30]; + int atti = 0; + int i; + + assert(gr->has_dmabuf_import); + + buffer->width = dmabuf->width; + buffer->height = dmabuf->height; + buffer->y_inverted = 1; /* XXX: readlly? */ + + attribs[atti++] = EGL_WIDTH; + attribs[atti++] = dmabuf->width; + attribs[atti++] = EGL_HEIGHT; + attribs[atti++] = dmabuf->height; + attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT; + attribs[atti++] = dmabuf->format; + + if (dmabuf->n_planes > 0) { + attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT; + attribs[atti++] = dmabuf->dmabuf_fd[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; + attribs[atti++] = dmabuf->offset[0]; + attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; + attribs[atti++] = dmabuf->stride[0]; + } + + if (dmabuf->n_planes > 1) { + attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT; + attribs[atti++] = dmabuf->dmabuf_fd[1]; + attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT; + attribs[atti++] = dmabuf->offset[1]; + attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT; + attribs[atti++] = dmabuf->stride[1]; + } + + if (dmabuf->n_planes > 2) { + attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT; + attribs[atti++] = dmabuf->dmabuf_fd[2]; + attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT; + attribs[atti++] = dmabuf->offset[2]; + attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT; + attribs[atti++] = dmabuf->stride[2]; + } + + attribs[atti++] = EGL_NONE; + + for (i = 0; i < gs->num_images; i++) + gr->destroy_image(gr->egl_display, gs->images[i]); + gs->num_images = 0; + gs->target = GL_TEXTURE_EXTERNAL_OES; + gs->shader = &gr->texture_shader_egl_external; + + ensure_textures(gs, 1); + + gs->images[0] = gr->create_image(gr->egl_display, EGL_NO_CONTEXT, +EGL_LINUX_DMA_BUF_EXT, NULL, +attribs); + if (!gs->images[0]) { + /* XXX: wrong resource for error code */ + wl_resource_post_error(dmabuf->resource, + ZLINUX_DMABUF_ERROR_INVALID_DMABUF, + "dmabuf import to EGL failed"); + return; + } + gs->num_images = 1; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(gs->target, gs->textures[0]); + gr->image_target_texture_2d(gs->target, gs->images[0]); + + gs->pitch = buffer->width; + gs->height = buffer->height; + gs->buffer_type = BUFFER_TYPE_EGL; + gs->y_inverted = buffer->y_inverted; + +#else + /* XXX: wrong resource for error code */ + wl_resource_post_error(dmabuf->resource, + ZLINUX_DMABUF_ERROR_INVALID_DMABUF, + "implementation error: EGL dmabuf import"); +#endif /* EGL_EXT_image_dma_buf_import */ +} + +static void gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { struct weston_compositor *ec = es->compositor; struct gl_renderer *gr = get_renderer(ec); struct gl_surface_state *gs = get_surface_state(es); struct wl_shm_buffer *shm_buffer; + struct linux_dmabuf_buffer *dmabuf; EGLint format; int i; @@ -1336,6 +1432,8 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) else if (gr-
[PATCH 2/7] dmabuf: implement linux_dmabuf extension
From: Pekka Paalanen Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne --- Makefile.am| 2 + src/linux-dmabuf.c | 322 + src/linux-dmabuf.h | 45 3 files changed, 369 insertions(+) create mode 100644 src/linux-dmabuf.c create mode 100644 src/linux-dmabuf.h diff --git a/Makefile.am b/Makefile.am index 0462fdd..16f5d13 100644 --- a/Makefile.am +++ b/Makefile.am @@ -72,6 +72,8 @@ weston_SOURCES = \ src/timeline.c \ src/timeline.h \ src/timeline-object.h \ + src/linux-dmabuf.c \ + src/linux-dmabuf.h \ shared/matrix.c \ shared/matrix.h \ shared/zalloc.h \ diff --git a/src/linux-dmabuf.c b/src/linux-dmabuf.c new file mode 100644 index 000..769bf60 --- /dev/null +++ b/src/linux-dmabuf.c @@ -0,0 +1,322 @@ +/* + * Copyright © 2014 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include + +#include "compositor.h" +#include "linux-dmabuf.h" +#include "linux-dmabuf-server-protocol.h" + +struct dmabuf_item { + int fd; + int n_planes; + int32_t offset[3]; + int32_t stride[3]; +}; + +struct dmabuf_batch { + struct wl_resource *resource; + int n_bufs; + struct wl_array bufs; /* struct dmabuf_item */ +}; + +static void +destroy_dmabuf_batch(struct wl_resource *dmabuf_batch_resource) +{ + struct dmabuf_batch *batch; + struct dmabuf_item *buf; + + batch = wl_resource_get_user_data(dmabuf_batch_resource); + + wl_array_for_each(buf, &batch->bufs) + close(buf->fd); + wl_array_release(&batch->bufs); + + free(batch); +} + +static void +dmabuf_batch_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +dmabuf_batch_add(struct wl_client *client, +struct wl_resource *resource, +int32_t name, +int32_t offset0, +int32_t stride0, +int32_t offset1, +int32_t stride1, +int32_t offset2, +int32_t stride2) +{ + struct dmabuf_batch *batch = wl_resource_get_user_data(resource); + struct dmabuf_item *buf; + + buf = wl_array_add(&batch->bufs, sizeof *buf); + if (!buf) { + wl_client_post_no_memory(client); + return; + } + + buf->fd = name; + buf->n_planes = 1; + buf->offset[0] = offset0; + buf->stride[0] = stride0; + + if (offset1 && stride1) { + buf->offset[buf->n_planes] = offset1; + buf->stride[buf->n_planes] = stride1; + buf->n_planes++; + } + + if (offset2 && stride2) { + buf->offset[buf->n_planes] = offset2; + buf->stride[buf->n_planes] = stride2; + buf->n_planes++; + } +} + +static const struct dmabuf_batch_interface dmabuf_batch_implementation = { + dmabuf_batch_destroy, + dmabuf_batch_add +}; + +static void +linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +linux_dmabuf_create_batch(struct wl_client *client, + struct wl_resource *linux_dmabuf_resource, + uint32_t batch_id) +{ + struct dm
[PATCH 3/8] weston-info: report presentation clock
From: Pekka Paalanen Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- Makefile.am | 3 ++ clients/weston-info.c | 81 +++ 2 files changed, 84 insertions(+) diff --git a/Makefile.am b/Makefile.am index b1dcc21..6a91a8f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -582,6 +582,9 @@ weston_simple_im_LDADD = $(CLIENT_LIBS) weston_simple_im_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) weston_info_SOURCES = clients/weston-info.c +nodist_weston_info_SOURCES = \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h weston_info_LDADD = $(WESTON_INFO_LIBS) libshared.la weston_info_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) diff --git a/clients/weston-info.c b/clients/weston-info.c index c53ac74..f777982 100644 --- a/clients/weston-info.c +++ b/clients/weston-info.c @@ -27,10 +27,14 @@ #include #include #include +#include #include #include "../shared/os-compatibility.h" +#include "presentation_timing-client-protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define MIN(x,y) (((x) < (y)) ? (x) : (y)) @@ -98,6 +102,13 @@ struct seat_info { int32_t repeat_delay; }; +struct presentation_info { + struct global_info global; + struct presentation *presentation; + + clockid_t clk_id; +}; + struct weston_info { struct wl_display *display; struct wl_registry *registry; @@ -554,6 +565,74 @@ add_output_info(struct weston_info *info, uint32_t id, uint32_t version) } static void +destroy_presentation_info(void *info) +{ + struct presentation_info *prinfo = info; + + presentation_destroy(prinfo->presentation); +} + +static const char * +clock_name(clockid_t clk_id) +{ + static const char *names[] = { + [CLOCK_REALTIME] = "CLOCK_REALTIME", + [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC", + [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW", + [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE", + [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE", + [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME", + }; + + if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names)) + return "unknown"; + + return names[clk_id]; +} + +static void +print_presentation_info(void *info) +{ + struct presentation_info *prinfo = info; + + print_global_info(info); + + printf("\tpresentation clock id: %d (%s)\n", + prinfo->clk_id, clock_name(prinfo->clk_id)); +} + +static void +presentation_handle_clock_id(void *data, struct presentation *presentation, +uint32_t clk_id) +{ + struct presentation_info *prinfo = data; + + prinfo->clk_id = clk_id; +} + +static const struct presentation_listener presentation_listener = { + presentation_handle_clock_id +}; + +static void +add_presentation_info(struct weston_info *info, uint32_t id, uint32_t version) +{ + struct presentation_info *prinfo = xzalloc(sizeof *prinfo); + + init_global_info(info, &prinfo->global, id, "presentation", version); + prinfo->global.print = print_presentation_info; + prinfo->global.destroy = destroy_presentation_info; + + prinfo->clk_id = -1; + prinfo->presentation = wl_registry_bind(info->registry, id, + &presentation_interface, 1); + presentation_add_listener(prinfo->presentation, &presentation_listener, + prinfo); + + info->roundtrip_needed = true; +} + +static void destroy_global_info(void *data) { } @@ -581,6 +660,8 @@ global_handler(void *data, struct wl_registry *registry, uint32_t id, add_shm_info(info, id, version); else if (!strcmp(interface, "wl_output")) add_output_info(info, id, version); + else if (!strcmp(interface, "presentation")) + add_presentation_info(info, id, version); else add_global_info(info, id, interface, version); } -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 6/8] compositor-drm: deliver frame seq for feedback
From: Pekka Paalanen Add 'msc' field to weston_output to maintain the refresh counter, and use it in presentation_feedback.presented. Make compositor-drm update the per-output refresh counter with the values reported by DRM. If the DRM reported value jumps backwards, assume it wrapped around once. Other backends do not update weston_output::msc, and there presentation_feedback will always deliver refresh counter as zero. Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- src/compositor-drm.c | 14 ++ src/compositor.c | 2 +- src/compositor.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 626a2de..07b83a7 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -726,6 +726,17 @@ finish_frame: } static void +drm_output_update_msc(struct drm_output *output, unsigned int seq) +{ + uint64_t msc_hi = output->base.msc >> 32; + + if (seq < (output->base.msc & 0x)) + msc_hi++; + + output->base.msc = (msc_hi << 32) + seq; +} + +static void vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { @@ -733,6 +744,7 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, struct drm_output *output = s->output; struct timespec ts; + drm_output_update_msc(output, frame); output->vblank_pending = 0; drm_output_release_fb(output, s->current); @@ -756,6 +768,8 @@ page_flip_handler(int fd, unsigned int frame, struct drm_output *output = (struct drm_output *) data; struct timespec ts; + drm_output_update_msc(output, frame); + /* We don't set page_flip_pending on start_repaint_loop, in that case * we just want to page flip to the current buffer to get an accurate * timestamp */ diff --git a/src/compositor.c b/src/compositor.c index 462f922..48e5cc4 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -2069,7 +2069,7 @@ weston_output_finish_frame(struct weston_output *output, refresh_nsec = 1UL / output->current_mode->refresh; weston_presentation_feedback_present_list(&output->feedback_list, output, refresh_nsec, stamp, - 0); + output->msc); output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 100; diff --git a/src/compositor.h b/src/compositor.h index 548ffe5..a1ab9d5 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -203,6 +203,7 @@ struct weston_output { struct wl_signal destroy_signal; int move_x, move_y; uint32_t frame_time; /* presentation timestamp in milliseconds */ + uint64_t msc;/* media stream counter */ int disable_planes; int destroying; struct wl_list feedback_list; -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 5/8] compositor: implement presentation_feedback
From: Pekka Paalanen Implement the presentation.feedback request, and the presentation_feedback protocol interface. Feedback information is delivered to clients as the backend reports it, except the refresh counter (MSC) which is always reported as zero. Changes in v4: * add 'flags' argument to 'presented' event without implementation Changes in v5: * remove the 'destroy' method implementation for feedback objects v5 Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- src/compositor.c | 149 +-- src/compositor.h | 5 ++ 2 files changed, 150 insertions(+), 4 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index f34d712..462f922 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -439,6 +439,78 @@ struct weston_frame_callback { struct wl_list link; }; +struct weston_presentation_feedback { + struct wl_resource *resource; + + /* XXX: could use just wl_resource_get_link() instead */ + struct wl_list link; +}; + +static void +weston_presentation_feedback_discard( + struct weston_presentation_feedback *feedback) +{ + presentation_feedback_send_discarded(feedback->resource); + wl_list_remove(&feedback->link); + wl_list_init(&feedback->link); + wl_resource_destroy(feedback->resource); +} + +static void +weston_presentation_feedback_discard_list(struct wl_list *list) +{ + struct weston_presentation_feedback *feedback, *tmp; + + wl_list_for_each_safe(feedback, tmp, list, link) + weston_presentation_feedback_discard(feedback); +} + +static void +weston_presentation_feedback_present( + struct weston_presentation_feedback *feedback, + struct weston_output *output, + uint32_t refresh_nsec, + const struct timespec *ts, + uint64_t seq) +{ + struct wl_client *client = wl_resource_get_client(feedback->resource); + struct wl_resource *o; + uint64_t secs; + uint32_t flags = 0; + + wl_resource_for_each(o, &output->resource_list) { + if (wl_resource_get_client(o) != client) + continue; + + presentation_feedback_send_sync_output(feedback->resource, o); + } + + secs = ts->tv_sec; + presentation_feedback_send_presented(feedback->resource, +secs >> 32, secs & 0x, +ts->tv_nsec, +refresh_nsec, +seq >> 32, seq & 0x, +flags); + wl_list_remove(&feedback->link); + wl_list_init(&feedback->link); + wl_resource_destroy(feedback->resource); +} + +static void +weston_presentation_feedback_present_list(struct wl_list *list, + struct weston_output *output, + uint32_t refresh_nsec, + const struct timespec *ts, + uint64_t seq) +{ + struct weston_presentation_feedback *feedback, *tmp; + + wl_list_for_each_safe(feedback, tmp, list, link) + weston_presentation_feedback_present(feedback, output, +refresh_nsec, ts, seq); +} + static void surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data) { @@ -464,6 +536,7 @@ weston_surface_state_init(struct weston_surface_state *state) region_init_infinite(&state->input); wl_list_init(&state->frame_callback_list); + wl_list_init(&state->feedback_list); state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL; state->buffer_viewport.buffer.scale = 1; @@ -481,6 +554,8 @@ weston_surface_state_fini(struct weston_surface_state *state) &state->frame_callback_list, link) wl_resource_destroy(cb->resource); + weston_presentation_feedback_discard_list(&state->feedback_list); + pixman_region32_fini(&state->input); pixman_region32_fini(&state->opaque); pixman_region32_fini(&state->damage); @@ -539,6 +614,7 @@ weston_surface_create(struct weston_compositor *compositor) wl_list_init(&surface->views); wl_list_init(&surface->frame_callback_list); + wl_list_init(&surface->feedback_list); wl_list_init(&surface->subsurface_list); wl_list_init(&surface->subsurface_list_pending); @@ -1555,6 +1631,8 @@ weston_surface_destroy(struct weston_surface *surface) wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link) wl_resource_destroy(cb->resource); + weston_presentation_feedback_discard_list(&surface->feedback_list); + free(surface); } @@ -1656,6 +1734,
[PATCH 2/8] compositor: add stub implementation of presentation interface
From: Pekka Paalanen You can bind to the global interface, and it delivers a fake clock id. All requests on it raise an error. Changes in v4: * queuing methods were extractracted for a later series [Louis-Francis Ratté-Boulianne: split queuing feature] Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne Reviewed-by: Mario Kleiner --- src/compositor.c | 47 ++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/compositor.c b/src/compositor.c index a219766..d789508 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1,7 +1,7 @@ /* * Copyright © 2010-2011 Intel Corporation * Copyright © 2008-2011 Kristian Høgsberg - * Copyright © 2012 Collabora, Ltd. + * Copyright © 2012-2014 Collabora, Ltd. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided @@ -55,6 +55,7 @@ #include "compositor.h" #include "scaler-server-protocol.h" +#include "presentation_timing-server-protocol.h" #include "../shared/os-compatibility.h" #include "git-version.h" #include "version.h" @@ -3736,6 +3737,46 @@ bind_scaler(struct wl_client *client, } static void +presentation_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +presentation_feedback(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *surface, + uint32_t callback) +{ + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_METHOD, + "presentation_feedback unimplemented"); +} + +static const struct presentation_interface presentation_implementation = { + presentation_destroy, + presentation_feedback +}; + +static void +bind_presentation(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct weston_compositor *compositor = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &presentation_interface, + MIN(version, 1), id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &presentation_implementation, + compositor, NULL); + presentation_send_clock_id(resource, CLOCK_MONOTONIC); +} + +static void compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { @@ -3830,6 +3871,10 @@ weston_compositor_init(struct weston_compositor *ec, ec, bind_scaler)) return -1; + if (!wl_global_create(ec->wl_display, &presentation_interface, 1, + ec, bind_presentation)) + return -1; + wl_list_init(&ec->view_list); wl_list_init(&ec->plane_list); wl_list_init(&ec->layer_list); -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 7/8] tests: presentation test, simple
From: Pekka Paalanen --- Makefile.am | 8 ++ tests/presentation-test.c | 246 ++ 2 files changed, 254 insertions(+) create mode 100644 tests/presentation-test.c diff --git a/Makefile.am b/Makefile.am index 6a91a8f..87204a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -842,6 +842,7 @@ weston_tests = \ event.weston\ button.weston \ text.weston \ + presentation.weston \ subsurface.weston @@ -944,6 +945,13 @@ subsurface_weston_SOURCES = tests/subsurface-test.c subsurface_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS) subsurface_weston_LDADD = libtest-client.la +presentation_weston_SOURCES = tests/presentation-test.c +nodist_presentation_weston_SOURCES = \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h +presentation_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS) +presentation_weston_LDADD = libtest-client.la + if ENABLE_EGL weston_tests += buffer-count.weston buffer_count_weston_SOURCES = tests/buffer-count-test.c diff --git a/tests/presentation-test.c b/tests/presentation-test.c new file mode 100644 index 000..57012fa --- /dev/null +++ b/tests/presentation-test.c @@ -0,0 +1,246 @@ +/* + * Copyright © 2014 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "weston-test-client-helper.h" +#include "presentation_timing-client-protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +static inline void * +xzalloc(size_t size) +{ + void *p; + + p = calloc(1, size); + assert(p); + + return p; +} + +static struct presentation * +get_presentation(struct client *client) +{ + struct global *g; + struct global *global_pres = NULL; + static struct presentation *pres; + + if (pres) + return pres; + + wl_list_for_each(g, &client->global_list, link) { + if (strcmp(g->interface, "presentation")) + continue; + + if (global_pres) + assert(0 && "multiple presentation objects"); + + global_pres = g; + } + + assert(global_pres && "no presentation found"); + + assert(global_pres->version == 1); + + pres = wl_registry_bind(client->wl_registry, global_pres->name, + &presentation_interface, 1); + assert(pres); + + return pres; +} + +struct feedback { + struct client *client; + struct presentation_feedback *obj; + + enum { + FB_PENDING = 0, + FB_PRESENTED, + FB_DISCARDED + } result; + + struct wl_output *sync_output; + uint64_t seq; + struct timespec time; + uint32_t refresh_nsec; + uint32_t flags; +}; + +static void +timespec_from_proto(struct timespec *tm, uint32_t tv_sec_hi, + uint32_t tv_sec_lo, uint32_t tv_nsec) +{ + tm->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo; + tm->tv_nsec = tv_nsec; +} + +static void +feedback_sync_output(void *data, +struct presentation_feedback *presentation_feedback, +struct wl_output *output) +{ + struct feedback *fb = data; + + assert(fb->result == FB_PENDING); + + if (output) + fb->sync_output = output; +} + +static void +feedback_presented(void *data, + struct presentation_feedback *presentation_feedback, + uint32_t tv_sec_hi, + uint32_t tv_sec_lo, + uint32_t tv_nsec, +
[PATCH 8/8] clients: add presentation-shm demo
From: Pekka Paalanen This started as a copy of simple-shm.c before it was converted to xdg_shell. This demo excercises the presentation feedback interface in five different modes: - A continuous repaint loop triggered by frame callbacks, and using immediate commits, just gathering presentation feedback and computing some time intervals for statistics. - The same as above, except with 1s sleep before actually repainting as a response to frame callback. This tests how well the compositor can do a repaint from idle state (not continuously repainting), assuming nothing else is causing repaints. - A continuous repaint loop triggered by 'presented' events rather than by frame callbacks. If Weston uses an appropriate scheduling algorithm, this mode achieves the smallest possible frame latency (below one output refresh period). In all modes, all frames are pre-rendered at startup, so no rendering happens during the animation. [Louis-Francis Ratté-Boulianne: split queuing feature] Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne --- .gitignore | 1 + Makefile.am| 8 + clients/presentation-shm.c | 866 + 3 files changed, 875 insertions(+) create mode 100644 clients/presentation-shm.c diff --git a/.gitignore b/.gitignore index fbffaa5..d521bcc 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ weston-gears weston-image weston-nested weston-nested-client +weston-presentation-shm weston-resizor weston-scaler weston-simple-egl diff --git a/Makefile.am b/Makefile.am index 87204a6..10be920 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,6 +393,7 @@ demo_clients += \ weston-simple-shm \ weston-simple-damage\ weston-simple-touch \ + weston-presentation-shm \ weston-multi-resource weston_simple_shm_SOURCES = clients/simple-shm.c @@ -419,6 +420,13 @@ weston_simple_touch_SOURCES = clients/simple-touch.c weston_simple_touch_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) weston_simple_touch_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la +weston_presentation_shm_SOURCES = clients/presentation-shm.c +nodist_weston_presentation_shm_SOURCES = \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h +weston_presentation_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) +weston_presentation_shm_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la -lm + weston_multi_resource_SOURCES = clients/multi-resource.c weston_multi_resource_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) weston_multi_resource_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la -lm diff --git a/clients/presentation-shm.c b/clients/presentation-shm.c new file mode 100644 index 000..2976b49 --- /dev/null +++ b/clients/presentation-shm.c @@ -0,0 +1,866 @@ +/* + * Copyright © 2011 Benjamin Franzke + * Copyright © 2010 Intel Corporation + * Copyright © 2014 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../shared/os-compatibility.h" +#include "presentation_timing-client-protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +enum run_mode { + RUN_MODE_FEEDBACK, + RUN_MODE_FEEDBACK_IDLE, + RUN_MODE_PRESENT, +}; + +struct output { + struct wl_output *output; + uint32_t name; + struct wl_list link; +}; + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_sh
[PATCH 1/8] protocol: add presentation extension v5
From: Pekka Paalanen Add accurate presentation timing features to Wayland: queueing and feedback. This specification is based on the draft written by Frederic Plourde and redesigned by Pekka Paalanen. The RFC v2 version is from http://lists.freedesktop.org/archives/wayland-devel/2014-January/012988.html Changes in v3: * associate presentation time to current surface contents This implements the suggestion from http://lists.freedesktop.org/archives/wayland-devel/2014-February/013066.html which prevents surface content from jumping backwards in time if a client retroactively queues an update with a target time in the past. * use 64-bit tv_sec in presentation The time_t type used in struct timespec could be almost anything. POSIX probably defines it to be an integer, but not the size. Apparently it is usually 'long', which makes it 64-bit on x86_64. To be able to fully represent timespec values returned by clock_gettime, change the protocol to use 64 bits for the tv_sec part. * define an error for invalid tv_nsec This allow us to rely on the normalized timestamp form. * define some interactions with sub-surfaces Sub-surface cached state updates (synchronized mode) are designed especially for resizing. As queued updates are not meant to produce any resizing-like effects, they also do not trigger any sub-surface operations. * add sub-headings as xml comments * queued update cannot map Because before mapping, the surface has no main output assigned. An immediate commit is needed anyway, to be able to set all the surface state, which a queued update cannot touch. * frame callbacks are not queued It is not known when queueing frame callbacks would be useful. Changes in v4: * remove mentions of the queuing feature The specification has been split and the queuing feature will be added back in another version of the extension. * add flags argument to 'presented' event Describe the nature of how the update was presented to screen and the characteristics of the feedback information. No flags have been defined for now. * add a protocol error code for invalid flags Changes in v5: * remove the destroy method for the feedback object The protocol object should instead be automatically destroyed after a 'presented' or 'discarded' event has been triggered. * some grammatical corrections to the specification [Louis-Francis Ratté-Boulianne: split the spec in two parts] Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne Reviewed-by: Mario Kleiner --- Makefile.am | 5 + protocol/presentation_timing.xml | 238 +++ 2 files changed, 243 insertions(+) create mode 100644 protocol/presentation_timing.xml diff --git a/Makefile.am b/Makefile.am index b2d6893..b1dcc21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,6 +78,8 @@ nodist_weston_SOURCES = \ protocol/input-method-server-protocol.h \ protocol/workspaces-protocol.c \ protocol/workspaces-server-protocol.h \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-server-protocol.h \ protocol/scaler-protocol.c \ protocol/scaler-server-protocol.h @@ -445,6 +447,8 @@ nodist_libtoytoolkit_la_SOURCES = \ protocol/scaler-client-protocol.h \ protocol/workspaces-protocol.c \ protocol/workspaces-client-protocol.h \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h \ protocol/xdg-shell-protocol.c \ protocol/xdg-shell-client-protocol.h @@ -987,6 +991,7 @@ EXTRA_DIST += \ protocol/wayland-test.xml \ protocol/xdg-shell.xml \ protocol/fullscreen-shell.xml \ + protocol/presentation_timing.xml\ protocol/scaler.xml man_MANS = weston.1 weston.ini.5 diff --git a/protocol/presentation_timing.xml b/protocol/presentation_timing.xml new file mode 100644 index 000..9158434 --- /dev/null +++ b/protocol/presentation_timing.xml @@ -0,0 +1,238 @@ + + + + + +Copyright © 2013-2014 Collabora, Ltd. + +Permission to use, copy, modify, distribute, and sell this +software and its documentation for any purpose is hereby granted +without fee, provided that the above copyright notice appear in +all copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the name of +the copyright holders not be used in advertising or publicity +pertaining to distribution of the software without specific, +written prior permission. The copyright holders make no +representations about
[PATCH 4/8] compositor: set and use the presentation clock everywhere
From: Pekka Paalanen Add presentation clock setters that verify the given clock actually works. Offer an automatic choice of a software fallback clock, when a backend has to always use clock_gettime() to approximate the presentation time. The DRM backend already queried the DRM about the clock id, just let the DRM backend set the presentation clock from that. For all other backends which do not get a timestamp from the driver, call the software clock setter to choose a suitable clock. Report the chosen clock via presentation.clock_id event to clients. In finish_frame(), upgrade the argument from uint32_t milliseconds to struct timespec which can accurately hold the presentation clock values. This will be needed when weston_output_finish_frame() starts to send out presentation_feedback.presented events. While at it, replace gettimeofday() calls with clock_gettime() using the chosen presentation clock, so we manufacture presentation timestamps from the presentation clock when the gfx drivers cannot give us a proper timestamp. Rpi patch is more verbose due to not having the compositor pointer available in rpi_flippipe_update_complete(). Explicitly carry the clock id with flippipe so it is available in the thread. Changes in v4: * rpi debug build fix v4 Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- src/compositor-drm.c | 32 +++ src/compositor-fbdev.c| 12 --- src/compositor-headless.c | 11 --- src/compositor-rdp.c | 11 --- src/compositor-rpi.c | 49 ++--- src/compositor-wayland.c | 11 +-- src/compositor-x11.c | 11 --- src/compositor.c | 79 ++- src/compositor.h | 14 +++-- 9 files changed, 161 insertions(+), 69 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index e4496e7..626a2de 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -118,7 +118,6 @@ struct drm_compositor { uint32_t prev_state; - clockid_t clock; struct udev_input input; uint32_t cursor_width; @@ -700,7 +699,6 @@ drm_output_start_repaint_loop(struct weston_output *output_base) struct drm_compositor *compositor = (struct drm_compositor *) output_base->compositor; uint32_t fb_id; - uint32_t msec; struct timespec ts; if (output->destroy_pending) @@ -723,9 +721,8 @@ drm_output_start_repaint_loop(struct weston_output *output_base) finish_frame: /* if we cannot page-flip, immediately finish frame */ - clock_gettime(compositor->clock, &ts); - msec = ts.tv_sec * 1000 + ts.tv_nsec / 100; - weston_output_finish_frame(output_base, msec); + clock_gettime(compositor->base.presentation_clock, &ts); + weston_output_finish_frame(output_base, &ts); } static void @@ -734,7 +731,7 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, { struct drm_sprite *s = (struct drm_sprite *)data; struct drm_output *output = s->output; - uint32_t msecs; + struct timespec ts; output->vblank_pending = 0; @@ -743,8 +740,9 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, s->next = NULL; if (!output->page_flip_pending) { - msecs = sec * 1000 + usec / 1000; - weston_output_finish_frame(&output->base, msecs); + ts.tv_sec = sec; + ts.tv_nsec = usec * 1000; + weston_output_finish_frame(&output->base, &ts); } } @@ -756,7 +754,7 @@ page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { struct drm_output *output = (struct drm_output *) data; - uint32_t msecs; + struct timespec ts; /* We don't set page_flip_pending on start_repaint_loop, in that case * we just want to page flip to the current buffer to get an accurate @@ -772,8 +770,9 @@ page_flip_handler(int fd, unsigned int frame, if (output->destroy_pending) drm_output_destroy(&output->base); else if (!output->vblank_pending) { - msecs = sec * 1000 + usec / 1000; - weston_output_finish_frame(&output->base, msecs); + ts.tv_sec = sec; + ts.tv_nsec = usec * 1000; + weston_output_finish_frame(&output->base, &ts); /* We can't call this from frame_notify, because the output's * repaint needed flag is cleared just after that */ @@ -1282,6 +1281,7 @@ init_drm(struct drm_compositor *ec, struct udev_device *device) const char *filename, *sysnum; uint64_t cap; int fd, ret; + clockid_t clk_id; sysnum = udev_device_get_sysnum(device); if (sysnum) @@ -1307,9 +1307,15 @@ init_drm(struct drm_compositor *ec, stru
[PATCH 0/8] Wayland Presentation Extension v5
Hi, Here is an update to the Wayland Presentation Extension. For context, please refer to the last thread about the extension: http://lists.freedesktop.org/archives/wayland-devel/2014-September/017278.html Differences compared to the last proposal (v4) are: * Remove the 'destroy' method from the feedback object. * Some grammatical corrections to the protocol specification. Thanks to Bryce Harrington. Pekka Paalanen (8): protocol: add presentation extension v5 compositor: add stub implementation of presentation interface weston-info: report presentation clock compositor: set and use the presentation clock everywhere compositor: implement presentation_feedback compositor-drm: deliver frame seq for feedback tests: presentation test, simple clients: add presentation-shm demo .gitignore | 1 + Makefile.am | 24 ++ clients/presentation-shm.c | 866 +++ clients/weston-info.c| 81 protocol/presentation_timing.xml | 238 +++ src/compositor-drm.c | 46 ++- src/compositor-fbdev.c | 12 +- src/compositor-headless.c| 11 +- src/compositor-rdp.c | 11 +- src/compositor-rpi.c | 49 ++- src/compositor-wayland.c | 11 +- src/compositor-x11.c | 11 +- src/compositor.c | 265 +++- src/compositor.h | 20 +- tests/presentation-test.c| 246 +++ 15 files changed, 1823 insertions(+), 69 deletions(-) create mode 100644 clients/presentation-shm.c create mode 100644 protocol/presentation_timing.xml create mode 100644 tests/presentation-test.c Thanks, Louis-Francis Ratté-Boulianne -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 0/8] Wayland Presentation Extension v4
Hi! To accelerate the merge of the Wayland Presentation extension, it was decided to split it into two parts: feedback and queuing. I've done the work of cleaning up the patches for the first one on behalf of Pekka Paalanen. For context, please refer to the last thread about the extension: http://lists.freedesktop.org/archives/wayland-devel/2014-March/013580.html Differences compared to the last proposal (RFC v3) are: * Remove the queuing feature. * Add flags argument to the 'presented' event. * Add a protocol error code for invalid flags. * Fix the RPI debug build. * Add simple presentation test. Patch 1 adds the protocol. See the commit message to have more details about the changes since RFC v2. More details about the addition of flags are available there: http://lists.freedesktop.org/archives/wayland-devel/2014-March/013857.html The whole patch set is available at http://cgit.collabora.com/git/user/lfrb/weston.git/log/?h=presentation-feedback Pekka Paalanen (8): protocol: add presentation extension v4 compositor: add stub implementation of presentation interface weston-info: report presentation clock compositor: set and use the presentation clock everywhere compositor: implement presentation_feedback compositor-drm: deliver frame seq for feedback tests: presentation test, simple clients: add presentation-shm demo .gitignore | 1 + Makefile.am | 24 ++ clients/presentation-shm.c | 866 +++ clients/weston-info.c| 81 protocol/presentation_timing.xml | 247 +++ src/compositor-drm.c | 46 ++- src/compositor-fbdev.c | 12 +- src/compositor-headless.c| 11 +- src/compositor-rdp.c | 11 +- src/compositor-rpi.c | 49 ++- src/compositor-wayland.c | 11 +- src/compositor-x11.c | 11 +- src/compositor.c | 279 - src/compositor.h | 20 +- tests/presentation-test.c| 246 +++ 15 files changed, 1846 insertions(+), 69 deletions(-) create mode 100644 clients/presentation-shm.c create mode 100644 protocol/presentation_timing.xml create mode 100644 tests/presentation-test.c The next step will be to finish the implementation of feedback flags. Hopefully, it will happen in time for 1.7.0. Afterwards, the second part of the extension (queuing) will have to be cleaned up and merged. However, it will probably not happen before release 1.7.0 given these two bugs must be closed first: https://bugs.freedesktop.org/show_bug.cgi?id=75303 https://bugs.freedesktop.org/show_bug.cgi?id=78190 According to Pekka, it's high time we get the feedback basics into Weston for everyone to try out. Let's hope it's ready to be merged. Thanks, Louis-Francis Ratté-Boulianne -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 4/8] compositor: set and use the presentation clock everywhere
From: Pekka Paalanen Add presentation clock setters that verify the given clock actually works. Offer an automatic choice of a software fallback clock, when a backend has to always use clock_gettime() to approximate the presentation time. The DRM backend already queried the DRM about the clock id, just let the DRM backend set the presentation clock from that. For all other backends which do not get a timestamp from the driver, call the software clock setter to choose a suitable clock. Report the chosen clock via presentation.clock_id event to clients. In finish_frame(), upgrade the argument from uint32_t milliseconds to struct timespec which can accurately hold the presentation clock values. This will be needed when weston_output_finish_frame() starts to send out presentation_feedback.presented events. While at it, replace gettimeofday() calls with clock_gettime() using the chosen presentation clock, so we manufacture presentation timestamps from the presentation clock when the gfx drivers cannot give us a proper timestamp. Rpi patch is more verbose due to not having the compositor pointer available in rpi_flippipe_update_complete(). Explicitly carry the clock id with flippipe so it is available in the thread. Changes in v4: * rpi debug build fix v4 Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- src/compositor-drm.c | 32 +++ src/compositor-fbdev.c| 12 --- src/compositor-headless.c | 11 --- src/compositor-rdp.c | 11 --- src/compositor-rpi.c | 49 ++--- src/compositor-wayland.c | 11 +-- src/compositor-x11.c | 11 --- src/compositor.c | 79 ++- src/compositor.h | 14 +++-- 9 files changed, 161 insertions(+), 69 deletions(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index e4496e7..626a2de 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -118,7 +118,6 @@ struct drm_compositor { uint32_t prev_state; - clockid_t clock; struct udev_input input; uint32_t cursor_width; @@ -700,7 +699,6 @@ drm_output_start_repaint_loop(struct weston_output *output_base) struct drm_compositor *compositor = (struct drm_compositor *) output_base->compositor; uint32_t fb_id; - uint32_t msec; struct timespec ts; if (output->destroy_pending) @@ -723,9 +721,8 @@ drm_output_start_repaint_loop(struct weston_output *output_base) finish_frame: /* if we cannot page-flip, immediately finish frame */ - clock_gettime(compositor->clock, &ts); - msec = ts.tv_sec * 1000 + ts.tv_nsec / 100; - weston_output_finish_frame(output_base, msec); + clock_gettime(compositor->base.presentation_clock, &ts); + weston_output_finish_frame(output_base, &ts); } static void @@ -734,7 +731,7 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, { struct drm_sprite *s = (struct drm_sprite *)data; struct drm_output *output = s->output; - uint32_t msecs; + struct timespec ts; output->vblank_pending = 0; @@ -743,8 +740,9 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, s->next = NULL; if (!output->page_flip_pending) { - msecs = sec * 1000 + usec / 1000; - weston_output_finish_frame(&output->base, msecs); + ts.tv_sec = sec; + ts.tv_nsec = usec * 1000; + weston_output_finish_frame(&output->base, &ts); } } @@ -756,7 +754,7 @@ page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { struct drm_output *output = (struct drm_output *) data; - uint32_t msecs; + struct timespec ts; /* We don't set page_flip_pending on start_repaint_loop, in that case * we just want to page flip to the current buffer to get an accurate @@ -772,8 +770,9 @@ page_flip_handler(int fd, unsigned int frame, if (output->destroy_pending) drm_output_destroy(&output->base); else if (!output->vblank_pending) { - msecs = sec * 1000 + usec / 1000; - weston_output_finish_frame(&output->base, msecs); + ts.tv_sec = sec; + ts.tv_nsec = usec * 1000; + weston_output_finish_frame(&output->base, &ts); /* We can't call this from frame_notify, because the output's * repaint needed flag is cleared just after that */ @@ -1282,6 +1281,7 @@ init_drm(struct drm_compositor *ec, struct udev_device *device) const char *filename, *sysnum; uint64_t cap; int fd, ret; + clockid_t clk_id; sysnum = udev_device_get_sysnum(device); if (sysnum) @@ -1307,9 +1307,15 @@ init_drm(struct drm_compositor *ec, stru
[PATCH 7/8] tests: presentation test, simple
From: Pekka Paalanen Added in v4. Signed-off-by: Pekka Paalanen --- Makefile.am | 8 ++ tests/presentation-test.c | 246 ++ 2 files changed, 254 insertions(+) create mode 100644 tests/presentation-test.c diff --git a/Makefile.am b/Makefile.am index 6a91a8f..87204a6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -842,6 +842,7 @@ weston_tests = \ event.weston\ button.weston \ text.weston \ + presentation.weston \ subsurface.weston @@ -944,6 +945,13 @@ subsurface_weston_SOURCES = tests/subsurface-test.c subsurface_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS) subsurface_weston_LDADD = libtest-client.la +presentation_weston_SOURCES = tests/presentation-test.c +nodist_presentation_weston_SOURCES = \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h +presentation_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS) +presentation_weston_LDADD = libtest-client.la + if ENABLE_EGL weston_tests += buffer-count.weston buffer_count_weston_SOURCES = tests/buffer-count-test.c diff --git a/tests/presentation-test.c b/tests/presentation-test.c new file mode 100644 index 000..57012fa --- /dev/null +++ b/tests/presentation-test.c @@ -0,0 +1,246 @@ +/* + * Copyright © 2014 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation for any purpose is hereby granted without fee, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the copyright holders not be used in + * advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. The copyright holders make + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "weston-test-client-helper.h" +#include "presentation_timing-client-protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +static inline void * +xzalloc(size_t size) +{ + void *p; + + p = calloc(1, size); + assert(p); + + return p; +} + +static struct presentation * +get_presentation(struct client *client) +{ + struct global *g; + struct global *global_pres = NULL; + static struct presentation *pres; + + if (pres) + return pres; + + wl_list_for_each(g, &client->global_list, link) { + if (strcmp(g->interface, "presentation")) + continue; + + if (global_pres) + assert(0 && "multiple presentation objects"); + + global_pres = g; + } + + assert(global_pres && "no presentation found"); + + assert(global_pres->version == 1); + + pres = wl_registry_bind(client->wl_registry, global_pres->name, + &presentation_interface, 1); + assert(pres); + + return pres; +} + +struct feedback { + struct client *client; + struct presentation_feedback *obj; + + enum { + FB_PENDING = 0, + FB_PRESENTED, + FB_DISCARDED + } result; + + struct wl_output *sync_output; + uint64_t seq; + struct timespec time; + uint32_t refresh_nsec; + uint32_t flags; +}; + +static void +timespec_from_proto(struct timespec *tm, uint32_t tv_sec_hi, + uint32_t tv_sec_lo, uint32_t tv_nsec) +{ + tm->tv_sec = ((uint64_t)tv_sec_hi << 32) + tv_sec_lo; + tm->tv_nsec = tv_nsec; +} + +static void +feedback_sync_output(void *data, +struct presentation_feedback *presentation_feedback, +struct wl_output *output) +{ + struct feedback *fb = data; + + assert(fb->result == FB_PENDING); + + if (output) + fb->sync_output = output; +} + +static void +feedback_presented(void *data, + struct presentation_feedback *presentation_feedback, + uint32_t tv_sec_hi, + uint32_t tv_sec_lo, +
[PATCH 3/8] weston-info: report presentation clock
From: Pekka Paalanen Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- Makefile.am | 3 ++ clients/weston-info.c | 81 +++ 2 files changed, 84 insertions(+) diff --git a/Makefile.am b/Makefile.am index b1dcc21..6a91a8f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -582,6 +582,9 @@ weston_simple_im_LDADD = $(CLIENT_LIBS) weston_simple_im_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) weston_info_SOURCES = clients/weston-info.c +nodist_weston_info_SOURCES = \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h weston_info_LDADD = $(WESTON_INFO_LIBS) libshared.la weston_info_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) diff --git a/clients/weston-info.c b/clients/weston-info.c index c53ac74..f777982 100644 --- a/clients/weston-info.c +++ b/clients/weston-info.c @@ -27,10 +27,14 @@ #include #include #include +#include #include #include "../shared/os-compatibility.h" +#include "presentation_timing-client-protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) #define MIN(x,y) (((x) < (y)) ? (x) : (y)) @@ -98,6 +102,13 @@ struct seat_info { int32_t repeat_delay; }; +struct presentation_info { + struct global_info global; + struct presentation *presentation; + + clockid_t clk_id; +}; + struct weston_info { struct wl_display *display; struct wl_registry *registry; @@ -554,6 +565,74 @@ add_output_info(struct weston_info *info, uint32_t id, uint32_t version) } static void +destroy_presentation_info(void *info) +{ + struct presentation_info *prinfo = info; + + presentation_destroy(prinfo->presentation); +} + +static const char * +clock_name(clockid_t clk_id) +{ + static const char *names[] = { + [CLOCK_REALTIME] = "CLOCK_REALTIME", + [CLOCK_MONOTONIC] = "CLOCK_MONOTONIC", + [CLOCK_MONOTONIC_RAW] = "CLOCK_MONOTONIC_RAW", + [CLOCK_REALTIME_COARSE] = "CLOCK_REALTIME_COARSE", + [CLOCK_MONOTONIC_COARSE] = "CLOCK_MONOTONIC_COARSE", + [CLOCK_BOOTTIME] = "CLOCK_BOOTTIME", + }; + + if (clk_id < 0 || (unsigned)clk_id >= ARRAY_LENGTH(names)) + return "unknown"; + + return names[clk_id]; +} + +static void +print_presentation_info(void *info) +{ + struct presentation_info *prinfo = info; + + print_global_info(info); + + printf("\tpresentation clock id: %d (%s)\n", + prinfo->clk_id, clock_name(prinfo->clk_id)); +} + +static void +presentation_handle_clock_id(void *data, struct presentation *presentation, +uint32_t clk_id) +{ + struct presentation_info *prinfo = data; + + prinfo->clk_id = clk_id; +} + +static const struct presentation_listener presentation_listener = { + presentation_handle_clock_id +}; + +static void +add_presentation_info(struct weston_info *info, uint32_t id, uint32_t version) +{ + struct presentation_info *prinfo = xzalloc(sizeof *prinfo); + + init_global_info(info, &prinfo->global, id, "presentation", version); + prinfo->global.print = print_presentation_info; + prinfo->global.destroy = destroy_presentation_info; + + prinfo->clk_id = -1; + prinfo->presentation = wl_registry_bind(info->registry, id, + &presentation_interface, 1); + presentation_add_listener(prinfo->presentation, &presentation_listener, + prinfo); + + info->roundtrip_needed = true; +} + +static void destroy_global_info(void *data) { } @@ -581,6 +660,8 @@ global_handler(void *data, struct wl_registry *registry, uint32_t id, add_shm_info(info, id, version); else if (!strcmp(interface, "wl_output")) add_output_info(info, id, version); + else if (!strcmp(interface, "presentation")) + add_presentation_info(info, id, version); else add_global_info(info, id, interface, version); } -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 6/8] compositor-drm: deliver frame seq for feedback
From: Pekka Paalanen Add 'msc' field to weston_output to maintain the refresh counter, and use it in presentation_feedback.presented. Make compositor-drm update the per-output refresh counter with the values reported by DRM. If the DRM reported value jumps backwards, assume it wrapped around once. Other backends do not update weston_output::msc, and there presentation_feedback will always deliver refresh counter as zero. Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- src/compositor-drm.c | 14 ++ src/compositor.c | 2 +- src/compositor.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/compositor-drm.c b/src/compositor-drm.c index 626a2de..07b83a7 100644 --- a/src/compositor-drm.c +++ b/src/compositor-drm.c @@ -726,6 +726,17 @@ finish_frame: } static void +drm_output_update_msc(struct drm_output *output, unsigned int seq) +{ + uint64_t msc_hi = output->base.msc >> 32; + + if (seq < (output->base.msc & 0x)) + msc_hi++; + + output->base.msc = (msc_hi << 32) + seq; +} + +static void vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) { @@ -733,6 +744,7 @@ vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, struct drm_output *output = s->output; struct timespec ts; + drm_output_update_msc(output, frame); output->vblank_pending = 0; drm_output_release_fb(output, s->current); @@ -756,6 +768,8 @@ page_flip_handler(int fd, unsigned int frame, struct drm_output *output = (struct drm_output *) data; struct timespec ts; + drm_output_update_msc(output, frame); + /* We don't set page_flip_pending on start_repaint_loop, in that case * we just want to page flip to the current buffer to get an accurate * timestamp */ diff --git a/src/compositor.c b/src/compositor.c index 805a677..d61e287 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -2067,7 +2067,7 @@ weston_output_finish_frame(struct weston_output *output, refresh_nsec = 1UL / output->current_mode->refresh; weston_presentation_feedback_present_list(&output->feedback_list, output, refresh_nsec, stamp, - 0); + output->msc); output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 100; diff --git a/src/compositor.h b/src/compositor.h index 548ffe5..a1ab9d5 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -203,6 +203,7 @@ struct weston_output { struct wl_signal destroy_signal; int move_x, move_y; uint32_t frame_time; /* presentation timestamp in milliseconds */ + uint64_t msc;/* media stream counter */ int disable_planes; int destroying; struct wl_list feedback_list; -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/8] compositor: add stub implementation of presentation interface
From: Pekka Paalanen You can bind to the global interface, and it delivers a fake clock id. All requests on it raise an error. Changes in v4: * queuing methods were extractracted for a later series [Louis-Francis Ratté-Boulianne: split queuing feature] Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne v3 Reviewed-by: Mario Kleiner --- src/compositor.c | 47 ++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/compositor.c b/src/compositor.c index a219766..d789508 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1,7 +1,7 @@ /* * Copyright © 2010-2011 Intel Corporation * Copyright © 2008-2011 Kristian Høgsberg - * Copyright © 2012 Collabora, Ltd. + * Copyright © 2012-2014 Collabora, Ltd. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided @@ -55,6 +55,7 @@ #include "compositor.h" #include "scaler-server-protocol.h" +#include "presentation_timing-server-protocol.h" #include "../shared/os-compatibility.h" #include "git-version.h" #include "version.h" @@ -3736,6 +3737,46 @@ bind_scaler(struct wl_client *client, } static void +presentation_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +presentation_feedback(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *surface, + uint32_t callback) +{ + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_METHOD, + "presentation_feedback unimplemented"); +} + +static const struct presentation_interface presentation_implementation = { + presentation_destroy, + presentation_feedback +}; + +static void +bind_presentation(struct wl_client *client, + void *data, uint32_t version, uint32_t id) +{ + struct weston_compositor *compositor = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &presentation_interface, + MIN(version, 1), id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &presentation_implementation, + compositor, NULL); + presentation_send_clock_id(resource, CLOCK_MONOTONIC); +} + +static void compositor_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { @@ -3830,6 +3871,10 @@ weston_compositor_init(struct weston_compositor *ec, ec, bind_scaler)) return -1; + if (!wl_global_create(ec->wl_display, &presentation_interface, 1, + ec, bind_presentation)) + return -1; + wl_list_init(&ec->view_list); wl_list_init(&ec->plane_list); wl_list_init(&ec->layer_list); -- 1.9.3 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/8] protocol: add presentation extension v4
From: Pekka Paalanen Add accurate presentation timing features to Wayland: queueing and feedback. This specification is based on the draft written by Frederic Plourde and redesigned by Pekka Paalanen. The RFC v2 version is from http://lists.freedesktop.org/archives/wayland-devel/2014-January/012988.html Changes in v3: * associate presentation time to current surface contents This implements the suggestion from http://lists.freedesktop.org/archives/wayland-devel/2014-February/013066.html which prevents surface content from jumping backwards in time if a client retroactively queues an update with a target time in the past. * use 64-bit tv_sec in presentation The time_t type used in struct timespec could be almost anything. POSIX probably defines it to be an integer, but not the size. Apparently it is usually 'long', which makes it 64-bit on x86_64. To be able to fully represent timespec values returned by clock_gettime, change the protocol to use 64 bits for the tv_sec part. * define an error for invalid tv_nsec This allow us to rely on the normalized timestamp form. * define some interactions with sub-surfaces Sub-surface cached state updates (synchronized mode) are designed especially for resizing. As queued updates are not meant to produce any resizing-like effects, they also do not trigger any sub-surface operations. * add sub-headings as xml comments * queued update cannot map Because before mapping, the surface has no main output assigned. An immediate commit is needed anyway, to be able to set all the surface state, which a queued update cannot touch. * frame callbacks are not queued It is not known when queueing frame callbacks would be useful. Changes in v4: * remove mentions of the queuing feature The specification has been split and the queuing feature will be added back in another version of the extension. * add flags argument to 'presented' event Describe the nature of how the update was presented to screen and the characteristics of the feedback information. No flags have been defined for now. * add a protocol error code for invalid flags [Louis-Francis Ratté-Boulianne: split the spec in two parts] Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne v3 Reviewed-by: Mario Kleiner --- Makefile.am | 5 + protocol/presentation_timing.xml | 247 +++ 2 files changed, 252 insertions(+) create mode 100644 protocol/presentation_timing.xml diff --git a/Makefile.am b/Makefile.am index b2d6893..b1dcc21 100644 --- a/Makefile.am +++ b/Makefile.am @@ -78,6 +78,8 @@ nodist_weston_SOURCES = \ protocol/input-method-server-protocol.h \ protocol/workspaces-protocol.c \ protocol/workspaces-server-protocol.h \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-server-protocol.h \ protocol/scaler-protocol.c \ protocol/scaler-server-protocol.h @@ -445,6 +447,8 @@ nodist_libtoytoolkit_la_SOURCES = \ protocol/scaler-client-protocol.h \ protocol/workspaces-protocol.c \ protocol/workspaces-client-protocol.h \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h \ protocol/xdg-shell-protocol.c \ protocol/xdg-shell-client-protocol.h @@ -987,6 +991,7 @@ EXTRA_DIST += \ protocol/wayland-test.xml \ protocol/xdg-shell.xml \ protocol/fullscreen-shell.xml \ + protocol/presentation_timing.xml\ protocol/scaler.xml man_MANS = weston.1 weston.ini.5 diff --git a/protocol/presentation_timing.xml b/protocol/presentation_timing.xml new file mode 100644 index 000..8aadff0 --- /dev/null +++ b/protocol/presentation_timing.xml @@ -0,0 +1,247 @@ + + + + + +Copyright © 2013-2014 Collabora, Ltd. + +Permission to use, copy, modify, distribute, and sell this +software and its documentation for any purpose is hereby granted +without fee, provided that the above copyright notice appear in +all copies and that both that copyright notice and this permission +notice appear in supporting documentation, and that the name of +the copyright holders not be used in advertising or publicity +pertaining to distribution of the software without specific, +written prior permission. The copyright holders make no +representations about the suitability of this software for any +purpose. It is provided "as is" without express or implied +warranty. + +THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
[PATCH 5/8] compositor: implement presentation_feedback
From: Pekka Paalanen Implement the presentation.feedback request, and the presentation_feedback protocol interface. Feedback information is delivered to clients as the backend reports it, except the refresh counter (MSC) which is always reported as zero. Changes in v4: * add 'flags' argument to 'presented' event without implementation v4 Signed-off-by: Pekka Paalanen v3 Reviewed-by: Mario Kleiner --- src/compositor.c | 163 +-- src/compositor.h | 5 ++ 2 files changed, 164 insertions(+), 4 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index f34d712..805a677 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -439,6 +439,76 @@ struct weston_frame_callback { struct wl_list link; }; +struct weston_presentation_feedback { + struct wl_resource *resource; + + /* XXX: could use just wl_resource_get_link() instead */ + struct wl_list link; +}; + +static void +weston_presentation_feedback_discard( + struct weston_presentation_feedback *feedback) +{ + presentation_feedback_send_discarded(feedback->resource); + wl_list_remove(&feedback->link); + wl_list_init(&feedback->link); +} + +static void +weston_presentation_feedback_discard_list(struct wl_list *list) +{ + struct weston_presentation_feedback *feedback, *tmp; + + wl_list_for_each_safe(feedback, tmp, list, link) + weston_presentation_feedback_discard(feedback); +} + +static void +weston_presentation_feedback_present( + struct weston_presentation_feedback *feedback, + struct weston_output *output, + uint32_t refresh_nsec, + const struct timespec *ts, + uint64_t seq) +{ + struct wl_client *client = wl_resource_get_client(feedback->resource); + struct wl_resource *o; + uint64_t secs; + uint32_t flags = 0; + + wl_resource_for_each(o, &output->resource_list) { + if (wl_resource_get_client(o) != client) + continue; + + presentation_feedback_send_sync_output(feedback->resource, o); + } + + secs = ts->tv_sec; + presentation_feedback_send_presented(feedback->resource, +secs >> 32, secs & 0x, +ts->tv_nsec, +refresh_nsec, +seq >> 32, seq & 0x, +flags); + wl_list_remove(&feedback->link); + wl_list_init(&feedback->link); +} + +static void +weston_presentation_feedback_present_list(struct wl_list *list, + struct weston_output *output, + uint32_t refresh_nsec, + const struct timespec *ts, + uint64_t seq) +{ + struct weston_presentation_feedback *feedback, *tmp; + + wl_list_for_each_safe(feedback, tmp, list, link) + weston_presentation_feedback_present(feedback, output, +refresh_nsec, ts, seq); +} + static void surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data) { @@ -464,6 +534,7 @@ weston_surface_state_init(struct weston_surface_state *state) region_init_infinite(&state->input); wl_list_init(&state->frame_callback_list); + wl_list_init(&state->feedback_list); state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL; state->buffer_viewport.buffer.scale = 1; @@ -481,6 +552,8 @@ weston_surface_state_fini(struct weston_surface_state *state) &state->frame_callback_list, link) wl_resource_destroy(cb->resource); + weston_presentation_feedback_discard_list(&state->feedback_list); + pixman_region32_fini(&state->input); pixman_region32_fini(&state->opaque); pixman_region32_fini(&state->damage); @@ -539,6 +612,7 @@ weston_surface_create(struct weston_compositor *compositor) wl_list_init(&surface->views); wl_list_init(&surface->frame_callback_list); + wl_list_init(&surface->feedback_list); wl_list_init(&surface->subsurface_list); wl_list_init(&surface->subsurface_list_pending); @@ -1555,6 +1629,8 @@ weston_surface_destroy(struct weston_surface *surface) wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link) wl_resource_destroy(cb->resource); + weston_presentation_feedback_discard_list(&surface->feedback_list); + free(surface); } @@ -1656,6 +1732,7 @@ weston_surface_attach(struct weston_surface *surface, surface->compositor->renderer->attach(surface, buffer); weston_surface_calculate_size_from_buffer(surfac
[PATCH 8/8] clients: add presentation-shm demo
From: Pekka Paalanen This started as a copy of simple-shm.c before it was converted to xdg_shell. This demo excercises the presentation feedback interface in five different modes: - A continuous repaint loop triggered by frame callbacks, and using immediate commits, just gathering presentation feedback and computing some time intervals for statistics. - The same as above, except with 1s sleep before actually repainting as a response to frame callback. This tests how well the compositor can do a repaint from idle state (not continuously repainting), assuming nothing else is causing repaints. - A continuous repaint loop triggered by 'presented' events rather than by frame callbacks. If Weston uses an appropriate scheduling algorithm, this mode achieves the smallest possible frame latency (below one output refresh period). In all modes, all frames are pre-rendered at startup, so no rendering happens during the animation. [Louis-Francis Ratté-Boulianne: split queuing feature] Signed-off-by: Pekka Paalanen Signed-off-by: Louis-Francis Ratté-Boulianne --- .gitignore | 1 + Makefile.am| 8 + clients/presentation-shm.c | 866 + 3 files changed, 875 insertions(+) create mode 100644 clients/presentation-shm.c diff --git a/.gitignore b/.gitignore index fbffaa5..d521bcc 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ weston-gears weston-image weston-nested weston-nested-client +weston-presentation-shm weston-resizor weston-scaler weston-simple-egl diff --git a/Makefile.am b/Makefile.am index 87204a6..10be920 100644 --- a/Makefile.am +++ b/Makefile.am @@ -393,6 +393,7 @@ demo_clients += \ weston-simple-shm \ weston-simple-damage\ weston-simple-touch \ + weston-presentation-shm \ weston-multi-resource weston_simple_shm_SOURCES = clients/simple-shm.c @@ -419,6 +420,13 @@ weston_simple_touch_SOURCES = clients/simple-touch.c weston_simple_touch_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) weston_simple_touch_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la +weston_presentation_shm_SOURCES = clients/presentation-shm.c +nodist_weston_presentation_shm_SOURCES = \ + protocol/presentation_timing-protocol.c \ + protocol/presentation_timing-client-protocol.h +weston_presentation_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) +weston_presentation_shm_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la -lm + weston_multi_resource_SOURCES = clients/multi-resource.c weston_multi_resource_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS) weston_multi_resource_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la -lm diff --git a/clients/presentation-shm.c b/clients/presentation-shm.c new file mode 100644 index 000..2976b49 --- /dev/null +++ b/clients/presentation-shm.c @@ -0,0 +1,866 @@ +/* + * Copyright © 2011 Benjamin Franzke + * Copyright © 2010 Intel Corporation + * Copyright © 2014 Collabora, Ltd. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../shared/os-compatibility.h" +#include "presentation_timing-client-protocol.h" + +#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) + +enum run_mode { + RUN_MODE_FEEDBACK, + RUN_MODE_FEEDBACK_IDLE, + RUN_MODE_PRESENT, +}; + +struct output { + struct wl_output *output; + uint32_t name; + struct wl_list link; +}; + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_sh
Re: [PATCH 3/4 v2] xwayland: Draw decoration on window manager side
Draw everything in a cairo image surface before copying it to the XCB surface. That removes the flickering visible on rpi whenever the decoration were redrawn. --- src/xwayland/window-manager.c | 26 -- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c index 15cb2ed..594c64f 100644 --- a/src/xwayland/window-manager.c +++ b/src/xwayland/window-manager.c @@ -97,6 +97,7 @@ struct weston_wm_window { xcb_window_t id; xcb_window_t frame_id; cairo_surface_t *cairo_surface; + cairo_surface_t *cairo_xcb_surface; struct weston_surface *surface; struct shell_surface *shsurf; struct wl_listener surface_destroy_listener; @@ -900,12 +901,16 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event) xcb_map_window(wm->conn, map_request->window); xcb_map_window(wm->conn, window->frame_id); - window->cairo_surface = + window->cairo_xcb_surface = cairo_xcb_surface_create_with_xrender_format(wm->conn, wm->screen, window->frame_id, &wm->format_rgba, width, height); + window->cairo_surface = + cairo_surface_create_similar_image(window->cairo_xcb_surface, + CAIRO_FORMAT_ARGB32, + width, height); hash_table_insert(wm->window_hash, window->frame_id, window); @@ -967,6 +972,8 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event) wl_event_source_remove(window->repaint_source); if (window->cairo_surface) cairo_surface_destroy(window->cairo_surface); + if (window->cairo_xcb_surface) + cairo_surface_destroy(window->cairo_xcb_surface); if (window->frame_id) { xcb_reparent_window(wm->conn, window->id, wm->wm_window, 0, 0); @@ -1009,7 +1016,16 @@ weston_wm_window_draw_decoration(void *data) weston_wm_window_get_frame_size(window, &width, &height); weston_wm_window_get_child_position(window, &x, &y); - cairo_xcb_surface_set_size(window->cairo_surface, width, height); + if (cairo_image_surface_get_width(window->cairo_surface) != width || + cairo_image_surface_get_height(window->cairo_surface) != height) { + cairo_surface_destroy(window->cairo_surface); + window->cairo_surface = + cairo_surface_create_similar_image(window->cairo_xcb_surface, + CAIRO_FORMAT_ARGB32, + width, height); + cairo_xcb_surface_set_size(window->cairo_xcb_surface, width, height); + } + cr = cairo_create(window->cairo_surface); if (window->fullscreen) { @@ -1036,6 +1052,12 @@ weston_wm_window_draw_decoration(void *data) cairo_destroy(cr); + cr = cairo_create(window->cairo_xcb_surface); + cairo_set_source_surface(cr, window->cairo_surface, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_destroy(cr); + if (window->surface) { pixman_region32_fini(&window->surface->pending.opaque); if(window->has_alpha) { -- 1.8.1.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH 3/4] xwayland: Draw decoration on window manager side
On Wednesday, July 31, 2013 10:41 EDT, Uli Schlachter wrote: > Hi, > > On 30.07.2013 18:13, Louis-Francis Ratté-Boulianne wrote: > > Draw everything in a cairo image surface before copying it to the XCB > > surface. That removes the flickering visible on rpi whenever the > > decoration were redrawn. > > --- > > src/xwayland/window-manager.c | 22 -- > > 1 file changed, 20 insertions(+), 2 deletions(-) > > > > diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c > > index b3c9251..57a5d99 100644 > > --- a/src/xwayland/window-manager.c > > +++ b/src/xwayland/window-manager.c > > @@ -97,6 +97,7 @@ struct weston_wm_window { > > xcb_window_t id; > > xcb_window_t frame_id; > > cairo_surface_t *cairo_surface; > > + cairo_surface_t *cairo_xcb_surface; > > struct weston_surface *surface; > > struct shell_surface *shsurf; > > struct wl_listener surface_destroy_listener; > > @@ -900,12 +901,14 @@ weston_wm_handle_map_request(struct weston_wm *wm, > > xcb_generic_event_t *event) > > xcb_map_window(wm->conn, map_request->window); > > xcb_map_window(wm->conn, window->frame_id); > > > > - window->cairo_surface = > > + window->cairo_xcb_surface = > > cairo_xcb_surface_create_with_xrender_format(wm->conn, > > wm->screen, > > window->frame_id, > > &wm->format_rgba, > > width, height); > > + window->cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, > > + width, height); > [...] > > Why do you use an image surface for this? I would suggest to use > cairo_surface_create_similar() instead. This might then give you an XCB > surface > drawing to a temporary pixmap (but it could also be an image surface or > something completely different). I tried this way, but it still flickers between a black surface and the drawn decoration when the decorations are updated or the window is resized. It's still better than having each element showing up one after the other, but still really ugly. Also, I was wondering..if the similar surface that has been created is a XCB one, is the rendering on the server side? The objective of my patch was to move the drawing on client side (wm) so we know when it's done and we can push it to the screen. > If there is some reason for forcing image surfaces and if depending on cairo > 1.12 is no problem, I would suggest to use > cairo_surface_create_similar_image() > at least. This would make it possible for cairo to use shared memory instead > of > sending all the pixels over the X11 socket. That's seem to be the only solution that avoids any flickering while drawing the decoration on slow hardware (Raspberry Pi in my case). Unfortunately, there is a bug in Cairo < 1.12.6. So if you feel confident that we can update the dependency, that's the patch you should push. If not, the old patch still seems to be the only working solution for me. Related cairo commit: "xcb: Clear the result of create_similar_image" > And a third idea would be to use cairo_push_group(); / > cairo_pop_group_to_source(); cairo_paint();. This would need to be done around > the drawing code. I don't know this code and I am too lazy to look it up, but > if > this works and could be done easily, this would avoid the memory usage for > keeping the double-buffering surface around always. That solution would have been really great to avoid the memory usage, but a similar problem occurs (flickering). I guess it's because the decorations are still rendered on server side. Thanks for the review. If you want to see the patches I came up with to test the other solutions, let me know. -- Louis-Francis > Cheers, > Uli > -- > - He made himself, me nothing, you nothing out of the dust > - Er machte sich mir nichts, dir nichts aus dem Staub ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 1/4] xwayland: Fix the race condition when mapping a surface
From: Louis-Francis Ratté-Boulianne Make sure XCB_MAP_NOTIFY has been received and the window id has been set before mapping the shell surface. It fixes race condition making the surface appears at wrong coordinates or with wrong size. --- src/xwayland/window-manager.c | 29 +++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c index 257c108..76294fa 100644 --- a/src/xwayland/window-manager.c +++ b/src/xwayland/window-manager.c @@ -117,6 +117,8 @@ struct weston_wm_window { int override_redirect; int fullscreen; int has_alpha; + int map_notified; + int mapped; }; static struct weston_wm_window * @@ -125,6 +127,9 @@ get_wm_window(struct weston_surface *surface); static void weston_wm_window_schedule_repaint(struct weston_wm_window *window); +static void +xserver_map_shell_surface(struct weston_wm *wm, struct weston_wm_window *window); + static int __attribute__ ((format (printf, 1, 2))) wm_log(const char *fmt, ...) { @@ -159,7 +164,6 @@ wm_log_continue(const char *fmt, ...) #endif } - const char * get_atom_name(xcb_connection_t *c, xcb_atom_t atom) { @@ -585,6 +589,8 @@ weston_wm_handle_configure_notify(struct weston_wm *wm, xcb_generic_event_t *eve weston_wm_window_get_child_position(window, &x, &y); window->x = configure_notify->x - x; window->y = configure_notify->y - y; + + weston_log("handle_configure_notify: (%d, %d)\n", window->x, window->y); } static void @@ -805,6 +811,14 @@ static void weston_wm_handle_map_notify(struct weston_wm *wm, xcb_generic_event_t *event) { xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) event; + struct weston_wm_window *window; + + window = hash_table_lookup(wm->window_hash, map_notify->window); + weston_log("MAP SURFACE %d, %p\n", map_notify->window, window); + + window->map_notified = 1; + if (window->surface != NULL) + xserver_map_shell_surface(wm, window); if (our_resource(wm, map_notify->window)) { wm_log("XCB_MAP_NOTIFY (window %d, ours)\n", @@ -853,6 +867,7 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event) wm->focus_window = NULL; if (window->surface) wl_list_remove(&window->surface_destroy_listener.link); + window->mapped = 0; window->surface = NULL; } @@ -1008,6 +1023,9 @@ weston_wm_window_create(struct weston_wm *wm, window->override_redirect = override; window->width = width; window->height = height; + window->surface = NULL; + window->map_notified = 0; + window->mapped = 0; geometry_reply = xcb_get_geometry_reply(wm->conn, geometry_cookie, NULL); /* technically we should use XRender and check the visual format's @@ -1914,9 +1932,14 @@ xserver_map_shell_surface(struct weston_wm *wm, &wm->server->compositor->shell_interface; struct theme *t = window->wm->theme; + if (window->mapped) + return; + if (!shell_interface->create_shell_surface) return; + weston_log("MAPPING SURFACE %p\n", window->surface); + window->mapped = 1; window->shsurf = shell_interface->create_shell_surface(shell_interface->shell, window->surface, @@ -1969,7 +1992,9 @@ xserver_set_window_id(struct wl_client *client, struct wl_resource *resource, &window->surface_destroy_listener); weston_wm_window_schedule_repaint(window); - xserver_map_shell_surface(wm, window); + + if (window->map_notified) + xserver_map_shell_surface(wm, window); } const struct xserver_interface xserver_implementation = { -- 1.8.3.1 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH] xwayland: Check surface is not null when handling enter events
--- hw/xfree86/xwayland/xwayland-input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/xfree86/xwayland/xwayland-input.c b/hw/xfree86/xwayland/xwayland-input.c index c550d77..e1858f2 100644 --- a/hw/xfree86/xwayland/xwayland-input.c +++ b/hw/xfree86/xwayland/xwayland-input.c @@ -278,6 +278,9 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, int sy = wl_fixed_to_int(sy_w); ScreenPtr pScreen = xwl_seat->xwl_screen->screen; +if (surface == NULL) +return; + xwl_seat->xwl_screen->serial = serial; xwl_seat->pointer_enter_serial = serial; -- 1.8.3.1 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 4/4] xwayland: Implement extended version of _NET_WM_SYNC_REQUEST protocol
"Extended synchronization provides a more general framework for redraw coordination, including spontaneous application updates as well as resizing." See documentation http://fishsoup.net/misc/wm-spec-synchronization.html --- src/compositor.c | 3 + src/compositor.h | 1 + src/xwayland/window-manager.c | 219 ++ src/xwayland/xwayland.h | 2 + 4 files changed, 206 insertions(+), 19 deletions(-) diff --git a/src/compositor.c b/src/compositor.c index e9ba0fd..8138f71 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1323,6 +1323,8 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs) if (output->dirty) weston_output_update_matrix(output); + wl_signal_emit(&output->repaint_signal, msecs); + output->repaint(output, &output_damage); pixman_region32_fini(&output_damage); @@ -2741,6 +2743,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c, wl_signal_init(&output->frame_signal); wl_signal_init(&output->destroy_signal); + wl_signal_init(&output->repaint_signal); wl_list_init(&output->animation_list); wl_list_init(&output->resource_list); diff --git a/src/compositor.h b/src/compositor.h index 57b206e..dccbbff 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -192,6 +192,7 @@ struct weston_output { int dirty; struct wl_signal frame_signal; struct wl_signal destroy_signal; + struct wl_signal repaint_signal; uint32_t frame_time; int disable_planes; diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c index 57a5d99..f083c8b 100644 --- a/src/xwayland/window-manager.c +++ b/src/xwayland/window-manager.c @@ -122,9 +122,15 @@ struct weston_wm_window { int mapped; xcb_sync_alarm_t sync_request_alarm; xcb_sync_counter_t sync_request_counter; + int sync_request_counter_extended; struct wl_event_source *sync_request_timer; + struct wl_listener frame_listener; + struct wl_listener repaint_listener; int64_t sync_request_serial; + int64_t sync_request_wait_serial; + uint64_t frame_time; int configure_pending; + int needs_frame_drawn; int sync_disabled; int wait_redraw; }; @@ -431,7 +437,12 @@ weston_wm_window_read_properties(struct weston_wm_window *window) break; case XCB_SYNC_COUNTER: counter = xcb_get_property_value(reply); - *(xcb_sync_counter_t *) p = *counter; + if (reply->value_len == 2) { + *(xcb_sync_counter_t *) p = counter[1]; + window->sync_request_counter_extended = 1; + } else { + *(xcb_sync_counter_t *) p = *counter; + } break; case TYPE_WM_PROTOCOLS: break; @@ -746,12 +757,34 @@ weston_wm_window_set_net_wm_state(struct weston_wm_window *window) 32, /* format */ i, property); } + +static void +weston_wm_window_update_frozen(struct weston_wm_window *window) +{ + int frozen = 0; + + if (!window->sync_disabled) { + if (window->sync_request_counter_extended && + window->sync_request_serial % 2 == 1) + frozen = 1; + + if (window->sync_request_serial < window->sync_request_wait_serial) + frozen = 1; + + if (window->repaint_source) + frozen = 1; + } + + window->wait_redraw = frozen; + /*if (window->surface) + window->surface->frozen = frozen;*/ + weston_log("UPDATE FROZEN %i\n", frozen); +} static void weston_wm_window_create_sync_alarm(struct weston_wm_window *window) { struct weston_wm *wm = window->wm; - xcb_sync_int64_t value; uint32_t mask; xcb_sync_create_alarm_value_list_t value_list; @@ -765,16 +798,29 @@ weston_wm_window_create_sync_alarm(struct weston_wm_window *window) return; } - value.hi = 0; - value.lo = 0; - window->sync_request_serial = 0; - xcb_sync_set_counter(wm->conn, window->sync_request_counter, value); + if (window->sync_request_counter_extended) { + xcb_sync_query_counter_cookie_t cookie; + xcb_sync_query_counter_reply_t *reply; + + cookie = xcb_sync_query_counter(wm->conn, window->sync_request_counter); + reply = xcb_sync_query_counter_reply(wm->conn, cookie, NULL); + window->sync_request_serial = reply->counter_value.lo; + window->sync_request_serial += (int64_t) reply->counter_value.hi << 3
[PATCH 3/4] xwayland: Draw decoration on window manager side
Draw everything in a cairo image surface before copying it to the XCB surface. That removes the flickering visible on rpi whenever the decoration were redrawn. --- src/xwayland/window-manager.c | 22 -- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c index b3c9251..57a5d99 100644 --- a/src/xwayland/window-manager.c +++ b/src/xwayland/window-manager.c @@ -97,6 +97,7 @@ struct weston_wm_window { xcb_window_t id; xcb_window_t frame_id; cairo_surface_t *cairo_surface; + cairo_surface_t *cairo_xcb_surface; struct weston_surface *surface; struct shell_surface *shsurf; struct wl_listener surface_destroy_listener; @@ -900,12 +901,14 @@ weston_wm_handle_map_request(struct weston_wm *wm, xcb_generic_event_t *event) xcb_map_window(wm->conn, map_request->window); xcb_map_window(wm->conn, window->frame_id); - window->cairo_surface = + window->cairo_xcb_surface = cairo_xcb_surface_create_with_xrender_format(wm->conn, wm->screen, window->frame_id, &wm->format_rgba, width, height); + window->cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); hash_table_insert(wm->window_hash, window->frame_id, window); @@ -967,6 +970,8 @@ weston_wm_handle_unmap_notify(struct weston_wm *wm, xcb_generic_event_t *event) wl_event_source_remove(window->repaint_source); if (window->cairo_surface) cairo_surface_destroy(window->cairo_surface); + if (window->cairo_xcb_surface) + cairo_surface_destroy(window->cairo_xcb_surface); if (window->frame_id) { xcb_reparent_window(wm->conn, window->id, wm->wm_window, 0, 0); @@ -1009,7 +1014,14 @@ weston_wm_window_draw_decoration(void *data) weston_wm_window_get_frame_size(window, &width, &height); weston_wm_window_get_child_position(window, &x, &y); - cairo_xcb_surface_set_size(window->cairo_surface, width, height); + if (cairo_image_surface_get_width(window->cairo_surface) != width || + cairo_image_surface_get_height(window->cairo_surface) != height) { + cairo_surface_destroy(window->cairo_surface); + window->cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + cairo_xcb_surface_set_size(window->cairo_xcb_surface, width, height); + } + cr = cairo_create(window->cairo_surface); if (window->fullscreen) { @@ -1036,6 +1048,12 @@ weston_wm_window_draw_decoration(void *data) cairo_destroy(cr); + cr = cairo_create(window->cairo_xcb_surface); + cairo_set_source_surface(cr, window->cairo_surface, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_destroy(cr); + if (window->surface) { pixman_region32_fini(&window->surface->pending.opaque); if(window->has_alpha) { -- 1.8.3.1 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
[PATCH 2/4] xwayland: Implement _NET_WM_SYNC_REQUEST protocol
>From the documentation: "This protocol uses the XSync extension to let client and window manager synchronize the repaint of the window manager frame and the client window" * It makes sure the window manager doesn't send configure events faster than the application can handle them. * If an sync request hasn't been replied after 1 second, the wm switches back to unsync'd resizing until the sync request counter is updated. * Only supported with application/toolkits implementing the protocol. --- configure.ac | 2 +- src/xwayland/window-manager.c | 231 -- src/xwayland/xwayland.h | 5 + 3 files changed, 230 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index f9f1c53..4edd283 100644 --- a/configure.ac +++ b/configure.ac @@ -91,7 +91,7 @@ AC_ARG_ENABLE(xwayland-test, [ --enable-xwayland-test],, AM_CONDITIONAL(ENABLE_XWAYLAND, test x$enable_xwayland = xyes) AM_CONDITIONAL(ENABLE_XWAYLAND_TEST, test x$enable_xwayland = xyes -a x$enable_xwayland_test = xyes) if test x$enable_xwayland = xyes; then - PKG_CHECK_MODULES([XWAYLAND], xcb xcb-xfixes xcursor cairo-xcb) + PKG_CHECK_MODULES([XWAYLAND], xcb xcb-sync xcb-xfixes xcursor cairo-xcb) AC_DEFINE([BUILD_XWAYLAND], [1], [Build the X server launcher]) AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH], diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c index 76294fa..b3c9251 100644 --- a/src/xwayland/window-manager.c +++ b/src/xwayland/window-manager.c @@ -119,12 +119,22 @@ struct weston_wm_window { int has_alpha; int map_notified; int mapped; + xcb_sync_alarm_t sync_request_alarm; + xcb_sync_counter_t sync_request_counter; + struct wl_event_source *sync_request_timer; + int64_t sync_request_serial; + int configure_pending; + int sync_disabled; + int wait_redraw; }; static struct weston_wm_window * get_wm_window(struct weston_surface *surface); static void +weston_wm_window_configure(void *data); + +static void weston_wm_window_schedule_repaint(struct weston_wm_window *window); static void @@ -356,6 +366,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) { wm->atom.net_wm_window_type, XCB_ATOM_ATOM, F(type) }, { wm->atom.net_wm_name, XCB_ATOM_STRING, F(name) }, { wm->atom.net_wm_pid, XCB_ATOM_CARDINAL, F(pid) }, + { wm->atom.net_wm_sync_request_counter, XCB_SYNC_COUNTER, F(sync_request_counter) }, { wm->atom.motif_wm_hints, TYPE_MOTIF_WM_HINTS, 0 }, { wm->atom.wm_client_machine, XCB_ATOM_WM_CLIENT_MACHINE, F(machine) }, }; @@ -366,6 +377,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) void *p; uint32_t *xid; xcb_atom_t *atom; + xcb_sync_counter_t *counter; uint32_t i; struct motif_wm_hints *hints; @@ -416,6 +428,10 @@ weston_wm_window_read_properties(struct weston_wm_window *window) atom = xcb_get_property_value(reply); *(xcb_atom_t *) p = *atom; break; + case XCB_SYNC_COUNTER: + counter = xcb_get_property_value(reply); + *(xcb_sync_counter_t *) p = *counter; + break; case TYPE_WM_PROTOCOLS: break; case TYPE_NET_WM_STATE: @@ -731,6 +747,93 @@ weston_wm_window_set_net_wm_state(struct weston_wm_window *window) } static void +weston_wm_window_create_sync_alarm(struct weston_wm_window *window) +{ + struct weston_wm *wm = window->wm; + xcb_sync_int64_t value; + uint32_t mask; + xcb_sync_create_alarm_value_list_t value_list; + + if (window->sync_request_counter == 0) { + weston_log("NET_WM_SYNC_REQUEST isn't supported by the client\n"); + return; + } + + if (window->sync_request_alarm != 0) { + weston_log("Sync request alarm has already been created\n"); + return; + } + + value.hi = 0; + value.lo = 0; + window->sync_request_serial = 0; + xcb_sync_set_counter(wm->conn, window->sync_request_counter, value); + + mask = (XCB_SYNC_CA_COUNTER | XCB_SYNC_CA_VALUE_TYPE | + XCB_SYNC_CA_VALUE | XCB_SYNC_CA_TEST_TYPE | + XCB_SYNC_CA_DELTA | XCB_SYNC_CA_EVENTS); + value_list.counter = window->sync_request_counter; + value_list.valueType = XCB_SYNC_VALUETYPE_ABSOLUTE; + value_list.value.hi = 0; + value_list.value.lo = 1; + value_list.testType = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON; + value_list.delta.hi = 0; + value_list.delta.lo = 1; + value_list.events = 1; + + window->sync_request_alarm = xcb_generate_id(wm->conn); + xcb_sync_create
[PATCH weston] xwayland: Remove transform listener when destroying the wm
Fix a segfault occuring after the last X window was closed. --- src/xwayland/window-manager.c |1 + 1 file changed, 1 insertion(+) diff --git a/src/xwayland/window-manager.c b/src/xwayland/window-manager.c index fd91004..57a5d99 100644 --- a/src/xwayland/window-manager.c +++ b/src/xwayland/window-manager.c @@ -2043,6 +2043,7 @@ weston_wm_destroy(struct weston_wm *wm) wl_list_remove(&wm->selection_listener.link); wl_list_remove(&wm->activate_listener.link); wl_list_remove(&wm->kill_listener.link); + wl_list_remove(&wm->transform_listener.link); free(wm); } -- 1.7.10.4 ___ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel
Re: [PATCH weston 17/18] xwayland: Fix the race condition when mapping a surface
Hi, On Monday, June 10, 2013 14:11 EDT, "MoD" wrote: > I've been poking at XWayland+Weston's XWM recently and wanted to find this > behavior and check that this patch is effective so I could vouch for it, but > I haven't seen something that looks like windows being mapped with the wrong > coordinates or size. Louis-Francis, could you explain how to reproduce this > behavior? I reproduced it by running LibreOffice on a RaspberryPi. A race condition made the menus (sometimes) appears at the wrong spot. The race might be easier to reproduce on slowest hardware (rpi) though. I also found it weird to map the surface without being sure we received MAP_NOTIFY first. > Thanks. > > On 22 de mayo de 2013 at 10:27 AM, ppaala...@gmail.com wrote: > > > >From: Louis-Francis Ratté-Boulianne > > > >Make sure XCB_MAP_NOTIFY has been received and the window id has > >been > >set before mapping the shell surface. It fixes race condition > >making the > >surface appears at wrong coordinates or with wrong size. > >--- > > src/xwayland/window-manager.c | 18 +- > > 1 file changed, 17 insertions(+), 1 deletion(-) > > > >diff --git a/src/xwayland/window-manager.c b/src/xwayland/window- > >manager.c > >index 366f2e0..c2e680b 100644 > >--- a/src/xwayland/window-manager.c > >+++ b/src/xwayland/window-manager.c > >@@ -113,6 +113,7 @@ struct weston_wm_window { > > int decorate; > > int override_redirect; > > int fullscreen; > >+int mapped; > > }; > > > > static struct weston_wm_window * > >@@ -121,6 +122,9 @@ get_wm_window(struct weston_surface *surface); > > static void > > weston_wm_window_schedule_repaint(struct weston_wm_window > >*window); > > > >+static void > >+xserver_map_shell_surface(struct weston_wm *wm, struct > >weston_wm_window *window); > >+ > > const char * > > get_atom_name(xcb_connection_t *c, xcb_atom_t atom) > > { > >@@ -723,6 +727,14 @@ static void > > weston_wm_handle_map_notify(struct weston_wm *wm, > >xcb_generic_event_t *event) > > { > > xcb_map_notify_event_t *map_notify = (xcb_map_notify_event_t *) > >event; > >+struct weston_wm_window *window; > >+ > >+window = hash_table_lookup(wm->window_hash, map_notify->window); > >+ > >+if (window->surface != NULL) > >+xserver_map_shell_surface(wm, window); > >+else > >+window->mapped = 1; > > > > if (our_resource(wm, map_notify->window)) { > > weston_log("XCB_MAP_NOTIFY (window %d, ours)\n", > >@@ -915,6 +927,8 @@ weston_wm_window_create(struct weston_wm *wm, > > window->override_redirect = override; > > window->width = width; > > window->height = height; > >+window->surface = NULL; > >+window->mapped = 0; > > > > hash_table_insert(wm->window_hash, id, window); > > } > >@@ -1874,7 +1888,9 @@ xserver_set_window_id(struct wl_client > >*client, struct wl_resource *resource, > > &window->surface_destroy_listener); > > > > weston_wm_window_schedule_repaint(window); > >-xserver_map_shell_surface(wm, window); > >+ > >+if (window->mapped) > >+xserver_map_shell_surface(wm, window); > > } > > > > const struct xserver_interface xserver_implementation = { > >-- > >1.8.1.5 > > > >___ > >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