"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 << 32;
+               free(reply);
+       } else {
+               xcb_sync_int64_t value;
+
+               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.valueType = XCB_SYNC_VALUETYPE_RELATIVE;
        value_list.value.hi = 0;
        value_list.value.lo = 1;
        value_list.testType = XCB_SYNC_TESTTYPE_POSITIVE_COMPARISON;
@@ -798,7 +844,7 @@ sync_request_timeout(void *data)
 
        weston_log("Sync request timed out. Temporarily disabling syncing.\n");
        window->sync_disabled = 1;
-       window->wait_redraw = 0;
+       weston_wm_window_update_frozen(window);
 
        if (window->configure_pending && !window->configure_source) {
                window->configure_source =
@@ -814,8 +860,17 @@ weston_wm_window_send_sync_request(struct weston_wm_window 
*window)
 {
        xcb_client_message_event_t client_message;
        struct weston_wm *wm = window->wm;
-
-       window->sync_request_serial++;
+       int64_t wait_serial;
+
+       /* For the old style of _NET_WM_SYNC_REQUEST_COUNTER, we just have to
+        * increase the value, but for the new "extended" style we need to
+        * pick an even (unfrozen) value sufficiently ahead of the last serial
+        * that we received from the client; the same code still works
+        * for the old style. The increment of 240 is specified by the EWMH
+        * and is (1 second) * (60fps) * (an increment of 4 per frame).
+        */
+       wait_serial = window->sync_request_serial + 240;
+       window->sync_request_wait_serial = wait_serial;
 
        client_message.response_type = XCB_CLIENT_MESSAGE;
        client_message.format = 32;
@@ -823,15 +878,105 @@ weston_wm_window_send_sync_request(struct 
weston_wm_window *window)
        client_message.type = wm->atom.wm_protocols;
        client_message.data.data32[0] = wm->atom.net_wm_sync_request;
        client_message.data.data32[1] = XCB_TIME_CURRENT_TIME;
-       client_message.data.data32[2] = window->sync_request_serial & 
0xffffffff;
-       client_message.data.data32[3] = (window->sync_request_serial >> 32) & 
0xffffffff;
+       client_message.data.data32[2] = wait_serial & 0xffffffff;
+       client_message.data.data32[3] = (wait_serial >> 32) & 0xffffffff;
+       client_message.data.data32[4] = window->sync_request_counter_extended;
 
-       weston_log("SEND SYNC REQUEST %llu\n", window->sync_request_serial);
+       weston_log("SEND SYNC REQUEST %llu\n", wait_serial);
 
        xcb_send_event(wm->conn, 0, window->id, 0,
                       (char *) &client_message);
 
        wl_event_source_timer_update(window->sync_request_timer, 1000);
+       weston_wm_window_update_frozen(window);
+}
+
+static void
+weston_wm_window_send_frame_drawn(struct weston_wm_window *window, uint32_t 
msecs)
+{
+       xcb_client_message_event_t client_message;
+       struct weston_wm *wm = window->wm;
+       uint64_t usecs = msecs * 1000;
+
+       /* FIXME keep track of request serial for this frame */
+
+       client_message.response_type = XCB_CLIENT_MESSAGE;
+       client_message.format = 32;
+       client_message.window = window->id;
+       client_message.type = wm->atom.net_wm_frame_drawn;
+       client_message.data.data32[0] = window->sync_request_serial & 
0xffffffff;
+       client_message.data.data32[1] = (window->sync_request_serial >> 32) & 
0xffffffff;
+       client_message.data.data32[2] = usecs & 0xffffffff;
+       client_message.data.data32[3] = (usecs >> 32) & 0xffffffff;
+
+       weston_log("SEND FRAME DRAWN %llu %u\n", window->sync_request_serial, 
msecs);
+ 
+       xcb_send_event(wm->conn, 0, window->id, 0,
+                      (char *) &client_message);
+}
+
+static void
+weston_wm_window_send_frame_timings(struct weston_wm_window *window, uint32_t 
msecs)
+{
+       xcb_client_message_event_t client_message;
+       struct weston_wm *wm = window->wm;
+       int refresh_rate, refresh_interval;
+       uint64_t usecs = msecs * 1000;
+       uint32_t offset = 0;
+
+       if (usecs != 0) {
+               offset = usecs - window->frame_time;
+               if (offset == 0)
+                       offset = 1;
+       }
+
+       refresh_rate = window->surface->output->current->refresh;
+       if (refresh_rate >= 1)
+               refresh_interval = 1000000000 / refresh_rate;
+       else
+               refresh_interval = 0;
+
+       client_message.response_type = XCB_CLIENT_MESSAGE;
+       client_message.format = 32;
+       client_message.window = window->id;
+       client_message.type = wm->atom.net_wm_frame_timings;
+       client_message.data.data32[0] = window->sync_request_serial & 
0xffffffff;
+       client_message.data.data32[1] = (window->sync_request_serial >> 32) & 
0xffffffff;
+       client_message.data.data32[2] = offset;
+       client_message.data.data32[3] = refresh_interval;
+       client_message.data.data32[4] = 0x80000000;
+
+       weston_log("SEND FRAME TIMINGS %llu %u\n", window->sync_request_serial, 
msecs);
+ 
+       xcb_send_event(wm->conn, 0, window->id, 0,
+                      (char *) &client_message);
+}
+
+static void
+weston_wm_window_repaint_notify(struct wl_listener *listener, void *data)
+{
+        struct weston_wm_window *window =
+                container_of(listener, struct weston_wm_window, 
repaint_listener);
+       struct weston_output *output = window->surface->output;
+       uint32_t msecs = (uint32_t) data;
+
+       window->frame_time = msecs * 1000;
+       window->needs_frame_drawn = 0;
+       wl_list_remove(&listener->link);
+       wl_signal_add(&output->frame_signal, &window->frame_listener);
+       weston_wm_window_send_frame_drawn(window, msecs);
+}
+
+static void
+weston_wm_window_frame_notify(struct wl_listener *listener, void *data)
+{
+        struct weston_wm_window *window =
+                container_of(listener, struct weston_wm_window, 
frame_listener);
+       struct weston_output *output = data;
+       uint32_t msecs = output->frame_time;
+
+       wl_list_remove(&listener->link);
+       weston_wm_window_send_frame_timings(window, msecs);
 }
 
 static void
@@ -1110,6 +1255,17 @@ weston_wm_window_schedule_repaint(struct 
weston_wm_window *window)
 }
 
 static void
+weston_wm_window_schedule_redraw(struct weston_wm_window *window)
+{
+       struct weston_output *output = window->surface->output;
+
+       window->needs_frame_drawn = 1;
+       wl_signal_add(&output->repaint_signal, &window->repaint_listener);
+       weston_surface_schedule_repaint(window->surface);
+}
+
+
+static void
 weston_wm_handle_property_notify(struct weston_wm *wm, xcb_generic_event_t 
*event)
 {
        xcb_property_notify_event_t *property_notify =
@@ -1165,11 +1321,16 @@ weston_wm_window_create(struct weston_wm *wm,
        window->map_notified = 0;
        window->mapped = 0;
        window->sync_request_counter = 0;
+       window->sync_request_counter_extended = 0;
        window->sync_request_alarm = 0;
        window->configure_pending = 0;
+       window->needs_frame_drawn = 0;
        window->sync_disabled = 0;
        window->wait_redraw = 0;
 
+       window->frame_listener.notify = weston_wm_window_frame_notify;
+       window->repaint_listener.notify = weston_wm_window_repaint_notify;
+
        geometry_reply = xcb_get_geometry_reply(wm->conn, geometry_cookie, 
NULL);
        /* technically we should use XRender and check the visual format's
        alpha_mask, but checking depth is simpler and works in all known cases 
*/
@@ -1394,6 +1555,8 @@ weston_wm_handle_sync_alarm_notify(struct weston_wm *wm,
                (xcb_sync_alarm_notify_event_t *) event;
        struct weston_wm_window *window;
        int64_t counter_value = 0;
+       int no_delay_frame = 0;
+       int needs_frame_drawn = 0;
 
        counter_value = alarm_event->counter_value.lo;
        counter_value += (int64_t) alarm_event->counter_value.hi << 32;
@@ -1407,15 +1570,31 @@ weston_wm_handle_sync_alarm_notify(struct weston_wm *wm,
                return;
        }
 
-       wl_event_source_timer_update(window->sync_request_timer, 0);
-       window->sync_disabled = 0;
-       window->wait_redraw = 0;
+       if (window->sync_request_counter_extended && (counter_value % 2) == 0) {
+               needs_frame_drawn = 1;
+               no_delay_frame = (counter_value == window->sync_request_serial 
+ 1);
+       }
 
-       if (window->configure_pending && !window->configure_source) {
+       window->sync_request_serial = counter_value;
+
+       if (window->sync_request_serial >= window->sync_request_wait_serial) {
+               wl_event_source_timer_update(window->sync_request_timer, 0);
+               window->sync_disabled = 0;
+       }
+
+       weston_wm_window_update_frozen(window);
+
+       if (window->configure_pending && !window->configure_source &&
+           !window->wait_redraw) {
                window->configure_source =
                        wl_event_loop_add_idle(wm->server->loop,
                                               weston_wm_window_configure, 
window);
        }
+
+       if (no_delay_frame || (needs_frame_drawn &&
+           counter_value >= window->sync_request_wait_serial)) {
+               weston_wm_window_schedule_redraw(window);
+       }
 }
 
 enum cursor_type {
@@ -1769,6 +1948,8 @@ weston_wm_get_resources(struct weston_wm *wm)
 
                { "_NET_WM_SYNC_REQUEST", F(atom.net_wm_sync_request) },
                { "_NET_WM_SYNC_REQUEST_COUNTER", 
F(atom.net_wm_sync_request_counter) },
+               { "_NET_WM_FRAME_DRAWN", F(atom.net_wm_frame_drawn) },
+               { "_NET_WM_FRAME_TIMINGS", F(atom.net_wm_frame_timings) },
 
                { "_NET_WM_MOVERESIZE", F(atom.net_wm_moveresize) },
                { "_NET_SUPPORTING_WM_CHECK",
@@ -1930,7 +2111,7 @@ weston_wm_create(struct weston_xserver *wxs)
        xcb_screen_iterator_t s;
        uint32_t values[1];
        int sv[2];
-       xcb_atom_t supported[5];
+       xcb_atom_t supported[6];
 
        wm = malloc(sizeof *wm);
        if (wm == NULL)
@@ -2002,6 +2183,7 @@ weston_wm_create(struct weston_xserver *wxs)
        supported[2] = wm->atom.net_wm_state_fullscreen;
        supported[3] = wm->atom.net_wm_sync_request;
        supported[4] = wm->atom.net_wm_sync_request_counter;
+       supported[5] = wm->atom.net_wm_frame_drawn;
        xcb_change_property(wm->conn,
                            XCB_PROP_MODE_REPLACE,
                            wm->screen->root,
@@ -2080,7 +2262,6 @@ weston_wm_window_configure(void *data)
        int x, y, width, height;
 
        if (window->sync_request_counter != 0 && !window->sync_disabled) {
-               window->wait_redraw = 1;
                weston_wm_window_send_sync_request(window);
        }
 
diff --git a/src/xwayland/xwayland.h b/src/xwayland/xwayland.h
index c609cf2..c07cfec 100644
--- a/src/xwayland/xwayland.h
+++ b/src/xwayland/xwayland.h
@@ -113,6 +113,8 @@ struct weston_wm {
                xcb_atom_t               net_wm_moveresize;
                xcb_atom_t               net_wm_sync_request;
                xcb_atom_t               net_wm_sync_request_counter;
+               xcb_atom_t               net_wm_frame_drawn;
+               xcb_atom_t               net_wm_frame_timings;
                xcb_atom_t               net_supporting_wm_check;
                xcb_atom_t               net_supported;
                xcb_atom_t               motif_wm_hints;
-- 
1.8.3.1

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to