Damage tracking for transformed outputs
This commit is contained in:
		
							parent
							
								
									a98ece68d3
								
							
						
					
					
						commit
						ece2c1e4e2
					
				| 
						 | 
				
			
			@ -581,15 +581,14 @@ static bool wlr_drm_connector_set_cursor(struct wlr_output *output,
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	struct wlr_box hotspot = {
 | 
			
		||||
		.width = plane->surf.width,
 | 
			
		||||
		.height = plane->surf.height,
 | 
			
		||||
		.x = hotspot_x,
 | 
			
		||||
		.y = hotspot_y,
 | 
			
		||||
	};
 | 
			
		||||
	enum wl_output_transform transform =
 | 
			
		||||
		wlr_output_transform_invert(output->transform);
 | 
			
		||||
	struct wlr_box transformed_hotspot;
 | 
			
		||||
	wlr_box_transform(&hotspot, transform, &transformed_hotspot);
 | 
			
		||||
	wlr_box_transform(&hotspot, transform,
 | 
			
		||||
		plane->surf.width, plane->surf.height, &transformed_hotspot);
 | 
			
		||||
	plane->cursor_hotspot_x = transformed_hotspot.x;
 | 
			
		||||
	plane->cursor_hotspot_y = transformed_hotspot.y;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -650,15 +649,15 @@ static bool wlr_drm_connector_move_cursor(struct wlr_output *output,
 | 
			
		|||
	}
 | 
			
		||||
	struct wlr_drm_plane *plane = conn->crtc->cursor;
 | 
			
		||||
 | 
			
		||||
	struct wlr_box box;
 | 
			
		||||
	box.x = x;
 | 
			
		||||
	box.y = y;
 | 
			
		||||
	wlr_output_effective_resolution(output, &box.width, &box.height);
 | 
			
		||||
	struct wlr_box box = { .x = x, .y = y };
 | 
			
		||||
 | 
			
		||||
	int width, height;
 | 
			
		||||
	wlr_output_effective_resolution(output, &width, &height);
 | 
			
		||||
 | 
			
		||||
	enum wl_output_transform transform =
 | 
			
		||||
		wlr_output_transform_invert(output->transform);
 | 
			
		||||
	struct wlr_box transformed_box;
 | 
			
		||||
	wlr_box_transform(&box, transform, &transformed_box);
 | 
			
		||||
	wlr_box_transform(&box, transform, width, height, &transformed_box);
 | 
			
		||||
 | 
			
		||||
	if (plane != NULL) {
 | 
			
		||||
		transformed_box.x -= plane->cursor_hotspot_x;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,14 +54,16 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
 | 
			
		|||
 | 
			
		||||
	struct wlr_output *wlr_output = &wlr_wl_pointer->current_output->wlr_output;
 | 
			
		||||
 | 
			
		||||
	struct wlr_box box;
 | 
			
		||||
	int width, height;
 | 
			
		||||
	wl_egl_window_get_attached_size(wlr_wl_pointer->current_output->egl_window,
 | 
			
		||||
		&box.width, &box.height);
 | 
			
		||||
	box.x = wl_fixed_to_int(surface_x);
 | 
			
		||||
	box.y = wl_fixed_to_int(surface_y);
 | 
			
		||||
		&width, &height);
 | 
			
		||||
 | 
			
		||||
	struct wlr_box box = {
 | 
			
		||||
		.x = wl_fixed_to_int(surface_x),
 | 
			
		||||
		.y = wl_fixed_to_int(surface_y),
 | 
			
		||||
	};
 | 
			
		||||
	struct wlr_box transformed;
 | 
			
		||||
	wlr_box_transform(&box, wlr_output->transform, &transformed);
 | 
			
		||||
	wlr_box_transform(&box, wlr_output->transform, width, height, &transformed);
 | 
			
		||||
	transformed.x /= wlr_output->scale;
 | 
			
		||||
	transformed.y /= wlr_output->scale;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@
 | 
			
		|||
 | 
			
		||||
/**
 | 
			
		||||
 * Damage tracking requires to keep track of previous frames' damage. To allow
 | 
			
		||||
 * damage tracking to work with triple buffering, an history of two frames is
 | 
			
		||||
 * damage tracking to work with triple buffering, a history of two frames is
 | 
			
		||||
 * required.
 | 
			
		||||
 */
 | 
			
		||||
#define ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN 2
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ struct roots_output {
 | 
			
		|||
	struct roots_view *fullscreen_view;
 | 
			
		||||
 | 
			
		||||
	struct timespec last_frame;
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
	pixman_region32_t damage; // in ouput-local coordinates
 | 
			
		||||
	bool frame_pending;
 | 
			
		||||
 | 
			
		||||
	// circular queue for previous damage
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#define WLR_TYPES_WLR_BOX_H
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
struct wlr_box {
 | 
			
		||||
	int x, y;
 | 
			
		||||
| 
						 | 
				
			
			@ -18,8 +19,11 @@ bool wlr_box_contains_point(const struct wlr_box *box, double x, double y);
 | 
			
		|||
 | 
			
		||||
bool wlr_box_empty(const struct wlr_box *box);
 | 
			
		||||
 | 
			
		||||
enum wl_output_transform;
 | 
			
		||||
/**
 | 
			
		||||
 * Transforms a box inside a `width` x `height` box.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_box_transform(const struct wlr_box *box,
 | 
			
		||||
	enum wl_output_transform transform, struct wlr_box *dest);
 | 
			
		||||
	enum wl_output_transform transform, int width, int height,
 | 
			
		||||
	struct wlr_box *dest);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,7 +61,8 @@ struct wlr_output {
 | 
			
		|||
	enum wl_output_transform transform;
 | 
			
		||||
 | 
			
		||||
	bool needs_swap;
 | 
			
		||||
	pixman_region32_t damage; // damage for cursors and fullscreen surface
 | 
			
		||||
	// damage for cursors and fullscreen surface, in output-local coordinates
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
	float transform_matrix[16];
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#define WLR_UTIL_REGION_H
 | 
			
		||||
 | 
			
		||||
#include <pixman.h>
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Scales a region, ie. multiplies all its coordinates by `scale`.
 | 
			
		||||
| 
						 | 
				
			
			@ -12,4 +13,10 @@
 | 
			
		|||
void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src,
 | 
			
		||||
	float scale);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Applies a transform to a region inside a box of size `width` x `height`.
 | 
			
		||||
 */
 | 
			
		||||
void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src,
 | 
			
		||||
	enum wl_output_transform transform, int width, int height);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -170,6 +170,39 @@ static bool surface_intersect_output(struct wlr_surface *surface,
 | 
			
		|||
	return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void output_get_transformed_size(struct wlr_output *wlr_output,
 | 
			
		||||
		int *width, int *height) {
 | 
			
		||||
	if (wlr_output->transform % 2 == 0) {
 | 
			
		||||
		*width = wlr_output->width;
 | 
			
		||||
		*height = wlr_output->height;
 | 
			
		||||
	} else {
 | 
			
		||||
		*width = wlr_output->height;
 | 
			
		||||
		*height = wlr_output->width;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void scissor_output(struct roots_output *output, pixman_box32_t *rect) {
 | 
			
		||||
	struct wlr_output *wlr_output = output->wlr_output;
 | 
			
		||||
 | 
			
		||||
	struct wlr_box box = {
 | 
			
		||||
		.x = rect->x1,
 | 
			
		||||
		.y = rect->y1,
 | 
			
		||||
		.width = rect->x2 - rect->x1,
 | 
			
		||||
		.height = rect->y2 - rect->y1,
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	int ow, oh;
 | 
			
		||||
	output_get_transformed_size(output->wlr_output, &ow, &oh);
 | 
			
		||||
 | 
			
		||||
	// Scissor is in renderer coordinates, ie. upside down
 | 
			
		||||
	enum wl_output_transform transform = wlr_output_transform_compose(
 | 
			
		||||
		wlr_output_transform_invert(wlr_output->transform),
 | 
			
		||||
		WL_OUTPUT_TRANSFORM_FLIPPED_180);
 | 
			
		||||
	wlr_box_transform(&box, transform, ow, oh, &box);
 | 
			
		||||
 | 
			
		||||
	wlr_renderer_scissor(output->desktop->server->renderer, &box);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void render_surface(struct wlr_surface *surface, double lx, double ly,
 | 
			
		||||
		float rotation, void *_data) {
 | 
			
		||||
	struct render_data *data = _data;
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +220,6 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly,
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: output transform support
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
	pixman_region32_init(&damage);
 | 
			
		||||
	pixman_region32_union_rect(&damage, &damage, box.x, box.y,
 | 
			
		||||
| 
						 | 
				
			
			@ -205,16 +237,9 @@ static void render_surface(struct wlr_surface *surface, double lx, double ly,
 | 
			
		|||
		&output->wlr_output->transform_matrix);
 | 
			
		||||
 | 
			
		||||
	int nrects;
 | 
			
		||||
	pixman_box32_t *rects =
 | 
			
		||||
		pixman_region32_rectangles(&damage, &nrects);
 | 
			
		||||
	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
 | 
			
		||||
	for (int i = 0; i < nrects; ++i) {
 | 
			
		||||
		struct wlr_box scissor = {
 | 
			
		||||
			.x = rects[i].x1,
 | 
			
		||||
			.y = output->wlr_output->height - rects[i].y2,
 | 
			
		||||
			.width = rects[i].x2 - rects[i].x1,
 | 
			
		||||
			.height = rects[i].y2 - rects[i].y1,
 | 
			
		||||
		};
 | 
			
		||||
		wlr_renderer_scissor(output->desktop->server->renderer, &scissor);
 | 
			
		||||
		scissor_output(output, &rects[i]);
 | 
			
		||||
		wlr_render_with_matrix(output->desktop->server->renderer,
 | 
			
		||||
			surface->texture, &matrix);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +283,6 @@ static void render_decorations(struct roots_view *view,
 | 
			
		|||
	struct wlr_box box;
 | 
			
		||||
	get_decoration_box(view, output, &box);
 | 
			
		||||
 | 
			
		||||
	// TODO: output transform support
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
	pixman_region32_init(&damage);
 | 
			
		||||
	pixman_region32_union_rect(&damage, &damage, box.x, box.y,
 | 
			
		||||
| 
						 | 
				
			
			@ -278,13 +302,7 @@ static void render_decorations(struct roots_view *view,
 | 
			
		|||
	pixman_box32_t *rects =
 | 
			
		||||
		pixman_region32_rectangles(&damage, &nrects);
 | 
			
		||||
	for (int i = 0; i < nrects; ++i) {
 | 
			
		||||
		struct wlr_box scissor = {
 | 
			
		||||
			.x = rects[i].x1,
 | 
			
		||||
			.y = output->wlr_output->height - rects[i].y2,
 | 
			
		||||
			.width = rects[i].x2 - rects[i].x1,
 | 
			
		||||
			.height = rects[i].y2 - rects[i].y1,
 | 
			
		||||
		};
 | 
			
		||||
		wlr_renderer_scissor(output->desktop->server->renderer, &scissor);
 | 
			
		||||
		scissor_output(output, &rects[i]);
 | 
			
		||||
		wlr_render_colored_quad(output->desktop->server->renderer, &color,
 | 
			
		||||
			&matrix);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -359,13 +377,15 @@ static void render_output(struct roots_output *output) {
 | 
			
		|||
	int buffer_age = -1;
 | 
			
		||||
	wlr_output_make_current(wlr_output, &buffer_age);
 | 
			
		||||
 | 
			
		||||
	int width, height;
 | 
			
		||||
	output_get_transformed_size(output->wlr_output, &width, &height);
 | 
			
		||||
 | 
			
		||||
	// Check if we can use damage tracking
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
	pixman_region32_init(&damage);
 | 
			
		||||
	if (buffer_age <= 0 || buffer_age - 1 > ROOTS_OUTPUT_PREVIOUS_DAMAGE_LEN) {
 | 
			
		||||
		// Buffer new or too old, damage the whole output
 | 
			
		||||
		pixman_region32_union_rect(&damage, &damage, 0, 0,
 | 
			
		||||
			wlr_output->width, wlr_output->height);
 | 
			
		||||
		pixman_region32_union_rect(&damage, &damage, 0, 0, width, height);
 | 
			
		||||
	} else {
 | 
			
		||||
		pixman_region32_copy(&damage, &output->damage);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -376,8 +396,7 @@ static void render_output(struct roots_output *output) {
 | 
			
		|||
			pixman_region32_union(&damage, &damage, &output->previous_damage[j]);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	pixman_region32_intersect_rect(&damage, &damage, 0, 0,
 | 
			
		||||
		wlr_output->width, wlr_output->height);
 | 
			
		||||
	pixman_region32_intersect_rect(&damage, &damage, 0, 0, width, height);
 | 
			
		||||
 | 
			
		||||
	if (!pixman_region32_not_empty(&damage) && !wlr_output->needs_swap) {
 | 
			
		||||
		// Output doesn't need swap and isn't damaged, skip rendering completely
 | 
			
		||||
| 
						 | 
				
			
			@ -401,13 +420,7 @@ static void render_output(struct roots_output *output) {
 | 
			
		|||
	int nrects;
 | 
			
		||||
	pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects);
 | 
			
		||||
	for (int i = 0; i < nrects; ++i) {
 | 
			
		||||
		struct wlr_box scissor = {
 | 
			
		||||
			.x = rects[i].x1,
 | 
			
		||||
			.y = wlr_output->height - rects[i].y2,
 | 
			
		||||
			.width = rects[i].x2 - rects[i].x1,
 | 
			
		||||
			.height = rects[i].y2 - rects[i].y1,
 | 
			
		||||
		};
 | 
			
		||||
		wlr_renderer_scissor(output->desktop->server->renderer, &scissor);
 | 
			
		||||
		scissor_output(output, &rects[i]);
 | 
			
		||||
		wlr_renderer_clear(output->desktop->server->renderer,
 | 
			
		||||
			clear_color[0], clear_color[1], clear_color[2], 1);
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -491,8 +504,11 @@ static void schedule_render(struct roots_output *output) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static void output_damage_whole(struct roots_output *output) {
 | 
			
		||||
	pixman_region32_union_rect(&output->damage, &output->damage,
 | 
			
		||||
		0, 0, output->wlr_output->width, output->wlr_output->height);
 | 
			
		||||
	int width, height;
 | 
			
		||||
	output_get_transformed_size(output->wlr_output, &width, &height);
 | 
			
		||||
 | 
			
		||||
	pixman_region32_union_rect(&output->damage, &output->damage, 0, 0,
 | 
			
		||||
		width, height);
 | 
			
		||||
 | 
			
		||||
	schedule_render(output);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -584,7 +600,6 @@ static void damage_from_surface(struct wlr_surface *surface,
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: output transform support
 | 
			
		||||
	pixman_region32_t damage;
 | 
			
		||||
	pixman_region32_init(&damage);
 | 
			
		||||
	pixman_region32_copy(&damage, &surface->current->surface_damage);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,47 +67,50 @@ bool wlr_box_contains_point(const struct wlr_box *box, double x, double y) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void wlr_box_transform(const struct wlr_box *box,
 | 
			
		||||
		enum wl_output_transform transform, struct wlr_box *dest) {
 | 
			
		||||
		enum wl_output_transform transform, int width, int height,
 | 
			
		||||
		struct wlr_box *dest) {
 | 
			
		||||
	struct wlr_box src = *box;
 | 
			
		||||
 | 
			
		||||
	if (transform % 2 == 0) {
 | 
			
		||||
		dest->width = box->width;
 | 
			
		||||
		dest->height = box->height;
 | 
			
		||||
		dest->width = src.width;
 | 
			
		||||
		dest->height = src.height;
 | 
			
		||||
	} else {
 | 
			
		||||
		dest->width = box->height;
 | 
			
		||||
		dest->height = box->width;
 | 
			
		||||
		dest->width = src.height;
 | 
			
		||||
		dest->height = src.width;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch (transform) {
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_NORMAL:
 | 
			
		||||
		dest->x = box->x;
 | 
			
		||||
		dest->y = box->y;
 | 
			
		||||
		dest->x = src.x;
 | 
			
		||||
		dest->y = src.y;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_90:
 | 
			
		||||
		dest->x = box->y;
 | 
			
		||||
		dest->y = box->width - box->x;
 | 
			
		||||
		dest->x = src.y;
 | 
			
		||||
		dest->y = width - src.x - src.width;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_180:
 | 
			
		||||
		dest->x = box->width - box->x;
 | 
			
		||||
		dest->y = box->height - box->y;
 | 
			
		||||
		dest->x = width - src.x - src.width;
 | 
			
		||||
		dest->y = height - src.y - src.height;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_270:
 | 
			
		||||
		dest->x = box->height - box->y;
 | 
			
		||||
		dest->y = box->x;
 | 
			
		||||
		dest->x = height - src.y - src.height;
 | 
			
		||||
		dest->y = src.x;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_FLIPPED:
 | 
			
		||||
		dest->x = box->width - box->x;
 | 
			
		||||
		dest->y = box->y;
 | 
			
		||||
		dest->x = width - src.x - src.width;
 | 
			
		||||
		dest->y = src.y;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 | 
			
		||||
		dest->x = box->height - box->y;
 | 
			
		||||
		dest->y = box->width - box->x;
 | 
			
		||||
		dest->x = height - src.y - src.height;
 | 
			
		||||
		dest->y = width - src.x - src.width;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
 | 
			
		||||
		dest->x = box->x;
 | 
			
		||||
		dest->y = box->height - box->y;
 | 
			
		||||
		dest->x = src.x;
 | 
			
		||||
		dest->y = height - src.y - src.height;
 | 
			
		||||
		break;
 | 
			
		||||
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
 | 
			
		||||
		dest->x = box->y;
 | 
			
		||||
		dest->y = box->x;
 | 
			
		||||
		dest->x = src.y;
 | 
			
		||||
		dest->y = src.x;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,7 @@
 | 
			
		|||
#include <wlr/render/matrix.h>
 | 
			
		||||
#include <wlr/render/gles2.h>
 | 
			
		||||
#include <wlr/render.h>
 | 
			
		||||
#include <wlr/util/region.h>
 | 
			
		||||
 | 
			
		||||
static void wl_output_send_to_resource(struct wl_resource *resource) {
 | 
			
		||||
	assert(resource);
 | 
			
		||||
| 
						 | 
				
			
			@ -554,6 +555,7 @@ static void output_fullscreen_surface_handle_commit(
 | 
			
		|||
	pixman_region32_t damage;
 | 
			
		||||
	pixman_region32_init(&damage);
 | 
			
		||||
	pixman_region32_copy(&damage, &surface->current->surface_damage);
 | 
			
		||||
	wlr_region_scale(&damage, &damage, output->scale);
 | 
			
		||||
	pixman_region32_translate(&damage, box.x, box.y);
 | 
			
		||||
	pixman_region32_union(&output->damage, &output->damage, &damage);
 | 
			
		||||
	pixman_region32_fini(&damage);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
#include <stdlib.h>
 | 
			
		||||
#include <wayland-server.h>
 | 
			
		||||
#include <wlr/util/log.h>
 | 
			
		||||
#include <wlr/util/region.h>
 | 
			
		||||
#include <wlr/render/interface.h>
 | 
			
		||||
#include <wlr/types/wlr_surface.h>
 | 
			
		||||
#include <wlr/render/egl.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -185,85 +186,6 @@ static bool wlr_surface_update_size(struct wlr_surface *surface,
 | 
			
		|||
	return update_damage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wlr_surface_to_buffer_region(int scale,
 | 
			
		||||
		enum wl_output_transform transform, pixman_region32_t *surface_region,
 | 
			
		||||
		pixman_region32_t *buffer_region, int width, int height) {
 | 
			
		||||
	int nrects;
 | 
			
		||||
	pixman_box32_t *src_rects =
 | 
			
		||||
		pixman_region32_rectangles(surface_region, &nrects);
 | 
			
		||||
	pixman_box32_t *dest_rects = malloc(nrects * sizeof(*dest_rects));
 | 
			
		||||
	if (dest_rects == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < nrects; i++) {
 | 
			
		||||
		switch (transform) {
 | 
			
		||||
		default:
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_NORMAL:
 | 
			
		||||
			dest_rects[i].x1 = src_rects[i].x1;
 | 
			
		||||
			dest_rects[i].y1 = src_rects[i].y1;
 | 
			
		||||
			dest_rects[i].x2 = src_rects[i].x2;
 | 
			
		||||
			dest_rects[i].y2 = src_rects[i].y2;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_90:
 | 
			
		||||
			dest_rects[i].x1 = height - src_rects[i].y2;
 | 
			
		||||
			dest_rects[i].y1 = src_rects[i].x1;
 | 
			
		||||
			dest_rects[i].x2 = height - src_rects[i].y1;
 | 
			
		||||
			dest_rects[i].y2 = src_rects[i].x2;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_180:
 | 
			
		||||
			dest_rects[i].x1 = width - src_rects[i].x2;
 | 
			
		||||
			dest_rects[i].y1 = height - src_rects[i].y2;
 | 
			
		||||
			dest_rects[i].x2 = width - src_rects[i].x1;
 | 
			
		||||
			dest_rects[i].y2 = height - src_rects[i].y1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_270:
 | 
			
		||||
			dest_rects[i].x1 = src_rects[i].y1;
 | 
			
		||||
			dest_rects[i].y1 = width - src_rects[i].x2;
 | 
			
		||||
			dest_rects[i].x2 = src_rects[i].y2;
 | 
			
		||||
			dest_rects[i].y2 = width - src_rects[i].x1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED:
 | 
			
		||||
			dest_rects[i].x1 = width - src_rects[i].x2;
 | 
			
		||||
			dest_rects[i].y1 = src_rects[i].y1;
 | 
			
		||||
			dest_rects[i].x2 = width - src_rects[i].x1;
 | 
			
		||||
			dest_rects[i].y2 = src_rects[i].y2;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 | 
			
		||||
			dest_rects[i].x1 = height - src_rects[i].y2;
 | 
			
		||||
			dest_rects[i].y1 = width - src_rects[i].x2;
 | 
			
		||||
			dest_rects[i].x2 = height - src_rects[i].y1;
 | 
			
		||||
			dest_rects[i].y2 = width - src_rects[i].x1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_180:
 | 
			
		||||
			dest_rects[i].x1 = src_rects[i].x1;
 | 
			
		||||
			dest_rects[i].y1 = height - src_rects[i].y2;
 | 
			
		||||
			dest_rects[i].x2 = src_rects[i].x2;
 | 
			
		||||
			dest_rects[i].y2 = height - src_rects[i].y1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_270:
 | 
			
		||||
			dest_rects[i].x1 = src_rects[i].y1;
 | 
			
		||||
			dest_rects[i].y1 = src_rects[i].x1;
 | 
			
		||||
			dest_rects[i].x2 = src_rects[i].y2;
 | 
			
		||||
			dest_rects[i].y2 = src_rects[i].x2;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (scale != 1) {
 | 
			
		||||
		for (int i = 0; i < nrects; i++) {
 | 
			
		||||
			dest_rects[i].x1 *= scale;
 | 
			
		||||
			dest_rects[i].x2 *= scale;
 | 
			
		||||
			dest_rects[i].y1 *= scale;
 | 
			
		||||
			dest_rects[i].y2 *= scale;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pixman_region32_fini(buffer_region);
 | 
			
		||||
	pixman_region32_init_rects(buffer_region, dest_rects, nrects);
 | 
			
		||||
	free(dest_rects);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Append pending state to current state and clear pending state.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -314,9 +236,11 @@ static void wlr_surface_move_state(struct wlr_surface *surface,
 | 
			
		|||
	if (update_damage) {
 | 
			
		||||
		pixman_region32_t buffer_damage;
 | 
			
		||||
		pixman_region32_init(&buffer_damage);
 | 
			
		||||
		wlr_surface_to_buffer_region(state->scale, state->transform,
 | 
			
		||||
			&state->surface_damage, &buffer_damage, state->width,
 | 
			
		||||
			state->height);
 | 
			
		||||
		pixman_region32_copy(&buffer_damage, &state->surface_damage);
 | 
			
		||||
		wlr_region_transform(&buffer_damage, &buffer_damage,
 | 
			
		||||
			wlr_output_transform_invert(state->transform),
 | 
			
		||||
			state->width, state->height);
 | 
			
		||||
		wlr_region_scale(&buffer_damage, &buffer_damage, state->scale);
 | 
			
		||||
		pixman_region32_union(&state->buffer_damage,
 | 
			
		||||
			&state->buffer_damage, &buffer_damage);
 | 
			
		||||
		pixman_region32_fini(&buffer_damage);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,5 +6,5 @@ lib_wlr_util = static_library(
 | 
			
		|||
		'region.c',
 | 
			
		||||
	),
 | 
			
		||||
	include_directories: wlr_inc,
 | 
			
		||||
	dependencies: [pixman],
 | 
			
		||||
	dependencies: [wayland_server, pixman],
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,4 +26,78 @@ void wlr_region_scale(pixman_region32_t *dst, pixman_region32_t *src,
 | 
			
		|||
 | 
			
		||||
	pixman_region32_fini(dst);
 | 
			
		||||
	pixman_region32_init_rects(dst, dst_rects, nrects);
 | 
			
		||||
	free(dst_rects);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void wlr_region_transform(pixman_region32_t *dst, pixman_region32_t *src,
 | 
			
		||||
		enum wl_output_transform transform, int width, int height) {
 | 
			
		||||
	if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
 | 
			
		||||
		pixman_region32_copy(dst, src);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int nrects;
 | 
			
		||||
	pixman_box32_t *src_rects = pixman_region32_rectangles(src, &nrects);
 | 
			
		||||
 | 
			
		||||
	pixman_box32_t *dst_rects = malloc(nrects * sizeof(pixman_box32_t));
 | 
			
		||||
	if (dst_rects == NULL) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < nrects; ++i) {
 | 
			
		||||
		switch (transform) {
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_NORMAL:
 | 
			
		||||
			dst_rects[i].x1 = src_rects[i].x1;
 | 
			
		||||
			dst_rects[i].y1 = src_rects[i].y1;
 | 
			
		||||
			dst_rects[i].x2 = src_rects[i].x2;
 | 
			
		||||
			dst_rects[i].y2 = src_rects[i].y2;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_90:
 | 
			
		||||
			dst_rects[i].x1 = src_rects[i].y1;
 | 
			
		||||
			dst_rects[i].y1 = width - src_rects[i].x2;
 | 
			
		||||
			dst_rects[i].x2 = src_rects[i].y2;
 | 
			
		||||
			dst_rects[i].y2 = width - src_rects[i].x1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_180:
 | 
			
		||||
			dst_rects[i].x1 = width - src_rects[i].x2;
 | 
			
		||||
			dst_rects[i].y1 = height - src_rects[i].y2;
 | 
			
		||||
			dst_rects[i].x2 = width - src_rects[i].x1;
 | 
			
		||||
			dst_rects[i].y2 = height - src_rects[i].y1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_270:
 | 
			
		||||
			dst_rects[i].x1 = height - src_rects[i].y2;
 | 
			
		||||
			dst_rects[i].y1 = src_rects[i].x1;
 | 
			
		||||
			dst_rects[i].x2 = height - src_rects[i].y1;
 | 
			
		||||
			dst_rects[i].y2 = src_rects[i].x2;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED:
 | 
			
		||||
			dst_rects[i].x1 = width - src_rects[i].x2;
 | 
			
		||||
			dst_rects[i].y1 = src_rects[i].y1;
 | 
			
		||||
			dst_rects[i].x2 = width - src_rects[i].x1;
 | 
			
		||||
			dst_rects[i].y2 = src_rects[i].y2;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 | 
			
		||||
			dst_rects[i].x1 = height - src_rects[i].y2;
 | 
			
		||||
			dst_rects[i].y1 = width - src_rects[i].x2;
 | 
			
		||||
			dst_rects[i].x2 = height - src_rects[i].y1;
 | 
			
		||||
			dst_rects[i].y2 = width - src_rects[i].x1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_180:
 | 
			
		||||
			dst_rects[i].x1 = src_rects[i].x1;
 | 
			
		||||
			dst_rects[i].y1 = height - src_rects[i].y2;
 | 
			
		||||
			dst_rects[i].x2 = src_rects[i].x2;
 | 
			
		||||
			dst_rects[i].y2 = height - src_rects[i].y1;
 | 
			
		||||
			break;
 | 
			
		||||
		case WL_OUTPUT_TRANSFORM_FLIPPED_270:
 | 
			
		||||
			dst_rects[i].x1 = src_rects[i].y1;
 | 
			
		||||
			dst_rects[i].y1 = src_rects[i].x1;
 | 
			
		||||
			dst_rects[i].x2 = src_rects[i].y2;
 | 
			
		||||
			dst_rects[i].y2 = src_rects[i].x2;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pixman_region32_fini(dst);
 | 
			
		||||
	pixman_region32_init_rects(dst, dst_rects, nrects);
 | 
			
		||||
	free(dst_rects);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue