static void
CreatorFillArcSliceSolid(DrawablePtr pDrawable, GCPtr pGC, xArc *arc)
{
	WindowPtr pWin = (WindowPtr) pDrawable;
	FFBPtr pFfb = GET_FFB_FROM_SCREEN(pDrawable->pScreen);
	CreatorPrivGCPtr gcPriv = CreatorGetGCPrivate (pGC);
	ffb_fbcPtr ffb = pFfb->regs;
	miFillArcRec info;
	miArcSliceRec slice;
	int x, y, e, yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
	int ya, xl, xr, xc;

	/* Get the RP ready. */
	if(gcPriv->stipple == NULL) {
		FFB_ATTR_GC(pFfb, pGC, pWin,
			    FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
			    FFB_DRAWOP_RECTANGLE);
	} else {
		unsigned int fbc;

		FFBSetStipple(pFfb, ffb, gcPriv->stipple,
			      FFB_PPC_CS_CONST, FFB_PPC_CS_MASK);
		FFB_WRITE_PMASK(pFfb, ffb, pGC->planemask);
		FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
		fbc = FFB_FBC_WIN(pWin);
		fbc = (fbc & ~FFB_FBC_XE_MASK) | FFB_FBC_XE_OFF;
		FFB_WRITE_FBC(pFfb, ffb, fbc);
		FFB_WRITE_FBC(pFfb, ffb, FFB_FBC_WIN(pWin));
	}
	miFillArcSetup(arc, &info);
	miFillArcSliceSetup(arc, &slice, pGC);
	MIFILLARCSETUP();
	slw = arc->height;
	if (slice.flip_top || slice.flip_bot)
		slw += (arc->height >> 1) + 1;
	if (pGC->miTranslate) {
		xorg += pDrawable->x;
		yorg += pDrawable->y;
		slice.edge1.x += pDrawable->x;
		slice.edge2.x += pDrawable->x;
	}
	while (y > 0) {
		MIFILLARCSTEP(slw);
		MIARCSLICESTEP(slice.edge1);
		MIARCSLICESTEP(slice.edge2);
		if (miFillSliceUpper(slice)) {
			ya = yorg - y;
			MIARCSLICEUPPER(xl, xr, slice, slw);
			ADDSLICESPANS(slice.flip_top);
		}
		if (miFillSliceLower(slice)) {
			ya = yorg + y + dy;
			MIARCSLICELOWER(xl, xr, slice, slw);
			ADDSLICESPANS(slice.flip_bot);
		}
	}
	pFfb->rp_active = 1;
	FFBSync(pFfb, ffb);
}
/* Wheee, circles... */
static void
CreatorFillEllipseSolid(DrawablePtr pDrawable, GCPtr pGC, xArc *arc)
{
	WindowPtr pWin = (WindowPtr) pDrawable;
	FFBPtr pFfb = GET_FFB_FROM_SCREEN(pDrawable->pScreen);
	CreatorPrivGCPtr gcPriv = CreatorGetGCPrivate (pGC);
	ffb_fbcPtr ffb = pFfb->regs;
	miFillArcRec info;
	int x, y, e, yk, xk, ym, xm, dx, dy, xorg, yorg, slw;

	/* Get the RP ready. */
	if(gcPriv->stipple == NULL) {
		FFB_ATTR_GC(pFfb, pGC, pWin,
			    FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
			    FFB_DRAWOP_RECTANGLE);
	} else {
		unsigned int fbc;

		FFBSetStipple(pFfb, ffb, gcPriv->stipple,
			      FFB_PPC_CS_CONST, FFB_PPC_CS_MASK);
		FFB_WRITE_PMASK(pFfb, ffb, pGC->planemask);
		FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_RECTANGLE);
		fbc = FFB_FBC_WIN(pWin);
		fbc = (fbc & ~FFB_FBC_XE_MASK) | FFB_FBC_XE_OFF;
		FFB_WRITE_FBC(pFfb, ffb, fbc);
	}

	/* Start computing the rects. */
	miFillArcSetup(arc, &info);
	MIFILLARCSETUP();
	if(pGC->miTranslate) {
		xorg += pDrawable->x;
		yorg += pDrawable->y;
	}
	while(y > 0) {
		MIFILLARCSTEP(slw);
		if(slw > 0) {
			/* Render. */
			FFBFifo(pFfb, 4);
			FFB_WRITE64(&ffb->by, yorg - y, xorg - x);
			FFB_WRITE64_2(&ffb->bh, 1, slw);
			if(miFillArcLower(slw)) {
				FFBFifo(pFfb, 4);
				FFB_WRITE64(&ffb->by, yorg + y + dy, xorg - x);
				FFB_WRITE64_2(&ffb->bh, 1, slw);
			}
		}
	}
	pFfb->rp_active = 1;
	FFBSync(pFfb, ffb);
}
void
CreatorPolySegment (DrawablePtr pDrawable, GCPtr pGC, int nseg, xSegment *pSeg)
{
	WindowPtr pWin = (WindowPtr) pDrawable;
	CreatorPrivGCPtr gcPriv = CreatorGetGCPrivate (pGC);
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pGC->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	BoxPtr extent;
	int xorg, yorg, lpat;

	if (nseg == 0)
		return;

	FFBLOG(("CreatorPolySegment: ALU(%x) PMSK(%08x) nseg(%d) lpat(%08x)\n",
		pGC->alu, pGC->planemask, nseg, gcPriv->linepat));

	if (gcPriv->stipple == NULL) {
		FFB_ATTR_GC(pFfb, pGC, pWin,
			    FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
			    SEG_DRAWOP(pGC));
	} else {
		unsigned int fbc;

		FFBSetStipple(pFfb, ffb, gcPriv->stipple,
			      FFB_PPC_CS_CONST, FFB_PPC_CS_MASK);
		FFB_WRITE_PMASK(pFfb, ffb, pGC->planemask);
		FFB_WRITE_DRAWOP(pFfb, ffb, SEG_DRAWOP(pGC));
		fbc = FFB_FBC_WIN(pWin);
		fbc = (fbc & ~FFB_FBC_XE_MASK) | FFB_FBC_XE_OFF;
		FFB_WRITE_FBC(pFfb, ffb, fbc);
	}

	pFfb->rp_active = 1;
	xorg = pDrawable->x;
	yorg = pDrawable->y;
	extent = REGION_RECTS(cfbGetCompositeClip(pGC));
	lpat = gcPriv->linepat;

	if (lpat == 0) {
		FFBFifo(pFfb, 1);
		ffb->lpat = 0;
		if (pFfb->has_brline_bug) {
			while (nseg--) {
				register int x1 = pSeg->x1 + xorg;
				register int y1 = pSeg->y1 + yorg;
				register int x2 = pSeg->x2 + xorg;
				register int y2 = pSeg->y2 + yorg;

				if (x1 >= extent->x1	&&
				    x2 >= extent->x1	&&
				    x1 < extent->x2	&&
				    x2 < extent->x2	&&
				    y1 >= extent->y1	&&
				    y2 >= extent->y1	&&
				    y1 < extent->y2	&&
				    y2 < extent->y2) {
					FFBFifo(pFfb, 5);
					ffb->ppc = 0;
					FFB_WRITE64(&ffb->by, y1, x1);
					FFB_WRITE64_2(&ffb->bh, y2, x2);
				} else {
					gcPriv->PolySegment(pDrawable, pGC, 1, pSeg);
					ReloadSegmentAttrs(pFfb, gcPriv, pGC, pWin);
					pFfb->rp_active = 1;
				}
				pSeg++;
			}
		} else {
			while (nseg--) {
				register int x1 = pSeg->x1 + xorg;
				register int y1 = pSeg->y1 + yorg;
				register int x2 = pSeg->x2 + xorg;
				register int y2 = pSeg->y2 + yorg;

				if (x1 >= extent->x1	&&
				    x2 >= extent->x1	&&
				    x1 < extent->x2	&&
				    x2 < extent->x2	&&
				    y1 >= extent->y1	&&
				    y2 >= extent->y1	&&
				    y1 < extent->y2	&&
				    y2 < extent->y2) {
					FFBFifo(pFfb, 4);
					FFB_WRITE64(&ffb->by, y1, x1);
					FFB_WRITE64_2(&ffb->bh, y2, x2);
				} else {
					gcPriv->PolySegment(pDrawable, pGC, 1, pSeg);
					ReloadSegmentAttrs(pFfb, gcPriv, pGC, pWin);
					pFfb->rp_active = 1;
				}
				pSeg++;
			}
		}
	} else {
		/* No reason to optimize the non-brline bug case since
		 * we have to write the line pattern register each loop
		 * anyways.
		 */
		while (nseg--) {
			register int x1 = pSeg->x1 + xorg;
			register int y1 = pSeg->y1 + yorg;
			register int x2 = pSeg->x2 + xorg;
			register int y2 = pSeg->y2 + yorg;

			if (x1 >= extent->x1	&&	x2 >= extent->x1	&&
			    x1 < extent->x2	&&	x2 < extent->x2		&&
			    y1 >= extent->y1	&&	y2 >= extent->y1	&&
			    y1 < extent->y2	&&	y2 < extent->y2) {
				FFBFifo(pFfb, 5);
				ffb->lpat = lpat;
				FFB_WRITE64(&ffb->by, y1, x1);
				FFB_WRITE64_2(&ffb->bh, y2, x2);
			} else {
				gcPriv->PolySegment(pDrawable, pGC, 1, pSeg);
				ReloadSegmentAttrs(pFfb, gcPriv, pGC, pWin);
				pFfb->rp_active = 1;
			}
			pSeg++;
		}
	}

	FFBSync(pFfb, ffb);
}
void
CreatorFillPolygon (DrawablePtr pDrawable, GCPtr pGC, int shape, int mode, int count, DDXPointPtr ppt)
{
	WindowPtr pWin = (WindowPtr) pDrawable;
	CreatorPrivGCPtr gcPriv = CreatorGetGCPrivate (pGC);
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pGC->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	BoxRec box;
	int lx, rx, ty, by;
	int t, b, i, j, k, l, tt;
	int xy[12] FFB_ALIGN64;
	int xOrg, yOrg;

	FFBLOG(("CreatorFillPolygon: ALU(%x) PMSK(%08x) shape(%d) mode(%d) count(%d)\n",
		pGC->alu, pGC->planemask, shape, mode, count));
	if (count < 3)
		return;
	
	if (shape != Convex && count > 3) {
		miFillPolygon (pDrawable, pGC, shape, mode, count, ppt);
		return;
	}
	
	xOrg = pDrawable->x;
	yOrg = pDrawable->y;

	ppt->x += xOrg;
	ppt->y += yOrg;	
	lx = ppt->x;
	rx = ppt->x;
	ty = ppt->y;
	by = ppt->y;
	t = b = 0;
	tt = 1;
	for (i = 1; i < count; i++) {
		if (mode == CoordModeOrigin) {
			ppt[i].x += xOrg;
			ppt[i].y += yOrg;
		} else {
			ppt[i].x += ppt[i-1].x;
			ppt[i].y += ppt[i-1].y;
		}
		if (ppt[i].x < lx)
			lx = ppt[i].x;
		if (ppt[i].x > rx)
			rx = ppt[i].x;
		if (ppt[i].y < ty) {
			ty = ppt[i].y;
			t = i;
			tt = 1;
		} else if (ppt[i].y == ty)
			tt++;
		if (ppt[i].y > by) {
			by = ppt[i].y;
			b = i;
		}
	}
	if (tt > 2) {
		miFillConvexPoly(pDrawable, pGC, count, ppt);
		return;
	} else if (tt == 2) {
		i = t - 1;
		if (i < 0)
			i = count - 1;
		if (ppt[i].y == ppt[t].y)
			t = i;
	}
	box.x1 = lx;
	box.x2 = rx + 1;
	box.y1 = ty;
	box.y2 = by + 1;
	
	switch (RECT_IN_REGION(pGC->pScreen, cfbGetCompositeClip(pGC), &box)) {
	case rgnPART:
		miFillConvexPoly(pDrawable, pGC, count, ppt);
	case rgnOUT:
		return;
	}
	if(gcPriv->stipple == NULL) {
		FFB_ATTR_GC(pFfb, pGC, pWin,
			    FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
			    FFB_DRAWOP_POLYGON);
	} else {
		unsigned int fbc;

		FFBSetStipple(pFfb, ffb, gcPriv->stipple,
			      FFB_PPC_CS_CONST, FFB_PPC_CS_MASK);
		FFB_WRITE_PMASK(pFfb, ffb, pGC->planemask);
		FFB_WRITE_DRAWOP(pFfb, ffb, FFB_DRAWOP_POLYGON);
		fbc = FFB_FBC_WIN(pWin);
		fbc = (fbc & ~FFB_FBC_XE_MASK) | FFB_FBC_XE_OFF;
		FFB_WRITE_FBC(pFfb, ffb, fbc);
	}	
	xy[0] = ppt[t].y;
	xy[1] = ppt[t].x;
	j = t + 1;
	if (j == count) j = 0;
	xy[2] = ppt[j].y;
	xy[3] = ppt[j].x;
	j = t + 2;
	if (j >= count)
		j -= count;
	for (i = 2 * count - 4; i; i -= k) {
		b = 2;
		for (k = 0; k < i && k < 8; k+=2) {
			xy[4 + k] = ppt[j].y;
			xy[4 + k + 1] = ppt[j].x;
			if (xy[4 + k] > xy[b])
				b = 4 + k;
			j++; if (j == count) j = 0;
		}
		FFBFifo(pFfb, 4 + k);
		for (l = 0; l < b - 2; l+=2)
			FFB_WRITE64P(&ffb->by, &xy[l]);
		FFB_WRITE64P(&ffb->bh, &xy[l]);
		for (l+=2; l <= k; l+=2)
			FFB_WRITE64P(&ffb->by, &xy[l]);
		FFB_WRITE64P(&ffb->ebyi, &xy[l]);
		xy[2] = xy[l];
		xy[3] = xy[l+1];
	}
	pFfb->rp_active = 1;
	FFBSync(pFfb, ffb);
}
void
CreatorDoHWBitblt(DrawablePtr pSrc, DrawablePtr pDst, int alu, RegionPtr prgnDst,
		  DDXPointPtr pptSrc, unsigned long planemask)
{
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pSrc->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	BoxPtr pboxTmp;
	DDXPointPtr pptTmp;
	int nbox;
	BoxPtr pboxNext, pboxBase, pbox;

	nbox = REGION_NUM_RECTS(prgnDst);
	pbox = REGION_RECTS(prgnDst);

	FFB_WRITE_ATTRIBUTES(pFfb,
			     FFB_PPC_ACE_DISABLE|FFB_PPC_APE_DISABLE|FFB_PPC_CS_CONST,
			     FFB_PPC_ACE_MASK|FFB_PPC_APE_MASK|FFB_PPC_CS_MASK,
			     planemask,
			     FFB_ROP_NEW,
			     FFB_DRAWOP_BCOPY, pFfb->fg_cache,
			     FFB_FBC_DEFAULT);
	
	/* need to blit rectangles in different orders, depending on the direction of copy
           so that an area isnt overwritten before it is blitted */
	if (pptSrc->y < pbox->y1 && nbox > 1) {
		if (pptSrc->x < pbox->x1) {
			pboxTmp = pbox + nbox;
			pptTmp = pptSrc + nbox;
			while(nbox--) {
				pboxTmp--;
				pptTmp--;
				FFBFifo(pFfb, 6);
				FFB_WRITE64(&ffb->by, pptTmp->y, pptTmp->x);
				FFB_WRITE64_2(&ffb->dy, pboxTmp->y1, pboxTmp->x1);
				FFB_WRITE64_3(&ffb->bh,
					      (pboxTmp->y2 - pboxTmp->y1),
					      (pboxTmp->x2 - pboxTmp->x1));
			}
		} else {
			/* keep ordering in each band, reverse order of bands */
			pboxBase = pboxNext = pbox+nbox-1;
			
			while (pboxBase >= pbox) { /* for each band */
				/* find first box in band */
				while (pboxNext >= pbox && pboxBase->y1 == pboxNext->y1)
					pboxNext--;
		
				pboxTmp = pboxNext + 1;			/* first box in band */
				pptTmp = pptSrc + (pboxTmp - pbox);	/* first point in band */
		
				while (pboxTmp <= pboxBase) { /* for each box in band */
					FFBFifo(pFfb, 6);
					FFB_WRITE64(&ffb->by, pptTmp->y, pptTmp->x);
					FFB_WRITE64_2(&ffb->dy, pboxTmp->y1, pboxTmp->x1);
					FFB_WRITE64_3(&ffb->bh,
						      (pboxTmp->y2 - pboxTmp->y1),
						      (pboxTmp->x2 - pboxTmp->x1));
					++pboxTmp;
					++pptTmp;	
				}
				pboxBase = pboxNext;
			}
		}
	} else {
		if((pptSrc->x < pbox->x1) && (nbox > 1)) {
			pboxBase = pboxNext = pbox;
			while(pboxBase < pbox+nbox) {
				while((pboxNext<pbox+nbox) &&
				      (pboxNext->y1 == pboxBase->y1))
					pboxNext++;
				pboxTmp = pboxNext;
				pptTmp = pptSrc + (pboxTmp - pbox);
				while(pboxTmp != pboxBase) {
					--pboxTmp;
					--pptTmp;
					FFBFifo(pFfb, 6);
					FFB_WRITE64(&ffb->by, pptTmp->y, pptTmp->x);
					FFB_WRITE64_2(&ffb->dy, pboxTmp->y1, pboxTmp->x1);
					FFB_WRITE64_3(&ffb->bh,
						      (pboxTmp->y2 - pboxTmp->y1),
						      (pboxTmp->x2 - pboxTmp->x1));
				}
				pboxBase = pboxNext;
			}
		} else {
			/* dont need to change order of anything */
			pptTmp = pptSrc;
			pboxTmp = pbox;
	    
			while (nbox--) {
				FFBFifo(pFfb, 6);
				FFB_WRITE64(&ffb->by, pptTmp->y, pptTmp->x);
				FFB_WRITE64_2(&ffb->dy, pboxTmp->y1, pboxTmp->x1);
				FFB_WRITE64_3(&ffb->bh,
					      (pboxTmp->y2 - pboxTmp->y1),
					      (pboxTmp->x2 - pboxTmp->x1));
				pboxTmp++;
				pptTmp++;
			}
		}
	}
	pFfb->rp_active = 1;
	FFBSync(pFfb, ffb);
}
RegionPtr
CreatorCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable,
		GCPtr pGC, int srcx, int srcy, int width, int height, int dstx, int dsty)
{
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDstDrawable->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	RegionPtr ret;
	unsigned char *dptr, *sptr, *sfb;
	int garbage, all_planes;
	
	cfbGetByteWidthAndPointer (pDstDrawable, garbage, dptr);
	cfbGetByteWidthAndPointer (pSrcDrawable, garbage, sptr);
	if (pSrcDrawable->bitsPerPixel == 8) {
		sfb = (unsigned char *) pFfb->sfb8r;
		all_planes = 0xff;
	} else {
		sfb = (unsigned char *) pFfb->sfb32;
		all_planes = 0xffffff;
	}

	FFBLOG(("CreatorCopyArea: SFB(%p) s(%p) d(%p) alu(%x) pmsk(%08x) "
		"src(%08x:%08x) dst(%08x:%08x)\n",
		sfb, sptr, dptr, pGC->alu, pGC->planemask,
		srcx, srcy, dstx, dsty));
	if (((pGC->planemask & all_planes) != all_planes || pGC->alu != GXcopy) &&
	    dptr != sfb) {
		if(sptr == sfb) {
			WindowPtr pWin = (WindowPtr) pSrcDrawable;

			FFB_ATTR_SFB_VAR_WIN(pFfb, pGC->planemask, pGC->alu, pWin);
			FFBWait(pFfb, ffb);
		}
		if (pSrcDrawable->bitsPerPixel == 8)
			return cfbCopyArea (pSrcDrawable, pDstDrawable,
					    pGC, srcx, srcy, width, height, dstx, dsty);
		else
			return cfb32CopyArea (pSrcDrawable, pDstDrawable,
					      pGC, srcx, srcy, width, height, dstx, dsty);
	}

	/* Try to use hw VSCROLL if possible */
	if (!pFfb->disable_vscroll &&	/* must not be ffb1 in hires */
	    pGC->alu == GXcopy &&	/* it must be a copy */
	    dstx == srcx &&		/* X must be unchanging */
	    dsty != srcy &&		/* Y must be changing */
	    sptr == dptr &&		/* src and dst must be the framebuffer */
	    dptr == sfb) {
		WindowPtr pWin = (WindowPtr) pSrcDrawable;
		CreatorPrivWinPtr pFfbPrivWin = CreatorGetWindowPrivate(pWin);
		unsigned int fbc = pFfbPrivWin->fbc_base;
		int same_buffer;

		/* One last check, the read buffer and the write buffer
		 * must be the same.  VSCROLL only allows to move pixels
		 * within the same buffer.
		 */
		if (!pFfb->has_double_buffer) {
			same_buffer = 1;
		} else {
			same_buffer = 0;
			if ((((fbc & FFB_FBC_WB_MASK) == FFB_FBC_WB_A) &&
			     ((fbc & FFB_FBC_RB_MASK) == FFB_FBC_RB_A)) ||
			    (((fbc & FFB_FBC_WB_MASK) == FFB_FBC_WB_B) &&
			     ((fbc & FFB_FBC_RB_MASK) == FFB_FBC_RB_B)))
				same_buffer = 1;
		}

		if (same_buffer != 0) {
			FFB_ATTR_VSCROLL_WIN(pFfb, pGC->planemask, pWin);
			if (pSrcDrawable->bitsPerPixel == 8)
				ret = cfbBitBlt (pSrcDrawable, pDstDrawable,
						 pGC, srcx, srcy, width, height,
						 dstx, dsty,
						 (void (*)())CreatorDoVertBitblt, 0);
			else
				ret = cfb32BitBlt (pSrcDrawable, pDstDrawable,
						   pGC, srcx, srcy, width, height,
						   dstx, dsty,
						   (void (*)())CreatorDoVertBitblt, 0);
			FFBLOG(("CreatorCopyArea: Done, returning %p\n", ret));
			return ret;
		}
	}

	/* OK, we have to use GCOPY. */

	/* Even when we are only reading from the framebuffer, we must
	 * set the SFB_VAR attributes to handle double-buffering correctly.
	 */
	if(dptr == sfb || sptr == sfb) {
		WindowPtr pWin;

		if (dptr == sfb)
			pWin = (WindowPtr) pDstDrawable;
		else
			pWin = (WindowPtr) pSrcDrawable;
		FFB_ATTR_SFB_VAR_WIN(pFfb, pGC->planemask, pGC->alu, pWin);
		FFBWait(pFfb, ffb);
	}
	if (pSrcDrawable->bitsPerPixel == 8)
		ret = cfbBitBlt (pSrcDrawable, pDstDrawable,
				 pGC, srcx, srcy, width, height,
				 dstx, dsty, (void (*)())CreatorDoBitblt, 0);
	else
		ret = cfb32BitBlt (pSrcDrawable, pDstDrawable,
				   pGC, srcx, srcy, width, height,
				   dstx, dsty, (void (*)())CreatorDoBitblt, 0);

	FFBLOG(("CreatorCopyArea: Done, returning %p\n", ret));
	return ret;
}
/* The hw attributes have been set by someone higher up in the call
 * chain.
 */
void
CreatorDoBitblt(DrawablePtr pSrc, DrawablePtr pDst, int alu, RegionPtr prgnDst,
		DDXPointPtr pptSrc, unsigned long planemask)
{
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDst->pScreen);
	BoxPtr pboxTmp, pboxNext, pboxBase, pbox;
	DDXPointPtr pptTmp;
	unsigned char *psrcBase, *pdstBase;
	int nbox, widthSrc, widthDst, careful, use_prefetch;
	int psz_shift;

	cfbGetByteWidthAndPointer (pSrc, widthSrc, psrcBase)
	cfbGetByteWidthAndPointer (pDst, widthDst, pdstBase)
	
	careful = ((pSrc == pDst) ||
		  ((pSrc->type == DRAWABLE_WINDOW) &&
		   (pDst->type == DRAWABLE_WINDOW)));
	use_prefetch = (pFfb->use_blkread_prefetch &&
			(psrcBase == (unsigned char *)pFfb->sfb32 ||
			 psrcBase == (unsigned char *)pFfb->sfb8r));

	pbox = REGION_RECTS(prgnDst);
	nbox = REGION_NUM_RECTS(prgnDst);

	pptTmp = pptSrc;
	pboxTmp = pbox;

	FFBLOG(("GCOPY(%d): ", nbox));

	if (pSrc->bitsPerPixel == 8)
		psz_shift = 0;
	else
		psz_shift = 2;

	if (careful && pptSrc->y < pbox->y1) {
		if (pptSrc->x < pbox->x1) {
			/* reverse order of bands and rects in each band */
			pboxTmp=pbox+nbox;
                        pptTmp=pptSrc+nbox;

			while (nbox--){
				pboxTmp--;
				pptTmp--;
				FFBLOG(("[%08x:%08x:%08x:%08x:%08x:%08x] ",
					pptTmp->x, pptTmp->y, pboxTmp->x1, pboxTmp->y1,
					pboxTmp->x2, pboxTmp->y2));
				if (pptTmp->x < pbox->x2) {
					if (use_prefetch) {
						FFBFifo(pFfb, 1);
						pFfb->regs->mer = FFB_MER_EDRA;
						pFfb->rp_active = 1;
						FFBWait(pFfb, pFfb->regs);
					}
					VISmoveImageRL ((psrcBase +
							 ((pptTmp->y + pboxTmp->y2 - pboxTmp->y1 - 1) *
							  widthSrc) +
							 (pptTmp->x << psz_shift)),
				        	        (pdstBase +
							 ((pboxTmp->y2 - 1) * widthDst) +
							 (pboxTmp->x1 << psz_shift)),
					                (pboxTmp->x2 - pboxTmp->x1) << psz_shift,
				        	        (pboxTmp->y2 - pboxTmp->y1),
					                -widthSrc, -widthDst);
				} else {
					if (use_prefetch) {
						FFBFifo(pFfb, 1);
						pFfb->regs->mer = FFB_MER_EIRA;
						pFfb->rp_active = 1;
						FFBWait(pFfb, pFfb->regs);
					}
					VISmoveImageLR ((psrcBase +
							 ((pptTmp->y + pboxTmp->y2 - pboxTmp->y1 - 1) *
							  widthSrc) +
							 (pptTmp->x << psz_shift)),
				        	        (pdstBase +
							 ((pboxTmp->y2 - 1) * widthDst) +
							 (pboxTmp->x1 << psz_shift)),
					                (pboxTmp->x2 - pboxTmp->x1) << psz_shift,
				        	        (pboxTmp->y2 - pboxTmp->y1),
					                -widthSrc, -widthDst);
				}
			}
		} else {
			/* keep ordering in each band, reverse order of bands */
			pboxBase = pboxNext = pbox+nbox-1;

			while (pboxBase >= pbox) {			/* for each band */

				/* find first box in band */
				while (pboxNext >= pbox &&
				       pboxBase->y1 == pboxNext->y1)
					pboxNext--;
		
				pboxTmp = pboxNext+1;			/* first box in band */
				pptTmp = pptSrc + (pboxTmp - pbox);	/* first point in band */
		
				FFBLOG(("[%08x:%08x:%08x:%08x:%08x:%08x] ",
					pptTmp->x, pptTmp->y, pboxTmp->x1, pboxTmp->y1,
					pboxTmp->x2, pboxTmp->y2));
				while (pboxTmp <= pboxBase) {		/* for each box in band */
					if (use_prefetch) {
						FFBFifo(pFfb, 1);
						pFfb->regs->mer = FFB_MER_EIRA;
						pFfb->rp_active = 1;
						FFBWait(pFfb, pFfb->regs);
					}
					VISmoveImageLR ((psrcBase +
							 ((pptTmp->y + pboxTmp->y2 - pboxTmp->y1 - 1) *
							  widthSrc) +
							 (pptTmp->x << psz_shift)),
				        	        (pdstBase +
							 ((pboxTmp->y2 - 1) * widthDst) +
							 (pboxTmp->x1 << psz_shift)),
					                (pboxTmp->x2 - pboxTmp->x1) << psz_shift,
				        	        (pboxTmp->y2 - pboxTmp->y1),
					                -widthSrc, -widthDst);
					++pboxTmp;
					++pptTmp;	
				}
				pboxBase = pboxNext;
			
			}
		}
	} else {
		if (careful && pptSrc->x < pbox->x1) {
			/* reverse order of rects in each band */

			pboxBase = pboxNext = pbox;

			while (pboxBase < pbox+nbox) { /* for each band */

				/* find last box in band */
				while (pboxNext < pbox+nbox &&
				       pboxNext->y1 == pboxBase->y1)
					pboxNext++;

				pboxTmp = pboxNext;			/* last box in band */
				pptTmp = pptSrc + (pboxTmp - pbox);	/* last point in band */

				while (pboxTmp != pboxBase) {		/* for each box in band */
					--pboxTmp;
					--pptTmp;
					FFBLOG(("[%08x:%08x:%08x:%08x:%08x:%08x] ",
						pptTmp->x, pptTmp->y, pboxTmp->x1, pboxTmp->y1,
						pboxTmp->x2, pboxTmp->y2));
					if (pptTmp->x < pbox->x2) {
						if (use_prefetch) {
							FFBFifo(pFfb, 1);
							pFfb->regs->mer = FFB_MER_EDRA;
							pFfb->regs->mer = FFB_MER_EIRA;
							pFfb->rp_active = 1;
						}
						VISmoveImageRL ((psrcBase +
								 (pptTmp->y * widthSrc) +
								 (pptTmp->x << psz_shift)),
						                (pdstBase +
								 (pboxTmp->y1 * widthDst) +
								 (pboxTmp->x1 << psz_shift)),
						                (pboxTmp->x2 - pboxTmp->x1) << psz_shift,
			        	        		(pboxTmp->y2 - pboxTmp->y1),
						                widthSrc, widthDst);
					} else {
						if (use_prefetch) {
							FFBFifo(pFfb, 1);
							pFfb->regs->mer = FFB_MER_EIRA;
							pFfb->rp_active = 1;
							FFBWait(pFfb, pFfb->regs);
						}
						VISmoveImageLR ((psrcBase +
								 (pptTmp->y * widthSrc) +
								 (pptTmp->x << psz_shift)),
						                (pdstBase +
								 (pboxTmp->y1 * widthDst) +
								 (pboxTmp->x1 << psz_shift)),
				                		(pboxTmp->x2 - pboxTmp->x1) << psz_shift,
					        	        (pboxTmp->y2 - pboxTmp->y1),
						                widthSrc, widthDst);
					}
				}
				pboxBase = pboxNext;
			}
		} else {
			while (nbox--) {
				FFBLOG(("[%08x:%08x:%08x:%08x:%08x:%08x] ",
					pptTmp->x, pptTmp->y, pboxTmp->x1, pboxTmp->y1,
					pboxTmp->x2, pboxTmp->y2));
				if (use_prefetch) {
					FFBFifo(pFfb, 1);
					pFfb->regs->mer = FFB_MER_EIRA;
					pFfb->rp_active = 1;
					FFBWait(pFfb, pFfb->regs);
				}
				VISmoveImageLR ((psrcBase +
						 (pptTmp->y * widthSrc) +
						 (pptTmp->x << psz_shift)),
				                (pdstBase +
						 (pboxTmp->y1 * widthDst) +
						 (pboxTmp->x1 << psz_shift)),
				                (pboxTmp->x2 - pboxTmp->x1) << psz_shift,
			        	        (pboxTmp->y2 - pboxTmp->y1),
				                widthSrc, widthDst);
				pboxTmp++;
				pptTmp++;
			}
		}
	}
	if (use_prefetch) {
		FFBFifo(pFfb, 1);
		pFfb->regs->mer = FFB_MER_DRA;
		pFfb->rp_active = 1;
		FFBWait(pFfb, pFfb->regs);
	}
	FFBLOG(("done\n"));
}
/* We know here that only y is changing and that the hw attributes
 * have been set higher up in the call chain.
 */
void
CreatorDoVertBitblt(DrawablePtr pSrc, DrawablePtr pDst, int alu, RegionPtr prgnDst,
		    DDXPointPtr pptSrc, unsigned long planemask)
{
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pSrc->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	BoxPtr pbox;
	int nbox;

	pbox = REGION_RECTS(prgnDst);
	nbox = REGION_NUM_RECTS(prgnDst);

	/* No garbage please. */
	if(nbox <= 0)
		return;

	FFBLOG(("VSCROLL(%d): ", nbox));

	/* Need to blit rectangles in different orders, depending
	 * on the direction of copy so that an area isnt overwritten
	 * before it is blitted.
	 */
	if (nbox > 1 && pptSrc->y < pbox->y1) {
		BoxPtr pboxBase = pbox + nbox - 1;
		BoxPtr pboxNext = pboxBase;

		/* Keep ordering in each band, reverse order of bands. */
		while (pboxBase >= pbox) { /* for each band */
			BoxPtr pboxTmp;
			DDXPointPtr pptTmp;

			/* find first box in band */
			while (pboxNext >= pbox && pboxBase->y1 == pboxNext->y1)
				pboxNext--;
		
			pboxTmp = pboxNext + 1;			/* first box in band */
			pptTmp = pptSrc + (pboxTmp - pbox);	/* first point in band */
			while (pboxTmp <= pboxBase) {
				FFBLOG(("1[%08x:%08x:%08x:%08x:%08x:%08x] ",
					pptTmp->x, pptTmp->y, pboxTmp->x1, pboxTmp->y1,
					pboxTmp->x2, pboxTmp->y2));
				FFBFifo(pFfb, 7);
				ffb->drawop = FFB_DRAWOP_VSCROLL;
				FFB_WRITE64(&ffb->by, pptTmp->y, pptTmp->x);
				FFB_WRITE64_2(&ffb->dy, pboxTmp->y1, pboxTmp->x1);
				FFB_WRITE64_3(&ffb->bh, (pboxTmp->y2 - pboxTmp->y1),
					      (pboxTmp->x2 - pboxTmp->x1));
				pboxTmp++;
				pptTmp++;
			}
			pboxBase = pboxNext;
		}
	} else {
		/* Dont need to change order of anything. */
		while (nbox--) {
			FFBLOG(("2[%08x:%08x:%08x:%08x:%08x:%08x] ",
				pptSrc->x, pptSrc->y, pbox->x1, pbox->y1,
				pbox->x2, pbox->y2));
			FFBFifo(pFfb, 7);
			ffb->drawop = FFB_DRAWOP_VSCROLL;
			FFB_WRITE64(&ffb->by, pptSrc->y, pptSrc->x);
			FFB_WRITE64_2(&ffb->dy, pbox->y1, pbox->x1);
			FFB_WRITE64_3(&ffb->bh, (pbox->y2 - pbox->y1),
				      (pbox->x2 - pbox->x1));
			pbox++;
			pptSrc++;
		}
	}
	pFfb->rp_active = 1;
	FFBLOG(("done\n"));
	FFBSync(pFfb, ffb);
}
void
CreatorGetSpans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt,
		int *pwidth, int nspans, char *pchardstStart)
{
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDrawable->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	char *addrp;

	FFBLOG(("CreatorGetSpans: wmax(%d) nspans(%d)\n", wMax, nspans));

	/* Punt early for this case. */
	if(pDrawable->bitsPerPixel == 1) {
		mfbGetSpans(pDrawable, wMax, ppt, pwidth,
			    nspans, pchardstStart);
		return;
	}

	/* This code only works when sucking bits directly from
	 * the framebuffer.
	 */
	if(pDrawable->type != DRAWABLE_WINDOW) {
		if (pDrawable->bitsPerPixel == 8)
			cfbGetSpans(pDrawable, wMax, ppt, pwidth,
				    nspans, pchardstStart);
		else
			cfb32GetSpans(pDrawable, wMax, ppt, pwidth,
				      nspans, pchardstStart);
		return;
	}

	/*
	 * XFree86 DDX empties the root borderClip when the VT is
	 * switched away; this checks for that case
	 */
	if (!cfbDrawableEnabled(pDrawable))
		return;
    
	/* We're just reading pixels from SFB, but we could be using
	 * a different read buffer when double-buffering.
	 */
	FFB_ATTR_SFB_VAR_WIN(pFfb, 0x00ffffff, GXcopy, (WindowPtr)pDrawable);
	FFBWait(pFfb, ffb);

	if (pDrawable->bitsPerPixel == 32) {
		unsigned int *pdst = (unsigned int *)pchardstStart;

		addrp = (char *) pFfb->sfb32;

		if ((nspans == 1) && (*pwidth == 1)) {
			*pdst = *(unsigned int *)(addrp + (ppt->y << 13) + (ppt->x << 2));
			return;
		}

		while(nspans--) {
			int w = min(ppt->x + *pwidth, 2048) - ppt->x;
			unsigned int *psrc = (unsigned int *) (addrp +
							       (ppt->y << 13) +
							       (ppt->x << 2));
			unsigned int *pdstNext = pdst + w;

			while (w--)
				*psrc++ = *pdst++;
			pdst = pdstNext;
			ppt++;
			pwidth++;
		}
	} else {
		unsigned char *pdst = (unsigned char *)pchardstStart;

		addrp = (char *) pFfb->sfb8r;

		if ((nspans == 1) && (*pwidth == 1)) {
			*pdst = *(unsigned char *)(addrp + (ppt->y << 11) + (ppt->x << 0));
			return;
		}

		while(nspans--) {
			int w = min(ppt->x + *pwidth, 2048) - ppt->x;
			unsigned char *psrc = (unsigned char *) (addrp +
							       (ppt->y << 11) +
							       (ppt->x << 0));
			unsigned char *pdstNext = pdst + w;

			while (w--)
				*psrc++ = *pdst++;
			pdst = pdstNext;
			ppt++;
			pwidth++;
		}
	}
}
Exemple #10
0
void
CreatorSetSpans(DrawablePtr pDrawable, GCPtr pGC, char *pcharsrc,
		DDXPointPtr ppt, int *pwidth, int nspans, int fSorted)
{
	WindowPtr pWin = (WindowPtr) pDrawable;
	FFBPtr pFfb = GET_FFB_FROM_SCREEN (pDrawable->pScreen);
	ffb_fbcPtr ffb = pFfb->regs;
	unsigned int *psrc = (unsigned int *)pcharsrc;
	BoxPtr pbox, pboxLast, pboxTest;
	DDXPointPtr pptLast;
	RegionPtr prgnDst;
	char *addrp;
	int xStart, xEnd, yMax;

	if(pDrawable->type != DRAWABLE_WINDOW) {
		if (pDrawable->bitsPerPixel == 8)
			cfbSetSpans(pDrawable, pGC, pcharsrc, ppt,
				    pwidth, nspans, fSorted);
		else
			cfb32SetSpans(pDrawable, pGC, pcharsrc, ppt,
				      pwidth, nspans, fSorted);
		return;
	}
	FFBLOG(("CreatorSetSpans: ALU(%x) PMSK(%08x) nspans(%d) fsorted(%d)\n",
		pGC->alu, pGC->planemask, nspans, fSorted));
	if (pGC->alu == GXnoop)
		return;

	/* Get SFB ready. */
	FFB_ATTR_SFB_VAR_WIN(pFfb, pGC->planemask, pGC->alu, pWin);
	FFBWait(pFfb, ffb);

	if (pGC->depth == 8)
		addrp = (char *) pFfb->sfb8r;
	else
		addrp = (char *) pFfb->sfb32;

	yMax = (int) pDrawable->y + (int) pDrawable->height;
	prgnDst = cfbGetCompositeClip(pGC);
	pbox = REGION_RECTS(prgnDst);
	pboxLast = pbox + REGION_NUM_RECTS(prgnDst);
	pptLast = ppt + nspans;
	if(fSorted) {
		pboxTest = pbox;
		while(ppt < pptLast) {
			pbox = pboxTest;
			if(ppt->y >= yMax)
				break;
			while(pbox < pboxLast) {
				if(pbox->y1 > ppt->y) {
					break;
				} else if(pbox->y2 <= ppt->y) {
					pboxTest = ++pbox;
					continue;
				} else if(pbox->x1 > ppt->x + *pwidth) {
					break;
				} else if(pbox->x2 <= ppt->x) {
					pbox++;
					continue;
				}
				xStart = max(pbox->x1, ppt->x);
				xEnd = min(ppt->x + *pwidth, pbox->x2);
				CreatorSetScanline(ppt->y, ppt->x, xStart, xEnd,
						   psrc, addrp, pGC->depth);
				if(ppt->x + *pwidth <= pbox->x2)
					break;
				else
					pbox++;
			}
			ppt++;
			psrc += *pwidth++;
		}
	} else {
		while(ppt < pptLast) {
			if(ppt->y >= 0 && ppt->y < yMax) {
				for(pbox = REGION_RECTS(prgnDst); pbox < pboxLast; pbox++) {
					if(pbox->y1 > ppt->y) {
						break;
					} else if(pbox->y2 <= ppt->y) {
						pbox++;
						break;
					}
					if(pbox->x1 <= ppt->x + *pwidth &&
					   pbox->x2 > ppt->x) {
						xStart = max(pbox->x1, ppt->x);
						xEnd = min(pbox->x2, ppt->x + *pwidth);
						CreatorSetScanline(ppt->y, ppt->x,
								   xStart, xEnd,
								   psrc, addrp, pGC->depth);
					}
				}
			}
			ppt++;
			psrc += *pwidth++;
		}
	}
}