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