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