mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 01:20:42 -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
|
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
|
||||||
|
@ -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 */
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user