1
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_cursor.c,v 1.23 2003/02/24 20:34:55 tsi Exp $ */
3
* Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
4
* VA Linux Systems Inc., Fremont, California.
8
* Permission is hereby granted, free of charge, to any person obtaining
9
* a copy of this software and associated documentation files (the
10
* "Software"), to deal in the Software without restriction, including
11
* without limitation on the rights to use, copy, modify, merge,
12
* publish, distribute, sublicense, and/or sell copies of the Software,
13
* and to permit persons to whom the Software is furnished to do so,
14
* subject to the following conditions:
16
* The above copyright notice and this permission notice (including the
17
* next paragraph) shall be included in all copies or substantial
18
* portions of the Software.
20
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
* NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
24
* THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
* DEALINGS IN THE SOFTWARE.
32
* Kevin E. Martin <martin@xfree86.org>
33
* Rickard E. Faith <faith@valinux.com>
38
* RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
39
* Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
42
* RAGE 128 Software Development Manual (Technical Reference Manual P/N
43
* SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
47
/* Driver data structures */
49
#include "radeon_macros.h"
50
#include "radeon_reg.h"
52
/* X and server generic header files */
55
/* Mono ARGB cursor colours (premultiplied). */
56
static CARD32 mono_cursor_color[] = {
57
0x00000000, /* White, fully transparent. */
58
0x00000000, /* Black, fully transparent. */
59
0xffffffff, /* White, fully opaque. */
60
0xff000000, /* Black, fully opaque. */
63
#define CURSOR_WIDTH 64
64
#define CURSOR_HEIGHT 64
67
* The cursor bits are always 32bpp. On MSBFirst busses,
68
* configure byte swapping to swap 32 bit units when writing
69
* the cursor image. Byte swapping must always be returned
70
* to its previous value before returning.
72
#if X_BYTE_ORDER == X_BIG_ENDIAN
74
#define CURSOR_SWAPPING_DECL_MMIO unsigned char *RADEONMMIO = info->MMIO;
75
#define CURSOR_SWAPPING_DECL CARD32 __surface_cntl;
76
#define CURSOR_SWAPPING_START() \
77
OUTREG(RADEON_SURFACE_CNTL, \
78
((__surface_cntl = INREG(RADEON_SURFACE_CNTL)) | \
79
RADEON_NONSURF_AP0_SWP_32BPP) & \
80
~RADEON_NONSURF_AP0_SWP_16BPP)
81
#define CURSOR_SWAPPING_END() (OUTREG(RADEON_SURFACE_CNTL, __surface_cntl))
85
#define CURSOR_SWAPPING_DECL_MMIO
86
#define CURSOR_SWAPPING_DECL
87
#define CURSOR_SWAPPING_START()
88
#define CURSOR_SWAPPING_END()
92
/* Set cursor foreground and background colors */
93
static void RADEONSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
95
RADEONInfoPtr info = RADEONPTR(pScrn);
96
CARD32 *pixels = (CARD32 *)(pointer)(info->FB + info->cursor_start);
98
CURSOR_SWAPPING_DECL_MMIO
102
/* Don't recolour cursors set with SetCursorARGB. */
103
if (info->cursor_argb)
110
/* Don't recolour the image if we don't have to. */
111
if (fg == info->cursor_fg && bg == info->cursor_bg)
114
CURSOR_SWAPPING_START();
116
/* Note: We assume that the pixels are either fully opaque or fully
117
* transparent, so we won't premultiply them, and we can just
118
* check for non-zero pixel values; those are either fg or bg
120
for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT; i++, pixels++)
121
if ((pixel = *pixels))
122
*pixels = (pixel == info->cursor_fg) ? fg : bg;
124
CURSOR_SWAPPING_END();
125
info->cursor_fg = fg;
126
info->cursor_bg = bg;
130
/* Set cursor position to (x,y) with offset into cursor bitmap at
133
static void RADEONSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
135
RADEONInfoPtr info = RADEONPTR(pScrn);
136
unsigned char *RADEONMMIO = info->MMIO;
137
xf86CursorInfoPtr cursor = info->cursor;
140
int total_y = pScrn->frameY1 - pScrn->frameY0;
141
int X2 = pScrn->frameX0 + x;
142
int Y2 = pScrn->frameY0 + y;
145
if (x < 0) xorigin = -x+1;
146
if (y < 0) yorigin = -y+1;
147
if (y > total_y) y = total_y;
148
if (info->Flags & V_DBLSCAN) y *= 2;
149
if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1;
150
if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
156
if ((info->CurCloneMode->VDisplay == pScrn->currentMode->VDisplay) &&
157
(info->CurCloneMode->HDisplay == pScrn->currentMode->HDisplay)) {
169
if (Y2 >= info->CurCloneMode->VDisplay + info->CloneFrameY0) {
170
Y0 = Y2 - info->CurCloneMode->VDisplay;
171
Y2 = info->CurCloneMode->VDisplay - 1;
172
} else if (Y2 < info->CloneFrameY0) {
176
Y2 -= info->CloneFrameY0;
177
Y0 = info->CloneFrameY0;
180
if (X2 >= info->CurCloneMode->HDisplay + info->CloneFrameX0) {
181
X0 = X2 - info->CurCloneMode->HDisplay;
182
X2 = info->CurCloneMode->HDisplay - 1;
183
} else if (X2 < info->CloneFrameX0) {
187
X2 -= info->CloneFrameX0;
188
X0 = info->CloneFrameX0;
191
if (info->CurCloneMode->Flags & V_DBLSCAN)
195
if ((X0 >= 0 || Y0 >= 0) &&
196
((info->CloneFrameX0 != X0) || (info->CloneFrameY0 != Y0))) {
197
RADEONDoAdjustFrame(pScrn, X0, Y0, TRUE);
198
info->CloneFrameX0 = X0;
199
info->CloneFrameY0 = Y0;
203
if (!info->IsSecondary) {
204
OUTREG(RADEON_CUR_HORZ_VERT_OFF, (RADEON_CUR_LOCK
207
OUTREG(RADEON_CUR_HORZ_VERT_POSN, (RADEON_CUR_LOCK
208
| ((xorigin ? 0 : x) << 16)
209
| (yorigin ? 0 : y)));
210
OUTREG(RADEON_CUR_OFFSET, info->cursor_start + yorigin * stride);
212
OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK
215
OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK
216
| ((xorigin ? 0 : x) << 16)
217
| (yorigin ? 0 : y)));
218
OUTREG(RADEON_CUR2_OFFSET,
219
info->cursor_start + pScrn->fbOffset + yorigin * stride);
225
if (X2 < 0) xorigin = -X2 + 1;
226
if (Y2 < 0) yorigin = -Y2 + 1;
227
if (xorigin >= cursor->MaxWidth) xorigin = cursor->MaxWidth - 1;
228
if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
230
OUTREG(RADEON_CUR2_HORZ_VERT_OFF, (RADEON_CUR2_LOCK
233
OUTREG(RADEON_CUR2_HORZ_VERT_POSN, (RADEON_CUR2_LOCK
234
| ((xorigin ? 0 : X2) << 16)
235
| (yorigin ? 0 : Y2)));
236
OUTREG(RADEON_CUR2_OFFSET,
237
info->cursor_start + pScrn->fbOffset + yorigin * stride);
241
/* Copy cursor image from `image' to video memory. RADEONSetCursorPosition
242
* will be called after this, so we can ignore xorigin and yorigin.
244
static void RADEONLoadCursorImage(ScrnInfoPtr pScrn, unsigned char *image)
246
RADEONInfoPtr info = RADEONPTR(pScrn);
247
unsigned char *RADEONMMIO = info->MMIO;
248
CARD8 *s = (CARD8 *)(pointer)image;
249
CARD32 *d = (CARD32 *)(pointer)(info->FB + info->cursor_start);
256
if (!info->IsSecondary) {
257
save1 = INREG(RADEON_CRTC_GEN_CNTL) & ~(CARD32) (3 << 20);
258
save1 |= (CARD32) (2 << 20);
259
OUTREG(RADEON_CRTC_GEN_CNTL, save1 & (CARD32)~RADEON_CRTC_CUR_EN);
262
if (info->IsSecondary || info->Clone) {
263
save2 = INREG(RADEON_CRTC2_GEN_CNTL) & ~(CARD32) (3 << 20);
264
save2 |= (CARD32) (2 << 20);
265
OUTREG(RADEON_CRTC2_GEN_CNTL, save2 & (CARD32)~RADEON_CRTC2_CUR_EN);
269
info->cursor_argb = FALSE;
273
* Convert the bitmap to ARGB32.
275
* HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 always places
276
* source in the low bit of the pair and mask in the high bit,
277
* and MSBFirst machines set HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
278
* (which actually bit swaps the image) to make the bits LSBFirst
280
CURSOR_SWAPPING_START();
281
#define ARGB_PER_CHUNK (8 * sizeof (chunk) / 2)
282
for (i = 0; i < CURSOR_WIDTH * CURSOR_HEIGHT / ARGB_PER_CHUNK; i++) {
284
for (j = 0; j < ARGB_PER_CHUNK; j++, chunk >>= 2)
285
*d++ = mono_cursor_color[chunk & 3];
287
CURSOR_SWAPPING_END();
289
info->cursor_bg = mono_cursor_color[2];
290
info->cursor_fg = mono_cursor_color[3];
292
if (!info->IsSecondary)
293
OUTREG(RADEON_CRTC_GEN_CNTL, save1);
295
if (info->IsSecondary || info->Clone)
296
OUTREG(RADEON_CRTC2_GEN_CNTL, save2);
300
/* Hide hardware cursor. */
301
static void RADEONHideCursor(ScrnInfoPtr pScrn)
303
RADEONInfoPtr info = RADEONPTR(pScrn);
304
unsigned char *RADEONMMIO = info->MMIO;
306
if (info->IsSecondary || info->Clone)
307
OUTREGP(RADEON_CRTC2_GEN_CNTL, 0, ~RADEON_CRTC2_CUR_EN);
309
if (!info->IsSecondary)
310
OUTREGP(RADEON_CRTC_GEN_CNTL, 0, ~RADEON_CRTC_CUR_EN);
313
/* Show hardware cursor. */
314
static void RADEONShowCursor(ScrnInfoPtr pScrn)
316
RADEONInfoPtr info = RADEONPTR(pScrn);
317
unsigned char *RADEONMMIO = info->MMIO;
319
if (info->IsSecondary || info->Clone)
320
OUTREGP(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_CUR_EN,
321
~RADEON_CRTC2_CUR_EN);
323
if (!info->IsSecondary)
324
OUTREGP(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_CUR_EN,
325
~RADEON_CRTC_CUR_EN);
328
/* Determine if hardware cursor is in use. */
329
static Bool RADEONUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
331
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
332
RADEONInfoPtr info = RADEONPTR(pScrn);
334
return info->cursor_start ? TRUE : FALSE;
338
#include "cursorstr.h"
340
static Bool RADEONUseHWCursorARGB (ScreenPtr pScreen, CursorPtr pCurs)
342
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
343
RADEONInfoPtr info = RADEONPTR(pScrn);
345
if (info->cursor_start &&
346
pCurs->bits->height <= CURSOR_HEIGHT && pCurs->bits->width <= CURSOR_WIDTH)
351
static void RADEONLoadCursorARGB (ScrnInfoPtr pScrn, CursorPtr pCurs)
353
RADEONInfoPtr info = RADEONPTR(pScrn);
354
unsigned char *RADEONMMIO = info->MMIO;
355
CARD32 *d = (CARD32 *)(pointer)(info->FB + info->cursor_start);
359
CARD32 *image = pCurs->bits->argb;
364
return; /* XXX can't happen */
366
if (!info->IsSecondary) {
367
save1 = INREG(RADEON_CRTC_GEN_CNTL) & ~(CARD32) (3 << 20);
368
save1 |= (CARD32) (2 << 20);
369
OUTREG(RADEON_CRTC_GEN_CNTL, save1 & (CARD32)~RADEON_CRTC_CUR_EN);
372
if (info->IsSecondary || info->Clone) {
373
save2 = INREG(RADEON_CRTC_GEN_CNTL) & ~(CARD32) (3 << 20);
374
save2 |= (CARD32) (2 << 20);
375
OUTREG(RADEON_CRTC2_GEN_CNTL, save2 & (CARD32)~RADEON_CRTC2_CUR_EN);
379
info->cursor_argb = TRUE;
382
CURSOR_SWAPPING_START();
384
w = pCurs->bits->width;
385
if (w > CURSOR_WIDTH)
387
h = pCurs->bits->height;
388
if (h > CURSOR_HEIGHT)
390
for (y = 0; y < h; y++)
393
image += pCurs->bits->width;
394
for (x = 0; x < w; x++)
396
/* pad to the right with transparent */
397
for (; x < CURSOR_WIDTH; x++)
400
/* pad below with transparent */
401
for (; y < CURSOR_HEIGHT; y++)
402
for (x = 0; x < CURSOR_WIDTH; x++)
405
CURSOR_SWAPPING_END ();
407
if (!info->IsSecondary)
408
OUTREG(RADEON_CRTC_GEN_CNTL, save1);
410
if (info->IsSecondary || info->Clone)
411
OUTREG(RADEON_CRTC2_GEN_CNTL, save2);
418
/* Initialize hardware cursor support. */
419
Bool RADEONCursorInit(ScreenPtr pScreen)
421
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
422
RADEONInfoPtr info = RADEONPTR(pScrn);
423
xf86CursorInfoPtr cursor;
430
if (!(cursor = info->cursor = xf86CreateCursorInfoRec())) return FALSE;
432
cursor->MaxWidth = CURSOR_WIDTH;
433
cursor->MaxHeight = CURSOR_HEIGHT;
434
cursor->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP
435
| HARDWARE_CURSOR_AND_SOURCE_WITH_MASK
436
#if X_BYTE_ORDER == X_BIG_ENDIAN
438
* HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
439
* actually inverts the bit order, so
440
* this switches to LSBFIRST
442
| HARDWARE_CURSOR_BIT_ORDER_MSBFIRST
444
| HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1);
446
cursor->SetCursorColors = RADEONSetCursorColors;
447
cursor->SetCursorPosition = RADEONSetCursorPosition;
448
cursor->LoadCursorImage = RADEONLoadCursorImage;
449
cursor->HideCursor = RADEONHideCursor;
450
cursor->ShowCursor = RADEONShowCursor;
451
cursor->UseHWCursor = RADEONUseHWCursor;
454
cursor->UseHWCursorARGB = RADEONUseHWCursorARGB;
455
cursor->LoadCursorARGB = RADEONLoadCursorARGB;
457
size_bytes = CURSOR_WIDTH * 4 * CURSOR_HEIGHT;
458
width = pScrn->displayWidth;
459
width_bytes = width * (pScrn->bitsPerPixel / 8);
460
height = (size_bytes + width_bytes - 1) / width_bytes;
461
fbarea = xf86AllocateOffscreenArea(pScreen,
470
info->cursor_start = 0;
471
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
472
"Hardware cursor disabled"
473
" due to insufficient offscreen memory\n");
475
info->cursor_start = RADEON_ALIGN((fbarea->box.x1 +
476
fbarea->box.y1 * width) *
477
info->CurrentLayout.pixel_bytes,
479
info->cursor_end = info->cursor_start + size_bytes;
482
RADEONTRACE(("RADEONCursorInit (0x%08x-0x%08x)\n",
483
info->cursor_start, info->cursor_end));
485
return xf86InitCursor(pScreen, cursor);