/* $XFree86: xc/programs/Xserver/hw/xfree86/xaa/xaaCpyArea.c,v 1.13 2001/02/19 22:19:49 mvojkovi Exp $ */ #include "misc.h" #include "xf86.h" #include "xf86_ansic.h" #include "xf86_OSproc.h" #include "X.h" #include "scrnintstr.h" #include "xf86str.h" #include "xaa.h" #include "xaalocal.h" #include "migc.h" #include "gcstruct.h" #include "pixmapstr.h" /* Written mostly by Harm Hanemaayer (H.Hanemaayer@inter.nl.net). */ RegionPtr XAACopyArea( DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GC *pGC, int srcx, int srcy, int width, int height, int dstx, int dsty ) { XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); if(pDstDrawable->type == DRAWABLE_WINDOW) { if((pSrcDrawable->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pSrcDrawable)){ if(infoRec->ScreenToScreenBitBlt && CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) && CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) && CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags)) return (XAABitBlt( pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, XAADoBitBlt, 0L)); } else { if(infoRec->WritePixmap && ((pDstDrawable->bitsPerPixel == pSrcDrawable->bitsPerPixel) || ((pDstDrawable->bitsPerPixel == 24) && (pSrcDrawable->bitsPerPixel == 32) && (infoRec->WritePixmapFlags & CONVERT_32BPP_TO_24BPP))) && CHECK_ROP(pGC,infoRec->WritePixmapFlags) && CHECK_ROPSRC(pGC,infoRec->WritePixmapFlags) && CHECK_PLANEMASK(pGC,infoRec->WritePixmapFlags) && CHECK_NO_GXCOPY(pGC,infoRec->WritePixmapFlags)) return (XAABitBlt( pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, XAADoImageWrite, 0L)); } } else if(IS_OFFSCREEN_PIXMAP(pDstDrawable)){ if((pSrcDrawable->type == DRAWABLE_WINDOW) || IS_OFFSCREEN_PIXMAP(pSrcDrawable)){ if(infoRec->ScreenToScreenBitBlt && CHECK_ROP(pGC,infoRec->ScreenToScreenBitBltFlags) && CHECK_ROPSRC(pGC,infoRec->ScreenToScreenBitBltFlags) && CHECK_PLANEMASK(pGC,infoRec->ScreenToScreenBitBltFlags)) return (XAABitBlt( pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty, XAADoBitBlt, 0L)); } } return (XAAFallbackOps.CopyArea(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, width, height, dstx, dsty)); } void XAADoBitBlt( DrawablePtr pSrc, DrawablePtr pDst, GC *pGC, RegionPtr prgnDst, DDXPointPtr pptSrc ) { int nbox, careful; BoxPtr pbox, pboxTmp, pboxNext, pboxBase, pboxNew1, pboxNew2; DDXPointPtr pptTmp, pptNew1, pptNew2; int xdir, ydir; XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); /* XXX we have to err on the side of safety when both are windows, * because we don't know if IncludeInferiors is being used. */ careful = ((pSrc == pDst) || ((pSrc->type == DRAWABLE_WINDOW) && (pDst->type == DRAWABLE_WINDOW))); pbox = REGION_RECTS(prgnDst); nbox = REGION_NUM_RECTS(prgnDst); pboxNew1 = NULL; pptNew1 = NULL; pboxNew2 = NULL; pptNew2 = NULL; if (careful && (pptSrc->y < pbox->y1)) { /* walk source botttom to top */ ydir = -1; if (nbox > 1) { /* keep ordering in each band, reverse order of bands */ pboxNew1 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); if(!pboxNew1) return; pptNew1 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); if(!pptNew1) { DEALLOCATE_LOCAL(pboxNew1); return; } pboxBase = pboxNext = pbox+nbox-1; while (pboxBase >= pbox) { while ((pboxNext >= pbox) && (pboxBase->y1 == pboxNext->y1)) pboxNext--; pboxTmp = pboxNext+1; pptTmp = pptSrc + (pboxTmp - pbox); while (pboxTmp <= pboxBase) { *pboxNew1++ = *pboxTmp++; *pptNew1++ = *pptTmp++; } pboxBase = pboxNext; } pboxNew1 -= nbox; pbox = pboxNew1; pptNew1 -= nbox; pptSrc = pptNew1; } } else { /* walk source top to bottom */ ydir = 1; } if (careful && (pptSrc->x < pbox->x1)) { /* walk source right to left */ xdir = -1; if (nbox > 1) { /* reverse order of rects in each band */ pboxNew2 = (BoxPtr)ALLOCATE_LOCAL(sizeof(BoxRec) * nbox); pptNew2 = (DDXPointPtr)ALLOCATE_LOCAL(sizeof(DDXPointRec) * nbox); if(!pboxNew2 || !pptNew2) { if (pptNew2) DEALLOCATE_LOCAL(pptNew2); if (pboxNew2) DEALLOCATE_LOCAL(pboxNew2); if (pboxNew1) { DEALLOCATE_LOCAL(pptNew1); DEALLOCATE_LOCAL(pboxNew1); } return; } 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) { *pboxNew2++ = *--pboxTmp; *pptNew2++ = *--pptTmp; } pboxBase = pboxNext; } pboxNew2 -= nbox; pbox = pboxNew2; pptNew2 -= nbox; pptSrc = pptNew2; } } else { /* walk source left to right */ xdir = 1; } (*infoRec->ScreenToScreenBitBlt)(infoRec->pScrn, nbox, pptSrc, pbox, xdir, ydir, pGC->alu, pGC->planemask); if (pboxNew2) { DEALLOCATE_LOCAL(pptNew2); DEALLOCATE_LOCAL(pboxNew2); } if (pboxNew1) { DEALLOCATE_LOCAL(pptNew1); DEALLOCATE_LOCAL(pboxNew1); } } void XAADoImageWrite( DrawablePtr pSrc, DrawablePtr pDst, GC *pGC, RegionPtr prgnDst, DDXPointPtr pptSrc ) { int srcwidth; unsigned char* psrcBase; /* start of image */ unsigned char* srcPntr; /* index into the image */ BoxPtr pbox = REGION_RECTS(prgnDst); int nbox = REGION_NUM_RECTS(prgnDst); XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); int Bpp = pSrc->bitsPerPixel >> 3; psrcBase = (unsigned char *)((PixmapPtr)pSrc)->devPrivate.ptr; srcwidth = (int)((PixmapPtr)pSrc)->devKind; for(; nbox; pbox++, pptSrc++, nbox--) { srcPntr = psrcBase + (pptSrc->y * srcwidth) + (pptSrc->x * Bpp); (*infoRec->WritePixmap)(infoRec->pScrn, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, srcPntr, srcwidth, pGC->alu, pGC->planemask, -1, pSrc->bitsPerPixel, pSrc->depth); } } void XAADoImageRead( DrawablePtr pSrc, DrawablePtr pDst, GC *pGC, RegionPtr prgnDst, DDXPointPtr pptSrc ) { int dstwidth; unsigned char* pdstBase; /* start of image */ unsigned char* dstPntr; /* index into the image */ BoxPtr pbox = REGION_RECTS(prgnDst); int nbox = REGION_NUM_RECTS(prgnDst); XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_GC(pGC); int Bpp = pSrc->bitsPerPixel >> 3; /* wouldn't get here unless both src and dst have same bpp */ pdstBase = (unsigned char *)((PixmapPtr)pDst)->devPrivate.ptr; dstwidth = (int)((PixmapPtr)pDst)->devKind; for(; nbox; pbox++, pptSrc++, nbox--) { dstPntr = pdstBase + (pbox->y1 * dstwidth) + (pbox->x1 * Bpp); (*infoRec->ReadPixmap)(infoRec->pScrn, pptSrc->x, pptSrc->y, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1, dstPntr, dstwidth, pSrc->bitsPerPixel, pSrc->depth); } } void XAAScreenToScreenBitBlt( ScrnInfoPtr pScrn, int nbox, DDXPointPtr pptSrc, BoxPtr pbox, int xdir, int ydir, int alu, unsigned int planemask ) { XAAInfoRecPtr infoRec = GET_XAAINFORECPTR_FROM_SCRNINFOPTR(pScrn); int dirsetup; if ((!(infoRec->CopyAreaFlags & ONLY_TWO_BITBLT_DIRECTIONS) || (xdir == ydir)) && (!(infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) || (xdir == 1))) { (*infoRec->SetupForScreenToScreenCopy)(pScrn, xdir, ydir, alu, planemask, -1); for (; nbox; pbox++, pptSrc++, nbox--) (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); SET_SYNC_FLAG(infoRec); return; } if (infoRec->CopyAreaFlags & ONLY_LEFT_TO_RIGHT_BITBLT) { /* * This is the case of a chip that only supports xdir = 1, * with ydir = 1 or ydir = -1, but we have xdir = -1. */ (*infoRec->SetupForScreenToScreenCopy)(pScrn, 1, ydir, alu, planemask, -1); for (; nbox; pbox++, pptSrc++, nbox--) if (pptSrc->y != pbox->y1 || pptSrc->x >= pbox->x1) /* No problem. Do a xdir = 1 blit instead. */ (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pptSrc->x, pptSrc->y, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); else { /* * This is the difficult case. Needs striping into * non-overlapping horizontal chunks. */ int stripeWidth, w, fullStripes, extra, i; stripeWidth = 16; w = pbox->x2 - pbox->x1; if (pbox->x1 - pptSrc->x < stripeWidth) stripeWidth = pbox->x1 - pptSrc->x; fullStripes = w / stripeWidth; extra = w % stripeWidth; /* First, take care of the little bit on the far right */ if (extra) (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pptSrc->x + fullStripes * stripeWidth, pptSrc->y, pbox->x1 + fullStripes * stripeWidth, pbox->y1, extra, pbox->y2 - pbox->y1); /* Now, take care of the rest of the blit */ for (i = fullStripes - 1; i >= 0; i--) (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pptSrc->x + i * stripeWidth, pptSrc->y, pbox->x1 + i * stripeWidth, pbox->y1, stripeWidth, pbox->y2 - pbox->y1); } SET_SYNC_FLAG(infoRec); return; } /* * Now the case of a chip that only supports xdir = ydir = 1 or * xdir = ydir = -1, but we have xdir != ydir. */ dirsetup = 0; /* No direction set up yet. */ for (; nbox; pbox++, pptSrc++, nbox--) { if (xdir == 1 && pptSrc->y != pbox->y1) { /* Do a xdir = ydir = -1 blit instead. */ if (dirsetup != -1) { (*infoRec->SetupForScreenToScreenCopy)(pScrn, -1, -1, alu, planemask, -1); dirsetup = -1; } (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } else if (xdir == -1 && pptSrc->y != pbox->y1) { /* Do a xdir = ydir = 1 blit instead. */ if (dirsetup != 1) { (*infoRec->SetupForScreenToScreenCopy)(pScrn, 1, 1, alu, planemask, -1); dirsetup = 1; } (*infoRec->SubsequentScreenToScreenCopy)(pScrn,pptSrc->x, pptSrc->y, pbox->x1, pbox->y1, pbox->x2 - pbox->x1, pbox->y2 - pbox->y1); } else if (xdir == 1) { /* * xdir = 1, ydir = -1. * Perform line-by-line xdir = ydir = 1 blits, going up. */ int i; if (dirsetup != 1) { (*infoRec->SetupForScreenToScreenCopy)(pScrn, 1, 1, alu, planemask, -1); dirsetup = 1; } for (i = pbox->y2 - pbox->y1 - 1; i >= 0; i--) (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i, pbox->x2 - pbox->x1, 1); } else { /* * xdir = -1, ydir = 1. * Perform line-by-line xdir = ydir = -1 blits, going down. */ int i; if (dirsetup != -1) { (*infoRec->SetupForScreenToScreenCopy)(pScrn, -1, -1, alu, planemask, -1); dirsetup = -1; } for (i = 0; i < pbox->y2 - pbox->y1; i++) (*infoRec->SubsequentScreenToScreenCopy)(pScrn, pptSrc->x, pptSrc->y + i, pbox->x1, pbox->y1 + i, pbox->x2 - pbox->x1, 1); } } /* next box */ SET_SYNC_FLAG(infoRec); }