TinyX/mi/mibank.c

2456 lines
66 KiB
C
Raw Normal View History

2013-11-30 13:51:10 +00:00
/*
* Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of Marc Aurele La France not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Marc Aurele La France makes no representations
* about the suitability of this software for any purpose. It is provided
* "as-is" without express or implied warranty.
*
* MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Copyright 1990,91,92,93 by Thomas Roell, Germany.
* Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA.
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation, and that the name of Thomas Roell nor
* SGCS be used in advertising or publicity pertaining to distribution
* of the software without specific, written prior permission.
* Thomas Roell nor SGCS makes no representations about the suitability
* of this software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This thing originated from an idea of Edwin Goei and his bank switching
* code for the DEC TX board.
*/
/*
* Heavily modified for the XFree86 Project to turn this into an mi wrapper.
* --- Marc Aurele La France (tsi@xfree86.org)
*/
/*
* "Heavily modified", indeed! By the time this is finalized, there probably
* won't be much left of Roell's code...
*
* Miscellaneous notes:
* - Pixels with imbedded bank boundaries are required to be off-screen. There
* >might< be a way to fool the underlying framebuffer into dealing with
* partial pixels.
* - Plans to generalise this to do (hardware) colour plane switching have been
* dropped due to colour flashing concerns.
*
* TODO:
* - Allow miModifyBanking() to change BankSize and nBankDepth.
* - Re-instate shared and double banking for framebuffers whose pixmap formats
* don't describe how the server "sees" the screen.
* - Remove remaining assumptions that a pixmap's devPrivate field points
* directly to its pixel data.
*/
/* #define NO_ALLOCA 1 */
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "servermd.h"
#include "gcstruct.h"
#include "pixmapstr.h"
#include "scrnintstr.h"
#include "windowstr.h"
#include "mi.h"
#include "mibank.h"
#define BANK_SINGLE 0
#define BANK_SHARED 1
#define BANK_DOUBLE 2
#define BANK_NOBANK 3
typedef struct _miBankScreen
{
miBankInfoRec BankInfo;
unsigned int nBankBPP;
unsigned int type;
unsigned long nBitsPerBank;
unsigned long nBitsPerScanline;
unsigned long nPixelsPerScanlinePadUnit;
PixmapPtr pScreenPixmap;
PixmapPtr pBankPixmap;
GCPtr pBankGC;
int nBanks, maxRects;
RegionPtr *pBanks;
pointer pbits;
/*
* Screen Wrappers
*/
CreateScreenResourcesProcPtr CreateScreenResources;
ModifyPixmapHeaderProcPtr ModifyPixmapHeader;
CloseScreenProcPtr CloseScreen;
GetImageProcPtr GetImage;
GetSpansProcPtr GetSpans;
CreateGCProcPtr CreateGC;
PaintWindowBackgroundProcPtr PaintWindowBackground;
PaintWindowBorderProcPtr PaintWindowBorder;
CopyWindowProcPtr CopyWindow;
} miBankScreenRec, *miBankScreenPtr;
typedef struct _miBankGC
{
GCOps *wrappedOps, *unwrappedOps;
const GCFuncs *wrappedFuncs, *unwrappedFuncs;
Bool fastCopy, fastPlane;
RegionPtr pBankedClips[1];
} miBankGCRec, *miBankGCPtr;
typedef struct _miBankQueue
{
Bool fastBlit;
unsigned short srcBankNo;
unsigned short dstBankNo;
short x;
short y;
short w;
short h;
} miBankQueue;
/*
* CAVEAT: This banking scheme requires that the DDX store Pixmap data in the
* server's address space.
*/
#define ModifyPixmap(_pPix, _width, _devKind, _pbits) \
(*pScreen->ModifyPixmapHeader)((_pPix), \
(_width), -1, -1, -1, (_devKind), (_pbits))
#define SET_SINGLE_BANK(_pPix, _width, _devKind, _no) \
ModifyPixmap(_pPix, _width, _devKind, \
(char *)pScreenPriv->BankInfo.pBankA + \
(*pScreenPriv->BankInfo.SetSourceAndDestinationBanks)(pScreen, (_no)) - \
(pScreenPriv->BankInfo.BankSize * (_no)))
#define SET_SOURCE_BANK(_pPix, _width, _devKind, _no) \
ModifyPixmap(_pPix, _width, _devKind, \
(char *)pScreenPriv->BankInfo.pBankA + \
(*pScreenPriv->BankInfo.SetSourceBank)(pScreen, (_no)) - \
(pScreenPriv->BankInfo.BankSize * (_no)))
#define SET_DESTINATION_BANK(_pPix, _width, _devKind, _no) \
ModifyPixmap(_pPix, _width, _devKind, \
(char *)pScreenPriv->BankInfo.pBankB + \
(*pScreenPriv->BankInfo.SetDestinationBank)(pScreen, (_no)) - \
(pScreenPriv->BankInfo.BankSize * (_no)))
#define ALLOCATE_LOCAL_ARRAY(atype, ntype) \
(atype *)ALLOCATE_LOCAL((ntype) * sizeof(atype))
static int miBankScreenIndex;
static int miBankGCIndex;
static unsigned long miBankGeneration = 0;
#define BANK_SCRPRIVLVAL pScreen->devPrivates[miBankScreenIndex].ptr
#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL))
#define BANK_GCPRIVLVAL(pGC) (pGC)->devPrivates[miBankGCIndex].ptr
#define BANK_GCPRIVATE(pGC) ((miBankGCPtr)(BANK_GCPRIVLVAL(pGC)))
#define PIXMAP_STATUS(_pPix) \
pointer pbits = (_pPix)->devPrivate.ptr
#define PIXMAP_SAVE(_pPix) \
PIXMAP_STATUS(_pPix); \
if (pbits == (pointer)pScreenPriv) \
(_pPix)->devPrivate.ptr = pScreenPriv->pbits
#define PIXMAP_RESTORE(_pPix) \
(_pPix)->devPrivate.ptr = pbits
#define BANK_SAVE \
int width = pScreenPriv->pBankPixmap->drawable.width; \
int devKind = pScreenPriv->pBankPixmap->devKind; \
PIXMAP_SAVE(pScreenPriv->pBankPixmap)
#define BANK_RESTORE \
pScreenPriv->pBankPixmap->drawable.width = width; \
pScreenPriv->pBankPixmap->devKind = devKind; \
PIXMAP_RESTORE(pScreenPriv->pBankPixmap)
#define SCREEN_STATUS \
PIXMAP_STATUS(pScreenPriv->pScreenPixmap)
#define SCREEN_SAVE \
PIXMAP_SAVE(pScreenPriv->pScreenPixmap)
#define SCREEN_RESTORE \
PIXMAP_RESTORE(pScreenPriv->pScreenPixmap)
#define SCREEN_INIT \
miBankScreenPtr pScreenPriv = BANK_SCRPRIVATE
#define SCREEN_UNWRAP(field) \
pScreen->field = pScreenPriv->field
#define SCREEN_WRAP(field, wrapper) \
pScreenPriv->field = pScreen->field; \
pScreen->field = wrapper
#define GC_INIT(pGC) \
miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC)
#define GC_UNWRAP(pGC) \
pGCPriv->unwrappedOps = (pGC)->ops; \
pGCPriv->unwrappedFuncs = (pGC)->funcs; \
(pGC)->ops = pGCPriv->wrappedOps; \
(pGC)->funcs = pGCPriv->wrappedFuncs
#define GC_WRAP(pGC) \
pGCPriv->wrappedOps = (pGC)->ops; \
pGCPriv->wrappedFuncs = (pGC)->funcs; \
(pGC)->ops = pGCPriv->unwrappedOps; \
(pGC)->funcs = pGCPriv->unwrappedFuncs
#define IS_BANKED(pDrawable) \
((pbits == (pointer)pScreenPriv) && \
(((DrawablePtr)(pDrawable))->type == DRAWABLE_WINDOW))
#define CLIP_SAVE \
RegionPtr pOrigCompositeClip = pGC->pCompositeClip
#define CLIP_RESTORE \
pGC->pCompositeClip = pOrigCompositeClip
#define GCOP_INIT \
ScreenPtr pScreen = pGC->pScreen; \
SCREEN_INIT; \
GC_INIT(pGC)
#define GCOP_UNWRAP \
GC_UNWRAP(pGC)
#define GCOP_WRAP \
GC_WRAP(pGC)
#define GCOP_TOP_PART \
for (i = 0; i < pScreenPriv->nBanks; i++) \
{ \
if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i])) \
continue; \
GCOP_UNWRAP; \
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i)
#define GCOP_BOTTOM_PART \
GCOP_WRAP; \
}
#define GCOP_SIMPLE(statement) \
if (nArray > 0) \
{ \
GCOP_INIT; \
SCREEN_SAVE; \
if (!IS_BANKED(pDrawable)) \
{ \
GCOP_UNWRAP; \
statement; \
GCOP_WRAP; \
} \
else \
{ \
int i; \
CLIP_SAVE; \
GCOP_TOP_PART; \
statement; \
GCOP_BOTTOM_PART; \
CLIP_RESTORE; \
} \
SCREEN_RESTORE; \
}
#define GCOP_0D_ARGS mode,
#define GCOP_1D_ARGS
#define GCOP_2D_ARGS shape, mode,
#define GCOP_COMPLEX(aop, atype) \
if (nArray > 0) \
{ \
GCOP_INIT; \
SCREEN_SAVE; \
if (!IS_BANKED(pDrawable)) \
{ \
GCOP_UNWRAP; \
(*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, pArray); \
GCOP_WRAP; \
} \
else \
{ \
atype *aarg = pArray, *acopy; \
int i; \
CLIP_SAVE; \
if ((acopy = ALLOCATE_LOCAL_ARRAY(atype, nArray))) \
aarg = acopy; \
GCOP_TOP_PART; \
if (acopy) \
memcpy(acopy, pArray, nArray * sizeof(atype)); \
(*pGC->ops->aop)(pDrawable, pGC, GCOP_ARGS nArray, aarg); \
GCOP_BOTTOM_PART; \
DEALLOCATE_LOCAL(acopy); \
CLIP_RESTORE; \
} \
SCREEN_RESTORE; \
}
/*********************
* Utility functions *
*********************/
static int
miBankOf(
miBankScreenPtr pScreenPriv,
int x,
int y
)
{
int iBank = ((x * (int)pScreenPriv->nBankBPP) +
(y * (long)pScreenPriv->nBitsPerScanline)) /
(long)pScreenPriv->nBitsPerBank;
if (iBank < 0)
iBank = 0;
else if (iBank >= pScreenPriv->nBanks)
iBank = pScreenPriv->nBanks - 1;
return iBank;
}
#define FirstBankOf(_x, _y) miBankOf(pScreenPriv, (_x), (_y))
#define LastBankOf(_x, _y) miBankOf(pScreenPriv, (_x) - 1, (_y))
/* Determine banking type from the BankInfoRec */
static unsigned int
miBankDeriveType(
ScreenPtr pScreen,
miBankInfoPtr pBankInfo
)
{
unsigned int type;
if (pBankInfo->pBankA == pBankInfo->pBankB)
{
if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
{
if (pBankInfo->SetSourceAndDestinationBanks !=
pBankInfo->SetSourceBank)
return BANK_NOBANK;
type = BANK_SINGLE;
}
else
{
if (pBankInfo->SetSourceAndDestinationBanks ==
pBankInfo->SetDestinationBank)
return BANK_NOBANK;
if (pBankInfo->SetSourceAndDestinationBanks ==
pBankInfo->SetSourceBank)
return BANK_NOBANK;
type = BANK_SHARED;
}
}
else
{
if ((unsigned long)abs((char *)pBankInfo->pBankA -
(char *)pBankInfo->pBankB) < pBankInfo->BankSize)
return BANK_NOBANK;
if (pBankInfo->SetSourceBank == pBankInfo->SetDestinationBank)
{
if (pBankInfo->SetSourceAndDestinationBanks !=
pBankInfo->SetSourceBank)
return BANK_NOBANK;
}
else
{
if (pBankInfo->SetSourceAndDestinationBanks ==
pBankInfo->SetDestinationBank)
return BANK_NOBANK;
}
type = BANK_DOUBLE;
}
/*
* Internal limitation: Currently, only single banking is supported when
* the pixmap format and the screen's pixel format are different. The
* following test is only partially successful at detecting this condition.
*/
if (pBankInfo->nBankDepth != pScreen->rootDepth)
type = BANK_SINGLE;
return type;
}
/* Least common multiple */
static unsigned int
miLCM(
unsigned int x,
unsigned int y
)
{
unsigned int m = x, n = y, o;
while ((o = m % n))
{
m = n;
n = o;
}
return (x / n) * y;
}
/******************
* GCOps wrappers *
******************/
static void
miBankFillSpans(
DrawablePtr pDrawable,
GCPtr pGC,
int nArray,
DDXPointPtr pptInit,
int *pwidthInit,
int fSorted
)
{
GCOP_SIMPLE((*pGC->ops->FillSpans)(pDrawable, pGC,
nArray, pptInit, pwidthInit, fSorted));
}
static void
miBankSetSpans(
DrawablePtr pDrawable,
GCPtr pGC,
char *psrc,
DDXPointPtr ppt,
int *pwidth,
int nArray,
int fSorted
)
{
GCOP_SIMPLE((*pGC->ops->SetSpans)(pDrawable, pGC, psrc,
ppt, pwidth, nArray, fSorted));
}
static void
miBankPutImage(
DrawablePtr pDrawable,
GCPtr pGC,
int depth,
int x,
int y,
int w,
int h,
int leftPad,
int format,
char *pImage
)
{
if ((w > 0) && (h > 0))
{
GCOP_INIT;
SCREEN_SAVE;
if (!IS_BANKED(pDrawable))
{
GCOP_UNWRAP;
(*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
leftPad, format, pImage);
GCOP_WRAP;
}
else
{
int i, j;
CLIP_SAVE;
i = FirstBankOf(x + pDrawable->x, y + pDrawable->y);
j = LastBankOf(x + pDrawable->x + w, y + pDrawable->y + h);
for (; i <= j; i++)
{
if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[i]))
continue;
GCOP_UNWRAP;
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, i);
(*pGC->ops->PutImage)(pDrawable, pGC, depth, x, y, w, h,
leftPad, format, pImage);
GCOP_WRAP;
}
CLIP_RESTORE;
}
SCREEN_RESTORE;
}
}
/*
* Here the CopyArea/CopyPlane wrappers. First off, we have to clip against
* the source in order to make the minimal number of copies in case of slow
* systems. Also the exposure handling is quite tricky. Special attention
* is to be given to the way the copies are sequenced. The list of boxes after
* the source clip is used to build a workqueue, that contains the atomic
* copies (i.e. only from one bank to one bank). Doing so produces a minimal
* list of things to do.
*/
static RegionPtr
miBankCopy(
DrawablePtr pSrc,
DrawablePtr pDst,
GCPtr pGC,
int srcx,
int srcy,
int w,
int h,
int dstx,
int dsty,
unsigned long plane,
Bool SinglePlane
)
{
int cx1, cy1, cx2, cy2;
int ns, nd, nse, nde, dx, dy, xorg = 0, yorg = 0;
int maxWidth = 0, maxHeight = 0, paddedWidth = 0;
int nBox, nBoxClipSrc, nBoxClipDst, nQueue;
BoxPtr pBox, pBoxClipSrc, pBoxClipDst;
BoxRec fastBox, ccBox;
RegionPtr ret = NULL, prgnSrcClip = NULL;
RegionRec rgnDst;
char *pImage = NULL;
miBankQueue *pQueue, *pQueueNew, *Queue;
miBankQueue *pQueueTmp, *pQueueNext, *pQueueBase;
Bool fastBlit, freeSrcClip, fastClip;
Bool fExpose = FALSE, fastExpose = FALSE;
GCOP_INIT;
SCREEN_SAVE;
if (!IS_BANKED(pSrc) && !IS_BANKED(pDst))
{
GCOP_UNWRAP;
if (SinglePlane)
ret = (*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
srcx, srcy, w, h, dstx, dsty, plane);
else
ret = (*pGC->ops->CopyArea)(pSrc, pDst, pGC,
srcx, srcy, w, h, dstx, dsty);
GCOP_WRAP;
}
else if (!IS_BANKED(pDst))
{
fExpose = pGC->fExpose;
pGC->fExpose = FALSE;
xorg = pSrc->x;
yorg = pSrc->y;
dx = dstx - srcx;
dy = dsty - srcy;
srcx += xorg;
srcy += yorg;
ns = FirstBankOf(srcx, srcy);
nse = LastBankOf(srcx + w, srcy + h);
for (; ns <= nse; ns++)
{
if (!pScreenPriv->pBanks[ns])
continue;
nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
pBox = REGION_RECTS(pScreenPriv->pBanks[ns]);
for (; nBox--; pBox++)
{
cx1 = max(pBox->x1, srcx);
cy1 = max(pBox->y1, srcy);
cx2 = min(pBox->x2, srcx + w);
cy2 = min(pBox->y2, srcy + h);
if ((cx1 >= cx2) || (cy1 >= cy2))
continue;
GCOP_UNWRAP;
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, ns);
if (SinglePlane)
(*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
cx1 - xorg, cy1 - yorg,
cx2 - cx1, cy2 - cy1,
cx1 + dx - xorg, cy1 + dy - yorg, plane);
else
(*pGC->ops->CopyArea)(pSrc, pDst, pGC,
cx1 - xorg, cy1 - yorg,
cx2 - cx1, cy2 - cy1,
cx1 + dx - xorg, cy1 + dy - yorg);
GCOP_WRAP;
}
}
pGC->fExpose = fExpose;
srcx -= xorg;
srcy -= yorg;
}
else if (!IS_BANKED(pSrc))
{
CLIP_SAVE;
if (pGC->miTranslate)
{
xorg = pDst->x;
yorg = pDst->y;
}
dx = srcx - dstx;
dy = srcy - dsty;
dstx += xorg;
dsty += yorg;
nd = FirstBankOf(dstx, dsty);
nde = LastBankOf(dstx + w, dsty + h);
for (; nd <= nde; nd++)
{
if (!(pGC->pCompositeClip = pGCPriv->pBankedClips[nd]))
continue;
/*
* It's faster to let the lower-level CopyArea do the clipping
* within each bank.
*/
nBox = REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
pBox = REGION_RECTS(pScreenPriv->pBanks[nd]);
for (; nBox--; pBox++)
{
cx1 = max(pBox->x1, dstx);
cy1 = max(pBox->y1, dsty);
cx2 = min(pBox->x2, dstx + w);
cy2 = min(pBox->y2, dsty + h);
if ((cx1 >= cx2) || (cy1 >= cy2))
continue;
GCOP_UNWRAP;
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap, -1, -1, nd);
if (SinglePlane)
(*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
cx1 + dx - xorg, cy1 + dy - yorg,
cx2 - cx1, cy2 - cy1,
cx1 - xorg, cy1 - yorg, plane);
else
(*pGC->ops->CopyArea)(pSrc, pDst, pGC,
cx1 + dx - xorg, cy1 + dy - yorg,
cx2 - cx1, cy2 - cy1,
cx1 - xorg, cy1 - yorg);
GCOP_WRAP;
}
}
CLIP_RESTORE;
}
else /* IS_BANKED(pSrc) && IS_BANKED(pDst) */
{
CLIP_SAVE;
fExpose = pGC->fExpose;
fastBox.x1 = srcx + pSrc->x;
fastBox.y1 = srcy + pSrc->y;
fastBox.x2 = fastBox.x1 + w;
fastBox.y2 = fastBox.y1 + h;
dx = dstx - fastBox.x1;
dy = dsty - fastBox.y1;
if (pGC->miTranslate)
{
xorg = pDst->x;
yorg = pDst->y;
}
/*
* Clip against the source. Otherwise we will blit too much for SINGLE
* and SHARED banked systems.
*/
freeSrcClip = FALSE;
fastClip = FALSE;
fastExpose = FALSE;
if (pGC->subWindowMode != IncludeInferiors)
prgnSrcClip = &((WindowPtr)pSrc)->clipList;
else if (!((WindowPtr)pSrc)->parent)
fastClip = TRUE;
else if ((pSrc == pDst) && (pGC->clientClipType == CT_NONE))
prgnSrcClip = pGC->pCompositeClip;
else
{
prgnSrcClip = NotClippedByChildren((WindowPtr)pSrc);
freeSrcClip = TRUE;
}
if (fastClip)
{
fastExpose = TRUE;
/*
* Clip the source. If regions extend beyond the source size, make
* sure exposure events get sent.
*/
if (fastBox.x1 < pSrc->x)
{
fastBox.x1 = pSrc->x;
fastExpose = FALSE;
}
if (fastBox.y1 < pSrc->y)
{
fastBox.y1 = pSrc->y;
fastExpose = FALSE;
}
if (fastBox.x2 > pSrc->x + (int) pSrc->width)
{
fastBox.x2 = pSrc->x + (int) pSrc->width;
fastExpose = FALSE;
}
if (fastBox.y2 > pSrc->y + (int) pSrc->height)
{
fastBox.y2 = pSrc->y + (int) pSrc->height;
fastExpose = FALSE;
}
nBox = 1;
pBox = &fastBox;
}
else
{
REGION_INIT(&rgnDst, &fastBox, 1);
REGION_INTERSECT(&rgnDst, &rgnDst, prgnSrcClip);
pBox = REGION_RECTS(&rgnDst);
nBox = REGION_NUM_RECTS(&rgnDst);
}
/*
* fastBlit can only be TRUE if we don't need to worry about attempts
* to read partial pixels through the destination bank.
*/
if (SinglePlane)
fastBlit = pGCPriv->fastPlane;
else
fastBlit = pGCPriv->fastCopy;
nQueue = nBox * pScreenPriv->maxRects * 2;
pQueue = Queue = ALLOCATE_LOCAL_ARRAY(miBankQueue, nQueue);
if (Queue)
{
for (; nBox--; pBox++)
{
ns = FirstBankOf(pBox->x1, pBox->y1);
nse = LastBankOf(pBox->x2, pBox->y2);
for (; ns <= nse; ns++)
{
if (!pScreenPriv->pBanks[ns])
continue;
nBoxClipSrc = REGION_NUM_RECTS(pScreenPriv->pBanks[ns]);
pBoxClipSrc = REGION_RECTS(pScreenPriv->pBanks[ns]);
for (; nBoxClipSrc--; pBoxClipSrc++)
{
cx1 = max(pBox->x1, pBoxClipSrc->x1);
cy1 = max(pBox->y1, pBoxClipSrc->y1);
cx2 = min(pBox->x2, pBoxClipSrc->x2);
cy2 = min(pBox->y2, pBoxClipSrc->y2);
/* Check to see if the region is empty */
if ((cx1 >= cx2) || (cy1 >= cy2))
continue;
/* Translate c[xy]* to destination coordinates */
cx1 += dx + xorg;
cy1 += dy + yorg;
cx2 += dx + xorg;
cy2 += dy + yorg;
nd = FirstBankOf(cx1, cy1);
nde = LastBankOf(cx2, cy2);
for (; nd <= nde; nd++)
{
if (!pGCPriv->pBankedClips[nd])
continue;
/*
* Clients can send quite large clip descriptions,
* so use the bank clips here instead.
*/
nBoxClipDst =
REGION_NUM_RECTS(pScreenPriv->pBanks[nd]);
pBoxClipDst =
REGION_RECTS(pScreenPriv->pBanks[nd]);
for (; nBoxClipDst--; pBoxClipDst++)
{
ccBox.x1 = max(cx1, pBoxClipDst->x1);
ccBox.y1 = max(cy1, pBoxClipDst->y1);
ccBox.x2 = min(cx2, pBoxClipDst->x2);
ccBox.y2 = min(cy2, pBoxClipDst->y2);
/* Check to see if the region is empty */
if ((ccBox.x1 >= ccBox.x2) ||
(ccBox.y1 >= ccBox.y2))
continue;
pQueue->srcBankNo = ns;
pQueue->dstBankNo = nd;
pQueue->x = ccBox.x1 - xorg;
pQueue->y = ccBox.y1 - yorg;
pQueue->w = ccBox.x2 - ccBox.x1;
pQueue->h = ccBox.y2 - ccBox.y1;
if (maxWidth < pQueue->w)
maxWidth = pQueue->w;
if (maxHeight < pQueue->h)
maxHeight = pQueue->h;
/*
* When shared banking is used and the source
* and destination banks differ, prevent
* attempts to fetch partial scanline pad units
* through the destination bank.
*/
pQueue->fastBlit = fastBlit;
if (fastBlit &&
(pScreenPriv->type == BANK_SHARED) &&
(ns != nd) &&
((ccBox.x1 %
pScreenPriv->nPixelsPerScanlinePadUnit) ||
(ccBox.x2 %
pScreenPriv->nPixelsPerScanlinePadUnit) ||
(RECT_IN_REGION(
pGCPriv->pBankedClips[nd], &ccBox) !=
rgnIN)))
pQueue->fastBlit = FALSE;
pQueue++;
}
}
}
}
}
}
if (!fastClip)
{
REGION_UNINIT(&rgnDst);
if (freeSrcClip)
REGION_DESTROY(prgnSrcClip);
}
pQueueNew = pQueue;
nQueue = pQueue - Queue;
if (nQueue > 0)
{
BANK_SAVE;
pQueue = Queue;
if ((nQueue > 1) &&
((pSrc == pDst) || (pGC->subWindowMode == IncludeInferiors)))
{
if ((srcy + pSrc->y) < (dsty + yorg))
{
/* Sort from bottom to top */
pQueueBase = pQueueNext = pQueue + nQueue - 1;
while (pQueueBase >= pQueue)
{
while ((pQueueNext >= pQueue) &&
(pQueueBase->y == pQueueNext->y))
pQueueNext--;
pQueueTmp = pQueueNext + 1;
while (pQueueTmp <= pQueueBase)
*pQueueNew++ = *pQueueTmp++;
pQueueBase = pQueueNext;
}
pQueueNew -= nQueue;
pQueue = pQueueNew;
pQueueNew = Queue;
}
if ((srcx + pSrc->x) < (dstx + xorg))
{
/* Sort from right to left */
pQueueBase = pQueueNext = pQueue;
while (pQueueBase < pQueue + nQueue)
{
while ((pQueueNext < pQueue + nQueue) &&
(pQueueNext->y == pQueueBase->y))
pQueueNext++;
pQueueTmp = pQueueNext;
while (pQueueTmp != pQueueBase)
*pQueueNew++ = *--pQueueTmp;
pQueueBase = pQueueNext;
}
pQueueNew -= nQueue;
pQueue = pQueueNew;
}
}
paddedWidth = PixmapBytePad(maxWidth,
pScreenPriv->pScreenPixmap->drawable.depth);
pImage = (char *)ALLOCATE_LOCAL(paddedWidth * maxHeight);
pGC->fExpose = FALSE;
while (nQueue--)
{
pGC->pCompositeClip = pGCPriv->pBankedClips[pQueue->dstBankNo];
GCOP_UNWRAP;
if (pQueue->srcBankNo == pQueue->dstBankNo)
{
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
-1, -1, pQueue->srcBankNo);
if (SinglePlane)
(*pGC->ops->CopyPlane)(pSrc, pDst, pGC,
pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
else
(*pGC->ops->CopyArea)(pSrc, pDst, pGC,
pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
pQueue->w, pQueue->h, pQueue->x, pQueue->y);
}
else if (pQueue->fastBlit)
{
SET_SOURCE_BANK (pScreenPriv->pBankPixmap,
pScreenPriv->pScreenPixmap->drawable.width,
pScreenPriv->pScreenPixmap->devKind,
pQueue->srcBankNo);
SET_DESTINATION_BANK(pScreenPriv->pScreenPixmap,
-1, -1, pQueue->dstBankNo);
if (SinglePlane)
(*pGC->ops->CopyPlane)(
(DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
pQueue->x - dx, pQueue->y - dy,
pQueue->w, pQueue->h, pQueue->x, pQueue->y, plane);
else
(*pGC->ops->CopyArea)(
(DrawablePtr)pScreenPriv->pBankPixmap, pDst, pGC,
pQueue->x - dx, pQueue->y - dy,
pQueue->w, pQueue->h, pQueue->x, pQueue->y);
}
else if (pImage)
{
ModifyPixmap(pScreenPriv->pBankPixmap,
maxWidth, paddedWidth, pImage);
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
-1, -1, pQueue->srcBankNo);
(*pScreenPriv->pBankGC->ops->CopyArea)(
pSrc, (DrawablePtr)pScreenPriv->pBankPixmap,
pScreenPriv->pBankGC,
pQueue->x - dx - pSrc->x, pQueue->y - dy - pSrc->y,
pQueue->w, pQueue->h, 0, 0);
SET_SINGLE_BANK(pScreenPriv->pScreenPixmap,
-1, -1, pQueue->dstBankNo);
if (SinglePlane)
(*pGC->ops->CopyPlane)(
(DrawablePtr)pScreenPriv->pBankPixmap,
pDst, pGC, 0, 0, pQueue->w, pQueue->h,
pQueue->x, pQueue->y, plane);
else
(*pGC->ops->CopyArea)(
(DrawablePtr)pScreenPriv->pBankPixmap,
pDst, pGC, 0, 0, pQueue->w, pQueue->h,
pQueue->x, pQueue->y);
}
GCOP_WRAP;
pQueue++;
}
DEALLOCATE_LOCAL(pImage);
BANK_RESTORE;
}
CLIP_RESTORE;
pGC->fExpose = fExpose;
DEALLOCATE_LOCAL(Queue);
}
SCREEN_RESTORE;
if (!fExpose || fastExpose)
return ret;
return miHandleExposures(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0);
}
static RegionPtr
miBankCopyArea(
DrawablePtr pSrc,
DrawablePtr pDst,
GCPtr pGC,
int srcx,
int srcy,
int w,
int h,
int dstx,
int dsty
)
{
return miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, 0, FALSE);
}
static RegionPtr
miBankCopyPlane(
DrawablePtr pSrc,
DrawablePtr pDst,
GCPtr pGC,
int srcx,
int srcy,
int w,
int h,
int dstx,
int dsty,
unsigned long plane
)
{
return
miBankCopy(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, dsty, plane, TRUE);
}
static void
miBankPolyPoint(
DrawablePtr pDrawable,
GCPtr pGC,
int mode,
int nArray,
xPoint *pArray
)
{
# define GCOP_ARGS GCOP_0D_ARGS
GCOP_COMPLEX(PolyPoint, xPoint);
# undef GCOP_ARGS
}
static void
miBankPolylines(
DrawablePtr pDrawable,
GCPtr pGC,
int mode,
int nArray,
DDXPointPtr pArray
)
{
# define GCOP_ARGS GCOP_0D_ARGS
GCOP_COMPLEX(Polylines, DDXPointRec);
# undef GCOP_ARGS
}
static void
miBankPolySegment(
DrawablePtr pDrawable,
GCPtr pGC,
int nArray,
xSegment *pArray
)
{
# define GCOP_ARGS GCOP_1D_ARGS
GCOP_COMPLEX(PolySegment, xSegment);
# undef GCOP_ARGS
}
static void
miBankPolyRectangle(
DrawablePtr pDrawable,
GCPtr pGC,
int nArray,
xRectangle *pArray
)
{
# define GCOP_ARGS GCOP_1D_ARGS
GCOP_COMPLEX(PolyRectangle, xRectangle);
# undef GCOP_ARGS
}
static void
miBankPolyArc(
DrawablePtr pDrawable,
GCPtr pGC,
int nArray,
xArc *pArray
)
{
# define GCOP_ARGS GCOP_1D_ARGS
GCOP_COMPLEX(PolyArc, xArc);
# undef GCOP_ARGS
}
static void
miBankFillPolygon(
DrawablePtr pDrawable,
GCPtr pGC,
int shape,
int mode,
int nArray,
DDXPointRec *pArray
)
{
# define GCOP_ARGS GCOP_2D_ARGS
GCOP_COMPLEX(FillPolygon, DDXPointRec);
# undef GCOP_ARGS
}
static void
miBankPolyFillRect(