Skip to content
Commits on Source (6)
......@@ -112,7 +112,7 @@ weston_coord_global_to_surface(struct weston_view *view, struct weston_coord_glo
static void
global_to_surface(pixman_box32_t *rect, struct weston_view *ev,
struct clipper_vertex polygon[4], bool *axis_aligned)
struct clipper_vertex polygon[4])
{
struct weston_coord_global rect_g[4] = {
{ .c = weston_coord(rect->x1, rect->y1) },
......@@ -128,9 +128,13 @@ global_to_surface(pixman_box32_t *rect, struct weston_view *ev,
polygon[i].x = (float)rect_s.x;
polygon[i].y = (float)rect_s.y;
}
}
*axis_aligned = !ev->transform.enabled ||
(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
static bool
node_axis_aligned(const struct weston_view *view)
{
return !view->transform.enabled ||
(view->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
}
/* ---------------------- copied ends -----------------------*/
......@@ -279,12 +283,11 @@ redraw_handler(struct widget *widget, void *data)
cairo_surface_t *surface;
struct clipper_quad quad;
struct clipper_vertex transformed_v[4], v[8];
bool axis_aligned;
int n;
global_to_surface(&g->quad, &cliptest->view, transformed_v,
&axis_aligned);
clipper_quad_init(&quad, transformed_v, axis_aligned);
global_to_surface(&g->quad, &cliptest->view, transformed_v);
clipper_quad_init(&quad, transformed_v,
node_axis_aligned(&cliptest->view));
n = clipper_quad_clip_box32(&quad, &g->surf, v);
widget_get_allocation(cliptest->widget, &allocation);
......@@ -554,7 +557,6 @@ benchmark(void)
struct geometry geom;
struct clipper_quad quad;
struct clipper_vertex transformed_v[4], v[8];
bool axis_aligned;
int i;
double t;
const int N = 1000000;
......@@ -579,9 +581,9 @@ benchmark(void)
reset_timer();
for (i = 0; i < N; i++) {
geometry_set_phi(&geom, (float)i / 360.0f);
global_to_surface(&geom.quad, &view, transformed_v,
&axis_aligned);
clipper_quad_init(&quad, transformed_v, axis_aligned);
global_to_surface(&geom.quad, &view, transformed_v);
clipper_quad_init(&quad, transformed_v,
node_axis_aligned(&view));
clipper_quad_clip_box32(&quad, &geom.surf, v);
}
t = read_timer();
......
......@@ -471,115 +471,29 @@ timeline_submit_render_sync(struct gl_renderer *gr,
wl_list_insert(&go->timeline_render_point_list, &trp->link);
}
static void
global_to_surface(pixman_box32_t *rect, struct weston_view *ev,
struct clipper_vertex polygon[4], bool *axis_aligned)
{
struct weston_coord_global rect_g[4] = {
{ .c = weston_coord(rect->x1, rect->y1) },
{ .c = weston_coord(rect->x2, rect->y1) },
{ .c = weston_coord(rect->x2, rect->y2) },
{ .c = weston_coord(rect->x1, rect->y2) },
};
struct weston_coord rect_s;
int i;
for (i = 0; i < 4; i++) {
rect_s = weston_coord_global_to_surface(ev, rect_g[i]).c;
polygon[i].x = (float)rect_s.x;
polygon[i].y = (float)rect_s.y;
}
*axis_aligned = !ev->transform.enabled ||
(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
}
static bool
merge_down(pixman_box32_t *a, pixman_box32_t *b, pixman_box32_t *merge)
{
if (a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y2) {
merge->x1 = a->x1;
merge->x2 = a->x2;
merge->y1 = b->y1;
merge->y2 = a->y2;
return true;
}
return false;
}
static int
compress_bands(pixman_box32_t *inrects, int nrects, pixman_box32_t **outrects)
{
bool merged = false;
pixman_box32_t *out, merge_rect;
int i, j, nout;
if (!nrects) {
*outrects = NULL;
return 0;
}
/* nrects is an upper bound - we're not too worried about
* allocating a little extra
*/
out = malloc(sizeof(pixman_box32_t) * nrects);
out[0] = inrects[0];
nout = 1;
for (i = 1; i < nrects; i++) {
for (j = 0; j < nout; j++) {
merged = merge_down(&inrects[i], &out[j], &merge_rect);
if (merged) {
out[j] = merge_rect;
break;
}
}
if (!merged) {
out[nout] = inrects[i];
nout++;
}
}
*outrects = out;
return nout;
}
static int
texture_region(struct weston_paint_node *pnode,
pixman_region32_t *region,
pixman_region32_t *surf_region)
struct clipper_quad *quads,
int nquads,
pixman_region32_t *region)
{
struct weston_compositor *ec = pnode->surface->compositor;
struct weston_view *ev = pnode->view;
struct gl_renderer *gr = get_renderer(ec);
struct clipper_vertex *v;
unsigned int *vtxcnt, nvtx = 0;
pixman_box32_t *rects, *surf_rects;
pixman_box32_t *raw_rects;
int i, j, nrects, nsurf, raw_nrects;
bool used_band_compression, axis_aligned;
struct clipper_vertex polygon[4];
struct clipper_quad quad;
pixman_box32_t *rects;
int i, j, nrects;
raw_rects = pixman_region32_rectangles(region, &raw_nrects);
surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
rects = pixman_region32_rectangles(region, &nrects);
if (raw_nrects < 4) {
used_band_compression = false;
nrects = raw_nrects;
rects = raw_rects;
} else {
nrects = compress_bands(raw_rects, raw_nrects, &rects);
used_band_compression = true;
}
/* worst case we can have 8 vertices per rect (ie. clipped into
* an octagon):
*/
v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * sizeof *v);
vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
v = wl_array_add(&gr->vertices, nquads * nrects * 8 * sizeof *v);
vtxcnt = wl_array_add(&gr->vtxcnt, nquads * nrects * sizeof *vtxcnt);
for (i = 0; i < nrects; i++) {
global_to_surface(&rects[i], ev, polygon, &axis_aligned);
clipper_quad_init(&quad, polygon, axis_aligned);
for (j = 0; j < nsurf; j++) {
for (i = 0; i < nquads; i++) {
for (j = 0; j < nrects; j++) {
int n;
/* The transformed quad, after clipping to the surface rect, can
......@@ -595,7 +509,7 @@ texture_region(struct weston_paint_node *pnode,
* To do this, we first calculate the (up to eight) points at the
* intersection of the edges of the quad and the surface rect.
*/
n = clipper_quad_clip_box32(&quad, &surf_rects[j], v);
n = clipper_quad_clip_box32(&quads[i], &rects[j], v);
if (n >= 3) {
v += n;
vtxcnt[nvtx++] = n;
......@@ -603,8 +517,6 @@ texture_region(struct weston_paint_node *pnode,
}
}
if (used_band_compression)
free(rects);
return nvtx;
}
......@@ -1003,8 +915,9 @@ triangle_fan_debug(struct gl_renderer *gr,
static void
repaint_region(struct gl_renderer *gr,
struct weston_paint_node *pnode,
struct clipper_quad *quads,
int nquads,
pixman_region32_t *region,
pixman_region32_t *surf_region,
const struct gl_shader_config *sconf)
{
struct weston_output *output = pnode->output;
......@@ -1012,15 +925,15 @@ repaint_region(struct gl_renderer *gr,
unsigned int *vtxcnt;
int i, first, nfans;
/* The final region to be painted is the intersection of
* 'region' and 'surf_region'. However, 'region' is in the global
* coordinates, and 'surf_region' is in the surface-local
* coordinates. texture_region() will iterate over all pairs of
* rectangles from both regions, compute the intersection
* polygon for each pair, and store it as a triangle fan if
* it has a non-zero area (at least 3 vertices, actually).
/* The final region to be painted is the intersection of the damage
* rects and the surface region. However, damage rects are in global
* coordinates and surface region is in surface coordinates.
* texture_region() will iterate over all pairs of rectangles from both
* regions, compute the intersection polygon for each pair, and store it
* as a triangle fan if it has a non-zero area (at least 3 vertices,
* actually).
*/
nfans = texture_region(pnode, region, surf_region);
nfans = texture_region(pnode, quads, nquads, region);
v = gr->vertices.data;
vtxcnt = gr->vtxcnt.data;
......@@ -1262,6 +1175,112 @@ gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf,
return true;
}
/* A Pixman region is implemented as a "y-x-banded" array of rectangles sorted
* first vertically and then horizontally. This means that if 2 rectangles with
* different y coordinates share a group of scanlines, both rectangles will be
* split into 2 more rectangles with sharing edges. While Pixman coalesces
* rectangles in horizontal bands whenever possible, this function merges
* vertical bands.
*/
static int
compress_bands(pixman_box32_t *inrects, int nrects, pixman_box32_t **outrects)
{
pixman_box32_t *out;
int i, j, nout;
assert(nrects > 0);
/* nrects is an upper bound - we're not too worried about
* allocating a little extra
*/
out = malloc(sizeof(pixman_box32_t) * nrects);
out[0] = inrects[0];
nout = 1;
for (i = 1; i < nrects; i++) {
for (j = 0; j < nout; j++) {
if (inrects[i].x1 == out[j].x1 &&
inrects[i].x2 == out[j].x2 &&
inrects[i].y1 == out[j].y2) {
out[j].y2 = inrects[i].y2;
goto merged;
}
}
out[nout] = inrects[i];
nout++;
merged: ;
}
*outrects = out;
return nout;
}
static void
global_to_surface(pixman_box32_t *rect, struct weston_view *ev,
struct clipper_vertex polygon[4])
{
struct weston_coord_global rect_g[4] = {
{ .c = weston_coord(rect->x1, rect->y1) },
{ .c = weston_coord(rect->x2, rect->y1) },
{ .c = weston_coord(rect->x2, rect->y2) },
{ .c = weston_coord(rect->x1, rect->y2) },
};
struct weston_coord rect_s;
int i;
for (i = 0; i < 4; i++) {
rect_s = weston_coord_global_to_surface(ev, rect_g[i]).c;
polygon[i].x = (float)rect_s.x;
polygon[i].y = (float)rect_s.y;
}
}
static bool
node_axis_aligned(const struct weston_view *view)
{
return !view->transform.enabled ||
(view->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
}
/* Transform damage 'region' in global coordinates to damage 'quads' in surface
* coordinates. 'quads' and 'nquads' are output arguments set if 'quads' is
* NULL, no transformation happens otherwise. Caller must free 'quads' if
* set. Caller must ensure 'region' is not empty.
*/
static void
transform_damage(const struct weston_paint_node *pnode,
pixman_region32_t *region,
struct clipper_quad **quads,
int *nquads)
{
pixman_box32_t *rects;
int nrects, i;
bool compress, axis_aligned;
struct clipper_quad *quads_alloc;
struct clipper_vertex polygon[4];
struct weston_view *view;
if (*quads)
return;
rects = pixman_region32_rectangles(region, &nrects);
compress = nrects >= 4;
if (compress)
nrects = compress_bands(rects, nrects, &rects);
assert(nrects > 0);
*quads = quads_alloc = malloc(nrects * sizeof *quads_alloc);
*nquads = nrects;
view = pnode->view;
axis_aligned = node_axis_aligned(view);
for (i = 0; i < nrects; i++) {
global_to_surface(&rects[i], view, polygon);
clipper_quad_init(&quads_alloc[i], polygon, axis_aligned);
}
if (compress)
free(rects);
}
static void
draw_paint_node(struct weston_paint_node *pnode,
pixman_region32_t *damage /* in global coordinates */)
......@@ -1278,6 +1297,8 @@ draw_paint_node(struct weston_paint_node *pnode,
pixman_region32_t surface_blend;
GLint filter;
struct gl_shader_config sconf;
struct clipper_quad *quads = NULL;
int nquads;
if (gb->shader_variant == SHADER_VARIANT_NONE &&
!buffer->direct_display)
......@@ -1337,16 +1358,21 @@ draw_paint_node(struct weston_paint_node *pnode,
else
glDisable(GL_BLEND);
repaint_region(gr, pnode, &repaint, &surface_opaque, &alt);
transform_damage(pnode, &repaint, &quads, &nquads);
repaint_region(gr, pnode, quads, nquads, &surface_opaque, &alt);
gs->used_in_output_repaint = true;
}
if (pixman_region32_not_empty(&surface_blend)) {
glEnable(GL_BLEND);
repaint_region(gr, pnode, &repaint, &surface_blend, &sconf);
transform_damage(pnode, &repaint, &quads, &nquads);
repaint_region(gr, pnode, quads, nquads, &surface_blend, &sconf);
gs->used_in_output_repaint = true;
}
if (quads)
free(quads);
pixman_region32_fini(&surface_blend);
pixman_region32_fini(&surface_opaque);
......