1/*
2 * Copyright (c) 2003 NVIDIA, Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "nv_include.h"
29
30#include "cursorstr.h"
31
32/****************************************************************************\
33*                                                                            *
34*                          HW Cursor Entrypoints                             *
35*                                                                            *
36\****************************************************************************/
37
38#define TRANSPARENT_PIXEL   0
39
40#define ConvertToRGB555(c) \
41(((c & 0xf80000) >> 9 ) | ((c & 0xf800) >> 6 ) | ((c & 0xf8) >> 3 ) | 0x8000)
42
43#define ConvertToRGB888(c) (c | 0xff000000)
44
45#define BYTE_SWAP_32(c)  ((c & 0xff000000) >> 24) |  \
46                         ((c & 0xff0000) >> 8) |     \
47                         ((c & 0xff00) << 8) |       \
48                         ((c & 0xff) << 24)
49
50
51static void
52ConvertCursor1555(NVPtr pNv, CARD32 *src, CARD16 *dst)
53{
54    CARD32 b, m;
55    int i, j;
56
57    for ( i = 0; i < 32; i++ ) {
58        b = *src++;
59        m = *src++;
60        for ( j = 0; j < 32; j++ ) {
61#if X_BYTE_ORDER == X_BIG_ENDIAN
62            if ( m & 0x80000000)
63                *dst = ( b & 0x80000000) ? pNv->curFg : pNv->curBg;
64            else
65                *dst = TRANSPARENT_PIXEL;
66            b <<= 1;
67            m <<= 1;
68#else
69            if ( m & 1 )
70                *dst = ( b & 1) ? pNv->curFg : pNv->curBg;
71            else
72                *dst = TRANSPARENT_PIXEL;
73            b >>= 1;
74            m >>= 1;
75#endif
76            dst++;
77        }
78    }
79}
80
81
82static void
83ConvertCursor8888(NVPtr pNv, CARD32 *src, CARD32 *dst)
84{
85    CARD32 b, m;
86    int i, j;
87
88    for ( i = 0; i < 128; i++ ) {
89        b = *src++;
90        m = *src++;
91        for ( j = 0; j < 32; j++ ) {
92#if X_BYTE_ORDER == X_BIG_ENDIAN
93            if ( m & 0x80000000)
94                *dst = ( b & 0x80000000) ? pNv->curFg : pNv->curBg;
95            else
96                *dst = TRANSPARENT_PIXEL;
97            b <<= 1;
98            m <<= 1;
99#else
100            if ( m & 1 )
101                *dst = ( b & 1) ? pNv->curFg : pNv->curBg;
102            else
103                *dst = TRANSPARENT_PIXEL;
104            b >>= 1;
105            m >>= 1;
106#endif
107            dst++;
108        }
109    }
110}
111
112
113static void
114TransformCursor (NVPtr pNv)
115{
116    CARD32 *tmp;
117    int i, dwords;
118
119    /* convert to color cursor */
120    if(pNv->alphaCursor) {
121       dwords = 64 * 64;
122       if(!(tmp = calloc(1, dwords * 4))) return;
123       ConvertCursor8888(pNv, pNv->curImage, tmp);
124    } else {
125       dwords = (32 * 32) >> 1;
126       if(!(tmp = calloc(1, dwords * 4))) return;
127       ConvertCursor1555(pNv, pNv->curImage, (CARD16*)tmp);
128    }
129
130    for(i = 0; i < dwords; i++)
131        pNv->CURSOR[i] = tmp[i];
132
133    free(tmp);
134}
135
136static void
137NVLoadCursorImage( ScrnInfoPtr pScrn, unsigned char *src )
138{
139    NVPtr pNv = NVPTR(pScrn);
140
141    /* save copy of image for color changes */
142    memcpy(pNv->curImage, src, (pNv->alphaCursor) ? 1024 : 256);
143
144    TransformCursor(pNv);
145}
146
147static void
148NVSetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
149{
150    NVPtr pNv = NVPTR(pScrn);
151
152    pNv->PRAMDAC[0x0000300/4] = (x & 0xFFFF) | (y << 16);
153}
154
155static void
156NVSetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
157{
158    NVPtr pNv = NVPTR(pScrn);
159    CARD32 fore, back;
160
161    if(pNv->alphaCursor) {
162        fore = ConvertToRGB888(fg);
163        back = ConvertToRGB888(bg);
164#if X_BYTE_ORDER == X_BIG_ENDIAN
165        if((pNv->Chipset & 0x0ff0) == 0x0110) {
166           fore = BYTE_SWAP_32(fore);
167           back = BYTE_SWAP_32(back);
168        }
169#endif
170    } else {
171        fore = ConvertToRGB555(fg);
172        back = ConvertToRGB555(bg);
173#if X_BYTE_ORDER == X_BIG_ENDIAN
174        if((pNv->Chipset & 0x0ff0) == 0x0110) {
175           fore = ((fore & 0xff) << 8) | (fore >> 8);
176           back = ((back & 0xff) << 8) | (back >> 8);
177        }
178#endif
179   }
180
181    if ((pNv->curFg != fore) || (pNv->curBg != back)) {
182        pNv->curFg = fore;
183        pNv->curBg = back;
184
185        TransformCursor(pNv);
186    }
187}
188
189
190static void
191NVShowCursor(ScrnInfoPtr pScrn)
192{
193    NVPtr pNv = NVPTR(pScrn);
194    /* Enable cursor - X-Windows mode */
195    NVShowHideCursor(pNv, 1);
196}
197
198static void
199NVHideCursor(ScrnInfoPtr pScrn)
200{
201    NVPtr pNv = NVPTR(pScrn);
202    /* Disable cursor */
203    NVShowHideCursor(pNv, 0);
204}
205
206static Bool
207NVUseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
208{
209    return TRUE;
210}
211
212#ifdef ARGB_CURSOR
213static Bool
214NVUseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
215{
216    if((pCurs->bits->width <= 64) && (pCurs->bits->height <= 64))
217        return TRUE;
218
219    return FALSE;
220}
221
222static void
223NVLoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
224{
225    NVPtr pNv = NVPTR(pScrn);
226    CARD32 *image = pCurs->bits->argb;
227    CARD32 *dst = (CARD32*)pNv->CURSOR;
228    CARD32 alpha, tmp;
229    int x, y, w, h;
230
231    w = pCurs->bits->width;
232    h = pCurs->bits->height;
233
234    if((pNv->Chipset & 0x0ff0) == 0x0110) {  /* premultiply */
235       for(y = 0; y < h; y++) {
236          for(x = 0; x < w; x++) {
237             alpha = *image >> 24;
238             if(alpha == 0xff)
239                tmp = *image;
240             else {
241                tmp = (alpha << 24) |
242                         (((*image & 0xff) * alpha) / 255) |
243                        ((((*image & 0xff00) * alpha) / 255) & 0xff00) |
244                       ((((*image & 0xff0000) * alpha) / 255) & 0xff0000);
245             }
246             image++;
247#if X_BYTE_ORDER == X_BIG_ENDIAN
248             *dst++ = BYTE_SWAP_32(tmp);
249#else
250             *dst++ = tmp;
251#endif
252         }
253         for(; x < 64; x++)
254             *dst++ = 0;
255      }
256    } else {
257       for(y = 0; y < h; y++) {
258          for(x = 0; x < w; x++)
259              *dst++ = *image++;
260          for(; x < 64; x++)
261              *dst++ = 0;
262       }
263    }
264
265    if(y < 64)
266      memset(dst, 0, 64 * (64 - y) * 4);
267}
268#endif
269
270Bool
271NVCursorInit(ScreenPtr pScreen)
272{
273    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
274    NVPtr pNv = NVPTR(pScrn);
275    xf86CursorInfoPtr infoPtr;
276
277    infoPtr = xf86CreateCursorInfoRec();
278    if(!infoPtr) return FALSE;
279
280    pNv->CursorInfoRec = infoPtr;
281
282    if(pNv->alphaCursor)
283       infoPtr->MaxWidth = infoPtr->MaxHeight = 64;
284    else
285       infoPtr->MaxWidth = infoPtr->MaxHeight = 32;
286
287    infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
288                     HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32;
289    infoPtr->SetCursorColors = NVSetCursorColors;
290    infoPtr->SetCursorPosition = NVSetCursorPosition;
291    infoPtr->LoadCursorImage = NVLoadCursorImage;
292    infoPtr->HideCursor = NVHideCursor;
293    infoPtr->ShowCursor = NVShowCursor;
294    infoPtr->UseHWCursor = NVUseHWCursor;
295
296#ifdef ARGB_CURSOR
297    if(pNv->alphaCursor) {
298       infoPtr->UseHWCursorARGB = NVUseHWCursorARGB;
299       infoPtr->LoadCursorARGB = NVLoadCursorARGB;
300    }
301#endif
302
303    return(xf86InitCursor(pScreen, infoPtr));
304}
305