mi: Fill spans for multiple arcs in miPolyFillArc

This allocates span data for multiple arcs and draws the
whole set in one call, rather than doing them one at a time. For
modern hardware, this is a significant performance improvement.

v2: Limit the number of spans per buffer to 4M to avoid
    integer overflow in computing the malloc size.

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Keith Packard 2014-04-25 22:43:51 -07:00 committed by Eric Anholt
parent a7fce36aff
commit ea678a73c5

View File

@ -476,26 +476,16 @@ miFillArcSliceSetup(xArc * arc, miArcSliceRec * slice, GCPtr pGC)
*wids++ = slw; \ *wids++ = slw; \
} }
static void static int
miFillEllipseI(DrawablePtr pDraw, GCPtr pGC, xArc * arc) miFillEllipseI(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
{ {
int x, y, e; int x, y, e;
int yk, xk, ym, xm, dx, dy, xorg, yorg; int yk, xk, ym, xm, dx, dy, xorg, yorg;
int slw; int slw;
miFillArcRec info; miFillArcRec info;
DDXPointPtr points;
DDXPointPtr pts; DDXPointPtr pts;
int *widths;
int *wids; int *wids;
points = malloc(sizeof(DDXPointRec) * arc->height);
if (!points)
return;
widths = malloc(sizeof(int) * arc->height);
if (!widths) {
free(points);
return;
}
miFillArcSetup(arc, &info); miFillArcSetup(arc, &info);
MIFILLARCSETUP(); MIFILLARCSETUP();
if (pGC->miTranslate) { if (pGC->miTranslate) {
@ -508,31 +498,19 @@ miFillEllipseI(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
MIFILLARCSTEP(slw); MIFILLARCSTEP(slw);
ADDSPANS(); ADDSPANS();
} }
(*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE); return pts - points;
free(widths);
free(points);
} }
static void static int
miFillEllipseD(DrawablePtr pDraw, GCPtr pGC, xArc * arc) miFillEllipseD(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
{ {
int x, y; int x, y;
int xorg, yorg, dx, dy, slw; int xorg, yorg, dx, dy, slw;
double e, yk, xk, ym, xm; double e, yk, xk, ym, xm;
miFillArcDRec info; miFillArcDRec info;
DDXPointPtr points;
DDXPointPtr pts; DDXPointPtr pts;
int *widths;
int *wids; int *wids;
points = malloc(sizeof(DDXPointRec) * arc->height);
if (!points)
return;
widths = malloc(sizeof(int) * arc->height);
if (!widths) {
free(points);
return;
}
miFillArcDSetup(arc, &info); miFillArcDSetup(arc, &info);
MIFILLARCSETUP(); MIFILLARCSETUP();
if (pGC->miTranslate) { if (pGC->miTranslate) {
@ -545,9 +523,7 @@ miFillEllipseD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
MIFILLARCSTEP(slw); MIFILLARCSTEP(slw);
ADDSPANS(); ADDSPANS();
} }
(*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE); return pts - points;
free(widths);
free(points);
} }
#define ADDSPAN(l,r) \ #define ADDSPAN(l,r) \
@ -572,17 +548,15 @@ miFillEllipseD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
ADDSPAN(xl, xc); \ ADDSPAN(xl, xc); \
} }
static void static int
miFillArcSliceI(DrawablePtr pDraw, GCPtr pGC, xArc * arc) miFillArcSliceI(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
{ {
int yk, xk, ym, xm, dx, dy, xorg, yorg, slw; int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
int x, y, e; int x, y, e;
miFillArcRec info; miFillArcRec info;
miArcSliceRec slice; miArcSliceRec slice;
int ya, xl, xr, xc; int ya, xl, xr, xc;
DDXPointPtr points;
DDXPointPtr pts; DDXPointPtr pts;
int *widths;
int *wids; int *wids;
miFillArcSetup(arc, &info); miFillArcSetup(arc, &info);
@ -591,14 +565,6 @@ miFillArcSliceI(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
slw = arc->height; slw = arc->height;
if (slice.flip_top || slice.flip_bot) if (slice.flip_top || slice.flip_bot)
slw += (arc->height >> 1) + 1; slw += (arc->height >> 1) + 1;
points = malloc(sizeof(DDXPointRec) * slw);
if (!points)
return;
widths = malloc(sizeof(int) * slw);
if (!widths) {
free(points);
return;
}
if (pGC->miTranslate) { if (pGC->miTranslate) {
xorg += pDraw->x; xorg += pDraw->x;
yorg += pDraw->y; yorg += pDraw->y;
@ -622,13 +588,11 @@ miFillArcSliceI(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
ADDSLICESPANS(slice.flip_bot); ADDSLICESPANS(slice.flip_bot);
} }
} }
(*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE); return pts - points;
free(widths);
free(points);
} }
static void static int
miFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc) miFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc, DDXPointPtr points, int *widths)
{ {
int x, y; int x, y;
int dx, dy, xorg, yorg, slw; int dx, dy, xorg, yorg, slw;
@ -636,9 +600,7 @@ miFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
miFillArcDRec info; miFillArcDRec info;
miArcSliceRec slice; miArcSliceRec slice;
int ya, xl, xr, xc; int ya, xl, xr, xc;
DDXPointPtr points;
DDXPointPtr pts; DDXPointPtr pts;
int *widths;
int *wids; int *wids;
miFillArcDSetup(arc, &info); miFillArcDSetup(arc, &info);
@ -647,14 +609,6 @@ miFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
slw = arc->height; slw = arc->height;
if (slice.flip_top || slice.flip_bot) if (slice.flip_top || slice.flip_bot)
slw += (arc->height >> 1) + 1; slw += (arc->height >> 1) + 1;
points = malloc(sizeof(DDXPointRec) * slw);
if (!points)
return;
widths = malloc(sizeof(int) * slw);
if (!widths) {
free(points);
return;
}
if (pGC->miTranslate) { if (pGC->miTranslate) {
xorg += pDraw->x; xorg += pDraw->x;
yorg += pDraw->y; yorg += pDraw->y;
@ -678,35 +632,69 @@ miFillArcSliceD(DrawablePtr pDraw, GCPtr pGC, xArc * arc)
ADDSLICESPANS(slice.flip_bot); ADDSLICESPANS(slice.flip_bot);
} }
} }
(*pGC->ops->FillSpans) (pDraw, pGC, pts - points, points, widths, FALSE); return pts - points;
free(widths);
free(points);
} }
/* MIPOLYFILLARC -- The public entry for the PolyFillArc request. /* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
* Since we don't have to worry about overlapping segments, we can just * Since we don't have to worry about overlapping segments, we can just
* fill each arc as it comes. * fill each arc as it comes.
*/ */
void
miPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs, xArc * parcs)
{
int i;
xArc *arc;
for (i = narcs, arc = parcs; --i >= 0; arc++) { /* Limit the number of spans in a single draw request to avoid integer
if (miFillArcEmpty(arc)) * overflow in the computation of the span buffer size.
continue; */
if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE)) { #define MAX_SPANS_PER_LOOP (4 * 1024 * 1024)
if (miCanFillArc(arc))
miFillEllipseI(pDraw, pGC, arc); void
else miPolyFillArc(DrawablePtr pDraw, GCPtr pGC, int narcs_all, xArc * parcs)
miFillEllipseD(pDraw, pGC, arc); {
while (narcs_all > 0) {
int narcs;
int i;
xArc *arc;
int nspans = 0;
DDXPointPtr pts, points;
int *wids, *widths;
int n;
for (narcs = 0, arc = parcs; narcs < narcs_all; narcs++, arc++) {
if (narcs && nspans + arc->height > MAX_SPANS_PER_LOOP)
break;
nspans += arc->height;
} }
else {
if (miCanFillArc(arc)) pts = points = malloc (sizeof (DDXPointRec) * nspans +
miFillArcSliceI(pDraw, pGC, arc); sizeof(int) * nspans);
else if (points) {
miFillArcSliceD(pDraw, pGC, arc); wids = widths = (int *) (points + nspans);
for (i = 0, arc = parcs; i < narcs; arc++, i++) {
if (miFillArcEmpty(arc))
continue;
if ((arc->angle2 >= FULLCIRCLE) || (arc->angle2 <= -FULLCIRCLE))
{
if (miCanFillArc(arc))
n = miFillEllipseI(pDraw, pGC, arc, pts, wids);
else
n = miFillEllipseD(pDraw, pGC, arc, pts, wids);
}
else
{
if (miCanFillArc(arc))
n = miFillArcSliceI(pDraw, pGC, arc, pts, wids);
else
n = miFillArcSliceD(pDraw, pGC, arc, pts, wids);
}
pts += n;
wids += n;
}
nspans = pts - points;
if (nspans)
(*pGC->ops->FillSpans) (pDraw, pGC, nspans, points,
widths, FALSE);
free (points);
} }
parcs += narcs;
narcs_all -= narcs;
} }
} }