2315 lines
63 KiB
C
2315 lines
63 KiB
C
/*
|
|
* 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:
|
|
* - 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;
|
|
CopyWindowProcPtr CopyWindow;
|
|
} miBankScreenRec, *miBankScreenPtr;
|
|
|
|
typedef struct _miBankGC
|
|
{
|
|
GCOps *wrappedOps, *unwrappedOps;
|
|
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 xalloc_ARRAY(atype, ntype) xalloc((ntype) * sizeof(atype))
|
|
|
|
static int miBankScreenKeyIndex;
|
|
static DevPrivateKey miBankScreenKey = &miBankScreenKeyIndex;
|
|
static int miBankGCKeyIndex;
|
|
static DevPrivateKey miBankGCKey = &miBankGCKeyIndex;
|
|
|
|
static unsigned long miBankGeneration = 0;
|
|
|
|
#define BANK_SCRPRIVLVAL dixLookupPrivate(&pScreen->devPrivates, miBankScreenKey)
|
|
|
|
#define BANK_SCRPRIVATE ((miBankScreenPtr)(BANK_SCRPRIVLVAL))
|
|
|
|
#define BANK_GCPRIVLVAL(pGC) dixLookupPrivate(&(pGC)->devPrivates, miBankGCKey)
|
|
|
|
#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 = xalloc_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; \
|
|
xfree(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(pScreen, &rgnDst, &fastBox, 1);
|
|
REGION_INTERSECT(pScreen, &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 = xalloc_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(pScreen,
|
|
pGCPriv->pBankedClips[nd], &ccBox) !=
|
|
rgnIN)))
|
|
pQueue->fastBlit = FALSE;
|
|
pQueue++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!fastClip)
|
|
{
|
|
REGION_UNINIT(pScreen, &rgnDst);
|
|
if (freeSrcClip)
|
|
REGION_DESTROY(pScreen, 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 = xalloc(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++;
|
|
}
|
|
|
|
xfree(pImage);
|
|
|
|
BANK_RESTORE;
|
|
}
|
|
|
|
CLIP_RESTORE;
|
|
|
|
pGC->fExpose = fExpose;
|
|
|
|
xfree(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(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int nArray,
|
|
xRectangle *pArray
|
|
)
|
|
{
|
|
# define GCOP_ARGS GCOP_1D_ARGS
|
|
GCOP_COMPLEX(PolyFillRect, xRectangle);
|
|
# undef GCOP_ARGS
|
|
}
|
|
|
|
static void
|
|
miBankPolyFillArc(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int nArray,
|
|
xArc *pArray
|
|
)
|
|
{
|
|
# define GCOP_ARGS GCOP_1D_ARGS
|
|
GCOP_COMPLEX(PolyFillArc, xArc);
|
|
# undef GCOP_ARGS
|
|
}
|
|
|
|
static int
|
|
miBankPolyText8(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
int nArray,
|
|
char *pchar
|
|
)
|
|
{
|
|
int retval = x;
|
|
|
|
GCOP_SIMPLE(retval =
|
|
(*pGC->ops->PolyText8)(pDrawable, pGC, x, y, nArray, pchar));
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int
|
|
miBankPolyText16(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
int nArray,
|
|
unsigned short *pchar
|
|
)
|
|
{
|
|
int retval = x;
|
|
|
|
GCOP_SIMPLE(retval =
|
|
(*pGC->ops->PolyText16)(pDrawable, pGC, x, y, nArray, pchar));
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void
|
|
miBankImageText8(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
int nArray,
|
|
char *pchar
|
|
)
|
|
{
|
|
GCOP_SIMPLE((*pGC->ops->ImageText8)(pDrawable, pGC, x, y, nArray, pchar));
|
|
}
|
|
|
|
static void
|
|
miBankImageText16(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
int nArray,
|
|
unsigned short *pchar
|
|
)
|
|
{
|
|
GCOP_SIMPLE((*pGC->ops->ImageText16)(pDrawable, pGC, x, y, nArray, pchar));
|
|
}
|
|
|
|
static void
|
|
miBankImageGlyphBlt(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
unsigned int nArray,
|
|
CharInfoPtr *ppci,
|
|
pointer pglyphBase
|
|
)
|
|
{
|
|
GCOP_SIMPLE((*pGC->ops->ImageGlyphBlt)(pDrawable, pGC,
|
|
x, y, nArray, ppci, pglyphBase));
|
|
}
|
|
|
|
static void
|
|
miBankPolyGlyphBlt(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
unsigned int nArray,
|
|
CharInfoPtr *ppci,
|
|
pointer pglyphBase
|
|
)
|
|
{
|
|
GCOP_SIMPLE((*pGC->ops->PolyGlyphBlt)(pDrawable, pGC,
|
|
x, y, nArray, ppci, pglyphBase));
|
|
}
|
|
|
|
static void
|
|
miBankPushPixels(
|
|
GCPtr pGC,
|
|
PixmapPtr pBitmap,
|
|
DrawablePtr pDrawable,
|
|
int w,
|
|
int h,
|
|
int x,
|
|
int y
|
|
)
|
|
{
|
|
if ((w > 0) && (h > 0))
|
|
{
|
|
GCOP_INIT;
|
|
SCREEN_SAVE;
|
|
|
|
if (!IS_BANKED(pDrawable))
|
|
{
|
|
GCOP_UNWRAP;
|
|
|
|
(*pGC->ops->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
|
|
|
|
GCOP_WRAP;
|
|
}
|
|
else
|
|
{
|
|
int i, j;
|
|
|
|
CLIP_SAVE;
|
|
|
|
i = FirstBankOf(x, y);
|
|
j = LastBankOf(x + w, 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->PushPixels)(pGC, pBitmap, pDrawable, w, h, x, y);
|
|
|
|
GCOP_WRAP;
|
|
}
|
|
|
|
CLIP_RESTORE;
|
|
}
|
|
|
|
SCREEN_RESTORE;
|
|
}
|
|
}
|
|
|
|
static GCOps miBankGCOps =
|
|
{
|
|
miBankFillSpans,
|
|
miBankSetSpans,
|
|
miBankPutImage,
|
|
miBankCopyArea,
|
|
miBankCopyPlane,
|
|
miBankPolyPoint,
|
|
miBankPolylines,
|
|
miBankPolySegment,
|
|
miBankPolyRectangle,
|
|
miBankPolyArc,
|
|
miBankFillPolygon,
|
|
miBankPolyFillRect,
|
|
miBankPolyFillArc,
|
|
miBankPolyText8,
|
|
miBankPolyText16,
|
|
miBankImageText8,
|
|
miBankImageText16,
|
|
miBankImageGlyphBlt,
|
|
miBankPolyGlyphBlt,
|
|
miBankPushPixels,
|
|
{NULL} /* devPrivate */
|
|
};
|
|
|
|
/********************
|
|
* GCFuncs wrappers *
|
|
********************/
|
|
|
|
static void
|
|
miBankValidateGC(
|
|
GCPtr pGC,
|
|
unsigned long changes,
|
|
DrawablePtr pDrawable
|
|
)
|
|
{
|
|
GC_INIT(pGC);
|
|
GC_UNWRAP(pGC);
|
|
|
|
(*pGC->funcs->ValidateGC)(pGC, changes, pDrawable);
|
|
|
|
if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
|
|
(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)))
|
|
{
|
|
ScreenPtr pScreen = pGC->pScreen;
|
|
RegionPtr prgnClip;
|
|
unsigned long planemask;
|
|
int i;
|
|
|
|
SCREEN_INIT;
|
|
SCREEN_SAVE;
|
|
|
|
if (IS_BANKED(pDrawable))
|
|
{
|
|
for (i = 0; i < pScreenPriv->nBanks; i++)
|
|
{
|
|
if (!pScreenPriv->pBanks[i])
|
|
continue;
|
|
|
|
if (!(prgnClip = pGCPriv->pBankedClips[i]))
|
|
prgnClip = REGION_CREATE(pScreen, NULL, 1);
|
|
|
|
REGION_INTERSECT(pScreen, prgnClip,
|
|
pScreenPriv->pBanks[i], pGC->pCompositeClip);
|
|
|
|
if ((REGION_NUM_RECTS(prgnClip) <= 1) &&
|
|
((prgnClip->extents.x1 == prgnClip->extents.x2) ||
|
|
(prgnClip->extents.y1 == prgnClip->extents.y2)))
|
|
{
|
|
REGION_DESTROY(pScreen, prgnClip);
|
|
pGCPriv->pBankedClips[i] = NULL;
|
|
}
|
|
else
|
|
pGCPriv->pBankedClips[i] = prgnClip;
|
|
}
|
|
|
|
/*
|
|
* fastCopy and fastPlane can only be TRUE if we don't need to
|
|
* worry about attempts to read partial pixels through the
|
|
* destination bank.
|
|
*/
|
|
switch (pScreenPriv->type)
|
|
{
|
|
case BANK_SHARED:
|
|
pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
|
|
|
|
if ((pGC->alu != GXclear) && (pGC->alu != GXcopy) &&
|
|
(pGC->alu != GXcopyInverted) && (pGC->alu != GXset))
|
|
break;
|
|
|
|
if (pScreen->rootDepth == 1)
|
|
pGCPriv->fastPlane = TRUE;
|
|
|
|
/* This is probably paranoia */
|
|
if ((pDrawable->depth != pScreen->rootDepth) ||
|
|
(pDrawable->depth != pGC->depth))
|
|
break;
|
|
|
|
planemask = (1 << pGC->depth) - 1;
|
|
if ((pGC->planemask & planemask) == planemask)
|
|
pGCPriv->fastCopy = TRUE;
|
|
|
|
break;
|
|
|
|
case BANK_DOUBLE:
|
|
pGCPriv->fastCopy = pGCPriv->fastPlane = TRUE;
|
|
break;
|
|
|
|
default:
|
|
pGCPriv->fastCopy = pGCPriv->fastPlane = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Here we are on a pixmap and don't need all that special clipping
|
|
* stuff, hence free it.
|
|
*/
|
|
for (i = 0; i < pScreenPriv->nBanks; i++)
|
|
{
|
|
if (!pGCPriv->pBankedClips[i])
|
|
continue;
|
|
|
|
REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
|
|
pGCPriv->pBankedClips[i] = NULL;
|
|
}
|
|
}
|
|
|
|
SCREEN_RESTORE;
|
|
}
|
|
|
|
GC_WRAP(pGC);
|
|
}
|
|
|
|
static void
|
|
miBankChangeGC(
|
|
GCPtr pGC,
|
|
unsigned long mask
|
|
)
|
|
{
|
|
GC_INIT(pGC);
|
|
GC_UNWRAP(pGC);
|
|
|
|
(*pGC->funcs->ChangeGC)(pGC, mask);
|
|
|
|
GC_WRAP(pGC);
|
|
}
|
|
|
|
static void
|
|
miBankCopyGC(
|
|
GCPtr pGCSrc,
|
|
unsigned long mask,
|
|
GCPtr pGCDst
|
|
)
|
|
{
|
|
GC_INIT(pGCDst);
|
|
GC_UNWRAP(pGCDst);
|
|
|
|
(*pGCDst->funcs->CopyGC)(pGCSrc, mask, pGCDst);
|
|
|
|
GC_WRAP(pGCDst);
|
|
}
|
|
|
|
static void
|
|
miBankDestroyGC(
|
|
GCPtr pGC
|
|
)
|
|
{
|
|
ScreenPtr pScreen = pGC->pScreen;
|
|
int i;
|
|
|
|
SCREEN_INIT;
|
|
GC_INIT(pGC);
|
|
GC_UNWRAP(pGC);
|
|
|
|
(*pGC->funcs->DestroyGC)(pGC);
|
|
|
|
for (i = 0; i < pScreenPriv->nBanks; i++)
|
|
{
|
|
if (!pGCPriv->pBankedClips[i])
|
|
continue;
|
|
|
|
REGION_DESTROY(pScreen, pGCPriv->pBankedClips[i]);
|
|
pGCPriv->pBankedClips[i] = NULL;
|
|
}
|
|
|
|
GC_WRAP(pGC);
|
|
}
|
|
|
|
static void
|
|
miBankChangeClip(
|
|
GCPtr pGC,
|
|
int type,
|
|
pointer pvalue,
|
|
int nrects
|
|
)
|
|
{
|
|
GC_INIT(pGC);
|
|
GC_UNWRAP(pGC);
|
|
|
|
(*pGC->funcs->ChangeClip)(pGC, type, pvalue, nrects);
|
|
|
|
GC_WRAP(pGC);
|
|
}
|
|
|
|
static void
|
|
miBankDestroyClip(
|
|
GCPtr pGC
|
|
)
|
|
{
|
|
GC_INIT(pGC);
|
|
GC_UNWRAP(pGC);
|
|
|
|
(*pGC->funcs->DestroyClip)(pGC);
|
|
|
|
GC_WRAP(pGC);
|
|
}
|
|
|
|
static void
|
|
miBankCopyClip(
|
|
GCPtr pGCDst,
|
|
GCPtr pGCSrc
|
|
)
|
|
{
|
|
GC_INIT(pGCDst);
|
|
GC_UNWRAP(pGCDst);
|
|
|
|
(*pGCDst->funcs->CopyClip)(pGCDst, pGCSrc);
|
|
|
|
GC_WRAP(pGCDst);
|
|
}
|
|
|
|
static GCFuncs miBankGCFuncs =
|
|
{
|
|
miBankValidateGC,
|
|
miBankChangeGC,
|
|
miBankCopyGC,
|
|
miBankDestroyGC,
|
|
miBankChangeClip,
|
|
miBankDestroyClip,
|
|
miBankCopyClip
|
|
};
|
|
|
|
/*******************
|
|
* Screen Wrappers *
|
|
*******************/
|
|
|
|
static Bool
|
|
miBankCreateScreenResources(
|
|
ScreenPtr pScreen
|
|
)
|
|
{
|
|
Bool retval;
|
|
|
|
SCREEN_INIT;
|
|
SCREEN_UNWRAP(CreateScreenResources);
|
|
|
|
if ((retval = (*pScreen->CreateScreenResources)(pScreen)))
|
|
{
|
|
/* Set screen buffer address to something recognizable */
|
|
pScreenPriv->pScreenPixmap = (*pScreen->GetScreenPixmap)(pScreen);
|
|
pScreenPriv->pbits = pScreenPriv->pScreenPixmap->devPrivate.ptr;
|
|
pScreenPriv->pScreenPixmap->devPrivate.ptr = (pointer)pScreenPriv;
|
|
|
|
/* Get shadow pixmap; width & height of 0 means no pixmap data */
|
|
pScreenPriv->pBankPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0,
|
|
pScreenPriv->pScreenPixmap->drawable.depth, 0);
|
|
if (!pScreenPriv->pBankPixmap)
|
|
retval = FALSE;
|
|
}
|
|
|
|
/* Shadow the screen */
|
|
if (retval)
|
|
retval = (*pScreen->ModifyPixmapHeader)(pScreenPriv->pBankPixmap,
|
|
pScreenPriv->pScreenPixmap->drawable.width,
|
|
pScreenPriv->pScreenPixmap->drawable.height,
|
|
pScreenPriv->pScreenPixmap->drawable.depth,
|
|
pScreenPriv->pScreenPixmap->drawable.bitsPerPixel,
|
|
pScreenPriv->pScreenPixmap->devKind, NULL);
|
|
|
|
/* Create shadow GC */
|
|
if (retval)
|
|
{
|
|
pScreenPriv->pBankGC = CreateScratchGC(pScreen,
|
|
pScreenPriv->pBankPixmap->drawable.depth);
|
|
if (!pScreenPriv->pBankGC)
|
|
retval = FALSE;
|
|
}
|
|
|
|
/* Validate shadow GC */
|
|
if (retval)
|
|
{
|
|
pScreenPriv->pBankGC->graphicsExposures = FALSE;
|
|
pScreenPriv->pBankGC->subWindowMode = IncludeInferiors;
|
|
ValidateGC((DrawablePtr)pScreenPriv->pBankPixmap,
|
|
pScreenPriv->pBankGC);
|
|
}
|
|
|
|
SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static Bool
|
|
miBankModifyPixmapHeader(
|
|
PixmapPtr pPixmap,
|
|
int width,
|
|
int height,
|
|
int depth,
|
|
int bitsPerPixel,
|
|
int devKind,
|
|
pointer pPixData
|
|
)
|
|
{
|
|
Bool retval = FALSE;
|
|
|
|
if (pPixmap)
|
|
{
|
|
ScreenPtr pScreen = pPixmap->drawable.pScreen;
|
|
|
|
SCREEN_INIT;
|
|
PIXMAP_SAVE(pPixmap);
|
|
SCREEN_UNWRAP(ModifyPixmapHeader);
|
|
|
|
retval = (*pScreen->ModifyPixmapHeader)(pPixmap, width, height,
|
|
depth, bitsPerPixel, devKind, pPixData);
|
|
|
|
SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
|
|
|
|
if (pbits == (pointer)pScreenPriv)
|
|
{
|
|
pScreenPriv->pbits = pPixmap->devPrivate.ptr;
|
|
pPixmap->devPrivate.ptr = pbits;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static Bool
|
|
miBankCloseScreen(
|
|
int nIndex,
|
|
ScreenPtr pScreen
|
|
)
|
|
{
|
|
int i;
|
|
|
|
SCREEN_INIT;
|
|
|
|
/* Free shadow GC */
|
|
FreeScratchGC(pScreenPriv->pBankGC);
|
|
|
|
/* Free shadow pixmap */
|
|
(*pScreen->DestroyPixmap)(pScreenPriv->pBankPixmap);
|
|
|
|
/* Restore screen pixmap devPrivate pointer */
|
|
pScreenPriv->pScreenPixmap->devPrivate.ptr = pScreenPriv->pbits;
|
|
|
|
/* Delete bank clips */
|
|
for (i = 0; i < pScreenPriv->nBanks; i++)
|
|
if (pScreenPriv->pBanks[i])
|
|
REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
|
|
|
|
Xfree(pScreenPriv->pBanks);
|
|
|
|
SCREEN_UNWRAP(CreateScreenResources);
|
|
SCREEN_UNWRAP(ModifyPixmapHeader);
|
|
SCREEN_UNWRAP(CloseScreen);
|
|
SCREEN_UNWRAP(GetImage);
|
|
SCREEN_UNWRAP(GetSpans);
|
|
SCREEN_UNWRAP(CreateGC);
|
|
SCREEN_UNWRAP(CopyWindow);
|
|
|
|
Xfree(pScreenPriv);
|
|
return (*pScreen->CloseScreen)(nIndex, pScreen);
|
|
}
|
|
|
|
static void
|
|
miBankGetImage(
|
|
DrawablePtr pDrawable,
|
|
int sx,
|
|
int sy,
|
|
int w,
|
|
int h,
|
|
unsigned int format,
|
|
unsigned long planemask,
|
|
char *pImage
|
|
)
|
|
{
|
|
if ((w > 0) && (h > 0))
|
|
{
|
|
ScreenPtr pScreen = pDrawable->pScreen;
|
|
|
|
SCREEN_INIT;
|
|
SCREEN_STATUS;
|
|
SCREEN_UNWRAP(GetImage);
|
|
|
|
if (!IS_BANKED(pDrawable))
|
|
{
|
|
(*pScreen->GetImage)(pDrawable, sx, sy, w, h,
|
|
format, planemask, pImage);
|
|
}
|
|
else
|
|
{
|
|
int paddedWidth;
|
|
char *pBankImage;
|
|
|
|
paddedWidth = PixmapBytePad(w,
|
|
pScreenPriv->pScreenPixmap->drawable.depth);
|
|
pBankImage = xalloc(paddedWidth * h);
|
|
|
|
if (pBankImage)
|
|
{
|
|
BANK_SAVE;
|
|
|
|
ModifyPixmap(pScreenPriv->pBankPixmap, w, paddedWidth,
|
|
pBankImage);
|
|
|
|
(*pScreenPriv->pBankGC->ops->CopyArea)(
|
|
(DrawablePtr)WindowTable[pScreen->myNum],
|
|
(DrawablePtr)pScreenPriv->pBankPixmap,
|
|
pScreenPriv->pBankGC,
|
|
sx + pDrawable->x, sy + pDrawable->y, w, h, 0, 0);
|
|
|
|
(*pScreen->GetImage)((DrawablePtr)pScreenPriv->pBankPixmap,
|
|
0, 0, w, h, format, planemask, pImage);
|
|
|
|
BANK_RESTORE;
|
|
|
|
xfree(pBankImage);
|
|
}
|
|
}
|
|
|
|
SCREEN_WRAP(GetImage, miBankGetImage);
|
|
}
|
|
}
|
|
|
|
static void
|
|
miBankGetSpans(
|
|
DrawablePtr pDrawable,
|
|
int wMax,
|
|
DDXPointPtr ppt,
|
|
int *pwidth,
|
|
int nspans,
|
|
char *pImage
|
|
)
|
|
{
|
|
if (nspans > 0)
|
|
{
|
|
ScreenPtr pScreen = pDrawable->pScreen;
|
|
|
|
SCREEN_INIT;
|
|
SCREEN_STATUS;
|
|
SCREEN_UNWRAP(GetSpans);
|
|
|
|
if (!IS_BANKED(pDrawable))
|
|
{
|
|
(*pScreen->GetSpans)(pDrawable, wMax, ppt, pwidth, nspans, pImage);
|
|
}
|
|
else
|
|
{
|
|
char *pBankImage;
|
|
int paddedWidth;
|
|
DDXPointRec pt;
|
|
|
|
pt.x = pt.y = 0;
|
|
|
|
paddedWidth =
|
|
PixmapBytePad(pScreenPriv->pScreenPixmap->drawable.width,
|
|
pScreenPriv->pScreenPixmap->drawable.depth);
|
|
pBankImage = xalloc(paddedWidth);
|
|
|
|
if (pBankImage)
|
|
{
|
|
BANK_SAVE;
|
|
|
|
ModifyPixmap(pScreenPriv->pBankPixmap,
|
|
pScreenPriv->pScreenPixmap->drawable.width,
|
|
paddedWidth, pBankImage);
|
|
|
|
for (; nspans--; ppt++, pwidth++)
|
|
{
|
|
if (*pwidth <= 0)
|
|
continue;
|
|
|
|
(*pScreenPriv->pBankGC->ops->CopyArea)(
|
|
(DrawablePtr)WindowTable[pScreen->myNum],
|
|
(DrawablePtr)pScreenPriv->pBankPixmap,
|
|
pScreenPriv->pBankGC,
|
|
ppt->x, ppt->y, *pwidth, 1, 0, 0);
|
|
|
|
(*pScreen->GetSpans)((DrawablePtr)pScreenPriv->pBankPixmap,
|
|
wMax, &pt, pwidth, 1, pImage);
|
|
|
|
pImage = pImage + PixmapBytePad(*pwidth, pDrawable->depth);
|
|
}
|
|
|
|
BANK_RESTORE;
|
|
|
|
xfree(pBankImage);
|
|
}
|
|
}
|
|
|
|
SCREEN_WRAP(GetSpans, miBankGetSpans);
|
|
}
|
|
}
|
|
|
|
static Bool
|
|
miBankCreateGC(
|
|
GCPtr pGC
|
|
)
|
|
{
|
|
ScreenPtr pScreen = pGC->pScreen;
|
|
miBankGCPtr pGCPriv = BANK_GCPRIVATE(pGC);
|
|
Bool ret;
|
|
|
|
SCREEN_INIT;
|
|
SCREEN_UNWRAP(CreateGC);
|
|
|
|
if ((ret = (*pScreen->CreateGC)(pGC)))
|
|
{
|
|
pGCPriv->unwrappedOps = &miBankGCOps;
|
|
pGCPriv->unwrappedFuncs = &miBankGCFuncs;
|
|
GC_WRAP(pGC);
|
|
|
|
memset(&pGCPriv->pBankedClips, 0,
|
|
pScreenPriv->nBanks * sizeof(pGCPriv->pBankedClips));
|
|
}
|
|
|
|
SCREEN_WRAP(CreateGC, miBankCreateGC);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
miBankCopyWindow(
|
|
WindowPtr pWindow,
|
|
DDXPointRec ptOldOrg,
|
|
RegionPtr pRgnSrc
|
|
)
|
|
{
|
|
ScreenPtr pScreen = pWindow->drawable.pScreen;
|
|
GCPtr pGC;
|
|
int dx, dy, nBox;
|
|
DrawablePtr pDrawable = (DrawablePtr)WindowTable[pScreen->myNum];
|
|
RegionPtr pRgnDst;
|
|
BoxPtr pBox, pBoxTmp, pBoxNext, pBoxBase, pBoxNew1, pBoxNew2;
|
|
XID subWindowMode = IncludeInferiors;
|
|
|
|
pGC = GetScratchGC(pDrawable->depth, pScreen);
|
|
|
|
ChangeGC(pGC, GCSubwindowMode, &subWindowMode);
|
|
ValidateGC(pDrawable, pGC);
|
|
|
|
pRgnDst = REGION_CREATE(pScreen, NULL, 1);
|
|
|
|
dx = ptOldOrg.x - pWindow->drawable.x;
|
|
dy = ptOldOrg.y - pWindow->drawable.y;
|
|
REGION_TRANSLATE(pScreen, pRgnSrc, -dx, -dy);
|
|
REGION_INTERSECT(pScreen, pRgnDst, &pWindow->borderClip, pRgnSrc);
|
|
|
|
pBox = REGION_RECTS(pRgnDst);
|
|
nBox = REGION_NUM_RECTS(pRgnDst);
|
|
|
|
pBoxNew1 = NULL;
|
|
pBoxNew2 = NULL;
|
|
|
|
if (nBox > 1)
|
|
{
|
|
if (dy < 0)
|
|
{
|
|
/* Sort boxes from bottom to top */
|
|
pBoxNew1 = xalloc_ARRAY(BoxRec, nBox);
|
|
|
|
if (pBoxNew1)
|
|
{
|
|
pBoxBase = pBoxNext = pBox + nBox - 1;
|
|
|
|
while (pBoxBase >= pBox)
|
|
{
|
|
while ((pBoxNext >= pBox) &&
|
|
(pBoxBase->y1 == pBoxNext->y1))
|
|
pBoxNext--;
|
|
|
|
pBoxTmp = pBoxNext + 1;
|
|
|
|
while (pBoxTmp <= pBoxBase)
|
|
*pBoxNew1++ = *pBoxTmp++;
|
|
|
|
pBoxBase = pBoxNext;
|
|
}
|
|
|
|
pBoxNew1 -= nBox;
|
|
pBox = pBoxNew1;
|
|
}
|
|
}
|
|
|
|
if (dx < 0)
|
|
{
|
|
/* Sort boxes from right to left */
|
|
pBoxNew2 = xalloc_ARRAY(BoxRec, nBox);
|
|
|
|
if (pBoxNew2)
|
|
{
|
|
pBoxBase = pBoxNext = pBox;
|
|
|
|
while (pBoxBase < pBox + nBox)
|
|
{
|
|
while ((pBoxNext < pBox + nBox) &&
|
|
(pBoxNext->y1 == pBoxBase->y1))
|
|
pBoxNext++;
|
|
|
|
pBoxTmp = pBoxNext;
|
|
|
|
while (pBoxTmp != pBoxBase)
|
|
*pBoxNew2++ = *--pBoxTmp;
|
|
|
|
pBoxBase = pBoxNext;
|
|
}
|
|
|
|
pBoxNew2 -= nBox;
|
|
pBox = pBoxNew2;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (nBox--)
|
|
{
|
|
(*pGC->ops->CopyArea)(pDrawable, pDrawable, pGC,
|
|
pBox->x1 + dx, pBox->y1 + dy,
|
|
pBox->x2 - pBox->x1, pBox->y2 - pBox->y1,
|
|
pBox->x1, pBox->y1);
|
|
|
|
pBox++;
|
|
}
|
|
|
|
FreeScratchGC(pGC);
|
|
|
|
REGION_DESTROY(pScreen, pRgnDst);
|
|
|
|
xfree(pBoxNew2);
|
|
xfree(pBoxNew1);
|
|
}
|
|
|
|
Bool
|
|
miInitializeBanking(
|
|
ScreenPtr pScreen,
|
|
unsigned int xsize,
|
|
unsigned int ysize,
|
|
unsigned int width,
|
|
miBankInfoPtr pBankInfo
|
|
)
|
|
{
|
|
miBankScreenPtr pScreenPriv;
|
|
unsigned long nBitsPerBank, nBitsPerScanline, nPixelsPerScanlinePadUnit;
|
|
unsigned long BankBase, ServerPad;
|
|
unsigned int type, iBank, nBanks, maxRects, we, nBankBPP;
|
|
int i;
|
|
|
|
if (!pBankInfo || !pBankInfo->BankSize)
|
|
return TRUE; /* No banking required */
|
|
|
|
/* Sanity checks */
|
|
|
|
if (!pScreen || !xsize || !ysize || (xsize > width) ||
|
|
!pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
|
|
!pBankInfo->SetSourceAndDestinationBanks ||
|
|
!pBankInfo->pBankA || !pBankInfo->pBankB ||
|
|
!pBankInfo->nBankDepth)
|
|
return FALSE;
|
|
|
|
/*
|
|
* DDX *must* have registered a pixmap format whose depth is
|
|
* pBankInfo->nBankDepth. This is not necessarily the rootDepth
|
|
* pixmap format.
|
|
*/
|
|
i = 0;
|
|
while (screenInfo.formats[i].depth != pBankInfo->nBankDepth)
|
|
if (++i >= screenInfo.numPixmapFormats)
|
|
return FALSE;
|
|
nBankBPP = screenInfo.formats[i].bitsPerPixel;
|
|
|
|
i = 0;
|
|
while (screenInfo.formats[i].depth != pScreen->rootDepth)
|
|
if (++i >= screenInfo.numPixmapFormats)
|
|
return FALSE;
|
|
|
|
if (nBankBPP > screenInfo.formats[i].bitsPerPixel)
|
|
return FALSE;
|
|
|
|
/* Determine banking type */
|
|
if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
|
|
return FALSE;
|
|
|
|
/* Internal data */
|
|
|
|
nBitsPerBank = pBankInfo->BankSize * 8;
|
|
ServerPad = PixmapBytePad(1, pBankInfo->nBankDepth) * 8;
|
|
if (nBitsPerBank % ServerPad)
|
|
return FALSE;
|
|
nBitsPerScanline = PixmapBytePad(width, pBankInfo->nBankDepth) * 8;
|
|
nBanks = ((nBitsPerScanline * (ysize - 1)) +
|
|
(nBankBPP * xsize) + nBitsPerBank - 1) / nBitsPerBank;
|
|
nPixelsPerScanlinePadUnit = miLCM(ServerPad, nBankBPP) / nBankBPP;
|
|
|
|
/* Private areas */
|
|
|
|
if (miBankGeneration != serverGeneration)
|
|
miBankGeneration = serverGeneration;
|
|
|
|
if (!dixRequestPrivate(miBankGCKey,
|
|
(nBanks * sizeof(RegionPtr)) +
|
|
(sizeof(miBankGCRec) - sizeof(RegionPtr))))
|
|
return FALSE;
|
|
|
|
if (!(pScreenPriv = (miBankScreenPtr)Xcalloc(sizeof(miBankScreenRec))))
|
|
return FALSE;
|
|
|
|
if (!(pScreenPriv->pBanks = /* Allocate and clear */
|
|
(RegionPtr *)Xcalloc(nBanks * sizeof(RegionPtr))))
|
|
{
|
|
Xfree(pScreenPriv);
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Translate banks into clipping regions which are themselves clipped
|
|
* against the screen. This also ensures that pixels with imbedded bank
|
|
* boundaries are off-screen.
|
|
*/
|
|
|
|
BankBase = 0;
|
|
maxRects = 0;
|
|
we = 0;
|
|
for (iBank = 0; iBank < nBanks; iBank++)
|
|
{
|
|
xRectangle pRects[3], *pRect = pRects;
|
|
unsigned int xb, yb, xe, ye;
|
|
|
|
xb = ((BankBase + nBankBPP - 1) % nBitsPerScanline) / nBankBPP;
|
|
yb = (BankBase + nBankBPP - 1) / nBitsPerScanline;
|
|
if (xb >= xsize)
|
|
{
|
|
xb = we = 0;
|
|
yb++;
|
|
}
|
|
if (yb >= ysize)
|
|
{
|
|
we = 0;
|
|
break;
|
|
}
|
|
|
|
if (we)
|
|
break;
|
|
|
|
BankBase += nBitsPerBank;
|
|
|
|
we = (BankBase % nBitsPerScanline) % nBankBPP;
|
|
xe = (BankBase % nBitsPerScanline) / nBankBPP;
|
|
ye = BankBase / nBitsPerScanline;
|
|
if (xe >= xsize)
|
|
{
|
|
we = xe = 0;
|
|
ye++;
|
|
}
|
|
if (ye >= ysize)
|
|
{
|
|
we = xe = 0;
|
|
ye = ysize;
|
|
}
|
|
|
|
if (yb == ye)
|
|
{
|
|
if (xb >= xe)
|
|
continue;
|
|
|
|
pRect->x = xb;
|
|
pRect->y = yb;
|
|
pRect->width = xe - xb;
|
|
pRect->height = 1;
|
|
maxRects += 2;
|
|
pRect++;
|
|
}
|
|
else
|
|
{
|
|
if (xb)
|
|
{
|
|
pRect->x = xb;
|
|
pRect->y = yb++;
|
|
pRect->width = xsize - xb;
|
|
pRect->height = 1;
|
|
maxRects += 2;
|
|
pRect++;
|
|
}
|
|
|
|
if (yb < ye)
|
|
{
|
|
pRect->x = 0;
|
|
pRect->y = yb;
|
|
pRect->width = xsize;
|
|
pRect->height = ye - yb;
|
|
maxRects += min(pRect->height, 3) + 1;
|
|
pRect++;
|
|
}
|
|
|
|
if (xe)
|
|
{
|
|
pRect->x = 0;
|
|
pRect->y = ye;
|
|
pRect->width = xe;
|
|
pRect->height = 1;
|
|
maxRects += 2;
|
|
pRect++;
|
|
}
|
|
}
|
|
|
|
pScreenPriv->pBanks[iBank] =
|
|
RECTS_TO_REGION(pScreen, pRect - pRects, pRects, 0);
|
|
if (!pScreenPriv->pBanks[iBank] ||
|
|
REGION_NAR(pScreenPriv->pBanks[iBank]))
|
|
{
|
|
we = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (we && (iBank < nBanks))
|
|
{
|
|
for (i = iBank; i >= 0; i--)
|
|
if (pScreenPriv->pBanks[i])
|
|
REGION_DESTROY(pScreen, pScreenPriv->pBanks[i]);
|
|
|
|
Xfree(pScreenPriv->pBanks);
|
|
Xfree(pScreenPriv);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Open for business */
|
|
|
|
pScreenPriv->type = type;
|
|
pScreenPriv->nBanks = nBanks;
|
|
pScreenPriv->maxRects = maxRects;
|
|
pScreenPriv->nBankBPP = nBankBPP;
|
|
pScreenPriv->BankInfo = *pBankInfo;
|
|
pScreenPriv->nBitsPerBank = nBitsPerBank;
|
|
pScreenPriv->nBitsPerScanline = nBitsPerScanline;
|
|
pScreenPriv->nPixelsPerScanlinePadUnit = nPixelsPerScanlinePadUnit;
|
|
|
|
SCREEN_WRAP(CreateScreenResources, miBankCreateScreenResources);
|
|
SCREEN_WRAP(ModifyPixmapHeader, miBankModifyPixmapHeader);
|
|
SCREEN_WRAP(CloseScreen, miBankCloseScreen);
|
|
SCREEN_WRAP(GetImage, miBankGetImage);
|
|
SCREEN_WRAP(GetSpans, miBankGetSpans);
|
|
SCREEN_WRAP(CreateGC, miBankCreateGC);
|
|
SCREEN_WRAP(CopyWindow, miBankCopyWindow);
|
|
|
|
dixSetPrivate(&pScreen->devPrivates, miBankScreenKey, pScreenPriv);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* Given various screen attributes, determine the minimum scanline width such
|
|
* that each scanline is server and DDX padded and any pixels with imbedded
|
|
* bank boundaries are off-screen. This function returns -1 if such a width
|
|
* cannot exist. This function exists because the DDX needs to be able to
|
|
* determine this width before initializing a frame buffer.
|
|
*/
|
|
int
|
|
miScanLineWidth(
|
|
unsigned int xsize, /* pixels */
|
|
unsigned int ysize, /* pixels */
|
|
unsigned int width, /* pixels */
|
|
unsigned long BankSize, /* char's */
|
|
PixmapFormatRec *pBankFormat,
|
|
unsigned int nWidthUnit /* bits */
|
|
)
|
|
{
|
|
unsigned long nBitsPerBank, nBitsPerScanline, nBitsPerScanlinePadUnit;
|
|
unsigned long minBitsPerScanline, maxBitsPerScanline;
|
|
|
|
/* Sanity checks */
|
|
|
|
if (!nWidthUnit || !pBankFormat)
|
|
return -1;
|
|
|
|
nBitsPerBank = BankSize * 8;
|
|
if (nBitsPerBank % pBankFormat->scanlinePad)
|
|
return -1;
|
|
|
|
if (xsize > width)
|
|
width = xsize;
|
|
nBitsPerScanlinePadUnit = miLCM(pBankFormat->scanlinePad, nWidthUnit);
|
|
nBitsPerScanline =
|
|
(((width * pBankFormat->bitsPerPixel) + nBitsPerScanlinePadUnit - 1) /
|
|
nBitsPerScanlinePadUnit) * nBitsPerScanlinePadUnit;
|
|
width = nBitsPerScanline / pBankFormat->bitsPerPixel;
|
|
|
|
if (!xsize || !(nBitsPerBank % pBankFormat->bitsPerPixel))
|
|
return (int)width;
|
|
|
|
/*
|
|
* Scanlines will be server-pad aligned at this point. They will also be
|
|
* a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
|
|
* bank boundaries are off-screen.
|
|
*
|
|
* It seems reasonable to limit total frame buffer size to 1/16 of the
|
|
* theoretical maximum address space size. On a machine with 32-bit
|
|
* addresses (to 8-bit quantities) this turns out to be 256MB. Not only
|
|
* does this provide a simple limiting condition for the loops below, but
|
|
* it also prevents unsigned long wraparounds.
|
|
*/
|
|
if (!ysize)
|
|
return -1;
|
|
|
|
minBitsPerScanline = xsize * pBankFormat->bitsPerPixel;
|
|
if (minBitsPerScanline > nBitsPerBank)
|
|
return -1;
|
|
|
|
if (ysize == 1)
|
|
return (int)width;
|
|
|
|
maxBitsPerScanline =
|
|
(((unsigned long)(-1) >> 1) - minBitsPerScanline) / (ysize - 1);
|
|
while (nBitsPerScanline <= maxBitsPerScanline)
|
|
{
|
|
unsigned long BankBase, BankUnit;
|
|
|
|
BankUnit = ((nBitsPerBank + nBitsPerScanline - 1) / nBitsPerBank) *
|
|
nBitsPerBank;
|
|
if (!(BankUnit % nBitsPerScanline))
|
|
return (int)width;
|
|
|
|
for (BankBase = BankUnit; ; BankBase += nBitsPerBank)
|
|
{
|
|
unsigned long x, y;
|
|
|
|
y = BankBase / nBitsPerScanline;
|
|
if (y >= ysize)
|
|
return (int)width;
|
|
|
|
x = BankBase % nBitsPerScanline;
|
|
if (!(x % pBankFormat->bitsPerPixel))
|
|
continue;
|
|
|
|
if (x < minBitsPerScanline)
|
|
{
|
|
/*
|
|
* Skip ahead certain widths by dividing the excess scanline
|
|
* amongst the y's.
|
|
*/
|
|
y *= nBitsPerScanlinePadUnit;
|
|
nBitsPerScanline +=
|
|
((x + y - 1) / y) * nBitsPerScanlinePadUnit;
|
|
width = nBitsPerScanline / pBankFormat->bitsPerPixel;
|
|
break;
|
|
}
|
|
|
|
if (BankBase != BankUnit)
|
|
continue;
|
|
|
|
if (!(nBitsPerScanline % x))
|
|
return (int)width;
|
|
|
|
BankBase = ((nBitsPerScanline - minBitsPerScanline) /
|
|
(nBitsPerScanline - x)) * BankUnit;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|