xenocara/xserver/hw/kdrive/ati/ati_cursor.c

561 lines
12 KiB
C
Raw Normal View History

2006-11-26 11:13:41 -07:00
/*
* Copyright <EFBFBD> 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.
*/
/* $RCSId$ */
#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;
}