From patchwork Thu Aug 30 21:47:18 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rob Clark X-Patchwork-Id: 11114 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 311EE23F27 for ; Thu, 30 Aug 2012 21:47:36 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 4C7B0A192CE for ; Thu, 30 Aug 2012 21:46:59 +0000 (UTC) Received: by mail-iy0-f180.google.com with SMTP id j25so3732075iaf.11 for ; Thu, 30 Aug 2012 14:47:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf :dkim-signature:sender:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references:x-gm-message-state; bh=DFyPwlb5SAFGdw0Rv/5YA9KK1bJRUameHLdL8/oxT4A=; b=A9ifwSueqy+lYm1RlpTbsdTYxk2YHgBXt8fGJeUM4JsmVEp3WN+NSQYZDI8slJmm4A LdsX69sFJgV7r/la7WmQhexf7hz90Ww6EjHLjMJM91YEN5vdeIqjYov6aO43uoNWvhW5 rbSaaicT5xHdG7QBpQNZawqUaphJ1evSF1EFtQD6k8FIxtKQq0z0ODb9bEEQmYZDS4g1 RiFeMdl23fIDpMEstsLgKXFgHwrE+apMZxIMgw/nUccaoDlhAcQdbk4/faa5mEHHF+5N xrAMkk3tDPzIlZzyYRBlVBriUfC6It9D6Y5vpF7wVK2mhZZZADmiXh+MViNOJi+x9HH7 GnKQ== Received: by 10.42.109.194 with SMTP id m2mr6328940icp.48.1346363255403; Thu, 30 Aug 2012 14:47:35 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.184.232 with SMTP id ex8csp33030igc; Thu, 30 Aug 2012 14:47:34 -0700 (PDT) Received: by 10.66.74.37 with SMTP id q5mr11772412pav.29.1346363254752; Thu, 30 Aug 2012 14:47:34 -0700 (PDT) Received: from mail-pb0-f50.google.com (mail-pb0-f50.google.com [209.85.160.50]) by mx.google.com with ESMTPS id iq5si4768719pbc.314.2012.08.30.14.47.34 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 30 Aug 2012 14:47:34 -0700 (PDT) Received-SPF: pass (google.com: domain of robdclark@gmail.com designates 209.85.160.50 as permitted sender) client-ip=209.85.160.50; Authentication-Results: mx.google.com; spf=pass (google.com: domain of robdclark@gmail.com designates 209.85.160.50 as permitted sender) smtp.mail=robdclark@gmail.com; dkim=pass header.i=@gmail.com Received: by mail-pb0-f50.google.com with SMTP id md12so4150965pbc.37 for ; Thu, 30 Aug 2012 14:47:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=DFyPwlb5SAFGdw0Rv/5YA9KK1bJRUameHLdL8/oxT4A=; b=Ks9muaiJjyzL0TVA2ELeA0fTUFpDZO737BlZByBm3eixGr4t52XmQ3DMOK7O0G03be ptNgpQIEDBrvRLJnGLdG0I9Olzi09U6y9EIZN4mJI1qQff3ffGRnd+lGJSubomflzsrK ErY8qe2WlR9Jj1uU1hQGfq2JhQTRuTLasNlYxmBxkiQUiIQMfbbhauJrcW2Wb5gzczFc oR4AMSUoy1w4wNKxOFTHXPmg5sLX2g6PtCtcmhfHTgUEbqNi8Fr7P6pt80WGxIGvB3j/ 0JbqRW2wKnHS0NYo/gqzzqVrLFqhSv3WQ3O3WxZnT/4R0VWKzhIzCJwbxcPSVdae8ZTN FoEg== Received: by 10.68.200.227 with SMTP id jv3mr13415497pbc.162.1346363254505; Thu, 30 Aug 2012 14:47:34 -0700 (PDT) Received: from localhost ([38.96.16.75]) by mx.google.com with ESMTPS id mr2sm2223655pbb.16.2012.08.30.14.47.32 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 30 Aug 2012 14:47:33 -0700 (PDT) Sender: Rob Clark From: Rob Clark To: wayland-devel@lists.freedesktop.org Cc: patches@linaro.org, Rob Clark Subject: [PATCH weston 2/5] compositor: simplify shaders Date: Thu, 30 Aug 2012 16:47:18 -0500 Message-Id: <1346363241-29219-3-git-send-email-rob.clark@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1346363241-29219-1-git-send-email-rob.clark@linaro.org> References: <1346363241-29219-1-git-send-email-rob.clark@linaro.org> X-Gm-Message-State: ALoCoQmVBo8fDBon0c4HgcxRfT7Icf94UPFD60xoK0UnVdUpDzt5OW82/6tfkae6s2t/UeTKL+rA From: Rob Clark Re-work how the shaders and emitted vertices work. Rather than always rendering clip-rect sized quads and doing transformation in tex coords (and requiring the corresponding clipping in frag shader), instead emit transformed vertices, clipped wrt. dirty region, and use simpler frag shaders. Also, split the rendering, so blended surfaces with an opaque region have the opaque region drawn with blend disabled. The result is considerably fewer pixels drawn with blend enabled, and much fewer cycles in the frag shader. This requires having some more complex logic to figure out the vertices of the shape which forms the intersection of the clip rect and the transformed surface. Which has perhaps got a few bugs or missing cases, still (visual glitches in some cases) but at this point more or less is starting to work. I think it is at least far enough along to get some initial review. The result, on small SoC GPU (omap4/pandaboard) on 1920x1080 display, for simple stuff like moving windows around, I get 60fps (before 30fps or less), and pushing YUV buffers for hw decoded 1080p video goes from ~6fps to 30fps, with no drop in framerate for transformed/rotated video surface. v1: original v2: check that perpendicular intersect vertex falls within bounds of transformed surface v3: update w/ comments and fixes from Pekka Paalanen v4: fix for full surface alpha from Pekka Paalanen, fix compositor- wayland build Signed-off-by: Rob Clark --- src/compositor-wayland.c | 1 - src/compositor.c | 558 +++++++++++++++++++++++++++++++++++++--------- src/compositor.h | 6 +- 3 files changed, 453 insertions(+), 112 deletions(-) diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c index 4fc77f1..131fa32 100644 --- a/src/compositor-wayland.c +++ b/src/compositor-wayland.c @@ -193,7 +193,6 @@ draw_border(struct wayland_output *output) glUniform1i(shader->tex_uniforms[0], 0); glUniform1f(shader->alpha_uniform, 1); - glUniform1f(shader->texwidth_uniform, 1); n = texture_border(output); diff --git a/src/compositor.c b/src/compositor.c index 756859f..228ffe4 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -861,74 +861,441 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer) } } + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) > (b)) ? (b) : (a)) +#define clip(x, a, b) min(max(x, a), b) +#define sign(x) ((x) >= 0) + static int -texture_region(struct weston_surface *es, pixman_region32_t *region) +calculate_edges(struct weston_surface *es, pixman_box32_t *rect, + pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey) +{ + int i, n = 0; + GLfloat min_x, max_x, min_y, max_y; + GLfloat x[4] = { + surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1, + }; + GLfloat y[4] = { + surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2, + }; + GLfloat cx1 = rect->x1; + GLfloat cx2 = rect->x2; + GLfloat cy1 = rect->y1; + GLfloat cy2 = rect->y2; + + GLfloat dist_squared(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) + { + GLfloat dx = (x1 - x2); + GLfloat dy = (y1 - y2); + return dx * dx + dy * dy; + } + + void append_vertex(GLfloat x, GLfloat y) + { + /* don't emit duplicate vertices: */ + if ((n > 0) && (ex[n-1] == x) && (ey[n-1] == y)) + return; + ex[n] = x; + ey[n] = y; + n++; + } + + /* transform surface to screen space: */ + for (i = 0; i < 4; i++) + weston_surface_to_global_float(es, x[i], y[i], &x[i], &y[i]); + + /* find bounding box: */ + min_x = max_x = x[0]; + min_y = max_y = y[0]; + + for (i = 1; i < 4; i++) { + min_x = min(min_x, x[i]); + max_x = max(max_x, x[i]); + min_y = min(min_y, y[i]); + max_y = max(max_y, y[i]); + } + + /* First, simple bounding box check to discard early transformed + * surface rects that do not intersect with the clip region: + */ + if ((min_x > cx2) || (max_x < cx1) || + (min_y > cy2) || (max_y < cy1)) + 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 (!es->transform.enabled) { + for (i = 0; i < 4; i++) { + ex[n] = clip(x[i], cx1, cx2); + ey[n] = clip(y[i], cy1, cy2); + n++; + } + return 4; + } + + /* Hard case, transformation applied. We need to find the vertices + * of the shape that is the intersection of the clip rect and + * transformed surface. This can be anything from 3 to 8 sides. + * + * Observation: all the resulting vertices will be the intersection + * points of the transformed surface and the clip rect, plus the + * vertices of the clip rect which are enclosed by the transformed + * surface and the vertices of the transformed surface which are + * enclosed by the clip rect. + * + * Observation: there will be zero, one, or two resulting vertices + * for each edge of the src rect. + * + * Loop over four edges of the transformed rect: + */ + for (i = 0; i < 4; i++) { + GLfloat x1, y1, x2, y2; + int last_n = n; + + x1 = x[i]; + y1 = y[i]; + + /* if this vertex is contained in the clip rect, use it as-is: */ + if ((cx1 <= x1) && (x1 <= cx2) && + (cy1 <= y1) && (y1 <= cy2)) + append_vertex(x1, y1); + + /* for remaining, we consider the point as part of a line: */ + x2 = x[(i+1) % 4]; + y2 = y[(i+1) % 4]; + + if (x1 == x2) { + append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2)); + append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2)); + } else if (y1 == y2) { + append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2)); + append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2)); + } else { + GLfloat m, c, p; + GLfloat tx[2], ty[2]; + int tn = 0; + + int intersect_horiz(GLfloat y, GLfloat *p) + { + GLfloat x; + + /* if y does not lie between y1 and y2, no + * intersection possible + */ + if (sign(y-y1) == sign(y-y2)) + return 0; + + x = (y - c) / m; + + /* if x does not lie between cx1 and cx2, no + * intersection: + */ + if (sign(x-cx1) == sign(x-cx2)) + return 0; + + *p = x; + return 1; + } + + int intersect_vert(GLfloat x, GLfloat *p) + { + GLfloat y; + + if (sign(x-x1) == sign(x-x2)) + return 0; + + y = m * x + c; + + if (sign(y-cy1) == sign(y-cy2)) + return 0; + + *p = y; + return 1; + } + + /* y = mx + c */ + m = (y2 - y1) / (x2 - x1); + c = y1 - m * x1; + + /* check for up to two intersections with the four edges + * of the clip rect. Note that we don't know the orientation + * of the transformed surface wrt. the clip rect. So if when + * there are two intersection points, we need to put the one + * closest to x1,y1 first: + */ + + /* check top clip rect edge: */ + if (intersect_horiz(cy1, &p)) { + ty[tn] = cy1; + tx[tn] = p; + tn++; + } + + /* check right clip rect edge: */ + if (intersect_vert(cx2, &p)) { + ty[tn] = p; + tx[tn] = cx2; + tn++; + if (tn == 2) + goto edge_check_done; + } + + /* check bottom clip rect edge: */ + if (intersect_horiz(cy2, &p)) { + ty[tn] = cy2; + tx[tn] = p; + tn++; + if (tn == 2) + goto edge_check_done; + } + + /* check left clip rect edge: */ + if (intersect_vert(cx1, &p)) { + ty[tn] = p; + tx[tn] = cx1; + tn++; + } + +edge_check_done: + if (tn == 1) { + append_vertex(tx[0], ty[0]); + } else if (tn == 2) { + if (dist_squared(x1, y1, tx[0], ty[0]) < + dist_squared(x1, y1, tx[1], ty[1])) { + append_vertex(tx[0], ty[0]); + append_vertex(tx[1], ty[1]); + } else { + append_vertex(tx[1], ty[1]); + append_vertex(tx[0], ty[0]); + } + } + + if (n == last_n) { + GLfloat best_x=0, best_y=0; + uint32_t d, best_d = (unsigned int)-1; /* distance squared */ + uint32_t max_d = dist_squared(x2, y2, + x[(i+2) % 4], y[(i+2) % 4]); + + /* if there are no vertices on this line, it could be that + * there is a vertex of the clip rect that is enclosed by + * the transformed surface. Find the vertex of the clip + * rect that is reached by the shortest line perpendicular + * to the current edge, if any. + * + * slope of perpendicular is 1/m, so + * + * cy = -cx/m + c2 + * c2 = cy + cx/m + * + */ + + int perp_intersect(GLfloat cx, GLfloat cy, uint32_t *d) + { + GLfloat c2 = cy + cx/m; + GLfloat x = (c2 - c) / (m + 1/m); + + /* if the x position of the intersection of the + * perpendicular with the transformed edge does + * not lie within the bounds of the edge, then + * no intersection: + */ + if (sign(x-x1) == sign(x-x2)) + return 0; + + *d = dist_squared(cx, cy, x, (m * x) + c); + + /* if intersection distance is further away than + * opposite edge of surface region, it is invalid: + */ + if (*d > max_d) + return 0; + + return 1; + } + + if (perp_intersect(cx1, cy1, &d)) { + best_x = cx1; + best_y = cy1; + best_d = d; + } + + if (perp_intersect(cx1, cy2, &d) && (d < best_d)) { + best_x = cx1; + best_y = cy2; + best_d = d; + } + + if (perp_intersect(cx2, cy2, &d) && (d < best_d)) { + best_x = cx2; + best_y = cy2; + best_d = d; + } + + if (perp_intersect(cx2, cy1, &d) && (d < best_d)) { + best_x = cx2; + best_y = cy1; + best_d = d; + } + + if (best_d != (unsigned int)-1) // XXX can this happen? + append_vertex(best_x, best_y); + } + } + + } + + return n; +} + +static int +texture_region(struct weston_surface *es, pixman_region32_t *region, + pixman_region32_t *surf_region) { struct weston_compositor *ec = es->compositor; GLfloat *v, inv_width, inv_height; - GLfloat sx, sy; - pixman_box32_t *rectangles; - unsigned int *p; - int i, n; + unsigned int *vtxcnt, nvtx = 0; + pixman_box32_t *rects, *surf_rects; + int i, j, k, nrects, nsurf; + + rects = pixman_region32_rectangles(region, &nrects); + surf_rects = pixman_region32_rectangles(surf_region, &nsurf); + + /* worst case we can have 10 vertices per rect (ie. clipped into + * an octagon): + */ + v = wl_array_add(&ec->vertices, nrects * nsurf * 10 * 4 * sizeof *v); + vtxcnt = wl_array_add(&ec->vtxcnt, nrects * nsurf * sizeof *vtxcnt); - rectangles = pixman_region32_rectangles(region, &n); - v = wl_array_add(&ec->vertices, n * 16 * sizeof *v); - p = wl_array_add(&ec->indices, n * 6 * sizeof *p); inv_width = 1.0 / es->pitch; inv_height = 1.0 / es->geometry.height; - for (i = 0; i < n; i++, v += 16, p += 6) { - surface_from_global_float(es, rectangles[i].x1, - rectangles[i].y1, &sx, &sy); - v[ 0] = rectangles[i].x1; - v[ 1] = rectangles[i].y1; - v[ 2] = sx * inv_width; - v[ 3] = sy * inv_height; - - surface_from_global_float(es, rectangles[i].x1, - rectangles[i].y2, &sx, &sy); - v[ 4] = rectangles[i].x1; - v[ 5] = rectangles[i].y2; - v[ 6] = sx * inv_width; - v[ 7] = sy * inv_height; - - surface_from_global_float(es, rectangles[i].x2, - rectangles[i].y1, &sx, &sy); - v[ 8] = rectangles[i].x2; - v[ 9] = rectangles[i].y1; - v[10] = sx * inv_width; - v[11] = sy * inv_height; - - surface_from_global_float(es, rectangles[i].x2, - rectangles[i].y2, &sx, &sy); - v[12] = rectangles[i].x2; - v[13] = rectangles[i].y2; - v[14] = sx * inv_width; - v[15] = sy * inv_height; - - p[0] = i * 4 + 0; - p[1] = i * 4 + 1; - p[2] = i * 4 + 2; - p[3] = i * 4 + 2; - p[4] = i * 4 + 1; - p[5] = i * 4 + 3; + for (i = 0; i < nrects; i++) { + pixman_box32_t *rect = &rects[i]; + for (j = 0; j < nsurf; j++) { + pixman_box32_t *surf_rect = &surf_rects[j]; + GLfloat cx, cy; + GLfloat ex[8], ey[8]; /* edge points in screen space */ + int n; + + void emit_vertex(GLfloat gx, GLfloat gy) + { + GLfloat sx, sy; + surface_from_global_float(es, gx, gy, &sx, &sy); + /* In groups of 4 attributes, first two are 'position', 2nd two + * are 'texcoord'. + */ + *(v++) = gx; + *(v++) = gy; + *(v++) = sx * inv_width; + *(v++) = sy * inv_height; + } + + /* The transformed surface, after clipping to the clip region, + * can have as many as eight sides, emitted as a triangle-fan. + * The first vertex is the center, followed by each corner. + * + * 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. + * + * To do this, we first calculate the (up to eight) points that + * form the intersection of the clip rect and the transformed + * surface. After that we calculate the average to determine + * the center point, and emit the center and edge vertices of + * the fan. + */ + n = calculate_edges(es, rect, surf_rect, ex, ey); + if (n < 3) + continue; + + /* calculate/emit center point: */ + cx = 0; + cy = 0; + for (k = 0; k < n; k++) { + cx += ex[k]; + cy += ey[k]; + } + cx /= n; + cy /= n; + emit_vertex(cx, cy); + + /* then emit edge points: */ + for (k = 0; k < n; k++) + emit_vertex(ex[k], ey[k]); + + /* and close the fan: */ + emit_vertex(ex[0], ey[0]); + + vtxcnt[nvtx++] = n + 2; + } } - return n; + return nvtx; } +static void +repaint_region(struct weston_surface *es, pixman_region32_t *region, + pixman_region32_t *surf_region) +{ + struct weston_compositor *ec = es->compositor; + GLfloat *v; + 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 + * corodinates. 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. + */ + nfans = texture_region(es, region, surf_region); + + v = ec->vertices.data; + vtxcnt = ec->vtxcnt.data; + + /* position: */ + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]); + glEnableVertexAttribArray(0); + + /* texcoord: */ + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]); + glEnableVertexAttribArray(1); + + for (i = 0, first = 0; i < nfans; i++) { + glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]); + first += vtxcnt[i]; + } + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + ec->vertices.size = 0; + ec->vtxcnt.size = 0; +} + + WL_EXPORT void weston_surface_draw(struct weston_surface *es, struct weston_output *output, pixman_region32_t *damage) { - GLfloat surface_rect[4] = { 0.0, 1.0, 0.0, 1.0 }; struct weston_compositor *ec = es->compositor; - GLfloat *v; + /* repaint bounding region in global coordinates: */ pixman_region32_t repaint; + /* regions of surface to draw opaque/blended in surface coordinates: */ + pixman_region32_t surface_opaque, surface_blend; GLint filter; - int i, n; + int i; pixman_region32_init(&repaint); + pixman_region32_init(&surface_opaque); + pixman_region32_init(&surface_blend); + pixman_region32_intersect(&repaint, &es->transform.boundingbox, damage); pixman_region32_subtract(&repaint, &repaint, &es->clip); @@ -940,10 +1307,20 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output, &ec->primary_plane.damage, &repaint); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - if (es->blend || es->alpha < 1.0) - glEnable(GL_BLEND); - else - glDisable(GL_BLEND); + if (es->blend || es->alpha < 1.0) { + /* blended region is whole surface minus opaque region: */ + pixman_region32_init_rect(&surface_blend, 0, 0, + es->geometry.width, es->geometry.height); + pixman_region32_init(&surface_opaque); + pixman_region32_copy(&surface_opaque, &es->opaque); + pixman_region32_subtract(&surface_blend, &surface_blend, + &surface_opaque); + } else { + /* whole surface is opaque: */ + pixman_region32_init_rect(&surface_opaque, 0, 0, + es->geometry.width, es->geometry.height); + pixman_region32_init(&surface_blend); + } if (ec->current_shader != es->shader) { glUseProgram(es->shader->program); @@ -954,20 +1331,12 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output, 1, GL_FALSE, output->matrix.d); glUniform4fv(es->shader->color_uniform, 1, es->color); glUniform1f(es->shader->alpha_uniform, es->alpha); - glUniform1f(es->shader->texwidth_uniform, - (GLfloat)es->geometry.width / es->pitch); - if (es->blend) - glUniform4fv(es->shader->opaque_uniform, 1, es->opaque_rect); - else - glUniform4fv(es->shader->opaque_uniform, 1, surface_rect); if (es->transform.enabled || output->zoom.active) filter = GL_LINEAR; else filter = GL_NEAREST; - n = texture_region(es, &repaint); - for (i = 0; i < es->num_textures; i++) { glUniform1i(es->shader->tex_uniforms[i], i); glActiveTexture(GL_TEXTURE0 + i); @@ -976,22 +1345,20 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output, glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter); } - v = ec->vertices.data; - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - - glDrawElements(GL_TRIANGLES, n * 6, GL_UNSIGNED_INT, ec->indices.data); - - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(0); + if (pixman_region32_not_empty(&surface_opaque)) { + glDisable(GL_BLEND); + repaint_region(es, &repaint, &surface_opaque); + } - ec->vertices.size = 0; - ec->indices.size = 0; + if (pixman_region32_not_empty(&surface_blend)) { + glEnable(GL_BLEND); + repaint_region(es, &repaint, &surface_blend); + } out: pixman_region32_fini(&repaint); + pixman_region32_fini(&surface_opaque); + pixman_region32_fini(&surface_blend); } WL_EXPORT void @@ -2818,39 +3185,23 @@ static const char vertex_shader[] = "}\n"; /* Declare common fragment shader uniforms */ -#define FRAGMENT_SHADER_UNIFORMS \ - "uniform float alpha;\n" \ - "uniform float texwidth;\n" \ - "uniform vec4 opaque;\n" - -/* Common fragment shader init code (check texture bounds) */ -#define FRAGMENT_SHADER_INIT \ - " if (v_texcoord.x < 0.0 || v_texcoord.x > texwidth ||\n" \ - " v_texcoord.y < 0.0 || v_texcoord.y > 1.0)\n" \ - " discard;\n" - -#define FRAGMENT_SHADER_EXIT \ - " if (opaque.x <= v_texcoord.x && v_texcoord.x < opaque.y &&\n" \ - " opaque.z <= v_texcoord.y && v_texcoord.y < opaque.w)\n" \ - " gl_FragColor.a = 1.0;\n" \ - " gl_FragColor = alpha * gl_FragColor;\n" - #define FRAGMENT_CONVERT_YUV \ + " y *= alpha;\n" \ + " u *= alpha;\n" \ + " v *= alpha;\n" \ " gl_FragColor.r = y + 1.59602678 * v;\n" \ " gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n" \ " gl_FragColor.b = y + 2.01723214 * u;\n" \ - " gl_FragColor.a = 1.0;\n" + " gl_FragColor.a = alpha;\n" static const char texture_fragment_shader_rgba[] = "precision mediump float;\n" "varying vec2 v_texcoord;\n" "uniform sampler2D tex;\n" - FRAGMENT_SHADER_UNIFORMS + "uniform float alpha;\n" "void main()\n" "{\n" - FRAGMENT_SHADER_INIT - " gl_FragColor = texture2D(tex, v_texcoord)\n;" - FRAGMENT_SHADER_EXIT + " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;" "}\n"; static const char texture_fragment_shader_egl_external[] = @@ -2858,12 +3209,10 @@ static const char texture_fragment_shader_egl_external[] = "precision mediump float;\n" "varying vec2 v_texcoord;\n" "uniform samplerExternalOES tex;\n" - FRAGMENT_SHADER_UNIFORMS + "uniform float alpha;\n" "void main()\n" "{\n" - FRAGMENT_SHADER_INIT - " gl_FragColor = texture2D(tex, v_texcoord)\n;" - FRAGMENT_SHADER_EXIT + " gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;" "}\n"; static const char texture_fragment_shader_y_uv[] = @@ -2871,14 +3220,12 @@ static const char texture_fragment_shader_y_uv[] = "uniform sampler2D tex;\n" "uniform sampler2D tex1;\n" "varying vec2 v_texcoord;\n" - FRAGMENT_SHADER_UNIFORMS + "uniform float alpha;\n" "void main() {\n" - FRAGMENT_SHADER_INIT " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n" " float u = texture2D(tex1, v_texcoord).r - 0.5;\n" " float v = texture2D(tex1, v_texcoord).g - 0.5;\n" FRAGMENT_CONVERT_YUV - FRAGMENT_SHADER_EXIT "}\n"; static const char texture_fragment_shader_y_u_v[] = @@ -2887,14 +3234,12 @@ static const char texture_fragment_shader_y_u_v[] = "uniform sampler2D tex1;\n" "uniform sampler2D tex2;\n" "varying vec2 v_texcoord;\n" - FRAGMENT_SHADER_UNIFORMS + "uniform float alpha;\n" "void main() {\n" - FRAGMENT_SHADER_INIT " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n" " float u = texture2D(tex1, v_texcoord).x - 0.5;\n" " float v = texture2D(tex2, v_texcoord).x - 0.5;\n" FRAGMENT_CONVERT_YUV - FRAGMENT_SHADER_EXIT "}\n"; static const char texture_fragment_shader_y_xuxv[] = @@ -2902,14 +3247,12 @@ static const char texture_fragment_shader_y_xuxv[] = "uniform sampler2D tex;\n" "uniform sampler2D tex1;\n" "varying vec2 v_texcoord;\n" - FRAGMENT_SHADER_UNIFORMS + "uniform float alpha;\n" "void main() {\n" - FRAGMENT_SHADER_INIT " float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n" " float u = texture2D(tex1, v_texcoord).g - 0.5;\n" " float v = texture2D(tex1, v_texcoord).a - 0.5;\n" FRAGMENT_CONVERT_YUV - FRAGMENT_SHADER_EXIT "}\n"; static const char solid_fragment_shader[] = @@ -2973,8 +3316,6 @@ weston_shader_init(struct weston_shader *shader, shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2"); shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha"); shader->color_uniform = glGetUniformLocation(shader->program, "color"); - shader->texwidth_uniform = glGetUniformLocation(shader->program, "texwidth"); - shader->opaque_uniform = glGetUniformLocation(shader->program, "opaque"); return 0; } @@ -3323,6 +3664,7 @@ weston_compositor_shutdown(struct weston_compositor *ec) wl_array_release(&ec->vertices); wl_array_release(&ec->indices); + wl_array_release(&ec->vtxcnt); wl_event_loop_destroy(ec->input_loop); } diff --git a/src/compositor.h b/src/compositor.h index f2ba4e1..3b8c705 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -247,8 +247,6 @@ struct weston_shader { GLint tex_uniforms[3]; GLint alpha_uniform; GLint color_uniform; - GLint texwidth_uniform; - GLint opaque_uniform; }; enum { @@ -318,7 +316,9 @@ struct weston_compositor { int idle_time; /* effective timeout, s */ /* Repaint state. */ - struct wl_array vertices, indices; + struct wl_array vertices; + struct wl_array indices; /* only used in compositor-wayland */ + struct wl_array vtxcnt; struct weston_plane primary_plane; uint32_t focus;