Damage tracking for transformed outputs

This commit is contained in:
emersion 2018-01-26 22:11:09 +01:00
parent a98ece68d3
commit ece2c1e4e2
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48
12 changed files with 185 additions and 154 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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);

View File

@ -6,5 +6,5 @@ lib_wlr_util = static_library(
'region.c',
),
include_directories: wlr_inc,
dependencies: [pixman],
dependencies: [wayland_server, pixman],
)

View File

@ -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);
}