gl-renderer: Remove polygon8 struct from clipper API

Pass a clip_vertex struct and a size to clip_transformed() instead of
a polygon8 struct to simplify the clipper API by sticking to a common
vertex representation.

Simmplify vertex-clip test since clip_transformed() now works on a
copy of the polygon (commit edd5d1cc09).

Signed-off-by: Loïc Molinari <loic.molinari@collabora.com>
This commit is contained in:
Loïc Molinari 2023-05-25 10:50:42 +02:00 committed by Pekka Paalanen
parent aac11c8884
commit b8063dbb13
5 changed files with 182 additions and 210 deletions

View file

@ -124,11 +124,10 @@ rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
int i;
/* Transform rect to surface space. */
quad->vertices.n = 4;
for (i = 0; i < quad->vertices.n; i++) {
for (i = 0; i < 4; i++) {
rect_s = weston_coord_global_to_surface(ev, rect_g[i]).c;
quad->vertices.pos[i].x = (float)rect_s.x;
quad->vertices.pos[i].y = (float)rect_s.y;
quad->polygon[i].x = (float)rect_s.x;
quad->polygon[i].y = (float)rect_s.y;
}
quad->axis_aligned = !ev->transform.enabled ||
@ -136,17 +135,13 @@ rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
/* Find axis-aligned bounding box. */
if (!quad->axis_aligned) {
quad->bbox.x1 = quad->bbox.x2 = quad->vertices.pos[0].x;
quad->bbox.y1 = quad->bbox.y2 = quad->vertices.pos[0].y;
for (i = 1; i < quad->vertices.n; i++) {
quad->bbox.x1 = MIN(quad->bbox.x1,
quad->vertices.pos[i].x);
quad->bbox.x2 = MAX(quad->bbox.x2,
quad->vertices.pos[i].x);
quad->bbox.y1 = MIN(quad->bbox.y1,
quad->vertices.pos[i].y);
quad->bbox.y2 = MAX(quad->bbox.y2,
quad->vertices.pos[i].y);
quad->bbox.x1 = quad->bbox.x2 = quad->polygon[0].x;
quad->bbox.y1 = quad->bbox.y2 = quad->polygon[0].y;
for (i = 1; i < 4; i++) {
quad->bbox.x1 = MIN(quad->bbox.x1, quad->polygon[i].x);
quad->bbox.x2 = MAX(quad->bbox.x2, quad->polygon[i].x);
quad->bbox.y1 = MIN(quad->bbox.y1, quad->polygon[i].y);
quad->bbox.y2 = MAX(quad->bbox.y2, quad->polygon[i].y);
}
}
}

View file

@ -485,11 +485,10 @@ rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
int i;
/* Transform rect to surface space. */
quad->vertices.n = 4;
for (i = 0; i < quad->vertices.n; i++) {
for (i = 0; i < 4; i++) {
rect_s = weston_coord_global_to_surface(ev, rect_g[i]).c;
quad->vertices.pos[i].x = (float)rect_s.x;
quad->vertices.pos[i].y = (float)rect_s.y;
quad->polygon[i].x = (float)rect_s.x;
quad->polygon[i].y = (float)rect_s.y;
}
quad->axis_aligned = !ev->transform.enabled ||
@ -497,17 +496,13 @@ rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
/* Find axis-aligned bounding box. */
if (!quad->axis_aligned) {
quad->bbox.x1 = quad->bbox.x2 = quad->vertices.pos[0].x;
quad->bbox.y1 = quad->bbox.y2 = quad->vertices.pos[0].y;
for (i = 1; i < quad->vertices.n; i++) {
quad->bbox.x1 = MIN(quad->bbox.x1,
quad->vertices.pos[i].x);
quad->bbox.x2 = MAX(quad->bbox.x2,
quad->vertices.pos[i].x);
quad->bbox.y1 = MIN(quad->bbox.y1,
quad->vertices.pos[i].y);
quad->bbox.y2 = MAX(quad->bbox.y2,
quad->vertices.pos[i].y);
quad->bbox.x1 = quad->bbox.x2 = quad->polygon[0].x;
quad->bbox.y1 = quad->bbox.y2 = quad->polygon[0].y;
for (i = 1; i < 4; i++) {
quad->bbox.x1 = MIN(quad->bbox.x1, quad->polygon[i].x);
quad->bbox.x2 = MAX(quad->bbox.x2, quad->polygon[i].x);
quad->bbox.y1 = MIN(quad->bbox.y1, quad->polygon[i].y);
quad->bbox.y2 = MAX(quad->bbox.y2, quad->polygon[i].y);
}
}
}

View file

@ -25,6 +25,7 @@
#include <assert.h>
#include <float.h>
#include <math.h>
#include <string.h>
#include "shared/helpers.h"
#include "vertex-clipping.h"
@ -194,6 +195,11 @@ clip_polygon_topbottom(struct clip_context *ctx,
ctx->prev.y = y;
}
struct polygon8 {
struct clip_vertex pos[8];
int n;
};
static void
clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
struct clip_vertex *dst)
@ -281,12 +287,18 @@ clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
WESTON_EXPORT_FOR_TESTS int
clip_transformed(struct clip_context *ctx,
const struct polygon8 *surf,
const struct clip_vertex *polygon,
size_t polygon_len,
struct clip_vertex *restrict vertices)
{
struct polygon8 p = *surf, tmp;
struct polygon8 p, tmp;
int i, n;
if (polygon_len > 8)
return -1;
memcpy(p.pos, polygon, polygon_len * sizeof *polygon);
p.n = polygon_len;
tmp.n = clip_polygon_left(ctx, &p, tmp.pos);
p.n = clip_polygon_right(ctx, &tmp, p.pos);
tmp.n = clip_polygon_top(ctx, &p, tmp.pos);
@ -327,9 +339,9 @@ clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
*/
if (quad->axis_aligned) {
for (i = 0; i < 4; i++) {
vertices[i].x = CLIP(quad->vertices.pos[i].x,
vertices[i].x = CLIP(quad->polygon[i].x,
ctx.clip.x1, ctx.clip.x2);
vertices[i].y = CLIP(quad->vertices.pos[i].y,
vertices[i].y = CLIP(quad->polygon[i].y,
ctx.clip.y1, ctx.clip.y2);
}
if ((vertices[0].x != vertices[1].x) &&
@ -352,7 +364,7 @@ clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
* https://www.codeguru.com/cplusplus/polygon-clipping/
* but without looking at any of that code.
*/
n = clip_transformed(&ctx, &quad->vertices, vertices);
n = clip_transformed(&ctx, quad->polygon, 4, vertices);
if (n < 3)
return 0;

View file

@ -25,6 +25,7 @@
#ifndef _WESTON_VERTEX_CLIPPING_H
#define _WESTON_VERTEX_CLIPPING_H
#include <stddef.h>
#include <stdbool.h>
#include <pixman.h>
@ -32,13 +33,8 @@ struct clip_vertex {
float x, y;
};
struct polygon8 {
struct clip_vertex pos[8];
int n;
};
struct gl_quad {
struct polygon8 vertices;
struct clip_vertex polygon[4];
struct { float x1, y1, x2, y2; } bbox; /* Valid if !axis_aligned. */
bool axis_aligned;
};
@ -59,7 +55,8 @@ float_difference(float a, float b);
int
clip_transformed(struct clip_context *ctx,
const struct polygon8 *surf,
const struct clip_vertex *polygon,
size_t polygon_len,
struct clip_vertex *restrict vertices);
/*

View file

@ -25,12 +25,7 @@
#include "config.h"
#include <assert.h>
#include <string.h>
#include "weston-test-runner.h"
#include "shared/helpers.h"
#include "vertex-clipping.h"
#define BOUNDING_BOX_TOP_Y 100.0f
@ -59,212 +54,190 @@ populate_clip_context (struct clip_context *ctx)
static int
clip_polygon (struct clip_context *ctx,
struct polygon8 *polygon,
struct clip_vertex *pos)
struct clip_vertex *polygon,
int n,
struct clip_vertex *vertices)
{
populate_clip_context(ctx);
return clip_transformed(ctx, polygon, pos);
return clip_transformed(ctx, polygon, n, vertices);
}
struct vertex_clip_test_data
{
struct polygon8 surface;
struct polygon8 expected;
struct vertex_clip_test_data {
struct clip_vertex polygon[8];
struct clip_vertex clipped[8];
int polygon_n;
int clipped_n;
};
const struct vertex_clip_test_data test_data[] =
{
const struct vertex_clip_test_data test_data[] = {
/* All inside */
{
{
.pos = {
{ .x = INSIDE_X1, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y2 },
{ .x = INSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
.polygon = {
{ INSIDE_X1, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y2 },
{ INSIDE_X1, INSIDE_Y2 },
},
{
.pos = {
{ .x = INSIDE_X1, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y2 },
{ .x = INSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
}
.clipped = {
{ INSIDE_X1, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y2 },
{ INSIDE_X1, INSIDE_Y2 },
},
.polygon_n = 4,
.clipped_n = 4,
},
/* Top outside */
{
{
.pos = {
{ .x = INSIDE_X1, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = OUTSIDE_Y2 },
{ .x = INSIDE_X1, .y = OUTSIDE_Y2 },
},
.n = 4
.polygon = {
{ INSIDE_X1, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y1 },
{ INSIDE_X2, OUTSIDE_Y2 },
{ INSIDE_X1, OUTSIDE_Y2 },
},
{
.pos = {
{ .x = INSIDE_X1, .y = BOUNDING_BOX_TOP_Y },
{ .x = INSIDE_X1, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = BOUNDING_BOX_TOP_Y },
},
.n = 4
}
.clipped = {
{ INSIDE_X1, BOUNDING_BOX_TOP_Y },
{ INSIDE_X1, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y1 },
{ INSIDE_X2, BOUNDING_BOX_TOP_Y },
},
.polygon_n = 4,
.clipped_n = 4,
},
/* Bottom outside */
{
{
.pos = {
{ .x = INSIDE_X1, .y = OUTSIDE_Y1 },
{ .x = INSIDE_X2, .y = OUTSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y2 },
{ .x = INSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
.polygon = {
{ INSIDE_X1, OUTSIDE_Y1 },
{ INSIDE_X2, OUTSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y2 },
{ INSIDE_X1, INSIDE_Y2 },
},
{
.pos = {
{ .x = INSIDE_X1, .y = BOUNDING_BOX_BOTTOM_Y },
{ .x = INSIDE_X2, .y = BOUNDING_BOX_BOTTOM_Y },
{ .x = INSIDE_X2, .y = INSIDE_Y2 },
{ .x = INSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
}
.clipped = {
{ INSIDE_X1, BOUNDING_BOX_BOTTOM_Y },
{ INSIDE_X2, BOUNDING_BOX_BOTTOM_Y },
{ INSIDE_X2, INSIDE_Y2 },
{ INSIDE_X1, INSIDE_Y2 },
},
.polygon_n = 4,
.clipped_n = 4,
},
/* Left outside */
{
{
.pos = {
{ .x = OUTSIDE_X1, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y2 },
{ .x = OUTSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
.polygon = {
{ OUTSIDE_X1, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y2 },
{ OUTSIDE_X1, INSIDE_Y2 },
},
{
.pos = {
{ .x = BOUNDING_BOX_LEFT_X, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y1 },
{ .x = INSIDE_X2, .y = INSIDE_Y2 },
{ .x = BOUNDING_BOX_LEFT_X, .y = INSIDE_Y2 },
},
.n = 4
}
.clipped = {
{ BOUNDING_BOX_LEFT_X, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y1 },
{ INSIDE_X2, INSIDE_Y2 },
{ BOUNDING_BOX_LEFT_X, INSIDE_Y2 },
},
.polygon_n = 4,
.clipped_n = 4,
},
/* Right outside */
{
{
.pos = {
{ .x = INSIDE_X1, .y = INSIDE_Y1 },
{ .x = OUTSIDE_X2, .y = INSIDE_Y1 },
{ .x = OUTSIDE_X2, .y = INSIDE_Y2 },
{ .x = INSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
.polygon = {
{ INSIDE_X1, INSIDE_Y1 },
{ OUTSIDE_X2, INSIDE_Y1 },
{ OUTSIDE_X2, INSIDE_Y2 },
{ INSIDE_X1, INSIDE_Y2 },
},
{
.pos = {
{ .x = INSIDE_X1, .y = INSIDE_Y1 },
{ .x = BOUNDING_BOX_RIGHT_X, .y = INSIDE_Y1 },
{ .x = BOUNDING_BOX_RIGHT_X, .y = INSIDE_Y2 },
{ .x = INSIDE_X1, .y = INSIDE_Y2 },
},
.n = 4
}
.clipped = {
{ INSIDE_X1, INSIDE_Y1 },
{ BOUNDING_BOX_RIGHT_X, INSIDE_Y1 },
{ BOUNDING_BOX_RIGHT_X, INSIDE_Y2 },
{ INSIDE_X1, INSIDE_Y2 },
},
.polygon_n = 4,
.clipped_n = 4,
},
/* Diamond extending from bounding box edges, clip to bounding box */
{
{
.pos = {
{ .x = BOUNDING_BOX_LEFT_X - 25, .y = BOUNDING_BOX_BOTTOM_Y + 25 },
{ .x = BOUNDING_BOX_LEFT_X + 25, .y = BOUNDING_BOX_TOP_Y + 25 },
{ .x = BOUNDING_BOX_RIGHT_X + 25, .y = BOUNDING_BOX_TOP_Y - 25 },
{ .x = BOUNDING_BOX_RIGHT_X - 25, .y = BOUNDING_BOX_BOTTOM_Y - 25 },
},
.n = 4
},
{
.pos = {
{ .x = BOUNDING_BOX_LEFT_X, .y = BOUNDING_BOX_BOTTOM_Y },
{ .x = BOUNDING_BOX_LEFT_X, .y = BOUNDING_BOX_TOP_Y },
{ .x = BOUNDING_BOX_RIGHT_X, .y = BOUNDING_BOX_TOP_Y },
{ .x = BOUNDING_BOX_RIGHT_X, .y = BOUNDING_BOX_BOTTOM_Y },
},
.n = 4
}
},
/* Diamond inside of bounding box edges, clip t bounding box, 8 resulting vertices */
{
{
.pos = {
{ .x = BOUNDING_BOX_LEFT_X - 12.5, .y = BOUNDING_BOX_BOTTOM_Y + 25 },
{ .x = BOUNDING_BOX_LEFT_X + 25, .y = BOUNDING_BOX_TOP_Y + 12.5 },
{ .x = BOUNDING_BOX_RIGHT_X + 12.5, .y = BOUNDING_BOX_TOP_Y - 25 },
{ .x = BOUNDING_BOX_RIGHT_X - 25, .y = BOUNDING_BOX_BOTTOM_Y - 12.5 },
},
.n = 4
},
{
.pos = {
{ .x = BOUNDING_BOX_LEFT_X + 12.5, .y = BOUNDING_BOX_BOTTOM_Y },
{ .x = BOUNDING_BOX_LEFT_X, .y = BOUNDING_BOX_BOTTOM_Y + 12.5 },
{ .x = BOUNDING_BOX_LEFT_X, .y = BOUNDING_BOX_TOP_Y - 12.5 },
{ .x = BOUNDING_BOX_LEFT_X + 12.5, .y = BOUNDING_BOX_TOP_Y },
{ .x = BOUNDING_BOX_RIGHT_X - 12.5, .y = BOUNDING_BOX_TOP_Y },
{ .x = BOUNDING_BOX_RIGHT_X, .y = BOUNDING_BOX_TOP_Y - 12.5 },
{ .x = BOUNDING_BOX_RIGHT_X, .y = BOUNDING_BOX_BOTTOM_Y + 12.5},
{ .x = BOUNDING_BOX_RIGHT_X - 12.5, .y = BOUNDING_BOX_BOTTOM_Y },
},
.n = 8
}
}
};
/* clip_polygon modifies the source operand and the test data must
* be const, so we need to deep copy it */
static void
deep_copy_polygon8(const struct polygon8 *src, struct polygon8 *dst)
{
dst->n = src->n;
ARRAY_COPY(dst->pos, src->pos);
}
/* Diamond extending from bounding box edges */
{
.polygon = {
{ BOUNDING_BOX_LEFT_X - 25, BOUNDING_BOX_BOTTOM_Y + 25 },
{ BOUNDING_BOX_LEFT_X + 25, BOUNDING_BOX_TOP_Y + 25 },
{ BOUNDING_BOX_RIGHT_X + 25, BOUNDING_BOX_TOP_Y - 25 },
{ BOUNDING_BOX_RIGHT_X - 25, BOUNDING_BOX_BOTTOM_Y - 25 },
},
.clipped = {
{ BOUNDING_BOX_LEFT_X, BOUNDING_BOX_BOTTOM_Y },
{ BOUNDING_BOX_LEFT_X, BOUNDING_BOX_TOP_Y },
{ BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_TOP_Y },
{ BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_BOTTOM_Y },
},
.polygon_n = 4,
.clipped_n = 4,
},
/* Diamond inside of bounding box edges */
{
.polygon = {
{ BOUNDING_BOX_LEFT_X - 12.5, BOUNDING_BOX_BOTTOM_Y + 25 },
{ BOUNDING_BOX_LEFT_X + 25, BOUNDING_BOX_TOP_Y + 12.5 },
{ BOUNDING_BOX_RIGHT_X + 12.5, BOUNDING_BOX_TOP_Y - 25 },
{ BOUNDING_BOX_RIGHT_X - 25, BOUNDING_BOX_BOTTOM_Y - 12.5 },
},
.clipped = {
{ BOUNDING_BOX_LEFT_X + 12.5, BOUNDING_BOX_BOTTOM_Y },
{ BOUNDING_BOX_LEFT_X, BOUNDING_BOX_BOTTOM_Y + 12.5 },
{ BOUNDING_BOX_LEFT_X, BOUNDING_BOX_TOP_Y - 12.5 },
{ BOUNDING_BOX_LEFT_X + 12.5, BOUNDING_BOX_TOP_Y },
{ BOUNDING_BOX_RIGHT_X - 12.5, BOUNDING_BOX_TOP_Y },
{ BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_TOP_Y - 12.5 },
{ BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_BOTTOM_Y + 12.5 },
{ BOUNDING_BOX_RIGHT_X - 12.5, BOUNDING_BOX_BOTTOM_Y },
},
.polygon_n = 4,
.clipped_n = 8,
},
};
TEST_P(clip_polygon_n_vertices_emitted, test_data)
{
struct vertex_clip_test_data *tdata = data;
struct clip_context ctx;
struct polygon8 polygon;
struct clip_vertex vertices[8];
deep_copy_polygon8(&tdata->surface, &polygon);
int emitted = clip_polygon(&ctx, &polygon, vertices);
struct clip_vertex clipped[8];
int clipped_n;
assert(emitted == tdata->expected.n);
clipped_n = clip_polygon(&ctx, tdata->polygon, tdata->polygon_n,
clipped);
assert(clipped_n == tdata->clipped_n);
}
TEST_P(clip_polygon_expected_vertices, test_data)
{
struct vertex_clip_test_data *tdata = data;
struct clip_context ctx;
struct polygon8 polygon;
struct clip_vertex vertices[8];
deep_copy_polygon8(&tdata->surface, &polygon);
int emitted = clip_polygon(&ctx, &polygon, vertices);
int i = 0;
struct clip_vertex clipped[8];
int clipped_n, i;
for (; i < emitted; ++i)
{
assert(vertices[i].x == tdata->expected.pos[i].x);
assert(vertices[i].y == tdata->expected.pos[i].y);
clipped_n = clip_polygon(&ctx, tdata->polygon, tdata->polygon_n,
clipped);
for (i = 0; i < clipped_n; i++) {
assert(clipped[i].x == tdata->clipped[i].x);
assert(clipped[i].y == tdata->clipped[i].y);
}
}
TEST(clip_transformed_size_too_high)
{
struct clip_context ctx;
struct clip_vertex polygon[8] = {};
assert(clip_transformed(&ctx, polygon, 9, NULL) == -1);
}
TEST(float_difference_different)
{
assert(float_difference(1.0f, 0.0f) == 1.0f);