randr12: Fixed a minor cursor bug.
[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         NVPtr pNv = NVPTR(pScrn);
224         /* Enable cursor - X-Windows mode */
225         NVShowHideCursor(pNv, 1);
226 }
227
228 static void
229 NVHideCursor(ScrnInfoPtr pScrn)
230 {
231         NVPtr pNv = NVPTR(pScrn);
232         /* Disable cursor */
233         NVShowHideCursor(pNv, 0);
234 }
235
236 static Bool 
237 NVUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
238 {
239         return TRUE;
240 }
241
242 #ifdef ARGB_CURSOR
243 static Bool 
244 NVUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
245 {
246     if((pCurs->bits->width <= MAX_CURSOR_SIZE_ALPHA) && (pCurs->bits->height <= MAX_CURSOR_SIZE_ALPHA))
247         return TRUE;
248
249     return FALSE;
250 }
251
252 static void
253 NVLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
254 {
255     NVPtr pNv = NVPTR(pScrn);
256     CARD32 *image = pCurs->bits->argb;
257     CARD32 *dst = (CARD32*)pNv->CURSOR;
258     CARD32 alpha, tmp;
259     int x, y, w, h;
260
261     w = pCurs->bits->width;
262     h = pCurs->bits->height;
263
264     if((pNv->Chipset & 0x0ff0) == CHIPSET_NV11) {  /* premultiply */
265        for(y = 0; y < h; y++) {
266           for(x = 0; x < w; x++) {
267              alpha = *image >> 24;
268              if(alpha == 0xff)
269                 tmp = *image;
270              else {
271                 tmp = (alpha << 24) |
272                          (((*image & 0xff) * alpha) / 255) |
273                         ((((*image & 0xff00) * alpha) / 255) & 0xff00) |
274                        ((((*image & 0xff0000) * alpha) / 255) & 0xff0000); 
275              }
276              image++;
277 #if X_BYTE_ORDER == X_BIG_ENDIAN
278              *dst++ = BYTE_SWAP_32(tmp);
279 #else
280              *dst++ = tmp;
281 #endif
282          }
283          for(; x < MAX_CURSOR_SIZE_ALPHA; x++)
284              *dst++ = 0;
285       }
286     } else {
287        for(y = 0; y < h; y++) {
288           for(x = 0; x < w; x++)
289               *dst++ = *image++;
290           for(; x < MAX_CURSOR_SIZE_ALPHA; x++)
291               *dst++ = 0;
292        }
293     }
294
295     if(y < MAX_CURSOR_SIZE_ALPHA)
296       memset(dst, 0, MAX_CURSOR_SIZE_ALPHA * (MAX_CURSOR_SIZE_ALPHA - y) * 4);
297 }
298 #endif
299
300 Bool 
301 NVCursorInit(ScreenPtr pScreen)
302 {
303     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
304     NVPtr pNv = NVPTR(pScrn);
305     xf86CursorInfoPtr infoPtr;
306
307     infoPtr = xf86CreateCursorInfoRec();
308     if(!infoPtr) return FALSE;
309     
310     pNv->CursorInfoRec = infoPtr;
311
312     if(pNv->alphaCursor)
313        infoPtr->MaxWidth = infoPtr->MaxHeight = MAX_CURSOR_SIZE_ALPHA;
314     else
315        infoPtr->MaxWidth = infoPtr->MaxHeight = MAX_CURSOR_SIZE;
316
317     infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
318                      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32; 
319     infoPtr->SetCursorColors = NVSetCursorColors;
320     infoPtr->SetCursorPosition = NVSetCursorPosition;
321     infoPtr->LoadCursorImage = NVLoadCursorImage;
322     infoPtr->HideCursor = NVHideCursor;
323     infoPtr->ShowCursor = NVShowCursor;
324     infoPtr->UseHWCursor = NVUseHWCursor;
325
326 #ifdef ARGB_CURSOR
327     if(pNv->alphaCursor) {
328        infoPtr->UseHWCursorARGB = NVUseHWCursorARGB;
329        infoPtr->LoadCursorARGB = NVLoadCursorARGB;
330     }
331 #endif
332
333     return(xf86InitCursor(pScreen, infoPtr));
334 }
335
336 #define CURSOR_PTR ((CARD32*)pNv->Cursor->map)
337
338 Bool NVCursorInitRandr12(ScreenPtr pScreen)
339 {
340         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
341         NVPtr pNv = NVPTR(pScrn);
342         int flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
343                         HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32;
344         int cursor_size = 0;
345         if (pNv->alphaCursor) { /* >= NV11 */
346                 cursor_size = MAX_CURSOR_SIZE_ALPHA;
347                 flags |= HARDWARE_CURSOR_ARGB;
348         } else {
349                 cursor_size = MAX_CURSOR_SIZE;
350         }
351         return xf86_cursors_init(pScreen, cursor_size, cursor_size, flags);
352 }
353
354 void nv_crtc_show_cursor(xf86CrtcPtr crtc)
355 {
356         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
357         ScrnInfoPtr pScrn = crtc->scrn;
358         NVPtr pNv = NVPTR(pScrn);
359         int current = NVReadVgaCrtc(crtc, NV_VGA_CRTCX_CURCTL1);
360
361         /* Enable on this crtc */
362         NVWriteVGA(pNv, nv_crtc->head, NV_VGA_CRTCX_CURCTL1, current | 1);
363
364         if (pNv->Architecture == NV_ARCH_40) {  /* HW bug */
365                 volatile CARD32 curpos = nvReadRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_CURSOR_POS);
366                 nvWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_CURSOR_POS, curpos);
367         }
368 }
369
370 void nv_crtc_hide_cursor(xf86CrtcPtr crtc)
371 {
372         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
373         ScrnInfoPtr pScrn = crtc->scrn;
374         NVPtr pNv = NVPTR(pScrn);
375         int current = NVReadVgaCrtc(crtc, NV_VGA_CRTCX_CURCTL1);
376
377         /* Disable on this crtc */
378         NVWriteVGA(pNv, nv_crtc->head, NV_VGA_CRTCX_CURCTL1, current & ~1);
379
380         if (pNv->Architecture == NV_ARCH_40) {  /* HW bug */
381                 volatile CARD32 curpos = nvReadRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_CURSOR_POS);
382                 nvWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_CURSOR_POS, curpos);
383         }
384 }
385
386 void nv_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
387 {
388         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
389         ScrnInfoPtr pScrn = crtc->scrn;
390         NVPtr pNv = NVPTR(pScrn);
391
392         nvWriteRAMDAC(pNv, nv_crtc->head, NV_RAMDAC_CURSOR_POS, ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | (y << CURSOR_Y_SHIFT));
393 }
394
395 void nv_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
396 {
397         ScrnInfoPtr pScrn = crtc->scrn;
398         NVPtr pNv = NVPTR(pScrn);
399         CARD32 fore, back;
400
401         fore = ConvertToRGB555(fg);
402         back = ConvertToRGB555(bg);
403 #if X_BYTE_ORDER == X_BIG_ENDIAN
404         if(pNv->NVArch == 0x11) {
405                 fore = ((fore & 0xff) << 8) | (fore >> 8);
406                 back = ((back & 0xff) << 8) | (back >> 8);
407         }
408 #endif
409
410         /* Eventually this must be replaced as well */
411         if ((pNv->curFg != fore) || (pNv->curBg != back)) {
412                 pNv->curFg = fore;
413                 pNv->curBg = back;
414                 TransformCursor(pNv);
415         }
416 }
417
418
419 void nv_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *image)
420 {
421         ScrnInfoPtr pScrn = crtc->scrn;
422         NVPtr pNv = NVPTR(pScrn);
423
424         /* save copy of image for color changes */
425         memcpy(pNv->curImage, image, 256);
426
427         /* Eventually this has to be replaced as well */
428         TransformCursor(pNv);
429 }
430
431 void nv_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
432 {
433         ScrnInfoPtr pScrn = crtc->scrn;
434         NVPtr pNv = NVPTR(pScrn);
435         uint32_t *dst = (uint32_t*)pNv->CURSOR;
436         uint32_t *src = image;
437
438         /* It seems we get premultiplied alpha and the hardware takes non-premultiplied? */
439         /* This is needed, because without bit28 of cursorControl, we use what ever ROP is set currently */
440         /* This causes artifacts (on nv4x at least) */
441         int x, y;
442         uint32_t alpha, value;
443
444         for (x = 0; x < MAX_CURSOR_SIZE_ALPHA; x++) {
445                 for (y = 0; y < MAX_CURSOR_SIZE_ALPHA; y++) {
446                         alpha = *src >> 24;
447                         if (alpha == 0x0 || alpha == 0xff) {
448                                 value = *src;
449                         } else {
450                                 value =         ((((*src & 0xff) * 0xff) / alpha)               & 0x000000ff)   |
451                                                 ((((*src & 0xff00) * 0xff) / alpha)     & 0x0000ff00)   |
452                                                 ((((*src & 0xff0000) * 0xff) / alpha)   & 0x00ff0000)   |
453                                                 ((alpha << 24)                          & 0xff000000);
454                         }
455                         src++;
456 #if X_BYTE_ORDER == X_BIG_ENDIAN
457                         *dst++ = BYTE_SWAP_32(value);
458 #else
459                         *dst++ = value;
460 #endif
461                 }
462         }
463 }
464