From 1bdecdb21725aaced0cf2aebe4c09c9b59586157 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 13 Jun 2023 16:02:00 +0200 Subject: [PATCH] scene/output: disable hardware cursors when idle When the cursor plane is enabled, a lot of hardware will drain more power. If the screen contents don't change, perform one final render pass to blend everything onto a single plane. --- include/wlr/types/wlr_scene.h | 2 ++ types/scene/wlr_scene.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index c1b6f1309..ac0d6355e 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -204,6 +204,8 @@ struct wlr_scene_output { struct wl_list damage_highlight_regions; struct wl_array render_list; + + struct wl_event_source *idle_timer; }; /** A layer shell scene helper */ diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index f640d5050..19acb39d8 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -21,6 +21,7 @@ #include "util/time.h" #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 +#define SCENE_OUTPUT_IDLE_DELAY_MS 10000 struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_TREE); @@ -1236,6 +1237,11 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data) WLR_OUTPUT_STATE_ENABLED)) { scene_output_update_geometry(scene_output); } + + if (event->committed & WLR_OUTPUT_STATE_BUFFER) { + wl_event_source_timer_update(scene_output->idle_timer, + SCENE_OUTPUT_IDLE_DELAY_MS); + } } static void scene_output_handle_damage(struct wl_listener *listener, void *data) { @@ -1253,6 +1259,22 @@ static void scene_output_handle_needs_frame(struct wl_listener *listener, void * wlr_output_schedule_frame(scene_output->output); } +static int scene_output_handle_idle(void *data) { + struct wlr_scene_output *scene_output = data; + + if (scene_output->output->hardware_cursor == NULL) { + return 0; + } + + // Paint one frame with hardware cursors disabled. This reduces the + // bandwidth used by the hardware and brings down power usage. + wlr_output_lock_software_cursors(scene_output->output, true); + wlr_output_schedule_frame(scene_output->output); + wlr_scene_output_commit(scene_output); + wlr_output_lock_software_cursors(scene_output->output, false); + return 0; +} + struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, struct wlr_output *output) { struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_output)); @@ -1260,6 +1282,14 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return NULL; } + struct wl_event_loop *loop = wl_display_get_event_loop(output->display); + scene_output->idle_timer = + wl_event_loop_add_timer(loop, scene_output_handle_idle, scene_output); + if (scene_output->idle_timer == NULL) { + free(scene_output); + return NULL; + } + scene_output->output = output; scene_output->scene = scene; wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); @@ -1329,6 +1359,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wl_list_remove(&scene_output->output_needs_frame.link); wl_array_release(&scene_output->render_list); + wl_event_source_remove(scene_output->idle_timer); free(scene_output); }