randr12: Do scaling / native fixup in the fixup function
[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 32x32 (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 #ifdef ENABLE_RANDR12
337
338 #define CURSOR_PTR ((CARD32*)pNv->Cursor->map)
339
340 Bool NVCursorInitRandr12(ScreenPtr pScreen)
341 {
342         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
343         NVPtr pNv = NVPTR(pScrn);
344         int flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
345                         HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32;
346         int cursor_size = 0;
347         if (pNv->alphaCursor) { /* >= NV11 */
348                 cursor_size = MAX_CURSOR_SIZE_ALPHA;
349                 flags |= HARDWARE_CURSOR_ARGB;
350         } else {
351                 cursor_size = MAX_CURSOR_SIZE;
352         }
353         return xf86_cursors_init(pScreen, cursor_size, cursor_size, flags);
354 }
355
356 void nv_crtc_show_cursor(xf86CrtcPtr crtc)
357 {
358         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
359         ScrnInfoPtr pScrn = crtc->scrn;
360         NVPtr pNv = NVPTR(pScrn);
361         int current = NVReadVgaCrtc(crtc, NV_VGA_CRTCX_CURCTL1);
362
363         /* Enable on this crtc */
364         NVWriteVGA(pNv, nv_crtc->head, NV_VGA_CRTCX_CURCTL1, current | 1);
365
366         if(pNv->Architecture == NV_ARCH_40) {  /* HW bug */
367                 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
368                 xf86OutputPtr output = NULL;
369                 int i;
370
371                 /* We need our output, so we know our ramdac */
372                 for (i = 0; i < xf86_config->num_output; i++) {
373                         output = xf86_config->output[i];
374
375                         if (output->crtc == crtc) {
376                                 /* TODO: Add a check if an output was found? */
377                                 break;
378                         }
379                 }
380
381                 volatile CARD32 curpos = NVOutputReadRAMDAC(output, NV_RAMDAC_CURSOR_POS);
382                 NVOutputWriteRAMDAC(output, NV_RAMDAC_CURSOR_POS, curpos);
383         }
384 }
385
386 void nv_crtc_hide_cursor(xf86CrtcPtr crtc)
387 {
388         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
389         ScrnInfoPtr pScrn = crtc->scrn;
390         NVPtr pNv = NVPTR(pScrn);
391         int current = NVReadVgaCrtc(crtc, NV_VGA_CRTCX_CURCTL1);
392
393         /* Disable on this crtc */
394         NVWriteVGA(pNv, nv_crtc->head, NV_VGA_CRTCX_CURCTL1, current & ~1);
395
396         if(pNv->Architecture == NV_ARCH_40) {  /* HW bug */
397                 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
398                 xf86OutputPtr output = NULL;
399                 int i;
400
401                 /* We need our output, so we know our ramdac */
402                 for (i = 0; i < xf86_config->num_output; i++) {
403                         output = xf86_config->output[i];
404
405                         if (output->crtc == crtc) {
406                                 /* TODO: Add a check if an output was found? */
407                                 break;
408                         }
409                 }
410
411                 volatile CARD32 curpos = NVOutputReadRAMDAC(output, NV_RAMDAC_CURSOR_POS);
412                 NVOutputWriteRAMDAC(output, NV_RAMDAC_CURSOR_POS, curpos);
413         }
414 }
415
416 void nv_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
417 {
418         ScrnInfoPtr pScrn = crtc->scrn;
419         NVPtr pNv = NVPTR(pScrn);
420         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
421         xf86OutputPtr output = NULL;
422         int i;
423
424         /* We need our output, so we know our ramdac */
425         for (i = 0; i < xf86_config->num_output; i++) {
426                 output = xf86_config->output[i];
427
428                 if (output->crtc == crtc) {
429                         /* TODO: Add a check if an output was found? */
430                         break;
431                 }
432         }
433
434         NVOutputWriteRAMDAC(output, NV_RAMDAC_CURSOR_POS, ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | (y << CURSOR_Y_SHIFT));
435 }
436
437 void nv_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
438 {
439         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
440         ScrnInfoPtr pScrn = crtc->scrn;
441         NVPtr pNv = NVPTR(pScrn);
442         CARD32 fore, back;
443
444         if(pNv->alphaCursor) {
445                 fore = ConvertToRGB888(fg);
446                 back = ConvertToRGB888(bg);
447 #if X_BYTE_ORDER == X_BIG_ENDIAN
448                 if(pNv->NVArch == 0x11) {
449                         fore = BYTE_SWAP_32(fore);
450                         back = BYTE_SWAP_32(back);
451                 }
452 #endif
453         } else {
454                 fore = ConvertToRGB555(fg);
455                 back = ConvertToRGB555(bg);
456 #if X_BYTE_ORDER == X_BIG_ENDIAN
457                 if(pNv->NVArch == 0x11) {
458                         fore = ((fore & 0xff) << 8) | (fore >> 8);
459                         back = ((back & 0xff) << 8) | (back >> 8);
460                 }
461 #endif
462         }
463
464         /* Eventually this must be replaced as well */
465         if ((pNv->curFg != fore) || (pNv->curBg != back)) {
466                 pNv->curFg = fore;
467                 pNv->curBg = back;
468                 TransformCursor(pNv);
469         }
470 }
471
472
473 void nv_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *image)
474 {
475         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
476         ScrnInfoPtr pScrn = crtc->scrn;
477         NVPtr pNv = NVPTR(pScrn);
478
479         /* save copy of image for color changes */
480         memcpy(pNv->curImage, image, 256);
481
482         /* Eventually this has to be replaced as well */
483         TransformCursor(pNv);
484 }
485
486 void nv_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image)
487 {
488         NVCrtcPrivatePtr nv_crtc = crtc->driver_private;
489         ScrnInfoPtr pScrn = crtc->scrn;
490         NVPtr pNv = NVPTR(pScrn);
491
492         /* Copy the cursor straight into the right registers */
493         memcpy(CURSOR_PTR, image, 16384);
494 }
495
496 #endif /* ENABLE_RANDR12 */