[mutter] wayland: Add presentation_feedback_present()
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] wayland: Add presentation_feedback_present()
- Date: Mon, 8 Mar 2021 10:19:07 +0000 (UTC)
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]