diff options
Diffstat (limited to 'glamor/glamor_trapezoid.c')
-rw-r--r-- | glamor/glamor_trapezoid.c | 1819 |
1 files changed, 1819 insertions, 0 deletions
diff --git a/glamor/glamor_trapezoid.c b/glamor/glamor_trapezoid.c new file mode 100644 index 000000000..76b3729cf --- /dev/null +++ b/glamor/glamor_trapezoid.c @@ -0,0 +1,1819 @@ +/* + * Copyright © 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Junyan He <junyan.he@linux.intel.com> + * + */ + +/** @file glamor_trapezoid.c + * + * Trapezoid acceleration implementation + */ + +#include "glamor_priv.h" + +#ifdef RENDER +#include "mipict.h" +#include "fbpict.h" + +static xFixed +_glamor_linefixedX (xLineFixed *l, xFixed y, Bool ceil) +{ + xFixed dx = l->p2.x - l->p1.x; + xFixed_32_32 ex = (xFixed_32_32) (y - l->p1.y) * dx; + xFixed dy = l->p2.y - l->p1.y; + if (ceil) + ex += (dy - 1); + return l->p1.x + (xFixed) (ex / dy); +} + +static xFixed +_glamor_linefixedY (xLineFixed *l, xFixed x, Bool ceil) +{ + xFixed dy = l->p2.y - l->p1.y; + xFixed_32_32 ey = (xFixed_32_32) (x - l->p1.x) * dy; + xFixed dx = l->p2.x - l->p1.x; + if (ceil) + ey += (dx - 1); + return l->p1.y + (xFixed) (ey / dx); +} + +#ifdef GLAMOR_TRAPEZOID_SHADER + +#define GLAMOR_VERTEX_TOP_BOTTOM (GLAMOR_VERTEX_SOURCE + 1) +#define GLAMOR_VERTEX_LEFT_PARAM (GLAMOR_VERTEX_SOURCE + 2) +#define GLAMOR_VERTEX_RIGHT_PARAM (GLAMOR_VERTEX_SOURCE + 3) + +#define DEBUG_CLIP_VTX 0 + +#define POINT_INSIDE_CLIP_RECT(point, rect) \ + (point[0] >= IntToxFixed(rect->x1) \ + && point[0] <= IntToxFixed(rect->x2) \ + && point[1] >= IntToxFixed(rect->y1) \ + && point[1] <= IntToxFixed(rect->y2)) + +static xFixed +_glamor_lines_crossfixedY (xLineFixed *l, xLineFixed *r) +{ + xFixed dx1 = l->p2.x - l->p1.x; + xFixed dx2 = r->p2.x - r->p1.x; + xFixed dy1 = l->p2.y - l->p1.y; + xFixed dy2 = r->p2.y - r->p1.y; + xFixed_32_32 tmp = (xFixed_32_32) dy2 * dy1; + xFixed_32_32 dividend1 = (tmp >> 32) * (l->p1.x - r->p1.x); + xFixed_32_32 dividend2; + xFixed_32_32 dividend3; + xFixed_32_32 divisor; + + tmp = (xFixed_32_32) dx1 * dy2; + dividend2 = (tmp >> 32) * l->p1.y; + tmp = (xFixed_32_32) dy1 * dx2; + dividend3 = (tmp >> 32) * r->p1.y; + divisor = ((xFixed_32_32) dx1 * (xFixed_32_32) dy2 + - (xFixed_32_32) dy1 * (xFixed_32_32) dx2) >> 32; + + if (divisor) + return (xFixed)((dividend2 - dividend1 - dividend3) / divisor); + + return 0xFFFFFFFF; +} + +static Bool +point_inside_trapezoid(int point[2], xTrapezoid * trap, xFixed cut_y) +{ + int ret = TRUE; + int tmp; + if (point[1] > trap->bottom) { + ret = FALSE; + if (DEBUG_CLIP_VTX) { + ErrorF("Out of Trap bottom, point[1] = %d(0x%x)), " + "bottom = %d(0x%x)\n", + (unsigned int)xFixedToInt(point[1]), point[1], + (unsigned int)xFixedToInt(trap->bottom), + (unsigned int)trap->bottom); + } + + return ret; + } + + if (point[1] < trap->top) { + ret = FALSE; + if (DEBUG_CLIP_VTX) { + ErrorF("Out of Trap top, point[1] = %d(0x%x)), " + "top = %d(0x%x)\n", + (unsigned int)xFixedToInt(point[1]), point[1], + (unsigned int)xFixedToInt(trap->top), + (unsigned int)trap->top); + } + + return ret; + } + + tmp = _glamor_linefixedX (&trap->left, point[1], FALSE); + if (point[0] < tmp) { + ret = FALSE; + + if (abs(cut_y - trap->top) < pixman_fixed_1_minus_e && + abs(point[1] - trap->top) < pixman_fixed_1_minus_e && + tmp - point[0] < pixman_fixed_1_minus_e) { + ret = TRUE; + } else if (abs(cut_y - trap->bottom) < pixman_fixed_1_minus_e && + point[1] - trap->bottom < pixman_fixed_1_minus_e && + tmp - point[0] < pixman_fixed_1_minus_e) { + ret = TRUE; + } + + if (DEBUG_CLIP_VTX && !ret) { + ErrorF("Out of Trap left, point[0] = %d(0x%x)), " + "left = %d(0x%x)\n", + (unsigned int)xFixedToInt(point[0]), point[0], + (unsigned int)xFixedToInt(tmp), (unsigned int)tmp); + } + + if (!ret) + return ret; + } + + tmp = _glamor_linefixedX (&trap->right, point[1], TRUE); + if (point[0] > tmp) { + ret = FALSE; + + if (abs(cut_y - trap->top) < pixman_fixed_1_minus_e && + abs(point[1] - trap->top) < pixman_fixed_1_minus_e && + point[0] - tmp < pixman_fixed_1_minus_e) { + ret = TRUE; + } else if (abs(cut_y - trap->bottom) < pixman_fixed_1_minus_e && + abs(point[1] - trap->bottom) < pixman_fixed_1_minus_e && + point[0] - tmp < pixman_fixed_1_minus_e) { + ret = TRUE; + } + + if (DEBUG_CLIP_VTX && !ret) { + ErrorF("Out of Trap right, point[0] = %d(0x%x)), " + "right = %d(0x%x)\n", + (unsigned int)xFixedToInt(point[0]), point[0], + (unsigned int)xFixedToInt(tmp), (unsigned int)tmp); + } + + if (!ret) + return ret; + } + + return ret; +} + +static void +glamor_emit_composite_triangle(ScreenPtr screen, + const float *src_coords, + const float *mask_coords, + const float *dst_coords) +{ + glamor_emit_composite_vert(screen, src_coords, mask_coords, + dst_coords, 0); + glamor_emit_composite_vert(screen, src_coords, mask_coords, + dst_coords, 1); + glamor_emit_composite_vert(screen, src_coords, mask_coords, + dst_coords, 2); +} + +static void +glamor_flush_composite_triangles(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv = + glamor_get_screen_private(screen); + glamor_gl_dispatch *dispatch; + + dispatch = glamor_get_dispatch(glamor_priv); + if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) + dispatch->glUnmapBuffer(GL_ARRAY_BUFFER); + else { + + dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo); + dispatch->glBufferData(GL_ARRAY_BUFFER, + glamor_priv->vbo_offset, + glamor_priv->vb, GL_DYNAMIC_DRAW); + } + + if (!glamor_priv->render_nr_verts) + return; + + dispatch->glDrawArrays(GL_TRIANGLES, 0, glamor_priv->render_nr_verts); + glamor_put_dispatch(glamor_priv); +} + +static Bool +_glamor_clip_trapezoid_vertex(xTrapezoid * trap, BoxPtr pbox, + int vertex[6], int *num) +{ + xFixed edge_cross_y = 0xFFFFFFFF; + int tl[2]; + int bl[2]; + int tr[2]; + int br[2]; + int left_cut_top[2]; + int left_cut_left[2]; + int left_cut_right[2]; + int left_cut_bottom[2]; + int right_cut_top[2]; + int right_cut_left[2]; + int right_cut_right[2]; + int right_cut_bottom[2]; + int tmp[2]; + int tmp_vtx[20*2]; + float tmp_vtx_slope[20]; + BoxRec trap_bound; + int i = 0; + int vertex_num = 0; + + if (DEBUG_CLIP_VTX) { + ErrorF("The parameter of xTrapezoid is:\ntop: %d 0x%x\tbottom: %d 0x%x\n" + "left: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n" + "right: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n", + xFixedToInt(trap->top), (unsigned int)trap->top, + xFixedToInt(trap->bottom), (unsigned int)trap->bottom, + xFixedToInt(trap->left.p1.x), (unsigned int)trap->left.p1.x, + xFixedToInt(trap->left.p1.y), (unsigned int)trap->left.p1.y, + xFixedToInt(trap->left.p2.x), (unsigned int)trap->left.p2.x, + xFixedToInt(trap->left.p2.y), (unsigned int)trap->left.p2.y, + xFixedToInt(trap->right.p1.x), (unsigned int)trap->right.p1.x, + xFixedToInt(trap->right.p1.y), (unsigned int)trap->right.p1.y, + xFixedToInt(trap->right.p2.x), (unsigned int)trap->right.p2.x, + xFixedToInt(trap->right.p2.y), (unsigned int)trap->right.p2.y); + } + + miTrapezoidBounds(1, trap, &trap_bound); + if (DEBUG_CLIP_VTX) + ErrorF("The bounds for this traps is: bounds.x1 = %d, bounds.x2 = %d, " + "bounds.y1 = %d, bounds.y2 = %d\n", trap_bound.x1, trap_bound.x2, + trap_bound.y1, trap_bound.y2); + + if (trap_bound.x1 > pbox->x2 || trap_bound.x2 < pbox->x1) + return FALSE; + if (trap_bound.y1 > pbox->y2 || trap_bound.y2 < pbox->y1) + return FALSE; + +#define IS_TRAP_EDGE_VERTICAL(edge) \ + (edge->p1.x == edge->p2.x) + +#define CACULATE_CUT_VERTEX(vtx, cal_x, ceil, vh_edge, edge) \ + do { \ + if(cal_x) { \ + vtx[1] = (vh_edge); \ + vtx[0] = (_glamor_linefixedX( \ + edge, vh_edge, ceil)); \ + if(DEBUG_CLIP_VTX) \ + ErrorF("The intersection point of line y=%d and " \ + "line of p1:(%d,%d) -- p2 (%d,%d) " \ + "is (%d, %d)\n", \ + xFixedToInt(vh_edge), \ + xFixedToInt(edge->p1.x), \ + xFixedToInt(edge->p1.y), \ + xFixedToInt(edge->p2.x), \ + xFixedToInt(edge->p2.y), \ + xFixedToInt(vtx[0]), \ + xFixedToInt(vtx[1])); \ + } else { \ + vtx[0] = (vh_edge); \ + vtx[1] = (_glamor_linefixedY( \ + edge, vh_edge, ceil)); \ + if(DEBUG_CLIP_VTX) \ + ErrorF("The intersection point of line x=%d and " \ + "line of p1:(%d,%d) -- p2 (%d,%d) " \ + "is (%d, %d)\n", \ + xFixedToInt(vh_edge), \ + xFixedToInt(edge->p1.x), \ + xFixedToInt(edge->p1.y), \ + xFixedToInt(edge->p2.x), \ + xFixedToInt(edge->p2.y), \ + xFixedToInt(vtx[0]), \ + xFixedToInt(vtx[1])); \ + } \ + } while(0) + +#define ADD_VERTEX_IF_INSIDE(vtx) \ + if(POINT_INSIDE_CLIP_RECT(vtx, pbox) \ + && point_inside_trapezoid(vtx, trap, edge_cross_y)){ \ + tmp_vtx[vertex_num] = xFixedToInt(vtx[0]); \ + tmp_vtx[vertex_num + 1] = xFixedToInt(vtx[1]); \ + vertex_num += 2; \ + if(DEBUG_CLIP_VTX) \ + ErrorF("@ Point: (%d, %d) is inside " \ + "the Rect and Trapezoid\n", \ + xFixedToInt(vtx[0]), \ + xFixedToInt(vtx[1])); \ + } else if(DEBUG_CLIP_VTX){ \ + ErrorF("X Point: (%d, %d) is outside " \ + "the Rect and Trapezoid\t", \ + xFixedToInt(vtx[0]), \ + xFixedToInt(vtx[1])); \ + if(POINT_INSIDE_CLIP_RECT(vtx, pbox)) \ + ErrorF("The Point is outside " \ + "the Trapezoid\n"); \ + else \ + ErrorF("The Point is outside " \ + "the Rect\n"); \ + } + + /*Trap's right edge cut right edge. */ + if((!IS_TRAP_EDGE_VERTICAL((&trap->left))) || + (!IS_TRAP_EDGE_VERTICAL((&trap->right)))) { + edge_cross_y = _glamor_lines_crossfixedY((&trap->left), (&trap->right)); + if (DEBUG_CLIP_VTX) { + ErrorF("Trap's left edge cut right edge at %d(0x%x), " + "trap_top = %x, trap_bottom = %x\n", + xFixedToInt(edge_cross_y), edge_cross_y, + (unsigned int)trap->top, (unsigned int)trap->bottom); + } + } + + /*Trap's TopLeft, BottomLeft, TopRight and BottomRight. */ + CACULATE_CUT_VERTEX(tl, 1, FALSE, trap->top, (&trap->left)); + CACULATE_CUT_VERTEX(bl, 1, FALSE, trap->bottom, (&trap->left)); + CACULATE_CUT_VERTEX(tr, 1, TRUE, trap->top, (&trap->right)); + CACULATE_CUT_VERTEX(br, 1, TRUE, trap->bottom, (&trap->right)); + + if (DEBUG_CLIP_VTX) + ErrorF("Trap's TopLeft, BottomLeft, TopRight and BottomRight\n"); + if (DEBUG_CLIP_VTX) + ErrorF("Caculate the vertex of trapezoid:\n" + " (%3d, %3d)-------------------------(%3d, %3d)\n" + " / \\ \n" + " / \\ \n" + " / \\ \n" + " (%3d, %3d)---------------------------------(%3d, %3d)\n" + "Clip with rect:\n" + " (%3d, %3d)------------------------(%3d, %3d) \n" + " | | \n" + " | | \n" + " | | \n" + " (%3d, %3d)------------------------(%3d, %3d) \n", + xFixedToInt(tl[0]), xFixedToInt(tl[1]), xFixedToInt(tr[0]), + xFixedToInt(tr[1]), xFixedToInt(bl[0]), xFixedToInt(bl[1]), + xFixedToInt(br[0]), xFixedToInt(br[1]), + pbox->x1, pbox->y1, pbox->x2, pbox->y1, pbox->x1, pbox->y2, + pbox->x2, pbox->y2); + + ADD_VERTEX_IF_INSIDE(tl); + ADD_VERTEX_IF_INSIDE(bl); + ADD_VERTEX_IF_INSIDE(tr); + ADD_VERTEX_IF_INSIDE(br); + + /*Trap's left edge cut Rect. */ + if (DEBUG_CLIP_VTX) + ErrorF("Trap's left edge cut Rect\n"); + CACULATE_CUT_VERTEX(left_cut_top, 1, FALSE, IntToxFixed(pbox->y1), (&trap->left)); + ADD_VERTEX_IF_INSIDE(left_cut_top); + if (!IS_TRAP_EDGE_VERTICAL((&trap->left))) { + CACULATE_CUT_VERTEX(left_cut_left, 0, FALSE, IntToxFixed(pbox->x1), (&trap->left)); + ADD_VERTEX_IF_INSIDE(left_cut_left); + } + CACULATE_CUT_VERTEX(left_cut_bottom, 1, FALSE, IntToxFixed(pbox->y2), (&trap->left)); + ADD_VERTEX_IF_INSIDE(left_cut_bottom); + if (!IS_TRAP_EDGE_VERTICAL((&trap->left))) { + CACULATE_CUT_VERTEX(left_cut_right, 0, FALSE, IntToxFixed(pbox->x2), (&trap->left)); + ADD_VERTEX_IF_INSIDE(left_cut_right); + } + + /*Trap's right edge cut Rect. */ + if (DEBUG_CLIP_VTX) + ErrorF("Trap's right edge cut Rect\n"); + CACULATE_CUT_VERTEX(right_cut_top, 1, TRUE, IntToxFixed(pbox->y1), (&trap->right)); + ADD_VERTEX_IF_INSIDE(right_cut_top); + if (!IS_TRAP_EDGE_VERTICAL((&trap->right))) { + CACULATE_CUT_VERTEX(right_cut_left, 0, TRUE, IntToxFixed(pbox->x1), (&trap->right)); + ADD_VERTEX_IF_INSIDE(right_cut_left); + } + CACULATE_CUT_VERTEX(right_cut_bottom, 1, TRUE, IntToxFixed(pbox->y2), (&trap->right)); + ADD_VERTEX_IF_INSIDE(right_cut_bottom); + if (!IS_TRAP_EDGE_VERTICAL((&trap->right))) { + CACULATE_CUT_VERTEX(right_cut_right, 0, TRUE, IntToxFixed(pbox->x2), (&trap->right)); + ADD_VERTEX_IF_INSIDE(right_cut_right); + } + + /* Trap's top cut Left and Right of rect. */ + if (DEBUG_CLIP_VTX) + ErrorF("Trap's top cut Left and Right of rect\n"); + tmp[0] = IntToxFixed(pbox->x1); + tmp[1] = trap->top; + ADD_VERTEX_IF_INSIDE(tmp); + tmp[0] = IntToxFixed(pbox->x2); + tmp[1] = trap->top; + ADD_VERTEX_IF_INSIDE(tmp); + + /* Trap's bottom cut Left and Right of rect. */ + if (DEBUG_CLIP_VTX) + ErrorF("Trap's bottom cut Left and Right of rect\n"); + tmp[0] = IntToxFixed(pbox->x1); + tmp[1] = trap->bottom; + ADD_VERTEX_IF_INSIDE(tmp); + tmp[0] = IntToxFixed(pbox->x2); + tmp[1] = trap->bottom; + ADD_VERTEX_IF_INSIDE(tmp); + + /* The orginal 4 vertex of rect. */ + if (DEBUG_CLIP_VTX) + ErrorF("The orginal 4 vertex of rect\n"); + tmp[0] = IntToxFixed(pbox->x1); + tmp[1] = IntToxFixed(pbox->y1); + ADD_VERTEX_IF_INSIDE(tmp); + tmp[0] = IntToxFixed(pbox->x1); + tmp[1] = IntToxFixed(pbox->y2); + ADD_VERTEX_IF_INSIDE(tmp); + tmp[0] = IntToxFixed(pbox->x2); + tmp[1] = IntToxFixed(pbox->y2); + ADD_VERTEX_IF_INSIDE(tmp); + tmp[0] = IntToxFixed(pbox->x2); + tmp[1] = IntToxFixed(pbox->y1); + ADD_VERTEX_IF_INSIDE(tmp); + + if (DEBUG_CLIP_VTX) { + ErrorF("\nThe candidate vertex number is %d\n", vertex_num / 2); + for (i = 0; i < vertex_num / 2; i++) { + ErrorF("(%d, %d) ", tmp_vtx[2*i], tmp_vtx[2*i + 1]); + } + ErrorF("\n"); + } + + /* Sort the vertex by X and then Y. */ + for (i = 0; i < vertex_num / 2; i++) { + int j; + for (j = 0; j < vertex_num / 2 - i - 1; j++) { + if (tmp_vtx[2*j] > tmp_vtx[2*(j+1)] + || (tmp_vtx[2*j] == tmp_vtx[2*(j+1)] + && tmp_vtx[2*j + 1] > tmp_vtx[2*(j+1) + 1])) { + tmp[0] = tmp_vtx[2*j]; + tmp[1] = tmp_vtx[2*j + 1]; + tmp_vtx[2*j] = tmp_vtx[2*(j+1)]; + tmp_vtx[2*j + 1] = tmp_vtx[2*(j+1) + 1]; + tmp_vtx[2*(j+1)] = tmp[0]; + tmp_vtx[2*(j+1) + 1] = tmp[1]; + } + } + + } + + if (DEBUG_CLIP_VTX) { + ErrorF("\nAfter sort vertex number is:\n"); + for (i = 0; i < vertex_num / 2; i++) { + ErrorF("(%d, %d) ", tmp_vtx[2*i], tmp_vtx[2*i + 1]); + } + ErrorF("\n"); + } + + memset(vertex, -1, 2*6); + *num = 0; + + for (i = 0; i < vertex_num / 2; i++) { + if (*num > 0 && vertex[2*(*num - 1)] == tmp_vtx[2*i] + && vertex[2*(*num - 1) + 1] == tmp_vtx[2*i + 1]) { + /*same vertex.*/ + if (DEBUG_CLIP_VTX) + ErrorF("X Point:(%d, %d) discard\n", + tmp_vtx[2*i], tmp_vtx[2*i + 1]); + continue; + } + + (*num)++; + if (*num > 6) { + if (DEBUG_CLIP_VTX) + FatalError("Trapezoid clip with Rect can never have vtx" + "number bigger than 6\n"); + else { + ErrorF("Trapezoid clip with Rect can never have vtx" + "number bigger than 6\n"); + *num = 6; + break; + } + } + + vertex[2*(*num - 1)] = tmp_vtx[2*i]; + vertex[2*(*num - 1) + 1] = tmp_vtx[2*i + 1]; + if (DEBUG_CLIP_VTX) + ErrorF("@ Point:(%d, %d) select, num now is %d\n", + tmp_vtx[2*i], tmp_vtx[2*i + 1], *num); + } + + /* Now we need to arrange the vtx in the polygon's counter-clockwise + order. We first select the left and top point as the start point and + sort every vtx by the slope from vtx to the start vtx. */ + for (i = 1; i < *num; i++) { + tmp_vtx_slope[i] = (vertex[2*i] != vertex[0] ? + (float)(vertex[2*i + 1] - vertex[1]) / (float)(vertex[2*i] - vertex[0]) + : (float)INT_MAX); + } + + if (DEBUG_CLIP_VTX) { + ErrorF("\nvtx number: %d, VTX and slope:\n", *num); + for (i = 0; i < *num; i++) { + ErrorF("(%d, %d):%f ", + vertex[2*i], vertex[2*i + 1], + tmp_vtx_slope[i]); + } + ErrorF("\n"); + } + + /* Sort the vertex by slope. */ + for (i = 0; i < *num - 1; i++) { + int j; + float tmp_slope; + for (j = 1; j < *num - i - 1; j++) { + if (tmp_vtx_slope[j] < tmp_vtx_slope[j + 1]) { + tmp_slope = tmp_vtx_slope[j]; + tmp_vtx_slope[j] = tmp_vtx_slope[j + 1]; + tmp_vtx_slope[j + 1] = tmp_slope; + tmp[0] = vertex[2*j]; + tmp[1] = vertex[2*j + 1]; + vertex[2*j] = vertex[2*(j+1)]; + vertex[2*j + 1] = vertex[2*(j+1) + 1]; + vertex[2*(j+1)] = tmp[0]; + vertex[2*(j+1) + 1] = tmp[1]; + } + } + } + + if (DEBUG_CLIP_VTX) { + ErrorF("\nBefore return, vtx number: %d, VTX and slope:\n", *num); + for (i = 0; i < *num; i++) { + ErrorF("(%d, %d):%f ", + vertex[2*i], vertex[2*i + 1], + tmp_vtx_slope[i]); + } + ErrorF("\n"); + } + + return TRUE; +} + +static void +glamor_setup_composite_vbo_for_trapezoid(ScreenPtr screen, int n_verts) +{ + glamor_screen_private *glamor_priv = + glamor_get_screen_private(screen); + glamor_gl_dispatch *dispatch; + int stride; + int vert_size; + + glamor_priv->render_nr_verts = 0; + + /* For GLAMOR_VERTEX_POS */ + glamor_priv->vb_stride = 2 * sizeof(float); + + /* For GLAMOR_GLAMOR_VERTEX_SOURCE */ + glamor_priv->vb_stride += 2 * sizeof(float); + + /* For GLAMOR_VERTEX_TOP_BOTTOM */ + glamor_priv->vb_stride += 2 * sizeof(float); + + /* For GLAMOR_VERTEX_LEFT_PARAM */ + glamor_priv->vb_stride += 4 * sizeof(float); + + /* For GLAMOR_VERTEX_RIGHT_PARAM */ + glamor_priv->vb_stride += 4 * sizeof(float); + + vert_size = n_verts * glamor_priv->vb_stride; + + dispatch = glamor_get_dispatch(glamor_priv); + + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_TOP_BOTTOM); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_LEFT_PARAM); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_RIGHT_PARAM); + + dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo); + if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) { + if (glamor_priv->vbo_size < (glamor_priv->vbo_offset + vert_size)) { + glamor_priv->vbo_size = GLAMOR_COMPOSITE_VBO_VERT_CNT * + glamor_priv->vb_stride; + glamor_priv->vbo_offset = 0; + dispatch->glBufferData(GL_ARRAY_BUFFER, + glamor_priv->vbo_size, + NULL, GL_STREAM_DRAW); + } + + glamor_priv->vb = dispatch->glMapBufferRange(GL_ARRAY_BUFFER, + glamor_priv->vbo_offset, + vert_size, + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + + assert(glamor_priv->vb != NULL); + glamor_priv->vb -= glamor_priv->vbo_offset; + } else { + glamor_priv->vbo_offset = 0; + } + + dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glamor_priv->ebo); + + /* Set the vertex pointer. */ + dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, + GL_FALSE, glamor_priv->vb_stride, + (void *) ((long)glamor_priv->vbo_offset)); + dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS); + stride = 2; + + dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT, + GL_FALSE, glamor_priv->vb_stride, + (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float))); + dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + stride += 2; + + dispatch->glVertexAttribPointer(GLAMOR_VERTEX_TOP_BOTTOM, 2, GL_FLOAT, + GL_FALSE, glamor_priv->vb_stride, + (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float))); + dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_TOP_BOTTOM); + stride += 2; + + dispatch->glVertexAttribPointer(GLAMOR_VERTEX_LEFT_PARAM, 4, GL_FLOAT, + GL_FALSE, glamor_priv->vb_stride, + (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float))); + dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_LEFT_PARAM); + stride += 4; + + dispatch->glVertexAttribPointer(GLAMOR_VERTEX_RIGHT_PARAM, 4, GL_FLOAT, + GL_FALSE, glamor_priv->vb_stride, + (void *) ((long)glamor_priv->vbo_offset + stride * sizeof(float))); + dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_RIGHT_PARAM); + + glamor_put_dispatch(glamor_priv); +} + +static Bool +_glamor_trapezoids_with_shader(CARD8 op, + PicturePtr src, PicturePtr dst, + PictFormatPtr mask_format, INT16 x_src, INT16 y_src, + int ntrap, xTrapezoid * traps) +{ + ScreenPtr screen = dst->pDrawable->pScreen; + glamor_screen_private *glamor_priv = glamor_get_screen_private(screen); + struct shader_key key; + glamor_composite_shader *shader = NULL; + struct blendinfo op_info; + PictFormatShort saved_source_format = 0; + PixmapPtr source_pixmap = NULL; + PixmapPtr dest_pixmap = NULL; + glamor_pixmap_private *source_pixmap_priv = NULL; + glamor_pixmap_private *dest_pixmap_priv = NULL; + glamor_pixmap_private *temp_src_priv = NULL; + int x_temp_src, y_temp_src; + int src_width, src_height; + int source_x_off, source_y_off; + GLfloat src_xscale = 1, src_yscale = 1; + int x_dst, y_dst; + int dest_x_off, dest_y_off; + GLfloat dst_xscale, dst_yscale; + BoxRec bounds; + PicturePtr temp_src = src; + glamor_gl_dispatch *dispatch = NULL; + int vert_stride = 3; + int ntriangle_per_loop; + int nclip_rect; + int mclip_rect; + int clip_processed; + int clipped_vtx[6*2]; + RegionRec region; + BoxPtr box = NULL; + BoxPtr pbox = NULL; + int traps_count = 0; + int traps_not_completed = 0; + xTrapezoid * ptrap = NULL; + int nbox; + float src_matrix[9]; + Bool ret = FALSE; + + /* If a mask format wasn't provided, we get to choose, but behavior should + * be as if there was no temporary mask the traps were accumulated into. + */ + if (!mask_format) { + if (dst->polyEdge == PolyEdgeSharp) + mask_format = PictureMatchFormat(screen, 1, PICT_a1); + else + mask_format = PictureMatchFormat(screen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + glamor_trapezoids(op, src, dst, mask_format, x_src, + y_src, 1, traps); + return TRUE; + } + + miTrapezoidBounds(ntrap, traps, &bounds); + DEBUGF("The bounds for all traps is: bounds.x1 = %d, bounds.x2 = %d, " + "bounds.y1 = %d, bounds.y2 = %d\n", bounds.x1, bounds.x2, + bounds.y1, bounds.y2); + + /* No area need to render. */ + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return TRUE; + + dest_pixmap = glamor_get_drawable_pixmap(dst->pDrawable); + dest_pixmap_priv = glamor_get_pixmap_private(dest_pixmap); + + if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(dest_pixmap_priv) + || dest_pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { + /* Currently. Always fallback to cpu if destination is in CPU memory.*/ + ret = FALSE; + DEBUGF("dst pixmap has no FBO.\n"); + goto TRAPEZOID_OUT; + } + + if (src->pDrawable) { + source_pixmap = glamor_get_drawable_pixmap(src->pDrawable); + source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); + temp_src_priv = source_pixmap_priv; + if (source_pixmap_priv + && (source_pixmap_priv->type == GLAMOR_DRM_ONLY + || source_pixmap_priv->type == GLAMOR_TEXTURE_LARGE)) { + ret = FALSE; + goto TRAPEZOID_OUT; + } + } + + x_dst = bounds.x1; + y_dst = bounds.y1; + + src_width = bounds.x2 - bounds.x1; + src_height = bounds.y2 - bounds.y1; + + x_temp_src = x_src + bounds.x1 - (traps[0].left.p1.x >> 16); + y_temp_src = y_src + bounds.y1 - (traps[0].left.p1.y >> 16); + + if ((!src->pDrawable && + (src->pSourcePict->type != SourcePictTypeSolidFill)) //1. The Gradient case. + /* 2. Has no fbo but can upload.*/ + || (src->pDrawable && !GLAMOR_PIXMAP_PRIV_HAS_FBO(source_pixmap_priv) + && ((src_width * src_height * 4 < + source_pixmap->drawable.width * source_pixmap->drawable.height) + || !glamor_check_fbo_size(glamor_priv, source_pixmap->drawable.width, + source_pixmap->drawable.height)))) { + + if (!glamor_check_fbo_size(glamor_priv, src_width, src_height)) { + ret = FALSE; + goto TRAPEZOID_OUT; + } + temp_src = glamor_convert_gradient_picture(screen, src, + x_src, y_src, + src_width, src_height); + if (!temp_src) { + temp_src = src; + ret = FALSE; + DEBUGF("Convert gradient picture failed\n"); + goto TRAPEZOID_OUT; + } + temp_src_priv = glamor_get_pixmap_private((PixmapPtr)temp_src->pDrawable); + x_temp_src = y_temp_src = 0; + } + + x_dst += dst->pDrawable->x; + y_dst += dst->pDrawable->y; + if (temp_src->pDrawable) { + x_temp_src += temp_src->pDrawable->x; + y_temp_src += temp_src->pDrawable->y; + } + + if (!miComputeCompositeRegion(®ion, + temp_src, NULL, dst, + x_temp_src, y_temp_src, + 0, 0, + x_dst, y_dst, + src_width, src_height)) { + DEBUGF("All the regions are clipped out, do nothing\n"); + goto TRAPEZOID_OUT; + } + + box = REGION_RECTS(®ion); + nbox = REGION_NUM_RECTS(®ion); + pbox = box; + + ret = glamor_composite_choose_shader(op, temp_src, NULL, dst, + temp_src_priv, NULL, dest_pixmap_priv, + &key, &shader, &op_info, &saved_source_format); + if (ret == FALSE) { + DEBUGF("can not set the shader program for composite\n"); + goto TRAPEZOID_RESET_GL; + } + glamor_set_destination_pixmap_priv_nc(dest_pixmap_priv); + glamor_composite_set_shader_blend(dest_pixmap_priv, &key, shader, &op_info); + glamor_priv->has_source_coords = key.source != SHADER_SOURCE_SOLID; + glamor_priv->has_mask_coords = (key.mask != SHADER_MASK_NONE && + key.mask != SHADER_MASK_SOLID); + + dispatch = glamor_get_dispatch(glamor_priv); + + glamor_get_drawable_deltas(dst->pDrawable, dest_pixmap, + &dest_x_off, &dest_y_off); + + pixmap_priv_get_dest_scale(dest_pixmap_priv, &dst_xscale, &dst_yscale); + + if (glamor_priv->has_source_coords) { + source_pixmap = glamor_get_drawable_pixmap(temp_src->pDrawable); + source_pixmap_priv = glamor_get_pixmap_private(source_pixmap); + glamor_get_drawable_deltas(temp_src->pDrawable, + source_pixmap, + &source_x_off, &source_y_off); + pixmap_priv_get_scale(source_pixmap_priv, + &src_xscale, &src_yscale); + glamor_picture_get_matrixf(temp_src, src_matrix); + vert_stride += 3; + } + + if (glamor_priv->has_mask_coords) { + DEBUGF("Should never have mask coords here!\n"); + ret = FALSE; + goto TRAPEZOID_RESET_GL; + } + + /* A trapezoid clip with a rectangle will at most generate a hexagon, + which can be devided into 4 triangles to render. */ + ntriangle_per_loop = (vert_stride * nbox * ntrap * 4) > GLAMOR_COMPOSITE_VBO_VERT_CNT ? + (GLAMOR_COMPOSITE_VBO_VERT_CNT / vert_stride) : nbox * ntrap * 4; + ntriangle_per_loop = (ntriangle_per_loop / 4) * 4; + + nclip_rect = nbox; + while (nclip_rect) { + mclip_rect = (nclip_rect * ntrap * 4) > ntriangle_per_loop ? + (ntriangle_per_loop / (4 * ntrap)) : nclip_rect; + + if (!mclip_rect) {/* Maybe too many traps. */ + mclip_rect = 1; + ptrap = traps; + traps_count = ntriangle_per_loop / 4; + traps_not_completed = ntrap - traps_count; + } else { + traps_count = ntrap; + ptrap = traps; + traps_not_completed = 0; + } + +NTRAPS_LOOP_AGAIN: + + glamor_setup_composite_vbo(screen, mclip_rect * traps_count * 4 * vert_stride); + clip_processed = mclip_rect; + + + while (mclip_rect--) { + while (traps_count--) { + int vtx_num; + int i; + float vertices[3*2], source_texcoords[3*2]; + + DEBUGF("In loop of render trapezoid, nclip_rect = %d, mclip_rect = %d, " + "clip_processed = %d, traps_count = %d, traps_not_completed = %d\n", + nclip_rect, mclip_rect, clip_processed, traps_count, traps_not_completed); + + if (_glamor_clip_trapezoid_vertex(ptrap, pbox, clipped_vtx, &vtx_num)) { + for (i = 0; i < vtx_num - 2; i++) { + int clipped_vtx_tmp[3*2]; + + clipped_vtx_tmp[0] = clipped_vtx[0]; + clipped_vtx_tmp[1] = clipped_vtx[1]; + clipped_vtx_tmp[2] = clipped_vtx[(i+1)*2]; + clipped_vtx_tmp[3] = clipped_vtx[(i+1)*2 + 1]; + clipped_vtx_tmp[4] = clipped_vtx[(i+2)*2]; + clipped_vtx_tmp[5] = clipped_vtx[(i+2)*2 + 1]; + glamor_set_normalize_tri_vcoords( + dst_xscale, dst_yscale, clipped_vtx_tmp, + glamor_priv->yInverted, vertices); + DEBUGF("vertices of triangle: (%f X %f), (%f X %f), " + "(%f X %f)\n", vertices[0], vertices[1], + vertices[2], vertices[3], vertices[4], vertices[5]); + + + if (key.source != SHADER_SOURCE_SOLID) { + if (src->transform) { + glamor_set_transformed_normalize_tri_tcoords( + source_pixmap_priv, + src_matrix, src_xscale, src_yscale, + clipped_vtx_tmp, + glamor_priv->yInverted, + source_texcoords); + } else { + glamor_set_normalize_tri_tcoords( + src_xscale, src_yscale, + clipped_vtx_tmp, + glamor_priv->yInverted, + source_texcoords); + } + + DEBUGF("source_texcoords of triangle: (%f X %f), " + "(%f X %f), (%f X %f)\n", + source_texcoords[0], source_texcoords[1], + source_texcoords[2], source_texcoords[3], + source_texcoords[4], source_texcoords[5]); + } + + glamor_emit_composite_triangle(screen, source_texcoords, + NULL, vertices); + } + } + + ptrap++; + } + + if (traps_not_completed) { /* one loop of ntraps not completed */ + mclip_rect = 1; + traps_count = traps_not_completed > (ntriangle_per_loop / 4) ? + (ntriangle_per_loop / 4) : traps_not_completed; + traps_not_completed -= traps_count; + glamor_flush_composite_triangles(screen); + goto NTRAPS_LOOP_AGAIN; + } else { + ptrap = traps; + traps_count = ntrap; + } + + pbox++; + } + + glamor_flush_composite_triangles(screen); + + nclip_rect -= clip_processed; + } + + ret = TRUE; + +TRAPEZOID_RESET_GL: + dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0); + dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_MASK); + dispatch->glDisable(GL_BLEND); +#ifndef GLAMOR_GLES2 + dispatch->glActiveTexture(GL_TEXTURE0); + dispatch->glDisable(GL_TEXTURE_2D); + dispatch->glActiveTexture(GL_TEXTURE1); + dispatch->glDisable(GL_TEXTURE_2D); +#endif + dispatch->glUseProgram(0); + +TRAPEZOID_OUT: + if (box) { + REGION_UNINIT(dst->pDrawable->pScreen, ®ion); + } + + if (temp_src != src) { + FreePicture(temp_src, 0); + } else { + if (saved_source_format) { + src->format = saved_source_format; + } + } + + if (dispatch) { + glamor_put_dispatch(glamor_priv); + } + + return ret; +} + +void +glamor_init_trapezoid_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + GLint fs_prog, vs_prog; + + const char *trapezoid_vs = + GLAMOR_DEFAULT_PRECISION + "attribute vec4 v_position;\n" + "attribute vec2 v_texcoord;\n" + /* v_top_bottom, v_left_param and v_right_param contain the + constant value for all the vertex of one rect. Using uniform + is more suitable but we need to reset the uniform variables + for every rect rendering and can not use the vbo, which causes + performance loss. So we set these attributes to same value + for every vertex of one rect and so it is also a constant in FS */ + "attribute vec2 v_top_bottom;\n" + "attribute vec4 v_left_param;\n" + "attribute vec4 v_right_param;\n" + "\n" + "varying vec2 source_texture;\n" + "varying float trap_top;\n" + "varying float trap_bottom;\n" + "varying float trap_left_x;\n" + "varying float trap_left_y;\n" + "varying float trap_left_slope;\n" + "varying float trap_left_vertical_f;\n" + "varying float trap_right_x;\n" + "varying float trap_right_y;\n" + "varying float trap_right_slope;\n" + "varying float trap_right_vertical_f;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = v_position;\n" + " source_texture = v_texcoord.xy;\n" + " trap_top = v_top_bottom.x;\n" + " trap_bottom = v_top_bottom.y;\n" + " \n" + " trap_left_x = v_left_param.x;\n" + " trap_left_y = v_left_param.y;\n" + " trap_left_slope = v_left_param.z;\n" + " trap_left_vertical_f = v_left_param.w;\n" + " \n" + " trap_right_x = v_right_param.x;\n" + " trap_right_y = v_right_param.y;\n" + " trap_right_slope = v_right_param.z;\n" + " trap_right_vertical_f = v_right_param.w;\n" + "}\n"; + + /* + * Because some GL fill function do not support the MultSample + * anti-alias, we need to do the MSAA here. This manner like + * pixman, will caculate the value of area in trapezoid dividing + * the totol area for each pixel, as follow: + | + ----+------------------------------------------------------> + | + | ------------- + | / \ + | / \ + | / \ + | / +----------------+ + | / |.....\ | + | / |......\ | + | / |.......\ | + | / |........\ | + | /-------------------+---------\ | + | | | + | | | + | +----------------+ + | + \|/ + + */ + const char *trapezoid_fs = + GLAMOR_DEFAULT_PRECISION + "varying vec2 source_texture; \n" + "varying float trap_top; \n" + "varying float trap_bottom; \n" + "varying float trap_left_x; \n" + "varying float trap_left_y; \n" + "varying float trap_left_slope; \n" + "varying float trap_left_vertical_f; \n" + "varying float trap_right_x; \n" + "varying float trap_right_y; \n" + "varying float trap_right_slope; \n" + "varying float trap_right_vertical_f; \n" + "float x_per_pix = 1.0;" + "float y_per_pix = 1.0;" + "\n" + "float get_alpha_val() \n" + "{ \n" + " float x_up_cut_left; \n" + " float x_bottom_cut_left; \n" + " float x_up_cut_right; \n" + " float x_bottom_cut_right; \n" + " bool trap_left_vertical;\n" + " bool trap_right_vertical;\n" + " if (abs(trap_left_vertical_f - 1.0) <= 0.0001)\n" + " trap_left_vertical = true;\n" + " else\n" + " trap_left_vertical = false;\n" + " if (abs(trap_right_vertical_f - 1.0) <= 0.0001)\n" + " trap_right_vertical = true;\n" + " else\n" + " trap_right_vertical = false;\n" + " \n" + " if(trap_left_vertical == true) { \n" + " x_up_cut_left = trap_left_x; \n" + " x_bottom_cut_left = trap_left_x; \n" + " } else { \n" + " x_up_cut_left = trap_left_x \n" + " + (source_texture.y - y_per_pix/2.0 - trap_left_y) \n" + " / trap_left_slope; \n" + " x_bottom_cut_left = trap_left_x \n" + " + (source_texture.y + y_per_pix/2.0 - trap_left_y) \n" + " / trap_left_slope; \n" + " } \n" + " \n" + " if(trap_right_vertical == true) { \n" + " x_up_cut_right = trap_right_x; \n" + " x_bottom_cut_right = trap_right_x; \n" + " } else { \n" + " x_up_cut_right = trap_right_x \n" + " + (source_texture.y - y_per_pix/2.0 - trap_right_y) \n" + " / trap_right_slope; \n" + " x_bottom_cut_right = trap_right_x \n" + " + (source_texture.y + y_per_pix/2.0 - trap_right_y) \n" + " / trap_right_slope; \n" + " } \n" + " \n" + " if((x_up_cut_left <= source_texture.x - x_per_pix/2.0) && \n" + " (x_bottom_cut_left <= source_texture.x - x_per_pix/2.0) && \n" + " (x_up_cut_right >= source_texture.x + x_per_pix/2.0) && \n" + " (x_bottom_cut_right >= source_texture.x + x_per_pix/2.0) && \n" + " (trap_top <= source_texture.y - y_per_pix/2.0) && \n" + " (trap_bottom >= source_texture.y + y_per_pix/2.0)) { \n" + // The complete inside case. + " return 1.0; \n" + " } else if((trap_top > source_texture.y + y_per_pix/2.0) || \n" + " (trap_bottom < source_texture.y - y_per_pix/2.0)) { \n" + // The complete outside. Above the top or Below the bottom. + " return 0.0; \n" + " } else { \n" + " if((x_up_cut_right < source_texture.x - x_per_pix/2.0 && \n" + " x_bottom_cut_right < source_texture.x - x_per_pix/2.0) \n" + " || (x_up_cut_left > source_texture.x + x_per_pix/2.0 && \n" + " x_bottom_cut_left > source_texture.x + x_per_pix/2.0)) { \n" + // The complete outside. At Left or Right of the trapezoide. + " return 0.0; \n" + " } \n" + " } \n" + // Get here, the pix is partly inside the trapezoid. + " { \n" + " float percent = 0.0; \n" + " float up = (source_texture.y - y_per_pix/2.0) >= trap_top ? \n" + " (source_texture.y - y_per_pix/2.0) : trap_top; \n" + " float bottom = (source_texture.y + y_per_pix/2.0) <= trap_bottom ? \n" + " (source_texture.y + y_per_pix/2.0) : trap_bottom; \n" + " float left = source_texture.x - x_per_pix/2.0; \n" + " float right = source_texture.x + x_per_pix/2.0; \n" + " \n" + " percent = (bottom - up) / y_per_pix; \n" + " \n" + " if(trap_left_vertical == true) { \n" + " if(trap_left_x > source_texture.x - x_per_pix/2.0 && \n" + " trap_left_x < source_texture.x + x_per_pix/2.0) \n" + " left = trap_left_x; \n" + " } \n" + " if(trap_right_vertical == true) { \n" + " if(trap_right_x > source_texture.x - x_per_pix/2.0 && \n" + " trap_right_x < source_texture.x + x_per_pix/2.0) \n" + " right = trap_right_x; \n" + " } \n" + " if((up >= bottom) || (left >= right)) \n" + " return 0.0; \n" + " \n" + " percent = percent * ((right - left)/x_per_pix); \n" + " if(trap_left_vertical == true && trap_right_vertical == true) \n" + " return percent; \n" + " \n" + " if(trap_left_vertical != true) { \n" + " float area; \n" + // the slope should never be 0.0 here + " float up_x = trap_left_x + (up - trap_left_y)/trap_left_slope; \n" + " float bottom_x = trap_left_x + (bottom - trap_left_y)/trap_left_slope; \n" + " if(trap_left_slope < 0.0 && up_x > left) { \n" + /* case 1 + | + ----+-------------------------------------> + | / + | / + | +---/--------+ + | | /.........| + | | /..........| + | |/...........| + | /............| + | /|............| + | +------------+ + | + \|/ + */ + " float left_y = trap_left_y + trap_left_slope*(left - trap_left_x); \n" + " if((up_x > left) && (left_y > up)) { \n" + " area = 0.5 * (up_x - left) * (left_y - up); \n" + " if(up_x > right) { \n" + " float right_y = trap_left_y \n" + " + trap_left_slope*(right - trap_left_x); \n" + " area = area - 0.5 * (up_x - right) * (right_y - up); \n" + " } \n" + " if(left_y > bottom) { \n" + " area = area - 0.5 * (bottom_x - left) * (left_y - bottom); \n" + " } \n" + " } else { \n" + " area = 0.0; \n" + " } \n" + " percent = percent * (1.0 - (area/((right-left)*(bottom-up)))); \n" + " } else if(trap_left_slope > 0.0 && bottom_x > left) { \n" + /* case 2 + | + ----+-------------------------------------> + | \ + | \ + | +\-----------+ + | | \..........| + | | \.........| + | | \........| + | | \.......| + | | \......| + | +------\-----+ + | \ + | \ + \|/ + */ + " float right_y = trap_left_y + trap_left_slope*(right - trap_left_x); \n" + " if((up_x < right) && (right_y > up)) { \n" + " area = 0.5 * (right - up_x) * (right_y - up); \n" + " if(up_x < left) { \n" + " float left_y = trap_left_y \n" + " + trap_left_slope*(left - trap_left_x); \n" + " area = area - 0.5 * (left - up_x) * (left_y - up); \n" + " } \n" + " if(right_y > bottom) { \n" + " area = area - 0.5 * (right - bottom_x) * (right_y - bottom); \n" + " } \n" + " } else { \n" + " area = 0.0; \n" + " } \n" + " percent = percent * (area/((right-left)*(bottom-up))); \n" + " } \n" + " } \n" + " \n" + " if(trap_right_vertical != true) { \n" + " float area; \n" + // the slope should never be 0.0 here + " float up_x = trap_right_x + (up - trap_right_y)/trap_right_slope; \n" + " float bottom_x = trap_right_x + (bottom - trap_right_y)/trap_right_slope; \n" + " if(trap_right_slope < 0.0 && bottom_x < right) { \n" + /* case 3 + | + ----+-------------------------------------> + | / + | +--------/---+ + | |......./ | + | |....../ | + | |...../ | + | |..../ | + | |.../ | + | +--/---------+ + | / + | + \|/ + */ + " float left_y = trap_right_y + trap_right_slope*(left - trap_right_x); \n" + " if((up_x > left) && (left_y > up)) { \n" + " area = 0.5 * (up_x - left) * (left_y - up); \n" + " if(up_x > right) { \n" + " float right_y = trap_right_y \n" + " + trap_right_slope*(right - trap_right_x); \n" + " area = area - 0.5 * (up_x - right) * (right_y - up); \n" + " } \n" + " if(left_y > bottom) { \n" + " area = area - 0.5 * (bottom_x - left) * (left_y - bottom); \n" + " } \n" + " } else { \n" + " area = 0.0; \n" + " } \n" + " percent = percent * (area/((right-left)*(bottom-up))); \n" + " } else if(trap_right_slope > 0.0 && up_x < right) { \n" + /* case 4 + | + ----+-------------------------------------> + | \ + | +--------\---+ + | |.........\ | + | |..........\ | + | |...........\| + | |............\ + | |............|\ + | +------------+ \ + | \ + | + \|/ + */ + " float right_y = trap_right_y + trap_right_slope*(right - trap_right_x); \n" + " if((up_x < right) && (right_y > up)) { \n" + " area = 0.5 * (right - up_x) * (right_y - up); \n" + " if(up_x < left) { \n" + " float left_y = trap_right_y \n" + " + trap_right_slope*(left - trap_right_x); \n" + " area = area - 0.5 * (left - up_x) * (left_y - up); \n" + " } \n" + " if(right_y > bottom) { \n" + " area = area - 0.5 * (right - bottom_x) * (right_y - bottom); \n" + " } \n" + " } else { \n" + " area = 0.0; \n" + " } \n" + " percent = percent * (1.0 - (area/((right-left)*(bottom-up)))); \n" + " } \n" + " } \n" + " \n" + " return percent; \n" + " } \n" + "} \n" + "\n" + "void main() \n" + "{ \n" + " float alpha_val = get_alpha_val(); \n" + " gl_FragColor = vec4(0.0, 0.0, 0.0, alpha_val); \n" + "}\n"; + + glamor_priv = glamor_get_screen_private(screen); + dispatch = glamor_get_dispatch(glamor_priv); + + glamor_priv->trapezoid_prog = dispatch->glCreateProgram(); + + vs_prog = glamor_compile_glsl_prog(dispatch, + GL_VERTEX_SHADER, trapezoid_vs); + fs_prog = glamor_compile_glsl_prog(dispatch, + GL_FRAGMENT_SHADER, trapezoid_fs); + + dispatch->glAttachShader(glamor_priv->trapezoid_prog, vs_prog); + dispatch->glAttachShader(glamor_priv->trapezoid_prog, fs_prog); + + dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog, + GLAMOR_VERTEX_POS, "v_positionsition"); + dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog, + GLAMOR_VERTEX_SOURCE, "v_texcoord"); + dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog, + GLAMOR_VERTEX_TOP_BOTTOM, "v_top_bottom"); + dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog, + GLAMOR_VERTEX_LEFT_PARAM, "v_left_param"); + dispatch->glBindAttribLocation(glamor_priv->trapezoid_prog, + GLAMOR_VERTEX_RIGHT_PARAM, "v_right_param"); + + glamor_link_glsl_prog(dispatch, glamor_priv->trapezoid_prog); + + dispatch->glUseProgram(0); + + glamor_put_dispatch(glamor_priv); +} + +void +glamor_fini_trapezoid_shader(ScreenPtr screen) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + + glamor_priv = glamor_get_screen_private(screen); + dispatch = glamor_get_dispatch(glamor_priv); + dispatch->glDeleteProgram(glamor_priv->trapezoid_prog); + glamor_put_dispatch(glamor_priv); +} + +static Bool +_glamor_generate_trapezoid_with_shader(ScreenPtr screen, PicturePtr picture, + xTrapezoid * traps, int ntrap, BoxRec *bounds) +{ + glamor_screen_private *glamor_priv; + glamor_gl_dispatch *dispatch; + glamor_pixmap_private *pixmap_priv; + PixmapPtr pixmap = NULL; + GLint trapezoid_prog; + GLfloat xscale, yscale; + float left_slope, right_slope; + xTrapezoid *ptrap; + BoxRec one_trap_bound; + int nrect_max; + int i, j; + float *vertices; + float params[4]; + + glamor_priv = glamor_get_screen_private(screen); + trapezoid_prog = glamor_priv->trapezoid_prog; + + pixmap = glamor_get_drawable_pixmap(picture->pDrawable); + pixmap_priv = glamor_get_pixmap_private(pixmap); + + if (!GLAMOR_PIXMAP_PRIV_HAS_FBO(pixmap_priv) + || pixmap_priv->type == GLAMOR_TEXTURE_LARGE) { /* should always have here. */ + DEBUGF("GLAMOR_PIXMAP_PRIV_HAS_FBO check failed, fallback\n"); + return FALSE; + } + + /* First, clear all to zero */ + if (!glamor_solid(pixmap, 0, 0, pixmap_priv->base.pixmap->drawable.width, + pixmap_priv->base.pixmap->drawable.height, + GXclear, 0xFFFFFFFF, 0)) { + DEBUGF("glamor_solid failed, fallback\n"); + return FALSE; + } + + dispatch = glamor_get_dispatch(glamor_priv); + + glamor_set_destination_pixmap_priv_nc(pixmap_priv); + + pixmap_priv_get_dest_scale(pixmap_priv, (&xscale), (&yscale)); + + dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0); + dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + /* Now draw the Trapezoid mask. */ + dispatch->glUseProgram(trapezoid_prog); + + dispatch->glEnable(GL_BLEND); + dispatch->glBlendFunc(GL_ONE, GL_ONE); + + nrect_max = GLAMOR_COMPOSITE_VBO_VERT_CNT / (4 * GLAMOR_VERTEX_RIGHT_PARAM); + + for (i = 0; i < ntrap;) { + int mrect; + int stride; + + mrect = (ntrap - i) > nrect_max ? nrect_max : (ntrap - i); + glamor_setup_composite_vbo_for_trapezoid(screen, 4 * mrect); + stride = glamor_priv->vb_stride / sizeof(float); + + for (j = 0; j < mrect; j++) { + ptrap = traps + i + j; + + DEBUGF("--- The parameter of xTrapezoid is:\ntop: %d 0x%x\tbottom: %d 0x%x\n" + "left: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n" + "right: p1 (%d 0x%x, %d 0x%x)\tp2 (%d 0x%x, %d 0x%x)\n", + xFixedToInt(ptrap->top), ptrap->top, + xFixedToInt(ptrap->bottom), ptrap->bottom, + xFixedToInt(ptrap->left.p1.x), ptrap->left.p1.x, + xFixedToInt(ptrap->left.p1.y), ptrap->left.p1.y, + xFixedToInt(ptrap->left.p2.x), ptrap->left.p2.x, + xFixedToInt(ptrap->left.p2.y), ptrap->left.p2.y, + xFixedToInt(ptrap->right.p1.x), ptrap->right.p1.x, + xFixedToInt(ptrap->right.p1.y), ptrap->right.p1.y, + xFixedToInt(ptrap->right.p2.x), ptrap->right.p2.x, + xFixedToInt(ptrap->right.p2.y), ptrap->right.p2.y); + + miTrapezoidBounds(1, ptrap, &one_trap_bound); + + vertices = (float*)(glamor_priv->vb + glamor_priv->vbo_offset) + 2; + glamor_set_tcoords_ext((pixmap_priv->base.pixmap->drawable.width), + (pixmap_priv->base.pixmap->drawable.height), + (one_trap_bound.x1), + (one_trap_bound.y1), + (one_trap_bound.x2), + (one_trap_bound.y2), + glamor_priv->yInverted, vertices, stride); + DEBUGF("tex_vertices --> leftup : %f X %f, rightup: %f X %f," + "rightbottom: %f X %f, leftbottom : %f X %f\n", + vertices[0], vertices[1], + vertices[1*stride], vertices[1*stride + 1], + vertices[2*stride], vertices[2*stride + 1], + vertices[3*stride], vertices[3*stride + 1]); + + /* Need to rebase. */ + one_trap_bound.x1 -= bounds->x1; + one_trap_bound.x2 -= bounds->x1; + one_trap_bound.y1 -= bounds->y1; + one_trap_bound.y2 -= bounds->y1; + + vertices -= 2; + + glamor_set_normalize_vcoords_ext(pixmap_priv, xscale, yscale, + one_trap_bound.x1, one_trap_bound.y1, + one_trap_bound.x2, one_trap_bound.y2, + glamor_priv->yInverted, vertices, stride); + DEBUGF("vertices --> leftup : %f X %f, rightup: %f X %f," + "rightbottom: %f X %f, leftbottom : %f X %f\n", + vertices[0], vertices[1], + vertices[1*stride], vertices[1*stride + 1], + vertices[2*stride], vertices[2*stride + 1], + vertices[3*stride], vertices[3*stride + 1]); + vertices += 4; + + /* Set the top and bottom. */ + params[0] = ((float)ptrap->top) / 65536; + params[1] = ((float)ptrap->bottom) / 65536; + glamor_set_const_ext(params, 2, vertices, 4, stride); + vertices += 2; + + /* Set the left params. */ + params[0] = ((float)ptrap->left.p1.x) / 65536; + params[1] = ((float)ptrap->left.p1.y) / 65536; + + if (ptrap->left.p1.x == ptrap->left.p2.x) { + left_slope = 0.0; + params[3] = 1.0; + } else { + left_slope = ((float)(ptrap->left.p1.y - ptrap->left.p2.y)) + / ((float)(ptrap->left.p1.x - ptrap->left.p2.x)); + params[3] = 0.0; + } + params[2] = left_slope; + glamor_set_const_ext(params, 4, vertices, 4, stride); + vertices += 4; + + /* Set the left params. */ + params[0] = ((float)ptrap->right.p1.x) / 65536; + params[1] = ((float)ptrap->right.p1.y) / 65536; + + if (ptrap->right.p1.x == ptrap->right.p2.x) { + right_slope = 0.0; + params[3] = 1.0; + } else { + right_slope = ((float)(ptrap->right.p1.y - ptrap->right.p2.y)) + / ((float)(ptrap->right.p1.x - ptrap->right.p2.x)); + params[3] = 0.0; + } + params[2] = right_slope; + glamor_set_const_ext(params, 4, vertices, 4, stride); + + DEBUGF("trap_top = %f, trap_bottom = %f, " + "trap_left_x = %f, trap_left_y = %f, left_slope = %f, " + "trap_right_x = %f, trap_right_y = %f, right_slope = %f\n", + ((float)ptrap->top) / 65536, ((float)ptrap->bottom) / 65536, + ((float)ptrap->left.p1.x) / 65536, ((float)ptrap->left.p1.y) / 65536, + left_slope, + ((float)ptrap->right.p1.x) / 65536, ((float)ptrap->right.p1.y) / 65536, + right_slope); + + glamor_priv->render_nr_verts += 4; + glamor_priv->vbo_offset += glamor_priv->vb_stride * 4; + } + + i += mrect; + + /* Now rendering. */ + if (!glamor_priv->render_nr_verts) + continue; + + if (glamor_priv->gl_flavor == GLAMOR_GL_DESKTOP) + dispatch->glUnmapBuffer(GL_ARRAY_BUFFER); + else { + dispatch->glBindBuffer(GL_ARRAY_BUFFER, glamor_priv->vbo); + dispatch->glBufferData(GL_ARRAY_BUFFER, + glamor_priv->vbo_offset, + glamor_priv->vb, GL_DYNAMIC_DRAW); + } + +#ifndef GLAMOR_GLES2 + dispatch->glDrawRangeElements(GL_TRIANGLES, 0, glamor_priv->render_nr_verts, + (glamor_priv->render_nr_verts * 3) / 2, + GL_UNSIGNED_SHORT, NULL); +#else + dispatch->glDrawElements(GL_TRIANGLES, (glamor_priv->render_nr_verts * 3) / 2, + GL_UNSIGNED_SHORT, NULL); +#endif + } + + dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0); + dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + dispatch->glBlendFunc(GL_ONE, GL_ZERO); + dispatch->glDisable(GL_BLEND); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_TOP_BOTTOM); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_LEFT_PARAM); + dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_RIGHT_PARAM); + dispatch->glUseProgram(0); + glamor_put_dispatch(glamor_priv); + return TRUE; +} + +#endif /*GLAMOR_TRAPEZOID_SHADER */ + +/** + * Creates an appropriate picture for temp mask use. + */ +static PicturePtr +glamor_create_mask_picture(ScreenPtr screen, + PicturePtr dst, + PictFormatPtr pict_format, + CARD16 width, CARD16 height, int gpu) +{ + PixmapPtr pixmap; + PicturePtr picture; + int error; + + if (!pict_format) { + if (dst->polyEdge == PolyEdgeSharp) + pict_format = + PictureMatchFormat(screen, 1, PICT_a1); + else + pict_format = + PictureMatchFormat(screen, 8, PICT_a8); + if (!pict_format) + return 0; + } + + if (gpu) { + pixmap = glamor_create_pixmap(screen, width, height, + pict_format->depth, 0); + } else { + pixmap = glamor_create_pixmap(screen, 0, 0, + pict_format->depth, + GLAMOR_CREATE_PIXMAP_CPU); + } + + if (!pixmap) + return 0; + picture = CreatePicture(0, &pixmap->drawable, pict_format, + 0, 0, serverClient, &error); + glamor_destroy_pixmap(pixmap); + return picture; +} + +static int +_glamor_trapezoid_bounds (int ntrap, xTrapezoid *traps, BoxPtr box) +{ + int has_large_trapezoid = 0; + box->y1 = MAXSHORT; + box->y2 = MINSHORT; + box->x1 = MAXSHORT; + box->x2 = MINSHORT; + + for (; ntrap; ntrap--, traps++) { + INT16 x1, y1, x2, y2; + + if (!xTrapezoidValid(traps)) + continue; + y1 = xFixedToInt (traps->top); + if (y1 < box->y1) + box->y1 = y1; + + y2 = xFixedToInt (xFixedCeil (traps->bottom)); + if (y2 > box->y2) + box->y2 = y2; + + x1 = xFixedToInt (min (_glamor_linefixedX (&traps->left, traps->top, FALSE), + _glamor_linefixedX (&traps->left, traps->bottom, FALSE))); + if (x1 < box->x1) + box->x1 = x1; + + x2 = xFixedToInt (xFixedCeil (max (_glamor_linefixedX (&traps->right, traps->top, TRUE), + _glamor_linefixedX (&traps->right, traps->bottom, TRUE)))); + if (x2 > box->x2) + box->x2 = x2; + + if (!has_large_trapezoid && (x2 - x1) > 256 && (y2 - y1) > 32) + has_large_trapezoid = 1; + } + + return has_large_trapezoid; +} + +/** + * glamor_trapezoids will first try to create a trapezoid mask using shader, + * if failed, miTrapezoids will generate trapezoid mask accumulating in + * system memory. + */ +static Bool +_glamor_trapezoids(CARD8 op, + PicturePtr src, PicturePtr dst, + PictFormatPtr mask_format, INT16 x_src, INT16 y_src, + int ntrap, xTrapezoid * traps, Bool fallback) +{ + ScreenPtr screen = dst->pDrawable->pScreen; + BoxRec bounds; + PicturePtr picture; + INT16 x_dst, y_dst; + INT16 x_rel, y_rel; + int width, height, stride; + PixmapPtr pixmap; + pixman_image_t *image = NULL; + int ret = 0; + int has_large_trapezoid; + + /* If a mask format wasn't provided, we get to choose, but behavior should + * be as if there was no temporary mask the traps were accumulated into. + */ + if (!mask_format) { + if (dst->polyEdge == PolyEdgeSharp) + mask_format = + PictureMatchFormat(screen, 1, PICT_a1); + else + mask_format = + PictureMatchFormat(screen, 8, PICT_a8); + for (; ntrap; ntrap--, traps++) + glamor_trapezoids(op, src, dst, mask_format, x_src, + y_src, 1, traps); + return TRUE; + } + + has_large_trapezoid = _glamor_trapezoid_bounds(ntrap, traps, &bounds); + DEBUGF("The bounds for all traps is: bounds.x1 = %d, bounds.x2 = %d, " + "bounds.y1 = %d, bounds.y2 = %d, ---- ntrap = %d\n", bounds.x1, + bounds.x2, bounds.y1, bounds.y2, ntrap); + + if (bounds.y1 >= bounds.y2 || bounds.x1 >= bounds.x2) + return TRUE; + + x_dst = traps[0].left.p1.x >> 16; + y_dst = traps[0].left.p1.y >> 16; + + width = bounds.x2 - bounds.x1; + height = bounds.y2 - bounds.y1; + stride = PixmapBytePad(width, mask_format->depth); + +#ifdef GLAMOR_TRAPEZOID_SHADER + /* We seperate the render to two paths. + Some GL implemetation do not implement the Anti-Alias for triangles + and polygen's filling. So when the edge is not vertical or horizontal, + sawtooth will be obvious. The trapezoid is widely used to render wide + lines and circles. In these case, the line or circle will be divided + into a large number of small trapezoids to approximate it, so the sawtooth + at the edge will cause the result not be acceptable. + When the depth of the mask is 1, there is no Anti-Alias needed, so we + use the clip logic to generate the result directly(fast path). + When the depth is not 1, AA is needed and we use a shader to generate + a temp mask pixmap. + */ + if (mask_format->depth == 1) { + ret = _glamor_trapezoids_with_shader(op, src, dst, mask_format, + x_src, y_src, ntrap, traps); + if(ret) + return TRUE; + } else { + if (has_large_trapezoid || ntrap > 256) { + /* The shader speed is relative slower than pixman when generating big chunk + trapezoid mask. We fallback to pixman to improve the performance. */ + ; + } else if (dst->polyMode == PolyModeImprecise) { + /* The precise mode is that we sample the trapezoid on the centre points of + an (2*n+1)x(2*n-1) subpixel grid. It is computationally expensive in shader + and we use inside area ratio to replace it if the polymode == Imprecise. */ + picture = glamor_create_mask_picture(screen, dst, mask_format, + width, height, 1); + if (!picture) + return TRUE; + + ret = _glamor_generate_trapezoid_with_shader(screen, picture, traps, ntrap, &bounds); + + if (!ret) + FreePicture(picture, 0); + } + } +#endif + + if (!ret) { + DEBUGF("Fallback to sw rasterize of trapezoid\n"); + + picture = glamor_create_mask_picture(screen, dst, mask_format, + width, height, 0); + if (!picture) + return TRUE; + + image = pixman_image_create_bits(picture->format, + width, height, NULL, stride); + if (!image) { + FreePicture(picture, 0); + return TRUE; + } + + for (; ntrap; ntrap--, traps++) + pixman_rasterize_trapezoid(image, + (pixman_trapezoid_t *) traps, + -bounds.x1, -bounds.y1); + + pixmap = glamor_get_drawable_pixmap(picture->pDrawable); + + screen->ModifyPixmapHeader(pixmap, width, height, + mask_format->depth, + BitsPerPixel(mask_format->depth), + PixmapBytePad(width, + mask_format->depth), + pixman_image_get_data(image)); + } + + x_rel = bounds.x1 + x_src - x_dst; + y_rel = bounds.y1 + y_src - y_dst; + DEBUGF("x_src = %d, y_src = %d, x_dst = %d, y_dst = %d, " + "x_rel = %d, y_rel = %d\n", x_src, y_src, x_dst, + y_dst, x_rel, y_rel); + + CompositePicture(op, src, picture, dst, + x_rel, y_rel, + 0, 0, + bounds.x1, bounds.y1, + bounds.x2 - bounds.x1, bounds.y2 - bounds.y1); + + if (image) + pixman_image_unref(image); + + FreePicture(picture, 0); + return TRUE; +} + +void +glamor_trapezoids(CARD8 op, + PicturePtr src, PicturePtr dst, + PictFormatPtr mask_format, INT16 x_src, INT16 y_src, + int ntrap, xTrapezoid * traps) +{ + DEBUGF("x_src = %d, y_src = %d, ntrap = %d\n", x_src, y_src, ntrap); + + _glamor_trapezoids(op, src, dst, mask_format, x_src, + y_src, ntrap, traps, TRUE); +} + +Bool +glamor_trapezoids_nf(CARD8 op, + PicturePtr src, PicturePtr dst, + PictFormatPtr mask_format, INT16 x_src, INT16 y_src, + int ntrap, xTrapezoid * traps) +{ + DEBUGF("x_src = %d, y_src = %d, ntrap = %d\n", x_src, y_src, ntrap); + + return _glamor_trapezoids(op, src, dst, mask_format, x_src, + y_src, ntrap, traps, FALSE); +} + +#endif /* RENDER */ + |