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.
This commit is contained in:
Simon Ser 2023-06-13 16:02:00 +02:00
parent 670915eeea
commit 1bdecdb217
2 changed files with 33 additions and 0 deletions

View file

@ -204,6 +204,8 @@ struct wlr_scene_output {
struct wl_list damage_highlight_regions; struct wl_list damage_highlight_regions;
struct wl_array render_list; struct wl_array render_list;
struct wl_event_source *idle_timer;
}; };
/** A layer shell scene helper */ /** A layer shell scene helper */

View file

@ -21,6 +21,7 @@
#include "util/time.h" #include "util/time.h"
#define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 #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) { struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) {
assert(node->type == WLR_SCENE_NODE_TREE); 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)) { WLR_OUTPUT_STATE_ENABLED)) {
scene_output_update_geometry(scene_output); 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) { 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); 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_scene_output *wlr_scene_output_create(struct wlr_scene *scene,
struct wlr_output *output) { struct wlr_output *output) {
struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_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; 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->output = output;
scene_output->scene = scene; scene_output->scene = scene;
wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); 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_list_remove(&scene_output->output_needs_frame.link);
wl_array_release(&scene_output->render_list); wl_array_release(&scene_output->render_list);
wl_event_source_remove(scene_output->idle_timer);
free(scene_output); free(scene_output);
} }