xenocara/driver/xf86-video-nv/src/g80_xaa.c

559 lines
14 KiB
C

/*
* 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"
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);
}
void
G80DMAKickoffCallback(ScrnInfoPtr pScrn)
{
G80Ptr pNv = G80PTR(pScrn);
G80DmaKickoff(pNv);
pNv->DMAKickoffCallback = NULL;
}
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);
}
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);
}
}
inline void
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);
}
#ifdef HAVE_XAA_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, 4);
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, 4);
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, 4);
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, 4);
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, 4);
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);
}
#endif
Bool
G80XAAInit(ScreenPtr pScreen)
{
#ifdef HAVE_XAA_H
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
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);
#else
return FALSE;
#endif
}