xserver-multidpi/mi/mibank.c
Aaron Plattner f2e310132f Add CreatePixmap allocation hints.
These hints allow an acceleration architecture to optimize allocation of certain
types of pixmaps, such as pixmaps that will serve as backing pixmaps for
redirected windows.
2007-11-04 16:11:28 -08:00

2385 lines
65 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:
* - 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;
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 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(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 = 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(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 = (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(
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 = (char *)ALLOCATE_LOCAL(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;
DEALLOCATE_LOCAL(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 = (char *)ALLOCATE_LOCAL(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;
DEALLOCATE_LOCAL(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 = ALLOCATE_LOCAL_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 = ALLOCATE_LOCAL_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);
DEALLOCATE_LOCAL(pBoxNew2);
DEALLOCATE_LOCAL(pBoxNew1);
}
_X_EXPORT 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)
{
if (((miBankScreenIndex = AllocateScreenPrivateIndex()) < 0) ||
((miBankGCIndex = AllocateGCPrivateIndex()) < 0))
return FALSE;
miBankGeneration = serverGeneration;
}
if (!AllocateGCPrivate(pScreen, miBankGCIndex,
(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);
BANK_SCRPRIVLVAL = (pointer)pScreenPriv;
return TRUE;
}
/* This is used to force GC revalidation when the banking type is changed */
/*ARGSUSED*/
static int
miBankNewSerialNumber(
WindowPtr pWin,
pointer unused
)
{
pWin->drawable.serialNumber = NEXT_SERIAL_NUMBER;
return WT_WALKCHILDREN;
}
/* This entry modifies the banking interface */
_X_EXPORT Bool
miModifyBanking(
ScreenPtr pScreen,
miBankInfoPtr pBankInfo
)
{
unsigned int type;
if (!pScreen)
return FALSE;
if (miBankGeneration == serverGeneration)
{
SCREEN_INIT;
if (pScreenPriv)
{
if (!pBankInfo || !pBankInfo->BankSize ||
!pBankInfo->pBankA || !pBankInfo->pBankB ||
!pBankInfo->SetSourceBank || !pBankInfo->SetDestinationBank ||
!pBankInfo->SetSourceAndDestinationBanks)
return FALSE;
/* BankSize and nBankDepth cannot, as yet, be changed */
if ((pScreenPriv->BankInfo.BankSize != pBankInfo->BankSize) ||
(pScreenPriv->BankInfo.nBankDepth != pBankInfo->nBankDepth))
return FALSE;
if ((type = miBankDeriveType(pScreen, pBankInfo)) == BANK_NOBANK)
return FALSE;
/* Reset banking info */
pScreenPriv->BankInfo = *pBankInfo;
if (type != pScreenPriv->type)
{
/*
* Banking type is changing. Revalidate all window GC's.
*/
pScreenPriv->type = type;
WalkTree(pScreen, miBankNewSerialNumber, 0);
}
return TRUE;
}
}
if (!pBankInfo || !pBankInfo->BankSize)
return TRUE; /* No change requested */
return FALSE;
}
/*
* 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;
}