mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-28 06:21:14 +00:00
53616a73e9
This attempts to improve the accuracy for the "presentation_time" of an individual GdkFrameTimings. That information is currently filled in as soon as we get a frame callback. However, if presentation-time wayland protocol is available, that will be used to supliment a more accurate time which may improve future presentation-time predictions within GdkFrameClockIdle. The protocol states that all related and sub surfaces will receive the same information so it is safe that this could be registered for more than just the toplevel. The information becomes idempotent.
153 lines
4.8 KiB
C
153 lines
4.8 KiB
C
#include "config.h"
|
|
|
|
#include <gdk/gdkframeclockprivate.h>
|
|
|
|
#include "gdkwaylandpresentationtime-private.h"
|
|
|
|
typedef struct _GdkWaylandPresentationFrame
|
|
{
|
|
GdkWaylandPresentationTime *self;
|
|
struct wp_presentation_feedback *feedback;
|
|
GdkFrameClock *frame_clock;
|
|
gint64 frame_number;
|
|
} GdkWaylandPresentationFrame;
|
|
|
|
static void
|
|
gdk_wayland_presentation_frame_free (GdkWaylandPresentationFrame *frame)
|
|
{
|
|
g_clear_pointer (&frame->feedback, wp_presentation_feedback_destroy);
|
|
g_clear_object (&frame->frame_clock);
|
|
frame->self = NULL;
|
|
g_free (frame);
|
|
}
|
|
|
|
struct _GdkWaylandPresentationTime
|
|
{
|
|
GdkWaylandDisplay *display;
|
|
GPtrArray *frames;
|
|
};
|
|
|
|
GdkWaylandPresentationTime *
|
|
gdk_wayland_presentation_time_new (GdkWaylandDisplay *display)
|
|
{
|
|
GdkWaylandPresentationTime *self;
|
|
|
|
g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);
|
|
|
|
self = g_new0 (GdkWaylandPresentationTime, 1);
|
|
self->display = g_object_ref (display);
|
|
self->frames = g_ptr_array_new_with_free_func ((GDestroyNotify)gdk_wayland_presentation_frame_free);
|
|
|
|
return self;
|
|
}
|
|
|
|
void
|
|
gdk_wayland_presentation_time_free (GdkWaylandPresentationTime *self)
|
|
{
|
|
g_clear_pointer (&self->frames, g_ptr_array_unref);
|
|
g_clear_object (&self->display);
|
|
g_free (self);
|
|
}
|
|
|
|
static gint64
|
|
time_from_wayland (uint32_t tv_sec_hi,
|
|
uint32_t tv_sec_lo,
|
|
uint32_t tv_nsec)
|
|
{
|
|
guint64 t = tv_sec_hi;
|
|
t <<= 32;
|
|
t |= tv_sec_lo;
|
|
t *= G_USEC_PER_SEC;
|
|
t += tv_nsec / 1000L;
|
|
return (gint64)t;
|
|
}
|
|
|
|
static void
|
|
gdk_wayland_presentation_feedback_sync_output (void *data,
|
|
struct wp_presentation_feedback *feedback,
|
|
struct wl_output *output)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_wayland_presentation_feedback_presented (void *data,
|
|
struct wp_presentation_feedback *feedback,
|
|
uint32_t tv_sec_hi,
|
|
uint32_t tv_sec_lo,
|
|
uint32_t tv_nsec,
|
|
uint32_t refresh,
|
|
uint32_t seq_hi,
|
|
uint32_t seq_lo,
|
|
uint32_t flags)
|
|
{
|
|
GdkWaylandPresentationFrame *frame = data;
|
|
GdkWaylandPresentationTime *self;
|
|
GdkFrameTimings *timings;
|
|
guint pos;
|
|
|
|
g_assert (frame != NULL);
|
|
g_assert (frame->self != NULL);
|
|
|
|
self = frame->self;
|
|
|
|
if ((timings = gdk_frame_clock_get_timings (frame->frame_clock, frame->frame_number)))
|
|
{
|
|
timings->presentation_time = time_from_wayland (tv_sec_hi, tv_sec_lo, tv_nsec);
|
|
timings->complete = TRUE;
|
|
}
|
|
|
|
if (g_ptr_array_find (self->frames, frame, &pos))
|
|
g_ptr_array_remove_index_fast (self->frames, pos);
|
|
}
|
|
|
|
static void
|
|
gdk_wayland_presentation_feedback_discarded (void *data,
|
|
struct wp_presentation_feedback *feedback)
|
|
{
|
|
GdkWaylandPresentationFrame *frame = data;
|
|
guint pos;
|
|
|
|
g_assert (frame != NULL);
|
|
g_assert (frame->self != NULL);
|
|
|
|
if (g_ptr_array_find (frame->self->frames, frame, &pos))
|
|
g_ptr_array_remove_index_fast (frame->self->frames, pos);
|
|
}
|
|
|
|
static const struct wp_presentation_feedback_listener gdk_wayland_presentation_feedback_listener = {
|
|
gdk_wayland_presentation_feedback_sync_output,
|
|
gdk_wayland_presentation_feedback_presented,
|
|
gdk_wayland_presentation_feedback_discarded,
|
|
};
|
|
|
|
void
|
|
gdk_wayland_presentation_time_track (GdkWaylandPresentationTime *self,
|
|
GdkFrameClock *frame_clock,
|
|
struct wl_surface *surface,
|
|
gint64 frame_number)
|
|
{
|
|
struct wp_presentation_feedback *feedback;
|
|
GdkWaylandPresentationFrame *frame;
|
|
|
|
g_return_if_fail (self != NULL);
|
|
g_return_if_fail (surface != NULL);
|
|
|
|
if (self->display->presentation == NULL)
|
|
return;
|
|
|
|
if (!(feedback = wp_presentation_feedback (self->display->presentation, surface)))
|
|
return;
|
|
|
|
frame = g_new0 (GdkWaylandPresentationFrame, 1);
|
|
frame->self = self;
|
|
frame->frame_clock = g_object_ref (frame_clock);
|
|
frame->frame_number = frame_number;
|
|
frame->feedback = g_steal_pointer (&feedback);
|
|
|
|
g_ptr_array_add (self->frames, frame);
|
|
|
|
wp_presentation_feedback_add_listener (frame->feedback,
|
|
&gdk_wayland_presentation_feedback_listener,
|
|
frame);
|
|
}
|