summaryrefslogtreecommitdiff
path: root/src/g80_xaa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/g80_xaa.c')
-rw-r--r--src/g80_xaa.c554
1 files changed, 554 insertions, 0 deletions
diff --git a/src/g80_xaa.c b/src/g80_xaa.c
new file mode 100644
index 0000000..1f07444
--- /dev/null
+++ b/src/g80_xaa.c
@@ -0,0 +1,554 @@
+/*
+ * 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 <miline.h>
+
+#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);
+}