xserver/glamor/glamor_trapezoid.c

1498 lines
51 KiB
C
Raw Normal View History

/*
* 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"
#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(&region,
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(&region);
nbox = REGION_NUM_RECTS(&region);
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, &region);
}
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 */