aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/kdrive/ati/ati_cursor.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/kdrive/ati/ati_cursor.c')
-rw-r--r--xorg-server/hw/kdrive/ati/ati_cursor.c559
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;
+}