1 /*
2 * Copyright © 2013 Intel 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 "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 */
24
25 #include "igt.h"
26 #include <errno.h>
27 #include <limits.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <string.h>
31
32
33 IGT_TEST_DESCRIPTION(
34 "Use the display CRC support to validate cursor plane functionality. "
35 "The test will position the cursor plane either fully onscreen, "
36 "partially onscreen, or fully offscreen, using either a fully opaque "
37 "or fully transparent surface. In each case it then reads the PF CRC "
38 "and compares it with the CRC value obtained when the cursor plane "
39 "was disabled.");
40
41 #ifndef DRM_CAP_CURSOR_WIDTH
42 #define DRM_CAP_CURSOR_WIDTH 0x8
43 #endif
44 #ifndef DRM_CAP_CURSOR_HEIGHT
45 #define DRM_CAP_CURSOR_HEIGHT 0x9
46 #endif
47
48 typedef struct {
49 int drm_fd;
50 igt_display_t display;
51 struct igt_fb primary_fb;
52 struct igt_fb fb;
53 igt_output_t *output;
54 enum pipe pipe;
55 igt_crc_t ref_crc;
56 int left, right, top, bottom;
57 int screenw, screenh;
58 int refresh;
59 int curw, curh; /* cursor size */
60 int cursor_max_w, cursor_max_h;
61 igt_pipe_crc_t *pipe_crc;
62 unsigned flags;
63 } data_t;
64
65 #define TEST_DPMS (1<<0)
66 #define TEST_SUSPEND (1<<1)
67
draw_cursor(cairo_t * cr,int x,int y,int cw,int ch,double a)68 static void draw_cursor(cairo_t *cr, int x, int y, int cw, int ch, double a)
69 {
70 int wl, wr, ht, hb;
71
72 /* deal with odd cursor width/height */
73 wl = cw / 2;
74 wr = (cw + 1) / 2;
75 ht = ch / 2;
76 hb = (ch + 1) / 2;
77
78 /* Cairo doesn't like to be fed numbers that are too wild */
79 if ((x < SHRT_MIN) || (x > SHRT_MAX) || (y < SHRT_MIN) || (y > SHRT_MAX))
80 return;
81 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
82 /* 4 color rectangles in the corners, RGBY */
83 igt_paint_color_alpha(cr, x, y, wl, ht, 1.0, 0.0, 0.0, a);
84 igt_paint_color_alpha(cr, x + wl, y, wr, ht, 0.0, 1.0, 0.0, a);
85 igt_paint_color_alpha(cr, x, y + ht, wl, hb, 0.0, 0.0, 1.0, a);
86 igt_paint_color_alpha(cr, x + wl, y + ht, wr, hb, 0.5, 0.5, 0.5, a);
87 }
88
cursor_enable(data_t * data)89 static void cursor_enable(data_t *data)
90 {
91 igt_output_t *output = data->output;
92 igt_plane_t *cursor =
93 igt_output_get_plane_type(output, DRM_PLANE_TYPE_CURSOR);
94
95 igt_plane_set_fb(cursor, &data->fb);
96 igt_plane_set_size(cursor, data->curw, data->curh);
97 igt_fb_set_size(&data->fb, cursor, data->curw, data->curh);
98 }
99
cursor_disable(data_t * data)100 static void cursor_disable(data_t *data)
101 {
102 igt_output_t *output = data->output;
103 igt_plane_t *cursor =
104 igt_output_get_plane_type(output, DRM_PLANE_TYPE_CURSOR);
105
106 igt_plane_set_fb(cursor, NULL);
107 igt_plane_set_position(cursor, 0, 0);
108 }
109
chv_cursor_broken(data_t * data,int x)110 static bool chv_cursor_broken(data_t *data, int x)
111 {
112 uint32_t devid;
113
114 if (!is_i915_device(data->drm_fd))
115 return false;
116
117 devid = intel_get_drm_devid(data->drm_fd);
118
119 /*
120 * CHV gets a FIFO underrun on pipe C when cursor x coordinate
121 * is negative and the cursor visible.
122 *
123 * i915 is fixed to return -EINVAL on cursor updates with those
124 * negative coordinates, so require cursor update to fail with
125 * -EINVAL in that case.
126 *
127 * See also kms_chv_cursor_fail.c
128 */
129 if (x >= 0)
130 return false;
131
132 return IS_CHERRYVIEW(devid) && data->pipe == PIPE_C;
133 }
134
cursor_visible(data_t * data,int x,int y)135 static bool cursor_visible(data_t *data, int x, int y)
136 {
137 if (x + data->curw <= 0 || y + data->curh <= 0)
138 return false;
139
140 if (x >= data->screenw || y >= data->screenh)
141 return false;
142
143 return true;
144 }
145
do_single_test(data_t * data,int x,int y)146 static void do_single_test(data_t *data, int x, int y)
147 {
148 igt_display_t *display = &data->display;
149 igt_pipe_crc_t *pipe_crc = data->pipe_crc;
150 igt_crc_t crc, ref_crc;
151 igt_plane_t *cursor =
152 igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_CURSOR);
153 cairo_t *cr;
154 int ret = 0;
155
156 igt_print_activity();
157
158 /* Hardware test */
159 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
160 igt_paint_test_pattern(cr, data->screenw, data->screenh);
161 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
162
163 cursor_enable(data);
164 igt_plane_set_position(cursor, x, y);
165
166 if (chv_cursor_broken(data, x) && cursor_visible(data, x, y)) {
167 ret = igt_display_try_commit2(display, COMMIT_LEGACY);
168 igt_assert_eq(ret, -EINVAL);
169 igt_plane_set_position(cursor, 0, y);
170
171 return;
172 }
173
174 igt_display_commit(display);
175
176 igt_wait_for_vblank(data->drm_fd, data->pipe);
177 igt_pipe_crc_collect_crc(pipe_crc, &crc);
178
179 if (data->flags & (TEST_DPMS | TEST_SUSPEND)) {
180 igt_crc_t crc_after;
181
182 if (data->flags & TEST_DPMS) {
183 igt_debug("dpms off/on cycle\n");
184 kmstest_set_connector_dpms(data->drm_fd,
185 data->output->config.connector,
186 DRM_MODE_DPMS_OFF);
187 kmstest_set_connector_dpms(data->drm_fd,
188 data->output->config.connector,
189 DRM_MODE_DPMS_ON);
190 }
191
192 if (data->flags & TEST_SUSPEND)
193 igt_system_suspend_autoresume(SUSPEND_STATE_MEM,
194 SUSPEND_TEST_NONE);
195
196 igt_pipe_crc_collect_crc(pipe_crc, &crc_after);
197 igt_assert_crc_equal(&crc, &crc_after);
198 }
199
200 cursor_disable(data);
201 igt_display_commit(display);
202
203 /* Now render the same in software and collect crc */
204 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
205 draw_cursor(cr, x, y, data->curw, data->curh, 1.0);
206 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
207 igt_display_commit(display);
208
209 igt_wait_for_vblank(data->drm_fd, data->pipe);
210 igt_pipe_crc_collect_crc(pipe_crc, &ref_crc);
211 igt_assert_crc_equal(&crc, &ref_crc);
212
213 /* Clear screen afterwards */
214 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
215 igt_paint_color(cr, 0, 0, data->screenw, data->screenh, 0.0, 0.0, 0.0);
216 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
217 }
218
do_fail_test(data_t * data,int x,int y,int expect)219 static void do_fail_test(data_t *data, int x, int y, int expect)
220 {
221 igt_display_t *display = &data->display;
222 igt_plane_t *cursor =
223 igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_CURSOR);
224 cairo_t *cr;
225 int ret;
226
227 igt_print_activity();
228
229 /* Hardware test */
230 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
231 igt_paint_test_pattern(cr, data->screenw, data->screenh);
232 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
233
234 cursor_enable(data);
235 igt_plane_set_position(cursor, x, y);
236 ret = igt_display_try_commit2(display, COMMIT_LEGACY);
237
238 igt_plane_set_position(cursor, 0, 0);
239 cursor_disable(data);
240 igt_display_commit(display);
241
242 igt_assert_eq(ret, expect);
243 }
244
do_test(data_t * data,int left,int right,int top,int bottom)245 static void do_test(data_t *data,
246 int left, int right, int top, int bottom)
247 {
248 do_single_test(data, left, top);
249 do_single_test(data, right, top);
250 do_single_test(data, right, bottom);
251 do_single_test(data, left, bottom);
252 }
253
test_crc_onscreen(data_t * data)254 static void test_crc_onscreen(data_t *data)
255 {
256 int left = data->left;
257 int right = data->right;
258 int top = data->top;
259 int bottom = data->bottom;
260 int cursor_w = data->curw;
261 int cursor_h = data->curh;
262
263 /* fully inside */
264 do_test(data, left, right, top, bottom);
265
266 /* 2 pixels inside */
267 do_test(data, left - (cursor_w-2), right + (cursor_w-2), top , bottom );
268 do_test(data, left , right , top - (cursor_h-2), bottom + (cursor_h-2));
269 do_test(data, left - (cursor_w-2), right + (cursor_w-2), top - (cursor_h-2), bottom + (cursor_h-2));
270
271 /* 1 pixel inside */
272 do_test(data, left - (cursor_w-1), right + (cursor_w-1), top , bottom );
273 do_test(data, left , right , top - (cursor_h-1), bottom + (cursor_h-1));
274 do_test(data, left - (cursor_w-1), right + (cursor_w-1), top - (cursor_h-1), bottom + (cursor_h-1));
275 }
276
test_crc_offscreen(data_t * data)277 static void test_crc_offscreen(data_t *data)
278 {
279 int left = data->left;
280 int right = data->right;
281 int top = data->top;
282 int bottom = data->bottom;
283 int cursor_w = data->curw;
284 int cursor_h = data->curh;
285
286 /* fully outside */
287 do_test(data, left - (cursor_w), right + (cursor_w), top , bottom );
288 do_test(data, left , right , top - (cursor_h), bottom + (cursor_h));
289 do_test(data, left - (cursor_w), right + (cursor_w), top - (cursor_h), bottom + (cursor_h));
290
291 /* fully outside by 1 extra pixels */
292 do_test(data, left - (cursor_w+1), right + (cursor_w+1), top , bottom );
293 do_test(data, left , right , top - (cursor_h+1), bottom + (cursor_h+1));
294 do_test(data, left - (cursor_w+1), right + (cursor_w+1), top - (cursor_h+1), bottom + (cursor_h+1));
295
296 /* fully outside by 2 extra pixels */
297 do_test(data, left - (cursor_w+2), right + (cursor_w+2), top , bottom );
298 do_test(data, left , right , top - (cursor_h+2), bottom + (cursor_h+2));
299 do_test(data, left - (cursor_w+2), right + (cursor_w+2), top - (cursor_h+2), bottom + (cursor_h+2));
300
301 /* fully outside by a lot of extra pixels */
302 do_test(data, left - (cursor_w+512), right + (cursor_w+512), top , bottom );
303 do_test(data, left , right , top - (cursor_h+512), bottom + (cursor_h+512));
304 do_test(data, left - (cursor_w+512), right + (cursor_w+512), top - (cursor_h+512), bottom + (cursor_h+512));
305
306 /* go nuts */
307 do_test(data, INT_MIN, INT_MAX - cursor_w, INT_MIN, INT_MAX - cursor_h);
308 do_test(data, SHRT_MIN, SHRT_MAX, SHRT_MIN, SHRT_MAX);
309
310 /* Make sure we get -ERANGE on integer overflow */
311 do_fail_test(data, INT_MAX - cursor_w + 1, INT_MAX - cursor_h + 1, -ERANGE);
312 }
313
test_crc_sliding(data_t * data)314 static void test_crc_sliding(data_t *data)
315 {
316 int i;
317
318 /* Make sure cursor moves smoothly and pixel-by-pixel, and that there are
319 * no alignment issues. Horizontal, vertical and diagonal test.
320 */
321 for (i = 0; i < 16; i++) {
322 do_single_test(data, i, 0);
323 do_single_test(data, 0, i);
324 do_single_test(data, i, i);
325 }
326 }
327
test_crc_random(data_t * data)328 static void test_crc_random(data_t *data)
329 {
330 int i, max;
331
332 max = data->flags & (TEST_DPMS | TEST_SUSPEND) ? 2 : 50;
333
334 /* Random cursor placement */
335 for (i = 0; i < max; i++) {
336 int x = rand() % (data->screenw + data->curw * 2) - data->curw;
337 int y = rand() % (data->screenh + data->curh * 2) - data->curh;
338 do_single_test(data, x, y);
339 }
340 }
341
cleanup_crtc(data_t * data)342 static void cleanup_crtc(data_t *data)
343 {
344 igt_display_t *display = &data->display;
345
346 igt_pipe_crc_free(data->pipe_crc);
347 data->pipe_crc = NULL;
348
349 igt_remove_fb(data->drm_fd, &data->primary_fb);
350
351 igt_display_reset(display);
352 }
353
prepare_crtc(data_t * data,igt_output_t * output,int cursor_w,int cursor_h)354 static void prepare_crtc(data_t *data, igt_output_t *output,
355 int cursor_w, int cursor_h)
356 {
357 drmModeModeInfo *mode;
358 igt_display_t *display = &data->display;
359 igt_plane_t *primary;
360
361 cleanup_crtc(data);
362
363 /* select the pipe we want to use */
364 igt_output_set_pipe(output, data->pipe);
365
366 /* create and set the primary plane fb */
367 mode = igt_output_get_mode(output);
368 igt_create_color_fb(data->drm_fd, mode->hdisplay, mode->vdisplay,
369 DRM_FORMAT_XRGB8888,
370 LOCAL_DRM_FORMAT_MOD_NONE,
371 0.0, 0.0, 0.0,
372 &data->primary_fb);
373
374 primary = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
375 igt_plane_set_fb(primary, &data->primary_fb);
376
377 igt_display_commit(display);
378
379 /* create the pipe_crc object for this pipe */
380 data->pipe_crc = igt_pipe_crc_new(data->drm_fd, data->pipe,
381 INTEL_PIPE_CRC_SOURCE_AUTO);
382
383 /* x/y position where the cursor is still fully visible */
384 data->left = 0;
385 data->right = mode->hdisplay - cursor_w;
386 data->top = 0;
387 data->bottom = mode->vdisplay - cursor_h;
388 data->screenw = mode->hdisplay;
389 data->screenh = mode->vdisplay;
390 data->curw = cursor_w;
391 data->curh = cursor_h;
392 data->refresh = mode->vrefresh;
393
394 /* get reference crc w/o cursor */
395 igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
396 }
397
test_cursor_alpha(data_t * data,double a)398 static void test_cursor_alpha(data_t *data, double a)
399 {
400 igt_display_t *display = &data->display;
401 igt_pipe_crc_t *pipe_crc = data->pipe_crc;
402 igt_crc_t crc, ref_crc;
403 cairo_t *cr;
404 uint32_t fb_id;
405 int curw = data->curw;
406 int curh = data->curh;
407
408 /*alpha cursor fb*/
409 fb_id = igt_create_fb(data->drm_fd, curw, curh,
410 DRM_FORMAT_ARGB8888,
411 LOCAL_DRM_FORMAT_MOD_NONE,
412 &data->fb);
413 igt_assert(fb_id);
414 cr = igt_get_cairo_ctx(data->drm_fd, &data->fb);
415 igt_paint_color_alpha(cr, 0, 0, curw, curh, 1.0, 1.0, 1.0, a);
416 igt_put_cairo_ctx(data->drm_fd, &data->fb, cr);
417
418 /*Hardware Test*/
419 cursor_enable(data);
420 igt_display_commit(display);
421 igt_wait_for_vblank(data->drm_fd, data->pipe);
422 igt_pipe_crc_collect_crc(pipe_crc, &crc);
423 cursor_disable(data);
424 igt_remove_fb(data->drm_fd, &data->fb);
425
426 /*Software Test*/
427 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
428 igt_paint_color_alpha(cr, 0, 0, curw, curh, 1.0, 1.0, 1.0, a);
429 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
430
431 igt_display_commit(display);
432 igt_wait_for_vblank(data->drm_fd, data->pipe);
433 igt_pipe_crc_collect_crc(pipe_crc, &ref_crc);
434 igt_assert_crc_equal(&crc, &ref_crc);
435
436 /*Clear Screen*/
437 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
438 igt_paint_color(cr, 0, 0, data->screenw, data->screenh,
439 0.0, 0.0, 0.0);
440 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
441 }
442
test_cursor_transparent(data_t * data)443 static void test_cursor_transparent(data_t *data)
444 {
445 test_cursor_alpha(data, 0.0);
446
447 }
448
test_cursor_opaque(data_t * data)449 static void test_cursor_opaque(data_t *data)
450 {
451 test_cursor_alpha(data, 1.0);
452 }
453
run_test(data_t * data,void (* testfunc)(data_t *),int cursor_w,int cursor_h)454 static void run_test(data_t *data, void (*testfunc)(data_t *), int cursor_w, int cursor_h)
455 {
456 prepare_crtc(data, data->output, cursor_w, cursor_h);
457 testfunc(data);
458 }
459
create_cursor_fb(data_t * data,int cur_w,int cur_h)460 static void create_cursor_fb(data_t *data, int cur_w, int cur_h)
461 {
462 cairo_t *cr;
463 uint32_t fb_id;
464
465 /*
466 * Make the FB slightly taller and leave the extra
467 * line opaque white, so that we can see that the
468 * hardware won't scan beyond what it should (esp.
469 * with non-square cursors).
470 */
471 fb_id = igt_create_color_fb(data->drm_fd, cur_w, cur_h + 1,
472 DRM_FORMAT_ARGB8888,
473 LOCAL_DRM_FORMAT_MOD_NONE,
474 1.0, 1.0, 1.0,
475 &data->fb);
476
477 igt_assert(fb_id);
478
479 cr = igt_get_cairo_ctx(data->drm_fd, &data->fb);
480 draw_cursor(cr, 0, 0, cur_w, cur_h, 1.0);
481 igt_put_cairo_ctx(data->drm_fd, &data->fb, cr);
482 }
483
has_nonsquare_cursors(data_t * data)484 static bool has_nonsquare_cursors(data_t *data)
485 {
486 uint32_t devid;
487
488 if (!is_i915_device(data->drm_fd))
489 return false;
490
491 devid = intel_get_drm_devid(data->drm_fd);
492
493 /*
494 * Test non-square cursors a bit on the platforms
495 * that support such things.
496 */
497 if (devid == PCI_CHIP_845_G || devid == PCI_CHIP_I865_G)
498 return true;
499
500 if (IS_VALLEYVIEW(devid) || IS_CHERRYVIEW(devid))
501 return false;
502
503 return intel_gen(devid) >= 7;
504 }
505
test_cursor_size(data_t * data)506 static void test_cursor_size(data_t *data)
507 {
508 igt_display_t *display = &data->display;
509 igt_pipe_crc_t *pipe_crc = data->pipe_crc;
510 igt_crc_t crc[10], ref_crc;
511 cairo_t *cr;
512 uint32_t fb_id;
513 int i, size;
514 int cursor_max_size = data->cursor_max_w;
515 igt_plane_t *cursor =
516 igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_CURSOR);
517
518 /* Create a maximum size cursor, then change the size in flight to
519 * smaller ones to see that the size is applied correctly
520 */
521 fb_id = igt_create_fb(data->drm_fd, cursor_max_size, cursor_max_size,
522 DRM_FORMAT_ARGB8888, LOCAL_DRM_FORMAT_MOD_NONE,
523 &data->fb);
524 igt_assert(fb_id);
525
526 /* Use a solid white rectangle as the cursor */
527 cr = igt_get_cairo_ctx(data->drm_fd, &data->fb);
528 igt_paint_color_alpha(cr, 0, 0, cursor_max_size, cursor_max_size, 1.0, 1.0, 1.0, 1.0);
529 igt_put_cairo_ctx(data->drm_fd, &data->fb, cr);
530
531 /* Hardware test loop */
532 cursor_enable(data);
533 for (i = 0, size = cursor_max_size; size >= 64; size /= 2, i++) {
534 /* Change size in flight: */
535 igt_plane_set_size(cursor, size, size);
536 igt_fb_set_size(&data->fb, cursor, size, size);
537 igt_display_commit(display);
538 igt_wait_for_vblank(data->drm_fd, data->pipe);
539 igt_pipe_crc_collect_crc(pipe_crc, &crc[i]);
540 }
541 cursor_disable(data);
542 igt_display_commit(display);
543 igt_remove_fb(data->drm_fd, &data->fb);
544 /* Software test loop */
545 for (i = 0, size = cursor_max_size; size >= 64; size /= 2, i++) {
546 /* Now render the same in software and collect crc */
547 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
548 igt_paint_color_alpha(cr, 0, 0, size, size, 1.0, 1.0, 1.0, 1.0);
549 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
550
551 igt_display_commit(display);
552 igt_wait_for_vblank(data->drm_fd, data->pipe);
553 igt_pipe_crc_collect_crc(pipe_crc, &ref_crc);
554 /* Clear screen afterwards */
555 cr = igt_get_cairo_ctx(data->drm_fd, &data->primary_fb);
556 igt_paint_color(cr, 0, 0, data->screenw, data->screenh,
557 0.0, 0.0, 0.0);
558 igt_put_cairo_ctx(data->drm_fd, &data->primary_fb, cr);
559 igt_assert_crc_equal(&crc[i], &ref_crc);
560 }
561 }
562
test_rapid_movement(data_t * data)563 static void test_rapid_movement(data_t *data)
564 {
565 struct timeval start, end, delta;
566 int x = 0, y = 0;
567 long usec;
568 igt_display_t *display = &data->display;
569 igt_plane_t *cursor =
570 igt_output_get_plane_type(data->output, DRM_PLANE_TYPE_CURSOR);
571
572 cursor_enable(data);
573
574 gettimeofday(&start, NULL);
575 for ( ; x < 100; x++) {
576 igt_plane_set_position(cursor, x, y);
577 igt_display_commit(display);
578 }
579 for ( ; y < 100; y++) {
580 igt_plane_set_position(cursor, x, y);
581 igt_display_commit(display);
582 }
583 for ( ; x > 0; x--) {
584 igt_plane_set_position(cursor, x, y);
585 igt_display_commit(display);
586 }
587 for ( ; y > 0; y--) {
588 igt_plane_set_position(cursor, x, y);
589 igt_display_commit(display);
590 }
591 gettimeofday(&end, NULL);
592
593 /*
594 * We've done 400 cursor updates now. If we're being throttled to
595 * vblank, then that would take roughly 400/refresh seconds. If the
596 * elapsed time is greater than 90% of that value, we'll consider it
597 * a failure (since cursor updates shouldn't be throttled).
598 */
599 timersub(&end, &start, &delta);
600 usec = delta.tv_usec + 1000000 * delta.tv_sec;
601 igt_assert_lt(usec, 0.9 * 400 * 1000000 / data->refresh);
602 }
603
run_tests_on_pipe(data_t * data,enum pipe pipe)604 static void run_tests_on_pipe(data_t *data, enum pipe pipe)
605 {
606 int cursor_size;
607
608 igt_fixture {
609 data->pipe = pipe;
610 data->output = igt_get_single_output_for_pipe(&data->display, pipe);
611 igt_require(data->output);
612 }
613
614 igt_subtest_f("pipe-%s-cursor-size-change", kmstest_pipe_name(pipe))
615 run_test(data, test_cursor_size,
616 data->cursor_max_w, data->cursor_max_h);
617
618 igt_subtest_f("pipe-%s-cursor-alpha-opaque", kmstest_pipe_name(pipe))
619 run_test(data, test_cursor_opaque, data->cursor_max_w, data->cursor_max_h);
620
621 igt_subtest_f("pipe-%s-cursor-alpha-transparent", kmstest_pipe_name(pipe))
622 run_test(data, test_cursor_transparent, data->cursor_max_w, data->cursor_max_h);
623
624 igt_fixture
625 create_cursor_fb(data, data->cursor_max_w, data->cursor_max_h);
626
627 igt_subtest_f("pipe-%s-cursor-dpms", kmstest_pipe_name(pipe)) {
628 data->flags = TEST_DPMS;
629 run_test(data, test_crc_random, data->cursor_max_w, data->cursor_max_h);
630 }
631 data->flags = 0;
632
633 igt_subtest_f("pipe-%s-cursor-suspend", kmstest_pipe_name(pipe)) {
634 data->flags = TEST_SUSPEND;
635 run_test(data, test_crc_random, data->cursor_max_w, data->cursor_max_h);
636 }
637 data->flags = 0;
638
639 igt_fixture
640 igt_remove_fb(data->drm_fd, &data->fb);
641
642 for (cursor_size = 64; cursor_size <= 512; cursor_size *= 2) {
643 int w = cursor_size;
644 int h = cursor_size;
645
646 igt_fixture {
647 igt_require(w <= data->cursor_max_w &&
648 h <= data->cursor_max_h);
649
650 create_cursor_fb(data, w, h);
651 }
652
653 /* Using created cursor FBs to test cursor support */
654 igt_subtest_f("pipe-%s-cursor-%dx%d-onscreen", kmstest_pipe_name(pipe), w, h)
655 run_test(data, test_crc_onscreen, w, h);
656 igt_subtest_f("pipe-%s-cursor-%dx%d-offscreen", kmstest_pipe_name(pipe), w, h)
657 run_test(data, test_crc_offscreen, w, h);
658 igt_subtest_f("pipe-%s-cursor-%dx%d-sliding", kmstest_pipe_name(pipe), w, h)
659 run_test(data, test_crc_sliding, w, h);
660 igt_subtest_f("pipe-%s-cursor-%dx%d-random", kmstest_pipe_name(pipe), w, h)
661 run_test(data, test_crc_random, w, h);
662
663 igt_subtest_f("pipe-%s-cursor-%dx%d-rapid-movement", kmstest_pipe_name(pipe), w, h) {
664 run_test(data, test_rapid_movement, w, h);
665 }
666
667 igt_fixture
668 igt_remove_fb(data->drm_fd, &data->fb);
669
670 /*
671 * Test non-square cursors a bit on the platforms
672 * that support such things. And make it a bit more
673 * interesting by using a non-pot height.
674 */
675 h /= 3;
676
677 igt_fixture {
678 if (has_nonsquare_cursors(data))
679 create_cursor_fb(data, w, h);
680 }
681
682 /* Using created cursor FBs to test cursor support */
683 igt_subtest_f("pipe-%s-cursor-%dx%d-onscreen", kmstest_pipe_name(pipe), w, h) {
684 igt_require(has_nonsquare_cursors(data));
685 run_test(data, test_crc_onscreen, w, h);
686 }
687 igt_subtest_f("pipe-%s-cursor-%dx%d-offscreen", kmstest_pipe_name(pipe), w, h) {
688 igt_require(has_nonsquare_cursors(data));
689 run_test(data, test_crc_offscreen, w, h);
690 }
691 igt_subtest_f("pipe-%s-cursor-%dx%d-sliding", kmstest_pipe_name(pipe), w, h) {
692 igt_require(has_nonsquare_cursors(data));
693 run_test(data, test_crc_sliding, w, h);
694 }
695 igt_subtest_f("pipe-%s-cursor-%dx%d-random", kmstest_pipe_name(pipe), w, h) {
696 igt_require(has_nonsquare_cursors(data));
697 run_test(data, test_crc_random, w, h);
698 }
699
700 igt_fixture
701 igt_remove_fb(data->drm_fd, &data->fb);
702 }
703 }
704
705 static data_t data;
706
707 igt_main
708 {
709 uint64_t cursor_width = 64, cursor_height = 64;
710 int ret;
711 enum pipe pipe;
712
713 igt_skip_on_simulation();
714
715 igt_fixture {
716 data.drm_fd = drm_open_driver_master(DRIVER_ANY);
717
718 ret = drmGetCap(data.drm_fd, DRM_CAP_CURSOR_WIDTH, &cursor_width);
719 igt_assert(ret == 0 || errno == EINVAL);
720 /* Not making use of cursor_height since it is same as width, still reading */
721 ret = drmGetCap(data.drm_fd, DRM_CAP_CURSOR_HEIGHT, &cursor_height);
722 igt_assert(ret == 0 || errno == EINVAL);
723
724 /* We assume width and height are same so max is assigned width */
725 igt_assert_eq(cursor_width, cursor_height);
726
727 kmstest_set_vt_graphics_mode();
728
729 igt_require_pipe_crc(data.drm_fd);
730
731 igt_display_require(&data.display, data.drm_fd);
732 }
733
734 data.cursor_max_w = cursor_width;
735 data.cursor_max_h = cursor_height;
736
737 for_each_pipe_static(pipe)
738 igt_subtest_group
739 run_tests_on_pipe(&data, pipe);
740
741 igt_fixture {
742 igt_display_fini(&data.display);
743 }
744 }
745