diff options
Diffstat (limited to 'xorg-server/hw/kdrive/ati/ati_cursor.c')
-rw-r--r-- | xorg-server/hw/kdrive/ati/ati_cursor.c | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/xorg-server/hw/kdrive/ati/ati_cursor.c b/xorg-server/hw/kdrive/ati/ati_cursor.c new file mode 100644 index 000000000..d2ce686df --- /dev/null +++ b/xorg-server/hw/kdrive/ati/ati_cursor.c @@ -0,0 +1,559 @@ +/* + * Copyright © 2004 Eric Anholt + * + * 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 Eric Anholt not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Eric Anholt makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL ERIC ANHOLT 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. + */ + +#ifdef HAVE_CONFIG_H +#include <kdrive-config.h> +#endif +#include "ati.h" +#include "ati_reg.h" +#include "cursorstr.h" +#include "ati_draw.h" + +static void +ATIMoveCursor(ScreenPtr pScreen, int x, int y) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + CARD16 xoff, yoff; + char *mmio = atic->reg_base; + int stride = atic->is_radeon ? 256 : 16; + + if (!pCurPriv->has_cursor) + return; + + if (!pScreenPriv->enabled) + return; + + x -= pCurPriv->xhot; + xoff = 0; + if (x < 0) { + xoff = -x; + x = 0; + } + y -= pCurPriv->yhot; + yoff = 0; + if (y < 0) { + yoff = -y; + y = 0; + } + + MMIO_OUT32(mmio, ATI_REG_CUR_HORZ_VERT_OFF, ATI_CUR_LOCK | + (xoff << 16) | yoff); + MMIO_OUT32(mmio, ATI_REG_CUR_HORZ_VERT_POSN, ATI_CUR_LOCK | + (x << 16) | y); + MMIO_OUT32(mmio, ATI_REG_CUR_OFFSET, (pCurPriv->area->offset + yoff * + stride)); +} + +static void +ClassicAllocCursorColors(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + CursorPtr pCursor = pCurPriv->pCursor; + + KdAllocateCursorPixels(pScreen, 0, pCursor, &pCurPriv->source, + &pCurPriv->mask); + switch (pScreenPriv->screen->fb[0].bitsPerPixel) { + case 4: + pCurPriv->source |= pCurPriv->source << 4; + pCurPriv->mask |= pCurPriv->mask << 4; + /* FALLTHROUGH */ + case 8: + pCurPriv->source |= pCurPriv->source << 8; + pCurPriv->mask |= pCurPriv->mask << 8; + /* FALLTHROUGH */ + case 16: + pCurPriv->source |= pCurPriv->source << 16; + pCurPriv->mask |= pCurPriv->mask << 16; + } +} + +static void +ClassicSetCursorColors(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + char *mmio = atic->reg_base; + + MMIO_OUT32(mmio, ATI_REG_CUR_CLR0, pCurPriv->mask); + MMIO_OUT32(mmio, ATI_REG_CUR_CLR1, pCurPriv->source); +} + +static void +ClassicRecolorCursor(ScreenPtr pScreen, int ndef, xColorItem *pdef) +{ + KdScreenPriv(pScreen); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + CursorPtr pCursor = pCurPriv->pCursor; + + if (!pCurPriv->has_cursor || !pCursor) + return; + + if (!pScreenPriv->enabled) + return; + + if (pdef) { + while (ndef != 0) { + if (pdef->pixel == pCurPriv->source || + pdef->pixel == pCurPriv->mask) + break; + ndef--; + } + + if (ndef == 0) + return; + } + ClassicAllocCursorColors(pScreen); + ClassicSetCursorColors(pScreen); +} + +#define InvertBits32(v) do { \ + v = ((v & 0x55555555) << 1) | ((v >> 1) & 0x55555555); \ + v = ((v & 0x33333333) << 2) | ((v >> 2) & 0x33333333); \ + v = ((v & 0x0f0f0f0f) << 4) | ((v >> 4) & 0x0f0f0f0f); \ +} while (0) + +static void +ClassicLoadCursor(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + CursorPtr pCursor = pCurPriv->pCursor; + CursorBitsPtr bits = pCursor->bits; + int h; + CARD32 *ram, *msk, *mskLine, *src, *srcLine; + int i; + int lwsrc; + CARD32 tmp; + char *mmio = atic->reg_base; + + ClassicAllocCursorColors(pScreen); + + pCurPriv->pCursor = pCursor; + pCurPriv->xhot = pCursor->bits->xhot; + pCurPriv->yhot = pCursor->bits->yhot; + + /* Stick new image into cursor memory */ + ram = (CARD32 *)(pScreenPriv->screen->memory_base + + pCurPriv->area->offset); + mskLine = (CARD32 *)bits->mask; + srcLine = (CARD32 *)bits->source; + + h = bits->height; + if (h > ATI_CURSOR_HEIGHT) + h = ATI_CURSOR_HEIGHT; + + lwsrc = BitmapBytePad(bits->width) / 4; /* words per line */ + + tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); + MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp & ~ATI_CRTC_CUR_EN); + + for (i = 0; i < ATI_CURSOR_HEIGHT; i++) { + CARD32 m1, m2, s1, s2; + + msk = mskLine; + src = srcLine; + mskLine += lwsrc; + srcLine += lwsrc; + + if (i < h && 0 < lwsrc) { + m1 = ~*msk++; + s1 = *src++; + InvertBits32(m1); + InvertBits32(s1); + } else { + m1 = 0xffffffff; + s1 = 0x0; + } + if (i < h && 1 < lwsrc) { + m2 = ~*msk++; + s2 = *src++; + InvertBits32(m2); + InvertBits32(s2); + } else { + m2 = 0xffffffff; + s2 = 0x0; + } + + *ram++ = m1; + *ram++ = m2; + *ram++ = s1; + *ram++ = s2; + } + + /* Not sure why this is necessary, but it prevents some cursor + * corruption. Not even all of it. + */ + for (i = 0; i < ATI_CURSOR_HEIGHT; i++) { + *ram++ = 0xffffffff; + *ram++ = 0xffffffff; + *ram++ = 0x0; + *ram++ = 0x0; + } + + /* Enable the cursor */ + tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); + MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp | ATI_CRTC_CUR_EN); + + /* Set new color */ + ClassicSetCursorColors(pScreen); + +} + +static void +RadeonLoadCursor(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + CursorPtr pCursor = pCurPriv->pCursor; + CursorBitsPtr bits = pCursor->bits; + int h, w; + int x, y; + CARD32 *ram, *msk, *mskLine, *src, *srcLine; + int lwsrc; + CARD32 tmp; + char *mmio = atic->reg_base; + + pCurPriv->pCursor = pCursor; + pCurPriv->xhot = pCursor->bits->xhot; + pCurPriv->yhot = pCursor->bits->yhot; + + w = bits->width; + if (w > ATI_CURSOR_WIDTH) + w = ATI_CURSOR_WIDTH; + + h = bits->height; + if (h > ATI_CURSOR_HEIGHT) + h = ATI_CURSOR_HEIGHT; + + tmp = MMIO_IN32(mmio, 0x7c); + tmp = 0x00010f80; + MMIO_OUT32 (mmio, 0x7c, tmp); + + tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); + tmp &= ~(ATI_CRTC_CUR_EN | ATI_CRTC_ICON_EN | ATI_CRTC_ARGB_EN); + MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp); + + /* Stick new image into cursor memory */ + ram = (CARD32 *)(pScreenPriv->screen->memory_base + + pCurPriv->area->offset); + if (pCursor->bits->argb) + { + srcLine = pCursor->bits->argb; + for (y = 0; y < h; y++) + { + src = srcLine; + srcLine += pCursor->bits->width; + for (x = 0; x < w; x++) + *ram++ = *src++; + for (; x < ATI_CURSOR_WIDTH; x++) + *ram++ = 0; + } + for (; y < ATI_CURSOR_HEIGHT; y++) + for (x = 0; x < ATI_CURSOR_WIDTH; x++) + *ram++ = 0; + } + else + { + CARD32 colors[4]; + + colors[0] = 0; + colors[1] = 0; + colors[2] = (((pCursor->backRed >> 8) << 16) | + ((pCursor->backGreen >> 8) << 8) | + ((pCursor->backBlue >> 8) << 0) | + 0xff000000); + colors[3] = (((pCursor->foreRed >> 8) << 16) | + ((pCursor->foreGreen >> 8) << 8) | + ((pCursor->foreBlue >> 8) << 0) | + 0xff000000); + + mskLine = (CARD32 *)bits->mask; + srcLine = (CARD32 *)bits->source; + + /* words per line */ + lwsrc = BitmapBytePad(bits->width) / 4; + + for (y = 0; y < ATI_CURSOR_HEIGHT; y++) + { + CARD32 m, s; + + msk = mskLine; + src = srcLine; + mskLine += lwsrc; + srcLine += lwsrc; + + for (x = 0; x < ATI_CURSOR_WIDTH / 32; x++) + { + int k; + if (y < h && x < lwsrc) + { + m = *msk++; + s = *src++; + } + else + { + m = 0x0; + s = 0x0; + } + + for (k = 0; k < 32; k++) + { + CARD32 bits = (s & 1) | ((m & 1) << 1); + *ram++ = colors[bits]; + s >>= 1; + m >>= 1; + } + } + } + } + + /* Enable the cursor */ + tmp &= ~(ATI_CRTC_ICON_EN); + tmp |= ATI_CRTC_ARGB_EN; + tmp |= ATI_CRTC_CUR_EN; + MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp); +} + +static void +ATIUnloadCursor(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + char *mmio = atic->reg_base; + CARD32 tmp; + + tmp = MMIO_IN32(mmio, ATI_REG_GEN_CNTL); + tmp &= ~(ATI_CRTC_CUR_EN | ATI_CRTC_ICON_EN | ATI_CRTC_ARGB_EN); + MMIO_OUT32(mmio, ATI_REG_GEN_CNTL, tmp); +} + +static Bool +ATIRealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + if (!pScreenPriv->enabled) + return TRUE; + + /* miRecolorCursor does this */ + if (pCursor && pCurPriv->pCursor == pCursor) + { + int x, y; + + miPointerPosition(&x, &y); + if (atic->is_radeon) + RadeonLoadCursor (pScreen); + else + ClassicLoadCursor(pScreen); + /* Move to new position */ + ATIMoveCursor(pScreen, x, y); + } + + return TRUE; +} + +static Bool +ATIUnrealizeCursor(ScreenPtr pScreen, CursorPtr pCursor) +{ + return TRUE; +} + +static void +ATISetCursor(ScreenPtr pScreen, CursorPtr pCursor, int x, int y) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + pCurPriv->pCursor = pCursor; + + if (!pScreenPriv->enabled) + return; + + if (pCursor) + { + if (atic->is_radeon) + RadeonLoadCursor (pScreen); + else + ClassicLoadCursor(pScreen); + /* Move to new position */ + ATIMoveCursor(pScreen, x, y); + } + else + ATIUnloadCursor(pScreen); +} + +miPointerSpriteFuncRec ATIPointerSpriteFuncs = { + ATIRealizeCursor, + ATIUnrealizeCursor, + ATISetCursor, + ATIMoveCursor, +}; + +static void +ATIQueryBestSize(int class, unsigned short *pwidth, unsigned short *pheight, + ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + switch (class) + { + case CursorShape: + if (*pwidth > pCurPriv->width) + *pwidth = pCurPriv->width; + if (*pheight > pCurPriv->height) + *pheight = pCurPriv->height; + if (*pwidth > pScreen->width) + *pwidth = pScreen->width; + if (*pheight > pScreen->height) + *pheight = pScreen->height; + break; + default: + fbQueryBestSize(class, pwidth, pheight, pScreen); + break; + } +} + +static void +ATICursorSave(ScreenPtr pScreen, KdOffscreenArea *area) +{ + KdScreenPriv(pScreen); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + pCurPriv->area = NULL; +} + +void +ATICursorEnable(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + if (!pCurPriv->has_cursor) + return; + + if (pCurPriv->area == NULL) { + if (atic->is_radeon) + pCurPriv->area = KdOffscreenAlloc(pScreen, + ATI_CURSOR_HEIGHT * ATI_CURSOR_WIDTH * 4, + 128, TRUE, ATICursorSave, atis); + else + pCurPriv->area = KdOffscreenAlloc(pScreen, + ATI_CURSOR_HEIGHT * ATI_CURSOR_PITCH * 2, + 32, TRUE, ATICursorSave, atis); + } + if (pCurPriv->area == NULL) + FatalError("Couldn't allocate offscreen memory for cursor.\n"); + + if (pCurPriv->pCursor) { + int x, y; + + miPointerPosition(&x, &y); + if (atic->is_radeon) + RadeonLoadCursor(pScreen); + else + ClassicLoadCursor(pScreen); + /* Move to new position */ + ATIMoveCursor(pScreen, x, y); + } + else + ATIUnloadCursor(pScreen); +} + +void +ATICursorDisable(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + if (!pScreenPriv->enabled || !pCurPriv->has_cursor) + return; + + if (pCurPriv->pCursor) + ATIUnloadCursor(pScreen); +} + +Bool +ATICursorInit(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + pCurPriv->has_cursor = FALSE; + + if (atic->reg_base == NULL) + return FALSE; + + pCurPriv->width = ATI_CURSOR_WIDTH; + pCurPriv->height= ATI_CURSOR_HEIGHT; + pScreen->QueryBestSize = ATIQueryBestSize; + miPointerInitialize(pScreen, &ATIPointerSpriteFuncs, + &kdPointerScreenFuncs, FALSE); + pCurPriv->has_cursor = TRUE; + pCurPriv->pCursor = NULL; + return TRUE; +} + +void +ATIRecolorCursor (ScreenPtr pScreen, int ndef, xColorItem *pdef) +{ + KdScreenPriv(pScreen); + ATICardInfo(pScreenPriv); + + if (!atic->is_radeon) + ClassicRecolorCursor (pScreen, ndef, pdef); +} + +void +ATICursorFini(ScreenPtr pScreen) +{ + KdScreenPriv(pScreen); + ATIScreenInfo(pScreenPriv); + ATICursor *pCurPriv = &atis->cursor; + + pCurPriv->has_cursor = FALSE; + pCurPriv->pCursor = NULL; +} |