From b66fec0450dc55f7221dc4e84c406ef30c4d177d Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Fri, 28 Feb 2014 10:15:45 -0500 Subject: [PATCH] egl: Add a way to pause the ClutterMasterClock When VT switched away, we need to pause the ClutterMasterClock, stop processing events, and stop trying to flip. https://bugzilla.gnome.org/show_bug.cgi?id=730215 --- clutter/clutter-master-clock.c | 15 +++++++ clutter/clutter-master-clock.h | 2 + clutter/egl/clutter-backend-eglnative.c | 54 +++++++++++++++++++++++++ clutter/egl/clutter-egl.h | 5 +++ 4 files changed, 76 insertions(+) diff --git a/clutter/clutter-master-clock.c b/clutter/clutter-master-clock.c index e0506779e..b830818bc 100644 --- a/clutter/clutter-master-clock.c +++ b/clutter/clutter-master-clock.c @@ -93,6 +93,8 @@ struct _ClutterMasterClock */ guint idle : 1; guint ensure_next_iteration : 1; + + guint paused : 1; }; struct _ClutterMasterClockClass @@ -143,6 +145,9 @@ master_clock_is_running (ClutterMasterClock *master_clock) stages = clutter_stage_manager_peek_stages (stage_manager); + if (master_clock->paused) + return FALSE; + if (master_clock->timelines) return TRUE; @@ -636,6 +641,7 @@ clutter_master_clock_init (ClutterMasterClock *self) self->idle = FALSE; self->ensure_next_iteration = FALSE; + self->paused = FALSE; #ifdef CLUTTER_ENABLE_DEBUG self->frame_budget = G_USEC_PER_SEC / 60; @@ -740,3 +746,12 @@ _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock) master_clock->ensure_next_iteration = TRUE; } + +void +_clutter_master_clock_set_paused (ClutterMasterClock *master_clock, + gboolean paused) +{ + g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock)); + + master_clock->paused = !!paused; +} diff --git a/clutter/clutter-master-clock.h b/clutter/clutter-master-clock.h index 211f378ba..771a26d77 100644 --- a/clutter/clutter-master-clock.h +++ b/clutter/clutter-master-clock.h @@ -43,6 +43,8 @@ void _clutter_master_clock_remove_timeline (Clutter ClutterTimeline *timeline); void _clutter_master_clock_start_running (ClutterMasterClock *master_clock); void _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock); +void _clutter_master_clock_set_paused (ClutterMasterClock *master_clock, + gboolean paused); void _clutter_timeline_advance (ClutterTimeline *timeline, gint64 tick_time); diff --git a/clutter/egl/clutter-backend-eglnative.c b/clutter/egl/clutter-backend-eglnative.c index bbc9e7025..1eccd31d9 100644 --- a/clutter/egl/clutter-backend-eglnative.c +++ b/clutter/egl/clutter-backend-eglnative.c @@ -204,3 +204,57 @@ clutter_egl_set_kms_fd (int fd) _kms_fd = fd; } #endif + +/** + * clutter_egl_freeze_master_clock: + * + * Freezing the master clock makes Clutter stop processing events, + * redrawing, and advancing timelines. This is necessary when implementing + * a display server, to ensure that Clutter doesn't keep trying to page + * flip when DRM master has been dropped, e.g. when VT switched away. + * + * The master clock starts out running, so if you are VT switched away on + * startup, you need to call this immediately. + * + * If you're also using the evdev backend, make sure to also use + * clutter_evdev_release_devices() to make sure that Clutter doesn't also + * access revoked evdev devices when VT switched away. + * + * To unthaw a frozen master clock, use clutter_egl_thaw_master_clock(). + * + * Since: 1.20 + */ +void +clutter_egl_freeze_master_clock (void) +{ + ClutterMasterClock *master_clock; + + g_return_if_fail (CLUTTER_IS_BACKEND_EGL_NATIVE (clutter_get_default_backend ())); + + master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_set_paused (master_clock, TRUE); +} + +/** + * clutter_egl_thaw_master_clock: + * + * Thaws a master clock that has previously been frozen with + * clutter_egl_freeze_master_clock(), and start pumping the master clock + * again at the next iteration. Note that if you're switching back to your + * own VT, you should probably also queue a stage redraw with + * clutter_stage_ensure_redraw(). + * + * Since: 1.20 + */ +void +clutter_egl_thaw_master_clock (void) +{ + ClutterMasterClock *master_clock; + + g_return_if_fail (CLUTTER_IS_BACKEND_EGL_NATIVE (clutter_get_default_backend ())); + + master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_set_paused (master_clock, FALSE); + + _clutter_master_clock_start_running (master_clock); +} diff --git a/clutter/egl/clutter-egl.h b/clutter/egl/clutter-egl.h index f70be6d8a..83b021343 100644 --- a/clutter/egl/clutter-egl.h +++ b/clutter/egl/clutter-egl.h @@ -92,6 +92,11 @@ CLUTTER_AVAILABLE_IN_1_18 void clutter_egl_set_kms_fd (int fd); #endif +CLUTTER_AVAILABLE_IN_1_20 +void clutter_egl_freeze_master_clock (void); +CLUTTER_AVAILABLE_IN_1_20 +void clutter_egl_thaw_master_clock (void); + G_END_DECLS #endif /* __CLUTTER_EGL_H__ */