/* * 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 * */ /** @file glamor_trapezoid.c * * Trapezoid acceleration implementation */ #include "glamor_priv.h" #ifdef RENDER #include "mipict.h" #include "fbpict.h" #ifdef GLAMOR_TRAPEZOID_SHADER #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_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); } static Bool point_inside_trapezoid(int point[2], xTrapezoid * trap) { int ret = TRUE; int tmp; if (point[1] > trap->bottom || point[1] < trap->top) ret = FALSE; tmp = _glamor_linefixedX (&trap->left, point[1], FALSE); if (point[0] < tmp) ret = FALSE; tmp = _glamor_linefixedX (&trap->right, point[1], TRUE); if (point[0] > tmp) ret = FALSE; 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; if (!glamor_priv->render_nr_verts) return; 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); } dispatch->glDrawArrays(GL_TRIANGLES, 0, glamor_priv->render_nr_verts); glamor_put_dispatch(glamor_priv); } #define DEBUG_CLIP_VTX 0 static Bool _glamor_clip_trapezoid_vertex(xTrapezoid * trap, BoxPtr pbox, int vertex[6], int *num) { 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)){ \ 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 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 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; 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)) { /* 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) { 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)))) { 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, &saved_source_format); if (ret == FALSE) { DEBUGF("can not set the shader program for composite\n"); goto TRAPEZOID_RESET_GL; } 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_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; } 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 vec4 v_texcoord;\n" "varying vec2 source_texture;\n" "\n" "void main()\n" "{\n" " gl_Position = v_position;\n" " source_texture = v_texcoord.xy;\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" "uniform float x_per_pix; \n" "uniform float y_per_pix; \n" "uniform float trap_top; \n" "uniform float trap_bottom; \n" "uniform float trap_left_x; \n" "uniform float trap_left_y; \n" "uniform float trap_left_slope; \n" "uniform int trap_left_vertical; \n" "uniform float trap_right_x; \n" "uniform float trap_right_y; \n" "uniform float trap_right_slope; \n" "uniform int trap_right_vertical; \n" "\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" " \n" " if(trap_left_vertical == 1) { \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 == 1) { \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 == 1) { \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 == 1) { \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 == 1 && trap_right_vertical == 1) \n" " return percent; \n" " \n" " if(trap_left_vertical != 1) { \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 != 1) { \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"); 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 x_per_pix_uniform_location; GLint y_per_pix_uniform_location; GLint trap_top_uniform_location; GLint trap_bottom_uniform_location; GLint trap_left_x_uniform_location; GLint trap_left_y_uniform_location; GLint trap_left_slope_uniform_location; GLint trap_right_x_uniform_location; GLint trap_right_y_uniform_location; GLint trap_right_slope_uniform_location; GLint trap_left_vertical_uniform_location; GLint trap_right_vertical_uniform_location; GLint trapezoid_prog; float width, height; xFixed width_fix, height_fix; GLfloat xscale, yscale; float left_slope, right_slope; xTrapezoid *ptrap; BoxRec one_trap_bound; float vertices[8]; float tex_vertices[8]; int i; 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)) { /* 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); /* Bind all the uniform vars .*/ x_per_pix_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "x_per_pix"); y_per_pix_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "y_per_pix"); trap_top_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_top"); trap_bottom_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_bottom"); trap_left_x_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_left_x"); trap_left_y_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_left_y"); trap_left_slope_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_left_slope"); trap_left_vertical_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_left_vertical"); trap_right_x_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_right_x"); trap_right_y_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_right_y"); trap_right_slope_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_right_slope"); trap_right_vertical_uniform_location = dispatch->glGetUniformLocation(trapezoid_prog, "trap_right_vertical"); glamor_set_destination_pixmap_priv_nc(pixmap_priv); pixmap_priv_get_dest_scale(pixmap_priv, (&xscale), (&yscale)); width = (float)(bounds->x2 - bounds->x1); height = (float)(bounds->y2 - bounds->y1); width_fix = IntToxFixed((bounds->x2 - bounds->x1)); height_fix = IntToxFixed((bounds->y2 - bounds->y1)); dispatch->glBindBuffer(GL_ARRAY_BUFFER, 0); dispatch->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_POS); dispatch->glDisableVertexAttribArray(GLAMOR_VERTEX_SOURCE); /* Now draw the Trapezoid mask. */ dispatch->glUseProgram(trapezoid_prog); dispatch->glVertexAttribPointer(GLAMOR_VERTEX_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices); dispatch->glVertexAttribPointer(GLAMOR_VERTEX_SOURCE, 2, GL_FLOAT, GL_FALSE, 0, tex_vertices); dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_POS); dispatch->glEnableVertexAttribArray(GLAMOR_VERTEX_SOURCE); dispatch->glEnable(GL_BLEND); dispatch->glBlendFunc(GL_ONE, GL_ONE); for (i = 0; i < ntrap; i++) { ptrap = traps + i; 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); glamor_set_tcoords_tri_strip((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, tex_vertices); /* 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; glamor_set_normalize_vcoords_tri_strip(xscale, yscale, one_trap_bound.x1, one_trap_bound.y1, one_trap_bound.x2, one_trap_bound.y2, glamor_priv->yInverted, vertices); DEBUGF("vertices --> leftup : %f X %f, rightup: %f X %f," "rightbottom: %f X %f, leftbottom : %f X %f\n", vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], vertices[6], vertices[7]); DEBUGF("tex_vertices --> leftup : %f X %f, rightup: %f X %f," "rightbottom: %f X %f, leftbottom : %f X %f\n", tex_vertices[0], tex_vertices[1], tex_vertices[2], tex_vertices[3], tex_vertices[4], tex_vertices[5], tex_vertices[6], tex_vertices[7]); if (ptrap->left.p1.x == ptrap->left.p2.x) { left_slope = 0.0; dispatch->glUniform1i(trap_left_vertical_uniform_location, 1); } else { left_slope = ((float)(ptrap->left.p1.y - ptrap->left.p2.y)) / ((float)(ptrap->left.p1.x - ptrap->left.p2.x)); dispatch->glUniform1i(trap_left_vertical_uniform_location, 0); } dispatch->glUniform1f(trap_left_slope_uniform_location, left_slope); if (ptrap->right.p1.x == ptrap->right.p2.x) { right_slope = 0.0; dispatch->glUniform1i(trap_right_vertical_uniform_location, 1); } else { right_slope = ((float)(ptrap->right.p1.y - ptrap->right.p2.y)) / ((float)(ptrap->right.p1.x - ptrap->right.p2.x)); dispatch->glUniform1i(trap_right_vertical_uniform_location, 0); } dispatch->glUniform1f(trap_right_slope_uniform_location, right_slope); dispatch->glUniform1f(x_per_pix_uniform_location, ((float)width_fix) / (65536 * width)); dispatch->glUniform1f(y_per_pix_uniform_location, ((float)height_fix) / (65536 * height)); dispatch->glUniform1f(trap_top_uniform_location, ((float)ptrap->top) / 65536); dispatch->glUniform1f(trap_bottom_uniform_location, ((float)ptrap->bottom) / 65536); dispatch->glUniform1f(trap_left_x_uniform_location, ((float)ptrap->left.p1.x) / 65536); dispatch->glUniform1f(trap_left_y_uniform_location, ((float)ptrap->left.p1.y) / 65536); dispatch->glUniform1f(trap_right_x_uniform_location, ((float)ptrap->right.p1.x) / 65536); dispatch->glUniform1f(trap_right_y_uniform_location, ((float)ptrap->right.p1.y) / 65536); DEBUGF("x_per_pix = %f, y_per_pix = %f, 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)width_fix) / (65536*width), ((float)height_fix) / (65536*height), ((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); /* Now rendering. */ dispatch->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } 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->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; } /** * 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; /* 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); 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 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 */