1 /*
2  * Copyright © 2007 Keith Packard
3  * Copyright © 2010-2011 Aaron Plattner
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that copyright
8  * notice and this permission notice appear in supporting documentation, and
9  * that the name of the copyright holders not be used in advertising or
10  * publicity pertaining to distribution of the software without specific,
11  * written prior permission.  The copyright holders make no representations
12  * about the suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21  * OF THIS SOFTWARE.
22  */
23 
24 #ifdef HAVE_XORG_CONFIG_H
25 #include <xorg-config.h>
26 #endif
27 
28 #include <stddef.h>
29 #include <string.h>
30 #include <stdio.h>
31 
32 #include <X11/Xarch.h>
33 #include "xf86.h"
34 #include "xf86DDC.h"
35 #include "xf86Crtc.h"
36 #include "xf86Modes.h"
37 #include "xf86RandR12.h"
38 #include "xf86CursorPriv.h"
39 #include "X11/extensions/render.h"
40 #include "X11/extensions/dpmsconst.h"
41 #include "X11/Xatom.h"
42 #include "picturestr.h"
43 #include "cursorstr.h"
44 #include "inputstr.h"
45 
46 /*
47  * Returns the rotation being performed by the server.  If the driver indicates
48  * that it's handling the screen transform, then this returns RR_Rotate_0.
49  */
50 static Rotation
xf86_crtc_cursor_rotation(xf86CrtcPtr crtc)51 xf86_crtc_cursor_rotation(xf86CrtcPtr crtc)
52 {
53     if (crtc->driverIsPerformingTransform & XF86DriverTransformCursorImage)
54         return RR_Rotate_0;
55     return crtc->rotation;
56 }
57 
58 /*
59  * Given a screen coordinate, rotate back to a cursor source coordinate
60  */
61 static void
xf86_crtc_rotate_coord(Rotation rotation,int width,int height,int x_dst,int y_dst,int * x_src,int * y_src)62 xf86_crtc_rotate_coord(Rotation rotation,
63                        int width,
64                        int height, int x_dst, int y_dst, int *x_src, int *y_src)
65 {
66     int t;
67 
68     switch (rotation & 0xf) {
69     case RR_Rotate_0:
70         break;
71     case RR_Rotate_90:
72         t = x_dst;
73         x_dst = width - y_dst - 1;
74         y_dst = t;
75         break;
76     case RR_Rotate_180:
77         x_dst = width - x_dst - 1;
78         y_dst = height - y_dst - 1;
79         break;
80     case RR_Rotate_270:
81         t = x_dst;
82         x_dst = y_dst;
83         y_dst = height - t - 1;
84         break;
85     }
86     if (rotation & RR_Reflect_X)
87         x_dst = width - x_dst - 1;
88     if (rotation & RR_Reflect_Y)
89         y_dst = height - y_dst - 1;
90     *x_src = x_dst;
91     *y_src = y_dst;
92 }
93 
94 /*
95  * Given a cursor source  coordinate, rotate to a screen coordinate
96  */
97 static void
xf86_crtc_rotate_coord_back(Rotation rotation,int width,int height,int x_dst,int y_dst,int * x_src,int * y_src)98 xf86_crtc_rotate_coord_back(Rotation rotation,
99                             int width,
100                             int height,
101                             int x_dst, int y_dst, int *x_src, int *y_src)
102 {
103     int t;
104 
105     if (rotation & RR_Reflect_X)
106         x_dst = width - x_dst - 1;
107     if (rotation & RR_Reflect_Y)
108         y_dst = height - y_dst - 1;
109 
110     switch (rotation & 0xf) {
111     case RR_Rotate_0:
112         break;
113     case RR_Rotate_90:
114         t = x_dst;
115         x_dst = y_dst;
116         y_dst = width - t - 1;
117         break;
118     case RR_Rotate_180:
119         x_dst = width - x_dst - 1;
120         y_dst = height - y_dst - 1;
121         break;
122     case RR_Rotate_270:
123         t = x_dst;
124         x_dst = height - y_dst - 1;
125         y_dst = t;
126         break;
127     }
128     *x_src = x_dst;
129     *y_src = y_dst;
130 }
131 
132 struct cursor_bit {
133     CARD8 *byte;
134     char bitpos;
135 };
136 
137 /*
138  * Convert an x coordinate to a position within the cursor bitmap
139  */
140 static struct cursor_bit
cursor_bitpos(CARD8 * image,xf86CursorInfoPtr cursor_info,int x,int y,Bool mask)141 cursor_bitpos(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y,
142               Bool mask)
143 {
144     const int flags = cursor_info->Flags;
145     const Bool interleaved =
146         ! !(flags & (HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
147                      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8 |
148                      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16 |
149                      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
150                      HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64));
151     const int width = cursor_info->MaxWidth;
152     const int height = cursor_info->MaxHeight;
153     const int stride = interleaved ? width / 4 : width / 8;
154 
155     struct cursor_bit ret;
156 
157     image += y * stride;
158 
159     if (flags & HARDWARE_CURSOR_SWAP_SOURCE_AND_MASK)
160         mask = !mask;
161     if (flags & HARDWARE_CURSOR_NIBBLE_SWAPPED)
162         x = (x & ~3) | (3 - (x & 3));
163     if (((flags & HARDWARE_CURSOR_BIT_ORDER_MSBFIRST) == 0) ==
164         (X_BYTE_ORDER == X_BIG_ENDIAN))
165         x = (x & ~7) | (7 - (x & 7));
166     if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1)
167         x = (x << 1) + mask;
168     else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_8)
169         x = ((x & ~7) << 1) | (mask << 3) | (x & 7);
170     else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_16)
171         x = ((x & ~15) << 1) | (mask << 4) | (x & 15);
172     else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32)
173         x = ((x & ~31) << 1) | (mask << 5) | (x & 31);
174     else if (flags & HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64)
175         x = ((x & ~63) << 1) | (mask << 6) | (x & 63);
176     else if (mask)
177         image += stride * height;
178 
179     ret.byte = image + (x / 8);
180     ret.bitpos = x & 7;
181 
182     return ret;
183 }
184 
185 /*
186  * Fetch one bit from a cursor bitmap
187  */
188 static CARD8
get_bit(CARD8 * image,xf86CursorInfoPtr cursor_info,int x,int y,Bool mask)189 get_bit(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
190 {
191     struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
192 
193     return (*bit.byte >> bit.bitpos) & 1;
194 }
195 
196 /*
197  * Set one bit in a cursor bitmap
198  */
199 static void
set_bit(CARD8 * image,xf86CursorInfoPtr cursor_info,int x,int y,Bool mask)200 set_bit(CARD8 *image, xf86CursorInfoPtr cursor_info, int x, int y, Bool mask)
201 {
202     struct cursor_bit bit = cursor_bitpos(image, cursor_info, x, y, mask);
203 
204     *bit.byte |= 1 << bit.bitpos;
205 }
206 
207 /*
208  * Wrappers to deal with API compatibility with drivers that don't expose
209  * *_cursor_*_check
210  */
211 static inline Bool
xf86_driver_has_show_cursor(xf86CrtcPtr crtc)212 xf86_driver_has_show_cursor(xf86CrtcPtr crtc)
213 {
214     return crtc->funcs->show_cursor_check || crtc->funcs->show_cursor;
215 }
216 
217 static inline Bool
xf86_driver_has_load_cursor_image(xf86CrtcPtr crtc)218 xf86_driver_has_load_cursor_image(xf86CrtcPtr crtc)
219 {
220     return crtc->funcs->load_cursor_image_check || crtc->funcs->load_cursor_image;
221 }
222 
223 static inline Bool
xf86_driver_has_load_cursor_argb(xf86CrtcPtr crtc)224 xf86_driver_has_load_cursor_argb(xf86CrtcPtr crtc)
225 {
226     return crtc->funcs->load_cursor_argb_check || crtc->funcs->load_cursor_argb;
227 }
228 
229 static inline Bool
xf86_driver_show_cursor(xf86CrtcPtr crtc)230 xf86_driver_show_cursor(xf86CrtcPtr crtc)
231 {
232     if (crtc->funcs->show_cursor_check)
233         return crtc->funcs->show_cursor_check(crtc);
234     crtc->funcs->show_cursor(crtc);
235     return TRUE;
236 }
237 
238 static inline Bool
xf86_driver_load_cursor_image(xf86CrtcPtr crtc,CARD8 * cursor_image)239 xf86_driver_load_cursor_image(xf86CrtcPtr crtc, CARD8 *cursor_image)
240 {
241     if (crtc->funcs->load_cursor_image_check)
242         return crtc->funcs->load_cursor_image_check(crtc, cursor_image);
243     crtc->funcs->load_cursor_image(crtc, cursor_image);
244     return TRUE;
245 }
246 
247 static inline Bool
xf86_driver_load_cursor_argb(xf86CrtcPtr crtc,CARD32 * cursor_argb)248 xf86_driver_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *cursor_argb)
249 {
250     if (crtc->funcs->load_cursor_argb_check)
251         return crtc->funcs->load_cursor_argb_check(crtc, cursor_argb);
252     crtc->funcs->load_cursor_argb(crtc, cursor_argb);
253     return TRUE;
254 }
255 
256 /*
257  * Load a two color cursor into a driver that supports only ARGB cursors
258  */
259 static Bool
xf86_crtc_convert_cursor_to_argb(xf86CrtcPtr crtc,unsigned char * src)260 xf86_crtc_convert_cursor_to_argb(xf86CrtcPtr crtc, unsigned char *src)
261 {
262     ScrnInfoPtr scrn = crtc->scrn;
263     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
264     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
265     CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
266     int x, y;
267     int xin, yin;
268     int flags = cursor_info->Flags;
269     CARD32 bits;
270     const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
271 
272     crtc->cursor_argb = FALSE;
273 
274     for (y = 0; y < cursor_info->MaxHeight; y++)
275         for (x = 0; x < cursor_info->MaxWidth; x++) {
276             xf86_crtc_rotate_coord(rotation,
277                                    cursor_info->MaxWidth,
278                                    cursor_info->MaxHeight, x, y, &xin, &yin);
279             if (get_bit(src, cursor_info, xin, yin, TRUE) ==
280                 ((flags & HARDWARE_CURSOR_INVERT_MASK) == 0)) {
281                 if (get_bit(src, cursor_info, xin, yin, FALSE))
282                     bits = xf86_config->cursor_fg;
283                 else
284                     bits = xf86_config->cursor_bg;
285             }
286             else
287                 bits = 0;
288             cursor_image[y * cursor_info->MaxWidth + x] = bits;
289         }
290     return xf86_driver_load_cursor_argb(crtc, cursor_image);
291 }
292 
293 /*
294  * Set the colors for a two-color cursor (ignore for ARGB cursors)
295  */
296 static void
xf86_set_cursor_colors(ScrnInfoPtr scrn,int bg,int fg)297 xf86_set_cursor_colors(ScrnInfoPtr scrn, int bg, int fg)
298 {
299     ScreenPtr screen = scrn->pScreen;
300     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
301     CursorPtr cursor = xf86CurrentCursor(screen);
302     int c;
303     CARD8 *bits = cursor ?
304         dixLookupScreenPrivate(&cursor->devPrivates, CursorScreenKey, screen)
305         : NULL;
306 
307     /* Save ARGB versions of these colors */
308     xf86_config->cursor_fg = (CARD32) fg | 0xff000000;
309     xf86_config->cursor_bg = (CARD32) bg | 0xff000000;
310 
311     for (c = 0; c < xf86_config->num_crtc; c++) {
312         xf86CrtcPtr crtc = xf86_config->crtc[c];
313 
314         if (crtc->enabled && !crtc->cursor_argb) {
315             if (xf86_driver_has_load_cursor_image(crtc))
316                 crtc->funcs->set_cursor_colors(crtc, bg, fg);
317             else if (bits)
318                 xf86_crtc_convert_cursor_to_argb(crtc, bits);
319         }
320     }
321 }
322 
323 void
xf86_crtc_hide_cursor(xf86CrtcPtr crtc)324 xf86_crtc_hide_cursor(xf86CrtcPtr crtc)
325 {
326     if (crtc->cursor_shown) {
327         crtc->funcs->hide_cursor(crtc);
328         crtc->cursor_shown = FALSE;
329     }
330 }
331 
332 void
xf86_hide_cursors(ScrnInfoPtr scrn)333 xf86_hide_cursors(ScrnInfoPtr scrn)
334 {
335     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
336     int c;
337 
338     xf86_config->cursor_on = FALSE;
339     for (c = 0; c < xf86_config->num_crtc; c++) {
340         xf86CrtcPtr crtc = xf86_config->crtc[c];
341 
342         if (crtc->enabled)
343             xf86_crtc_hide_cursor(crtc);
344     }
345 }
346 
347 Bool
xf86_crtc_show_cursor(xf86CrtcPtr crtc)348 xf86_crtc_show_cursor(xf86CrtcPtr crtc)
349 {
350     if (!crtc->cursor_in_range) {
351         crtc->funcs->hide_cursor(crtc);
352         return TRUE;
353     }
354 
355     if (!crtc->cursor_shown)
356         crtc->cursor_shown = xf86_driver_show_cursor(crtc);
357 
358     return crtc->cursor_shown;
359 }
360 
361 Bool
xf86_show_cursors(ScrnInfoPtr scrn)362 xf86_show_cursors(ScrnInfoPtr scrn)
363 {
364     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
365     int c;
366 
367     xf86_config->cursor_on = TRUE;
368     for (c = 0; c < xf86_config->num_crtc; c++) {
369         xf86CrtcPtr crtc = xf86_config->crtc[c];
370 
371         if (crtc->enabled && !xf86_crtc_show_cursor(crtc))
372             return FALSE;
373     }
374 
375     return TRUE;
376 }
377 
378 static void
xf86_crtc_transform_cursor_position(xf86CrtcPtr crtc,int * x,int * y)379 xf86_crtc_transform_cursor_position(xf86CrtcPtr crtc, int *x, int *y)
380 {
381     ScrnInfoPtr scrn = crtc->scrn;
382     ScreenPtr screen = scrn->pScreen;
383     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
384     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
385     xf86CursorScreenPtr ScreenPriv =
386         (xf86CursorScreenPtr) dixLookupPrivate(&screen->devPrivates,
387                                                xf86CursorScreenKey);
388     int dx, dy, t;
389     Bool swap_reflection = FALSE;
390 
391     *x = *x - crtc->x + ScreenPriv->HotX;
392     *y = *y - crtc->y + ScreenPriv->HotY;
393 
394     switch (crtc->rotation & 0xf) {
395     case RR_Rotate_0:
396         break;
397     case RR_Rotate_90:
398         t = *x;
399         *x = *y;
400         *y = crtc->mode.VDisplay - t - 1;
401         swap_reflection = TRUE;
402         break;
403     case RR_Rotate_180:
404         *x = crtc->mode.HDisplay - *x - 1;
405         *y = crtc->mode.VDisplay - *y - 1;
406         break;
407     case RR_Rotate_270:
408         t = *x;
409         *x = crtc->mode.HDisplay - *y - 1;
410         *y = t;
411         swap_reflection = TRUE;
412         break;
413     }
414 
415     if (swap_reflection) {
416         if (crtc->rotation & RR_Reflect_Y)
417             *x = crtc->mode.HDisplay - *x - 1;
418         if (crtc->rotation & RR_Reflect_X)
419             *y = crtc->mode.VDisplay - *y - 1;
420     } else {
421         if (crtc->rotation & RR_Reflect_X)
422             *x = crtc->mode.HDisplay - *x - 1;
423         if (crtc->rotation & RR_Reflect_Y)
424             *y = crtc->mode.VDisplay - *y - 1;
425     }
426 
427     /*
428      * Transform position of cursor upper left corner
429      */
430     xf86_crtc_rotate_coord_back(crtc->rotation, cursor_info->MaxWidth,
431                                 cursor_info->MaxHeight, ScreenPriv->HotX,
432                                 ScreenPriv->HotY, &dx, &dy);
433     *x -= dx;
434     *y -= dy;
435 }
436 
437 static void
xf86_crtc_set_cursor_position(xf86CrtcPtr crtc,int x,int y)438 xf86_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
439 {
440     ScrnInfoPtr scrn = crtc->scrn;
441     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
442     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
443     DisplayModePtr mode = &crtc->mode;
444     int crtc_x = x, crtc_y = y;
445 
446     /*
447      * Transform position of cursor on screen
448      */
449     if (crtc->rotation != RR_Rotate_0)
450         xf86_crtc_transform_cursor_position(crtc, &crtc_x, &crtc_y);
451     else {
452         crtc_x -= crtc->x;
453         crtc_y -= crtc->y;
454     }
455 
456     /*
457      * Disable the cursor when it is outside the viewport
458      */
459     if (crtc_x >= mode->HDisplay || crtc_y >= mode->VDisplay ||
460         crtc_x <= -cursor_info->MaxWidth || crtc_y <= -cursor_info->MaxHeight) {
461         crtc->cursor_in_range = FALSE;
462         xf86_crtc_hide_cursor(crtc);
463     } else {
464         crtc->cursor_in_range = TRUE;
465         if (crtc->driverIsPerformingTransform & XF86DriverTransformCursorPosition)
466             crtc->funcs->set_cursor_position(crtc, x, y);
467         else
468             crtc->funcs->set_cursor_position(crtc, crtc_x, crtc_y);
469         xf86_crtc_show_cursor(crtc);
470     }
471 }
472 
473 static void
xf86_set_cursor_position(ScrnInfoPtr scrn,int x,int y)474 xf86_set_cursor_position(ScrnInfoPtr scrn, int x, int y)
475 {
476     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
477     int c;
478 
479     /* undo what xf86HWCurs did to the coordinates */
480     x += scrn->frameX0;
481     y += scrn->frameY0;
482     for (c = 0; c < xf86_config->num_crtc; c++) {
483         xf86CrtcPtr crtc = xf86_config->crtc[c];
484 
485         if (crtc->enabled)
486             xf86_crtc_set_cursor_position(crtc, x, y);
487     }
488 }
489 
490 /*
491  * Load a two-color cursor into a crtc, performing rotation as needed
492  */
493 static Bool
xf86_crtc_load_cursor_image(xf86CrtcPtr crtc,CARD8 * src)494 xf86_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *src)
495 {
496     ScrnInfoPtr scrn = crtc->scrn;
497     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
498     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
499     CARD8 *cursor_image;
500     const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
501 
502     crtc->cursor_argb = FALSE;
503 
504     if (rotation == RR_Rotate_0)
505         cursor_image = src;
506     else {
507         int x, y;
508         int xin, yin;
509         int stride = cursor_info->MaxWidth >> 2;
510 
511         cursor_image = xf86_config->cursor_image;
512         memset(cursor_image, 0, cursor_info->MaxHeight * stride);
513 
514         for (y = 0; y < cursor_info->MaxHeight; y++)
515             for (x = 0; x < cursor_info->MaxWidth; x++) {
516                 xf86_crtc_rotate_coord(rotation,
517                                        cursor_info->MaxWidth,
518                                        cursor_info->MaxHeight,
519                                        x, y, &xin, &yin);
520                 if (get_bit(src, cursor_info, xin, yin, FALSE))
521                     set_bit(cursor_image, cursor_info, x, y, FALSE);
522                 if (get_bit(src, cursor_info, xin, yin, TRUE))
523                     set_bit(cursor_image, cursor_info, x, y, TRUE);
524             }
525     }
526     return xf86_driver_load_cursor_image(crtc, cursor_image);
527 }
528 
529 /*
530  * Load a cursor image into all active CRTCs
531  */
532 static Bool
xf86_load_cursor_image(ScrnInfoPtr scrn,unsigned char * src)533 xf86_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src)
534 {
535     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
536     int c;
537 
538     xf86_config->cursor = xf86CurrentCursor(scrn->pScreen);
539     for (c = 0; c < xf86_config->num_crtc; c++) {
540         xf86CrtcPtr crtc = xf86_config->crtc[c];
541 
542         if (crtc->enabled) {
543             if (xf86_driver_has_load_cursor_image(crtc)) {
544                 if (!xf86_crtc_load_cursor_image(crtc, src))
545                     return FALSE;
546             } else if (xf86_driver_has_load_cursor_argb(crtc)) {
547                 if (!xf86_crtc_convert_cursor_to_argb(crtc, src))
548                     return FALSE;
549             } else
550                 return FALSE;
551         }
552     }
553     return TRUE;
554 }
555 
556 static Bool
xf86_use_hw_cursor(ScreenPtr screen,CursorPtr cursor)557 xf86_use_hw_cursor(ScreenPtr screen, CursorPtr cursor)
558 {
559     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
560     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
561     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
562     int c;
563 
564     if (cursor->bits->width > cursor_info->MaxWidth ||
565         cursor->bits->height > cursor_info->MaxHeight)
566         return FALSE;
567 
568     for (c = 0; c < xf86_config->num_crtc; c++) {
569         xf86CrtcPtr crtc = xf86_config->crtc[c];
570 
571         if (!crtc->enabled)
572             continue;
573 
574         if (crtc->transformPresent)
575             return FALSE;
576     }
577 
578     return TRUE;
579 }
580 
581 static Bool
xf86_use_hw_cursor_argb(ScreenPtr screen,CursorPtr cursor)582 xf86_use_hw_cursor_argb(ScreenPtr screen, CursorPtr cursor)
583 {
584     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
585     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
586     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
587 
588     if (!xf86_use_hw_cursor(screen, cursor))
589         return FALSE;
590 
591     /* Make sure ARGB support is available */
592     if ((cursor_info->Flags & HARDWARE_CURSOR_ARGB) == 0)
593         return FALSE;
594 
595     return TRUE;
596 }
597 
598 static Bool
xf86_crtc_load_cursor_argb(xf86CrtcPtr crtc,CursorPtr cursor)599 xf86_crtc_load_cursor_argb(xf86CrtcPtr crtc, CursorPtr cursor)
600 {
601     ScrnInfoPtr scrn = crtc->scrn;
602     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
603     xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
604     CARD32 *cursor_image = (CARD32 *) xf86_config->cursor_image;
605     CARD32 *cursor_source = (CARD32 *) cursor->bits->argb;
606     int x, y;
607     int xin, yin;
608     CARD32 bits;
609     int source_width = cursor->bits->width;
610     int source_height = cursor->bits->height;
611     int image_width = cursor_info->MaxWidth;
612     int image_height = cursor_info->MaxHeight;
613     const Rotation rotation = xf86_crtc_cursor_rotation(crtc);
614 
615     for (y = 0; y < image_height; y++)
616         for (x = 0; x < image_width; x++) {
617             xf86_crtc_rotate_coord(rotation, image_width, image_height, x, y,
618                                    &xin, &yin);
619             if (xin < source_width && yin < source_height)
620                 bits = cursor_source[yin * source_width + xin];
621             else
622                 bits = 0;
623             cursor_image[y * image_width + x] = bits;
624         }
625 
626     return xf86_driver_load_cursor_argb(crtc, cursor_image);
627 }
628 
629 static Bool
xf86_load_cursor_argb(ScrnInfoPtr scrn,CursorPtr cursor)630 xf86_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor)
631 {
632     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
633     int c;
634 
635     xf86_config->cursor = cursor;
636     for (c = 0; c < xf86_config->num_crtc; c++) {
637         xf86CrtcPtr crtc = xf86_config->crtc[c];
638 
639         if (crtc->enabled)
640             if (!xf86_crtc_load_cursor_argb(crtc, cursor))
641                 return FALSE;
642     }
643     return TRUE;
644 }
645 
646 Bool
xf86_cursors_init(ScreenPtr screen,int max_width,int max_height,int flags)647 xf86_cursors_init(ScreenPtr screen, int max_width, int max_height, int flags)
648 {
649     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
650     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
651     xf86CursorInfoPtr cursor_info;
652 
653     cursor_info = xf86CreateCursorInfoRec();
654     if (!cursor_info)
655         return FALSE;
656 
657     xf86_config->cursor_image = malloc(max_width * max_height * 4);
658 
659     if (!xf86_config->cursor_image) {
660         xf86DestroyCursorInfoRec(cursor_info);
661         return FALSE;
662     }
663 
664     xf86_config->cursor_info = cursor_info;
665 
666     cursor_info->MaxWidth = max_width;
667     cursor_info->MaxHeight = max_height;
668     cursor_info->Flags = flags;
669 
670     cursor_info->SetCursorColors = xf86_set_cursor_colors;
671     cursor_info->SetCursorPosition = xf86_set_cursor_position;
672     cursor_info->LoadCursorImageCheck = xf86_load_cursor_image;
673     cursor_info->HideCursor = xf86_hide_cursors;
674     cursor_info->ShowCursorCheck = xf86_show_cursors;
675     cursor_info->UseHWCursor = xf86_use_hw_cursor;
676     if (flags & HARDWARE_CURSOR_ARGB) {
677         cursor_info->UseHWCursorARGB = xf86_use_hw_cursor_argb;
678         cursor_info->LoadCursorARGBCheck = xf86_load_cursor_argb;
679     }
680 
681     xf86_hide_cursors(scrn);
682 
683     return xf86InitCursor(screen, cursor_info);
684 }
685 
686 /**
687  * Clean up CRTC-based cursor code
688  */
689 void
xf86_cursors_fini(ScreenPtr screen)690 xf86_cursors_fini(ScreenPtr screen)
691 {
692     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
693     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
694 
695     if (xf86_config->cursor_info) {
696         xf86DestroyCursorInfoRec(xf86_config->cursor_info);
697         xf86_config->cursor_info = NULL;
698     }
699     free(xf86_config->cursor_image);
700     xf86_config->cursor_image = NULL;
701     xf86_config->cursor = NULL;
702 }
703