410 lines
16 KiB
C
410 lines
16 KiB
C
|
|
#ifdef HAVE_XORG_CONFIG_H
|
|
#include <xorg-config.h>
|
|
#endif
|
|
|
|
#include "misc.h"
|
|
#include "xf86.h"
|
|
#include "xf86_OSproc.h"
|
|
|
|
#include <X11/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 = RegionRects(prgnDst);
|
|
nbox = RegionNumRects(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) malloc(sizeof(BoxRec) * nbox);
|
|
if (!pboxNew1)
|
|
return;
|
|
pptNew1 = (DDXPointPtr) malloc(sizeof(DDXPointRec) * nbox);
|
|
if (!pptNew1) {
|
|
free(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) malloc(sizeof(BoxRec) * nbox);
|
|
pptNew2 = (DDXPointPtr) malloc(sizeof(DDXPointRec) * nbox);
|
|
if (!pboxNew2 || !pptNew2) {
|
|
free(pptNew2);
|
|
free(pboxNew2);
|
|
if (pboxNew1) {
|
|
free(pptNew1);
|
|
free(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) {
|
|
free(pptNew2);
|
|
free(pboxNew2);
|
|
}
|
|
if (pboxNew1) {
|
|
free(pptNew1);
|
|
free(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 = RegionRects(prgnDst);
|
|
int nbox = RegionNumRects(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 = RegionRects(prgnDst);
|
|
int nbox = RegionNumRects(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);
|
|
}
|