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:
parent
a7fce36aff
commit
ea678a73c5
144
mi/mifillarc.c
144
mi/mifillarc.c
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user