gl-renderer: Store clipped vertices directly into the vertex buffer

Move vertex clipper back to single-precision floating point
intermediates. Since positions are sent down the graphics hardware as
single-precision values, this prevents useless conversions between
single and double precision values and lets compilers fit twice as
much data into vector registers. It also removes a copy by letting the
clipper store vertices directly into the vertex buffer.

This is mostly reverting the conversion to double-precision that
happened along with the switch to the weston_coord struct for vertex
coordinates (commit 10e70bf23c).

Signed-off-by: Loïc Molinari <loic.molinari@gmail.com>
This commit is contained in:
Loïc Molinari 2023-03-08 10:43:06 +01:00 committed by Pekka Paalanen
parent bcd04e0fad
commit 49053a2aa2
5 changed files with 91 additions and 89 deletions

View file

@ -54,6 +54,7 @@
#include <linux/input.h>
#include <wayland-client.h>
#include "libweston/matrix.h"
#include "libweston/vertex-clipping.h"
#include "shared/helpers.h"
#include "shared/xalloc.h"
@ -83,8 +84,8 @@ struct weston_view {
};
static void
weston_view_from_global_double(struct weston_view *view,
double x, double y, double *sx, double *sy)
weston_view_from_global_float(struct weston_view *view,
float x, float y, float *sx, float *sy)
{
struct geometry *g = view->geometry;
@ -96,10 +97,10 @@ weston_view_from_global_double(struct weston_view *view,
static struct weston_coord_surface
weston_coord_global_to_surface(struct weston_view *view, struct weston_coord_global g_pos)
{
double sx, sy;
float sx, sy;
struct weston_coord_surface pos;
weston_view_from_global_double(view, g_pos.c.x, g_pos.c.y, &sx, &sy);
weston_view_from_global_float(view, g_pos.c.x, g_pos.c.y, &sx, &sy);
pos.c = weston_coord(sx, sy);
return pos;
@ -112,19 +113,22 @@ static void
rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
struct gl_quad *quad)
{
struct weston_coord_global tmp[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;
/* Transform rect to surface space. */
quad->vertices.n = 4;
for (i = 0; i < quad->vertices.n; i++)
quad->vertices.pos[i] =
weston_coord_global_to_surface(ev, tmp[i]).c;
for (i = 0; i < quad->vertices.n; 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;
}
/* Find axis-aligned bounding box. */
quad->bbox.x1 = quad->bbox.x2 = quad->vertices.pos[0].x;
@ -142,13 +146,13 @@ rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
/*
* Compute the boundary vertices of the intersection of an arbitrary
* quadrilateral 'quad' and the axis-aligned rectangle 'surf_rect'. The vertices
* are written to 'e', and the return value is the number of vertices. Vertices
* are produced in clockwise winding order. Guarantees to produce either zero
* vertices, or 3-8 vertices with non-zero polygon area.
* are written to 'vertices', and the return value is the number of vertices.
* Vertices are produced in clockwise winding order. Guarantees to produce
* either zero vertices, or 3-8 vertices with non-zero polygon area.
*/
static int
clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
struct weston_coord *e)
struct clip_vertex *vertices)
{
struct clip_context ctx = {
.clip.x1 = surf_rect->x1,
@ -170,7 +174,7 @@ clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
* rect bounds:
*/
if (quad->axis_aligned)
return clip_simple(&ctx, &quad->vertices, e);
return clip_simple(&ctx, &quad->vertices, vertices);
/* Transformed case: use a general polygon clipping algorithm to
* clip the quad with each side of the surface rect.
@ -178,7 +182,7 @@ clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
* http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
* but without looking at any of that code.
*/
n = clip_transformed(&ctx, &quad->vertices, e);
n = clip_transformed(&ctx, &quad->vertices, vertices);
if (n < 3)
return 0;
@ -234,7 +238,7 @@ struct cliptest {
};
static void
draw_polygon_closed(cairo_t *cr, struct weston_coord *pos, int n)
draw_polygon_closed(cairo_t *cr, struct clip_vertex *pos, int n)
{
int i;
@ -245,7 +249,7 @@ draw_polygon_closed(cairo_t *cr, struct weston_coord *pos, int n)
}
static void
draw_polygon_labels(cairo_t *cr, struct weston_coord *pos, int n)
draw_polygon_labels(cairo_t *cr, struct clip_vertex *pos, int n)
{
char str[16];
int i;
@ -258,7 +262,7 @@ draw_polygon_labels(cairo_t *cr, struct weston_coord *pos, int n)
}
static void
draw_coordinates(cairo_t *cr, double ox, double oy, struct weston_coord *pos, int n)
draw_coordinates(cairo_t *cr, double ox, double oy, struct clip_vertex *pos, int n)
{
char str[64];
int i;
@ -275,18 +279,18 @@ draw_coordinates(cairo_t *cr, double ox, double oy, struct weston_coord *pos, in
static void
draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_view *view)
{
struct weston_coord pos[4];
struct clip_vertex pos[4];
if (view) {
weston_view_from_global_double(view, box->x1, box->y1, &pos[0].x, &pos[0].y);
weston_view_from_global_double(view, box->x2, box->y1, &pos[1].x, &pos[1].y);
weston_view_from_global_double(view, box->x2, box->y2, &pos[2].x, &pos[2].y);
weston_view_from_global_double(view, box->x1, box->y2, &pos[3].x, &pos[3].y);
weston_view_from_global_float(view, box->x1, box->y1, &pos[0].x, &pos[0].y);
weston_view_from_global_float(view, box->x2, box->y1, &pos[1].x, &pos[1].y);
weston_view_from_global_float(view, box->x2, box->y2, &pos[2].x, &pos[2].y);
weston_view_from_global_float(view, box->x1, box->y2, &pos[3].x, &pos[3].y);
} else {
pos[0] = weston_coord(box->x1, box->y1);
pos[1] = weston_coord(box->x2, box->y1);
pos[2] = weston_coord(box->x2, box->y2);
pos[3] = weston_coord(box->x1, box->y2);
pos[0].x = box->x1; pos[0].y = box->y1;
pos[1].x = box->x2; pos[1].y = box->y1;
pos[2].x = box->x2; pos[2].y = box->y2;
pos[3].x = box->x1; pos[3].y = box->y2;
}
draw_polygon_closed(cr, pos, 4);
@ -294,15 +298,15 @@ draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_view *view)
static void
draw_geometry(cairo_t *cr, struct weston_view *view,
struct weston_coord *e, int n)
struct clip_vertex *v, int n)
{
struct geometry *g = view->geometry;
double cx, cy;
float cx, cy;
draw_box(cr, &g->quad, view);
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
cairo_fill(cr);
weston_view_from_global_double(view, g->quad.x1 - 4, g->quad.y1 - 4, &cx, &cy);
weston_view_from_global_float(view, g->quad.x1 - 4, g->quad.y1 - 4, &cx, &cy);
cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI);
if (view->transform.enabled == 0)
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8);
@ -313,12 +317,12 @@ draw_geometry(cairo_t *cr, struct weston_view *view,
cairo_fill(cr);
if (n) {
draw_polygon_closed(cr, e, n);
draw_polygon_closed(cr, v, n);
cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
cairo_stroke(cr);
cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
draw_polygon_labels(cr, e, n);
draw_polygon_labels(cr, v, n);
}
}
@ -331,11 +335,11 @@ redraw_handler(struct widget *widget, void *data)
cairo_t *cr;
cairo_surface_t *surface;
struct gl_quad quad;
struct weston_coord e[8];
struct clip_vertex v[8];
int n;
rect_to_quad(&g->quad, &cliptest->view, &quad);
n = clip_quad(&quad, &g->surf, e);
n = clip_quad(&quad, &g->surf, v);
widget_get_allocation(cliptest->widget, &allocation);
@ -369,7 +373,7 @@ redraw_handler(struct widget *widget, void *data)
cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 5.0);
draw_geometry(cr, &cliptest->view, e, n);
draw_geometry(cr, &cliptest->view, v, n);
cairo_pop_group_to_source(cr);
cairo_paint(cr);
@ -377,7 +381,7 @@ redraw_handler(struct widget *widget, void *data)
cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cr, 12.0);
draw_coordinates(cr, 10.0, 10.0, e, n);
draw_coordinates(cr, 10.0, 10.0, v, n);
cairo_destroy(cr);
@ -596,7 +600,7 @@ benchmark(void)
struct weston_view view;
struct geometry geom;
struct gl_quad quad;
struct weston_coord e[8];
struct clip_vertex v[8];
int i;
double t;
const int N = 1000000;
@ -621,7 +625,7 @@ benchmark(void)
for (i = 0; i < N; i++) {
geometry_set_phi(&geom, (float)i / 360.0f);
rect_to_quad(&geom.quad, &view, &quad);
clip_quad(&quad, &geom.surf, e);
clip_quad(&quad, &geom.surf, v);
}
t = read_timer();

View file

@ -442,19 +442,22 @@ static void
rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
struct gl_quad *quad)
{
struct weston_coord_global tmp[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;
/* Transform rect to surface space. */
quad->vertices.n = 4;
for (i = 0; i < quad->vertices.n; i++)
quad->vertices.pos[i] =
weston_coord_global_to_surface(ev, tmp[i]).c;
for (i = 0; i < quad->vertices.n; 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;
}
/* Find axis-aligned bounding box. */
quad->bbox.x1 = quad->bbox.x2 = quad->vertices.pos[0].x;
@ -472,13 +475,13 @@ rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
/*
* Compute the boundary vertices of the intersection of an arbitrary
* quadrilateral 'quad' and the axis-aligned rectangle 'surf_rect'. The vertices
* are written to 'e', and the return value is the number of vertices. Vertices
* are produced in clockwise winding order. Guarantees to produce either zero
* vertices, or 3-8 vertices with non-zero polygon area.
* are written to 'vertices', and the return value is the number of vertices.
* Vertices are produced in clockwise winding order. Guarantees to produce
* either zero vertices, or 3-8 vertices with non-zero polygon area.
*/
static int
clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
struct weston_coord *e)
struct clip_vertex *vertices)
{
struct clip_context ctx = {
.clip.x1 = surf_rect->x1,
@ -500,7 +503,7 @@ clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
* rect bounds:
*/
if (quad->axis_aligned)
return clip_simple(&ctx, &quad->vertices, e);
return clip_simple(&ctx, &quad->vertices, vertices);
/* Transformed case: use a general polygon clipping algorithm to
* clip the quad with each side of the surface rect.
@ -508,7 +511,7 @@ clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
* http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
* but without looking at any of that code.
*/
n = clip_transformed(&ctx, &quad->vertices, e);
n = clip_transformed(&ctx, &quad->vertices, vertices);
if (n < 3)
return 0;
@ -572,11 +575,11 @@ texture_region(struct weston_paint_node *pnode,
struct weston_compositor *ec = pnode->surface->compositor;
struct weston_view *ev = pnode->view;
struct gl_renderer *gr = get_renderer(ec);
GLfloat *v;
struct clip_vertex *v;
unsigned int *vtxcnt, nvtx = 0;
pixman_box32_t *rects, *surf_rects;
pixman_box32_t *raw_rects;
int i, j, k, nrects, nsurf, raw_nrects;
int i, j, nrects, nsurf, raw_nrects;
bool used_band_compression;
struct gl_quad quad;
@ -594,13 +597,12 @@ texture_region(struct weston_paint_node *pnode,
/* worst case we can have 8 vertices per rect (ie. clipped into
* an octagon):
*/
v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 2 * sizeof *v);
v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * sizeof *v);
vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
for (i = 0; i < nrects; i++) {
rect_to_quad(&rects[i], ev, &quad);
for (j = 0; j < nsurf; j++) {
struct weston_coord e[8];
int n;
/* The transformed quad, after clipping to the surface rect, can
@ -616,17 +618,11 @@ 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 = clip_quad(&quad, &surf_rects[j], e);
if (n < 3)
continue;
/* emit edge points: */
for (k = 0; k < n; k++) {
*(v++) = e[k].x;
*(v++) = e[k].y;
n = clip_quad(&quad, &surf_rects[j], v);
if (n >= 3) {
v += n;
vtxcnt[nvtx++] = n;
}
vtxcnt[nvtx++] = n;
}
}

View file

@ -103,7 +103,8 @@ enum path_transition {
static void
clip_append_vertex(struct clip_context *ctx, float x, float y)
{
*ctx->vertices = weston_coord(x, y);
ctx->vertices->x = x;
ctx->vertices->y = y;
ctx->vertices++;
}
@ -195,7 +196,7 @@ clip_polygon_topbottom(struct clip_context *ctx,
static void
clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
struct weston_coord *dst)
struct clip_vertex *dst)
{
ctx->prev.x = src->pos[src->n - 1].x;
ctx->prev.y = src->pos[src->n - 1].y;
@ -204,7 +205,7 @@ clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
struct weston_coord *dst)
struct clip_vertex *dst)
{
enum path_transition trans;
int i;
@ -223,7 +224,7 @@ clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
struct weston_coord *dst)
struct clip_vertex *dst)
{
enum path_transition trans;
int i;
@ -242,7 +243,7 @@ clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
struct weston_coord *dst)
struct clip_vertex *dst)
{
enum path_transition trans;
int i;
@ -261,7 +262,7 @@ clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
static int
clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
struct weston_coord *dst)
struct clip_vertex *dst)
{
enum path_transition trans;
int i;
@ -281,12 +282,12 @@ clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
WESTON_EXPORT_FOR_TESTS int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
struct weston_coord *e)
struct clip_vertex *restrict vertices)
{
int i;
for (i = 0; i < surf->n; i++) {
e[i].x = CLIP(surf->pos[i].x, ctx->clip.x1, ctx->clip.x2);
e[i].y = CLIP(surf->pos[i].y, ctx->clip.y1, ctx->clip.y2);
vertices[i].x = CLIP(surf->pos[i].x, ctx->clip.x1, ctx->clip.x2);
vertices[i].y = CLIP(surf->pos[i].y, ctx->clip.y1, ctx->clip.y2);
}
return surf->n;
}
@ -294,7 +295,7 @@ clip_simple(struct clip_context *ctx,
WESTON_EXPORT_FOR_TESTS int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
struct weston_coord *e)
struct clip_vertex *restrict vertices)
{
struct polygon8 polygon;
int i, n;
@ -305,17 +306,17 @@ clip_transformed(struct clip_context *ctx,
surf->n = clip_polygon_bottom(ctx, &polygon, surf->pos);
/* Get rid of duplicate vertices */
e[0] = surf->pos[0];
vertices[0] = surf->pos[0];
n = 1;
for (i = 1; i < surf->n; i++) {
if (float_difference(e[n - 1].x, surf->pos[i].x) == 0.0f &&
float_difference(e[n - 1].y, surf->pos[i].y) == 0.0f)
if (float_difference(vertices[n - 1].x, surf->pos[i].x) == 0.0f &&
float_difference(vertices[n - 1].y, surf->pos[i].y) == 0.0f)
continue;
e[n] = surf->pos[i];
vertices[n] = surf->pos[i];
n++;
}
if (float_difference(e[n - 1].x, surf->pos[0].x) == 0.0f &&
float_difference(e[n - 1].y, surf->pos[0].y) == 0.0f)
if (float_difference(vertices[n - 1].x, surf->pos[0].x) == 0.0f &&
float_difference(vertices[n - 1].y, surf->pos[0].y) == 0.0f)
n--;
return n;

View file

@ -25,10 +25,14 @@
#ifndef _WESTON_VERTEX_CLIPPING_H
#define _WESTON_VERTEX_CLIPPING_H
#include <libweston/matrix.h>
#include <stdbool.h>
struct clip_vertex {
float x, y;
};
struct polygon8 {
struct weston_coord pos[8];
struct clip_vertex pos[8];
int n;
};
@ -39,17 +43,14 @@ struct gl_quad {
};
struct clip_context {
struct {
float x;
float y;
} prev;
struct clip_vertex prev;
struct {
float x1, y1;
float x2, y2;
} clip;
struct weston_coord *vertices;
struct clip_vertex *vertices;
};
float
@ -58,11 +59,11 @@ float_difference(float a, float b);
int
clip_simple(struct clip_context *ctx,
struct polygon8 *surf,
struct weston_coord *e);
struct clip_vertex *restrict vertices);
int
clip_transformed(struct clip_context *ctx,
struct polygon8 *surf,
struct weston_coord *e);
struct clip_vertex *restrict vertices);
#endif

View file

@ -60,7 +60,7 @@ populate_clip_context (struct clip_context *ctx)
static int
clip_polygon (struct clip_context *ctx,
struct polygon8 *polygon,
struct weston_coord *pos)
struct clip_vertex *pos)
{
populate_clip_context(ctx);
return clip_transformed(ctx, polygon, pos);
@ -241,7 +241,7 @@ TEST_P(clip_polygon_n_vertices_emitted, test_data)
struct vertex_clip_test_data *tdata = data;
struct clip_context ctx;
struct polygon8 polygon;
struct weston_coord vertices[8];
struct clip_vertex vertices[8];
deep_copy_polygon8(&tdata->surface, &polygon);
int emitted = clip_polygon(&ctx, &polygon, vertices);
@ -253,7 +253,7 @@ TEST_P(clip_polygon_expected_vertices, test_data)
struct vertex_clip_test_data *tdata = data;
struct clip_context ctx;
struct polygon8 polygon;
struct weston_coord vertices[8];
struct clip_vertex vertices[8];
deep_copy_polygon8(&tdata->surface, &polygon);
int emitted = clip_polygon(&ctx, &polygon, vertices);
int i = 0;