/*
 * 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.
 */
/* $XFree86: xc/programs/Xserver/hw/tinyx/sis530/sisdraw.c,v 1.1 2004/06/02 22:43:02 dawes Exp $ */
/*
 * Copyright (c) 2004 by The XFree86 Project, Inc.
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject
 * to the following conditions:
 *
 *   1.  Redistributions of source code must retain the above copyright
 *       notice, this list of conditions, and the following disclaimer.
 *
 *   2.  Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer
 *       in the documentation and/or other materials provided with the
 *       distribution, and in the same place and form as other copyright,
 *       license and disclaimer information.
 *
 *   3.  The end-user documentation included with the redistribution,
 *       if any, must include the following acknowledgment: "This product
 *       includes software developed by The XFree86 Project, Inc
 *       (http://www.xfree86.org/) and its contributors", in the same
 *       place and form as other third-party acknowledgments.  Alternately,
 *       this acknowledgment may appear in the software itself, in the
 *       same form and location as other such third-party acknowledgments.
 *
 *   4.  Except as contained in this notice, the name of The XFree86
 *       Project, Inc shall not be used in advertising or otherwise to
 *       promote the sale, use or other dealings in this Software without
 *       prior written authorization from The XFree86 Project, Inc.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE XFREE86 PROJECT, INC OR ITS CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#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"
#include	"mispans.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);
}

static void
sisGlyphBltClipped (DrawablePtr	    pDrawable, 
		    GCPtr	    pGC, 
		    int		    x, 
		    int		    y, 
		    unsigned int    nglyph,
		    CharInfoPtr	    *ppciInit,
		    Bool	    imageBlt)
{
    SetupSis(pDrawable->pScreen);
    int		    height;
    int		    width;
    int		    xBack = 0, yBack = 0;
    int		    hBack = 0, wBack;
    int		    nb;
    CharInfoPtr	    pci;
    CARD32	    *bits32;
    BoxRec	    bbox;
    unsigned char   alu;
    CARD32	    cmd;
    SisExpand	    expand;
    CARD32	    *dst, d;
    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);
}

static 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;
    int		    glyphsPer;
    FontPtr	    pfont = pGC->font;
    unsigned long   *char1, *char2, *char3, *char4, *char5;
    CARD32	    *dst, tmp;
    int		    nb;
    int		    bwidth;
    CARD32	    cmd;
    int		    h;
    BoxRec	    bbox;
    SisExpand	    expand;
    int		    lwTmp, lw;
    
    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;
}

static 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 = 0, yBack = 0;
    int		    hBack = 0, wBack;
    int		    nb, bwidth;
    FontPtr	    pfont = pGC->font;
    CharInfoPtr	    pci;
    CARD8	    *bits8;
    CARD16	    *bits16;
    CARD32	    *bits32;
    BoxRec	    bbox;
    CharInfoPtr	    *ppci;
    unsigned char   alu;
    CARD32	    cmd;
    SisExpand	    expand;
    CARD32	    *dst, d = 0;

    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)
 */

static 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);
}

static 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))

static 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));
    }
    return TRUE;
}

static 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, 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;
}

static 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);
}

static 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);
}

static 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);
}

static 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.
*/

static 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);
}

static RegionPtr
sisCopyArea(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
	   int srcx, int srcy, int width, int height, int dstx, int dsty)
{
    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;

static 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	*psrc;
    FbStride	widthRest;
    FbStip	bits, tmp;
    int		leftShift, rightShift;
    int		nl, nlMiddle;
    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;
}
	    
static 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);
}

static RegionPtr
sisCopyPlane(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, GCPtr pGC,
	int srcx, int srcy, int width, int height, 
	int dstx, int dsty, unsigned long bitPlane)
{
    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);
}

static void
sisFillSpans (DrawablePtr pDrawable, GCPtr pGC, int n, 
	     DDXPointPtr ppt, int *pwidth, int fSorted)
{
    SetupSis(pDrawable->pScreen);
    DDXPointPtr	    pptFree;
    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 *)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;
    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);
    DEALLOCATE_LOCAL(pptFree);
    DEALLOCATE_LOCAL(pwidthFree);
}

#define NUM_STACK_RECTS	1024

static 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];
    int		    numRects;
    int		    n;
    int		    xorg, yorg;

    (void)sis;

    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)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)
    {
	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)
    	DEALLOCATE_LOCAL(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,
#ifdef NEED_LINEHELPER
    ,NULL
#endif
};

static void
sisValidateGC (GCPtr pGC, Mask changes, DrawablePtr pDrawable)
{
    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
};

static int
sisCreateGC (GCPtr pGC)
{
    if (!fbCreateGC (pGC))
	return FALSE;

    if (pGC->depth != 1)
	pGC->funcs = &sisGCFuncs;
    
    pGC->ops = (GCOps *) &kdAsyncPixmapGCOps;
    
    return TRUE;
}

static void
sisCopyWindow(WindowPtr pWin, DDXPointRec ptOldOrg, RegionPtr prgnSrc)
{
    ScreenPtr	pScreen = pWin->drawable.pScreen;
    RegionRec	rgnDst;
    int		dx, dy;
    WindowPtr	pwinRoot;

    pwinRoot = WindowTable[pScreen->myNum];

    dx = ptOldOrg.x - pWin->drawable.x;
    dy = ptOldOrg.y - pWin->drawable.y;
    REGION_TRANSLATE(pScreen, prgnSrc, -dx, -dy);

    REGION_NULL(pScreen, &rgnDst);
    
    REGION_INTERSECT(pScreen, &rgnDst, &pWin->borderClip, prgnSrc);

    fbCopyRegion ((DrawablePtr)pwinRoot, (DrawablePtr)pwinRoot,
		  0,
		  &rgnDst, dx, dy, sisCopyNtoN, 0, 0);
    
    REGION_UNINIT(pScreen, &rgnDst);
}

static void
sisPaintWindow(WindowPtr pWin, RegionPtr pRegion, int what)
{
    PixmapPtr	pTile;

    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:
	    pTile = pWin->background.pixmap;
	    if (sisPatternDimOk (pTile->drawable.width) &&
		sisPatternDimOk (pTile->drawable.height))
	    {
		sisFillBoxTiled ((DrawablePtr)pWin,
				 (int)REGION_NUM_RECTS(pRegion),
				 REGION_RECTS(pRegion),
				 pTile, 
				 pWin->drawable.x, pWin->drawable.y, GXcopy);
		return;
	    }
	    break;
	case BackgroundPixel:
	    sisFillBoxSolid((DrawablePtr)pWin,
			     (int)REGION_NUM_RECTS(pRegion),
			     REGION_RECTS(pRegion),
			     pWin->background.pixel, GXcopy);
	    return;
    	}
    	break;
    case PW_BORDER:
	if (pWin->borderIsPixel)
	{
	    sisFillBoxSolid((DrawablePtr)pWin,
			     (int)REGION_NUM_RECTS(pRegion),
			     REGION_RECTS(pRegion),
			     pWin->border.pixel, GXcopy);
	    return;
	}
	else
	{
	    pTile = pWin->border.pixmap;
	    if (sisPatternDimOk (pTile->drawable.width) &&
		sisPatternDimOk (pTile->drawable.height))
	    {
		sisFillBoxTiled ((DrawablePtr)pWin,
				 (int)REGION_NUM_RECTS(pRegion),
				 REGION_RECTS(pRegion),
				 pTile, 
				 pWin->drawable.x, pWin->drawable.y, GXcopy);
		return;
	    }
	}
	break;
    }
    KdCheckPaintWindow (pWin, pRegion, what);
}

Bool
sisDrawInit (ScreenPtr pScreen)
{
    /*
     * Hook up asynchronous drawing
     */
    KdScreenInitAsync (pScreen);
    /*
     * Replace various fb screen functions
     */
    pScreen->CreateGC = sisCreateGC;
    pScreen->CopyWindow = sisCopyWindow;
    pScreen->PaintWindowBackground = sisPaintWindow;
    pScreen->PaintWindowBorder = sisPaintWindow;
    
    return TRUE;
}

void
sisDrawEnable (ScreenPtr pScreen)
{
    SetupSis(pScreen);
    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%lx\n", sis->u.accel.src_addr);
    sis->u.accel.src_addr = (base & 0x3fffff);
    fprintf (stderr, "src 0x%lx\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)
{
}
