mirror of
https://github.com/brl/mutter.git
synced 2024-11-12 17:27:03 -05:00
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:
parent
dccc60ec3e
commit
bb57f35296
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user