[mutter] wayland: Add presentation_feedback_present()



commit bb57f352969ca3fcb40dc0e51713db2a7fda988b
Author: Ivan Molodetskikh <yalterz gmail com>
Date:   Thu Oct 8 15:39:22 2020 +0300

    wayland: Add presentation_feedback_present()
    
    Regarding the sequence = 0 fallback: in some cases (moving a cursor
    plane on atomic amdgpu) we get sequence = 0 in the page flip callback.
    This seems like an amdgpu bug, so work around it by assuming a sequence
    delta of 1 (it is equal to 1 because of the sequence != 0 check above).
    
    Sequence can also legitimately be 0 if we're lucky during the 32-bit
    overflow, in which case assuming a delta of 1 will give more or less
    reasonable values on this and next presentation, after which it'll be
    back to normal.
    
    Sequence is also 0 on mode set fallback and when running nested, in
    which case assuming a delta of 1 every frame is the best we can do.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1484>

 clutter/clutter/clutter-private.h                  |  14 ++-
 .../meta-wayland-presentation-time-private.h       |   5 +
 src/wayland/meta-wayland-presentation-time.c       | 125 +++++++++++++++++++++
 src/wayland/meta-wayland-surface.h                 |  11 ++
 4 files changed, 154 insertions(+), 1 deletion(-)
---
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
index f596ded9c7..d64625a196 100644
--- a/clutter/clutter/clutter-private.h
+++ b/clutter/clutter/clutter-private.h
@@ -309,7 +309,19 @@ ns2us (int64_t ns)
 static inline int64_t
 s2us (int64_t s)
 {
-  return ms2us (s * 1000);
+  return s * G_USEC_PER_SEC;
+}
+
+static inline int64_t
+us2s (int64_t us)
+{
+  return us / G_USEC_PER_SEC;
+}
+
+static inline int64_t
+s2ns (int64_t s)
+{
+  return us2ns (s2us (s));
 }
 
 static inline int64_t
diff --git a/src/wayland/meta-wayland-presentation-time-private.h 
b/src/wayland/meta-wayland-presentation-time-private.h
index e8e5bbf79a..f13e42c0f7 100644
--- a/src/wayland/meta-wayland-presentation-time-private.h
+++ b/src/wayland/meta-wayland-presentation-time-private.h
@@ -25,6 +25,7 @@
 
 #include <wayland-server.h>
 
+#include "clutter/clutter.h"
 #include "wayland/meta-wayland-types.h"
 
 typedef struct _MetaWaylandPresentationFeedback
@@ -39,4 +40,8 @@ void meta_wayland_init_presentation_time (MetaWaylandCompositor *compositor);
 
 void meta_wayland_presentation_feedback_discard (MetaWaylandPresentationFeedback *feedback);
 
+void meta_wayland_presentation_feedback_present (MetaWaylandPresentationFeedback *feedback,
+                                                 ClutterFrameInfo                *frame_info,
+                                                 MetaWaylandOutput               *output);
+
 #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
index d54e1e50ce..ef74d11504 100644
--- a/src/wayland/meta-wayland-presentation-time.c
+++ b/src/wayland/meta-wayland-presentation-time.c
@@ -28,6 +28,7 @@
 
 #include "wayland/meta-wayland-private.h"
 #include "wayland/meta-wayland-surface.h"
+#include "wayland/meta-wayland-outputs.h"
 #include "wayland/meta-wayland-versions.h"
 
 #include "presentation-time-server-protocol.h"
@@ -127,3 +128,127 @@ meta_wayland_presentation_feedback_discard (MetaWaylandPresentationFeedback *fee
   wp_presentation_feedback_send_discarded (feedback->resource);
   wl_resource_destroy (feedback->resource);
 }
+
+static void
+maybe_update_presentation_sequence (MetaWaylandSurface *surface,
+                                    ClutterFrameInfo   *frame_info,
+                                    MetaWaylandOutput  *output)
+{
+  unsigned int sequence_delta;
+
+  if (!surface->presentation_time.needs_sequence_update)
+    return;
+
+  surface->presentation_time.needs_sequence_update = FALSE;
+
+  if (!(frame_info->flags & CLUTTER_FRAME_INFO_FLAG_VSYNC))
+    goto invalid_sequence;
+
+  /* Getting sequence = 0 after sequence = UINT_MAX is likely valid (32-bit
+   * overflow, on a 144 Hz display that's ~173 days of operation). Getting it
+   * otherwise is usually a driver bug.
+   */
+  if (frame_info->sequence == 0 &&
+      !(surface->presentation_time.is_last_output_sequence_valid &&
+        surface->presentation_time.last_output_sequence == UINT_MAX))
+    {
+      g_warning_once ("Invalid sequence for VSYNC frame info");
+      goto invalid_sequence;
+    }
+
+  if (surface->presentation_time.is_last_output_sequence_valid &&
+      surface->presentation_time.last_output == output)
+    {
+      sequence_delta =
+        frame_info->sequence - surface->presentation_time.last_output_sequence;
+    }
+  else
+    {
+      /* Sequence generally has different base between different outputs, but we
+       * want to keep it monotonic and without sudden jumps when the surface is
+       * moved between outputs. This matches the Xorg behavior with regards to
+       * the GLX_OML_sync_control implementation.
+       */
+      sequence_delta = 1;
+    }
+
+  surface->presentation_time.sequence += sequence_delta;
+  surface->presentation_time.last_output = output;
+  surface->presentation_time.last_output_sequence = frame_info->sequence;
+  surface->presentation_time.is_last_output_sequence_valid = TRUE;
+
+  return;
+
+invalid_sequence:
+  surface->presentation_time.sequence += 1;
+  surface->presentation_time.last_output = output;
+  surface->presentation_time.is_last_output_sequence_valid = FALSE;
+}
+
+void
+meta_wayland_presentation_feedback_present (MetaWaylandPresentationFeedback *feedback,
+                                            ClutterFrameInfo                *frame_info,
+                                            MetaWaylandOutput               *output)
+{
+  MetaWaylandSurface *surface = feedback->surface;
+  int64_t time_us = frame_info->presentation_time;
+  uint64_t time_s;
+  uint32_t tv_sec_hi, tv_sec_lo, tv_nsec;
+  uint32_t refresh_interval_ns;
+  uint32_t seq_hi, seq_lo;
+  uint32_t flags;
+  GList *l;
+
+  if (output == NULL)
+    {
+      g_warning ("Output is NULL while sending presentation feedback");
+      meta_wayland_presentation_feedback_discard (feedback);
+      return;
+    }
+
+  time_s = us2s (time_us);
+
+  tv_sec_hi = time_s >> 32;
+  tv_sec_lo = time_s;
+  tv_nsec = (uint32_t) us2ns (time_us - s2us (time_s));
+
+  refresh_interval_ns = (uint32_t) (0.5 + s2ns (1) / frame_info->refresh_rate);
+
+  maybe_update_presentation_sequence (surface, frame_info, output);
+
+  seq_hi = surface->presentation_time.sequence >> 32;
+  seq_lo = surface->presentation_time.sequence;
+
+  flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION;
+
+  if (frame_info->flags & CLUTTER_FRAME_INFO_FLAG_HW_CLOCK)
+    flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+
+  if (frame_info->flags & CLUTTER_FRAME_INFO_FLAG_ZERO_COPY)
+    flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
+
+  if (frame_info->flags & CLUTTER_FRAME_INFO_FLAG_VSYNC)
+    flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC;
+
+  for (l = output->resources; l; l = l->next)
+    {
+      struct wl_resource *output_resource = l->data;
+
+      if (feedback->resource->client == output_resource->client)
+        {
+          wp_presentation_feedback_send_sync_output (feedback->resource,
+                                                     output_resource);
+        }
+    }
+
+  wp_presentation_feedback_send_presented (feedback->resource,
+                                           tv_sec_hi,
+                                           tv_sec_lo,
+                                           tv_nsec,
+                                           refresh_interval_ns,
+                                           seq_hi,
+                                           seq_lo,
+                                           flags);
+
+  wl_resource_destroy (feedback->resource);
+}
diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h
index 1fabd57dd6..22afb0ae17 100644
--- a/src/wayland/meta-wayland-surface.h
+++ b/src/wayland/meta-wayland-surface.h
@@ -234,6 +234,17 @@ struct _MetaWaylandSurface
   /* presentation-time */
   struct {
     struct wl_list feedback_list;
+    MetaWaylandOutput *last_output;
+    unsigned int last_output_sequence;
+    gboolean is_last_output_sequence_valid;
+    gboolean needs_sequence_update;
+
+    /*
+     * Sequence has an undefined base, but is guaranteed to monotonically
+     * increase. DRM only gives us a 32-bit sequence, so we compute our own
+     * delta to update our own 64-bit sequence.
+     */
+    uint64_t sequence;
   } presentation_time;
 };
 


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