386 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /* $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);
 | |
| }
 |