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
This commit is contained in:
Jonas Ådahl 2019-03-25 10:24:46 +01:00
parent 53b59d8bff
commit 3cc3b7526c
4 changed files with 102 additions and 29 deletions

View File

@ -475,7 +475,7 @@ meta_backend_real_post_init (MetaBackend *backend)
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend); MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterDeviceManager *device_manager = clutter_device_manager_get_default (); ClutterDeviceManager *device_manager = clutter_device_manager_get_default ();
priv->stage = meta_stage_new (); priv->stage = meta_stage_new (backend);
clutter_actor_realize (priv->stage); clutter_actor_realize (priv->stage);
META_BACKEND_GET_CLASS (backend)->select_stage_events (backend); META_BACKEND_GET_CLASS (backend)->select_stage_events (backend);

View File

@ -23,12 +23,13 @@
#include "backends/meta-cursor.h" #include "backends/meta-cursor.h"
#include "meta/boxes.h" #include "meta/boxes.h"
#include "meta/meta-stage.h" #include "meta/meta-stage.h"
#include "meta/types.h"
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _MetaOverlay MetaOverlay; typedef struct _MetaOverlay MetaOverlay;
ClutterActor *meta_stage_new (void); ClutterActor *meta_stage_new (MetaBackend *backend);
MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage); MetaOverlay *meta_stage_create_cursor_overlay (MetaStage *stage);
void meta_stage_remove_cursor_overlay (MetaStage *stage, void meta_stage_remove_cursor_overlay (MetaStage *stage,

View File

@ -180,6 +180,15 @@ meta_stage_deactivate (ClutterStage *actor)
stage->is_active = FALSE; 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 static void
meta_stage_class_init (MetaStageClass *klass) meta_stage_class_init (MetaStageClass *klass)
{ {
@ -209,11 +218,21 @@ meta_stage_init (MetaStage *stage)
} }
ClutterActor * ClutterActor *
meta_stage_new (void) meta_stage_new (MetaBackend *backend)
{ {
return g_object_new (META_TYPE_STAGE, MetaStage *stage;
"cursor-visible", FALSE, MetaMonitorManager *monitor_manager;
NULL);
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 static void

View File

@ -213,6 +213,9 @@ struct _MetaRendererNative
int64_t frame_counter; int64_t frame_counter;
gboolean pending_unset_disabled_crtcs; gboolean pending_unset_disabled_crtcs;
GList *power_save_page_flip_closures;
guint power_save_page_flip_source_id;
}; };
static void static void
@ -1526,6 +1529,38 @@ is_timestamp_earlier_than (uint64_t ts1,
return ts2 - ts1 < UINT64_MAX / 2; 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 typedef struct _RetryPageFlipData
{ {
MetaCrtc *crtc; MetaCrtc *crtc;
@ -1748,12 +1783,8 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen,
uint32_t fb_id; uint32_t fb_id;
gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc));
if (!meta_gpu_kms_is_crtc_active (gpu_kms, crtc))
{ g_assert (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;
}
renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native,
render_gpu); render_gpu);
@ -1994,7 +2025,11 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
CoglOnscreenEGL *onscreen_egl = onscreen->winsys; CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
MetaRendererView *view = onscreen_native->view; 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; GClosure *flip_closure;
MetaPowerSave power_save_mode;
MetaLogicalMonitor *logical_monitor; MetaLogicalMonitor *logical_monitor;
/* /*
@ -2012,23 +2047,28 @@ meta_onscreen_native_flip_crtcs (CoglOnscreen *onscreen)
(GClosureNotify) flip_closure_destroyed); (GClosureNotify) flip_closure_destroyed);
g_closure_set_marshal (flip_closure, meta_marshal_VOID__OBJECT_OBJECT_INT64); 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 power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager);
* of the stage, or all of the CRTC's if we are drawing the whole stage. if (power_save_mode == META_POWER_SAVE_ON)
*/ {
FlipCrtcData data = { FlipCrtcData data = {
.onscreen = onscreen, .onscreen = onscreen,
.flip_closure = flip_closure, .flip_closure = flip_closure,
}; };
logical_monitor = meta_renderer_view_get_logical_monitor (view); logical_monitor = meta_renderer_view_get_logical_monitor (view);
meta_logical_monitor_foreach_crtc (logical_monitor, flip_crtc, &data); 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 * If we didn't queue a page flip, but instead directly changed the mode
* to the driver not supporting mode setting, wes must swap the buffers * due to the driver not supporting mode setting, we must swap the
* directly as we won't get a page flip callback. * buffers directly as we won't get a page flip callback.
*/ */
if (!data.did_flip && data.did_mode_set) if (!data.did_flip && data.did_mode_set)
meta_onscreen_native_swap_drm_fb (onscreen); 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; 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; CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys;
MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform;
MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native;
MetaMonitorManager *monitor_manager =
META_MONITOR_MANAGER (renderer_native->monitor_manager_kms);
CoglOnscreenEGL *onscreen_egl = onscreen->winsys; CoglOnscreenEGL *onscreen_egl = onscreen->winsys;
MetaOnscreenNative *onscreen_native = onscreen_egl->platform; MetaOnscreenNative *onscreen_native = onscreen_egl->platform;
MetaGpuKms *render_gpu = onscreen_native->render_gpu; MetaGpuKms *render_gpu = onscreen_native->render_gpu;
CoglFrameInfo *frame_info; CoglFrameInfo *frame_info;
gboolean egl_context_changed = FALSE; gboolean egl_context_changed = FALSE;
MetaPowerSave power_save_mode;
/* /*
* Wait for the flip callback before continuing, as we might have started the * 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 /* If this is the first framebuffer to be presented then we now setup the
* crtc modes, else we flip from the previous buffer */ * 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); meta_onscreen_native_set_crtc_modes (onscreen);
onscreen_native->pending_set_crtc = FALSE; onscreen_native->pending_set_crtc = FALSE;
@ -4157,6 +4203,13 @@ meta_renderer_native_finalize (GObject *object)
{ {
MetaRendererNative *renderer_native = META_RENDERER_NATIVE (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_hash_table_destroy (renderer_native->gpu_datas);
g_clear_object (&renderer_native->gles3); g_clear_object (&renderer_native->gles3);