[mutter] renderer-native: Fake page flipping slower when power saving



commit 3cc3b7526c31bd90cb9cb0b42a1096b1da76f48b
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Mon Mar 25 10:24:46 2019 +0100

    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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]