xserver-multidpi/hw/kdrive/sis530/sisdraw.c
Daniel Stone caf5450634 KDrive: Remove usage of alloca
Replace with heap allocations.
2007-11-05 14:34:42 +00:00

1650 lines
38 KiB
C

/*
* Copyright © 1999 Keith Packard
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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.
*/
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
#include "sis.h"
#include "sisdraw.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"
CARD8 sisPatRop[16] = {
/* GXclear */ 0x00, /* 0 */
/* GXand */ 0xa0, /* src AND dst */
/* GXandReverse */ 0x50, /* src AND NOT dst */
/* GXcopy */ 0xf0, /* src */
/* GXandInverted*/ 0x0a, /* NOT src AND dst */
/* GXnoop */ 0xaa, /* dst */
/* GXxor */ 0x5a, /* src XOR dst */
/* GXor */ 0xfa, /* src OR dst */
/* GXnor */ 0x05, /* NOT src AND NOT dst */
/* GXequiv */ 0xa5, /* NOT src XOR dst */
/* GXinvert */ 0x55, /* NOT dst */
/* GXorReverse */ 0xf5, /* src OR NOT dst */
/* GXcopyInverted*/ 0x0f, /* NOT src */
/* GXorInverted */ 0xaf, /* NOT src OR dst */
/* GXnand */ 0x5f, /* NOT src OR NOT dst */
/* GXset */ 0xff, /* 1 */
};
CARD8 sisBltRop[16] = {
/* GXclear */ 0x00, /* 0 */
/* GXand */ 0x88, /* src AND dst */
/* GXandReverse */ 0x44, /* src AND NOT dst */
/* GXcopy */ 0xcc, /* src */
/* GXandInverted*/ 0x22, /* NOT src AND dst */
/* GXnoop */ 0xaa, /* dst */
/* GXxor */ 0x66, /* src XOR dst */
/* GXor */ 0xee, /* src OR dst */
/* GXnor */ 0x11, /* NOT src AND NOT dst */
/* GXequiv */ 0x99, /* NOT src XOR dst */
/* GXinvert */ 0x55, /* NOT dst */
/* GXorReverse */ 0xdd, /* src OR NOT dst */
/* GXcopyInverted*/ 0x33, /* NOT src */
/* GXorInverted */ 0xbb, /* NOT src OR dst */
/* GXnand */ 0x77, /* NOT src OR NOT dst */
/* GXset */ 0xff, /* 1 */
};
/* Align blts to this boundary or risk trashing an in-progress expand */
#define SIS_MIN_PATTERN 8
/* Do plane bits in this increment to balance CPU and graphics engine */
#define SIS_PATTERN_INC 1024
typedef struct _SisExpand {
SisCardInfo *sisc;
SisScreenInfo *siss;
CARD32 off;
int last;
} SisExpand;
static void
sisExpandInit (ScreenPtr pScreen,
SisExpand *e)
{
KdScreenPriv(pScreen);
sisCardInfo(pScreenPriv);
sisScreenInfo(pScreenPriv);
e->sisc = sisc;
e->siss = siss;
e->off = siss->expand_off;
e->last = 0;
}
static CARD32 *
sisExpandAlloc (SisExpand *e,
int nb)
{
SisCardInfo *sisc = e->sisc;
SisScreenInfo *siss = e->siss;
SisPtr sis = sisc->sis;
CARD32 off;
/* round up to alignment boundary */
nb = (nb + SIS_MIN_PATTERN-1) & ~(SIS_MIN_PATTERN-1);
off = e->off + e->last;
if (off + nb > siss->expand_off + siss->expand_len)
{
_sisWaitIdleEmpty (sis);
off = siss->expand_off;
}
e->off = off;
e->last = nb;
return (CARD32 *) (sisc->frameBuffer + off);
}
void
sisGlyphBltClipped (DrawablePtr pDrawable,
GCPtr pGC,
int x,
int y,
unsigned int nglyph,
CharInfoPtr *ppciInit,
Bool imageBlt)
{
SetupSis(pDrawable->pScreen);
FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC);
int height;
int width;
int xBack, yBack;
int hBack, wBack;
int nb, bwidth, nl;
FontPtr pfont = pGC->font;
CharInfoPtr pci;
CARD8 *bits8, b;
CARD16 *bits16;
CARD32 *bits32;
BoxPtr extents;
BoxRec bbox;
unsigned char alu;
CARD32 cmd;
SisExpand expand;
CARD32 *dst, d;
int nbytes;
int shift;
int x1, y1, x2, y2;
RegionPtr pClip = fbGetCompositeClip(pGC);
BoxPtr pBox;
int nbox;
int rect_in;
int widthBlt;
CharInfoPtr *ppci;
x += pDrawable->x;
y += pDrawable->y;
if (imageBlt)
{
xBack = x;
yBack = y - FONTASCENT(pGC->font);
wBack = 0;
hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
if (hBack)
{
height = nglyph;
ppci = ppciInit;
while (height--)
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)
{
_sisSetSolidRect (sis, pGC->bgPixel, GXcopy, cmd);
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)
{
_sisRect (sis, x1, y1, x2 - x1, y2 - y1, cmd);
}
}
}
sisExpandInit (pDrawable->pScreen, &expand);
sis->u.general.src_fg = pGC->fgPixel;
sis->u.general.src_pitch = 0;
sis->u.general.src_x = 0;
sis->u.general.src_y = 0;
cmd = (SIS_CMD_ENH_COLOR_EXPAND |
SIS_CMD_SRC_SCREEN |
SIS_CMD_PAT_FG |
(sisBltRop[alu] << 8) |
SIS_CMD_INC_X |
SIS_CMD_INC_Y |
SIS_CMD_RECT_CLIP_ENABLE |
SIS_CMD_TRANSPARENT);
ppci = ppciInit;
while (nglyph--)
{
pci = *ppci++;
height = pci->metrics.ascent + pci->metrics.descent;
width = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
widthBlt = (width + 31) & ~31;
nb = (widthBlt >> 3) * height;
if (nb)
{
x1 = x + pci->metrics.leftSideBearing;
y1 = y - pci->metrics.ascent;
bbox.x1 = x1;
bbox.y1 = y1;
bbox.x2 = x1 + width;
bbox.y2 = y1 + height;
rect_in = RECT_IN_REGION(pGC->pScreen, pClip, &bbox);
if (rect_in != rgnOUT)
{
dst = sisExpandAlloc (&expand, nb);
sis->u.general.src_base = expand.off;
sis->u.general.dst_x = x1;
sis->u.general.dst_y = y1;
sis->u.general.rect_width = widthBlt;
sis->u.general.rect_height = height;
nb >>= 2;
bits32 = (CARD32 *) pci->bits;
while (nb--)
{
d = *bits32++;
SisInvertBits32 (d);
*dst++ = d;
}
if (rect_in == rgnPART)
{
for (nbox = REGION_NUM_RECTS (pClip),
pBox = REGION_RECTS (pClip);
nbox--;
pBox++)
{
_sisClip (sis, pBox->x1, pBox->y1, pBox->x2, pBox->y2);
sis->u.general.command = cmd;
}
}
else
{
_sisClip (sis, 0, 0, x1+width, pScreenPriv->screen->height);
sis->u.general.command = cmd;
}
}
}
x += pci->metrics.characterWidth;
}
_sisClip (sis, 0, 0,
pScreenPriv->screen->width, pScreenPriv->screen->height);
KdMarkSync (pDrawable->pScreen);
}
Bool
sisTEGlyphBlt (DrawablePtr pDrawable,
GCPtr pGC,
int xInit,
int yInit,
unsigned int nglyph,
CharInfoPtr *ppci,
Bool imageBlt)
{
SetupSis(pDrawable->pScreen);
int x, y;
int widthGlyphs, widthGlyph;
int widthBlt;
FbBits depthMask;
int glyphsPer;
FontPtr pfont = pGC->font;
unsigned long *char1, *char2, *char3, *char4, *char5;
CARD8 alu;
CARD32 *dst, tmp;
CARD8 *dst8, *bits8;
int nb;
int bwidth;
CARD32 cmd;
int h;
BoxRec bbox;
SisExpand expand;
int lwTmp, lw;
int extra, n;
widthGlyph = FONTMAXBOUNDS(pfont,characterWidth);
if (!widthGlyph)
return TRUE;
h = FONTASCENT(pfont) + FONTDESCENT(pfont);
if (!h)
return TRUE;
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 rgnPART:
if (x < 0 || y < 0)
return FALSE;
sisGlyphBltClipped (pDrawable, pGC, xInit, yInit, nglyph, ppci, imageBlt);
case rgnOUT:
return TRUE;
}
if (widthGlyph <= 6)
glyphsPer = 5;
else if (widthGlyph <= 8)
glyphsPer = 4;
else if (widthGlyph <= 10)
glyphsPer = 3;
else if (widthGlyph <= 16)
glyphsPer = 2;
else
glyphsPer = 1;
widthGlyphs = widthGlyph * glyphsPer;
widthBlt = widthGlyphs;
/* make sure scanlines are 32-bit aligned */
if (widthGlyphs <= 24)
widthBlt = 25;
cmd = (SIS_CMD_ENH_COLOR_EXPAND |
SIS_CMD_SRC_SCREEN |
SIS_CMD_PAT_FG |
SIS_CMD_INC_X |
SIS_CMD_INC_Y);
if (imageBlt)
{
sis->u.general.clip_right = bbox.x2;
cmd |= ((sisBltRop[GXcopy] << 8) |
SIS_CMD_OPAQUE |
SIS_CMD_RECT_CLIP_ENABLE);
}
else
{
cmd |= ((sisBltRop[pGC->alu] << 8) |
SIS_CMD_TRANSPARENT |
SIS_CMD_RECT_CLIP_DISABLE);
}
sisExpandInit (pDrawable->pScreen, &expand);
sis->u.general.src_fg = pGC->fgPixel;
sis->u.general.src_bg = pGC->bgPixel;
bwidth = (widthBlt + 7) >> 3;
nb = bwidth * h;
#define LoopIt(count, loadup, fetch) \
while (nglyph >= count) \
{ \
nglyph -= count; \
dst = sisExpandAlloc (&expand, nb); \
sis->u.general.src_base = expand.off; \
sis->u.general.src_pitch = 0; \
sis->u.general.src_x = 0; \
sis->u.general.src_y = 0; \
sis->u.general.dst_x = x; \
sis->u.general.dst_y = y; \
sis->u.general.rect_width = widthBlt; \
sis->u.general.rect_height = h; \
x += widthGlyphs; \
loadup \
lwTmp = h; \
while (lwTmp--) { \
tmp = fetch; \
SisInvertBits32(tmp); \
*dst++ = tmp; \
} \
sis->u.general.command = cmd; \
}
switch (glyphsPer) {
case 5:
LoopIt(5,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;
char3 = (unsigned long *) (*ppci++)->bits;
char4 = (unsigned long *) (*ppci++)->bits;
char5 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | ((*char2++ | ((*char3++ | ((*char4++ | (*char5++
<< widthGlyph))
<< widthGlyph))
<< widthGlyph))
<< widthGlyph)));
break;
case 4:
LoopIt(4,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;
char3 = (unsigned long *) (*ppci++)->bits;
char4 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | ((*char2++ | ((*char3++ | (*char4++
<< widthGlyph))
<< widthGlyph))
<< widthGlyph)));
break;
case 3:
LoopIt(3,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;
char3 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | ((*char2++ | (*char3++ << widthGlyph)) << widthGlyph)));
break;
case 2:
LoopIt(2,
char1 = (unsigned long *) (*ppci++)->bits;
char2 = (unsigned long *) (*ppci++)->bits;,
(*char1++ | (*char2++ << widthGlyph)));
break;
}
widthBlt = (widthGlyph + 31) & ~31;
bwidth = widthBlt >> 3;
nb = bwidth * h;
lw = (widthBlt >> 5) * h;
while (nglyph--)
{
dst = (CARD32 *) sisExpandAlloc (&expand, nb);
char1 = (CARD32 *) (*ppci++)->bits;
sis->u.general.src_base = expand.off;
sis->u.general.src_pitch = 0;
sis->u.general.src_x = 0;
sis->u.general.src_y = 0;
sis->u.general.dst_x = x;
sis->u.general.dst_y = y;
sis->u.general.rect_width = widthBlt;
sis->u.general.rect_height = h;
lwTmp = lw;
while (lwTmp--)
{
tmp = *char1++;
SisInvertBits32 (tmp);
*dst++ = tmp;
}
sis->u.general.command = cmd;
x += widthGlyph;
}
if (imageBlt)
sis->u.general.clip_right = pScreenPriv->screen->width;
KdMarkSync (pDrawable->pScreen);
return TRUE;
}
Bool
sisGlyphBlt(DrawablePtr pDrawable,
GCPtr pGC,
int x,
int y,
unsigned int nglyph,
CharInfoPtr *ppciInit,
Bool imageBlt)
{
SetupSis(pDrawable->pScreen);
int height;
int width;
int xBack, yBack;
int hBack, wBack;
int nb, bwidth, nl;
FontPtr pfont = pGC->font;
CharInfoPtr pci;
CARD8 *bits8, b;
CARD16 *bits16;
CARD32 *bits32;
BoxPtr extents;
BoxRec bbox;
CharInfoPtr *ppci;
unsigned char alu;
CARD32 cmd;
SisExpand expand;
CARD32 *dst, d;
int nbytes;
int shift;
x += pDrawable->x;
y += pDrawable->y;
/* compute an approximate (but covering) bounding box */
ppci = ppciInit;
width = 0;
height = nglyph;
while (height--)
width += (*ppci++)->metrics.characterWidth;
if (width < 0)
{
bbox.x1 = x + width;
bbox.x2 = x;
}
else
{
bbox.x1 = x;
bbox.x2 = x + width;
}
width = FONTMINBOUNDS(pfont,leftSideBearing);
if (width < 0)
bbox.x1 += width;
width = FONTMAXBOUNDS(pfont, rightSideBearing) - FONTMINBOUNDS(pfont, characterWidth);
if (width > 0)
bbox.x2 += width;
bbox.y1 = y - FONTMAXBOUNDS(pfont,ascent);
bbox.y2 = y + FONTMAXBOUNDS(pfont,descent);
switch (RECT_IN_REGION(pGC->pScreen, fbGetCompositeClip(pGC), &bbox))
{
case rgnPART:
if (bbox.x1 < 0 || bbox.y1 < 0)
return FALSE;
sisGlyphBltClipped (pDrawable, pGC,
x - pDrawable->x, y - pDrawable->y,
nglyph, ppciInit, imageBlt);
case rgnOUT:
return TRUE;
}
if (imageBlt)
{
xBack = x;
yBack = y - FONTASCENT(pGC->font);
wBack = 0;
hBack = FONTASCENT(pGC->font) + FONTDESCENT(pGC->font);
if (hBack)
{
height = nglyph;
ppci = ppciInit;
while (height--)
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)
{
_sisSetSolidRect (sis, pGC->bgPixel, GXcopy, cmd);
_sisRect (sis, xBack, yBack, wBack, hBack, cmd);
}
sisExpandInit (pDrawable->pScreen, &expand);
sis->u.general.src_fg = pGC->fgPixel;
cmd = (SIS_CMD_ENH_COLOR_EXPAND |
SIS_CMD_SRC_SCREEN |
SIS_CMD_PAT_FG |
(sisBltRop[alu] << 8) |
SIS_CMD_INC_X |
SIS_CMD_INC_Y |
SIS_CMD_RECT_CLIP_DISABLE |
SIS_CMD_TRANSPARENT);
ppci = ppciInit;
while (nglyph--)
{
pci = *ppci++;
height = pci->metrics.ascent + pci->metrics.descent;
width = pci->metrics.rightSideBearing - pci->metrics.leftSideBearing;
/*
* For glyphs wider than 16 pixels, expand the blt to the nearest multiple
* of 32; this allows the scanlines to be padded to a 32-bit boundary
* instead of requiring byte packing
*/
if (width > 16)
width = (width + 31) & ~31;
bwidth = (width + 7) >> 3;
nb = bwidth * height;
if (nb)
{
dst = sisExpandAlloc (&expand, nb);
sis->u.general.src_base = expand.off;
sis->u.general.src_pitch = 0;
sis->u.general.src_x = 0;
sis->u.general.src_y = 0;
sis->u.general.dst_x = x + pci->metrics.leftSideBearing;
sis->u.general.dst_y = y - pci->metrics.ascent;
sis->u.general.rect_width = width;
sis->u.general.rect_height = height;
switch (bwidth) {
case 1:
bits8 = (CARD8 *) pci->bits;
while (height >= 4)
{
d = (bits8[0] | (bits8[4] << 8) |
(bits8[8] << 16) | (bits8[12] << 24));
SisInvertBits32(d);
*dst++ = d;
bits8 += 16;
height -= 4;
}
if (height)
{
switch (height) {
case 3:
d = bits8[0] | (bits8[4] << 8) | (bits8[8] << 16);
break;
case 2:
d = bits8[0] | (bits8[4] << 8);
break;
case 1:
d = bits8[0];
break;
}
SisInvertBits32(d);
*dst++ = d;
}
break;
case 2:
bits16 = (CARD16 *) pci->bits;
while (height >= 2)
{
d = bits16[0] | (bits16[2] << 16);
SisInvertBits32(d);
*dst++ = d;
bits16 += 4;
height -= 2;
}
if (height)
{
d = bits16[0];
SisInvertBits32(d);
*dst++ = d;
}
break;
default:
nb >>= 2;
bits32 = (CARD32 *) pci->bits;
while (nb--)
{
d = *bits32++;
SisInvertBits32 (d);
*dst++ = d;
}
}
sis->u.general.command = cmd;
}
x += pci->metrics.characterWidth;
}
KdMarkSync (pDrawable->pScreen);
return TRUE;
}
/*
* Blt glyphs using Sis image transfer register, this does both
* poly glyph blt and image glyph blt (when pglyphBase == 1)
*/
void
sisPolyGlyphBlt (DrawablePtr pDrawable,
GCPtr pGC,
int x, int y,
unsigned int nglyph,
CharInfoPtr *ppci,
pointer pglyphBase)
{
FbBits depthMask;
depthMask = FbFullMask (pDrawable->depth);
if ((pGC->planemask & depthMask) == depthMask &&
pGC->fillStyle == FillSolid)
{
if (TERMINALFONT(pGC->font))
{
if (sisTEGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, FALSE))
return;
}
else
{
if (sisGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, FALSE))
return;
}
}
KdCheckPolyGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
}
void
sisImageGlyphBlt (DrawablePtr pDrawable,
GCPtr pGC,
int x, int y,
unsigned int nglyph,
CharInfoPtr *ppci,
pointer pglyphBase)
{
FbBits depthMask;
depthMask = FbFullMask (pDrawable->depth);
if ((pGC->planemask & depthMask) == depthMask)
{
if (TERMINALFONT(pGC->font))
{
if (sisTEGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, TRUE))
return;
}
else
{
if (sisGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, TRUE))
return;
}
}
KdCheckImageGlyphBlt (pDrawable, pGC, x, y, nglyph, ppci, pglyphBase);
}
#define sourceInvarient(alu) (((alu) & 3) == (((alu) >> 2) & 3))
#define sisPatternDimOk(d) ((d) <= 8 && (((d) & ((d) - 1)) == 0))
BOOL
sisFillOk (GCPtr pGC)
{
FbBits depthMask;
depthMask = FbFullMask(pGC->depth);
if ((pGC->planemask & depthMask) != depthMask)
return FALSE;
switch (pGC->fillStyle) {
case FillSolid:
return TRUE;
case FillTiled:
return (sisPatternDimOk (pGC->tile.pixmap->drawable.width) &&
sisPatternDimOk (pGC->tile.pixmap->drawable.height));
case FillStippled:
case FillOpaqueStippled:
return (sisPatternDimOk (pGC->stipple->drawable.width) &&
sisPatternDimOk (pGC->stipple->drawable.height));
}
}
CARD32
sisStipplePrepare (DrawablePtr pDrawable, GCPtr pGC)
{
SetupSis(pGC->pScreen);
PixmapPtr pStip = pGC->stipple;
int stipHeight = pStip->drawable.height;
int xRot, yRot;
int rot, stipX, stipY;
FbStip *stip, *stipEnd, bits;
FbStride stipStride;
int stipBpp;
int stipXoff, stipYoff; /* XXX assumed to be zero */
int y;
CARD32 cmd;
xRot = pGC->patOrg.x + pDrawable->x;
yRot = pGC->patOrg.y + pDrawable->y;
modulus (- yRot, stipHeight, stipY);
modulus (- xRot, FB_UNIT, stipX);
rot = stipX;
fbGetStipDrawable (&pStip->drawable, stip, stipStride, stipBpp, stipXoff, stipYoff);
for (y = 0; y < 8; y++)
{
bits = stip[stipY<<1];
FbRotLeft(bits, rot);
SisInvertBits32(bits);
sis->u.general.mask[y] = (CARD8) bits;
stipY++;
if (stipY == stipHeight)
stipY = 0;
}
sis->u.general.pattern_fg = pGC->fgPixel;
cmd = (SIS_CMD_BITBLT |
SIS_CMD_SRC_SCREEN |
SIS_CMD_PAT_MONO |
(sisPatRop[pGC->alu] << 8) |
SIS_CMD_INC_X |
SIS_CMD_INC_Y |
SIS_CMD_RECT_CLIP_DISABLE |
SIS_CMD_RECT_CLIP_DONT_MERGE);
if (pGC->fillStyle == FillOpaqueStippled)
{
sis->u.general.pattern_bg = pGC->bgPixel;
cmd |= SIS_CMD_OPAQUE;
}
else
cmd |= SIS_CMD_TRANSPARENT;
return cmd;
}
CARD32
sisTilePrepare (PixmapPtr pTile, int xRot, int yRot, CARD8 alu)
{
SetupSis(pTile->drawable.pScreen);
int tileHeight = pTile->drawable.height;
int tileWidth = pTile->drawable.width;
FbBits *tile;
FbStride tileStride;
int tileBpp;
int tileXoff, tileYoff; /* XXX assumed to be zero */
fbGetDrawable (&pTile->drawable, tile, tileStride, tileBpp, tileXoff, tileYoff);
/*
* Tile the pattern register
*/
fbTile ((FbBits *) sis->u.general.pattern,
(8 * tileBpp) >> FB_SHIFT,
0,
8 * tileBpp, 8,
tile,
tileStride,
tileWidth * tileBpp,
tileHeight,
GXcopy, FB_ALLONES, tileBpp,
xRot * tileBpp,
yRot);
return (SIS_CMD_BITBLT |
SIS_CMD_SRC_SCREEN |
SIS_CMD_PAT_PATTERN |
(sisPatRop[alu] << 8) |
SIS_CMD_INC_X |
SIS_CMD_INC_Y |
SIS_CMD_RECT_CLIP_DISABLE |
SIS_CMD_RECT_CLIP_DONT_MERGE);
}
void
sisFillBoxSolid (DrawablePtr pDrawable, int nBox, BoxPtr pBox,
unsigned long pixel, int alu)
{
SetupSis(pDrawable->pScreen);
CARD32 cmd;
_sisSetSolidRect(sis,pixel,alu,cmd);
while (nBox--)
{
_sisRect(sis,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1,cmd);
pBox++;
}
KdMarkSync (pDrawable->pScreen);
}
void
sisFillBoxStipple (DrawablePtr pDrawable, GCPtr pGC,
int nBox, BoxPtr pBox)
{
SetupSis(pDrawable->pScreen);
CARD32 cmd;
cmd = sisStipplePrepare (pDrawable, pGC);
while (nBox--)
{
_sisRect(sis,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1,cmd);
pBox++;
}
KdMarkSync (pDrawable->pScreen);
}
void
sisFillBoxTiled (DrawablePtr pDrawable,
int nBox, BoxPtr pBox,
PixmapPtr pTile, int xRot, int yRot, CARD8 alu)
{
SetupSis (pDrawable->pScreen);
CARD32 cmd;
cmd = sisTilePrepare (pTile, xRot, yRot, alu);
while (nBox--)
{
_sisRect(sis,pBox->x1,pBox->y1,pBox->x2-pBox->x1,pBox->y2-pBox->y1,cmd);
pBox++;
}
KdMarkSync (pDrawable->pScreen);
}
/*
sisDoBitBlt
=============
Bit Blit for all window to window blits.
*/
void
sisCopyNtoN (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse,
Bool upsidedown,
Pixel bitplane,
void *closure)
{
SetupSis(pDstDrawable->pScreen);
int srcX, srcY, dstX, dstY;
int w, h;
CARD32 flags;
CARD32 cmd;
CARD8 alu;
if (pGC)
{
alu = pGC->alu;
if (sourceInvarient (pGC->alu))
{
sisFillBoxSolid (pDstDrawable, nbox, pbox, 0, pGC->alu);
return;
}
}
else
alu = GXcopy;
_sisSetBlt(sis,alu,cmd);
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 |= SIS_CMD_INC_X;
}
srcX = dstX + dx;
if (upsidedown)
{
dstY = pbox->y2 - 1;
}
else
{
dstY = pbox->y1;
flags |= SIS_CMD_INC_Y;
}
srcY = dstY + dy;
_sisBlt (sis, srcX, srcY, dstX, dstY, w, h, cmd|flags);
pbox++;
}
KdMarkSync (pDstDrawable->pScreen);
}
RegionPtr
sisCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height, int dstx, int dsty)
{
KdScreenPriv(pDstDrawable->pScreen);
FbBits depthMask;
depthMask = FbFullMask (pDstDrawable->depth);
if ((pGC->planemask & depthMask) == depthMask &&
pSrcDrawable->type == DRAWABLE_WINDOW &&
pDstDrawable->type == DRAWABLE_WINDOW)
{
return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, sisCopyNtoN, 0, 0);
}
return KdCheckCopyArea (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height, dstx, dsty);
}
typedef struct _sis1toNargs {
unsigned long copyPlaneFG, copyPlaneBG;
} sis1toNargs;
void
_sisStipple (ScreenPtr pScreen,
FbStip *psrcBase,
FbStride widthSrc,
CARD8 alu,
int srcx,
int srcy,
int dstx,
int dsty,
int width,
int height)
{
SetupSis(pScreen);
FbStip *psrcLine, *psrc;
FbStride widthRest;
FbStip bits, tmp, lastTmp;
int leftShift, rightShift;
int nl, nlMiddle;
int r;
SisExpand expand;
CARD32 *dst;
int hthis;
int hper;
int bwidth;
CARD32 cmd;
sisExpandInit (pScreen, &expand);
/* Compute blt address and parameters */
psrc = psrcBase + srcy * widthSrc + (srcx >> 5);
nlMiddle = (width + 31) >> 5;
leftShift = srcx & 0x1f;
rightShift = 32 - leftShift;
widthRest = widthSrc - nlMiddle;
cmd = (SIS_CMD_ENH_COLOR_EXPAND |
SIS_CMD_SRC_SCREEN |
SIS_CMD_PAT_FG |
(sisBltRop[alu] << 8) |
SIS_CMD_INC_X |
SIS_CMD_INC_Y |
SIS_CMD_OPAQUE |
SIS_CMD_RECT_CLIP_ENABLE);
if (leftShift != 0)
widthRest--;
sis->u.general.src_x = 0;
sis->u.general.src_y = 0;
sis->u.general.dst_x = dstx;
sis->u.general.rect_width = (width + 31) & ~31;
sis->u.general.clip_right = (dstx + width);
bwidth = nlMiddle << 2;
hper = SIS_PATTERN_INC / bwidth;
if (hper == 0)
hper = 1;
while (height)
{
hthis = hper;
if (hthis > height)
hthis = height;
dst = sisExpandAlloc (&expand, bwidth * hthis);
sis->u.general.src_base = expand.off;
sis->u.general.dst_y = dsty;
sis->u.general.rect_height = hthis;
dsty += hthis;
height -= hthis;
if (leftShift == 0)
{
while (hthis--)
{
nl = nlMiddle;
while (nl--)
{
tmp = *psrc++;
SisInvertBits32(tmp);
*dst++ = tmp;
}
psrc += widthRest;
}
}
else
{
while (hthis--)
{
bits = *psrc++;
nl = nlMiddle;
while (nl--)
{
tmp = FbStipLeft(bits, leftShift);
bits = *psrc++;
tmp |= FbStipRight(bits, rightShift);
SisInvertBits32(tmp);
*dst++ = tmp;
}
psrc += widthRest;
}
}
sis->u.general.command = cmd;
}
sis->u.general.clip_right = pScreenPriv->screen->width;
}
void
sisCopy1toN (DrawablePtr pSrcDrawable,
DrawablePtr pDstDrawable,
GCPtr pGC,
BoxPtr pbox,
int nbox,
int dx,
int dy,
Bool reverse,
Bool upsidedown,
Pixel bitplane,
void *closure)
{
SetupSis(pDstDrawable->pScreen);
sis1toNargs *args = closure;
int dstx, dsty;
FbStip *psrcBase;
FbStride widthSrc;
int srcBpp;
int srcXoff, srcYoff;
if (sourceInvarient (pGC->alu))
{
sisFillBoxSolid (pDstDrawable, nbox, pbox,
pGC->bgPixel, pGC->alu);
return;
}
fbGetStipDrawable (pSrcDrawable, psrcBase, widthSrc, srcBpp, srcXoff, srcYoff);
sis->u.general.src_fg = args->copyPlaneFG;
sis->u.general.src_bg = args->copyPlaneBG;
while (nbox--)
{
dstx = pbox->x1;
dsty = pbox->y1;
_sisStipple (pDstDrawable->pScreen,
psrcBase, widthSrc,
pGC->alu,
dstx + dx - srcXoff, dsty + dy - srcYoff,
dstx, dsty,
pbox->x2 - dstx, pbox->y2 - dsty);
pbox++;
}
KdMarkSync (pDstDrawable->pScreen);
}
RegionPtr
sisCopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
int srcx, int srcy, int width, int height,
int dstx, int dsty, unsigned long bitPlane)
{
KdScreenPriv (pDstDrawable->pScreen);
RegionPtr ret;
sis1toNargs args;
FbBits depthMask;
depthMask = FbFullMask (pDstDrawable->depth);
if ((pGC->planemask & depthMask) == depthMask &&
pDstDrawable->type == DRAWABLE_WINDOW &&
pSrcDrawable->depth == 1)
{
args.copyPlaneFG = pGC->fgPixel;
args.copyPlaneBG = pGC->bgPixel;
return fbDoCopy (pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, sisCopy1toN, bitPlane, &args);
}
return KdCheckCopyPlane(pSrcDrawable, pDstDrawable, pGC,
srcx, srcy, width, height,
dstx, dsty, bitPlane);
}
void
sisFillSpans (DrawablePtr pDrawable, GCPtr pGC, int n,
DDXPointPtr ppt, int *pwidth, int fSorted)
{
SetupSis(pDrawable->pScreen);
DDXPointPtr pptFree;
FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC);
int *pwidthFree;/* copies of the pointers to free */
CARD32 cmd;
int nTmp;
INT16 x, y;
int width;
if (!sisFillOk (pGC))
{
KdCheckFillSpans (pDrawable, pGC, n, ppt, pwidth, fSorted);
return;
}
nTmp = n * miFindMaxBand(fbGetCompositeClip(pGC));
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;
switch (pGC->fillStyle) {
case FillSolid:
_sisSetSolidRect(sis,pGC->fgPixel,pGC->alu,cmd);
break;
case FillTiled:
cmd = sisTilePrepare (pGC->tile.pixmap,
pGC->patOrg.x + pDrawable->x,
pGC->patOrg.y + pDrawable->y,
pGC->alu);
break;
default:
cmd = sisStipplePrepare (pDrawable, pGC);
break;
}
while (n--)
{
x = ppt->x;
y = ppt->y;
ppt++;
width = *pwidth++;
if (width)
{
_sisRect(sis,x,y,width,1,cmd);
}
}
KdMarkSync (pDrawable->pScreen);
xfree(pptFree);
xfree(pwidthFree);
}
#define NUM_STACK_RECTS 1024
void
sisPolyFillRect (DrawablePtr pDrawable, GCPtr pGC,
int nrectFill, xRectangle *prectInit)
{
SetupSis(pDrawable->pScreen);
xRectangle *prect;
RegionPtr prgnClip;
register BoxPtr pbox;
register BoxPtr pboxClipped;
BoxPtr pboxClippedBase;
BoxPtr pextent;
BoxRec stackRects[NUM_STACK_RECTS];
FbGCPrivPtr fbPriv = fbGetGCPrivate (pGC);
int numRects;
int n;
int xorg, yorg;
int x, y;
if (!sisFillOk (pGC))
{
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)
{
switch (pGC->fillStyle) {
case FillSolid:
sisFillBoxSolid(pDrawable,
pboxClipped-pboxClippedBase, pboxClippedBase,
pGC->fgPixel, pGC->alu);
break;
case FillTiled:
sisFillBoxTiled(pDrawable,
pboxClipped-pboxClippedBase, pboxClippedBase,
pGC->tile.pixmap,
pGC->patOrg.x + pDrawable->x,
pGC->patOrg.y + pDrawable->y,
pGC->alu);
break;
case FillStippled:
case FillOpaqueStippled:
sisFillBoxStipple (pDrawable, pGC,
pboxClipped-pboxClippedBase, pboxClippedBase);
break;
}
}
if (pboxClippedBase != stackRects)
xfree(pboxClippedBase);
}
static const GCOps sisOps = {
sisFillSpans,
KdCheckSetSpans,
KdCheckPutImage,
sisCopyArea,
sisCopyPlane,
KdCheckPolyPoint,
KdCheckPolylines,
KdCheckPolySegment,
miPolyRectangle,
KdCheckPolyArc,
miFillPolygon,
sisPolyFillRect,
KdCheckPolyFillArc,
miPolyText8,
miPolyText16,
miImageText8,
miImageText16,
sisImageGlyphBlt,
sisPolyGlyphBlt,
KdCheckPushPixels,
};
void
sisValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
{
FbGCPrivPtr fbPriv = fbGetGCPrivate(pGC);
fbValidateGC (pGC, changes, pDrawable);
if (pDrawable->type == DRAWABLE_WINDOW)
pGC->ops = (GCOps *) &sisOps;
else
pGC->ops = (GCOps *) &kdAsyncPixmapGCOps;
}
GCFuncs sisGCFuncs = {
sisValidateGC,
miChangeGC,
miCopyGC,
miDestroyGC,
miChangeClip,
miDestroyClip,
miCopyClip
};
int
sisCreateGC (GCPtr pGC)
{
if (!fbCreateGC (pGC))
return FALSE;
if (pGC->depth != 1)
pGC->funcs = &sisGCFuncs;
pGC->ops = (GCOps *) &kdAsyncPixmapGCOps;
return TRUE;
}
void
sisCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
KdScreenPriv(pScreen);
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, sisCopyNtoN, 0, 0);
REGION_UNINIT(pWin->drawable.pScreen, &rgnDst);
}
Bool
sisDrawInit (ScreenPtr pScreen)
{
KdScreenPriv(pScreen);
sisScreenInfo(pScreenPriv);
/*
* Hook up asynchronous drawing
*/
KdScreenInitAsync (pScreen);
/*
* Replace various fb screen functions
*/
pScreen->CreateGC = sisCreateGC;
pScreen->CopyWindow = sisCopyWindow;
return TRUE;
}
void
sisDrawEnable (ScreenPtr pScreen)
{
SetupSis(pScreen);
sisScreenInfo(pScreenPriv);
CARD32 cmd;
CARD32 base;
CARD16 stride;
CARD16 op;
base = pScreenPriv->screen->fb[0].frameBuffer - sisc->frameBuffer;
stride = pScreenPriv->screen->fb[0].byteStride;
#if 0
sis->u.general.dst_base = base;
sis->u.general.dst_pitch = stride;
sis->u.general.src_pitch = stride;
sis->u.general._pad0 = stride;
sis->u.general.dst_height = pScreenPriv->screen->height;
_sisClip (sis, 0, 0,
pScreenPriv->screen->width, pScreenPriv->screen->height);
_sisSetSolidRect(sis, pScreen->blackPixel, GXcopy, cmd);
_sisRect (sis, 0, 0,
pScreenPriv->screen->width, pScreenPriv->screen->height,
cmd);
#endif
base = (CARD32) (pScreenPriv->screen->fb[0].frameBuffer);
fprintf (stderr, "src 0x%x\n", sis->u.accel.src_addr);
sis->u.accel.src_addr = (base & 0x3fffff);
fprintf (stderr, "src 0x%x\n", sis->u.accel.src_addr);
sis->u.accel.dst_addr = (base & 0x3fffff);
sis->u.accel.pitch = (stride << 16) | stride;
sis->u.accel.dimension = ((pScreenPriv->screen->height-1) << 16 |
(pScreenPriv->screen->width - 1));
sis->u.accel.fg = (sisBltRop[GXcopy] << 24) | 0xf800;
sis->u.accel.bg = (sisBltRop[GXcopy] << 24) | 0x00;
#define sisLEFT2RIGHT 0x10
#define sisRIGHT2LEFT 0x00
#define sisTOP2BOTTOM 0x20
#define sisBOTTOM2TOP 0x00
#define sisSRCSYSTEM 0x03
#define sisSRCVIDEO 0x02
#define sisSRCFG 0x01
#define sisSRCBG 0x00
#define sisCMDBLT 0x0000
#define sisCMDBLTMSK 0x0100
#define sisCMDCOLEXP 0x0200
#define sisCMDLINE 0x0300
#define sisCMDENHCOLEXP 0x2000
#define sisXINCREASE 0x10
#define sisYINCREASE 0x20
#define sisCLIPENABL 0x40
#define sisCLIPINTRN 0x80
#define sisCLIPEXTRN 0x00
#define sisPATREG 0x08
#define sisPATFG 0x04
#define sisPATBG 0x00
#define sisLASTPIX 0x0800
#define sisXMAJOR 0x0400
op = sisCMDBLT | sisLEFT2RIGHT | sisTOP2BOTTOM | sisSRCFG | sisPATFG;
sis->u.accel.cmd = op;
KdMarkSync (pScreen);
}
void
sisDrawSync (ScreenPtr pScreen)
{
SetupSis(pScreen);
_sisWaitIdleEmpty (sis);
}
void
sisDrawDisable (ScreenPtr pScreen)
{
}
void
sisDrawFini (ScreenPtr pScreen)
{
}