xf86HWCurs.c revision 35c4bbdf
1
2#ifdef HAVE_XORG_CONFIG_H
3#include <xorg-config.h>
4#endif
5
6#include <string.h>
7
8#include "misc.h"
9#include "xf86.h"
10#include "xf86_OSproc.h"
11
12#include <X11/X.h>
13#include "scrnintstr.h"
14#include "pixmapstr.h"
15#include "windowstr.h"
16#include "xf86str.h"
17#include "cursorstr.h"
18#include "mi.h"
19#include "mipointer.h"
20#include "xf86CursorPriv.h"
21
22#include "servermd.h"
23
24static CARD32
25xf86ReverseBitOrder(CARD32 v)
26{
27    return (((0x01010101 & v) << 7) | ((0x02020202 & v) << 5) |
28            ((0x04040404 & v) << 3) | ((0x08080808 & v) << 1) |
29            ((0x10101010 & v) >> 1) | ((0x20202020 & v) >> 3) |
30            ((0x40404040 & v) >> 5) | ((0x80808080 & v) >> 7));
31}
32
33#if BITMAP_SCANLINE_PAD == 64
34
35#if 1
36/* Cursors might be only 32 wide. Give'em a chance */
37#define SCANLINE CARD32
38#define CUR_BITMAP_SCANLINE_PAD 32
39#define CUR_LOG2_BITMAP_PAD 5
40#define REVERSE_BIT_ORDER(w) xf86ReverseBitOrder(w)
41#else
42#define SCANLINE CARD64
43#define CUR_BITMAP_SCANLINE_PAD BITMAP_SCANLINE_PAD
44#define CUR_LOG2_BITMAP_PAD LOG2_BITMAP_PAD
45#define REVERSE_BIT_ORDER(w) xf86CARD64ReverseBits(w)
46static CARD64 xf86CARD64ReverseBits(CARD64 w);
47
48static CARD64
49xf86CARD64ReverseBits(CARD64 w)
50{
51    unsigned char *p = (unsigned char *) &w;
52
53    p[0] = byte_reversed[p[0]];
54    p[1] = byte_reversed[p[1]];
55    p[2] = byte_reversed[p[2]];
56    p[3] = byte_reversed[p[3]];
57    p[4] = byte_reversed[p[4]];
58    p[5] = byte_reversed[p[5]];
59    p[6] = byte_reversed[p[6]];
60    p[7] = byte_reversed[p[7]];
61
62    return w;
63}
64#endif
65
66#else
67
68#define SCANLINE CARD32
69#define CUR_BITMAP_SCANLINE_PAD BITMAP_SCANLINE_PAD
70#define CUR_LOG2_BITMAP_PAD LOG2_BITMAP_PAD
71#define REVERSE_BIT_ORDER(w) xf86ReverseBitOrder(w)
72
73#endif                          /* BITMAP_SCANLINE_PAD == 64 */
74
75static unsigned char *RealizeCursorInterleave0(xf86CursorInfoPtr, CursorPtr);
76static unsigned char *RealizeCursorInterleave1(xf86CursorInfoPtr, CursorPtr);
77static unsigned char *RealizeCursorInterleave8(xf86CursorInfoPtr, CursorPtr);
78static unsigned char *RealizeCursorInterleave16(xf86CursorInfoPtr, CursorPtr);
79static unsigned char *RealizeCursorInterleave32(xf86CursorInfoPtr, CursorPtr);
80static unsigned char *RealizeCursorInterleave64(xf86CursorInfoPtr, CursorPtr);
81
82Bool
83xf86InitHardwareCursor(ScreenPtr pScreen, xf86CursorInfoPtr infoPtr)
84{
85    if ((infoPtr->MaxWidth <= 0) || (infoPtr->MaxHeight <= 0))
86        return FALSE;
87
88    /* These are required for now */
89    if (!infoPtr->SetCursorPosition ||
90        !xf86DriverHasLoadCursorImage(infoPtr) ||
91        !infoPtr->HideCursor ||
92        !infoPtr->ShowCursor || !infoPtr->SetCursorColors)
93        return FALSE;
94
95    if (infoPtr->RealizeCursor) {
96        /* Don't overwrite a driver provided Realize Cursor function */
97    }
98    else if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 & infoPtr->Flags) {
99        infoPtr->RealizeCursor = RealizeCursorInterleave1;
100    }
101    else if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 & infoPtr->Flags) {
102        infoPtr->RealizeCursor = RealizeCursorInterleave8;
103    }
104    else if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 & infoPtr->Flags) {
105        infoPtr->RealizeCursor = RealizeCursorInterleave16;
106    }
107    else if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 & infoPtr->Flags) {
108        infoPtr->RealizeCursor = RealizeCursorInterleave32;
109    }
110    else if (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 & infoPtr->Flags) {
111        infoPtr->RealizeCursor = RealizeCursorInterleave64;
112    }
113    else {                      /* not interleaved */
114        infoPtr->RealizeCursor = RealizeCursorInterleave0;
115    }
116
117    infoPtr->pScrn = xf86ScreenToScrn(pScreen);
118
119    return TRUE;
120}
121
122Bool
123xf86SetCursor(ScreenPtr pScreen, CursorPtr pCurs, int x, int y)
124{
125    xf86CursorScreenPtr ScreenPriv =
126        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
127                                               xf86CursorScreenKey);
128    xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr;
129    unsigned char *bits;
130
131    if (pCurs == NullCursor) {
132        (*infoPtr->HideCursor) (infoPtr->pScrn);
133        return TRUE;
134    }
135
136    bits =
137        dixLookupScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen);
138
139    x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX;
140    y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY;
141
142    if (!pCurs->bits->argb || !xf86DriverHasLoadCursorARGB(infoPtr))
143        if (!bits) {
144            bits = (*infoPtr->RealizeCursor) (infoPtr, pCurs);
145            dixSetScreenPrivate(&pCurs->devPrivates, CursorScreenKey, pScreen,
146                                bits);
147        }
148
149    if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN))
150        (*infoPtr->HideCursor) (infoPtr->pScrn);
151
152    if (pCurs->bits->argb && xf86DriverHasLoadCursorARGB(infoPtr)) {
153        if (!xf86DriverLoadCursorARGB (infoPtr, pCurs))
154            return FALSE;
155    } else
156    if (bits)
157        if (!xf86DriverLoadCursorImage (infoPtr, bits))
158            return FALSE;
159
160    xf86RecolorCursor(pScreen, pCurs, 1);
161
162    (*infoPtr->SetCursorPosition) (infoPtr->pScrn, x, y);
163
164    (*infoPtr->ShowCursor) (infoPtr->pScrn);
165    return TRUE;
166}
167
168void
169xf86SetTransparentCursor(ScreenPtr pScreen)
170{
171    xf86CursorScreenPtr ScreenPriv =
172        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
173                                               xf86CursorScreenKey);
174    xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr;
175
176    if (!ScreenPriv->transparentData)
177        ScreenPriv->transparentData =
178            (*infoPtr->RealizeCursor) (infoPtr, NullCursor);
179
180    if (!(infoPtr->Flags & HARDWARE_CURSOR_UPDATE_UNHIDDEN))
181        (*infoPtr->HideCursor) (infoPtr->pScrn);
182
183    if (ScreenPriv->transparentData)
184        xf86DriverLoadCursorImage (infoPtr,
185                                   ScreenPriv->transparentData);
186
187    (*infoPtr->ShowCursor) (infoPtr->pScrn);
188}
189
190void
191xf86MoveCursor(ScreenPtr pScreen, int x, int y)
192{
193    xf86CursorScreenPtr ScreenPriv =
194        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
195                                               xf86CursorScreenKey);
196    xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr;
197
198    x -= infoPtr->pScrn->frameX0 + ScreenPriv->HotX;
199    y -= infoPtr->pScrn->frameY0 + ScreenPriv->HotY;
200
201    (*infoPtr->SetCursorPosition) (infoPtr->pScrn, x, y);
202}
203
204void
205xf86RecolorCursor(ScreenPtr pScreen, CursorPtr pCurs, Bool displayed)
206{
207    xf86CursorScreenPtr ScreenPriv =
208        (xf86CursorScreenPtr) dixLookupPrivate(&pScreen->devPrivates,
209                                               xf86CursorScreenKey);
210    xf86CursorInfoPtr infoPtr = ScreenPriv->CursorInfoPtr;
211
212    /* recoloring isn't applicable to ARGB cursors and drivers
213       shouldn't have to ignore SetCursorColors requests */
214    if (pCurs->bits->argb)
215        return;
216
217    if (ScreenPriv->PalettedCursor) {
218        xColorItem sourceColor, maskColor;
219        ColormapPtr pmap = ScreenPriv->pInstalledMap;
220
221        if (!pmap)
222            return;
223
224        sourceColor.red = pCurs->foreRed;
225        sourceColor.green = pCurs->foreGreen;
226        sourceColor.blue = pCurs->foreBlue;
227        FakeAllocColor(pmap, &sourceColor);
228        maskColor.red = pCurs->backRed;
229        maskColor.green = pCurs->backGreen;
230        maskColor.blue = pCurs->backBlue;
231        FakeAllocColor(pmap, &maskColor);
232        FakeFreeColor(pmap, sourceColor.pixel);
233        FakeFreeColor(pmap, maskColor.pixel);
234        (*infoPtr->SetCursorColors) (infoPtr->pScrn,
235                                     maskColor.pixel, sourceColor.pixel);
236    }
237    else {                      /* Pass colors in 8-8-8 RGB format */
238        (*infoPtr->SetCursorColors) (infoPtr->pScrn,
239                                     (pCurs->backBlue >> 8) |
240                                     ((pCurs->backGreen >> 8) << 8) |
241                                     ((pCurs->backRed >> 8) << 16),
242                                     (pCurs->foreBlue >> 8) |
243                                     ((pCurs->foreGreen >> 8) << 8) |
244                                     ((pCurs->foreRed >> 8) << 16)
245            );
246    }
247}
248
249/* These functions assume that MaxWidth is a multiple of 32 */
250static unsigned char *
251RealizeCursorInterleave0(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
252{
253
254    SCANLINE *SrcS, *SrcM, *DstS, *DstM;
255    SCANLINE *pSrc, *pMsk;
256    unsigned char *mem;
257    int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2;
258    int SrcPitch, DstPitch, Pitch, y, x;
259
260    /* how many words are in the source or mask */
261    int words = size / (CUR_BITMAP_SCANLINE_PAD / 4);
262
263    if (!(mem = calloc(1, size)))
264        return NULL;
265
266    if (pCurs == NullCursor) {
267        if (infoPtr->Flags & HARDWARE_CURSOR_INVERT_MASK) {
268            DstM = (SCANLINE *) mem;
269            if (!(infoPtr->Flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK))
270                DstM += words;
271            memset(DstM, -1, words * sizeof(SCANLINE));
272        }
273        return mem;
274    }
275
276    /* SrcPitch == the number of scanlines wide the cursor image is */
277    SrcPitch = (pCurs->bits->width + (BITMAP_SCANLINE_PAD - 1)) >>
278        CUR_LOG2_BITMAP_PAD;
279
280    /* DstPitch is the width of the hw cursor in scanlines */
281    DstPitch = infoPtr->MaxWidth >> CUR_LOG2_BITMAP_PAD;
282    Pitch = SrcPitch < DstPitch ? SrcPitch : DstPitch;
283
284    SrcS = (SCANLINE *) pCurs->bits->source;
285    SrcM = (SCANLINE *) pCurs->bits->mask;
286    DstS = (SCANLINE *) mem;
287    DstM = DstS + words;
288
289    if (infoPtr->Flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK) {
290        SCANLINE *tmp;
291
292        tmp = DstS;
293        DstS = DstM;
294        DstM = tmp;
295    }
296
297    if (infoPtr->Flags & HARDWARE_CURSOR_AND_SOURCE_WITH_MASK) {
298        for (y = pCurs->bits->height, pSrc = DstS, pMsk = DstM;
299             y--;
300             pSrc += DstPitch, pMsk += DstPitch, SrcS += SrcPitch, SrcM +=
301             SrcPitch) {
302            for (x = 0; x < Pitch; x++) {
303                pSrc[x] = SrcS[x] & SrcM[x];
304                pMsk[x] = SrcM[x];
305            }
306        }
307    }
308    else {
309        for (y = pCurs->bits->height, pSrc = DstS, pMsk = DstM;
310             y--;
311             pSrc += DstPitch, pMsk += DstPitch, SrcS += SrcPitch, SrcM +=
312             SrcPitch) {
313            for (x = 0; x < Pitch; x++) {
314                pSrc[x] = SrcS[x];
315                pMsk[x] = SrcM[x];
316            }
317        }
318    }
319
320    if (infoPtr->Flags & HARDWARE_CURSOR_NIBBLE_SWAPPED) {
321        int count = size;
322        unsigned char *pntr1 = (unsigned char *) DstS;
323        unsigned char *pntr2 = (unsigned char *) DstM;
324        unsigned char a, b;
325
326        while (count) {
327
328            a = *pntr1;
329            b = *pntr2;
330            *pntr1 = ((a & 0xF0) >> 4) | ((a & 0x0F) << 4);
331            *pntr2 = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4);
332            pntr1++;
333            pntr2++;
334            count -= 2;
335        }
336    }
337
338    /*
339     * Must be _after_ HARDWARE_CURSOR_AND_SOURCE_WITH_MASK to avoid wiping
340     * out entire source mask.
341     */
342    if (infoPtr->Flags & HARDWARE_CURSOR_INVERT_MASK) {
343        int count = words;
344        SCANLINE *pntr = DstM;
345
346        while (count--) {
347            *pntr = ~(*pntr);
348            pntr++;
349        }
350    }
351
352    if (infoPtr->Flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) {
353        for (y = pCurs->bits->height, pSrc = DstS, pMsk = DstM;
354             y--; pSrc += DstPitch, pMsk += DstPitch) {
355            for (x = 0; x < Pitch; x++) {
356                pSrc[x] = REVERSE_BIT_ORDER(pSrc[x]);
357                pMsk[x] = REVERSE_BIT_ORDER(pMsk[x]);
358            }
359        }
360    }
361
362    return mem;
363}
364
365static unsigned char *
366RealizeCursorInterleave1(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
367{
368    unsigned char *DstS, *DstM;
369    unsigned char *pntr;
370    unsigned char *mem, *mem2;
371    int count;
372    int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2;
373
374    /* Realize the cursor without interleaving */
375    if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs)))
376        return NULL;
377
378    if (!(mem = calloc(1, size))) {
379        free(mem2);
380        return NULL;
381    }
382
383    /* 1 bit interleave */
384    DstS = mem2;
385    DstM = DstS + (size >> 1);
386    pntr = mem;
387    count = size;
388    while (count) {
389        *pntr++ = ((*DstS & 0x01)) | ((*DstM & 0x01) << 1) |
390            ((*DstS & 0x02) << 1) | ((*DstM & 0x02) << 2) |
391            ((*DstS & 0x04) << 2) | ((*DstM & 0x04) << 3) |
392            ((*DstS & 0x08) << 3) | ((*DstM & 0x08) << 4);
393        *pntr++ = ((*DstS & 0x10) >> 4) | ((*DstM & 0x10) >> 3) |
394            ((*DstS & 0x20) >> 3) | ((*DstM & 0x20) >> 2) |
395            ((*DstS & 0x40) >> 2) | ((*DstM & 0x40) >> 1) |
396            ((*DstS & 0x80) >> 1) | ((*DstM & 0x80));
397        DstS++;
398        DstM++;
399        count -= 2;
400    }
401
402    /* Free the uninterleaved cursor */
403    free(mem2);
404
405    return mem;
406}
407
408static unsigned char *
409RealizeCursorInterleave8(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
410{
411    unsigned char *DstS, *DstM;
412    unsigned char *pntr;
413    unsigned char *mem, *mem2;
414    int count;
415    int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2;
416
417    /* Realize the cursor without interleaving */
418    if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs)))
419        return NULL;
420
421    if (!(mem = calloc(1, size))) {
422        free(mem2);
423        return NULL;
424    }
425
426    /* 8 bit interleave */
427    DstS = mem2;
428    DstM = DstS + (size >> 1);
429    pntr = mem;
430    count = size;
431    while (count) {
432        *pntr++ = *DstS++;
433        *pntr++ = *DstM++;
434        count -= 2;
435    }
436
437    /* Free the uninterleaved cursor */
438    free(mem2);
439
440    return mem;
441}
442
443static unsigned char *
444RealizeCursorInterleave16(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
445{
446    unsigned short *DstS, *DstM;
447    unsigned short *pntr;
448    unsigned char *mem, *mem2;
449    int count;
450    int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2;
451
452    /* Realize the cursor without interleaving */
453    if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs)))
454        return NULL;
455
456    if (!(mem = calloc(1, size))) {
457        free(mem2);
458        return NULL;
459    }
460
461    /* 16 bit interleave */
462    DstS = (void *) mem2;
463    DstM = DstS + (size >> 2);
464    pntr = (void *) mem;
465    count = (size >> 1);
466    while (count) {
467        *pntr++ = *DstS++;
468        *pntr++ = *DstM++;
469        count -= 2;
470    }
471
472    /* Free the uninterleaved cursor */
473    free(mem2);
474
475    return mem;
476}
477
478static unsigned char *
479RealizeCursorInterleave32(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
480{
481    CARD32 *DstS, *DstM;
482    CARD32 *pntr;
483    unsigned char *mem, *mem2;
484    int count;
485    int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2;
486
487    /* Realize the cursor without interleaving */
488    if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs)))
489        return NULL;
490
491    if (!(mem = calloc(1, size))) {
492        free(mem2);
493        return NULL;
494    }
495
496    /* 32 bit interleave */
497    DstS = (void *) mem2;
498    DstM = DstS + (size >> 3);
499    pntr = (void *) mem;
500    count = (size >> 2);
501    while (count) {
502        *pntr++ = *DstS++;
503        *pntr++ = *DstM++;
504        count -= 2;
505    }
506
507    /* Free the uninterleaved cursor */
508    free(mem2);
509
510    return mem;
511}
512
513static unsigned char *
514RealizeCursorInterleave64(xf86CursorInfoPtr infoPtr, CursorPtr pCurs)
515{
516    CARD32 *DstS, *DstM;
517    CARD32 *pntr;
518    unsigned char *mem, *mem2;
519    int count;
520    int size = (infoPtr->MaxWidth * infoPtr->MaxHeight) >> 2;
521
522    /* Realize the cursor without interleaving */
523    if (!(mem2 = RealizeCursorInterleave0(infoPtr, pCurs)))
524        return NULL;
525
526    if (!(mem = calloc(1, size))) {
527        free(mem2);
528        return NULL;
529    }
530
531    /* 64 bit interleave */
532    DstS = (void *) mem2;
533    DstM = DstS + (size >> 3);
534    pntr = (void *) mem;
535    count = (size >> 2);
536    while (count) {
537        *pntr++ = *DstS++;
538        *pntr++ = *DstS++;
539        *pntr++ = *DstM++;
540        *pntr++ = *DstM++;
541        count -= 4;
542    }
543
544    /* Free the uninterleaved cursor */
545    free(mem2);
546
547    return mem;
548}
549