Skip to content
Commits on Source (8)
......@@ -22,12 +22,16 @@
* DEALINGS IN THE SOFTWARE.
*/
/* cliptest: for debugging calculate_edges() function.
/* cliptest:
* For debugging the rect_to_quad() and clip_quad() functions. An arbitrary
* quad (red) is transformed from global coordinate space to surface
* coordinate space and clipped to an axis-aligned rect (blue).
*
* controls:
* clip box position: mouse left drag, keys: w a s d
* clip box size: mouse right drag, keys: i j k l
* surface orientation: mouse wheel, keys: n m
* surface transform disable key: r
* surface rect position: mouse left drag, keys: w a s d
* surface rect size: mouse right drag, keys: i j k l
* quad orientation: mouse wheel, keys: n m
* quad transform disable: key: r
*/
#include "config.h"
......@@ -50,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"
......@@ -58,9 +63,9 @@
typedef float GLfloat;
struct geometry {
pixman_box32_t clip;
pixman_box32_t surf;
pixman_box32_t quad;
float s; /* sin phi */
float c; /* cos phi */
float phi;
......@@ -73,111 +78,77 @@ struct weston_view {
struct weston_surface *surface;
struct {
int enabled;
struct weston_matrix matrix;
} transform;
struct geometry *geometry;
};
static void
weston_view_to_global_double(struct weston_view *view,
double sx, double sy, double *x, double *y)
weston_view_from_global_float(struct weston_view *view,
float x, float y, float *sx, float *sy)
{
struct geometry *g = view->geometry;
/* pure rotation around origin by sine and cosine */
*x = g->c * sx + g->s * sy;
*y = -g->s * sx + g->c * sy;
*sx = g->c * x + g->s * y;
*sy = -g->s * x + g->c * y;
}
static struct weston_coord_global
weston_coord_surface_to_global(struct weston_view *view, struct weston_coord_surface pos)
static struct weston_coord_surface
weston_coord_global_to_surface(struct weston_view *view, struct weston_coord_global g_pos)
{
double gx, gy;
struct weston_coord_global g_pos;
float sx, sy;
struct weston_coord_surface pos;
weston_view_to_global_double(view, pos.c.x, pos.c.y, &gx, &gy);
g_pos.c = weston_coord(gx, gy);
weston_view_from_global_float(view, g_pos.c.x, g_pos.c.y, &sx, &sy);
pos.c = weston_coord(sx, sy);
return g_pos;
return pos;
}
/* ---------------------- copied begins -----------------------*/
/* Keep this in sync with what is in gl-renderer.c! */
/*
* Compute the boundary vertices of the intersection of the global coordinate
* aligned rectangle 'rect', and an arbitrary quadrilateral produced from
* 'surf_rect' when transformed from surface coordinates into global coordinates.
* The vertices are written to 'ex' and 'ey', 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
calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
pixman_box32_t *surf_rect, struct weston_coord *e)
static void
rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
struct gl_quad *quad)
{
struct clip_context ctx;
int i, n;
GLfloat min_x, max_x, min_y, max_y;
struct weston_surface *es = ev->surface;
struct weston_coord_surface tmp[4] = {
weston_coord_surface(surf_rect->x1, surf_rect->y1, es),
weston_coord_surface(surf_rect->x2, surf_rect->y1, es),
weston_coord_surface(surf_rect->x2, surf_rect->y2, es),
weston_coord_surface(surf_rect->x1, surf_rect->y2, es),
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 polygon8 surf;
surf.n = 4;
ctx.clip.x1 = rect->x1;
ctx.clip.y1 = rect->y1;
ctx.clip.x2 = rect->x2;
ctx.clip.y2 = rect->y2;
/* transform surface to screen space: */
for (i = 0; i < surf.n; i++)
surf.pos[i] = weston_coord_surface_to_global(ev, tmp[i]).c;
/* find bounding box: */
min_x = max_x = surf.pos[0].x;
min_y = max_y = surf.pos[0].y;
struct weston_coord rect_s;
int i;
for (i = 1; i < surf.n; i++) {
min_x = MIN(min_x, surf.pos[i].x);
max_x = MAX(max_x, surf.pos[i].x);
min_y = MIN(min_y, surf.pos[i].y);
max_y = MAX(max_y, surf.pos[i].y);
/* Transform rect to surface space. */
quad->vertices.n = 4;
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;
}
/* First, simple bounding box check to discard early transformed
* surface rects that do not intersect with the clip region:
*/
if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
(min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
return 0;
/* Simple case, bounding box edges are parallel to surface edges,
* there will be only four edges. We just need to clip the surface
* vertices to the clip rect bounds:
*/
if (!ev->transform.enabled)
return clip_simple(&ctx, &surf, e);
/* Transformed case: use a general polygon clipping algorithm to
* clip the surface rectangle with each side of 'rect'.
* The algorithm is Sutherland-Hodgman, as explained in
* 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, &surf, e);
if (n < 3)
return 0;
return n;
quad->axis_aligned = !ev->transform.enabled ||
(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
/* 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);
}
}
}
/* ---------------------- copied ends -----------------------*/
......@@ -193,15 +164,15 @@ geometry_set_phi(struct geometry *g, float phi)
static void
geometry_init(struct geometry *g)
{
g->clip.x1 = -50;
g->clip.y1 = -50;
g->clip.x2 = -10;
g->clip.y2 = -10;
g->surf.x1 = -50;
g->surf.y1 = -50;
g->surf.x2 = -10;
g->surf.y2 = -10;
g->surf.x1 = -20;
g->surf.y1 = -20;
g->surf.x2 = 20;
g->surf.y2 = 20;
g->quad.x1 = -20;
g->quad.y1 = -20;
g->quad.x2 = 20;
g->quad.y2 = 20;
geometry_set_phi(g, 0.0);
}
......@@ -228,7 +199,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;
......@@ -239,7 +210,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;
......@@ -252,7 +223,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;
......@@ -269,18 +240,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_to_global_double(view, box->x1, box->y1, &pos[0].x, &pos[0].y);
weston_view_to_global_double(view, box->x2, box->y1, &pos[1].x, &pos[1].y);
weston_view_to_global_double(view, box->x2, box->y2, &pos[2].x, &pos[2].y);
weston_view_to_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);
......@@ -288,31 +259,31 @@ 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->surf, view);
draw_box(cr, &g->quad, view);
cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
cairo_fill(cr);
weston_view_to_global_double(view, g->surf.x1 - 4, g->surf.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);
cairo_fill(cr);
draw_box(cr, &g->clip, NULL);
draw_box(cr, &g->surf, NULL);
cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
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);
}
}
......@@ -324,10 +295,12 @@ redraw_handler(struct widget *widget, void *data)
struct rectangle allocation;
cairo_t *cr;
cairo_surface_t *surface;
struct weston_coord e[8];
struct gl_quad quad;
struct clip_vertex v[8];
int n;
n = calculate_edges(&cliptest->view, &g->clip, &g->surf, e);
rect_to_quad(&g->quad, &cliptest->view, &quad);
n = clip_quad(&quad, &g->surf, v);
widget_get_allocation(cliptest->widget, &allocation);
......@@ -361,7 +334,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);
......@@ -369,7 +342,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);
......@@ -394,12 +367,12 @@ motion_handler(struct widget *widget, struct input *input,
switch (ui->button) {
case BTN_LEFT:
geom->clip.x1 = ref->clip.x1 + dx;
geom->clip.y1 = ref->clip.y1 + dy;
geom->surf.x1 = ref->surf.x1 + dx;
geom->surf.y1 = ref->surf.y1 + dy;
/* fall through */
case BTN_RIGHT:
geom->clip.x2 = ref->clip.x2 + dx;
geom->clip.y2 = ref->clip.y2 + dy;
geom->surf.x2 = ref->surf.x2 + dx;
geom->surf.y2 = ref->surf.y2 + dy;
break;
default:
return CURSOR_LEFT_PTR;
......@@ -441,6 +414,7 @@ axis_handler(struct widget *widget, struct input *input, uint32_t time,
geometry_set_phi(geom, geom->phi +
(M_PI / 12.0) * wl_fixed_to_double(value));
cliptest->view.transform.enabled = 1;
cliptest->view.transform.matrix.type = WESTON_MATRIX_TRANSFORM_ROTATE;
widget_schedule_redraw(cliptest->widget);
}
......@@ -461,44 +435,49 @@ key_handler(struct window *window, struct input *input, uint32_t time,
display_exit(cliptest->display);
return;
case XKB_KEY_w:
g->clip.y1 -= 1;
g->clip.y2 -= 1;
g->surf.y1 -= 1;
g->surf.y2 -= 1;
break;
case XKB_KEY_a:
g->clip.x1 -= 1;
g->clip.x2 -= 1;
g->surf.x1 -= 1;
g->surf.x2 -= 1;
break;
case XKB_KEY_s:
g->clip.y1 += 1;
g->clip.y2 += 1;
g->surf.y1 += 1;
g->surf.y2 += 1;
break;
case XKB_KEY_d:
g->clip.x1 += 1;
g->clip.x2 += 1;
g->surf.x1 += 1;
g->surf.x2 += 1;
break;
case XKB_KEY_i:
g->clip.y2 -= 1;
g->surf.y2 -= 1;
break;
case XKB_KEY_j:
g->clip.x2 -= 1;
g->surf.x2 -= 1;
break;
case XKB_KEY_k:
g->clip.y2 += 1;
g->surf.y2 += 1;
break;
case XKB_KEY_l:
g->clip.x2 += 1;
g->surf.x2 += 1;
break;
case XKB_KEY_n:
geometry_set_phi(g, g->phi + (M_PI / 24.0));
cliptest->view.transform.enabled = 1;
cliptest->view.transform.matrix.type =
WESTON_MATRIX_TRANSFORM_ROTATE;
break;
case XKB_KEY_m:
geometry_set_phi(g, g->phi - (M_PI / 24.0));
cliptest->view.transform.enabled = 1;
cliptest->view.transform.matrix.type =
WESTON_MATRIX_TRANSFORM_ROTATE;
break;
case XKB_KEY_r:
geometry_set_phi(g, 0.0);
cliptest->view.transform.enabled = 0;
cliptest->view.transform.matrix.type = 0;
break;
default:
return;
......@@ -534,6 +513,7 @@ cliptest_create(struct display *display)
cliptest->view.surface = &cliptest->surface;
cliptest->view.geometry = &cliptest->geometry;
cliptest->view.transform.enabled = 0;
cliptest->view.transform.matrix.type = 0;
geometry_init(&cliptest->geometry);
geometry_init(&cliptest->ui.geometry);
......@@ -587,31 +567,34 @@ benchmark(void)
struct weston_surface surface;
struct weston_view view;
struct geometry geom;
struct weston_coord e[8];
struct gl_quad quad;
struct clip_vertex v[8];
int i;
double t;
const int N = 1000000;
geom.clip.x1 = -19;
geom.clip.y1 = -19;
geom.clip.x2 = 19;
geom.clip.y2 = 19;
geom.surf.x1 = -19;
geom.surf.y1 = -19;
geom.surf.x2 = 19;
geom.surf.y2 = 19;
geom.surf.x1 = -20;
geom.surf.y1 = -20;
geom.surf.x2 = 20;
geom.surf.y2 = 20;
geom.quad.x1 = -20;
geom.quad.y1 = -20;
geom.quad.x2 = 20;
geom.quad.y2 = 20;
geometry_set_phi(&geom, 0.0);
view.surface = &surface;
view.transform.enabled = 1;
view.transform.matrix.type = WESTON_MATRIX_TRANSFORM_ROTATE;
view.geometry = &geom;
reset_timer();
for (i = 0; i < N; i++) {
geometry_set_phi(&geom, (float)i / 360.0f);
calculate_edges(&view, &geom.clip, &geom.surf, e);
rect_to_quad(&geom.quad, &view, &quad);
clip_quad(&quad, &geom.surf, v);
}
t = read_timer();
......
......@@ -38,6 +38,12 @@
#include "shared/weston-egl-ext.h" /* for PFN* stuff */
#include "shared/helpers.h"
/* Keep the following in sync with vertex.glsl. */
enum gl_shader_texcoord_input {
SHADER_TEXCOORD_INPUT_ATTRIB = 0,
SHADER_TEXCOORD_INPUT_SURFACE,
};
enum gl_shader_texture_variant {
SHADER_VARIANT_NONE = 0,
/* Keep the following in sync with fragment.glsl. */
......@@ -75,6 +81,8 @@ enum gl_shader_color_mapping {
*/
struct gl_shader_requirements
{
unsigned texcoord_input:1; /* enum gl_shader_texcoord_input */
unsigned variant:4; /* enum gl_shader_texture_variant */
bool input_is_premult:1;
bool green_tint:1;
......@@ -86,7 +94,7 @@ struct gl_shader_requirements
* The total size of all bitfields plus pad_bits_ must fill up exactly
* how many bytes the compiler allocates for them together.
*/
unsigned pad_bits_:22;
unsigned pad_bits_:21;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
......@@ -100,6 +108,7 @@ struct gl_shader_config {
struct gl_shader_requirements req;
struct weston_matrix projection;
struct weston_matrix surface_to_buffer;
float view_alpha;
GLfloat unicolor[4];
GLint input_tex_filter; /* GL_NEAREST or GL_LINEAR */
......
......@@ -438,80 +438,45 @@ timeline_submit_render_sync(struct gl_renderer *gr,
wl_list_insert(&go->timeline_render_point_list, &trp->link);
}
/*
* Compute the boundary vertices of the intersection of the global coordinate
* aligned rectangle 'rect', and an arbitrary quadrilateral produced from
* 'surf_rect' when transformed from surface coordinates into global coordinates.
* The vertices are written to 'ex' and 'ey', 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
calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
pixman_box32_t *surf_rect, struct weston_coord *e)
static void
rect_to_quad(pixman_box32_t *rect, struct weston_view *ev,
struct gl_quad *quad)
{
struct clip_context ctx;
int i, n;
GLfloat min_x, max_x, min_y, max_y;
struct weston_surface *es = ev->surface;
struct weston_coord_surface tmp[4] = {
weston_coord_surface(surf_rect->x1, surf_rect->y1, es),
weston_coord_surface(surf_rect->x2, surf_rect->y1, es),
weston_coord_surface(surf_rect->x2, surf_rect->y2, es),
weston_coord_surface(surf_rect->x1, surf_rect->y2, es),
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 polygon8 surf;
surf.n = 4;
ctx.clip.x1 = rect->x1;
ctx.clip.y1 = rect->y1;
ctx.clip.x2 = rect->x2;
ctx.clip.y2 = rect->y2;
/* transform surface to screen space: */
for (i = 0; i < surf.n; i++)
surf.pos[i] = weston_coord_surface_to_global(ev, tmp[i]).c;
/* find bounding box: */
min_x = max_x = surf.pos[0].x;
min_y = max_y = surf.pos[0].y;
struct weston_coord rect_s;
int i;
for (i = 1; i < surf.n; i++) {
min_x = MIN(min_x, surf.pos[i].x);
max_x = MAX(max_x, surf.pos[i].x);
min_y = MIN(min_y, surf.pos[i].y);
max_y = MAX(max_y, surf.pos[i].y);
/* Transform rect to surface space. */
quad->vertices.n = 4;
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;
}
quad->axis_aligned = !ev->transform.enabled ||
(ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
/* 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);
}
}
/* First, simple bounding box check to discard early transformed
* surface rects that do not intersect with the clip region:
*/
if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
(min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
return 0;
/* Simple case, bounding box edges are parallel to surface edges,
* there will be only four edges. We just need to clip the surface
* vertices to the clip rect bounds:
*/
if (!ev->transform.enabled)
return clip_simple(&ctx, &surf, e);
/* Transformed case: use a general polygon clipping algorithm to
* clip the surface rectangle with each side of 'rect'.
* The algorithm is Sutherland-Hodgman, as explained in
* 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, &surf, e);
if (n < 3)
return 0;
return n;
}
static bool
......@@ -567,17 +532,17 @@ texture_region(struct weston_paint_node *pnode,
pixman_region32_t *region,
pixman_region32_t *surf_region)
{
struct gl_surface_state *gs = get_surface_state(pnode->surface);
struct weston_buffer *buffer = gs->buffer_ref.buffer;
struct weston_compositor *ec = pnode->surface->compositor;
struct weston_view *ev = pnode->view;
struct gl_renderer *gr = get_renderer(ec);
GLfloat *v, inv_width, inv_height;
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;
raw_rects = pixman_region32_rectangles(region, &raw_nrects);
surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
......@@ -592,62 +557,32 @@ 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 * 4 * sizeof *v);
v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * sizeof *v);
vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
inv_width = 1.0 / buffer->width;
inv_height = 1.0 / buffer->height;
for (i = 0; i < nrects; i++) {
pixman_box32_t *rect = &rects[i];
rect_to_quad(&rects[i], ev, &quad);
for (j = 0; j < nsurf; j++) {
pixman_box32_t *surf_rect = &surf_rects[j];
struct weston_coord e[8]; /* edge points in screen space */
int n;
/* The transformed surface, after clipping to the clip region,
* can have as many as eight sides, emitted as a triangle-fan.
* The first vertex in the triangle fan can be chosen arbitrarily,
/* The transformed quad, after clipping to the surface rect, can
* have as many as eight sides, emitted as a triangle-fan. The
* first vertex in the triangle fan can be chosen arbitrarily,
* since the area is guaranteed to be convex.
*
* If a corner of the transformed surface falls outside of the
* clip region, instead of emitting one vertex for the corner
* of the surface, up to two are emitted for two corresponding
* intersection point(s) between the surface and the clip region.
* If a corner of the transformed quad falls outside of the
* surface rect, instead of emitting one vertex, up to two are
* emitted for two corresponding intersection point(s) between the
* edges.
*
* To do this, we first calculate the (up to eight) points that
* form the intersection of the clip rect and the transformed
* surface.
* 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 = calculate_edges(ev, rect, surf_rect, e);
if (n < 3)
continue;
/* emit edge points: */
for (k = 0; k < n; k++) {
struct weston_coord_global pos_g;
struct weston_coord_surface pos_s;
struct weston_coord_buffer pos_b;
pos_g.c = e[k];
/* position: */
*(v++) = pos_g.c.x;
*(v++) = pos_g.c.y;
/* texcoord: */
pos_s = weston_coord_global_to_surface(ev, pos_g);
pos_b = weston_coord_surface_to_buffer(ev->surface, pos_s);
*(v++) = pos_b.c.x * inv_width;
if (buffer->buffer_origin == ORIGIN_TOP_LEFT) {
*(v++) = pos_b.c.y * inv_height;
} else {
*(v++) = (buffer->height - pos_b.c.y) * inv_height;
}
n = clip_quad(&quad, &surf_rects[j], v);
if (n >= 3) {
v += n;
vtxcnt[nvtx++] = n;
}
vtxcnt[nvtx++] = n;
}
}
......@@ -1066,9 +1001,7 @@ repaint_region(struct gl_renderer *gr,
vtxcnt = gr->vtxcnt.data;
/* position: */
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
/* texcoord: */
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof *v, v);
if (!gl_renderer_use_program(gr, sconf)) {
gl_renderer_send_shader_error(pnode);
......@@ -1265,16 +1198,33 @@ gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf,
{
struct gl_surface_state *gs = get_surface_state(pnode->surface);
struct gl_output_state *go = get_output_state(pnode->output);
struct weston_buffer *buffer = gs->buffer_ref.buffer;
if (!pnode->surf_xform_valid)
return false;
*sconf = (struct gl_shader_config) {
.projection = go->output_matrix,
.req.texcoord_input = SHADER_TEXCOORD_INPUT_SURFACE,
.projection = pnode->view->transform.matrix,
.surface_to_buffer =
pnode->view->surface->surface_to_buffer_matrix,
.view_alpha = pnode->view->alpha,
.input_tex_filter = filter,
};
weston_matrix_multiply(&sconf->projection, &go->output_matrix);
if (buffer->buffer_origin == ORIGIN_TOP_LEFT) {
weston_matrix_scale(&sconf->surface_to_buffer,
1.0f / buffer->width,
1.0f / buffer->height, 1);
} else {
weston_matrix_scale(&sconf->surface_to_buffer,
1.0f / buffer->width,
-1.0f / buffer->height, 1);
weston_matrix_translate(&sconf->surface_to_buffer, 0, 1, 0);
}
gl_shader_config_set_input_textures(sconf, gs);
if (!gl_shader_config_set_color_transform(sconf, pnode->surf_xform.transform)) {
......@@ -1386,9 +1336,7 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
struct weston_paint_node *pnode;
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
wl_list_for_each_reverse(pnode, &output->paint_node_z_order_list,
z_order_link) {
......@@ -1396,7 +1344,6 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
draw_paint_node(pnode, damage);
}
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
}
......
......@@ -56,6 +56,7 @@ struct gl_shader {
GLuint program;
GLuint vertex_shader, fragment_shader;
GLint proj_uniform;
GLint surface_to_buffer_uniform;
GLint tex_uniforms[3];
GLint view_alpha_uniform;
GLint color_uniform;
......@@ -74,6 +75,19 @@ struct gl_shader {
struct timespec last_used;
};
static const char *
gl_shader_texcoord_input_to_string(enum gl_shader_texcoord_input kind)
{
switch (kind) {
#define CASERET(x) case x: return #x;
CASERET(SHADER_TEXCOORD_INPUT_SURFACE)
CASERET(SHADER_TEXCOORD_INPUT_ATTRIB)
#undef CASERET
}
return "!?!?"; /* never reached */
}
static const char *
gl_shader_texture_variant_to_string(enum gl_shader_texture_variant v)
{
......@@ -186,7 +200,8 @@ create_shader_description_string(const struct gl_shader_requirements *req)
int size;
char *str;
size = asprintf(&str, "%s %s %s %s %cinput_is_premult %cgreen",
size = asprintf(&str, "%s %s %s %s %s %cinput_is_premult %cgreen",
gl_shader_texcoord_input_to_string(req->variant),
gl_shader_texture_variant_to_string(req->variant),
gl_shader_color_curve_to_string(req->color_pre_curve),
gl_shader_color_mapping_to_string(req->color_mapping),
......@@ -199,7 +214,21 @@ create_shader_description_string(const struct gl_shader_requirements *req)
}
static char *
create_shader_config_string(const struct gl_shader_requirements *req)
create_vertex_shader_config_string(const struct gl_shader_requirements *req)
{
int size;
char *str;
size = asprintf(&str,
"#define DEF_TEXCOORD_INPUT %s\n",
gl_shader_texcoord_input_to_string(req->texcoord_input));
if (size < 0)
return NULL;
return str;
}
static char *
create_fragment_shader_config_string(const struct gl_shader_requirements *req)
{
int size;
char *str;
......@@ -252,12 +281,18 @@ gl_shader_create(struct gl_renderer *gr,
free(desc);
}
sources[0] = vertex_shader;
shader->vertex_shader = compile_shader(GL_VERTEX_SHADER, 1, sources);
conf = create_vertex_shader_config_string(&shader->key);
if (!conf)
goto error_vertex;
sources[0] = conf;
sources[1] = vertex_shader;
shader->vertex_shader = compile_shader(GL_VERTEX_SHADER, 2, sources);
if (shader->vertex_shader == GL_NONE)
goto error_vertex;
conf = create_shader_config_string(&shader->key);
free(conf);
conf = create_fragment_shader_config_string(&shader->key);
if (!conf)
goto error_fragment;
......@@ -273,7 +308,8 @@ gl_shader_create(struct gl_renderer *gr,
glAttachShader(shader->program, shader->vertex_shader);
glAttachShader(shader->program, shader->fragment_shader);
glBindAttribLocation(shader->program, 0, "position");
glBindAttribLocation(shader->program, 1, "texcoord");
if (requirements->texcoord_input == SHADER_TEXCOORD_INPUT_ATTRIB)
glBindAttribLocation(shader->program, 1, "texcoord");
glLinkProgram(shader->program);
glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
......@@ -287,6 +323,8 @@ gl_shader_create(struct gl_renderer *gr,
glDeleteShader(shader->fragment_shader);
shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
shader->surface_to_buffer_uniform =
glGetUniformLocation(shader->program, "surface_to_buffer");
shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
......@@ -540,6 +578,10 @@ gl_shader_load_config(struct gl_shader *shader,
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, sconf->projection.d);
if (shader->surface_to_buffer_uniform != -1)
glUniformMatrix4fv(shader->surface_to_buffer_uniform,
1, GL_FALSE, sconf->surface_to_buffer.d);
if (shader->color_uniform != -1)
glUniform4fv(shader->color_uniform, 1, sconf->unicolor);
......
......@@ -25,6 +25,10 @@
* SOFTWARE.
*/
/* enum gl_shader_texcoord_input */
#define SHADER_TEXCOORD_INPUT_ATTRIB 0
#define SHADER_TEXCOORD_INPUT_SURFACE 1
/* Always use high-precision for vertex calculations */
precision highp float;
......@@ -35,6 +39,8 @@ precision highp float;
#endif
uniform mat4 proj;
uniform mat4 surface_to_buffer;
attribute vec2 position;
attribute vec2 texcoord;
......@@ -44,5 +50,10 @@ varying FRAG_PRECISION vec2 v_texcoord;
void main()
{
gl_Position = proj * vec4(position, 0.0, 1.0);
#if DEF_TEXCOORD_INPUT == SHADER_TEXCOORD_INPUT_ATTRIB
v_texcoord = texcoord;
#elif DEF_TEXCOORD_INPUT == SHADER_TEXCOORD_INPUT_SURFACE
v_texcoord = vec2(surface_to_buffer * vec4(position, 0.0, 1.0));
#endif
}
......@@ -32,7 +32,7 @@
WESTON_EXPORT_FOR_TESTS float
float_difference(float a, float b)
{
/* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
/* https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */
static const float max_diff = 4.0f * FLT_MIN;
static const float max_rel_diff = 4.0e-5;
float diff = a - b;
......@@ -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,18 +306,64 @@ 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;
}
int
clip_quad(struct gl_quad *quad, pixman_box32_t *surf_rect,
struct clip_vertex *vertices)
{
struct clip_context ctx = {
.clip.x1 = surf_rect->x1,
.clip.y1 = surf_rect->y1,
.clip.x2 = surf_rect->x2,
.clip.y2 = surf_rect->y2,
};
int n;
/* Simple case: quad edges are parallel to surface rect edges, there
* will be either four or zero edges. We just need to clip the quad to
* the surface rect bounds and test for non-zero area:
*/
if (quad->axis_aligned) {
clip_simple(&ctx, &quad->vertices, vertices);
if ((vertices[0].x != vertices[1].x) &&
(vertices[0].y != vertices[2].y))
return 4;
else
return 0;
}
/* Transformed case: first, simple bounding box check to discard early a
* quad that does not intersect with the rect:
*/
if ((quad->bbox.x1 >= ctx.clip.x2) || (quad->bbox.x2 <= ctx.clip.x1) ||
(quad->bbox.y1 >= ctx.clip.y2) || (quad->bbox.y2 <= ctx.clip.y1))
return 0;
/* Then, use a general polygon clipping algorithm to clip the quad with
* each side of the surface rect. The algorithm is Sutherland-Hodgman,
* as explained in
* https://www.codeguru.com/cplusplus/polygon-clipping/
* but without looking at any of that code.
*/
n = clip_transformed(&ctx, &quad->vertices, vertices);
if (n < 3)
return 0;
return n;
}
......@@ -25,25 +25,33 @@
#ifndef _WESTON_VERTEX_CLIPPING_H
#define _WESTON_VERTEX_CLIPPING_H
#include <libweston/matrix.h>
#include <stdbool.h>
#include <pixman.h>
struct clip_vertex {
float x, y;
};
struct polygon8 {
struct weston_coord pos[8];
struct clip_vertex pos[8];
int n;
};
struct gl_quad {
struct polygon8 vertices;
struct { float x1, y1, x2, y2; } bbox; /* Valid if !axis_aligned. */
bool axis_aligned;
};
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
......@@ -52,11 +60,23 @@ 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);
/*
* Compute the boundary vertices of the intersection of an arbitrary
* quadrilateral 'quad' and the axis-aligned rectangle 'surf_rect'. The vertices
* 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.
*/
int
clip_quad(struct gl_quad *quad,
pixman_box32_t *surf_rect,
struct clip_vertex *vertices);
#endif
......@@ -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;
......