[mutter] wayland: Implement stub presentation-time



commit dccc60ec3e04790467cc585e17c25109b887b042
Author: Ivan Molodetskikh <yalterz gmail com>
Date:   Wed Oct 7 12:02:41 2020 +0300

    wayland: Implement stub presentation-time
    
    The presentation-time protocol allows surfaces to get accurate
    timestamps of when their contents were shown on screen.
    
    This commit implements a stub version of the protocol which correctly
    discards all presentation feedback objects (as if the surface contents
    are never shown on screen). Subsequent commits will implement sending
    the presented events to surfaces shown on screen.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>

 src/meson.build                                    |   2 +
 .../meta-wayland-presentation-time-private.h       |  42 +++++++
 src/wayland/meta-wayland-presentation-time.c       | 129 +++++++++++++++++++++
 src/wayland/meta-wayland-surface.c                 |  55 +++++++++
 src/wayland/meta-wayland-surface.h                 |   8 ++
 src/wayland/meta-wayland-versions.h                |   1 +
 src/wayland/meta-wayland.c                         |   2 +
 7 files changed, 239 insertions(+)
---
diff --git a/src/meson.build b/src/meson.build
index fec9d541c3..4b015e6200 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -562,6 +562,8 @@ if have_wayland
     'wayland/meta-wayland-pointer.h',
     'wayland/meta-wayland-popup.c',
     'wayland/meta-wayland-popup.h',
+    'wayland/meta-wayland-presentation-time.c',
+    'wayland/meta-wayland-presentation-time-private.h',
     'wayland/meta-wayland-private.h',
     'wayland/meta-wayland-region.c',
     'wayland/meta-wayland-region.h',
diff --git a/src/wayland/meta-wayland-presentation-time-private.h 
b/src/wayland/meta-wayland-presentation-time-private.h
new file mode 100644
index 0000000000..e8e5bbf79a
--- /dev/null
+++ b/src/wayland/meta-wayland-presentation-time-private.h
@@ -0,0 +1,42 @@
+/*
+ * presentation-time protocol
+ *
+ * Copyright (C) 2020 Ivan Molodetskikh <yalterz gmail com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#ifndef META_WAYLAND_PRESENTATION_TIME_PRIVATE_H
+#define META_WAYLAND_PRESENTATION_TIME_PRIVATE_H
+
+#include <wayland-server.h>
+
+#include "wayland/meta-wayland-types.h"
+
+typedef struct _MetaWaylandPresentationFeedback
+{
+  struct wl_list link;
+  struct wl_resource *resource;
+
+  MetaWaylandSurface *surface;
+} MetaWaylandPresentationFeedback;
+
+void meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor);
+
+void meta_wayland_presentation_feedback_discard (MetaWaylandPresentationFeedback *feedback);
+
+#endif /* META_WAYLAND_PRESENTATION_TIME_PRIVATE_H */
diff --git a/src/wayland/meta-wayland-presentation-time.c b/src/wayland/meta-wayland-presentation-time.c
new file mode 100644
index 0000000000..d54e1e50ce
--- /dev/null
+++ b/src/wayland/meta-wayland-presentation-time.c
@@ -0,0 +1,129 @@
+/*
+ * presentation-time protocol
+ *
+ * Copyright (C) 2020 Ivan Molodetskikh <yalterz gmail com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "meta-wayland-presentation-time-private.h"
+
+#include <glib.h>
+
+#include "wayland/meta-wayland-private.h"
+#include "wayland/meta-wayland-surface.h"
+#include "wayland/meta-wayland-versions.h"
+
+#include "presentation-time-server-protocol.h"
+
+static void
+wp_presentation_feedback_destructor (struct wl_resource *resource)
+{
+  MetaWaylandPresentationFeedback *feedback =
+    wl_resource_get_user_data (resource);
+
+  wl_list_remove (&feedback->link);
+  g_free (feedback);
+}
+
+static void
+wp_presentation_destroy (struct wl_client   *client,
+                         struct wl_resource *resource)
+{
+  wl_resource_destroy (resource);
+}
+
+static void
+wp_presentation_feedback (struct wl_client   *client,
+                          struct wl_resource *resource,
+                          struct wl_resource *surface_resource,
+                          uint32_t            callback_id)
+{
+  MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
+  MetaWaylandSurfaceState *pending;
+  MetaWaylandPresentationFeedback *feedback;
+
+  feedback = g_new0 (MetaWaylandPresentationFeedback, 1);
+  wl_list_init (&feedback->link);
+  feedback->resource = wl_resource_create (client,
+                                           &wp_presentation_feedback_interface,
+                                           wl_resource_get_version (resource),
+                                           callback_id);
+  wl_resource_set_implementation (feedback->resource,
+                                  NULL,
+                                  feedback,
+                                  wp_presentation_feedback_destructor);
+
+  if (surface == NULL)
+    {
+      g_warn_if_reached ();
+      meta_wayland_presentation_feedback_discard (feedback);
+      return;
+    }
+
+  pending = meta_wayland_surface_get_pending_state (surface);
+  wl_list_insert (&pending->presentation_feedback_list, &feedback->link);
+
+  feedback->surface = surface;
+}
+
+static const struct wp_presentation_interface
+meta_wayland_presentation_interface = {
+  wp_presentation_destroy,
+  wp_presentation_feedback,
+};
+
+static void
+wp_presentation_bind (struct wl_client *client,
+                      void             *data,
+                      uint32_t          version,
+                      uint32_t          id)
+{
+  struct wl_resource *resource;
+
+  resource = wl_resource_create (client,
+                                 &wp_presentation_interface,
+                                 version,
+                                 id);
+  wl_resource_set_implementation (resource,
+                                  &meta_wayland_presentation_interface,
+                                  NULL,
+                                  NULL);
+
+  /* Presentation timestamps in Mutter are guaranteed to be CLOCK_MONOTONIC. */
+  wp_presentation_send_clock_id (resource, CLOCK_MONOTONIC);
+}
+
+void
+meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor)
+{
+  if (wl_global_create (compositor->wayland_display,
+                        &wp_presentation_interface,
+                        META_WP_PRESENTATION_VERSION,
+                        NULL,
+                        wp_presentation_bind) == NULL)
+    g_error ("Failed to register a global wp_presentation object");
+}
+
+void
+meta_wayland_presentation_feedback_discard (MetaWaylandPresentationFeedback *feedback)
+{
+  wp_presentation_feedback_send_discarded (feedback->resource);
+  wl_resource_destroy (feedback->resource);
+}
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 66275055fa..db0d7f2f31 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -46,6 +46,7 @@
 #include "wayland/meta-wayland-legacy-xdg-shell.h"
 #include "wayland/meta-wayland-outputs.h"
 #include "wayland/meta-wayland-pointer.h"
+#include "wayland/meta-wayland-presentation-time-private.h"
 #include "wayland/meta-wayland-private.h"
 #include "wayland/meta-wayland-region.h"
 #include "wayland/meta-wayland-seat.h"
@@ -466,6 +467,20 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state)
   state->has_new_buffer_transform = FALSE;
   state->has_new_viewport_src_rect = FALSE;
   state->has_new_viewport_dst_size = FALSE;
+
+  wl_list_init (&state->presentation_feedback_list);
+}
+
+static void
+meta_wayland_surface_state_discard_presentation_feedback (MetaWaylandSurfaceState *state)
+{
+  while (!wl_list_empty (&state->presentation_feedback_list))
+    {
+      MetaWaylandPresentationFeedback *feedback =
+        wl_container_of (state->presentation_feedback_list.next, feedback, link);
+
+      meta_wayland_presentation_feedback_discard (feedback);
+    }
 }
 
 static void
@@ -483,6 +498,8 @@ meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state)
 
   wl_list_for_each_safe (cb, next, &state->frame_callback_list, link)
     wl_resource_destroy (cb->resource);
+
+  meta_wayland_surface_state_discard_presentation_feedback (state);
 }
 
 static void
@@ -592,6 +609,10 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from,
                           to);
     }
 
+  wl_list_insert_list (&to->presentation_feedback_list,
+                       &from->presentation_feedback_list);
+  wl_list_init (&from->presentation_feedback_list);
+
   meta_wayland_surface_state_reset (from);
 }
 
@@ -627,6 +648,19 @@ meta_wayland_surface_state_class_init (MetaWaylandSurfaceStateClass *klass)
                   G_TYPE_NONE, 0);
 }
 
+static void
+meta_wayland_surface_discard_presentation_feedback (MetaWaylandSurface *surface)
+{
+  while (!wl_list_empty (&surface->presentation_time.feedback_list))
+    {
+      MetaWaylandPresentationFeedback *feedback =
+        wl_container_of (surface->presentation_time.feedback_list.next,
+                         feedback, link);
+
+      meta_wayland_presentation_feedback_discard (feedback);
+    }
+}
+
 static void
 meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
                                   MetaWaylandSurfaceState *state)
@@ -755,6 +789,16 @@ meta_wayland_surface_apply_state (MetaWaylandSurface      *surface,
         surface->input_region = NULL;
     }
 
+  /*
+   * A new commit indicates a new content update, so any previous
+   * content update did not go on screen and needs to be discarded.
+   */
+  meta_wayland_surface_discard_presentation_feedback (surface);
+
+  wl_list_insert_list (&surface->presentation_time.feedback_list,
+                       &state->presentation_feedback_list);
+  wl_list_init (&state->presentation_feedback_list);
+
   if (surface->role)
     {
       meta_wayland_surface_role_apply_state (surface->role, state);
@@ -870,6 +914,13 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
       MetaWaylandSurfaceState *cached_state;
 
       cached_state = meta_wayland_surface_ensure_cached_state (surface);
+
+      /*
+       * A new commit indicates a new content update, so any previous
+       * cached content update did not go on screen and needs to be discarded.
+       */
+      meta_wayland_surface_state_discard_presentation_feedback (cached_state);
+
       meta_wayland_surface_state_merge_into (pending, cached_state);
     }
   else
@@ -1350,6 +1401,8 @@ wl_surface_destructor (struct wl_resource *resource)
                          link)
     wl_resource_destroy (cb->resource);
 
+  meta_wayland_surface_discard_presentation_feedback (surface);
+
   if (surface->resource)
     wl_resource_set_user_data (surface->resource, NULL);
 
@@ -1397,6 +1450,8 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor,
   surface->outputs = g_hash_table_new (NULL, NULL);
   surface->shortcut_inhibited_seats = g_hash_table_new (NULL, NULL);
 
+  wl_list_init (&surface->presentation_time.feedback_list);
+
   meta_wayland_compositor_notify_surface_id (compositor, id, surface);
 
   return surface;
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 0c7298886d..1fabd57dd6 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -120,6 +120,9 @@ struct _MetaWaylandSurfaceState
   gboolean has_new_viewport_dst_size;
   int viewport_dst_width;
   int viewport_dst_height;
+
+  /* presentation-time */
+  struct wl_list presentation_feedback_list;
 };
 
 struct _MetaWaylandDragDestFuncs
@@ -227,6 +230,11 @@ struct _MetaWaylandSurface
 
   /* table of seats for which shortcuts are inhibited */
   GHashTable *shortcut_inhibited_seats;
+
+  /* presentation-time */
+  struct {
+    struct wl_list feedback_list;
+  } presentation_time;
 };
 
 void                meta_wayland_shell_init     (MetaWaylandCompositor *compositor);
diff --git a/src/wayland/meta-wayland-versions.h b/src/wayland/meta-wayland-versions.h
index bf891d99a1..8f71c19dce 100644
--- a/src/wayland/meta-wayland-versions.h
+++ b/src/wayland/meta-wayland-versions.h
@@ -57,5 +57,6 @@
 #define META_WP_VIEWPORTER_VERSION          1
 #define META_GTK_PRIMARY_SELECTION_VERSION  1
 #define META_ZWP_PRIMARY_SELECTION_V1_VERSION 1
+#define META_WP_PRESENTATION_VERSION        1
 
 #endif
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index ef7a495b5c..45bc7ace09 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -39,6 +39,7 @@
 #include "wayland/meta-wayland-inhibit-shortcuts-dialog.h"
 #include "wayland/meta-wayland-inhibit-shortcuts.h"
 #include "wayland/meta-wayland-outputs.h"
+#include "wayland/meta-wayland-presentation-time-private.h"
 #include "wayland/meta-wayland-private.h"
 #include "wayland/meta-wayland-region.h"
 #include "wayland/meta-wayland-seat.h"
@@ -444,6 +445,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *compositor)
   meta_wayland_surface_inhibit_shortcuts_dialog_init ();
   meta_wayland_text_input_init (compositor);
   meta_wayland_gtk_text_input_init (compositor);
+  meta_wayland_init_presentation_time (compositor);
 
   /* Xwayland specific protocol, needs to be filtered out for all other clients */
   if (meta_xwayland_grab_keyboard_init (compositor))


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]