aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_scene.h1
-rw-r--r--types/scene/wlr_scene.c102
2 files changed, 102 insertions, 1 deletions
diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
index 2625dd80..0802014e 100644
--- a/include/wlr/types/wlr_scene.h
+++ b/include/wlr/types/wlr_scene.h
@@ -91,6 +91,7 @@ struct wlr_scene {
struct wl_listener presentation_destroy;
enum wlr_scene_debug_damage_option debug_damage_option;
+ struct wl_list damage_highlight_regions;
};
/** A sub-tree in the scene-graph. */
diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
index 6f0591bc..676fe127 100644
--- a/types/scene/wlr_scene.c
+++ b/types/scene/wlr_scene.c
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -12,6 +13,9 @@
#include <wlr/util/region.h>
#include "types/wlr_scene.h"
#include "util/signal.h"
+#include "util/time.h"
+
+#define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250
static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) {
assert(node->type == WLR_SCENE_NODE_ROOT);
@@ -67,6 +71,18 @@ static void scene_node_init(struct wlr_scene_node *node,
static void scene_node_damage_whole(struct wlr_scene_node *node);
+struct highlight_region {
+ pixman_region32_t region;
+ struct timespec when;
+ struct wl_list link;
+};
+
+static void highlight_region_destroy(struct highlight_region *damage) {
+ wl_list_remove(&damage->link);
+ pixman_region32_fini(&damage->region);
+ free(damage);
+}
+
void wlr_scene_node_destroy(struct wlr_scene_node *node) {
if (node == NULL) {
return;
@@ -88,6 +104,11 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) {
wlr_scene_output_destroy(scene_output);
}
+ struct highlight_region *damage, *tmp_damage;
+ wl_list_for_each_safe(damage, tmp_damage, &scene->damage_highlight_regions, link) {
+ highlight_region_destroy(damage);
+ }
+
wl_list_remove(&scene->presentation_destroy.link);
break;
case WLR_SCENE_NODE_BUFFER:;
@@ -130,6 +151,7 @@ struct wlr_scene *wlr_scene_create(void) {
scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL);
wl_list_init(&scene->outputs);
wl_list_init(&scene->presentation_destroy.link);
+ wl_list_init(&scene->damage_highlight_regions);
char *debug_damage = getenv("WLR_SCENE_DEBUG_DAMAGE");
if (debug_damage) {
@@ -1056,6 +1078,13 @@ static void check_scanout_iterator(struct wlr_scene_node *node,
}
static bool scene_output_scanout(struct wlr_scene_output *scene_output) {
+ if (scene_output->scene->debug_damage_option ==
+ WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
+ // We don't want to enter direct scan out if we have highlight regions
+ // enabled. Otherwise, we won't be able to render the damage regions.
+ return false;
+ }
+
struct wlr_output *output = scene_output->output;
struct wlr_box viewport_box = { .x = scene_output->x, .y = scene_output->y };
@@ -1126,6 +1155,45 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
wlr_output_damage_add_whole(scene_output->damage);
}
+ struct timespec now;
+ if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
+ struct wl_list *regions = &scene_output->scene->damage_highlight_regions;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ // add the current frame's damage if there is damage
+ if (pixman_region32_not_empty(&scene_output->damage->current)) {
+ struct highlight_region *current_damage =
+ calloc(1, sizeof(*current_damage));
+ if (current_damage) {
+ pixman_region32_init(&current_damage->region);
+ pixman_region32_copy(&current_damage->region,
+ &scene_output->damage->current);
+ memcpy(&current_damage->when, &now, sizeof(now));
+ wl_list_insert(regions, &current_damage->link);
+ }
+ }
+
+ pixman_region32_t acc_damage;
+ pixman_region32_init(&acc_damage);
+ struct highlight_region *damage, *tmp_damage;
+ wl_list_for_each_safe(damage, tmp_damage, regions, link) {
+ // remove overlaping damage regions
+ pixman_region32_subtract(&damage->region, &damage->region, &acc_damage);
+ pixman_region32_union(&acc_damage, &acc_damage, &damage->region);
+
+ // if this damage is too old or has nothing in it, get rid of it
+ struct timespec time_diff;
+ timespec_sub(&time_diff, &now, &damage->when);
+ if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME ||
+ !pixman_region32_not_empty(&damage->region)) {
+ highlight_region_destroy(damage);
+ }
+ }
+
+ wlr_output_damage_add(scene_output->damage, &acc_damage);
+ pixman_region32_fini(&acc_damage);
+ }
+
bool needs_frame;
pixman_region32_t damage;
pixman_region32_init(&damage);
@@ -1158,6 +1226,31 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
-scene_output->x, -scene_output->y,
render_node_iterator, &data);
wlr_renderer_scissor(renderer, NULL);
+
+ if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
+ struct highlight_region *damage;
+ wl_list_for_each(damage, &scene_output->scene->damage_highlight_regions, link) {
+ struct timespec time_diff;
+ timespec_sub(&time_diff, &now, &damage->when);
+ int64_t time_diff_ms = timespec_to_msec(&time_diff);
+ float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME;
+
+ int nrects;
+ pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects);
+ for (int i = 0; i < nrects; ++i) {
+ struct wlr_box box = {
+ .x = rects[i].x1,
+ .y = rects[i].y1,
+ .width = rects[i].x2 - rects[i].x1,
+ .height = rects[i].y2 - rects[i].y1,
+ };
+
+ float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 };
+ wlr_render_rect(renderer, &box, color, output->transform_matrix);
+ }
+ }
+ }
+
wlr_output_render_software_cursors(output, &damage);
wlr_renderer_end(renderer);
@@ -1176,7 +1269,14 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) {
wlr_output_set_damage(output, &frame_damage);
pixman_region32_fini(&frame_damage);
- return wlr_output_commit(output);
+ bool success = wlr_output_commit(output);
+
+ if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
+ !wl_list_empty(&scene_output->scene->damage_highlight_regions)) {
+ wlr_output_schedule_frame(scene_output->output);
+ }
+
+ return success;
}
static void scene_node_send_frame_done(struct wlr_scene_node *node,