parent
							
								
									7abda952d0
								
							
						
					
					
						commit
						9ef98452a3
					
				| @ -1,95 +0,0 @@ | ||||
| /*
 | ||||
|  * This an unstable interface of wlroots. No guarantees are made regarding the | ||||
|  * future consistency of this API. | ||||
|  */ | ||||
| #ifndef WLR_USE_UNSTABLE | ||||
| #error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features" | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * NOTE: wlr/types/wlr_output_damage.h is deprecated and will be removed in | ||||
|  * the next release. Use wlr/types/wlr_damage_ring.h instead. | ||||
|  */ | ||||
| 
 | ||||
| #ifndef WLR_TYPES_WLR_OUTPUT_DAMAGE_H | ||||
| #define WLR_TYPES_WLR_OUTPUT_DAMAGE_H | ||||
| 
 | ||||
| #include <pixman.h> | ||||
| #include <time.h> | ||||
| #include <wlr/types/wlr_output.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * Damage tracking requires to keep track of previous frames' damage. To allow | ||||
|  * damage tracking to work with triple buffering, a history of two frames is | ||||
|  * required. | ||||
|  */ | ||||
| #define WLR_OUTPUT_DAMAGE_PREVIOUS_LEN 2 | ||||
| 
 | ||||
| struct wlr_box; | ||||
| 
 | ||||
| /**
 | ||||
|  * Tracks damage for an output. | ||||
|  * | ||||
|  * The `frame` event will be emitted when it is a good time for the compositor | ||||
|  * to submit a new frame. | ||||
|  * | ||||
|  * To render a new frame, compositors should call | ||||
|  * wlr_output_damage_attach_render(), render and call wlr_output_commit(). No | ||||
|  * rendering should happen outside a `frame` event handler or before | ||||
|  * wlr_output_damage_attach_render(). | ||||
|  */ | ||||
| struct wlr_output_damage { | ||||
| 	struct wlr_output *output; | ||||
| 	int max_rects; // max number of damaged rectangles
 | ||||
| 
 | ||||
| 	pixman_region32_t current; // in output-local coordinates
 | ||||
| 
 | ||||
| 	// circular queue for previous damage
 | ||||
| 	pixman_region32_t previous[WLR_OUTPUT_DAMAGE_PREVIOUS_LEN]; | ||||
| 	size_t previous_idx; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal frame; | ||||
| 		struct wl_signal destroy; | ||||
| 	} events; | ||||
| 
 | ||||
| 	struct wl_listener output_destroy; | ||||
| 	struct wl_listener output_needs_frame; | ||||
| 	struct wl_listener output_damage; | ||||
| 	struct wl_listener output_frame; | ||||
| 	struct wl_listener output_commit; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_output_damage *wlr_output_damage_create(struct wlr_output *output); | ||||
| void wlr_output_damage_destroy(struct wlr_output_damage *output_damage); | ||||
| /**
 | ||||
|  * Attach the renderer's buffer to the output. Compositors must call this | ||||
|  * function before rendering. After they are done rendering, they should call | ||||
|  * wlr_output_set_damage() and wlr_output_commit() to submit the new frame. | ||||
|  * | ||||
|  * `needs_frame` will be set to true if a frame should be submitted. `damage` | ||||
|  * will be set to the region of the output that needs to be repainted, in | ||||
|  * output-buffer-local coordinates. | ||||
|  * | ||||
|  * The buffer damage region accumulates all damage since the buffer has last | ||||
|  * been swapped. This is not to be confused with the output surface damage, | ||||
|  * which only contains the changes between two frames. | ||||
|  */ | ||||
| bool wlr_output_damage_attach_render(struct wlr_output_damage *output_damage, | ||||
| 	bool *needs_frame, pixman_region32_t *buffer_damage); | ||||
| /**
 | ||||
|  * Accumulates damage and schedules a `frame` event. | ||||
|  */ | ||||
| void wlr_output_damage_add(struct wlr_output_damage *output_damage, | ||||
| 	const pixman_region32_t *damage); | ||||
| /**
 | ||||
|  * Damages the whole output and schedules a `frame` event. | ||||
|  */ | ||||
| void wlr_output_damage_add_whole(struct wlr_output_damage *output_damage); | ||||
| /**
 | ||||
|  * Accumulates damage from a box and schedules a `frame` event. | ||||
|  */ | ||||
| void wlr_output_damage_add_box(struct wlr_output_damage *output_damage, | ||||
| 	struct wlr_box *box); | ||||
| 
 | ||||
| #endif | ||||
| @ -1,196 +0,0 @@ | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <wayland-server-core.h> | ||||
| #include <wlr/types/wlr_output_damage.h> | ||||
| #include <wlr/types/wlr_output.h> | ||||
| #include <wlr/util/box.h> | ||||
| #include "types/wlr_output.h" | ||||
| 
 | ||||
| static void output_handle_destroy(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output_damage *output_damage = | ||||
| 		wl_container_of(listener, output_damage, output_destroy); | ||||
| 	wlr_output_damage_destroy(output_damage); | ||||
| } | ||||
| 
 | ||||
| static void output_handle_needs_frame(struct wl_listener *listener, | ||||
| 		void *data) { | ||||
| 	struct wlr_output_damage *output_damage = | ||||
| 		wl_container_of(listener, output_damage, output_needs_frame); | ||||
| 	wlr_output_schedule_frame(output_damage->output); | ||||
| } | ||||
| 
 | ||||
| static void output_handle_damage(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output_damage *output_damage = | ||||
| 		wl_container_of(listener, output_damage, output_damage); | ||||
| 	struct wlr_output_event_damage *event = data; | ||||
| 	wlr_output_damage_add(output_damage, event->damage); | ||||
| } | ||||
| 
 | ||||
| static void output_handle_frame(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output_damage *output_damage = | ||||
| 		wl_container_of(listener, output_damage, output_frame); | ||||
| 
 | ||||
| 	if (!output_damage->output->enabled) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	wl_signal_emit_mutable(&output_damage->events.frame, output_damage); | ||||
| } | ||||
| 
 | ||||
| static void output_handle_commit(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output_damage *output_damage = | ||||
| 		wl_container_of(listener, output_damage, output_commit); | ||||
| 	struct wlr_output_event_commit *event = data; | ||||
| 
 | ||||
| 	if (event->committed & WLR_OUTPUT_STATE_BUFFER) { | ||||
| 		pixman_region32_t *prev; | ||||
| 		if (!output_is_direct_scanout(output_damage->output, event->buffer)) { | ||||
| 			// render-buffers have been swapped, rotate the damage
 | ||||
| 
 | ||||
| 			// same as decrementing, but works on unsigned integers
 | ||||
| 			output_damage->previous_idx += WLR_OUTPUT_DAMAGE_PREVIOUS_LEN - 1; | ||||
| 			output_damage->previous_idx %= WLR_OUTPUT_DAMAGE_PREVIOUS_LEN; | ||||
| 
 | ||||
| 			prev = &output_damage->previous[output_damage->previous_idx]; | ||||
| 			pixman_region32_copy(prev, &output_damage->current); | ||||
| 		} else { | ||||
| 			// accumulate render-buffer damage
 | ||||
| 			prev = &output_damage->previous[output_damage->previous_idx]; | ||||
| 			pixman_region32_union(prev, prev, &output_damage->current); | ||||
| 		} | ||||
| 
 | ||||
| 		pixman_region32_clear(&output_damage->current); | ||||
| 	} | ||||
| 
 | ||||
| 	if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_SCALE | | ||||
| 			WLR_OUTPUT_STATE_TRANSFORM)) { | ||||
| 		wlr_output_damage_add_whole(output_damage); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| struct wlr_output_damage *wlr_output_damage_create(struct wlr_output *output) { | ||||
| 	struct wlr_output_damage *output_damage = | ||||
| 		calloc(1, sizeof(struct wlr_output_damage)); | ||||
| 	if (output_damage == NULL) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	output_damage->output = output; | ||||
| 	output_damage->max_rects = 20; | ||||
| 	wl_signal_init(&output_damage->events.frame); | ||||
| 	wl_signal_init(&output_damage->events.destroy); | ||||
| 
 | ||||
| 	pixman_region32_init(&output_damage->current); | ||||
| 	for (size_t i = 0; i < WLR_OUTPUT_DAMAGE_PREVIOUS_LEN; ++i) { | ||||
| 		pixman_region32_init(&output_damage->previous[i]); | ||||
| 	} | ||||
| 
 | ||||
| 	wl_signal_add(&output->events.destroy, &output_damage->output_destroy); | ||||
| 	output_damage->output_destroy.notify = output_handle_destroy; | ||||
| 	wl_signal_add(&output->events.needs_frame, &output_damage->output_needs_frame); | ||||
| 	output_damage->output_needs_frame.notify = output_handle_needs_frame; | ||||
| 	wl_signal_add(&output->events.damage, &output_damage->output_damage); | ||||
| 	output_damage->output_damage.notify = output_handle_damage; | ||||
| 	wl_signal_add(&output->events.frame, &output_damage->output_frame); | ||||
| 	output_damage->output_frame.notify = output_handle_frame; | ||||
| 	wl_signal_add(&output->events.commit, &output_damage->output_commit); | ||||
| 	output_damage->output_commit.notify = output_handle_commit; | ||||
| 
 | ||||
| 	return output_damage; | ||||
| } | ||||
| 
 | ||||
| void wlr_output_damage_destroy(struct wlr_output_damage *output_damage) { | ||||
| 	if (output_damage == NULL) { | ||||
| 		return; | ||||
| 	} | ||||
| 	wl_signal_emit_mutable(&output_damage->events.destroy, output_damage); | ||||
| 	wl_list_remove(&output_damage->output_destroy.link); | ||||
| 	wl_list_remove(&output_damage->output_needs_frame.link); | ||||
| 	wl_list_remove(&output_damage->output_damage.link); | ||||
| 	wl_list_remove(&output_damage->output_frame.link); | ||||
| 	wl_list_remove(&output_damage->output_commit.link); | ||||
| 	pixman_region32_fini(&output_damage->current); | ||||
| 	for (size_t i = 0; i < WLR_OUTPUT_DAMAGE_PREVIOUS_LEN; ++i) { | ||||
| 		pixman_region32_fini(&output_damage->previous[i]); | ||||
| 	} | ||||
| 	free(output_damage); | ||||
| } | ||||
| 
 | ||||
| bool wlr_output_damage_attach_render(struct wlr_output_damage *output_damage, | ||||
| 		bool *needs_frame, pixman_region32_t *damage) { | ||||
| 	struct wlr_output *output = output_damage->output; | ||||
| 
 | ||||
| 	int buffer_age = -1; | ||||
| 	if (!wlr_output_attach_render(output, &buffer_age)) { | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	*needs_frame = | ||||
| 		output->needs_frame || pixman_region32_not_empty(&output_damage->current); | ||||
| 	// Check if we can use damage tracking
 | ||||
| 	if (buffer_age <= 0 || buffer_age - 1 > WLR_OUTPUT_DAMAGE_PREVIOUS_LEN) { | ||||
| 		int width, height; | ||||
| 		wlr_output_transformed_resolution(output, &width, &height); | ||||
| 
 | ||||
| 		// Buffer new or too old, damage the whole output
 | ||||
| 		pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||||
| 		*needs_frame = true; | ||||
| 	} else { | ||||
| 		pixman_region32_copy(damage, &output_damage->current); | ||||
| 
 | ||||
| 		// Accumulate damage from old buffers
 | ||||
| 		size_t idx = output_damage->previous_idx; | ||||
| 		for (int i = 0; i < buffer_age - 1; ++i) { | ||||
| 			int j = (idx + i) % WLR_OUTPUT_DAMAGE_PREVIOUS_LEN; | ||||
| 			pixman_region32_union(damage, damage, &output_damage->previous[j]); | ||||
| 		} | ||||
| 
 | ||||
| 		// Check the number of rectangles
 | ||||
| 		int n_rects = pixman_region32_n_rects(damage); | ||||
| 		if (n_rects > output_damage->max_rects) { | ||||
| 			pixman_box32_t *extents = pixman_region32_extents(damage); | ||||
| 			pixman_region32_union_rect(damage, damage, extents->x1, extents->y1, | ||||
| 				extents->x2 - extents->x1, extents->y2 - extents->y1); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| void wlr_output_damage_add(struct wlr_output_damage *output_damage, | ||||
| 		const pixman_region32_t *damage) { | ||||
| 	int width, height; | ||||
| 	wlr_output_transformed_resolution(output_damage->output, &width, &height); | ||||
| 
 | ||||
| 	pixman_region32_t clipped_damage; | ||||
| 	pixman_region32_init(&clipped_damage); | ||||
| 	pixman_region32_intersect_rect(&clipped_damage, damage, 0, 0, width, height); | ||||
| 
 | ||||
| 	if (pixman_region32_not_empty(&clipped_damage)) { | ||||
| 		pixman_region32_union(&output_damage->current, &output_damage->current, | ||||
| 			&clipped_damage); | ||||
| 		wlr_output_schedule_frame(output_damage->output); | ||||
| 	} | ||||
| 
 | ||||
| 	pixman_region32_fini(&clipped_damage); | ||||
| } | ||||
| 
 | ||||
| void wlr_output_damage_add_whole(struct wlr_output_damage *output_damage) { | ||||
| 	int width, height; | ||||
| 	wlr_output_transformed_resolution(output_damage->output, &width, &height); | ||||
| 
 | ||||
| 	pixman_region32_union_rect(&output_damage->current, &output_damage->current, | ||||
| 		0, 0, width, height); | ||||
| 
 | ||||
| 	wlr_output_schedule_frame(output_damage->output); | ||||
| } | ||||
| 
 | ||||
| void wlr_output_damage_add_box(struct wlr_output_damage *output_damage, | ||||
| 		struct wlr_box *box) { | ||||
| 	pixman_region32_t damage; | ||||
| 	pixman_region32_init_rect(&damage, | ||||
| 		box->x, box->y, box->width, box->height); | ||||
| 	wlr_output_damage_add(output_damage, &damage); | ||||
| 	pixman_region32_fini(&damage); | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue