xserver-multidpi/hw/kdrive/savage/s3draw.c
Eamon Walsh 4017d31902 devPrivates rework: since API is already broken, switch everything
over to new system.

Need to update documentation and address some remaining vestiges of
old system such as CursorRec structure, fb "offman" structure, and
FontRec privates.
2007-08-28 09:28:25 -04:00

3233 lines
71 KiB
C

/*
* Copyright 1999 SuSE, Inc.
*
* 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 SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* 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.
*
* Author: Keith Packard, SuSE, Inc.
*/
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
#include "s3.h"
#include "s3draw.h"
#include "Xmd.h"
#include "gcstruct.h"
#include "scrnintstr.h"
#include "pixmapstr.h"
#include "regionstr.h"
#include "mistruct.h"
#include "fontstruct.h"
#include "dixfontstr.h"
#include "fb.h"
#include "migc.h"
#include "miline.h"
/*
* Map X rops to S3 rops
*/
short s3alu[16] = {
MIX_0,
MIX_AND,
MIX_SRC_AND_NOT_DST,
MIX_SRC,
MIX_NOT_SRC_AND_DST,
MIX_DST,
MIX_XOR,
MIX_OR,
MIX_NOR,
MIX_XNOR,
MIX_NOT_DST,
MIX_SRC_OR_NOT_DST,
MIX_NOT_SRC,
MIX_NOT_SRC_OR_DST,
MIX_NAND,
MIX_1
};
/*
* Handle pixel transfers
*/
#define BURST
#ifdef BURST
#define PixTransDeclare VOL32 *pix_trans_base = (VOL32 *) (s3c->registers),\
*pix_trans = pix_trans_base
#define PixTransStart(n) if (pix_trans + (n) > pix_trans_base + 8192) pix_trans = pix_trans_base
#define PixTransStore(t) *pix_trans++ = (t)
#else
#define PixTransDeclare VOL32 *pix_trans = &s3->pix_trans
#define PixTransStart(n)
#define PixTransStore(t) *pix_trans = (t)
#endif
DevPrivateKey s3GCPrivateKey = &s3GCPrivateKey;
DevPrivateKey s3WindowPrivateKey = &s3WindowPrivateKey;
/*
s3DoBitBlt
=============
Bit Blit for all window to window blits.
*/
#define sourceInvarient(alu) (((alu) & 3) == (((alu) >> 2) & 3))
void
s3CopyNtoN (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse,
Bool upsidedown,
Pixel bitplane,
void *closure)
{
SetupS3(pDstDrawable->pScreen);
int srcX, srcY, dstX, dstY;
int w, h;
int flags;
if (sourceInvarient (pGC->alu))
{
s3FillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu, pGC->planemask);
return;
}
s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC));
_s3SetBlt(s3,pGC->alu,pGC->planemask);
DRAW_DEBUG ((DEBUG_RENDER, "s3CopyNtoN alu %d planemask 0x%x",
pGC->alu, pGC->planemask));
while (nbox--)
{
w = pbox->x2 - pbox->x1;
h = pbox->y2 - pbox->y1;
flags = 0;
if (reverse)
{
dstX = pbox->x2 - 1;
}
else
{
dstX = pbox->x1;
flags |= INC_X;
}
srcX = dstX + dx;
if (upsidedown)
{
dstY = pbox->y2 - 1;
}
else
{
dstY = pbox->y1;
flags |= INC_Y;
}
srcY = dstY + dy;
_s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags);
pbox++;
}
MarkSyncS3 (pSrcDrawable->pScreen);
}
RegionPtr
s3CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty)
{
SetupS3(pDstDrawable->pScreen);
if (pSrcDrawable->type == DRAWABLE_WINDOW &&
pDstDrawable->type == DRAWABLE_WINDOW)
{
return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, s3CopyNtoN, 0, 0);
}
return KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height, dstx, dsty);
}
typedef struct _s31toNargs {
unsigned long copyPlaneFG, copyPlaneBG;
Bool opaque;
} s31toNargs;
void
_s3Stipple (S3CardInfo *s3c,
FbStip *psrcBase,
FbStride widthSrc,
int srcx,
int srcy,
int dstx,
int dsty,
int width,
int height)
{
S3Ptr s3 = s3c->s3;
FbStip *psrcLine, *psrc;
FbStride widthRest;
FbStip bits, tmp, lastTmp;
int leftShift, rightShift;
int nl, nlMiddle;
int r;
PixTransDeclare;
/* Compute blt address and parameters */
psrc = psrcBase + srcy * widthSrc + (srcx >> 5);
nlMiddle = (width + 31) >> 5;
leftShift = srcx & 0x1f;
rightShift = 32 - leftShift;
widthRest = widthSrc - nlMiddle;
_s3PlaneBlt(s3,dstx,dsty,width,height);
if (leftShift == 0)
{
while (height--)
{
nl = nlMiddle;
PixTransStart(nl);
while (nl--)
{
tmp = *psrc++;
S3AdjustBits32 (tmp);
PixTransStore (tmp);
}
psrc += widthRest;
}
}
else
{
widthRest--;
while (height--)
{
bits = *psrc++;
nl = nlMiddle;
PixTransStart(nl);
while (nl--)
{
tmp = FbStipLeft(bits, leftShift);
bits = *psrc++;
tmp |= FbStipRight(bits, rightShift);
S3AdjustBits32(tmp);
PixTransStore (tmp);
}
psrc += widthRest;
}
}
}
void
s3Copy1toN (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse,
Bool upsidedown,
Pixel bitplane,
void *closure)
{
SetupS3(pDstDrawable->pScreen);
s31toNargs *args = closure;
int dstx, dsty;
FbStip *psrcBase;
FbStride widthSrc;
int srcBpp;
int srcXoff, srcYoff;
if (args->opaque && sourceInvarient (pGC->alu))
{
s3FillBoxSolid (pDstDrawable, nbox, pbox,
pGC->bgPixel, pGC->alu, pGC->planemask);
return;
}
s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC));
fbGetStipDrawable (pSrcDrawable, psrcBase, widthSrc, srcBpp, srcXoff, srcYoff);
if (args->opaque)
{
_s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,args->copyPlaneFG,
args->copyPlaneBG);
}
else
{
_s3SetTransparentPlaneBlt (s3, pGC->alu,
pGC->planemask, args->copyPlaneFG);
}
while (nbox--)
{
dstx = pbox->x1;
dsty = pbox->y1;
_s3Stipple (s3c,
psrcBase, widthSrc,
dstx + dx - srcXoff, dsty + dy - srcYoff,
dstx, dsty,
pbox->x2 - dstx, pbox->y2 - dsty);
pbox++;
}
MarkSyncS3 (pDstDrawable->pScreen);
}
RegionPtr
s3CopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height,
int dstx, int dsty, unsigned long bitPlane)
{
SetupS3 (pDstDrawable->pScreen);
RegionPtr ret;
s31toNargs args;
if (pDstDrawable->type == DRAWABLE_WINDOW &&
pSrcDrawable->depth == 1)
{
args.copyPlaneFG = pGC->fgPixel;
args.copyPlaneBG = pGC->bgPixel;
args.opaque = TRUE;
return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, s3Copy1toN, bitPlane, &args);
}
return KdCheckCopyPlane(pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, bitPlane);
}
void
s3PushPixels (GCPtr pGC, PixmapPtr pBitmap,
DrawablePtr pDrawable,
int w, int h, int x, int y)
{
SetupS3 (pDrawable->pScreen);
s31toNargs args;
if (pDrawable->type == DRAWABLE_WINDOW && pGC->fillStyle == FillSolid)
{
args.opaque = FALSE;
args.copyPlaneFG = pGC->fgPixel;
(void) fbDoCopy ((DrawablePtr) pBitmap, pDrawable, pGC,
0, 0, w, h, x, y, s3Copy1toN, 1, &args);
}
else
{
KdCheckPushPixels (pGC, pBitmap, pDrawable, w, h, x, y);
}
}
void
s3FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
unsigned long pixel, int alu, unsigned long planemask)
{
SetupS3(pDrawable->pScreen);
register int r;
s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
_s3SetSolidFill(s3,pixel,alu,planemask);
while (nBox--) {
_s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1);
pBox++;
}
MarkSyncS3 (pDrawable->pScreen);
}
void
_s3SetPattern (ScreenPtr pScreen, int ma,
int alu, unsigned long planemask, s3PatternPtr pPattern)
{
SetupS3(pScreen);
S3PatternCache *cache;
_s3LoadPattern (pScreen, ma, pPattern);
cache = pPattern->cache;
switch (pPattern->fillStyle) {
case FillTiled:
_s3SetTile(s3,alu,planemask);
break;
case FillStippled:
_s3SetStipple(s3,alu,planemask,pPattern->fore);
break;
case FillOpaqueStippled:
_s3SetOpaqueStipple(s3,alu,planemask,pPattern->fore,pPattern->back);
break;
}
}
void
s3FillBoxPattern (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
int alu, unsigned long planemask, s3PatternPtr pPattern)
{
SetupS3(pDrawable->pScreen);
S3PatternCache *cache;
int patx, paty;
s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
_s3SetPattern (pDrawable->pScreen, s3DrawMap(pDrawable), alu, planemask, pPattern);
cache = pPattern->cache;
while (nBox--)
{
_s3PatRect(s3,cache->x, cache->y,
pBox->x1, pBox->y1,
pBox->x2-pBox->x1, pBox->y2-pBox->y1);
pBox++;
}
MarkSyncS3 (pDrawable->pScreen);
}
void
s3FillBoxLargeStipple (DrawablePtr pDrawable, GCPtr pGC,
int nBox, BoxPtr pBox)
{
SetupS3(pDrawable->pScreen);
DrawablePtr pStipple = &pGC->stipple->drawable;
int xRot = pGC->patOrg.x + pDrawable->x;
int yRot = pGC->patOrg.y + pDrawable->y;
FbStip *stip;
FbStride stipStride;
int stipBpp;
int stipXoff, stipYoff;
int stipWidth, stipHeight;
int dstX, dstY, width, height;
stipWidth = pStipple->width;
stipHeight = pStipple->height;
fbGetStipDrawable (pStipple, stip, stipStride, stipBpp, stipXoff, stipYoff);
s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
if (pGC->fillStyle == FillOpaqueStippled)
{
_s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,
pGC->fgPixel, pGC->bgPixel);
}
else
{
_s3SetTransparentPlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel);
}
while (nBox--)
{
int stipX, stipY, sx;
int widthTmp;
int h, w;
int x, y;
dstX = pBox->x1;
dstY = pBox->y1;
width = pBox->x2 - pBox->x1;
height = pBox->y2 - pBox->y1;
pBox++;
modulus (dstY - yRot - stipYoff, stipHeight, stipY);
modulus (dstX - xRot - stipXoff, stipWidth, stipX);
y = dstY;
while (height)
{
h = stipHeight - stipY;
if (h > height)
h = height;
height -= h;
widthTmp = width;
x = dstX;
sx = stipX;
while (widthTmp)
{
w = (stipWidth - sx);
if (w > widthTmp)
w = widthTmp;
widthTmp -= w;
_s3Stipple (s3c,
stip,
stipStride,
sx, stipY,
x, y,
w, h);
x += w;
sx = 0;
}
y += h;
stipY = 0;
}
}
MarkSyncS3 (pDrawable->pScreen);
}
#define NUM_STACK_RECTS 1024
void
s3PolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
int nrectFill, xRectangle *prectInit)
{
s3GCPrivate(pGC);
xRectangle *prect;
RegionPtr prgnClip;
register BoxPtr pbox;
register BoxPtr pboxClipped;
BoxPtr pboxClippedBase;
BoxPtr pextent;
BoxRec stackRects[NUM_STACK_RECTS];
int numRects;
int n;
int xorg, yorg;
int x, y;
prgnClip = fbGetCompositeClip(pGC);
xorg = pDrawable->x;
yorg = pDrawable->y;
if (xorg || yorg)
{
prect = prectInit;
n = nrectFill;
while(n--)
{
prect->x += xorg;
prect->y += yorg;
prect++;
}
}
prect = prectInit;
numRects = REGION_NUM_RECTS(prgnClip) * nrectFill;
if (numRects > NUM_STACK_RECTS)
{
pboxClippedBase = (BoxPtr)ALLOCATE_LOCAL(numRects * sizeof(BoxRec));
if (!pboxClippedBase)
return;
}
else
pboxClippedBase = stackRects;
pboxClipped = pboxClippedBase;
if (REGION_NUM_RECTS(prgnClip) == 1)
{
int x1, y1, x2, y2, bx2, by2;
pextent = REGION_RECTS(prgnClip);
x1 = pextent->x1;
y1 = pextent->y1;
x2 = pextent->x2;
y2 = pextent->y2;
while (nrectFill--)
{
if ((pboxClipped->x1 = prect->x) < x1)
pboxClipped->x1 = x1;
if ((pboxClipped->y1 = prect->y) < y1)
pboxClipped->y1 = y1;
bx2 = (int) prect->x + (int) prect->width;
if (bx2 > x2)
bx2 = x2;
pboxClipped->x2 = bx2;
by2 = (int) prect->y + (int) prect->height;
if (by2 > y2)
by2 = y2;
pboxClipped->y2 = by2;
prect++;
if ((pboxClipped->x1 < pboxClipped->x2) &&
(pboxClipped->y1 < pboxClipped->y2))
{
pboxClipped++;
}
}
}
else
{
int x1, y1, x2, y2, bx2, by2;
pextent = REGION_EXTENTS(pGC->pScreen, prgnClip);
x1 = pextent->x1;
y1 = pextent->y1;
x2 = pextent->x2;
y2 = pextent->y2;
while (nrectFill--)
{
BoxRec box;
if ((box.x1 = prect->x) < x1)
box.x1 = x1;
if ((box.y1 = prect->y) < y1)
box.y1 = y1;
bx2 = (int) prect->x + (int) prect->width;
if (bx2 > x2)
bx2 = x2;
box.x2 = bx2;
by2 = (int) prect->y + (int) prect->height;
if (by2 > y2)
by2 = y2;
box.y2 = by2;
prect++;
if ((box.x1 >= box.x2) || (box.y1 >= box.y2))
continue;
n = REGION_NUM_RECTS (prgnClip);
pbox = REGION_RECTS(prgnClip);
/* clip the rectangle to each box in the clip region
this is logically equivalent to calling Intersect()
*/
while(n--)
{
pboxClipped->x1 = max(box.x1, pbox->x1);
pboxClipped->y1 = max(box.y1, pbox->y1);
pboxClipped->x2 = min(box.x2, pbox->x2);
pboxClipped->y2 = min(box.y2, pbox->y2);
pbox++;
/* see if clipping left anything */
if(pboxClipped->x1 < pboxClipped->x2 &&
pboxClipped->y1 < pboxClipped->y2)
{
pboxClipped++;
}
}
}
}
if (pboxClipped != pboxClippedBase)
{
if (pGC->fillStyle == FillSolid)
s3FillBoxSolid(pDrawable,
pboxClipped-pboxClippedBase, pboxClippedBase,
pGC->fgPixel, pGC->alu, pGC->planemask);
else if (s3Priv->pPattern)
s3FillBoxPattern (pDrawable,
pboxClipped-pboxClippedBase, pboxClippedBase,
pGC->alu, pGC->planemask,
s3Priv->pPattern);
else
s3FillBoxLargeStipple (pDrawable, pGC,
pboxClipped-pboxClippedBase,
pboxClippedBase);
}
if (pboxClippedBase != stackRects)
DEALLOCATE_LOCAL(pboxClippedBase);
}
void
_s3FillSpanLargeStipple (DrawablePtr pDrawable, GCPtr pGC,
int n, DDXPointPtr ppt, int *pwidth)
{
SetupS3 (pDrawable->pScreen);
DrawablePtr pStipple = &pGC->stipple->drawable;
int xRot = pGC->patOrg.x + pDrawable->x;
int yRot = pGC->patOrg.y + pDrawable->y;
FbStip *stip;
FbStride stipStride;
int stipBpp;
int stipXoff, stipYoff;
int stipWidth, stipHeight;
int dstX, dstY, width, height;
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
stipWidth = pStipple->width;
stipHeight = pStipple->height;
fbGetStipDrawable (pStipple, stip, stipStride, stipBpp, stipXoff, stipYoff);
if (pGC->fillStyle == FillOpaqueStippled)
{
_s3SetOpaquePlaneBlt(s3,pGC->alu,pGC->planemask,
pGC->fgPixel, pGC->bgPixel);
}
else
{
_s3SetTransparentPlaneBlt(s3,pGC->alu,pGC->planemask, pGC->fgPixel);
}
while (n--)
{
int stipX, stipY, sx;
int w;
int x, y;
dstX = ppt->x;
dstY = ppt->y;
ppt++;
width = *pwidth++;
modulus (dstY - yRot - stipYoff, stipHeight, stipY);
modulus (dstX - xRot - stipXoff, stipWidth, stipX);
y = dstY;
x = dstX;
sx = stipX;
while (width)
{
w = (stipWidth - sx);
if (w > width)
w = width;
width -= w;
_s3Stipple (s3c,
stip,
stipStride,
sx, stipY,
x, y,
w, 1);
x += w;
sx = 0;
}
}
}
void
s3FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n,
DDXPointPtr ppt, int *pwidth, int fSorted)
{
s3GCPrivate(pGC);
SetupS3(pDrawable->pScreen);
int x, y, x1, y1, x2, y2;
int width;
/* next three parameters are post-clip */
int nTmp;
int *pwidthFree;/* copies of the pointers to free */
DDXPointPtr pptFree;
BoxPtr extents;
S3PatternCache *cache;
RegionPtr pClip = fbGetCompositeClip (pGC);
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
if (REGION_NUM_RECTS(pClip) == 1 &&
(pGC->fillStyle == FillSolid || s3Priv->pPattern))
{
extents = REGION_RECTS(pClip);
x1 = extents->x1;
x2 = extents->x2;
y1 = extents->y1;
y2 = extents->y2;
if (pGC->fillStyle == FillSolid)
{
_s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
cache = 0;
}
else
{
_s3SetPattern (pDrawable->pScreen, s3GCMap(pGC), pGC->alu, pGC->planemask,
s3Priv->pPattern);
cache = s3Priv->pPattern->cache;
}
while (n--)
{
y = ppt->y;
if (y1 <= y && y < y2)
{
x = ppt->x;
width = *pwidth;
if (x < x1)
{
width -= (x1 - x);
x = x1;
}
if (x2 < x + width)
width = x2 - x;
if (width > 0)
{
if (cache)
{
_s3PatRect(s3, cache->x, cache->y, x, y, width, 1);
}
else
{
_s3SolidRect(s3,x,y,width,1);
}
}
}
ppt++;
pwidth++;
}
}
else
{
nTmp = n * miFindMaxBand(pClip);
pwidthFree = (int *)ALLOCATE_LOCAL(nTmp * sizeof(int));
pptFree = (DDXPointRec *)ALLOCATE_LOCAL(nTmp * sizeof(DDXPointRec));
if(!pptFree || !pwidthFree)
{
if (pptFree) DEALLOCATE_LOCAL(pptFree);
if (pwidthFree) DEALLOCATE_LOCAL(pwidthFree);
return;
}
n = miClipSpans(fbGetCompositeClip(pGC),
ppt, pwidth, n,
pptFree, pwidthFree, fSorted);
pwidth = pwidthFree;
ppt = pptFree;
if (pGC->fillStyle == FillSolid)
{
_s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
while (n--)
{
x = ppt->x;
y = ppt->y;
ppt++;
width = *pwidth++;
if (width)
{
_s3SolidRect(s3,x,y,width,1);
}
}
}
else if (s3Priv->pPattern)
{
_s3SetPattern (pDrawable->pScreen, s3GCMap(pGC), pGC->alu, pGC->planemask,
s3Priv->pPattern);
cache = s3Priv->pPattern->cache;
while (n--)
{
x = ppt->x;
y = ppt->y;
ppt++;
width = *pwidth++;
if (width)
{
_s3PatRect(s3, cache->x, cache->y, x, y, width, 1);
}
}
}
else
{
_s3FillSpanLargeStipple (pDrawable, pGC, n, ppt, pwidth);
}
DEALLOCATE_LOCAL(pptFree);
DEALLOCATE_LOCAL(pwidthFree);
}
MarkSyncS3 (pDrawable->pScreen);
}
#include "mifillarc.h"
#define FILLSPAN(s3,y,__x1,__x2) {\
DRAW_DEBUG ((DEBUG_ARCS, "FILLSPAN %d: %d->%d", y, __x1, __x2)); \
if ((__x2) >= (__x1)) {\
_s3SolidRect(s3,(__x1),(y),(__x2)-(__x1)+1,1); \
} \
}
#define FILLSLICESPANS(flip,__y) \
if (!flip) \
{ \
FILLSPAN(s3,__y,xl,xr) \
} \
else \
{ \
xc = xorg - x; \
FILLSPAN(s3, __y, xc, xr) \
xc += slw - 1; \
FILLSPAN(s3, __y, xl, xc) \
}
static void
_s3FillEllipse (DrawablePtr pDraw, S3Ptr s3, xArc *arc)
{
KdScreenPriv(pDraw->pScreen);
int x, y, e;
int yk, xk, ym, xm, dx, dy, xorg, yorg;
int y_top, y_bot;
miFillArcRec info;
register int xpos;
int slw;
s3SetGlobalBitmap (pDraw->pScreen, s3DrawMap (pDraw));
miFillArcSetup(arc, &info);
MIFILLARCSETUP();
y_top = pDraw->y + yorg - y;
y_bot = pDraw->y + yorg + y + dy;
xorg += pDraw->x;
while (y)
{
y_top++;
y_bot--;
MIFILLARCSTEP(slw);
if (!slw)
continue;
xpos = xorg - x;
_s3SolidRect (s3,xpos,y_top,slw,1);
if (miFillArcLower(slw))
_s3SolidRect (s3,xpos,y_bot,slw,1);
}
}
static void
_s3FillArcSlice (DrawablePtr pDraw, GCPtr pGC, S3Ptr s3, xArc *arc)
{
KdScreenPriv(pDraw->pScreen);
int yk, xk, ym, xm, dx, dy, xorg, yorg, slw;
register int x, y, e;
miFillArcRec info;
miArcSliceRec slice;
int xl, xr, xc;
int y_top, y_bot;
s3SetGlobalBitmap (pDraw->pScreen, s3DrawMap (pDraw));
DRAW_DEBUG ((DEBUG_ARCS, "slice %dx%d+%d+%d %d->%d",
arc->width, arc->height, arc->x, arc->y,
arc->angle1, arc->angle2));
miFillArcSetup(arc, &info);
miFillArcSliceSetup(arc, &slice, pGC);
DRAW_DEBUG ((DEBUG_ARCS, "edge1.x %d edge2.x %d",
slice.edge1.x, slice.edge2.x));
MIFILLARCSETUP();
DRAW_DEBUG ((DEBUG_ARCS, "xorg %d yorg %d",
xorg, yorg));
xorg += pDraw->x;
yorg += pDraw->y;
y_top = yorg - y;
y_bot = yorg + y + dy;
slice.edge1.x += pDraw->x;
slice.edge2.x += pDraw->x;
DRAW_DEBUG ((DEBUG_ARCS, "xorg %d y_top %d y_bot %d",
xorg, y_top, y_bot));
while (y > 0)
{
y_top++;
y_bot--;
MIFILLARCSTEP(slw);
MIARCSLICESTEP(slice.edge1);
MIARCSLICESTEP(slice.edge2);
if (miFillSliceUpper(slice))
{
MIARCSLICEUPPER(xl, xr, slice, slw);
FILLSLICESPANS(slice.flip_top, y_top);
}
if (miFillSliceLower(slice))
{
MIARCSLICELOWER(xl, xr, slice, slw);
FILLSLICESPANS(slice.flip_bot, y_bot);
}
}
}
void
s3PolyFillArcSolid (DrawablePtr pDraw, GCPtr pGC, int narcs, xArc *parcs)
{
SetupS3(pDraw->pScreen);
xArc *arc;
int i;
int x, y;
BoxRec box;
RegionPtr pClip = fbGetCompositeClip(pGC);
BOOL set;
set = FALSE;
for (; --narcs >= 0; parcs++)
{
if (miFillArcEmpty(parcs))
continue;
if (miCanFillArc(parcs))
{
box.x1 = parcs->x + pDraw->x;
box.y1 = parcs->y + pDraw->y;
box.x2 = box.x1 + (int)parcs->width + 1;
box.y2 = box.y1 + (int)parcs->height + 1;
switch (RECT_IN_REGION(pDraw->pScreen, pClip, &box))
{
case rgnIN:
if (!set)
{
_s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
set = TRUE;
}
if ((parcs->angle2 >= FULLCIRCLE) ||
(parcs->angle2 <= -FULLCIRCLE))
{
DRAW_DEBUG ((DEBUG_ARCS, "Full circle ellipse %dx%d",
parcs->width, parcs->height));
_s3FillEllipse (pDraw, s3, parcs);
}
else
{
DRAW_DEBUG ((DEBUG_ARCS, "Partial ellipse %dx%d",
parcs->width, parcs->height));
_s3FillArcSlice (pDraw, pGC, s3, parcs);
}
/* fall through ... */
case rgnOUT:
continue;
case rgnPART:
break;
}
}
if (set)
{
MarkSyncS3 (pDraw->pScreen);
set = FALSE;
}
KdCheckPolyFillArc(pDraw, pGC, 1, parcs);
}
if (set)
{
MarkSyncS3 (pDraw->pScreen);
set = FALSE;
}
}
void
s3FillPoly (DrawablePtr pDrawable, GCPtr pGC, int shape,
int mode, int countInit, DDXPointPtr ptsIn)
{
SetupS3(pDrawable->pScreen);
int nwidth;
int maxy;
int origin;
int count;
register int vertex1, vertex2;
int c;
RegionPtr pClip = fbGetCompositeClip(pGC);
BoxPtr extents;
int clip;
int y, sy;
int *vertex1p, *vertex2p;
int *endp;
int x1, x2, sx;
int dx1, dx2;
int dy1, dy2;
int e1, e2;
int step1, step2;
int sign1, sign2;
int h;
int l, r;
int nmiddle;
if (mode == CoordModePrevious || REGION_NUM_RECTS(pClip) != 1)
{
KdCheckFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
return;
}
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
sy = pDrawable->y;
sx = pDrawable->x;
origin = *((int *) &pDrawable->x);
origin -= (origin & 0x8000) << 1;
extents = &pClip->extents;
vertex1 = *((int *) &extents->x1) - origin;
vertex2 = *((int *) &extents->x2) - origin - 0x00010001;
clip = 0;
y = 32767;
maxy = 0;
vertex2p = (int *) ptsIn;
endp = vertex2p + countInit;
if (shape == Convex)
{
count = countInit;
while (count--)
{
c = *vertex2p;
clip |= (c - vertex1) | (vertex2 - c);
c = intToY(c);
DRAW_DEBUG ((DEBUG_POLYGON, "Y coordinate %d", c));
if (c < y)
{
y = c;
vertex1p = vertex2p;
}
vertex2p++;
if (c > maxy)
maxy = c;
}
}
else
{
int yFlip = 0;
dx1 = 1;
x2 = -1;
x1 = -1;
count = countInit;
while (count--)
{
c = *vertex2p;
clip |= (c - vertex1) | (vertex2 - c);
c = intToY(c);
DRAW_DEBUG ((DEBUG_POLYGON, "Y coordinate %d", c));
if (c < y)
{
y = c;
vertex1p = vertex2p;
}
vertex2p++;
if (c > maxy)
maxy = c;
if (c == x1)
continue;
if (dx1 > 0)
{
if (x2 < 0)
x2 = c;
else
dx2 = dx1 = (c - x1) >> 31;
}
else
if ((c - x1) >> 31 != dx1)
{
dx1 = ~dx1;
yFlip++;
}
x1 = c;
}
x1 = (x2 - c) >> 31;
if (x1 != dx1)
yFlip++;
if (x1 != dx2)
yFlip++;
if (yFlip != 2)
clip = 0x8000;
}
if (y == maxy)
return;
if (clip & 0x80008000)
{
KdCheckFillPolygon (pDrawable, pGC, shape, mode, countInit, ptsIn);
return;
}
_s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
vertex2p = vertex1p;
vertex2 = vertex1 = *vertex2p++;
if (vertex2p == endp)
vertex2p = (int *) ptsIn;
#define Setup(c,x,vertex,dx,dy,e,sign,step) {\
x = intToX(vertex); \
if (dy = intToY(c) - y) { \
dx = intToX(c) - x; \
step = 0; \
if (dx >= 0) \
{ \
e = 0; \
sign = 1; \
if (dx >= dy) {\
step = dx / dy; \
dx = dx % dy; \
} \
} \
else \
{ \
e = 1 - dy; \
sign = -1; \
dx = -dx; \
if (dx >= dy) { \
step = - (dx / dy); \
dx = dx % dy; \
} \
} \
} \
x += sx; \
vertex = c; \
}
#define Step(x,dx,dy,e,sign,step) {\
x += step; \
if ((e += dx) > 0) \
{ \
x += sign; \
e -= dy; \
} \
}
sy += y;
DRAW_DEBUG ((DEBUG_POLYGON, "Starting polygon at %d", sy));
for (;;)
{
DRAW_DEBUG ((DEBUG_POLYGON, "vertex1 0x%x vertex2 0x%x y %d vy1 %d vy2 %d",
vertex1, vertex2,
y, intToY(vertex1), intToY (vertex2)));
if (y == intToY(vertex1))
{
DRAW_DEBUG ((DEBUG_POLYGON, "Find next -- vertext"));
do
{
if (vertex1p == (int *) ptsIn)
vertex1p = endp;
c = *--vertex1p;
Setup (c,x1,vertex1,dx1,dy1,e1,sign1,step1);
DRAW_DEBUG ((DEBUG_POLYGON, "-- vertex 0x%x y %d",
vertex1, intToY(vertex1)));
} while (y >= intToY(vertex1));
h = dy1;
}
else
{
Step(x1,dx1,dy1,e1,sign1,step1)
h = intToY(vertex1) - y;
}
if (y == intToY(vertex2))
{
DRAW_DEBUG ((DEBUG_POLYGON, "Find next ++ vertext"));
do
{
c = *vertex2p++;
if (vertex2p == endp)
vertex2p = (int *) ptsIn;
Setup (c,x2,vertex2,dx2,dy2,e2,sign2,step2)
DRAW_DEBUG ((DEBUG_POLYGON, "++ vertex 0x%x y %d",
vertex1, intToY(vertex1)));
} while (y >= intToY(vertex2));
if (dy2 < h)
h = dy2;
}
else
{
Step(x2,dx2,dy2,e2,sign2,step2)
if ((c = (intToY(vertex2) - y)) < h)
h = c;
}
DRAW_DEBUG ((DEBUG_POLYGON, "This band %d", h));
/* fill spans for this segment */
for (;;)
{
nmiddle = x2 - x1;
DRAW_DEBUG ((DEBUG_POLYGON, "This span %d->%d", x1, x2));
if (nmiddle)
{
l = x1;
if (nmiddle < 0)
{
nmiddle = -nmiddle;
l = x2;
}
_s3SolidRect(s3,l,sy,nmiddle,1);
}
y++;
sy++;
if (!--h)
break;
Step(x1,dx1,dy1,e1,sign1,step1)
Step(x2,dx2,dy2,e2,sign2,step2)
}
if (y == maxy)
break;
}
MarkSyncS3 (pDrawable->pScreen);
}
void
s3PolyGlyphBltClipped (DrawablePtr pDrawable,
GCPtr pGC,
int x, int y,
unsigned int nglyph,
CharInfoPtr *ppciInit,
pointer pglyphBase)
{
SetupS3(pDrawable->pScreen);
int h;
int w;
int xBack, yBack;
int hBack, wBack;
int lw;
FontPtr pfont = pGC->font;
CharInfoPtr pci;
unsigned long *bits;
BoxPtr extents;
BoxRec bbox;
CARD32 b;
CharInfoPtr *ppci;
FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC);
RegionPtr pClip = fbGetCompositeClip(pGC);
BoxPtr pBox;
int nbox;
int x1, y1, x2, y2;
unsigned char alu;
Bool set;
PixTransDeclare;
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
x += pDrawable->x;
y += pDrawable->y;
if (pglyphBase == (pointer) 1)
{
xBack = x;
yBack = y - FONTASCENT(pGC->font);
wBack = 0;
hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
if (hBack)
{
h = nglyph;
ppci = ppciInit;
while (h--)
wBack += (*ppci++)->metrics.characterWidth;
}
if (wBack < 0)
{
xBack = xBack + wBack;
wBack = -wBack;
}
if (hBack < 0)
{
yBack = yBack + hBack;
hBack = -hBack;
}
alu = GXcopy;
}
else
{
wBack = 0;
alu = pGC->alu;
}
if (wBack)
{
_s3SetSolidFill (s3, pGC->bgPixel, GXcopy, pGC->planemask);
for (nbox = REGION_NUM_RECTS (pClip),
pBox = REGION_RECTS (pClip);
nbox--;
pBox++)
{
x1 = xBack;
x2 = xBack + wBack;
y1 = yBack;
y2 = yBack + hBack;
if (x1 < pBox->x1) x1 = pBox->x1;
if (x2 > pBox->x2) x2 = pBox->x2;
if (y1 < pBox->y1) y1 = pBox->y1;
if (y2 > pBox->y2) y2 = pBox->y2;
if (x1 < x2 && y1 < y2)
{
_s3SolidRect (s3, x1, y1, x2 - x1, y2 - y1);
}
}
MarkSyncS3 (pDrawable->pScreen);
}
ppci = ppciInit;
set = FALSE;
while (nglyph--)
{
pci = *ppci++;
h = pci->metrics.ascent + pci->metrics.descent;
w = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
x1 = x + pci->metrics.leftSideBearing;
y1 = y - pci->metrics.ascent;
bbox.x1 = x1;
bbox.y1 = y1;
bbox.x2 = x1 + w;
bbox.y2 = y1 + h;
switch (RECT_IN_REGION(pGC->pScreen, pClip, &bbox))
{
case rgnIN:
#if 1
lw = h * ((w + 31) >> 5);
if (lw)
{
if (!set)
{
_s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel);
set = TRUE;
}
_s3PlaneBlt(s3,
x + pci->metrics.leftSideBearing,
y - pci->metrics.ascent,
w, h);
bits = (unsigned long *) pci->bits;
PixTransStart (lw);
while (lw--)
{
b = *bits++;
S3AdjustBits32 (b);
PixTransStore(b);
}
MarkSyncS3 (pDrawable->pScreen);
}
break;
#endif
case rgnPART:
set = FALSE;
CheckSyncS3 (pDrawable->pScreen);
fbPutXYImage (pDrawable,
pClip,
fbPriv->fg,
fbPriv->bg,
fbPriv->pm,
alu,
FALSE,
x1, y1,
w, h,
(FbStip *) pci->bits,
(w + 31) >> 5,
0);
break;
case rgnOUT:
break;
}
x += pci->metrics.characterWidth;
}
}
/*
* Blt glyphs using S3 image transfer register, this does both
* poly glyph blt and image glyph blt (when pglyphBase == 1)
*/
void
s3PolyGlyphBlt (DrawablePtr pDrawable,
GCPtr pGC,
int x, int y,
unsigned int nglyph,
CharInfoPtr *ppciInit,
pointer pglyphBase)
{
SetupS3(pDrawable->pScreen);
int h;
int w;
int xBack, yBack;
int hBack, wBack;
int lw;
FontPtr pfont = pGC->font;
CharInfoPtr pci;
unsigned long *bits;
BoxPtr extents;
BoxRec bbox;
CARD32 b;
CharInfoPtr *ppci;
unsigned char alu;
PixTransDeclare;
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
x += pDrawable->x;
y += pDrawable->y;
/* compute an approximate (but covering) bounding box */
ppci = ppciInit;
w = 0;
h = nglyph;
while (h--)
w += (*ppci++)->metrics.characterWidth;
if (w < 0)
{
bbox.x1 = x + w;
bbox.x2 = x;
}
else
{
bbox.x1 = x;
bbox.x2 = x + w;
}
w = FONTMINBOUNDS(pfont,leftSideBearing);
if (w < 0)
bbox.x1 += w;
w = FONTMAXBOUNDS(pfont, rightSideBearing) - FONTMINBOUNDS(pfont, characterWidth);
if (w > 0)
bbox.x2 += w;
bbox.y1 = y - FONTMAXBOUNDS(pfont,ascent);
bbox.y2 = y + FONTMAXBOUNDS(pfont,descent);
DRAW_DEBUG ((DEBUG_TEXT, "PolyGlyphBlt %d box is %d %d", nglyph,
bbox.x1, bbox.x2));
switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox))
{
case rgnIN:
break;
case rgnPART:
s3PolyGlyphBltClipped(pDrawable, pGC, x - pDrawable->x,
y - pDrawable->y,
nglyph, ppciInit, pglyphBase);
case rgnOUT:
return;
}
if (pglyphBase == (pointer) 1)
{
xBack = x;
yBack = y - FONTASCENT(pGC->font);
wBack = 0;
hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
if (hBack)
{
h = nglyph;
ppci = ppciInit;
while (h--)
wBack += (*ppci++)->metrics.characterWidth;
}
if (wBack < 0)
{
xBack = xBack + wBack;
wBack = -wBack;
}
if (hBack < 0)
{
yBack = yBack + hBack;
hBack = -hBack;
}
alu = GXcopy;
}
else
{
wBack = 0;
alu = pGC->alu;
}
if (wBack)
{
_s3SetSolidFill (s3, pGC->bgPixel, GXcopy, pGC->planemask);
_s3SolidRect (s3, xBack, yBack, wBack, hBack);
}
_s3SetTransparentPlaneBlt (s3, alu, pGC->planemask, pGC->fgPixel);
ppci = ppciInit;
while (nglyph--)
{
pci = *ppci++;
h = pci->metrics.ascent + pci->metrics.descent;
w = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
lw = h * ((w + 31) >> 5);
if (lw)
{
_s3PlaneBlt(s3,
x + pci->metrics.leftSideBearing,
y - pci->metrics.ascent,
w, h);
bits = (unsigned long *) pci->bits;
PixTransStart(lw);
while (lw--)
{
b = *bits++;
S3AdjustBits32 (b);
PixTransStore(b);
}
}
x += pci->metrics.characterWidth;
}
MarkSyncS3 (pDrawable->pScreen);
}
void
s3ImageGlyphBlt (DrawablePtr pDrawable,
GCPtr pGC,
int x, int y,
unsigned int nglyph,
CharInfoPtr *ppci,
pointer pglyphBase)
{
s3PolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, (pointer) 1);
}
/*
* Blt TE fonts using S3 image transfer. Differs from
* above in that it doesn't need to fill a solid rect for
* the background and it can draw multiple characters at a time
*/
void
s3ImageTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
int xInit, int yInit,
unsigned int nglyph,
CharInfoPtr *ppci,
pointer pglyphBase)
{
SetupS3(pDrawable->pScreen);
int x, y;
int h, lw, lwTmp;
int w;
FontPtr pfont = pGC->font;
unsigned long *char1, *char2, *char3, *char4;
int widthGlyphs, widthGlyph;
BoxRec bbox;
CARD32 tmp;
PixTransDeclare;
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
widthGlyph = FONTMAXBOUNDS(pfont,characterWidth);
if (!widthGlyph)
return;
h = FONTASCENT(pfont) + FONTDESCENT(pfont);
if (!h)
return;
DRAW_DEBUG ((DEBUG_TEXT, "ImageTEGlyphBlt chars are %d %d",
widthGlyph, h));
x = xInit + FONTMAXBOUNDS(pfont,leftSideBearing) + pDrawable->x;
y = yInit - FONTASCENT(pfont) + pDrawable->y;
bbox.x1 = x;
bbox.x2 = x + (widthGlyph * nglyph);
bbox.y1 = y;
bbox.y2 = y + h;
switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox))
{
case rgnIN:
break;
case rgnPART:
if (pglyphBase == (pointer) 1)
pglyphBase = 0;
else
pglyphBase = (pointer) 1;
s3PolyGlyphBltClipped(pDrawable, pGC,
xInit,
yInit,
nglyph, ppci,
pglyphBase);
case rgnOUT:
return;
}
if (pglyphBase == (pointer) 1)
{
_s3SetTransparentPlaneBlt (s3, pGC->alu, pGC->planemask, pGC->fgPixel);
}
else
{
_s3SetOpaquePlaneBlt (s3, GXcopy, pGC->planemask, pGC->fgPixel, pGC->bgPixel);
}
#if BITMAP_BIT_ORDER == LSBFirst
#define SHIFT <<
#else
#define SHIFT >>
#endif
#define LoopIt(count, w, loadup, fetch) \
while (nglyph >= count) \
{ \
nglyph -= count; \
_s3PlaneBlt (s3, x, y, w, h); \
x += w; \
loadup \
lwTmp = h; \
PixTransStart(h); \
while (lwTmp--) { \
tmp = fetch; \
S3AdjustBits32(tmp); \
PixTransStore(tmp); \
} \
}
if (widthGlyph <= 8)
{
widthGlyphs = widthGlyph << 2;
LoopIt(4, widthGlyphs,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;
char3 = (unsigned long *) (*ppci++)->bits;
char4 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | ((*char2++ | ((*char3++ | (*char4++
SHIFT widthGlyph))
SHIFT widthGlyph))
SHIFT widthGlyph)))
}
else if (widthGlyph <= 10)
{
widthGlyphs = (widthGlyph << 1) + widthGlyph;
LoopIt(3, widthGlyphs,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;
char3 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | ((*char2++ | (*char3++ SHIFT widthGlyph)) SHIFT widthGlyph)))
}
else if (widthGlyph <= 16)
{
widthGlyphs = widthGlyph << 1;
LoopIt(2, widthGlyphs,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | (*char2++ SHIFT widthGlyph)))
}
lw = h * ((widthGlyph + 31) >> 5);
while (nglyph--)
{
_s3PlaneBlt (s3, x, y, widthGlyph, h);
x += widthGlyph;
char1 = (unsigned long *) (*ppci++)->bits;
lwTmp = lw;
PixTransStart(lw);
while (lwTmp--)
{
tmp = *char1++;
S3AdjustBits32(tmp);
PixTransStore(tmp);
}
}
MarkSyncS3 (pDrawable->pScreen);
}
void
s3PolyTEGlyphBlt (DrawablePtr pDrawable, GCPtr pGC,
int x, int y,
unsigned int nglyph, CharInfoPtr *ppci,
pointer pglyphBase)
{
s3ImageTEGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, (pointer) 1);
}
Bool
_s3Segment (DrawablePtr pDrawable,
GCPtr pGC,
int x1,
int y1,
int x2,
int y2,
Bool drawLast,
Bool s3Set)
{
SetupS3(pDrawable->pScreen);
FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
RegionPtr pClip = fbGetCompositeClip(pGC);
BoxPtr pBox;
int nBox;
int adx; /* abs values of dx and dy */
int ady;
int signdx; /* sign of dx and dy */
int signdy;
int e, e1, e2; /* bresenham error and increments */
int len; /* length of segment */
int axis; /* major axis */
int octant;
int cmd;
unsigned int bias = miGetZeroLineBias(pDrawable->pScreen);
unsigned int oc1; /* outcode of point 1 */
unsigned int oc2; /* outcode of point 2 */
CalcLineDeltas(x1, y1, x2, y2, adx, ady, signdx, signdy,
1, 1, octant);
cmd = LASTPIX;
if (adx > ady)
{
axis = X_AXIS;
e1 = ady << 1;
e2 = e1 - (adx << 1);
e = e1 - adx;
len = adx;
}
else
{
cmd |= YMAJAXIS;
axis = Y_AXIS;
e1 = adx << 1;
e2 = e1 - (ady << 1);
e = e1 - ady;
SetYMajorOctant(octant);
len = ady;
}
/* S3 line drawing hardware has limited resolution for error terms */
if (len >= 4096)
{
int dashOff = 0;
KdCheckSync (pDrawable->pScreen);
fbSegment (pDrawable, pGC, x1, y1, x2, y2, drawLast, &dashOff);
return FALSE;
}
FIXUP_ERROR (e, octant, bias);
nBox = REGION_NUM_RECTS (pClip);
pBox = REGION_RECTS (pClip);
if (signdx > 0)
cmd |= INC_X;
if (signdy > 0)
cmd |= INC_Y;
/* we have bresenham parameters and two points.
all we have to do now is clip and draw.
*/
if (drawLast)
len++;
while(nBox--)
{
oc1 = 0;
oc2 = 0;
OUTCODES(oc1, x1, y1, pBox);
OUTCODES(oc2, x2, y2, pBox);
if ((oc1 | oc2) == 0)
{
if (!s3Set)
{
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
_s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
s3Set = TRUE;
}
_s3SetCur (s3, x1, y1);
_s3ClipLine (s3, cmd, e1, e2, e, len);
break;
}
else if (oc1 & oc2)
{
pBox++;
}
else
{
int new_x1 = x1, new_y1 = y1, new_x2 = x2, new_y2 = y2;
int clip1 = 0, clip2 = 0;
int clipdx, clipdy;
int err;
if (miZeroClipLine(pBox->x1, pBox->y1, pBox->x2-1,
pBox->y2-1,
&new_x1, &new_y1, &new_x2, &new_y2,
adx, ady, &clip1, &clip2,
octant, bias, oc1, oc2) == -1)
{
pBox++;
continue;
}
if (axis == X_AXIS)
len = abs(new_x2 - new_x1);
else
len = abs(new_y2 - new_y1);
if (clip2 != 0 || drawLast)
len++;
if (len)
{
/* unwind bresenham error term to first point */
err = e;
if (clip1)
{
clipdx = abs(new_x1 - x1);
clipdy = abs(new_y1 - y1);
if (axis == X_AXIS)
err += (e2 - e1) * clipdy + e1 * clipdx;
else
err += (e2 - e1) * clipdx + e1 * clipdy;
}
if (!s3Set)
{
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
_s3SetSolidFill (s3, pGC->fgPixel, pGC->alu, pGC->planemask);
s3Set = TRUE;
}
_s3SetCur (s3, new_x1, new_y1);
_s3ClipLine (s3, cmd, e1, e2, err, len);
}
pBox++;
}
} /* while (nBox--) */
return s3Set;
}
void
s3Polylines (DrawablePtr pDrawable, GCPtr pGC,
int mode, int npt, DDXPointPtr ppt)
{
SetupS3(pDrawable->pScreen);
int x, y, nx, ny;
int ox = pDrawable->x, oy = pDrawable->y;
Bool s3Set = FALSE;
if (!npt)
return;
x = ppt->x + ox;
y = ppt->y + oy;
while (--npt)
{
++ppt;
if (mode == CoordModePrevious)
{
nx = x + ppt->x;
ny = y + ppt->y;
}
else
{
nx = ppt->x + ox;
ny = ppt->y + oy;
}
s3Set = _s3Segment (pDrawable, pGC, x, y, nx, ny,
npt == 1 && pGC->capStyle != CapNotLast,
s3Set);
x = nx;
y = ny;
}
if (s3Set)
MarkSyncS3 (pDrawable->pScreen);
}
void
s3PolySegment (DrawablePtr pDrawable, GCPtr pGC,
int nsegInit, xSegment *pSegInit)
{
SetupS3(pDrawable->pScreen);
int x, y;
int ox = pDrawable->x, oy = pDrawable->y;
RegionPtr pClip = fbGetCompositeClip (pGC);
BoxPtr pBox;
int nbox;
int nseg;
xSegment *pSeg;
int dx, dy;
int maj, min, len, inc;
int t;
CARD32 cmd;
CARD32 init_cmd;
Bool drawLast;
Bool s3Set = FALSE;
drawLast = pGC->capStyle != CapNotLast;
for (nseg = nsegInit, pSeg = pSegInit; nseg--; pSeg++)
{
s3Set = _s3Segment (pDrawable, pGC, pSeg->x1 + ox, pSeg->y1 + oy,
pSeg->x2 + ox, pSeg->y2 + oy, drawLast, s3Set);
}
if (s3Set)
MarkSyncS3 (pDrawable->pScreen);
}
/*
* Check to see if a pattern can be painted with the S3
*/
#define _s3CheckPatternSize(s) ((s) <= S3_TILE_SIZE && ((s) & ((s) - 1)) == 0)
#define s3CheckPattern(w,h) (_s3CheckPatternSize(w) && _s3CheckPatternSize(h))
Bool
s3AllocPattern (ScreenPtr pScreen,
int ma,
PixmapPtr pPixmap,
int xorg, int yorg,
int fillStyle, Pixel fg, Pixel bg,
s3PatternPtr *ppPattern)
{
KdScreenPriv(pScreen);
s3ScreenInfo(pScreenPriv);
s3PatternPtr pPattern;
if (s3s->fb[ma].patterns.cache && fillStyle != FillSolid &&
s3CheckPattern (pPixmap->drawable.width, pPixmap->drawable.height))
{
if (!(pPattern = *ppPattern))
{
pPattern = (s3PatternPtr) xalloc (sizeof (s3PatternRec));
if (!pPattern)
return FALSE;
*ppPattern = pPattern;
}
pPattern->cache = 0;
pPattern->id = 0;
pPattern->pPixmap = pPixmap;
pPattern->fillStyle = fillStyle;
pPattern->xrot = (-xorg) & (S3_TILE_SIZE-1);
pPattern->yrot = (-yorg) & (S3_TILE_SIZE-1);
pPattern->fore = fg;
pPattern->back = bg;
return TRUE;
}
else
{
if (*ppPattern)
{
xfree (*ppPattern);
*ppPattern = 0;
}
return FALSE;
}
}
void
s3CheckGCFill (GCPtr pGC)
{
s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC);
PixmapPtr pPixmap;
switch (pGC->fillStyle) {
case FillSolid:
pPixmap = 0;
break;
case FillOpaqueStippled:
case FillStippled:
pPixmap = pGC->stipple;
break;
case FillTiled:
pPixmap = pGC->tile.pixmap;
break;
}
s3AllocPattern (pGC->pScreen,
s3GCMap(pGC),
pPixmap,
pGC->patOrg.x + pGC->lastWinOrg.x,
pGC->patOrg.y + pGC->lastWinOrg.y,
pGC->fillStyle, pGC->fgPixel, pGC->bgPixel,
&s3Priv->pPattern);
}
void
s3MoveGCFill (GCPtr pGC)
{
s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC);
int xorg, yorg;
s3PatternPtr pPattern;
if (pPattern = s3Priv->pPattern)
{
/*
* Reset origin
*/
xorg = pGC->patOrg.x + pGC->lastWinOrg.x;
yorg = pGC->patOrg.y + pGC->lastWinOrg.y;
pPattern->xrot = (-xorg) & (S3_TILE_SIZE - 1);
pPattern->yrot = (-yorg) & (S3_TILE_SIZE - 1);
/*
* Invalidate cache entry
*/
pPattern->id = 0;
pPattern->cache = 0;
}
}
/*
* S3 Patterns. These are always full-depth images, stored in off-screen
* memory.
*/
Pixel
s3FetchPatternPixel (s3PatternPtr pPattern, int x, int y)
{
CARD8 *src;
CARD16 *src16;
CARD32 *src32;
PixmapPtr pPixmap = pPattern->pPixmap;
x = (x + pPattern->xrot) % pPixmap->drawable.width;
y = (y + pPattern->yrot) % pPixmap->drawable.height;
src = (CARD8 *) pPixmap->devPrivate.ptr + y * pPixmap->devKind;
switch (pPixmap->drawable.bitsPerPixel) {
case 1:
return (src[x>>3] >> (x & 7)) & 1 ? 0xffffffff : 0x00;
case 4:
if (x & 1)
return src[x>>1] >> 4;
else
return src[x>>1] & 0xf;
case 8:
return src[x];
case 16:
src16 = (CARD16 *) src;
return src16[x];
case 32:
src32 = (CARD32 *) src;
return src32[x];
}
}
/*
* Place pattern image on screen; done with S3 locked
*/
void
_s3PutPattern (ScreenPtr pScreen, int ma, s3PatternPtr pPattern)
{
SetupS3(pScreen);
s3ScreenInfo(pScreenPriv);
int x, y;
CARD8 *dstLine, *dst8;
CARD16 *dst16;
CARD32 *dst32;
S3PatternCache *cache = pPattern->cache;
#ifdef S3_TRIO
int fb = 0;
#else
int fb = s3s->fbmap[ma];
#endif
DRAW_DEBUG ((DEBUG_PATTERN, "_s3PutPattern 0x%x id %d to %d %d",
pPattern, pPattern->id, cache->x, cache->y));
dstLine = (pScreenPriv->screen->fb[fb].frameBuffer +
cache->y * pScreenPriv->screen->fb[fb].byteStride +
cache->x * pScreenPriv->bytesPerPixel[fb]);
CheckSyncS3 (pScreen);
for (y = 0; y < S3_TILE_SIZE; y++)
{
switch (pScreenPriv->screen->fb[fb].bitsPerPixel) {
case 8:
dst8 = dstLine;
for (x = 0; x < S3_TILE_SIZE; x++)
*dst8++ = s3FetchPatternPixel (pPattern, x, y);
DRAW_DEBUG ((DEBUG_PATTERN, "%c%c%c%c%c%c%c%c",
dstLine[0] ? 'X' : ' ',
dstLine[1] ? 'X' : ' ',
dstLine[2] ? 'X' : ' ',
dstLine[3] ? 'X' : ' ',
dstLine[4] ? 'X' : ' ',
dstLine[5] ? 'X' : ' ',
dstLine[6] ? 'X' : ' ',
dstLine[7] ? 'X' : ' '));
break;
case 16:
dst16 = (CARD16 *) dstLine;
for (x = 0; x < S3_TILE_SIZE; x++)
*dst16++ = s3FetchPatternPixel (pPattern, x, y);
break;
case 32:
dst32 = (CARD32 *) dstLine;
for (x = 0; x < S3_TILE_SIZE; x++)
*dst32++ = s3FetchPatternPixel (pPattern, x, y);
break;
}
dstLine += pScreenPriv->screen->fb[fb].byteStride;
}
}
/*
* Load a stipple to off-screen memory; done with S3 locked
*/
void
_s3LoadPattern (ScreenPtr pScreen, int ma, s3PatternPtr pPattern)
{
SetupS3(pScreen);
s3ScreenInfo(pScreenPriv);
S3PatternCache *cache;
DRAW_DEBUG((DEBUG_PATTERN,
"s3LoadPattern 0x%x id %d cache 0x%x cacheid %d",
pPattern, pPattern->id, pPattern->cache,
pPattern->cache ? pPattern->cache->id : -1));
/*
* Check to see if its still loaded
*/
cache = pPattern->cache;
if (cache && cache->id == pPattern->id)
return;
/*
* Lame replacement strategy; assume we'll have plenty of room.
*/
cache = &s3s->fb[ma].patterns.cache[s3s->fb[ma].patterns.last_used];
if (++s3s->fb[ma].patterns.last_used == s3s->fb[ma].patterns.ncache)
s3s->fb[ma].patterns.last_used = 0;
cache->id = ++s3s->fb[ma].patterns.last_id;
pPattern->id = cache->id;
pPattern->cache = cache;
_s3PutPattern (pScreen, ma, pPattern);
}
void
s3DestroyGC (GCPtr pGC)
{
s3PrivGCPtr s3Priv = s3GetGCPrivate (pGC);
if (s3Priv->pPattern)
xfree (s3Priv->pPattern);
miDestroyGC (pGC);
}
GCFuncs s3GCFuncs = {
s3ValidateGC,
miChangeGC,
miCopyGC,
s3DestroyGC,
miChangeClip,
miDestroyClip,
miCopyClip
};
int
s3CreateGC (GCPtr pGC)
{
KdScreenPriv(pGC->pScreen);
s3ScreenInfo(pScreenPriv);
s3PrivGCPtr s3Priv;
if (!fbCreateGC (pGC))
return FALSE;
if (pGC->depth != 1)
pGC->funcs = &s3GCFuncs;
s3Priv = s3GetGCPrivate(pGC);
s3Priv->type = DRAWABLE_PIXMAP;
s3Priv->pPattern = 0;
#ifndef S3_TRIO
if (pGC->depth == s3s->primary_depth)
s3Priv->ma = 0;
else
s3Priv->ma = 1;
#endif
return TRUE;
}
Bool
s3CreateWindow (WindowPtr pWin)
{
KdScreenPriv(pWin->drawable.pScreen);
s3ScreenInfo(pScreenPriv);
dixSetPrivate(&pWin->devPrivates, s3WindowPrivateKey, NULL);
return KdCreateWindow (pWin);
}
Bool
s3DestroyWindow (WindowPtr pWin)
{
s3PatternPtr pPattern;
if (pPattern = s3GetWindowPrivate(pWin))
xfree (pPattern);
return fbDestroyWindow (pWin);
}
Bool
s3ChangeWindowAttributes (WindowPtr pWin, Mask mask)
{
KdScreenPriv(pWin->drawable.pScreen);
Bool ret;
s3PatternPtr pPattern;
PixmapPtr pPixmap;
int fillStyle;
ret = fbChangeWindowAttributes (pWin, mask);
if (mask & CWBackPixmap)
{
if (pWin->backgroundState == BackgroundPixmap)
{
pPixmap = pWin->background.pixmap;
fillStyle = FillTiled;
}
else
{
pPixmap = 0;
fillStyle = FillSolid;
}
pPattern = s3GetWindowPrivate(pWin);
s3AllocPattern (pWin->drawable.pScreen,
s3DrawMap (&pWin->drawable),
pPixmap,
pWin->drawable.x, pWin->drawable.y,
fillStyle, 0, 0, &pPattern);
DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "Background pattern 0x%x pixmap 0x%x style %d",
pPattern, pPixmap, fillStyle));
s3SetWindowPrivate (pWin, pPattern);
}
return ret;
}
#ifndef S3_TRIO
void
s3PaintKey (DrawablePtr pDrawable,
RegionPtr pRegion,
CARD32 pixel,
int fb)
{
SetupS3 (pDrawable->pScreen);
s3ScreenInfo (pScreenPriv);
int nBox = REGION_NUM_RECTS(pRegion);
BoxPtr pBox = REGION_RECTS(pRegion);
int ma;
if (!nBox)
return;
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
if (s3s->fbmap[ma] == fb)
break;
s3SetGlobalBitmap (pDrawable->pScreen, ma);
_s3SetSolidFill (s3, pixel, GXcopy, 0xffffffff);
while (nBox--)
{
_s3SolidRect(s3,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1);
pBox++;
}
MarkSyncS3 (pDrawable->pScreen);
}
#endif
void
s3PaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
{
SetupS3(pWin->drawable.pScreen);
s3ScreenInfo(pScreenPriv);
s3PatternPtr pPattern;
DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "s3PaintWindow 0x%x extents %d %d %d %d n %d",
pWin->drawable.id,
pRegion->extents.x1, pRegion->extents.y1,
pRegion->extents.x2, pRegion->extents.y2,
REGION_NUM_RECTS(pRegion)));
if (!REGION_NUM_RECTS(pRegion))
return;
switch (what) {
case PW_BACKGROUND:
switch (pWin->backgroundState) {
case None:
return;
case ParentRelative:
do {
pWin = pWin->parent;
} while (pWin->backgroundState == ParentRelative);
(*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
what);
return;
case BackgroundPixmap:
pPattern = s3GetWindowPrivate(pWin);
if (pPattern)
{
s3FillBoxPattern ((DrawablePtr)pWin,
(int)REGION_NUM_RECTS(pRegion),
REGION_RECTS(pRegion),
GXcopy, ~0, pPattern);
return;
}
break;
case BackgroundPixel:
s3FillBoxSolid((DrawablePtr)pWin,
(int)REGION_NUM_RECTS(pRegion),
REGION_RECTS(pRegion),
pWin->background.pixel, GXcopy, ~0);
return;
}
break;
case PW_BORDER:
#ifndef S3_TRIO
if (s3s->fbmap[1] >= 0)
fbOverlayUpdateLayerRegion (pWin->drawable.pScreen,
fbOverlayWindowLayer (pWin),
pRegion);
#endif
if (pWin->borderIsPixel)
{
s3FillBoxSolid((DrawablePtr)pWin,
(int)REGION_NUM_RECTS(pRegion),
REGION_RECTS(pRegion),
pWin->border.pixel, GXcopy, ~0);
return;
}
break;
}
KdCheckPaintWindow (pWin, pRegion, what);
}
void
s3CopyWindowProc (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pboxOrig,
int nboxOrig,
int dx,
int dy,
Bool reverse,
Bool upsidedown,
Pixel bitplane,
void *closure)
{
SetupS3(pDstDrawable->pScreen);
s3ScreenInfo(pScreenPriv);
KdScreenInfo *screen = pScreenPriv->screen;
int srcX, srcY, dstX, dstY;
int x1, x2;
int w, h;
int flags;
int fb = (int) closure;
int ma;
BoxPtr pbox;
int nbox;
int bitsPerPixel;
#ifdef S3_TRIO
ma = 0;
#else
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
if (s3s->fbmap[ma] == fb)
break;
#endif
bitsPerPixel = screen->fb[fb].bitsPerPixel;
if (bitsPerPixel == 24)
dx *= 3;
nbox = nboxOrig;
pbox = pboxOrig;
s3SetGlobalBitmap (pDstDrawable->pScreen, ma);
_s3SetBlt(s3,GXcopy,~0);
while (nbox--)
{
x1 = pbox->x1;
x2 = pbox->x2;
if (bitsPerPixel == 24)
{
x1 *= 3;
x2 *= 3;
}
w = x2 - x1;
h = pbox->y2 - pbox->y1;
flags = 0;
if (reverse)
{
dstX = x2 - 1;
}
else
{
dstX = x1;
flags |= INC_X;
}
srcX = dstX + dx;
if (upsidedown)
{
dstY = pbox->y2 - 1;
}
else
{
dstY = pbox->y1;
flags |= INC_Y;
}
srcY = dstY + dy;
_s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags);
pbox++;
}
MarkSyncS3 (pDstDrawable->pScreen);
}
void
s3CopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
KdScreenPriv (pScreen);
s3ScreenInfo (pScreenPriv);
KdScreenInfo *screen = pScreenPriv->screen;
RegionRec rgnDst;
int dx, dy;
WindowPtr pwinRoot;
pwinRoot = WindowTable[pWin->drawable.pScreen->myNum];
dx = ptOldOrg.x - pWin->drawable.x;
dy = ptOldOrg.y - pWin->drawable.y;
REGION_TRANSLATE(pWin->drawable.pScreen, prgnSrc, -dx, -dy);
REGION_INIT (pWin->drawable.pScreen, &rgnDst, NullBox, 0);
REGION_INTERSECT(pWin->drawable.pScreen, &rgnDst,
&pWin->borderClip, prgnSrc);
fbCopyRegion ((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot,
0,
&rgnDst, dx, dy, s3CopyWindowProc, 0, 0);
REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
}
void
s3_24FillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
unsigned long pixel, int alu, unsigned long planemask)
{
SetupS3(pDrawable->pScreen);
register int r;
int x1, x2;
s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
_s3SetSolidFill(s3,pixel,alu,planemask);
while (nBox--) {
x1 = pBox->x1 * 3;
x2 = pBox->x2 * 3;
_s3SolidRect(s3,x1,pBox->y1,x2-x1,pBox->y2-pBox->y1);
pBox++;
}
MarkSyncS3 (pDrawable->pScreen);
}
#define ok24(p) (((p) & 0xffffff) == ((((p) & 0xff) << 16) | (((p) >> 8) & 0xffff)))
void
s3_24FillSpans (DrawablePtr pDrawable, GCPtr pGC, int n,
DDXPointPtr ppt, int *pwidth, int fSorted)
{
SetupS3(pDrawable->pScreen);
int x, y, x1, y1, x2, y2;
int width;
/* next three parameters are post-clip */
int nTmp;
int *pwidthFree;/* copies of the pointers to free */
DDXPointPtr pptFree;
BoxPtr extents;
RegionPtr pClip = fbGetCompositeClip (pGC);
if (pGC->fillStyle != FillSolid || !ok24 (pGC->fgPixel) || !ok24(pGC->planemask))
{
KdCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
return;
}
s3SetGlobalBitmap (pDrawable->pScreen, s3GCMap (pGC));
if (REGION_NUM_RECTS(pClip) == 1)
{
extents = REGION_RECTS(pClip);
x1 = extents->x1;
x2 = extents->x2;
y1 = extents->y1;
y2 = extents->y2;
_s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
while (n--)
{
y = ppt->y;
if (y1 <= y && y < y2)
{
x = ppt->x;
width = *pwidth;
if (x < x1)
{
width -= (x1 - x);
x = x1;
}
if (x2 < x + width)
width = x2 - x;
if (width > 0)
{
_s3SolidRect(s3,x*3,y,width*3,1);
}
}
ppt++;
pwidth++;
}
}
else
{
nTmp = n * miFindMaxBand(pClip);
pwidthFree = (int *)ALLOCATE_LOCAL(nTmp * sizeof(int));
pptFree = (DDXPointRec *)ALLOCATE_LOCAL(nTmp * sizeof(DDXPointRec));
if(!pptFree || !pwidthFree)
{
if (pptFree) DEALLOCATE_LOCAL(pptFree);
if (pwidthFree) DEALLOCATE_LOCAL(pwidthFree);
return;
}
n = miClipSpans(fbGetCompositeClip(pGC),
ppt, pwidth, n,
pptFree, pwidthFree, fSorted);
pwidth = pwidthFree;
ppt = pptFree;
_s3SetSolidFill(s3,pGC->fgPixel,pGC->alu,pGC->planemask);
while (n--)
{
x = ppt->x;
y = ppt->y;
ppt++;
width = *pwidth++;
if (width)
{
_s3SolidRect(s3,x*3,y,width*3,1);
}
}
DEALLOCATE_LOCAL(pptFree);
DEALLOCATE_LOCAL(pwidthFree);
}
MarkSyncS3 (pDrawable->pScreen);
}
void
s3_24CopyNtoN (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse,
Bool upsidedown,
Pixel bitplane,
void *closure)
{
SetupS3(pDstDrawable->pScreen);
int srcX, srcY, dstX, dstY;
int w, h;
int flags;
int x1, x2;
if (sourceInvarient (pGC->alu))
{
s3_24FillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu, pGC->planemask);
return;
}
s3SetGlobalBitmap (pDstDrawable->pScreen, s3GCMap (pGC));
_s3SetBlt(s3,pGC->alu,pGC->planemask);
DRAW_DEBUG ((DEBUG_RENDER, "s3CopyNtoN alu %d planemask 0x%x",
pGC->alu, pGC->planemask));
dx *= 3;
while (nbox--)
{
x1 = pbox->x1 * 3;
x2 = pbox->x2 * 3;
w = x2 - x1;
h = pbox->y2 - pbox->y1;
flags = 0;
if (reverse)
{
dstX = x2 - 1;
}
else
{
dstX = x1;
flags |= INC_X;
}
srcX = dstX + dx;
if (upsidedown)
{
dstY = pbox->y2 - 1;
}
else
{
dstY = pbox->y1;
flags |= INC_Y;
}
srcY = dstY + dy;
_s3Blt (s3, srcX, srcY, dstX, dstY, w, h, flags);
pbox++;
}
MarkSyncS3 (pSrcDrawable->pScreen);
}
RegionPtr
s3_24CopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty)
{
SetupS3(pDstDrawable->pScreen);
if (pSrcDrawable->type == DRAWABLE_WINDOW &&
pDstDrawable->type == DRAWABLE_WINDOW &&
ok24(pGC->planemask))
{
return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, s3_24CopyNtoN, 0, 0);
}
return KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height, dstx, dsty);
}
#define NUM_STACK_RECTS 1024
void
s3_24PolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
int nrectFill, xRectangle *prectInit)
{
s3GCPrivate(pGC);
xRectangle *prect;
RegionPtr prgnClip;
register BoxPtr pbox;
register BoxPtr pboxClipped;
BoxPtr pboxClippedBase;
BoxPtr pextent;
BoxRec stackRects[NUM_STACK_RECTS];
int numRects;
int n;
int xorg, yorg;
int x, y;
if (pGC->fillStyle != FillSolid || !ok24 (pGC->fgPixel) || !ok24(pGC->planemask))
{
KdCheckPolyFillRect (pDrawable, pGC, nrectFill, prectInit);
return;
}
prgnClip = fbGetCompositeClip(pGC);
xorg = pDrawable->x;
yorg = pDrawable->y;
if (xorg || yorg)
{
prect = prectInit;
n = nrectFill;
while(n--)
{
prect->x += xorg;
prect->y += yorg;
prect++;
}
}
prect = prectInit;
numRects = REGION_NUM_RECTS(prgnClip) * nrectFill;
if (numRects > NUM_STACK_RECTS)
{
pboxClippedBase = (BoxPtr)ALLOCATE_LOCAL(numRects * sizeof(BoxRec));
if (!pboxClippedBase)
return;
}
else
pboxClippedBase = stackRects;
pboxClipped = pboxClippedBase;
if (REGION_NUM_RECTS(prgnClip) == 1)
{
int x1, y1, x2, y2, bx2, by2;
pextent = REGION_RECTS(prgnClip);
x1 = pextent->x1;
y1 = pextent->y1;
x2 = pextent->x2;
y2 = pextent->y2;
while (nrectFill--)
{
if ((pboxClipped->x1 = prect->x) < x1)
pboxClipped->x1 = x1;
if ((pboxClipped->y1 = prect->y) < y1)
pboxClipped->y1 = y1;
bx2 = (int) prect->x + (int) prect->width;
if (bx2 > x2)
bx2 = x2;
pboxClipped->x2 = bx2;
by2 = (int) prect->y + (int) prect->height;
if (by2 > y2)
by2 = y2;
pboxClipped->y2 = by2;
prect++;
if ((pboxClipped->x1 < pboxClipped->x2) &&
(pboxClipped->y1 < pboxClipped->y2))
{
pboxClipped++;
}
}
}
else
{
int x1, y1, x2, y2, bx2, by2;
pextent = REGION_EXTENTS(pGC->pScreen, prgnClip);
x1 = pextent->x1;
y1 = pextent->y1;
x2 = pextent->x2;
y2 = pextent->y2;
while (nrectFill--)
{
BoxRec box;
if ((box.x1 = prect->x) < x1)
box.x1 = x1;
if ((box.y1 = prect->y) < y1)
box.y1 = y1;
bx2 = (int) prect->x + (int) prect->width;
if (bx2 > x2)
bx2 = x2;
box.x2 = bx2;
by2 = (int) prect->y + (int) prect->height;
if (by2 > y2)
by2 = y2;
box.y2 = by2;
prect++;
if ((box.x1 >= box.x2) || (box.y1 >= box.y2))
continue;
n = REGION_NUM_RECTS (prgnClip);
pbox = REGION_RECTS(prgnClip);
/* clip the rectangle to each box in the clip region
this is logically equivalent to calling Intersect()
*/
while(n--)
{
pboxClipped->x1 = max(box.x1, pbox->x1);
pboxClipped->y1 = max(box.y1, pbox->y1);
pboxClipped->x2 = min(box.x2, pbox->x2);
pboxClipped->y2 = min(box.y2, pbox->y2);
pbox++;
/* see if clipping left anything */
if(pboxClipped->x1 < pboxClipped->x2 &&
pboxClipped->y1 < pboxClipped->y2)
{
pboxClipped++;
}
}
}
}
if (pboxClipped != pboxClippedBase)
{
s3_24FillBoxSolid(pDrawable,
pboxClipped-pboxClippedBase, pboxClippedBase,
pGC->fgPixel, pGC->alu, pGC->planemask);
}
if (pboxClippedBase != stackRects)
DEALLOCATE_LOCAL(pboxClippedBase);
}
void
s3_24SolidBoxClipped (DrawablePtr pDrawable,
RegionPtr pClip,
int x1,
int y1,
int x2,
int y2,
FbBits fg)
{
SetupS3 (pDrawable->pScreen);
BoxPtr pbox;
int nbox;
int partX1, partX2, partY1, partY2;
s3SetGlobalBitmap (pDrawable->pScreen, s3DrawMap (pDrawable));
_s3SetSolidFill(s3,fg,GXcopy,~0);
for (nbox = REGION_NUM_RECTS(pClip), pbox = REGION_RECTS(pClip);
nbox--;
pbox++)
{
partX1 = pbox->x1;
if (partX1 < x1)
partX1 = x1;
partX2 = pbox->x2;
if (partX2 > x2)
partX2 = x2;
if (partX2 <= partX1)
continue;
partY1 = pbox->y1;
if (partY1 < y1)
partY1 = y1;
partY2 = pbox->y2;
if (partY2 > y2)
partY2 = y2;
if (partY2 <= partY1)
continue;
partX1 *= 3;
partX2 *= 3;
_s3SolidRect(s3,partX1, partY1, partX2-partX1, partY2-partY1);
}
MarkSyncS3(pDrawable->pScreen);
}
void
s3_24ImageGlyphBlt (DrawablePtr pDrawable,
GCPtr pGC,
int x,
int y,
unsigned int nglyph,
CharInfoPtr *ppciInit,
pointer pglyphBase)
{
FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
CharInfoPtr *ppci;
CharInfoPtr pci;
unsigned char *pglyph; /* pointer bits in glyph */
int gWidth, gHeight; /* width and height of glyph */
FbStride gStride; /* stride of glyph */
Bool opaque;
int n;
int gx, gy;
FbBits *dst;
FbStride dstStride;
int dstBpp;
int dstXoff, dstYoff;
FbBits depthMask;
int xBack, widthBack;
int yBack, heightBack;
depthMask = FbFullMask(pDrawable->depth);
if (!ok24 (pGC->fgPixel) ||
!ok24(pGC->bgPixel) ||
!ok24(pGC->planemask))
{
KdCheckImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppciInit, pglyphBase);
return;
}
fbGetDrawable (pDrawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
x += pDrawable->x;
y += pDrawable->y;
ppci = ppciInit;
n = nglyph;
widthBack = 0;
while (n--)
widthBack += (*ppci++)->metrics.characterWidth;
xBack = x;
if (widthBack < 0)
{
xBack += widthBack;
widthBack = -widthBack;
}
yBack = y - FONTASCENT(pGC->font);
heightBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
s3_24SolidBoxClipped (pDrawable,
fbGetCompositeClip(pGC),
xBack,
yBack,
xBack + widthBack,
yBack + heightBack,
pPriv->bg);
KdCheckSync (pDrawable->pScreen);
ppci = ppciInit;
while (nglyph--)
{
pci = *ppci++;
pglyph = FONTGLYPHBITS(pglyphBase, pci);
gWidth = GLYPHWIDTHPIXELS(pci);
gHeight = GLYPHHEIGHTPIXELS(pci);
if (gWidth && gHeight)
{
gx = x + pci->metrics.leftSideBearing;
gy = y - pci->metrics.ascent;
if (gWidth <= sizeof (FbStip) * 8 &&
fbGlyphIn (fbGetCompositeClip(pGC), gx, gy, gWidth, gHeight))
{
fbGlyph24 (dst + (gy - dstYoff) * dstStride,
dstStride,
dstBpp,
(FbStip *) pglyph,
pPriv->fg,
gx - dstXoff,
gHeight);
}
else
{
gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof (FbStip);
fbPutXYImage (pDrawable,
fbGetCompositeClip(pGC),
pPriv->fg,
pPriv->bg,
pPriv->pm,
GXcopy,
FALSE,
gx,
gy,
gWidth, gHeight,
(FbStip *) pglyph,
gStride,
0);
}
}
x += pci->metrics.characterWidth;
}
}
static const GCOps s3_24GCOps = {
s3_24FillSpans,
KdCheckSetSpans,
KdCheckPutImage,
KdCheckCopyArea,
KdCheckCopyPlane,
KdCheckPolyPoint,
KdCheckPolylines,
KdCheckPolySegment,
KdCheckPolyRectangle,
KdCheckPolyArc,
KdCheckFillPolygon,
s3_24PolyFillRect,
KdCheckPolyFillArc,
miPolyText8,
miPolyText16,
miImageText8,
miImageText16,
s3_24ImageGlyphBlt,
KdCheckPolyGlyphBlt,
KdCheckPushPixels,
};
void
s3_24ValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
{
if (pDrawable->type != DRAWABLE_WINDOW)
pGC->ops = (GCOps *) &kdAsyncPixmapGCOps;
else
pGC->ops = (GCOps *) &s3_24GCOps;
fbValidateGC (pGC, changes, pDrawable);
}
GCFuncs s3_24GCFuncs = {
s3_24ValidateGC,
miChangeGC,
miCopyGC,
miDestroyGC,
miChangeClip,
miDestroyClip,
miCopyClip
};
Bool
s3_24CreateGC (GCPtr pGC)
{
if (!fbCreateGC (pGC))
return FALSE;
if (pGC->depth != 1)
pGC->funcs = &s3_24GCFuncs;
return TRUE;
}
Bool
s3_24CreateWindow(WindowPtr pWin)
{
return fbCreateWindow (pWin);
}
void
s3_24PaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
{
SetupS3(pWin->drawable.pScreen);
s3PatternPtr pPattern;
DRAW_DEBUG ((DEBUG_PAINT_WINDOW, "s3PaintWindow 0x%x extents %d %d %d %d n %d",
pWin->drawable.id,
pRegion->extents.x1, pRegion->extents.y1,
pRegion->extents.x2, pRegion->extents.y2,
REGION_NUM_RECTS(pRegion)));
if (!REGION_NUM_RECTS(pRegion))
return;
switch (what) {
case PW_BACKGROUND:
switch (pWin->backgroundState) {
case None:
return;
case ParentRelative:
do {
pWin = pWin->parent;
} while (pWin->backgroundState == ParentRelative);
(*pWin->drawable.pScreen->PaintWindowBackground)(pWin, pRegion,
what);
return;
case BackgroundPixel:
if (ok24(pWin->background.pixel))
{
s3_24FillBoxSolid((DrawablePtr)pWin,
(int)REGION_NUM_RECTS(pRegion),
REGION_RECTS(pRegion),
pWin->background.pixel, GXcopy, ~0);
return;
}
}
break;
case PW_BORDER:
if (pWin->borderIsPixel && ok24(pWin->border.pixel))
{
s3_24FillBoxSolid((DrawablePtr)pWin,
(int)REGION_NUM_RECTS(pRegion),
REGION_RECTS(pRegion),
pWin->border.pixel, GXcopy, ~0);
return;
}
break;
}
KdCheckPaintWindow (pWin, pRegion, what);
}
Bool
s3DrawInit (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
s3ScreenInfo(pScreenPriv);
int ncache_w, ncache_h, ncache;
int px, py;
S3PatternCache *cache;
Bool dumb = FALSE;
int ma;
switch (pScreenPriv->screen->fb[0].bitsPerPixel) {
case 8:
case 16:
case 32:
break;
case 24:
dumb = TRUE;
break;
default:
return FALSE;
}
/*
* Hook up asynchronous drawing
*/
RegisterSync (pScreen);
/*
* Replace various fb screen functions
*/
if (dumb)
{
pScreen->CreateGC = s3_24CreateGC;
pScreen->CreateWindow = s3_24CreateWindow;
pScreen->PaintWindowBackground = s3_24PaintWindow;
pScreen->PaintWindowBorder = s3_24PaintWindow;
pScreen->CopyWindow = s3CopyWindow;
}
else
{
if (!dixRequestPrivate(s3GCPrivateKey, sizeof (s3PrivGCRec)))
return FALSE;
pScreen->CreateGC = s3CreateGC;
pScreen->CreateWindow = s3CreateWindow;
pScreen->ChangeWindowAttributes = s3ChangeWindowAttributes;
pScreen->DestroyWindow = s3DestroyWindow;
pScreen->PaintWindowBackground = s3PaintWindow;
pScreen->PaintWindowBorder = s3PaintWindow;
#ifndef S3_TRIO
if (pScreenPriv->screen->fb[1].depth)
{
FbOverlayScrPrivPtr pScrPriv = fbOverlayGetScrPriv(pScreen);
pScrPriv->PaintKey = s3PaintKey;
pScrPriv->CopyWindow = s3CopyWindowProc;
pScreen->CopyWindow = fbOverlayCopyWindow;
}
else
#endif
pScreen->CopyWindow = s3CopyWindow;
/*
* Initialize patterns
*/
#ifdef S3_TRIO
ma = 0;
#else
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
#endif
{
ncache_w = s3s->fb[ma].offscreen_width / S3_TILE_SIZE;
ncache_h = s3s->fb[ma].offscreen_height / S3_TILE_SIZE;
ncache = ncache_w * ncache_h;
if (ncache > 64)
ncache = 64;
DRAW_DEBUG ((DEBUG_S3INIT, "ncache_w %d ncache_h %d ncache %d",
ncache_w, ncache_h, ncache));
s3s->fb[ma].patterns.cache = (S3PatternCache *) xalloc (ncache * sizeof (S3PatternCache));
if (s3s->fb[ma].patterns.cache)
{
DRAW_DEBUG ((DEBUG_S3INIT, "Have pattern cache"));
s3s->fb[ma].patterns.ncache = ncache;
s3s->fb[ma].patterns.last_used = 0;
s3s->fb[ma].patterns.last_id = 0;
cache = s3s->fb[ma].patterns.cache;
for (py = 0; py < ncache_h && ncache; py++)
for (px = 0; px < ncache_w && ncache; px++)
{
cache->id = 0;
cache->x = s3s->fb[ma].offscreen_x + px * S3_TILE_SIZE;
cache->y = s3s->fb[ma].offscreen_y + py * S3_TILE_SIZE;
cache++;
ncache--;
}
}
}
}
return TRUE;
}
void
s3DrawEnable (ScreenPtr pScreen)
{
SetupS3(pScreen);
s3ScreenInfo(pScreenPriv);
int c;
int ma;
s3SetGlobalBitmap (pScreen, 0);
_s3WaitIdleEmpty (s3);
if (pScreenPriv->screen->fb[0].bitsPerPixel == 24)
{
_s3SetScissorsTl(s3, 0, 0);
_s3SetScissorsBr(s3, pScreenPriv->screen->width*3 - 1, pScreenPriv->screen->height - 1);
_s3SetSolidFill(s3, pScreen->whitePixel, GXcopy, ~0);
_s3SolidRect (s3, 0, 0, pScreenPriv->screen->width*3, pScreenPriv->screen->height);
}
else
{
/*
* Flush pattern cache
*/
#ifdef S3_TRIO
ma = 0;
#else
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
#endif
{
for (c = 0; c < s3s->fb[ma].patterns.ncache; c++)
s3s->fb[ma].patterns.cache[c].id = 0;
}
_s3SetScissorsTl(s3, 0, 0);
_s3SetScissorsBr(s3, pScreenPriv->screen->width - 1, pScreenPriv->screen->height - 1);
_s3SetSolidFill(s3, pScreen->blackPixel, GXcopy, ~0);
_s3SolidRect (s3, 0, 0, pScreenPriv->screen->width, pScreenPriv->screen->height);
}
MarkSyncS3 (pScreen);
}
void
s3DrawDisable (ScreenPtr pScreen)
{
SetupS3 (pScreen);
_s3WaitIdleEmpty (s3);
}
void
s3DrawFini (ScreenPtr pScreen)
{
SetupS3(pScreen);
s3ScreenInfo(pScreenPriv);
int ma;
#ifdef S3_TRIO
ma = 0;
#else
for (ma = 0; s3s->fbmap[ma] >= 0; ma++)
#endif
{
if (s3s->fb[ma].patterns.cache)
{
xfree (s3s->fb[ma].patterns.cache);
s3s->fb[ma].patterns.cache = 0;
s3s->fb[ma].patterns.ncache = 0;
}
}
}
void
s3DrawSync (ScreenPtr pScreen)
{
SetupS3(pScreen);
_s3WaitIdleEmpty(s3c->s3);
}