mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-09 18:30:08 +00:00
gdk/wayland: use wp_presentation for more accurate frame timings
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.
This commit is contained in:
parent
2d3a3d6a78
commit
53616a73e9
@ -58,6 +58,7 @@
|
||||
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
||||
#include <wayland/server-decoration-client-protocol.h>
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
|
||||
#include "wm-button-layout-translation.h"
|
||||
|
||||
@ -598,6 +599,13 @@ gdk_registry_handle_global (void *data,
|
||||
wl_registry_bind (display_wayland->wl_registry, id,
|
||||
&wp_viewporter_interface, 1);
|
||||
}
|
||||
else if (strcmp (interface, "wp_presentation") == 0)
|
||||
{
|
||||
display_wayland->presentation =
|
||||
wl_registry_bind (display_wayland->wl_registry, id,
|
||||
&wp_presentation_interface,
|
||||
MIN (version, 1));
|
||||
}
|
||||
|
||||
|
||||
g_hash_table_insert (display_wayland->known_globals,
|
||||
@ -808,6 +816,7 @@ gdk_wayland_display_dispose (GObject *object)
|
||||
g_clear_pointer (&display_wayland->xdg_activation, xdg_activation_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->fractional_scale, wp_fractional_scale_manager_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->viewporter, wp_viewporter_destroy);
|
||||
g_clear_pointer (&display_wayland->presentation, wp_presentation_destroy);
|
||||
g_clear_pointer (&display_wayland->linux_dmabuf, zwp_linux_dmabuf_v1_destroy);
|
||||
g_clear_pointer (&display_wayland->linux_dmabuf_feedback, zwp_linux_dmabuf_feedback_v1_destroy);
|
||||
if (display_wayland->linux_dmabuf_formats)
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include <gdk/wayland/xdg-activation-v1-client-protocol.h>
|
||||
#include <gdk/wayland/fractional-scale-v1-client-protocol.h>
|
||||
#include <gdk/wayland/viewporter-client-protocol.h>
|
||||
#include <gdk/wayland/presentation-time-client-protocol.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gdk/gdkkeys.h>
|
||||
@ -125,6 +126,7 @@ struct _GdkWaylandDisplay
|
||||
struct xdg_activation_v1 *xdg_activation;
|
||||
struct wp_fractional_scale_manager_v1 *fractional_scale;
|
||||
struct wp_viewporter *viewporter;
|
||||
struct wp_presentation *presentation;
|
||||
|
||||
GList *async_roundtrips;
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <gdk/wayland/gdkwayland.h>
|
||||
#include <gdk/wayland/gdkdisplay-wayland.h>
|
||||
#include <gdk/wayland/gdkseat-wayland.h>
|
||||
#include <gdk/wayland/gdkwaylandpresentationtime-private.h>
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
|
@ -44,6 +44,8 @@ struct _GdkWaylandSurface
|
||||
struct wl_event_queue *event_queue;
|
||||
struct wl_callback *frame_callback;
|
||||
|
||||
GdkWaylandPresentationTime *presentation_time;
|
||||
|
||||
unsigned int initial_configure_received : 1;
|
||||
unsigned int has_uncommitted_ack_configure : 1;
|
||||
unsigned int has_pending_subsurface_commits : 1;
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "gdktoplevel-wayland-private.h"
|
||||
|
||||
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
||||
#include "presentation-time-client-protocol.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -403,6 +404,17 @@ gdk_wayland_surface_request_frame (GdkSurface *surface)
|
||||
wl_proxy_set_queue ((struct wl_proxy *) self->frame_callback, NULL);
|
||||
wl_callback_add_listener (self->frame_callback, &frame_listener, surface);
|
||||
|
||||
if (self->presentation_time == NULL)
|
||||
{
|
||||
GdkWaylandDisplay *wayland_display = GDK_WAYLAND_DISPLAY (gdk_surface_get_display (surface));
|
||||
self->presentation_time = gdk_wayland_presentation_time_new (wayland_display);
|
||||
}
|
||||
|
||||
gdk_wayland_presentation_time_track (self->presentation_time,
|
||||
clock,
|
||||
self->display_server.wl_surface,
|
||||
gdk_frame_clock_get_frame_counter (clock));
|
||||
|
||||
for (gsize i = 0; i < gdk_surface_get_n_subsurfaces (surface); i++)
|
||||
{
|
||||
GdkSubsurface *subsurface = gdk_surface_get_subsurface (surface, i);
|
||||
@ -1048,6 +1060,7 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
|
||||
|
||||
unmap_popups_for_surface (surface);
|
||||
|
||||
g_clear_pointer (&impl->presentation_time, gdk_wayland_presentation_time_free);
|
||||
g_clear_pointer (&impl->frame_callback, wl_callback_destroy);
|
||||
if (impl->awaiting_frame_frozen)
|
||||
{
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "gdktoplevelprivate.h"
|
||||
#include "gdkdevice-wayland-private.h"
|
||||
|
||||
#include <wayland/presentation-time-client-protocol.h>
|
||||
#include <wayland/xdg-shell-unstable-v6-client-protocol.h>
|
||||
#include <wayland/xdg-foreign-unstable-v2-client-protocol.h>
|
||||
|
||||
@ -122,6 +123,8 @@ struct _GdkWaylandToplevel
|
||||
|
||||
struct wl_output *initial_fullscreen_output;
|
||||
|
||||
struct wp_presentation_feedback *feedback;
|
||||
|
||||
struct {
|
||||
GdkToplevelState unset_flags;
|
||||
GdkToplevelState set_flags;
|
||||
|
19
gdk/wayland/gdkwaylandpresentationtime-private.h
Normal file
19
gdk/wayland/gdkwaylandpresentationtime-private.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <gdk/gdkframeclock.h>
|
||||
#include <gdk/wayland/gdkdisplay-wayland.h>
|
||||
#include <gdk/wayland/gdksurface-wayland.h>
|
||||
#include <gdk/wayland/gdkwaylanddisplay.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GdkWaylandPresentationTime GdkWaylandPresentationTime;
|
||||
|
||||
GdkWaylandPresentationTime *gdk_wayland_presentation_time_new (GdkWaylandDisplay *display);
|
||||
void gdk_wayland_presentation_time_track (GdkWaylandPresentationTime *self,
|
||||
GdkFrameClock *frame_clock,
|
||||
struct wl_surface *surface,
|
||||
gint64 frame_number);
|
||||
void gdk_wayland_presentation_time_free (GdkWaylandPresentationTime *self);
|
||||
|
||||
G_END_DECLS
|
152
gdk/wayland/gdkwaylandpresentationtime.c
Normal file
152
gdk/wayland/gdkwaylandpresentationtime.c
Normal file
@ -0,0 +1,152 @@
|
||||
#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);
|
||||
}
|
@ -22,6 +22,7 @@ gdk_wayland_sources = files([
|
||||
'gdktoplevel-wayland.c',
|
||||
'gdkpopup-wayland.c',
|
||||
'gdkvulkancontext-wayland.c',
|
||||
'gdkwaylandpresentationtime.c',
|
||||
'wm-button-layout-translation.c',
|
||||
])
|
||||
|
||||
@ -69,6 +70,7 @@ proto_sources = [
|
||||
['xdg-activation', 'staging', 'v1', ],
|
||||
['fractional-scale', 'staging', 'v1', ],
|
||||
['linux-dmabuf', 'unstable', 'v1', ],
|
||||
['presentation-time', 'stable', 'v1', ],
|
||||
]
|
||||
|
||||
gdk_wayland_gen_headers = []
|
||||
|
Loading…
Reference in New Issue
Block a user