diff options
| -rw-r--r-- | wlr_scene.c | 102 | 
1 files changed, 101 insertions, 1 deletions
diff --git a/wlr_scene.c b/wlr_scene.c index 6f0591b..676fe12 100644 --- a/wlr_scene.c +++ b/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(¤t_damage->region); +				pixman_region32_copy(¤t_damage->region, +					&scene_output->damage->current); +				memcpy(¤t_damage->when, &now, sizeof(now)); +				wl_list_insert(regions, ¤t_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,  | 
