/* * Copyright (c) 2007 NVIDIA, Corporation * * 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: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include "g80_type.h" #include "g80_dma.h" #include "g80_xaa.h" static void G80Sync(ScrnInfoPtr pScrn) { G80Ptr pNv = G80PTR(pScrn); volatile CARD16 *pSync = (volatile CARD16*)&pNv->reg[0x00711008/4] + 1; G80DmaStart(pNv, 0x104, 1); G80DmaNext (pNv, 0); G80DmaStart(pNv, 0x100, 1); G80DmaNext (pNv, 0); *pSync = 0x8000; G80DmaKickoff(pNv); while(*pSync); } static void G80DMAKickoffCallback(ScrnInfoPtr pScrn) { G80Ptr pNv = G80PTR(pScrn); G80DmaKickoff(pNv); pNv->DMAKickoffCallback = NULL; } static void G80SetPattern(G80Ptr pNv, int bg, int fg, int pat0, int pat1) { G80DmaStart(pNv, 0x2f0, 4); G80DmaNext (pNv, bg); G80DmaNext (pNv, fg); G80DmaNext (pNv, pat0); G80DmaNext (pNv, pat1); } static void G80SetRopSolid(G80Ptr pNv, CARD32 rop, CARD32 planemask) { static const int rops[] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0 }; if(planemask != ~0) { G80SetPattern(pNv, 0, planemask, ~0, ~0); if(pNv->currentRop != (rop + 32)) { pNv->currentRop = rop + 32; rop = rops[rop] | 0xA; G80DmaStart(pNv, 0x2a0, 1); G80DmaNext (pNv, rop); } } else if(pNv->currentRop != rop) { if(pNv->currentRop >= 16) G80SetPattern(pNv, ~0, ~0, ~0, ~0); pNv->currentRop = rop; rop = rops[rop]; rop |= rop >> 4; G80DmaStart(pNv, 0x2a0, 1); G80DmaNext (pNv, rop); } } static void inline G80SetClip(G80Ptr pNv, int x, int y, int w, int h) { G80DmaStart(pNv, 0x280, 4); G80DmaNext (pNv, x); G80DmaNext (pNv, y); G80DmaNext (pNv, w); G80DmaNext (pNv, h); } /* Screen to screen copies */ static void G80SetupForScreenToScreenCopy( ScrnInfoPtr pScrn, int xdir, int ydir, int rop, unsigned planemask, int transparency_color ) { G80Ptr pNv = G80PTR(pScrn); planemask |= ~0 << pScrn->depth; G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff); G80DmaStart(pNv, 0x2ac, 1); if(rop == GXcopy && planemask == ~0) { G80DmaNext (pNv, 3); } else { G80DmaNext (pNv, 1); G80SetRopSolid(pNv, rop, planemask); } pNv->DMAKickoffCallback = G80DMAKickoffCallback; } static void G80SubsequentScreenToScreenCopy( ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2, int w, int h ) { G80Ptr pNv = G80PTR(pScrn); G80DmaStart(pNv, 0x110, 1); G80DmaNext (pNv, 0); G80DmaStart(pNv, 0x8b0, 12); G80DmaNext (pNv, x2); G80DmaNext (pNv, y2); G80DmaNext (pNv, w); G80DmaNext (pNv, h); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, x1); G80DmaNext (pNv, 0); G80DmaNext (pNv, y1); if(w * h >= 512) G80DmaKickoff(pNv); } /* Solid fills */ static void G80SetupForSolidFill( ScrnInfoPtr pScrn, int color, int rop, unsigned planemask ) { G80Ptr pNv = G80PTR(pScrn); planemask |= ~0 << pScrn->depth; G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff); G80DmaStart(pNv, 0x2ac, 1); G80DmaNext (pNv, 1); G80SetRopSolid(pNv, rop, planemask); G80DmaStart(pNv, 0x580, 1); G80DmaNext (pNv, 4); G80DmaStart(pNv, 0x588, 1); G80DmaNext (pNv, color); pNv->DMAKickoffCallback = G80DMAKickoffCallback; } static void G80SubsequentFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h) { G80Ptr pNv = G80PTR(pScrn); G80DmaStart(pNv, 0x600, 4); G80DmaNext (pNv, x); G80DmaNext (pNv, y); G80DmaNext (pNv, x + w); G80DmaNext (pNv, y + h); if(w * h >= 512) G80DmaKickoff(pNv); } /* 8x8 pattern fills */ static void G80SetupForMono8x8PatternFill( ScrnInfoPtr pScrn, int patternx, int patterny, int fg, int bg, int rop, unsigned planemask ) { G80Ptr pNv = G80PTR(pScrn); static const int rops[] = { 0x00, 0xA0, 0x50, 0xF0, 0x0A, 0xAA, 0x5A, 0xFA, 0x05, 0xA5, 0x55, 0xF5, 0x0F, 0xAF, 0x5F, 0xFF }; planemask = ~0 << pScrn->depth; fg |= planemask; if(bg == -1) bg = 0; else bg |= planemask; if(pNv->currentRop != (rop + 16)) { G80DmaStart(pNv, 0x2a0, 1); G80DmaNext (pNv, rops[rop]); pNv->currentRop = rop + 16; } G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff); G80SetPattern(pNv, bg, fg, patternx, patterny); G80DmaStart(pNv, 0x2ac, 1); G80DmaNext (pNv, 1); G80DmaStart(pNv, 0x580, 1); G80DmaNext (pNv, 4); G80DmaStart(pNv, 0x588, 1); G80DmaNext (pNv, fg); pNv->DMAKickoffCallback = G80DMAKickoffCallback; } static void G80SubsequentMono8x8PatternFillRect( ScrnInfoPtr pScrn, int patternx, int patterny, int x, int y, int w, int h ) { G80SubsequentFillRect(pScrn, x, y, w, h); } /* Color expansion fills */ static CARD32 _color_expand_dwords; static int _remaining; static unsigned char *_storage_buffer[1]; static void G80SetupForScanlineCPUToScreenColorExpandFill( ScrnInfoPtr pScrn, int fg, int bg, int rop, unsigned int planemask ) { G80Ptr pNv = G80PTR(pScrn); CARD32 mask = ~0 << pScrn->depth; planemask |= mask; G80DmaStart(pNv, 0x2ac, 1); G80DmaNext (pNv, 1); G80SetRopSolid(pNv, rop, planemask); G80DmaStart(pNv, 0x800, 1); G80DmaNext (pNv, 1); G80DmaStart(pNv, 0x808, 6); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, bg | mask); G80DmaNext (pNv, fg | mask); G80DmaNext (pNv, (bg == -1) ? 0 : 1); } static void G80SubsequentScanlineCPUToScreenColorExpandFill( ScrnInfoPtr pScrn, int x, int y, int w, int h, int skipleft ) { G80Ptr pNv = G80PTR(pScrn); int bw = (w + 31) & ~31; _color_expand_dwords = bw >> 5; _remaining = h; G80SetClip(pNv, x + skipleft, y, w - skipleft, h); G80DmaStart(pNv, 0x838, 10); G80DmaNext (pNv, bw); G80DmaNext (pNv, h); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, x); G80DmaNext (pNv, 0); G80DmaNext (pNv, y); G80DmaStart(pNv, 0x40000860, _color_expand_dwords); _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent]; } static void G80SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno) { G80Ptr pNv = G80PTR(pScrn); pNv->dmaCurrent += _color_expand_dwords; if(--_remaining) { G80DmaStart(pNv, 0x40000860, _color_expand_dwords); _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent]; } else { G80DmaKickoff(pNv); } } /* Scaline image write */ static void G80SetupForScanlineImageWrite( ScrnInfoPtr pScrn, int rop, unsigned int planemask, int trans_color, int bpp, int depth ) { G80Ptr pNv = G80PTR(pScrn); planemask |= ~0 << pScrn->depth; G80DmaStart(pNv, 0x2ac, 1); if(rop == GXcopy && planemask == ~0) { G80DmaNext (pNv, 3); } else { G80DmaNext (pNv, 1); G80SetRopSolid(pNv, rop, planemask); } G80DmaStart(pNv, 0x800, 1); G80DmaNext (pNv, 0); } static CARD32 _image_dwords; static void G80SubsequentScanlineImageWriteRect( ScrnInfoPtr pScrn, int x, int y, int w, int h, int skipleft ) { G80Ptr pNv = G80PTR(pScrn); int Bpp = pScrn->bitsPerPixel >> 3; _remaining = h; _image_dwords = (w * Bpp + 3) / 4; G80SetClip(pNv, x + skipleft, y, w - skipleft, h); G80DmaStart(pNv, 0x838, 10); G80DmaNext (pNv, w); G80DmaNext (pNv, h); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, 1); G80DmaNext (pNv, 0); G80DmaNext (pNv, x); G80DmaNext (pNv, 0); G80DmaNext (pNv, y); G80DmaStart(pNv, 0x40000860, _image_dwords); _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent]; } static void G80SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno) { G80Ptr pNv = G80PTR(pScrn); pNv->dmaCurrent += _image_dwords; if(--_remaining) { G80DmaStart(pNv, 0x40000860, _image_dwords); _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent]; } else { G80DmaKickoff(pNv); } } /* Solid lines */ static void G80SetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop, unsigned planemask) { G80Ptr pNv = G80PTR(pScrn); planemask |= ~0 << pScrn->depth; G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff); G80DmaStart(pNv, 0x2ac, 1); G80DmaNext (pNv, 1); G80SetRopSolid(pNv, rop, planemask); G80DmaStart(pNv, 0x580, 1); G80DmaNext (pNv, 1); G80DmaStart(pNv, 0x588, 1); G80DmaNext (pNv, color); pNv->DMAKickoffCallback = G80DMAKickoffCallback; } static void G80SubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len, int dir) { G80Ptr pNv = G80PTR(pScrn); G80DmaStart(pNv, 0x400005e0, 2); G80DmaNext (pNv, (y << 16) | (x & 0xffff)); if(dir == DEGREES_0) { G80DmaNext (pNv, (y << 16) | ((x + len) & 0xffff)); } else { G80DmaNext (pNv, ((y + len) << 16) | (x & 0xffff)); } } static void G80SubsequentSolidTwoPointLine( ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2, int flags ) { G80Ptr pNv = G80PTR(pScrn); Bool drawLast = !(flags & OMIT_LAST); G80DmaStart(pNv, 0x400005e0, drawLast ? 4 : 2); G80DmaNext (pNv, (y1 << 16) | (x1 & 0xffff)); G80DmaNext (pNv, (y2 << 16) | (x2 & 0xffff)); if(drawLast) { G80DmaNext (pNv, (y2 << 16) | (x2 & 0xffff)); G80DmaNext (pNv, ((y2 + 1) << 16) | (x2 & 0xffff)); } } static void G80SetClippingRectangle(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2) { G80Ptr pNv = G80PTR(pScrn); int h = y2 - y1 + 1; int w = x2 - x1 + 1; G80SetClip(pNv, x1, y1, w, h); } static void G80DisableClipping(ScrnInfoPtr pScrn) { G80Ptr pNv = G80PTR(pScrn); G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff); } Bool G80XAAInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; G80Ptr pNv = G80PTR(pScrn); XAAInfoRecPtr xaa; xaa = pNv->xaa = XAACreateInfoRec(); if(!xaa) return FALSE; xaa->Flags = LINEAR_FRAMEBUFFER | PIXMAP_CACHE | OFFSCREEN_PIXMAPS; xaa->Sync = G80Sync; /* Screen to screen copies */ xaa->ScreenToScreenCopyFlags = NO_TRANSPARENCY; xaa->SetupForScreenToScreenCopy = G80SetupForScreenToScreenCopy; xaa->SubsequentScreenToScreenCopy = G80SubsequentScreenToScreenCopy; /* Solid fills */ xaa->SolidFillFlags = 0; xaa->SetupForSolidFill = G80SetupForSolidFill; xaa->SubsequentSolidFillRect = G80SubsequentFillRect; /* 8x8 pattern fills */ xaa->Mono8x8PatternFillFlags = HARDWARE_PATTERN_SCREEN_ORIGIN | HARDWARE_PATTERN_PROGRAMMED_BITS | NO_PLANEMASK; xaa->SetupForMono8x8PatternFill = G80SetupForMono8x8PatternFill; xaa->SubsequentMono8x8PatternFillRect = G80SubsequentMono8x8PatternFillRect; /* Color expansion fills */ xaa->ScanlineCPUToScreenColorExpandFillFlags = BIT_ORDER_IN_BYTE_LSBFIRST | CPU_TRANSFER_PAD_DWORD | LEFT_EDGE_CLIPPING | LEFT_EDGE_CLIPPING_NEGATIVE_X; xaa->NumScanlineColorExpandBuffers = 1; xaa->SetupForScanlineCPUToScreenColorExpandFill = G80SetupForScanlineCPUToScreenColorExpandFill; xaa->SubsequentScanlineCPUToScreenColorExpandFill = G80SubsequentScanlineCPUToScreenColorExpandFill; xaa->SubsequentColorExpandScanline = G80SubsequentColorExpandScanline; xaa->ScanlineColorExpandBuffers = _storage_buffer; /* Scaline image write */ xaa->ScanlineImageWriteFlags = NO_GXCOPY | NO_TRANSPARENCY | LEFT_EDGE_CLIPPING | LEFT_EDGE_CLIPPING_NEGATIVE_X; xaa->NumScanlineImageWriteBuffers = 1; xaa->SetupForScanlineImageWrite = G80SetupForScanlineImageWrite; xaa->SubsequentScanlineImageWriteRect = G80SubsequentScanlineImageWriteRect; xaa->SubsequentImageWriteScanline = G80SubsequentImageWriteScanline; xaa->ScanlineImageWriteBuffers = _storage_buffer; /* Solid lines */ xaa->SolidLineFlags = 0; xaa->SetupForSolidLine = G80SetupForSolidLine; xaa->SubsequentSolidHorVertLine = G80SubsequentSolidHorVertLine; xaa->SubsequentSolidTwoPointLine = G80SubsequentSolidTwoPointLine; xaa->SetClippingRectangle = G80SetClippingRectangle; xaa->DisableClipping = G80DisableClipping; xaa->ClippingFlags = HARDWARE_CLIP_SOLID_LINE; miSetZeroLineBias(pScreen, OCTANT1 | OCTANT3 | OCTANT4 | OCTANT6); return XAAInit(pScreen, xaa); }