xenocara/xserver/hw/kdrive/savage/s3draw.c

3115 lines
67 KiB
C
Raw Normal View History

/*
* 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)xalloc(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)
xfree(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 *)xalloc(nTmp * sizeof(int));
pptFree = (DDXPointRec *)xalloc(nTmp * sizeof(DDXPointRec));
if(!pptFree || !pwidthFree)
{
if (pptFree) xfree(pptFree);
if (pwidthFree) xfree(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);
}
xfree(pptFree);
xfree(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
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 *)xalloc(nTmp * sizeof(int));
pptFree = (DDXPointRec *)xalloc(nTmp * sizeof(DDXPointRec));
if(!pptFree || !pwidthFree)
{
if (pptFree) xfree(pptFree);
if (pwidthFree) xfree(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);
}
}
xfree(pptFree);
xfree(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)xalloc(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)
xfree(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);
}
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->CopyWindow = s3CopyWindow;
}
else
{
if (!dixRequestPrivate(s3GCPrivateKey, sizeof (s3PrivGCRec)))
return FALSE;
pScreen->CreateGC = s3CreateGC;
pScreen->CreateWindow = s3CreateWindow;
pScreen->ChangeWindowAttributes = s3ChangeWindowAttributes;
pScreen->DestroyWindow = s3DestroyWindow;
#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);
}