From: Pekka Paalanen <[email protected]>

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 <[email protected]>
v3 Reviewed-by: Mario Kleiner <[email protected]>
---
 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 & 0xffffffff,
+                                            ts->tv_nsec,
+                                            refresh_nsec,
+                                            seq >> 32, seq & 0xffffffff,
+                                            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(surface);
+       weston_presentation_feedback_discard_list(&surface->feedback_list);
 }
 
 WL_EXPORT void
@@ -1927,6 +2004,10 @@ weston_output_repaint(struct weston_output *output)
                        wl_list_insert_list(&frame_callback_list,
                                            &ev->surface->frame_callback_list);
                        wl_list_init(&ev->surface->frame_callback_list);
+
+                       wl_list_insert_list(&output->feedback_list,
+                                           &ev->surface->feedback_list);
+                       wl_list_init(&ev->surface->feedback_list);
                }
        }
 
@@ -1981,6 +2062,12 @@ weston_output_finish_frame(struct weston_output *output,
        struct wl_event_loop *loop =
                wl_display_get_event_loop(compositor->wl_display);
        int fd, r;
+       uint32_t refresh_nsec;
+
+       refresh_nsec = 1000000000000UL / output->current_mode->refresh;
+       weston_presentation_feedback_present_list(&output->feedback_list,
+                                                 output, refresh_nsec, stamp,
+                                                 0);
 
        output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
 
@@ -2274,6 +2361,16 @@ weston_surface_commit_state(struct weston_surface 
*surface,
        wl_list_insert_list(&surface->frame_callback_list,
                            &state->frame_callback_list);
        wl_list_init(&state->frame_callback_list);
+
+       /* XXX:
+        * What should happen with a feedback request, if there
+        * is no wl_buffer attached for this commit?
+        */
+
+       /* presentation.feedback */
+       wl_list_insert_list(&surface->feedback_list,
+                           &state->feedback_list);
+       wl_list_init(&state->feedback_list);
 }
 
 static void
@@ -2501,6 +2598,8 @@ weston_subsurface_commit_to_cache(struct 
weston_subsurface *sub)
                                                surface->pending.buffer);
                weston_buffer_reference(&sub->cached_buffer_ref,
                                        surface->pending.buffer);
+               weston_presentation_feedback_discard_list(
+                                       &sub->cached.feedback_list);
        }
        sub->cached.sx += surface->pending.sx;
        sub->cached.sy += surface->pending.sy;
@@ -2522,6 +2621,10 @@ weston_subsurface_commit_to_cache(struct 
weston_subsurface *sub)
                            &surface->pending.frame_callback_list);
        wl_list_init(&surface->pending.frame_callback_list);
 
+       wl_list_insert_list(&sub->cached.feedback_list,
+                           &surface->pending.feedback_list);
+       wl_list_init(&surface->pending.feedback_list);
+
        sub->has_cached_data = 1;
 }
 
@@ -3254,6 +3357,8 @@ weston_output_destroy(struct weston_output *output)
 
        output->destroying = 1;
 
+       weston_presentation_feedback_discard_list(&output->feedback_list);
+
        weston_compositor_remove_output(output->compositor, output);
        wl_list_remove(&output->link);
 
@@ -3462,6 +3567,7 @@ weston_output_init(struct weston_output *output, struct 
weston_compositor *c,
        wl_signal_init(&output->destroy_signal);
        wl_list_init(&output->animation_list);
        wl_list_init(&output->resource_list);
+       wl_list_init(&output->feedback_list);
 
        output->id = ffs(~output->compositor->output_id_pool) - 1;
        output->compositor->output_id_pool |= 1 << output->id;
@@ -3738,6 +3844,29 @@ bind_scaler(struct wl_client *client,
 }
 
 static void
+presentation_feedback_destroy(struct wl_client *client,
+                             struct wl_resource *feedback_resource)
+{
+       wl_resource_destroy(feedback_resource);
+}
+
+static const struct presentation_feedback_interface
+presentation_feedback_implementation = {
+       presentation_feedback_destroy
+};
+
+static void
+destroy_presentation_feedback(struct wl_resource *feedback_resource)
+{
+       struct weston_presentation_feedback *feedback;
+
+       feedback = wl_resource_get_user_data(feedback_resource);
+
+       wl_list_remove(&feedback->link);
+       free(feedback);
+}
+
+static void
 presentation_destroy(struct wl_client *client, struct wl_resource *resource)
 {
        wl_resource_destroy(resource);
@@ -3745,12 +3874,38 @@ presentation_destroy(struct wl_client *client, struct 
wl_resource *resource)
 
 static void
 presentation_feedback(struct wl_client *client,
-                     struct wl_resource *resource,
-                     struct wl_resource *surface,
+                     struct wl_resource *presentation_resource,
+                     struct wl_resource *surface_resource,
                      uint32_t callback)
 {
-       wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_METHOD,
-                              "presentation_feedback unimplemented");
+       struct weston_surface *surface;
+       struct weston_presentation_feedback *feedback;
+
+       surface = wl_resource_get_user_data(surface_resource);
+
+       feedback = calloc(1, sizeof *feedback);
+       if (!feedback)
+               goto err_calloc;
+
+       feedback->resource = wl_resource_create(client,
+                                       &presentation_feedback_interface,
+                                       1, callback);
+       if (!feedback->resource)
+               goto err_create;
+
+       wl_resource_set_implementation(feedback->resource,
+                                      &presentation_feedback_implementation,
+                                      feedback, destroy_presentation_feedback);
+
+       wl_list_insert(&surface->pending.feedback_list, &feedback->link);
+
+       return;
+
+err_create:
+       free(feedback);
+
+err_calloc:
+       wl_client_post_no_memory(client);
 }
 
 static const struct presentation_interface presentation_implementation = {
diff --git a/src/compositor.h b/src/compositor.h
index ba7e6fc..548ffe5 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -205,6 +205,7 @@ struct weston_output {
        uint32_t frame_time; /* presentation timestamp in milliseconds */
        int disable_planes;
        int destroying;
+       struct wl_list feedback_list;
 
        char *make, *model, *serial_number;
        uint32_t subpixel;
@@ -835,6 +836,9 @@ struct weston_surface_state {
        /* wl_surface.frame */
        struct wl_list frame_callback_list;
 
+       /* presentation.feedback */
+       struct wl_list feedback_list;
+
        /* wl_surface.set_buffer_transform */
        /* wl_surface.set_scaling_factor */
        /* wl_viewport.set */
@@ -874,6 +878,7 @@ struct weston_surface {
        uint32_t output_mask;
 
        struct wl_list frame_callback_list;
+       struct wl_list feedback_list;
 
        struct weston_buffer_reference buffer_ref;
        struct weston_buffer_viewport buffer_viewport;
-- 
1.9.3

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

Reply via email to