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>
This commit is contained in:
Ivan Molodetskikh 2020-10-08 15:39:22 +03:00 committed by Marge Bot
parent dccc60ec3e
commit bb57f35296
4 changed files with 154 additions and 1 deletions

View File

@ -309,7 +309,19 @@ ns2us (int64_t ns)
static inline int64_t static inline int64_t
s2us (int64_t s) 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 static inline int64_t

View File

@ -25,6 +25,7 @@
#include <wayland-server.h> #include <wayland-server.h>
#include "clutter/clutter.h"
#include "wayland/meta-wayland-types.h" #include "wayland/meta-wayland-types.h"
typedef struct _MetaWaylandPresentationFeedback 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_discard (MetaWaylandPresentationFeedback *feedback);
void meta_wayland_presentation_feedback_present (MetaWaylandPresentationFeedback *feedback,
ClutterFrameInfo *frame_info,
MetaWaylandOutput *output);
#endif /* META_WAYLAND_PRESENTATION_TIME_PRIVATE_H */ #endif /* META_WAYLAND_PRESENTATION_TIME_PRIVATE_H */

View File

@ -28,6 +28,7 @@
#include "wayland/meta-wayland-private.h" #include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-surface.h" #include "wayland/meta-wayland-surface.h"
#include "wayland/meta-wayland-outputs.h"
#include "wayland/meta-wayland-versions.h" #include "wayland/meta-wayland-versions.h"
#include "presentation-time-server-protocol.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); wp_presentation_feedback_send_discarded (feedback->resource);
wl_resource_destroy (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);
}

View File

@ -234,6 +234,17 @@ struct _MetaWaylandSurface
/* presentation-time */ /* presentation-time */
struct { struct {
struct wl_list feedback_list; 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; } presentation_time;
}; };