/* * 2D Acceleration for SiS 530, 620, 300, 540, 630, 730. * * Copyright (C) 2001-2005 by Thomas Winischhofer, Vienna, Austria * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 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. * 3) The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 AUTHOR 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. * * Authors: Thomas Winischhofer * Can-Ru Yeou, SiS Inc. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #if 0 #define DEBUG #endif #include "sis.h" #include "sis_regs.h" #include "sis300_accel.h" /* This is the offset to the memory for each head */ #define HEADOFFSET (pSiS->dhmOffset) #ifdef SIS_USE_XAA #undef STSCE /* Use/Don't use ScreenToScreenColorExpand - does not work */ #undef TRAP /* Use/Don't use Trapezoid Fills - does not work - XAA provides * illegal trapezoid data (left and right edges cross each other * sometimes) which causes drawing errors. Further, I have not found * out how to draw polygones with a height greater than 127... */ #endif /* XAA */ #ifdef SIS_USE_EXA extern void SiSScratchSave(ScreenPtr pScreen, ExaOffscreenArea *area); extern Bool SiSUploadToScratch(PixmapPtr pSrc, PixmapPtr pDst); #endif /* EXA */ extern UChar SiSGetCopyROP(int rop); extern UChar SiSGetPatternROP(int rop); static void SiSInitializeAccelerator(ScrnInfoPtr pScrn) { #ifdef SIS_USE_XAA SISPtr pSiS = SISPTR(pScrn); pSiS->DoColorExpand = FALSE; #endif } static void SiSSync(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); SiSIdle } static void SiSSyncAccel(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); if(!pSiS->NoAccel) SiSSync(pScrn); } static void SiSSetupForScreenToScreenCopy(ScrnInfoPtr pScrn, int xdir, int ydir, int rop, unsigned int planemask, int trans_color) { SISPtr pSiS = SISPTR(pScrn); SiSSetupDSTColorDepth(pSiS->DstColor); SiSSetupSRCPitch(pSiS->scrnOffset) SiSSetupDSTRect(pSiS->scrnOffset, -1) if(trans_color != -1) { SiSSetupROP(0x0A) SiSSetupSRCTrans(trans_color) SiSSetupCMDFlag(TRANSPARENT_BITBLT) } else { SiSSetupROP(SiSGetCopyROP(rop)) } if(xdir > 0) { SiSSetupCMDFlag(X_INC) } if(ydir > 0) { SiSSetupCMDFlag(Y_INC) } } static void SiSSubsequentScreenToScreenCopy(ScrnInfoPtr pScrn, int src_x, int src_y, int dst_x, int dst_y, int width, int height) { SISPtr pSiS = SISPTR(pScrn); CARD32 srcbase, dstbase; srcbase = dstbase = 0; if(src_y >= 2048) { srcbase = pSiS->scrnOffset * src_y; src_y = 0; } if((dst_y >= pScrn->virtualY) || (dst_y >= 2048)) { dstbase = pSiS->scrnOffset * dst_y; dst_y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { srcbase += HEADOFFSET; dstbase += HEADOFFSET; } #endif SiSSetupSRCBase(srcbase); SiSSetupDSTBase(dstbase); if(!(pSiS->CommandReg & X_INC)) { src_x += width-1; dst_x += width-1; } if(!(pSiS->CommandReg & Y_INC)) { src_y += height-1; dst_y += height-1; } SiSSetupRect(width, height) SiSSetupSRCXY(src_x, src_y) SiSSetupDSTXY(dst_x, dst_y) SiSDoCMD } static void SiSSetupForSolidFill(ScrnInfoPtr pScrn, int color, int rop, unsigned int planemask) { SISPtr pSiS = SISPTR(pScrn); if(pSiS->disablecolorkeycurrent) { if((CARD32)color == pSiS->colorKey) { rop = 5; /* NOOP */ } } SiSSetupPATFG(color) SiSSetupDSTRect(pSiS->scrnOffset, -1) SiSSetupDSTColorDepth(pSiS->DstColor); SiSSetupROP(SiSGetPatternROP(rop)) /* SiSSetupCMDFlag(PATFG) - is zero */ } static void SiSSubsequentSolidFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) { SISPtr pSiS = SISPTR(pScrn); CARD32 dstbase = 0; if(y >= 2048) { dstbase = pSiS->scrnOffset * y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) SiSSetupDSTXY(x,y) SiSSetupRect(w,h) /* Clear commandReg because Setup can be used for Rect and Trap */ pSiS->CommandReg &= ~(T_XISMAJORL | T_XISMAJORR | T_L_X_INC | T_L_Y_INC | T_R_X_INC | T_R_Y_INC | TRAPAZOID_FILL); SiSSetupCMDFlag(X_INC | Y_INC | BITBLT) SiSDoCMD } #ifdef SIS_USE_XAA /* ---------------------------- XAA -------------------------- */ #ifdef SISDUALHEAD static void SiSRestoreAccelState(ScrnInfoPtr pScrn) { SISPtr pSiS = SISPTR(pScrn); /* We don't need to do anything special here; forcing the * other head to re-read the CmdQueLen is not necessary: * After the Sync in RestoreAccelState(), the real queue * length is always larger than (or at least equal to) * the amount stored in CmdQueueLen of the other head, * so the only thing that might happen is one unnecessary * Sync on the other head. I think we can live with that. */ pSiS->DoColorExpand = FALSE; SiSIdle } #endif /* Trapezoid */ /* This would work better if XAA would provide us with valid trapezoids. * In fact, with small trapezoids the left and the right edge often cross * each other or result in a line length of 0 which causes drawing errors * (filling over whole scanline). * Furthermore, I have not found out how to draw trapezoids with a height * greater than 127. */ #ifdef TRAP static void SiSSubsequentSolidFillTrap(ScrnInfoPtr pScrn, int y, int h, int left, int dxL, int dyL, int eL, int right, int dxR, int dyR, int eR ) { SISPtr pSiS = SISPTR(pScrn); CARD32 dstbase; #if 0 float kL, kR; #endif dstbase = 0; if(y >= 2048) { dstbase=pSiS->scrnOffset*y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) /* SiSSetupRect(w,h) */ #if 1 SiSSetupPATFG(0xff0000) /* FOR TESTING */ #endif /* Clear CommandReg because SetUp can be used for Rect and Trap */ pSiS->CommandReg &= ~(T_L_X_INC | T_L_Y_INC | T_R_X_INC | T_R_Y_INC | T_XISMAJORL | T_XISMAJORR | BITBLT); xf86DrvMsg(0, X_INFO, "Trap (%d %d %d %d) dxL %d dyL %d eL %d dxR %d dyR %d eR %d\n", left, right, y, h, dxL, dyL, eL, dxR, dyR, eR); /* Unfortunately, we must check if the right and the left edge * cross each other... INCOMPLETE (line equation wrong) */ #if 0 if (dxL == 0) kL = 0; else kL = (float)dyL / (float)dxL; if (dxR == 0) kR = 0; else kR = (float)dyR / (float)dxR; xf86DrvMsg(0, X_INFO, "kL %f kR %f!\n", kL, kR); if ( (kR != kL) && (!(kR == 0 && kL == 0)) && (!(kR < 0 && kL > 0)) ) { xf86DrvMsg(0, X_INFO, "Inside if (%f - %d)\n", ( kL * ( ( ((float)right - (float)left) / (kL - kR) ) - left) + y), h+y); if ( ( ( kL * ( ( ((float)right - (float)left) / (kL - kR) ) - (float)left) + (float)y) < (h + y) ) ) { xf86DrvMsg(0, X_INFO, "Cross detected!\n"); } } #endif /* Determine egde angles */ if(dxL < 0) { dxL = -dxL; } else { SiSSetupCMDFlag(T_L_X_INC) } if(dxR < 0) { dxR = -dxR; } else { SiSSetupCMDFlag(T_R_X_INC) } /* (Y direction always positive - do this anyway) */ if(dyL < 0) { dyL = -dyL; } else { SiSSetupCMDFlag(T_L_Y_INC) } if(dyR < 0) { dyR = -dyR; } else { SiSSetupCMDFlag(T_R_Y_INC) } /* Determine major axis */ if(dxL >= dyL) { /* X is major axis */ SiSSetupCMDFlag(T_XISMAJORL) } if(dxR >= dyR) { /* X is major axis */ SiSSetupCMDFlag(T_XISMAJORR) } /* Set up deltas */ SiSSetupdL(dxL, dyL) SiSSetupdR(dxR, dyR) #if 0 /* Could it be that this crappy engine can only draw trapezoids up to 127 pixels high? */ h &= 0x7F; if (h == 0) h = 10; #endif /* Set up y, h, left, right */ SiSSetupYH(y,h) SiSSetupLR(left,right) /* Set up initial error term */ SiSSetupEL(eL) SiSSetupER(eR) SiSSetupCMDFlag(TRAPAZOID_FILL); SiSDoCMD } #endif static void SiSSetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop, unsigned int planemask) { SISPtr pSiS = SISPTR(pScrn); SiSSetupLineCount(1) SiSSetupPATFG(color) SiSSetupDSTRect(pSiS->scrnOffset, -1) SiSSetupDSTColorDepth(pSiS->DstColor); SiSSetupROP(SiSGetPatternROP(rop)) SiSSetupCMDFlag(PATFG | LINE) } static void SiSSubsequentSolidTwoPointLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2, int flags) { SISPtr pSiS = SISPTR(pScrn); int miny, maxy; CARD32 dstbase = 0; miny = (y1 > y2) ? y2 : y1; maxy = (y1 > y2) ? y1 : y2; if(maxy >= 2048) { dstbase = pSiS->scrnOffset * miny; y1 -= miny; y2 -= miny; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) SiSSetupX0Y0(x1,y1) SiSSetupX1Y1(x2,y2) if(flags & OMIT_LAST) { SiSSetupCMDFlag(NO_LAST_PIXEL) } else { pSiS->CommandReg &= ~(NO_LAST_PIXEL); } SiSDoCMD } static void SiSSubsequentSolidHorzVertLine(ScrnInfoPtr pScrn, int x, int y, int len, int dir) { SISPtr pSiS = SISPTR(pScrn); CARD32 dstbase = 0; len--; /* starting point is included! */ if((y >= 2048) || ((dir != DEGREES_0) && ((y + len) >= 2048))) { dstbase = pSiS->scrnOffset * y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) SiSSetupX0Y0(x,y) if(dir == DEGREES_0) { SiSSetupX1Y1(x + len, y); } else { SiSSetupX1Y1(x, y + len); } SiSDoCMD } static void SiSSetupForDashedLine(ScrnInfoPtr pScrn, int fg, int bg, int rop, unsigned int planemask, int length, UChar *pattern) { SISPtr pSiS = SISPTR(pScrn); SiSSetupLineCount(1) SiSSetupDSTRect(pSiS->scrnOffset, -1) SiSSetupDSTColorDepth(pSiS->DstColor); SiSSetupStyleLow(*pattern) SiSSetupStyleHigh(*(pattern+4)) SiSSetupStylePeriod(length-1); SiSSetupROP(SiSGetPatternROP(rop)) SiSSetupPATFG(fg) SiSSetupCMDFlag(LINE | LINE_STYLE) if(bg != -1) { SiSSetupPATBG(bg) } else { SiSSetupCMDFlag(TRANSPARENT); } } static void SiSSubsequentDashedTwoPointLine(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2, int flags, int phase) { SISPtr pSiS = SISPTR(pScrn); int miny, maxy; CARD32 dstbase = 0; miny = (y1 > y2) ? y2 : y1; maxy = (y1 > y2) ? y1 : y2; if(maxy >= 2048) { dstbase = pSiS->scrnOffset * miny; y1 -= miny; y2 -= miny; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) SiSSetupX0Y0(x1,y1) SiSSetupX1Y1(x2,y2) if(flags & OMIT_LAST) { SiSSetupCMDFlag(NO_LAST_PIXEL) } else { pSiS->CommandReg &= ~(NO_LAST_PIXEL); } SiSDoCMD } static void SiSSetupForMonoPatternFill(ScrnInfoPtr pScrn, int patx, int paty, int fg, int bg, int rop, unsigned int planemask) { SISPtr pSiS = SISPTR(pScrn); SiSSetupDSTRect(pSiS->scrnOffset, -1) SiSSetupDSTColorDepth(pSiS->DstColor); SiSSetupMONOPAT(patx,paty) SiSSetupPATFG(fg) SiSSetupROP(SiSGetPatternROP(rop)) SiSSetupCMDFlag(PATMONO) if(bg != -1) { SiSSetupPATBG(bg) } else { SiSSetupCMDFlag(TRANSPARENT) } } static void SiSSubsequentMonoPatternFill(ScrnInfoPtr pScrn, int patx, int paty, int x, int y, int w, int h) { SISPtr pSiS = SISPTR(pScrn); CARD32 dstbase = 0; if(y >= 2048) { dstbase = pSiS->scrnOffset * y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) SiSSetupDSTXY(x, y) SiSSetupRect(w, h) /* Clear commandReg because Setup can be used for Rect and Trap */ pSiS->CommandReg &= ~(T_XISMAJORL | T_XISMAJORR | T_L_X_INC | T_L_Y_INC | T_R_X_INC | T_R_Y_INC | TRAPAZOID_FILL); SiSSetupCMDFlag(X_INC | Y_INC) SiSDoCMD } /* Trapezoid */ #ifdef TRAP static void SiSSubsequentMonoPatternFillTrap(ScrnInfoPtr pScrn, int patx, int paty, int y, int h, int left, int dxL, int dyL, int eL, int right, int dxR, int dyR, int eR ) { SISPtr pSiS = SISPTR(pScrn); CARD32 dstbase = 0; if(y >= 2048) { dstbase = pSiS->scrnOffset * y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif SiSSetupDSTBase(dstbase) /* Clear CommandReg because SetUp can be used for Rect and Trap */ pSiS->CommandReg &= ~(T_XISMAJORL | T_XISMAJORR | T_L_X_INC | T_L_Y_INC | T_R_X_INC | T_R_Y_INC | BITBLT); if(dxL < 0) { dxL = -dxL; } else { SiSSetupCMDFlag(T_L_X_INC) } if(dxR < 0) { dxR = -dxR; } else { SiSSetupCMDFlag(T_R_X_INC) } if(dyL < 0) { dyL = -dyL; } else { SiSSetupCMDFlag(T_L_Y_INC) } if(dyR < 0) { dyR = -dyR; } else { SiSSetupCMDFlag(T_R_Y_INC) } /* Determine major axis */ if(dxL >= dyL) { /* X is major axis */ SiSSetupCMDFlag(T_XISMAJORL) } if(dxR >= dyR) { /* X is major axis */ SiSSetupCMDFlag(T_XISMAJORR) } SiSSetupYH(y,h) SiSSetupLR(left,right) SiSSetupdL(dxL, dyL) SiSSetupdR(dxR, dyR) SiSSetupEL(eL) SiSSetupER(eR) SiSSetupCMDFlag(TRAPAZOID_FILL); SiSDoCMD } #endif /* ------ Screen To Screen Color Expand ------------------------------- */ /* The hareware does not seem to support this the way we need it */ #ifdef STSCE static void SiSSetupForScreenToScreenColorExpand(ScrnInfoPtr pScrn, int fg, int bg, int rop, unsigned int planemask) { SISPtr pSiS = SISPTR(pScrn); SiSSetupDSTColorDepth(pSiS->DstColor) SiSSetupDSTRect(pSiS->scrnOffset, -1) SiSSetupROP(SiSGetCopyROP(rop)) SiSSetupSRCFG(fg) /* SiSSetupSRCXY(0,0) */ if(bg == -1) { SiSSetupCMDFlag(TRANSPARENT | ENCOLOREXP | X_INC | Y_INC | SRCVIDEO); } else { SiSSetupSRCBG(bg); SiSSetupCMDFlag(ENCOLOREXP | X_INC | Y_INC | SRCVIDEO); }; } #endif /* This method blits in a single task; this does not seem to work * because the hardware does not use the source pitch as scanline * offset but only to calculate pattern address from source X and Y. * XAA provides the pattern bitmap with scrnOffset (displayWidth * bpp/8) * offset, but this does not seem to be supported by the hardware. */ #ifdef STSCE /* For testing, these are the methods: (use only one at a time!) */ #undef npitch /* Normal: Use srcx/y as srcx/y, use scrnOffset as source pitch * This would work if the hareware used the source pitch for * incrementing the source address after each scanline - but * it doesn't do this! The first line of the area is correctly * color expanded, but since the source pitch is ignored and * the source address not incremented correctly, the following * lines are color expanded with any bit pattern that is left * in the unused space of the source bitmap (which is organized * with the depth of the screen framebuffer hence with a pitch * of scrnOffset). */ #undef pitchdw /* Use source pitch "displayWidth / 8" instead * of scrnOffset (=displayWidth * bpp / 8) * This can't work, because the pitch of the source * bitmap is scrnoffset! */ #define nopitch /* Calculate srcbase with srcx and srcy, set the * pitch to scrnOffset (which IS the correct pitch * for the source bitmap) and set srcx and srcy both * to 0. * This would work if the hareware used the source pitch for * incrementing the source address after each scanline - but * it doesn't do this! Again: The first line of the area is * correctly color expanded, but since the source pitch is * ignored for scanline address incremention, the following * lines are not correctly color expanded. * WHATEVER I write to source pitch is ignored! */ static void SiSSubsequentScreenToScreenColorExpand(ScrnInfoPtr pScrn, int x, int y, int w, int h, int srcx, int srcy, int skipleft) { SISPtr pSiS = SISPTR(pScrn); CARD32 srcbase, dstbase; #if 0 int _x0, _y0, _x1, _y1; #endif #ifdef pitchdw int newsrcx, newsrcy; /* srcx and srcy are provided based on a scrnOffset pitch ( = displayWidth * bpp / 8 ) * We recalulate srcx and srcy based on pitch = displayWidth / 8 */ newsrcy = ((pSiS->scrnOffset * srcy) + (srcx * ((pScrn->bitsPerPixel+7)/8))) / (pScrn->displayWidth/8); newsrcx = ((pSiS->scrnOffset * srcy) + (srcx * ((pScrn->bitsPerPixel+7)/8))) % (pScrn->displayWidth/8); #endif xf86DrvMsg(0, X_INFO, "Sub ScreenToScreen ColorExp(%d,%d, %d,%d, %d,%d, %d)\n", x, y, w, h, srcx, srcy, skipleft); srcbase = dstbase = 0; #ifdef pitchdw if(newsrcy >= 2048) { srcbase = (pScrn->displayWidth / 8) * newsrcy; newsrcy = 0; } #endif #ifdef nopitch srcbase = (pSiS->scrnOffset * srcy) + (srcx * ((pScrn->bitsPerPixel+7)/8)); #endif #ifdef npitch if(srcy >= 2048) { srcbase = pSiS->scrnOffset * srcy; srcy = 0; } #endif if(y >= 2048) { dstbase = pSiS->scrnOffset * y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { srcbase += HEADOFFSET; dstbase += HEADOFFSET; } #endif SiSSetupSRCBase(srcbase) SiSSetupDSTBase(dstbase) #ifdef pitchdw SiSSetupSRCPitch(pScrn->displayWidth/8) #endif #ifdef nopitch SiSSetupSRCPitch(pSiS->scrnOffset) /* SiSSetupSRCPitch(100) */ /* For test - has NO effect WHATSOEVER */ #endif #ifdef npitch SiSSetupSRCPitch(pSiS->scrnOffset) #endif SiSSetupRect(w,h) #if 0 /* How do I implement the offset? Not this way, that's for sure.. */ if (skipleft > 0) { _x0 = x+skipleft; _y0 = y; _x1 = x+w; _y1 = y+h; SiSSetupClipLT(_x0, _y0); SiSSetupClipRB(_x1, _y1); SiSSetupCMDFlag(CLIPENABLE); } #endif #ifdef pitchdw SiSSetupSRCXY(newsrcx, newsrcy) #endif #ifdef nopitch SiSSetupSRCXY(0,0) #endif #ifdef npitch SiSSetupSRCXY(srcx, srcy) #endif SiSSetupDSTXY(x,y) SiSDoCMD } #endif /* ----- CPU To Screen Color Expand (scanline-wise) ----------------- */ /* We do it using the indirect method */ static void SiSSetupForScanlineCPUToScreenColorExpandFill(ScrnInfoPtr pScrn, int fg, int bg, int rop, unsigned int planemask) { SISPtr pSiS=SISPTR(pScrn); /* Make sure that current CPU-driven BitBlt buffer stage is 0 * This is required!!! (Otherwise -> drawing errors) */ while((SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0x1F00) != 0) {} /* WDR: == 0x10 */ SiSSetupSRCXY(0,0); SiSSetupROP(SiSGetCopyROP(rop)); SiSSetupSRCFG(fg); SiSSetupDSTRect(pSiS->scrnOffset, -1); SiSSetupDSTColorDepth(pSiS->DstColor); if(bg == -1) { SiSSetupCMDFlag(TRANSPARENT | ENCOLOREXP | X_INC | Y_INC | SRCCPUBLITBUF); } else { SiSSetupSRCBG(bg); SiSSetupCMDFlag(ENCOLOREXP | X_INC | Y_INC | SRCCPUBLITBUF); } } static void SiSSubsequentScanlineCPUToScreenColorExpandFill( ScrnInfoPtr pScrn, int x, int y, int w, int h, int skipleft) { SISPtr pSiS = SISPTR(pScrn); int _x0, _y0, _x1, _y1; CARD32 dstbase = 0; if((y >= 2048) || ((y + h) >= 2048)) { dstbase = pSiS->scrnOffset * y; y = 0; } #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { dstbase += HEADOFFSET; } #endif /* Wait until there is no color expansion command in queue * (This solves the OpenOffice.org window-move bug) * Added Idle-check - bit 23 is set sometimes, although * engine is actually idle! * Update: Bit 23 is not reliable. After heavy 3D engine * action, this bit never gets cleared again. So do * SiSIdle instead. */ if((SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xe000) != 0xe000) { /* while ((SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0x0080) != 0) {} */ SiSIdle } SiSSetupDSTBase(dstbase) if(skipleft > 0) { _x0 = x + skipleft; _y0 = y; _x1 = x + w; _y1 = y + h; SiSSetupClipLT(_x0, _y0); SiSSetupClipRB(_x1, _y1); SiSSetupCMDFlag(CLIPENABLE); } else { pSiS->CommandReg &= (~CLIPENABLE); } SiSSetupRect(w, 1); SiSSetupSRCPitch(((((w + 7) / 8) + 3) >> 2) * 4); pSiS->xcurrent = x; pSiS->ycurrent = y; } static void SiSSubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno) { SISPtr pSiS=SISPTR(pScrn); #if 0 int newhead,bltbufstage,newtail; #endif CARD32 cbo; cbo = pSiS->ColorExpandBufferScreenOffset[bufno]; #ifdef SISDUALHEAD if(pSiS->VGAEngine != SIS_530_VGA) { cbo += HEADOFFSET; } #endif /* Wait until there is no color expansion command in queue * (This solves the GTK-big-font bug) * Added Idle-check - bit 23 is set sometimes, although * engine is actually idle! * Update: Bit 23 is not reliable. After heavy 3D engine * action, this bit never gets cleared again. So do * SiSIdle instead. */ if((SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0xe000) != 0xe000) { /* while ((SIS_MMIO_IN16(pSiS->IOBase, 0x8242) & 0x0080) != 0) {} */ SiSIdle } SiSSetupSRCBase(cbo); SiSSetupDSTXY(pSiS->xcurrent, pSiS->ycurrent); SiSDoCMD pSiS->ycurrent++; if(pSiS->VGAEngine == SIS_530_VGA) { while(SIS_MMIO_IN8(pSiS->IOBase, 0x8242) & 0x80) {} } } #endif /* XAA */ #ifdef SIS_USE_EXA /* ---------------------------- EXA -------------------------- */ static const unsigned short dstcol[] = { 0x0000, 0x8000, 0xc000 }; static void SiSEXASync(ScreenPtr pScreen, int marker) { SISPtr pSiS = SISPTR(xf86ScreenToScrn(pScreen)); SiSIdle } static Bool SiSPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planemask, Pixel fg) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); SISPtr pSiS = SISPTR(pScrn); CARD32 dstbase; /* Planemask not supported */ if((planemask & ((1 << pPixmap->drawable.depth) - 1)) != (1 << pPixmap->drawable.depth) - 1) { return FALSE; } /* Since the 530/620 have no "dest color depth" register, I * assume that the 2D engine reads the current color depth * from the DAC.... FIXME ? */ if(pSiS->VGAEngine == SIS_530_VGA) { if(pPixmap->drawable.bitsPerPixel != pSiS->CurrentLayout.bitsPerPixel) return FALSE; } else if((pPixmap->drawable.bitsPerPixel != 8) && (pPixmap->drawable.bitsPerPixel != 16) && (pPixmap->drawable.bitsPerPixel != 32)) return FALSE; if(pSiS->disablecolorkeycurrent) { if((CARD32)fg == pSiS->colorKey) { alu = 5; /* NOOP */ } } /* Check that the pitch matches the hardware's requirements. Should * never be a problem due to pixmapPitchAlign and fbScreenInit. */ if(exaGetPixmapPitch(pPixmap) & 3) return FALSE; dstbase = (CARD32)exaGetPixmapOffset(pPixmap) + HEADOFFSET; SiSSetupPATFG(fg) SiSSetupDSTRect(exaGetPixmapPitch(pPixmap), -1) SiSSetupDSTColorDepth(dstcol[pPixmap->drawable.bitsPerPixel >> 4]); SiSSetupROP(SiSGetPatternROP(alu)) SiSSetupDSTBase(dstbase) /* SiSSetupCMDFlag(PATFG) - is zero */ return TRUE; } static void SiSSolid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pPixmap->drawable.pScreen); SISPtr pSiS = SISPTR(pScrn); SiSSetupDSTXY(x1, y1) SiSSetupRect(x2-x1, y2-y1) SiSSetupCMDFlag(X_INC | Y_INC | BITBLT) SiSDoCMD } static void SiSDoneSolid(PixmapPtr pPixmap) { } static Bool SiSPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, int ydir, int alu, Pixel planemask) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); SISPtr pSiS = SISPTR(pScrn); CARD32 srcbase, dstbase; /* Planemask not supported */ if((planemask & ((1 << pSrcPixmap->drawable.depth) - 1)) != (1 << pSrcPixmap->drawable.depth) - 1) { return FALSE; } /* Since the 530/620 have no "dest color depth" register, I * assume that the 2D engine reads the current color depth * from the DAC.... FIXME ? */ if(pSiS->VGAEngine == SIS_530_VGA) { if(pDstPixmap->drawable.bitsPerPixel != pSiS->CurrentLayout.bitsPerPixel) return FALSE; } else if((pDstPixmap->drawable.bitsPerPixel != 8) && (pDstPixmap->drawable.bitsPerPixel != 16) && (pDstPixmap->drawable.bitsPerPixel != 32)) return FALSE; /* Check that the pitch matches the hardware's requirements. Should * never be a problem due to pixmapPitchAlign and fbScreenInit. */ if(exaGetPixmapPitch(pSrcPixmap) & 3) return FALSE; if(exaGetPixmapPitch(pDstPixmap) & 3) return FALSE; SiSSetupDSTColorDepth(dstcol[pDstPixmap->drawable.bitsPerPixel >> 4]); SiSSetupSRCPitch(exaGetPixmapPitch(pSrcPixmap)) SiSSetupDSTRect(exaGetPixmapPitch(pDstPixmap), -1) SiSSetupROP(SiSGetCopyROP(alu)) if(xdir >= 0) { SiSSetupCMDFlag(X_INC) } if(ydir >= 0) { SiSSetupCMDFlag(Y_INC) } srcbase = (CARD32)exaGetPixmapOffset(pSrcPixmap) + HEADOFFSET; dstbase = (CARD32)exaGetPixmapOffset(pDstPixmap) + HEADOFFSET; SiSSetupSRCBase(srcbase); SiSSetupDSTBase(dstbase); return TRUE; } static void SiSCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, int width, int height) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pDstPixmap->drawable.pScreen); SISPtr pSiS = SISPTR(pScrn); if(!(pSiS->CommandReg & X_INC)) { srcX += width-1; dstX += width-1; } if(!(pSiS->CommandReg & Y_INC)) { srcY += height-1; dstY += height-1; } SiSSetupRect(width, height) SiSSetupSRCXY(srcX, srcY) SiSSetupDSTXY(dstX, dstY) SiSDoCMD } static void SiSDoneCopy(PixmapPtr pDstPixmap) { } #endif /* EXA */ /* For DGA usage */ static void SiSDGAFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h, int color) { SiSSetupForSolidFill(pScrn, color, GXcopy, ~0); SiSSubsequentSolidFillRect(pScrn, x, y, w, h); } static void SiSDGABlitRect(ScrnInfoPtr pScrn, int srcx, int srcy, int dstx, int dsty, int w, int h, int color) { int xdir = ((srcx < dstx) && (srcy == dsty)) ? -1 : 1; int ydir = (srcy < dsty) ? -1 : 1; SiSSetupForScreenToScreenCopy(pScrn, xdir, ydir, GXcopy, (CARD32)~0, color); SiSSubsequentScreenToScreenCopy(pScrn, srcx, srcy, dstx, dsty, w, h); } /* Initialisation */ Bool SiS300AccelInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); SISPtr pSiS = SISPTR(pScrn); #ifdef SIS_USE_XAA XAAInfoRecPtr infoPtr = NULL; UChar *AvailBufBase; int topFB, reservedFbSize, usableFbSize, i; BoxRec Avail; #endif /* XAA */ pSiS->ColorExpandBufferNumber = 0; pSiS->PerColorExpandBufferSize = 0; pSiS->RenderAccelArray = NULL; #ifdef SIS_USE_XAA pSiS->AccelInfoPtr = NULL; #endif #ifdef SIS_USE_EXA pSiS->EXADriverPtr = NULL; pSiS->exa_scratch = NULL; #endif if((pScrn->bitsPerPixel != 8) && (pScrn->bitsPerPixel != 16) && (pScrn->bitsPerPixel != 32)) { pSiS->NoAccel = TRUE; } if(!pSiS->NoAccel) { #ifdef SIS_USE_XAA if(!pSiS->useEXA) { pSiS->AccelInfoPtr = infoPtr = XAACreateInfoRec(); if(!infoPtr) pSiS->NoAccel = TRUE; } #endif #ifdef SIS_USE_EXA if(pSiS->useEXA) { if(!(pSiS->EXADriverPtr = exaDriverAlloc())) { pSiS->NoAccel = TRUE; pSiS->NoXvideo = TRUE; /* No fbmem manager -> no xv */ } } #endif } if(!pSiS->NoAccel) { SiSInitializeAccelerator(pScrn); pSiS->InitAccel = SiSInitializeAccelerator; pSiS->SyncAccel = SiSSyncAccel; pSiS->FillRect = SiSDGAFillRect; pSiS->BlitRect = SiSDGABlitRect; #ifdef SIS_USE_XAA /* ----------------------- XAA ----------------------- */ if(!pSiS->useEXA) { infoPtr->Flags = LINEAR_FRAMEBUFFER | OFFSCREEN_PIXMAPS | PIXMAP_CACHE; /* sync */ infoPtr->Sync = SiSSync; /* Although SiS states that the 300 series supports a * virtual screen of 4096x4096, the 2D accelerator * does not seem to know that. If the destination bitmap * pitch is > 8192 (which easily happens in 32bpp mode), * the accelerator engine collapses. * TODO: Find out about the 530 and 620 */ if(pSiS->scrnOffset < 8192) { /* screen to screen copy */ infoPtr->SetupForScreenToScreenCopy = SiSSetupForScreenToScreenCopy; infoPtr->SubsequentScreenToScreenCopy = SiSSubsequentScreenToScreenCopy; infoPtr->ScreenToScreenCopyFlags = NO_PLANEMASK | TRANSPARENCY_GXCOPY_ONLY; /* solid fills */ infoPtr->SetupForSolidFill = SiSSetupForSolidFill; infoPtr->SubsequentSolidFillRect = SiSSubsequentSolidFillRect; #ifdef TRAP infoPtr->SubsequentSolidFillTrap = SiSSubsequentSolidFillTrap; #endif infoPtr->SolidFillFlags = NO_PLANEMASK; /* solid line */ infoPtr->SetupForSolidLine = SiSSetupForSolidLine; infoPtr->SubsequentSolidTwoPointLine = SiSSubsequentSolidTwoPointLine; infoPtr->SubsequentSolidHorVertLine = SiSSubsequentSolidHorzVertLine; infoPtr->SolidLineFlags = NO_PLANEMASK; /* dashed line */ infoPtr->SetupForDashedLine = SiSSetupForDashedLine; infoPtr->SubsequentDashedTwoPointLine = SiSSubsequentDashedTwoPointLine; infoPtr->DashPatternMaxLength = 64; infoPtr->DashedLineFlags = NO_PLANEMASK | LINE_PATTERN_MSBFIRST_LSBJUSTIFIED; /* 8x8 mono pattern fill */ infoPtr->SetupForMono8x8PatternFill = SiSSetupForMonoPatternFill; infoPtr->SubsequentMono8x8PatternFillRect = SiSSubsequentMonoPatternFill; #ifdef TRAP infoPtr->SubsequentMono8x8PatternFillTrap = SiSSubsequentMonoPatternFillTrap; #endif infoPtr->Mono8x8PatternFillFlags = NO_PLANEMASK | HARDWARE_PATTERN_SCREEN_ORIGIN | HARDWARE_PATTERN_PROGRAMMED_BITS | /* NO_TRANSPARENCY | */ BIT_ORDER_IN_BYTE_MSBFIRST ; #ifdef STSCE /* Screen To Screen Color Expand */ /* The hardware does support this the way we need it */ infoPtr->SetupForScreenToScreenColorExpandFill = SiSSetupForScreenToScreenColorExpand; infoPtr->SubsequentScreenToScreenColorExpandFill = SiSSubsequentScreenToScreenColorExpand; infoPtr->ScreenToScreenColorExpandFillFlags = NO_PLANEMASK | BIT_ORDER_IN_BYTE_MSBFIRST ; #endif /* per-scanline color expansion (using indirect method) */ if(pSiS->VGAEngine == SIS_530_VGA) { pSiS->ColorExpandBufferNumber = 4; pSiS->ColorExpandBufferCountMask = 0x03; } else { pSiS->ColorExpandBufferNumber = 16; pSiS->ColorExpandBufferCountMask = 0x0F; } pSiS->PerColorExpandBufferSize = ((pScrn->virtualX + 31)/32) * 4; infoPtr->NumScanlineColorExpandBuffers = pSiS->ColorExpandBufferNumber; infoPtr->ScanlineColorExpandBuffers = (UChar **)&pSiS->ColorExpandBufferAddr[0]; infoPtr->SetupForScanlineCPUToScreenColorExpandFill = SiSSetupForScanlineCPUToScreenColorExpandFill; infoPtr->SubsequentScanlineCPUToScreenColorExpandFill = SiSSubsequentScanlineCPUToScreenColorExpandFill; infoPtr->SubsequentColorExpandScanline = SiSSubsequentColorExpandScanline; infoPtr->ScanlineCPUToScreenColorExpandFillFlags = NO_PLANEMASK | CPU_TRANSFER_PAD_DWORD | SCANLINE_PAD_DWORD | BIT_ORDER_IN_BYTE_MSBFIRST | LEFT_EDGE_CLIPPING; } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Virtual screen width too large for accelerator engine\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "\t2D acceleration and Xv disabled\n"); pSiS->NoXvideo = TRUE; } #ifdef SISDUALHEAD if(pSiS->DualHeadMode) { infoPtr->RestoreAccelState = SiSRestoreAccelState; } #endif } /* !exa */ #endif /* XAA */ #ifdef SIS_USE_EXA /* ----------------------- EXA ----------------------- */ if(pSiS->useEXA) { pSiS->EXADriverPtr->exa_major = 2; pSiS->EXADriverPtr->exa_minor = 0; if(pSiS->scrnOffset < 8192) { /* data */ pSiS->EXADriverPtr->memoryBase = pSiS->FbBase; pSiS->EXADriverPtr->memorySize = pSiS->maxxfbmem; pSiS->EXADriverPtr->offScreenBase = pScrn->virtualX * pScrn->virtualY * ((pScrn->bitsPerPixel + 7) / 8); if(pSiS->EXADriverPtr->memorySize > pSiS->EXADriverPtr->offScreenBase) { pSiS->EXADriverPtr->flags = EXA_OFFSCREEN_PIXMAPS; } else { pSiS->NoXvideo = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Not enough video RAM for offscreen memory manager. Xv disabled\n"); } pSiS->EXADriverPtr->pixmapOffsetAlign = 16; /* src/dst: double quad word boundary */ pSiS->EXADriverPtr->pixmapPitchAlign = 4; /* pitch: double word boundary */ if(pSiS->VGAEngine == SIS_300_VGA) { pSiS->EXADriverPtr->maxX = 4095; pSiS->EXADriverPtr->maxY = 4095; } else { pSiS->EXADriverPtr->maxX = 2047; pSiS->EXADriverPtr->maxY = 2047; } /* Sync */ pSiS->EXADriverPtr->WaitMarker = SiSEXASync; /* Solid fill */ pSiS->EXADriverPtr->PrepareSolid = SiSPrepareSolid; pSiS->EXADriverPtr->Solid = SiSSolid; pSiS->EXADriverPtr->DoneSolid = SiSDoneSolid; /* Copy */ pSiS->EXADriverPtr->PrepareCopy = SiSPrepareCopy; pSiS->EXADriverPtr->Copy = SiSCopy; pSiS->EXADriverPtr->DoneCopy = SiSDoneCopy; /* Composite not supported */ } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Virtual screen width too large for accelerator engine\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "\t2D acceleration and Xv disabled\n"); pSiS->NoAccel = TRUE; pSiS->NoXvideo = TRUE; /* No fbmem manager -> no xv */ } } #endif /* EXA */ } /* NoAccel */ /* Init framebuffer memory manager */ /* Layout: (Sizes do not reflect correct proportions) * |--------------++++++++++++++++++++^************==========~~~~~~~~~~~~| * UsableFbSize ColorExpandBuffers | DRI-Heap | HWCursor TurboQueue 300/310/325 series * |--------------++++++++++++++++++++| ====================~~~~~~~~~~~~| * UsableFbSize ColorExpandBuffers | TurboQueue HWCursor 530/620 * topFB */ #ifdef SIS_USE_XAA if(!pSiS->useEXA) { topFB = pSiS->maxxfbmem; reservedFbSize = pSiS->ColorExpandBufferNumber * pSiS->PerColorExpandBufferSize; usableFbSize = topFB - reservedFbSize; AvailBufBase = pSiS->FbBase + usableFbSize; for(i = 0; i < pSiS->ColorExpandBufferNumber; i++) { pSiS->ColorExpandBufferAddr[i] = AvailBufBase + i * pSiS->PerColorExpandBufferSize; pSiS->ColorExpandBufferScreenOffset[i] = usableFbSize + i * pSiS->PerColorExpandBufferSize; } Avail.x1 = 0; Avail.y1 = 0; Avail.x2 = pScrn->displayWidth; Avail.y2 = (usableFbSize / (pScrn->displayWidth * pScrn->bitsPerPixel/8)) - 1; if(Avail.y2 < 0) Avail.y2 = 32767; if(Avail.y2 < pScrn->currentMode->VDisplay) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Not enough video RAM for accelerator. At least " "%dKB needed, %dKB available\n", ((((pScrn->displayWidth * pScrn->bitsPerPixel/8) /* +8 for make it sure */ * pScrn->currentMode->VDisplay) + reservedFbSize) / 1024) + 8, pSiS->maxxfbmem/1024); pSiS->NoAccel = TRUE; pSiS->NoXvideo = TRUE; XAADestroyInfoRec(pSiS->AccelInfoPtr); pSiS->AccelInfoPtr = NULL; return FALSE; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Framebuffer from (%d,%d) to (%d,%d)\n", Avail.x1, Avail.y1, Avail.x2 - 1, Avail.y2 - 1); xf86InitFBManager(pScreen, &Avail); if(!pSiS->NoAccel) { return XAAInit(pScreen, infoPtr); } } /* !exa */ #endif /* XAA */ #ifdef SIS_USE_EXA if(pSiS->useEXA) { if(!pSiS->NoAccel) { if(!exaDriverInit(pScreen, pSiS->EXADriverPtr)) { pSiS->NoAccel = TRUE; pSiS->NoXvideo = TRUE; /* No fbmem manager -> no xv */ return FALSE; } /* Reserve locked offscreen scratch area of 128K for glyph data */ pSiS->exa_scratch = exaOffscreenAlloc(pScreen, 128 * 1024, 16, TRUE, SiSScratchSave, pSiS); if(pSiS->exa_scratch) { pSiS->exa_scratch_next = pSiS->exa_scratch->offset; pSiS->EXADriverPtr->UploadToScratch = SiSUploadToScratch; } } else { pSiS->NoXvideo = TRUE; /* No fbmem manager -> no xv */ } } #endif /* EXA */ return TRUE; }