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