From 3cc3b7526c31bd90cb9cb0b42a1096b1da76f48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 25 Mar 2019 10:24:46 +0100 Subject: [PATCH] renderer-native: Fake page flipping slower when power saving We rely on the frame clock to compress input events, thus if the frame clock stops, input events are not dispatched. At the same time, there is no reason to redraw at a full frame rate, as nothing will be presented anyway, so slow down to 10Hz (compared to the most common 60Hz). Note that we'll only actually reach 10Hz if there is an active animation being displayed, which won't happen e.g. if there is a screen shield in the way. https://gitlab.gnome.org/GNOME/mutter/merge_requests/506 --- src/backends/meta-backend.c | 2 +- src/backends/meta-stage-private.h | 3 +- src/backends/meta-stage.c | 27 +++++- src/backends/native/meta-renderer-native.c | 99 +++++++++++++++++----- 4 files changed, 102 insertions(+), 29 deletions(-) diff --git a/src/backends/meta-backend.c b/src/backends/meta-backend.c index c527114be..58eec8c94 100644 --- a/src/backends/meta-backend.c +++ b/src/backends/meta-backend.c @@ -475,7 +475,7 @@ meta_backend_real_post_init (MetaBackend *backend) MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); ClutterDeviceManager *device_manager = clutter_device_manager_get_default (); - priv->stage = meta_stage_new (); + priv->stage = meta_stage_new (backend); clutter_actor_realize (priv->stage); META_BACKEND_GET_CLASS (backend)->select_stage_events (backend); diff --git a/src/backends/meta-stage-private.h b/src/backends/meta-stage-private.h index 21feab3ac..639d2372c 100644 --- a/src/backends/meta-stage-private.h +++ b/src/backends/meta-stage-private.h @@ -23,12 +23,13 @@ #include "backends/meta-cursor.h" #include "meta/boxes.h" #include "meta/meta-stage.h" +#include "meta/types.h" G_BEGIN_DECLS typedef struct _MetaOverlay MetaOverlay; -ClutterActor *meta_stage_new (void); +ClutterActor *meta_stage_new (MetaBackend *backend); MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage); void meta_stage_remove_cursor_overlay (MetaStage *stage, diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c index 1f0d9c050..47a00e51a 100644 --- a/src/backends/meta-stage.c +++ b/src/backends/meta-stage.c @@ -180,6 +180,15 @@ meta_stage_deactivate (ClutterStage *actor) stage->is_active = FALSE; } +static void +on_power_save_changed (MetaMonitorManager *monitor_manager, + MetaStage *stage) +{ + if (meta_monitor_manager_get_power_save_mode (monitor_manager) == + META_POWER_SAVE_ON) + clutter_actor_queue_redraw (CLUTTER_ACTOR (stage)); +} + static void meta_stage_class_init (MetaStageClass *klass) { @@ -209,11 +218,21 @@ meta_stage_init (MetaStage *stage) } ClutterActor * -meta_stage_new (void) +meta_stage_new (MetaBackend *backend) { - return g_object_new (META_TYPE_STAGE, - "cursor-visible", FALSE, - NULL); + MetaStage *stage; + MetaMonitorManager *monitor_manager; + + stage = g_object_new (META_TYPE_STAGE, + "cursor-visible", FALSE, + NULL); + + monitor_manager = meta_backend_get_monitor_manager (backend); + g_signal_connect (monitor_manager, "power-save-mode-changed", + G_CALLBACK (on_power_save_changed), + stage); + + return CLUTTER_ACTOR (stage); } static void diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c index e550a47e7..0f0992cbf 100644 --- a/src/backends/native/meta-renderer-native.c +++ b/src/backends/native/meta-renderer-native.c @@ -213,6 +213,9 @@ struct _MetaRendererNative int64_t frame_counter; gboolean pending_unset_disabled_crtcs; + + GList *power_save_page_flip_closures; + guint power_save_page_flip_source_id; }; static void @@ -1526,6 +1529,38 @@ is_timestamp_earlier_than (uint64_t ts1, return ts2 - ts1 < UINT64_MAX / 2; } +static gboolean +dummy_power_save_page_flip_cb (gpointer user_data) +{ + MetaRendererNative *renderer_native = user_data; + + g_list_free_full (renderer_native->power_save_page_flip_closures, + (GDestroyNotify) g_closure_unref); + renderer_native->power_save_page_flip_closures = NULL; + renderer_native->power_save_page_flip_source_id = 0; + + return G_SOURCE_REMOVE; +} + +static void +queue_dummy_power_save_page_flip (MetaRendererNative *renderer_native, + GClosure *flip_closure) +{ + const unsigned int timeout_ms = 100; + + if (!renderer_native->power_save_page_flip_source_id) + { + renderer_native->power_save_page_flip_source_id = + g_timeout_add (timeout_ms, + dummy_power_save_page_flip_cb, + renderer_native); + } + + renderer_native->power_save_page_flip_closures = + g_list_prepend (renderer_native->power_save_page_flip_closures, + g_closure_ref (flip_closure)); +} + typedef struct _RetryPageFlipData { MetaCrtc *crtc; @@ -1748,12 +1783,8 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, uint32_t fb_id; gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - if (!meta_gpu_kms_is_crtc_active (gpu_kms, crtc)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Tried to flip inactive CRTC"); - return FALSE; - } + + g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc)); renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, render_gpu); @@ -1994,7 +2025,11 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen) CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaRendererView *view = onscreen_native->view; + MetaRendererNative *renderer_native = onscreen_native->renderer_native; + MetaMonitorManager *monitor_manager = + META_MONITOR_MANAGER (renderer_native->monitor_manager_kms); GClosure *flip_closure; + MetaPowerSave power_save_mode; MetaLogicalMonitor *logical_monitor; /* @@ -2012,23 +2047,28 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen) (GClosureNotify) flip_closure_destroyed); g_closure_set_marshal (flip_closure, meta_marshal_VOID__OBJECT_OBJECT_INT64); - /* Either flip the CRTC's of the monitor info, if we are drawing just part - * of the stage, or all of the CRTC's if we are drawing the whole stage. - */ - FlipCrtcData data = { - .onscreen = onscreen, - .flip_closure = flip_closure, - }; - logical_monitor = meta_renderer_view_get_logical_monitor (view); - meta_logical_monitor_foreach_crtc (logical_monitor, flip_crtc, &data); + power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); + if (power_save_mode == META_POWER_SAVE_ON) + { + FlipCrtcData data = { + .onscreen = onscreen, + .flip_closure = flip_closure, + }; + logical_monitor = meta_renderer_view_get_logical_monitor (view); + meta_logical_monitor_foreach_crtc (logical_monitor, flip_crtc, &data); - /* - * If we didn't queue a page flip, but instead directly changed the mode due - * to the driver not supporting mode setting, wes must swap the buffers - * directly as we won't get a page flip callback. - */ - if (!data.did_flip && data.did_mode_set) - meta_onscreen_native_swap_drm_fb (onscreen); + /* + * If we didn't queue a page flip, but instead directly changed the mode + * due to the driver not supporting mode setting, we must swap the + * buffers directly as we won't get a page flip callback. + */ + if (!data.did_flip && data.did_mode_set) + meta_onscreen_native_swap_drm_fb (onscreen); + } + else + { + queue_dummy_power_save_page_flip (renderer_native, flip_closure); + } onscreen_native->pending_queue_swap_notify = TRUE; @@ -2401,11 +2441,14 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; + MetaMonitorManager *monitor_manager = + META_MONITOR_MANAGER (renderer_native->monitor_manager_kms); CoglOnscreenEGL *onscreen_egl = onscreen->winsys; MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaGpuKms *render_gpu = onscreen_native->render_gpu; CoglFrameInfo *frame_info; gboolean egl_context_changed = FALSE; + MetaPowerSave power_save_mode; /* * Wait for the flip callback before continuing, as we might have started the @@ -2447,7 +2490,10 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, /* If this is the first framebuffer to be presented then we now setup the * crtc modes, else we flip from the previous buffer */ - if (onscreen_native->pending_set_crtc) + + power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); + if (onscreen_native->pending_set_crtc && + power_save_mode == META_POWER_SAVE_ON) { meta_onscreen_native_set_crtc_modes (onscreen); onscreen_native->pending_set_crtc = FALSE; @@ -4157,6 +4203,13 @@ meta_renderer_native_finalize (GObject *object) { MetaRendererNative *renderer_native = META_RENDERER_NATIVE (object); + if (renderer_native->power_save_page_flip_closures) + { + g_list_free_full (renderer_native->power_save_page_flip_closures, + (GDestroyNotify) g_closure_unref); + g_source_remove (renderer_native->power_save_page_flip_source_id); + } + g_hash_table_destroy (renderer_native->gpu_datas); g_clear_object (&renderer_native->gles3);