gdk/frameclock: Make surfaces inhibit freeze

To make a frame clock tick as long as any of the associated surfaces
expect to receive ticks, make the surfaces inhibit freezing the clock,
instead of directly tell the frame clock to freeze itself.

This makes it so that as long as any surface using a certain frame clock
is not frozen (e.g. just received a frame event from the display
server), the frame clock will not be frozen.

With this, the frame clock is initiated as frozen, and won't be thawed
until any surface inhibits freeze. It will be frozen again, when every
surface has that previously inhibited freeze uninhibited freeze.
This commit is contained in:
Jonas Ådahl 2019-06-28 18:45:44 +02:00
parent a2ff6af4b3
commit 5db079b052
8 changed files with 93 additions and 30 deletions

View File

@ -88,10 +88,10 @@ gdk_broadway_surface_finalize (GObject *object)
}
static gboolean
thaw_clock_cb (GdkFrameClock *clock)
thaw_updates_cb (GdkSurface *surface)
{
_gdk_frame_clock_thaw (clock);
g_object_unref (clock);
gdk_surface_thaw_updates (surface);
g_object_unref (surface);
return G_SOURCE_REMOVE;
}
@ -109,9 +109,9 @@ _gdk_broadway_roundtrip_notify (GdkSurface *surface,
/* If there is no remote web client, rate limit update to once a second */
if (local_reply)
g_timeout_add_seconds (1, (GSourceFunc)thaw_clock_cb, g_object_ref (clock));
g_timeout_add_seconds (1, (GSourceFunc)thaw_updates_cb, g_object_ref (surface));
else
_gdk_frame_clock_thaw (clock);
gdk_surface_thaw_updates (surface);
if (timings)
{
@ -140,7 +140,7 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
GdkBroadwayDisplay *broadway_display;
impl->pending_frame_counter = gdk_frame_clock_get_frame_counter (clock);
_gdk_frame_clock_freeze (gdk_surface_get_frame_clock (surface));
gdk_surface_freeze_updates (surface);
broadway_display = GDK_BROADWAY_DISPLAY (display);

View File

@ -97,10 +97,14 @@ struct _GdkFrameClockPrivate
gint n_timings;
gint current;
GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
gint n_freeze_inhibitors;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT)
static void
_gdk_frame_clock_freeze (GdkFrameClock *clock);
static void
gdk_frame_clock_finalize (GObject *object)
{
@ -114,12 +118,21 @@ gdk_frame_clock_finalize (GObject *object)
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->finalize (object);
}
static void
gdk_frame_clock_constructed (GObject *object)
{
G_OBJECT_CLASS (gdk_frame_clock_parent_class)->constructed (object);
_gdk_frame_clock_freeze (GDK_FRAME_CLOCK (object));
}
static void
gdk_frame_clock_class_init (GdkFrameClockClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
gobject_class->finalize = gdk_frame_clock_finalize;
gobject_class->constructed = gdk_frame_clock_constructed;
/**
* GdkFrameClock::flush-events:
@ -335,7 +348,7 @@ gdk_frame_clock_end_updating (GdkFrameClock *frame_clock)
GDK_FRAME_CLOCK_GET_CLASS (frame_clock)->end_updating (frame_clock);
}
void
static void
_gdk_frame_clock_freeze (GdkFrameClock *clock)
{
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
@ -344,7 +357,7 @@ _gdk_frame_clock_freeze (GdkFrameClock *clock)
}
void
static void
_gdk_frame_clock_thaw (GdkFrameClock *clock)
{
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
@ -352,6 +365,35 @@ _gdk_frame_clock_thaw (GdkFrameClock *clock)
GDK_FRAME_CLOCK_GET_CLASS (clock)->thaw (clock);
}
void
_gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock)
{
GdkFrameClockPrivate *priv;
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
priv = clock->priv;
priv->n_freeze_inhibitors++;
if (priv->n_freeze_inhibitors == 1)
_gdk_frame_clock_thaw (clock);
}
void
_gdk_frame_clock_uninhibit_freeze (GdkFrameClock *clock)
{
GdkFrameClockPrivate *priv;
g_return_if_fail (GDK_IS_FRAME_CLOCK (clock));
priv = clock->priv;
priv->n_freeze_inhibitors--;
if (priv->n_freeze_inhibitors == 0)
_gdk_frame_clock_freeze (clock);
}
/**
* gdk_frame_clock_get_frame_counter:
* @frame_clock: a #GdkFrameClock

View File

@ -105,8 +105,8 @@ struct _GdkFrameTimings
guint slept_before : 1;
};
void _gdk_frame_clock_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_thaw (GdkFrameClock *clock);
void _gdk_frame_clock_inhibit_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_uninhibit_freeze (GdkFrameClock *clock);
void _gdk_frame_clock_begin_frame (GdkFrameClock *clock);
void _gdk_frame_clock_debug_print_timings (GdkFrameClock *clock,

View File

@ -1341,10 +1341,14 @@ gdk_surface_schedule_update (GdkSurface *surface)
{
GdkFrameClock *frame_clock;
if (surface &&
(surface->update_freeze_count ||
gdk_surface_is_toplevel_frozen (surface)))
return;
g_return_if_fail (surface);
if (surface->update_freeze_count ||
gdk_surface_is_toplevel_frozen (surface))
{
surface->pending_schedule_update = TRUE;
return;
}
/* If there's no frame clock (a foreign surface), then the invalid
* region will just stick around unless gdk_surface_process_updates()
@ -1581,13 +1585,17 @@ gdk_surface_freeze_updates (GdkSurface *surface)
g_return_if_fail (GDK_IS_SURFACE (surface));
surface->update_freeze_count++;
if (surface->update_freeze_count == 1)
_gdk_frame_clock_uninhibit_freeze (surface->frame_clock);
}
/**
* gdk_surface_thaw_updates:
* @surface: a #GdkSurface
*
* Thaws a surface frozen with gdk_surface_freeze_updates().
* Thaws a surface frozen with gdk_surface_freeze_updates(). Note that this
* will not necessarily schedule updates if the surface freeze count reaches
* zero.
**/
void
gdk_surface_thaw_updates (GdkSurface *surface)
@ -1597,7 +1605,15 @@ gdk_surface_thaw_updates (GdkSurface *surface)
g_return_if_fail (surface->update_freeze_count > 0);
if (--surface->update_freeze_count == 0)
gdk_surface_schedule_update (surface);
{
_gdk_frame_clock_inhibit_freeze (surface->frame_clock);
if (surface->pending_schedule_update)
{
surface->pending_schedule_update = FALSE;
gdk_surface_schedule_update (surface);
}
}
}
void
@ -1606,7 +1622,7 @@ gdk_surface_freeze_toplevel_updates (GdkSurface *surface)
g_return_if_fail (GDK_IS_SURFACE (surface));
surface->update_and_descendants_freeze_count++;
_gdk_frame_clock_freeze (gdk_surface_get_frame_clock (surface));
gdk_surface_freeze_updates (surface);
}
void
@ -1616,9 +1632,9 @@ gdk_surface_thaw_toplevel_updates (GdkSurface *surface)
g_return_if_fail (surface->update_and_descendants_freeze_count > 0);
surface->update_and_descendants_freeze_count--;
_gdk_frame_clock_thaw (gdk_surface_get_frame_clock (surface));
gdk_surface_schedule_update (surface);
gdk_surface_thaw_updates (surface);
}
/**
@ -3718,6 +3734,9 @@ gdk_surface_set_frame_clock (GdkSurface *surface,
G_CALLBACK (gdk_surface_paint_on_clock),
surface);
}
if (surface->update_freeze_count == 0)
_gdk_frame_clock_inhibit_freeze (clock);
}
if (surface->frame_clock)
@ -3737,6 +3756,10 @@ gdk_surface_set_frame_clock (GdkSurface *surface,
G_CALLBACK (gdk_surface_paint_on_clock),
surface);
}
if (surface->update_freeze_count == 0)
_gdk_frame_clock_uninhibit_freeze (surface->frame_clock);
g_object_unref (surface->frame_clock);
}

View File

@ -49,6 +49,7 @@ struct _GdkSurface
cairo_region_t *update_area;
guint update_freeze_count;
gboolean pending_schedule_update;
/* This is the update_area that was in effect when the current expose
started. It may be smaller than the expose area if we'e painting
more than we have to, but it represents the "true" damage. */

View File

@ -349,7 +349,7 @@ frame_callback (void *data,
return;
impl->awaiting_frame = FALSE;
_gdk_frame_clock_thaw (clock);
gdk_surface_thaw_updates (surface);
timings = gdk_frame_clock_get_timings (clock, impl->pending_frame_counter);
impl->pending_frame_counter = 0;
@ -465,8 +465,9 @@ on_frame_clock_after_paint (GdkFrameClock *clock,
g_signal_emit (impl, signals[COMMITTED], 0);
}
if (impl->awaiting_frame)
_gdk_frame_clock_freeze (clock);
if (impl->awaiting_frame &&
impl->pending_frame_counter == gdk_frame_clock_get_frame_counter (clock))
gdk_surface_freeze_updates (surface);
}
void
@ -2577,12 +2578,8 @@ gdk_wayland_surface_hide_surface (GdkSurface *surface)
if (impl->awaiting_frame)
{
GdkFrameClock *frame_clock;
impl->awaiting_frame = FALSE;
frame_clock = gdk_surface_get_frame_clock (surface);
if (frame_clock)
_gdk_frame_clock_thaw (frame_clock);
gdk_surface_thaw_updates (surface);
}
if (impl->display_server.gtk_surface)

View File

@ -874,7 +874,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
surface_impl->toplevel->frame_pending)
{
surface_impl->toplevel->frame_pending = FALSE;
_gdk_frame_clock_thaw (gdk_surface_get_frame_clock (event->any.surface));
gdk_surface_thaw_updates (event->any.surface);
}
if (toplevel)
@ -1238,7 +1238,7 @@ _gdk_wm_protocols_filter (const XEvent *xevent,
if (surface_impl->toplevel->frame_pending)
{
surface_impl->toplevel->frame_pending = FALSE;
_gdk_frame_clock_thaw (clock);
gdk_surface_thaw_updates (event->any.surface);
}
gdk_frame_clock_get_refresh_info (clock,

View File

@ -397,7 +397,7 @@ gdk_x11_surface_end_frame (GdkSurface *surface)
g_intern_static_string ("_NET_WM_FRAME_DRAWN")))
{
impl->toplevel->frame_pending = TRUE;
_gdk_frame_clock_freeze (gdk_surface_get_frame_clock (surface));
gdk_surface_freeze_updates (surface);
timings->cookie = impl->toplevel->current_counter_value;
}
}