Small cleanups.
[nouveau] / src / nv_cursor.c
1  /***************************************************************************\
2 |*                                                                           *|
3 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
4 |*                                                                           *|
5 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
6 |*     international laws.  Users and possessors of this source code are     *|
7 |*     hereby granted a nonexclusive,  royalty-free copyright license to     *|
8 |*     use this code in individual and commercial software.                  *|
9 |*                                                                           *|
10 |*     Any use of this source code must include,  in the user documenta-     *|
11 |*     tion and  internal comments to the code,  notices to the end user     *|
12 |*     as follows:                                                           *|
13 |*                                                                           *|
14 |*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
15 |*                                                                           *|
16 |*     NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY     *|
17 |*     OF  THIS SOURCE  CODE  FOR ANY PURPOSE.  IT IS  PROVIDED  "AS IS"     *|
18 |*     WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.  NVIDIA, CORPOR-     *|
19 |*     ATION DISCLAIMS ALL WARRANTIES  WITH REGARD  TO THIS SOURCE CODE,     *|
20 |*     INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE-     *|
21 |*     MENT,  AND FITNESS  FOR A PARTICULAR PURPOSE.   IN NO EVENT SHALL     *|
22 |*     NVIDIA, CORPORATION  BE LIABLE FOR ANY SPECIAL,  INDIRECT,  INCI-     *|
23 |*     DENTAL, OR CONSEQUENTIAL DAMAGES,  OR ANY DAMAGES  WHATSOEVER RE-     *|
24 |*     SULTING FROM LOSS OF USE,  DATA OR PROFITS,  WHETHER IN AN ACTION     *|
25 |*     OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  ARISING OUT OF     *|
26 |*     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE.     *|
27 |*                                                                           *|
28 |*     U.S. Government  End  Users.   This source code  is a "commercial     *|
29 |*     item,"  as that  term is  defined at  48 C.F.R. 2.101 (OCT 1995),     *|
30 |*     consisting  of "commercial  computer  software"  and  "commercial     *|
31 |*     computer  software  documentation,"  as such  terms  are  used in     *|
32 |*     48 C.F.R. 12.212 (SEPT 1995)  and is provided to the U.S. Govern-     *|
33 |*     ment only as  a commercial end item.   Consistent with  48 C.F.R.     *|
34 |*     12.212 and  48 C.F.R. 227.7202-1 through  227.7202-4 (JUNE 1995),     *|
35 |*     all U.S. Government End Users  acquire the source code  with only     *|
36 |*     those rights set forth herein.                                        *|
37 |*                                                                           *|
38  \***************************************************************************/
39
40 /* Copyright 2007 Maarten Maathuis */
41
42 /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/nv_cursor.c,v 1.13 2004/03/13 22:07:05 mvojkovi Exp $ */
43
44 #include "nv_include.h"
45
46 #include "cursorstr.h"
47
48 /****************************************************************************\
49 *                                                                            *
50 *                          HW Cursor Entrypoints                             *
51 *                                                                            *
52 \****************************************************************************/
53
54 #define NV_CURSOR_X 64
55 #define NV_CURSOR_Y 64
56
57 #define CURSOR_X_SHIFT 0
58 #define CURSOR_Y_SHIFT 16
59 #define CURSOR_POS_MASK 0xffff
60
61 #define TRANSPARENT_PIXEL   0
62
63 #define ConvertToRGB555(c)  (((c & 0xf80000) >> 9 ) | /* Blue  */           \
64                             ((c & 0xf800) >> 6 )    | /* Green */           \
65                             ((c & 0xf8) >> 3 )      | /* Red   */           \
66                             0x8000)                   /* Set upper bit, else we get complete transparency. */
67
68 #define ConvertToRGB888(c) (c | 0xff000000)
69
70 #define BYTE_SWAP_32(c)  ((c & 0xff000000) >> 24) |  \
71                          ((c & 0xff0000) >> 8) |     \
72                          ((c & 0xff00) << 8) |       \
73                          ((c & 0xff) << 24)
74
75 /* Limit non-alpha cursors to 32x32 (x2 bytes) */
76 #define MAX_CURSOR_SIZE 32
77
78 /* Limit alpha cursors to 64x64 (x4 bytes) */
79 #define MAX_CURSOR_SIZE_ALPHA (MAX_CURSOR_SIZE * 2)
80
81 static void 
82 ConvertCursor1555(NVPtr pNv, CARD32 *src, CARD16 *dst)
83 {
84         CARD32 b, m;
85         int i, j;
86
87         for ( i = 0; i < MAX_CURSOR_SIZE; i++ ) {
88                 b = *src++;
89                 m = *src++;
90                 for ( j = 0; j < MAX_CURSOR_SIZE; j++ ) {
91 #if X_BYTE_ORDER == X_BIG_ENDIAN
92                         if ( m & 0x80000000)
93                                 *dst = ( b & 0x80000000) ? pNv->curFg : pNv->curBg;
94                         else
95                                 *dst = TRANSPARENT_PIXEL;
96                         b <<= 1;
97                         m <<= 1;
98 #else
99                         if ( m & 1 )
100                                 *dst = ( b & 1) ? pNv->curFg : pNv->curBg;
101                         else
102                                 *dst = TRANSPARENT_PIXEL;
103                         b >>= 1;
104                         m >>= 1;
105 #endif
106                         dst++;
107                 }
108         }
109 }
110
111
112 static void
113 ConvertCursor8888(NVPtr pNv, CARD32 *src, CARD32 *dst)
114 {
115         CARD32 b, m;
116         int i, j;
117
118         /* Iterate over each byte in the cursor. */
119         for ( i = 0; i < MAX_CURSOR_SIZE * 4; i++ ) {
120                 b = *src++;
121                 m = *src++;
122                 for ( j = 0; j < MAX_CURSOR_SIZE; j++ ) {
123 #if X_BYTE_ORDER == X_BIG_ENDIAN
124                         if ( m & 0x80000000)
125                                 *dst = ( b & 0x80000000) ? pNv->curFg : pNv->curBg;
126                         else
127                                 *dst = TRANSPARENT_PIXEL;
128                         b <<= 1;
129                         m <<= 1;
130 #else
131                         if ( m & 1 )
132                                 *dst = ( b & 1) ? pNv->curFg : pNv->curBg;
133                         else
134                                 *dst = TRANSPARENT_PIXEL;
135                         b >>= 1;
136                         m >>= 1;
137 #endif
138                         dst++;
139                 }
140         }
141 }
142
143
144 static void
145 TransformCursor (NVPtr pNv)
146 {
147         CARD32 *tmp;
148         int i, dwords;
149
150         /* convert to color cursor */
151         if(pNv->alphaCursor) {
152                 dwords = MAX_CURSOR_SIZE_ALPHA * MAX_CURSOR_SIZE_ALPHA;
153                 if(!(tmp = xalloc(dwords * 4))) return;
154                 ConvertCursor8888(pNv, pNv->curImage, tmp);
155         } else {
156                 dwords = (MAX_CURSOR_SIZE * MAX_CURSOR_SIZE) >> 1;
157                 if(!(tmp = xalloc(dwords * 4))) return;
158                 ConvertCursor1555(pNv, pNv->curImage, (CARD16*)tmp);
159         }
160
161         for(i = 0; i < dwords; i++)
162                 pNv->CURSOR[i] = tmp[i];
163
164         xfree(tmp);
165 }
166
167 static void
168 NVLoadCursorImage( ScrnInfoPtr pScrn, unsigned char *src )
169 {
170     NVPtr pNv = NVPTR(pScrn);
171
172     /* save copy of image for color changes */
173     memcpy(pNv->curImage, src, (pNv->alphaCursor) ? 1024 : 256);
174
175     TransformCursor(pNv);
176 }
177
178 static void
179 NVSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
180 {
181         NVPtr pNv = NVPTR(pScrn);
182         nvWriteCurRAMDAC(pNv, NV_RAMDAC_CURSOR_POS, (x & 0xFFFF) | (y << 16));
183 }
184
185 static void
186 NVSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
187 {
188     NVPtr pNv = NVPTR(pScrn);
189     CARD32 fore, back;
190
191     if(pNv->alphaCursor) {
192         fore = ConvertToRGB888(fg);
193         back = ConvertToRGB888(bg);
194 #if X_BYTE_ORDER == X_BIG_ENDIAN
195         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
196            fore = BYTE_SWAP_32(fore);
197            back = BYTE_SWAP_32(back);
198         }
199 #endif
200     } else {
201         fore = ConvertToRGB555(fg);
202         back = ConvertToRGB555(bg);
203 #if X_BYTE_ORDER == X_BIG_ENDIAN
204         if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {
205            fore = ((fore & 0xff) << 8) | (fore >> 8);
206            back = ((back & 0xff) << 8) | (back >> 8);
207         }
208 #endif
209    }
210
211     if ((pNv->curFg != fore) || (pNv->curBg != back)) {
212         pNv->curFg = fore;
213         pNv->curBg = back;
214             
215         TransformCursor(pNv);
216     }
217 }
218
219
220 static void 
221 NVShowCursor(ScrnInfoPtr pScrn)
222 {
223         /* Enable cursor - X-Windows mode */
224         NVShowHideCursor(pScrn, 1);
225 }
226
227 static void
228 NVHideCursor(ScrnInfoPtr pScrn)
229 {
230         /* Disable cursor */
231         NVShowHideCursor(pScrn, 0);
232 }
233
234 static Bool 
235 NVUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
236 {
237         return TRUE;
238 }
239
240 #ifdef ARGB_CURSOR
241 static Bool 
242 NVUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
243 {
244     if((pCurs->bits->width <= MAX_CURSOR_SIZE_ALPHA) && (pCurs->bits->height <= MAX_CURSOR_SIZE_ALPHA))
245         return TRUE;
246
247     return FALSE;
248 }
249
250 static void
251 NVLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
252 {
253     NVPtr pNv = NVPTR(pScrn);
254     CARD32 *image = pCurs->bits->argb;
255     CARD32 *dst = (CARD32*)pNv->CURSOR;
256     CARD32 alpha, tmp;
257     int x, y, w, h;
258
259     w = pCurs->bits->width;
260     h = pCurs->bits->height;
261
262     if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {  /* premultiply */
263        for(y = 0; y < h; y++) {
264           for(x = 0; x < w; x++) {
265              alpha = *image >> 24;
266              if(alpha == 0xff)
267                 tmp = *image;
268              else {
269                 tmp = (alpha << 24) |
270                          (((*image & 0xff) * alpha) / 255) |
271                         ((((*image & 0xff00) * alpha) / 255) & 0xff00) |
272                        ((((*image & 0xff0000) * alpha) / 255) & 0xff0000); 
273              }
274              image++;
275 #if X_BYTE_ORDER == X_BIG_ENDIAN
276              *dst++ = BYTE_SWAP_32(tmp);
277 #else
278              *dst++ = tmp;
279 #endif
280          }
281          for(; x < MAX_CURSOR_SIZE_ALPHA; x++)
282              *dst++ = 0;
283       }
284     } else {
285        for(y = 0; y < h; y++) {
286           for(x = 0; x < w; x++)
287               *dst++ = *image++;
288           for(; x < MAX_CURSOR_SIZE_ALPHA; x++)
289               *dst++ = 0;
290        }
291     }
292
293     if(y < MAX_CURSOR_SIZE_ALPHA)
294       memset(dst, 0, MAX_CURSOR_SIZE_ALPHA * (MAX_CURSOR_SIZE_ALPHA - y) * 4);
295 }
296 #endif
297
298 Bool 
299 NVCursorInit(ScreenPtr pScreen)
300 {
301     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
302     NVPtr pNv = NVPTR(pScrn);
303     xf86CursorInfoPtr infoPtr;
304
305     infoPtr = xf86CreateCursorInfoRec();
306     if(!infoPtr) return FALSE;
307     
308     pNv->CursorInfoRec = infoPtr;
309
310     if(pNv->alphaCursor)
311        infoPtr->MaxWidth = infoPtr->MaxHeight = MAX_CURSOR_SIZE_ALPHA;
312     else
313        infoPtr->MaxWidth = infoPtr->MaxHeight = MAX_CURSOR_SIZE;
314
315     infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
316                      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32; 
317     infoPtr->SetCursorColors = NVSetCursorColors;
318     infoPtr->SetCursorPosition = NVSetCursorPosition;
319     infoPtr->LoadCursorImage = NVLoadCursorImage;
320     infoPtr->HideCursor = NVHideCursor;
321     infoPtr->ShowCursor = NVShowCursor;
322     infoPtr->UseHWCursor = NVUseHWCursor;
323
324 #ifdef ARGB_CURSOR
325     if(pNv->alphaCursor) {
326        infoPtr->UseHWCursorARGB = NVUseHWCursorARGB;
327        infoPtr->LoadCursorARGB = NVLoadCursorARGB;
328     }
329 #endif
330
331     return(xf86InitCursor(pScreen, infoPtr));
332 }
333
334 #define CURSOR_PTR ((CARD32*)pNv->Cursor->map)
335
336 Bool NVCursorInitRandr12(ScreenPtr pScreen)
337 {
338         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
339         NVPtr pNv = NVPTR(pScrn);
340         int flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
341                         HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32;
342         int cursor_size = 0;
343         if (pNv->alphaCursor) { /* >= NV11 */
344                 cursor_size = MAX_CURSOR_SIZE_ALPHA;
345                 flags |= HARDWARE_CURSOR_ARGB;
346         } else {
347                 cursor_size = MAX_CURSOR_SIZE;
348         }
349         return xf86_cursors_init(pScreen, cursor_size, cursor_size, flags);
350 }
351
352 void nv_crtc_fix_nv40_hw_cursor(ScrnInfoPtr pScrn, uint8_t head)
353 {
354         NVPtr pNv = NVPTR(pScrn);
355         volatile uint32_t curpos = NVReadRAMDAC(pNv, head, NV_RAMDAC_CURSOR_POS);
356         NVWriteRAMDAC(pNv, head, NV_RAMDAC_CURSOR_POS, curpos);
357 }
358
359 void nv_crtc_show_hide_cursor(ScrnInfoPtr pScrn, uint8_t head, Bool show)
360 {
361         NVPtr pNv = NVPTR(pScrn);
362         uint32_t current = NVReadVGA(pNv, head, NV_VGA_CRTCX_CURCTL1);
363
364         if (show)
365                 NVWriteVGA(pNv, head, NV_VGA_CRTCX_CURCTL1, current | 1);
366         else
367                 NVWriteVGA(pNv, head, NV_VGA_CRTCX_CURCTL1, current & ~1);
368
369         if (pNv->Architecture == NV_ARCH_40) /* HW bug */
370                 nv_crtc_fix_nv40_hw_cursor(pScrn, head);
371 }
372
373 void nv_crtc_show_cursor(xf86CrtcPtr crtc)
374 {
375         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
376         ScrnInfoPtr pScrn = crtc->scrn;
377
378         nv_crtc_show_hide_cursor(pScrn, nv_crtc->head, TRUE);
379 }
380
381 void nv_crtc_hide_cursor(xf86CrtcPtr crtc)
382 {
383         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
384         ScrnInfoPtr pScrn = crtc->scrn;
385
386         nv_crtc_show_hide_cursor(pScrn, nv_crtc->head, FALSE);
387 }
388
389 void nv_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
390 {
391         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
392         ScrnInfoPtr pScrn = crtc->scrn;
393         NVPtr pNv = NVPTR(pScrn);
394
395         NVWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_CURSOR_POS, ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | (y << CURSOR_Y_SHIFT));
396 }
397
398 void nv_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
399 {
400         ScrnInfoPtr pScrn = crtc->scrn;
401         NVPtr pNv = NVPTR(pScrn);
402         CARD32 fore, back;
403
404         fore = ConvertToRGB555(fg);
405         back = ConvertToRGB555(bg);
406 #if X_BYTE_ORDER == X_BIG_ENDIAN
407         if(pNv->NVArch == 0x11) {
408                 fore = ((fore & 0xff) << 8) | (fore >> 8);
409                 back = ((back & 0xff) << 8) | (back >> 8);
410         }
411 #endif
412
413         /* Eventually this must be replaced as well */
414         if ((pNv->curFg != fore) || (pNv->curBg != back)) {
415                 pNv->curFg = fore;
416                 pNv->curBg = back;
417                 TransformCursor(pNv);
418         }
419 }
420
421
422 void nv_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *image)
423 {
424         ScrnInfoPtr pScrn = crtc->scrn;
425         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
426         NVPtr pNv = NVPTR(pScrn);
427
428         /* save copy of image for color changes */
429         memcpy(pNv->curImage, image, 256);
430
431         if (pNv->Architecture >= NV_ARCH_10) {
432                 /* Due to legacy code */
433                 if (nv_crtc->head == 1)
434                         pNv->CURSOR = (CARD32 *) pNv->Cursor2->map;
435                 else
436                         pNv->CURSOR = (CARD32 *) pNv->Cursor->map;
437         }
438
439         /* Eventually this has to be replaced as well */
440         TransformCursor(pNv);
441 }
442
443 void nv_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
444 {
445         ScrnInfoPtr pScrn = crtc->scrn;
446         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
447         NVPtr pNv = NVPTR(pScrn);
448         uint32_t *dst = NULL;
449         uint32_t *src = (uint32_t *)image;
450
451         if (nv_crtc->head == 1) {
452                 dst = (uint32_t *) pNv->Cursor2->map;
453         } else {
454                 dst = (uint32_t *) pNv->Cursor->map;
455         }
456
457         /* It seems we get premultiplied alpha and the hardware takes non-premultiplied? */
458         /* This is needed, because without bit28 of cursorControl, we use what ever ROP is set currently */
459         /* This causes artifacts (on nv4x at least) */
460         int x, y;
461         uint32_t alpha, value;
462
463         for (x = 0; x < MAX_CURSOR_SIZE_ALPHA; x++) {
464                 for (y = 0; y < MAX_CURSOR_SIZE_ALPHA; y++) {
465                         alpha = *src >> 24;
466                         if (alpha == 0x0 || alpha == 0xff) {
467                                 value = *src;
468                         } else {
469                                 value =         ((((*src & 0xff) * 0xff) / alpha)               & 0x000000ff)   |
470                                                 ((((*src & 0xff00) * 0xff) / alpha)     & 0x0000ff00)   |
471                                                 ((((*src & 0xff0000) * 0xff) / alpha)   & 0x00ff0000)   |
472                                                 ((alpha << 24)                          & 0xff000000);
473                         }
474                         src++;
475 #if X_BYTE_ORDER == X_BIG_ENDIAN
476                         *dst++ = BYTE_SWAP_32(value);
477 #else
478                         *dst++ = value;
479 #endif
480                 }
481         }
482 }
483