1 /*
2 * Copyright © 2013,2014 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 <math.h>
27
28 #define MAX_FENCES 32
29 #define MAXMULTIPLANESAMOUNT 2
30
31 struct p_struct {
32 igt_plane_t *plane;
33 struct igt_fb fb;
34 };
35
36 enum p_pointorigo {
37 p_top = 1 << 0,
38 p_bottom = 1 << 1,
39 p_left = 1 << 2,
40 p_right = 1 << 3
41 };
42
43 struct p_point{
44 enum p_pointorigo origo;
45 float_t x;
46 float_t y;
47 };
48
49 typedef struct {
50 int gfx_fd;
51 igt_display_t display;
52 struct igt_fb fb;
53 struct igt_fb fb_reference;
54 struct igt_fb fb_unrotated;
55 struct igt_fb fb_flip;
56 igt_crc_t ref_crc;
57 igt_crc_t flip_crc;
58 igt_pipe_crc_t *pipe_crc;
59 igt_rotation_t rotation;
60 int pos_x;
61 int pos_y;
62 uint32_t override_fmt;
63 uint64_t override_tiling;
64 int devid;
65
66 struct p_struct *multiplaneoldview;
67 struct p_point planepos[MAXMULTIPLANESAMOUNT];
68 } data_t;
69
70 typedef struct {
71 float r;
72 float g;
73 float b;
74 } rgb_color_t;
75
set_color(rgb_color_t * color,float r,float g,float b)76 static void set_color(rgb_color_t *color, float r, float g, float b)
77 {
78 color->r = r;
79 color->g = g;
80 color->b = b;
81 }
82
rotate_colors(rgb_color_t * tl,rgb_color_t * tr,rgb_color_t * br,rgb_color_t * bl,igt_rotation_t rotation)83 static void rotate_colors(rgb_color_t *tl, rgb_color_t *tr, rgb_color_t *br,
84 rgb_color_t *bl, igt_rotation_t rotation)
85 {
86 rgb_color_t bl_tmp, br_tmp, tl_tmp, tr_tmp;
87
88 if (rotation & IGT_REFLECT_X) {
89 igt_swap(*tl, *tr);
90 igt_swap(*bl, *br);
91 }
92
93 if (rotation & IGT_ROTATION_90) {
94 bl_tmp = *bl;
95 br_tmp = *br;
96 tl_tmp = *tl;
97 tr_tmp = *tr;
98 *tl = tr_tmp;
99 *bl = tl_tmp;
100 *tr = br_tmp;
101 *br = bl_tmp;
102 } else if (rotation & IGT_ROTATION_180) {
103 igt_swap(*tl, *br);
104 igt_swap(*tr, *bl);
105 } else if (rotation & IGT_ROTATION_270) {
106 bl_tmp = *bl;
107 br_tmp = *br;
108 tl_tmp = *tl;
109 tr_tmp = *tr;
110 *tl = bl_tmp;
111 *bl = br_tmp;
112 *tr = tl_tmp;
113 *br = tr_tmp;
114 }
115 }
116
117 #define RGB_COLOR(color) \
118 color.r, color.g, color.b
119
120 static void
paint_squares(data_t * data,igt_rotation_t rotation,struct igt_fb * fb,float o)121 paint_squares(data_t *data, igt_rotation_t rotation,
122 struct igt_fb *fb, float o)
123 {
124 cairo_t *cr;
125 unsigned int w = fb->width;
126 unsigned int h = fb->height;
127 rgb_color_t tl, tr, bl, br;
128
129 igt_assert_f(!(w&1), "rotation image must be even width, now attempted %d\n", w);
130 igt_assert_f(!(h&1), "rotation image must be even height, now attempted %d\n", h);
131
132 cr = igt_get_cairo_ctx(data->gfx_fd, fb);
133
134 set_color(&tl, o, 0.0f, 0.0f);
135 set_color(&tr, 0.0f, o, 0.0f);
136 set_color(&br, o, o, o);
137 set_color(&bl, 0.0f, 0.0f, o);
138
139 rotate_colors(&tl, &tr, &br, &bl, rotation);
140
141 igt_paint_color(cr, 0, 0, w / 2, h / 2, RGB_COLOR(tl));
142 igt_paint_color(cr, w / 2, 0, w / 2, h / 2, RGB_COLOR(tr));
143 igt_paint_color(cr, 0, h / 2, w / 2, h / 2, RGB_COLOR(bl));
144 igt_paint_color(cr, w / 2, h / 2, w / 2, h / 2, RGB_COLOR(br));
145
146 igt_put_cairo_ctx(data->gfx_fd, fb, cr);
147 }
148
remove_fbs(data_t * data)149 static void remove_fbs(data_t *data)
150 {
151 igt_remove_fb(data->gfx_fd, &data->fb);
152 igt_remove_fb(data->gfx_fd, &data->fb_reference);
153 igt_remove_fb(data->gfx_fd, &data->fb_unrotated);
154 igt_remove_fb(data->gfx_fd, &data->fb_flip);
155 }
156
cleanup_crtc(data_t * data)157 static void cleanup_crtc(data_t *data)
158 {
159 igt_display_t *display = &data->display;
160
161 igt_pipe_crc_free(data->pipe_crc);
162 data->pipe_crc = NULL;
163
164 remove_fbs(data);
165
166 igt_display_reset(display);
167 }
168
prepare_crtc(data_t * data,igt_output_t * output,enum pipe pipe,igt_plane_t * plane,bool start_crc)169 static void prepare_crtc(data_t *data, igt_output_t *output, enum pipe pipe,
170 igt_plane_t *plane, bool start_crc)
171 {
172 igt_display_t *display = &data->display;
173
174 cleanup_crtc(data);
175
176 igt_output_set_pipe(output, pipe);
177 igt_plane_set_rotation(plane, IGT_ROTATION_0);
178
179 /* create the pipe_crc object for this pipe */
180 igt_pipe_crc_free(data->pipe_crc);
181
182 igt_display_commit2(display, COMMIT_ATOMIC);
183 data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
184
185 if (start_crc)
186 igt_pipe_crc_start(data->pipe_crc);
187 }
188
189 enum rectangle_type {
190 rectangle,
191 square,
192 portrait,
193 landscape,
194 num_rectangle_types /* must be last */
195 };
196
prepare_fbs(data_t * data,igt_output_t * output,igt_plane_t * plane,enum rectangle_type rect,uint32_t format)197 static void prepare_fbs(data_t *data, igt_output_t *output,
198 igt_plane_t *plane, enum rectangle_type rect, uint32_t format)
199 {
200 drmModeModeInfo *mode;
201 igt_display_t *display = &data->display;
202 unsigned int w, h, ref_w, ref_h, min_w, min_h;
203 uint64_t tiling = data->override_tiling ?: LOCAL_DRM_FORMAT_MOD_NONE;
204 uint32_t pixel_format = data->override_fmt ?: DRM_FORMAT_XRGB8888;
205 const float flip_opacity = 0.75;
206
207 remove_fbs(data);
208
209 igt_plane_set_rotation(plane, IGT_ROTATION_0);
210
211 mode = igt_output_get_mode(output);
212 if (plane->type != DRM_PLANE_TYPE_CURSOR) {
213 w = mode->hdisplay;
214 h = mode->vdisplay;
215
216 min_w = 256;
217 min_h = 256;
218 } else {
219 pixel_format = data->override_fmt ?: DRM_FORMAT_ARGB8888;
220
221 w = h = 256;
222 min_w = min_h = 64;
223 }
224
225 switch (rect) {
226 case rectangle:
227 break;
228 case square:
229 w = h = min(h, w);
230 break;
231 case portrait:
232 w = min_w;
233 break;
234 case landscape:
235 h = min_h;
236 break;
237 case num_rectangle_types:
238 igt_assert(0);
239 }
240
241 ref_w = w;
242 ref_h = h;
243
244 /*
245 * For 90/270, we will use create smaller fb so that the rotated
246 * frame can fit in
247 */
248 if (data->rotation & (IGT_ROTATION_90 | IGT_ROTATION_270)) {
249 tiling = data->override_tiling ?: LOCAL_I915_FORMAT_MOD_Y_TILED;
250
251 igt_swap(w, h);
252 }
253
254 /*
255 * Create a reference software rotated flip framebuffer.
256 */
257 igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format, tiling,
258 &data->fb_flip);
259 paint_squares(data, data->rotation, &data->fb_flip,
260 flip_opacity);
261 igt_plane_set_fb(plane, &data->fb_flip);
262 if (plane->type != DRM_PLANE_TYPE_CURSOR)
263 igt_plane_set_position(plane, data->pos_x, data->pos_y);
264 igt_display_commit2(display, COMMIT_ATOMIC);
265
266 igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &data->flip_crc);
267
268 /*
269 * Prepare the non-rotated flip fb.
270 */
271 igt_remove_fb(data->gfx_fd, &data->fb_flip);
272 igt_create_fb(data->gfx_fd, w, h, pixel_format, tiling,
273 &data->fb_flip);
274 paint_squares(data, IGT_ROTATION_0, &data->fb_flip,
275 flip_opacity);
276
277 /*
278 * Create a reference CRC for a software-rotated fb.
279 */
280 igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format,
281 data->override_tiling ?: LOCAL_DRM_FORMAT_MOD_NONE, &data->fb_reference);
282 paint_squares(data, data->rotation, &data->fb_reference, 1.0);
283
284 igt_plane_set_fb(plane, &data->fb_reference);
285 if (plane->type != DRM_PLANE_TYPE_CURSOR)
286 igt_plane_set_position(plane, data->pos_x, data->pos_y);
287 igt_display_commit2(display, COMMIT_ATOMIC);
288
289 igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &data->ref_crc);
290
291 /*
292 * Prepare the non-rotated reference fb.
293 */
294 igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format, tiling, &data->fb_unrotated);
295 paint_squares(data, IGT_ROTATION_0, &data->fb_unrotated, 1.0);
296 igt_plane_set_fb(plane, &data->fb_unrotated);
297 igt_plane_set_rotation(plane, IGT_ROTATION_0);
298 if (plane->type != DRM_PLANE_TYPE_CURSOR)
299 igt_plane_set_position(plane, data->pos_x, data->pos_y);
300 igt_display_commit2(display, COMMIT_ATOMIC);
301
302 /*
303 * Prepare the plane with an non-rotated fb let the hw rotate it.
304 */
305 igt_create_fb(data->gfx_fd, w, h, pixel_format, tiling, &data->fb);
306 paint_squares(data, IGT_ROTATION_0, &data->fb, 1.0);
307 igt_plane_set_fb(plane, &data->fb);
308
309 if (plane->type != DRM_PLANE_TYPE_CURSOR)
310 igt_plane_set_position(plane, data->pos_x, data->pos_y);
311 }
312
test_single_case(data_t * data,enum pipe pipe,igt_output_t * output,igt_plane_t * plane,enum rectangle_type rect,uint32_t format,bool test_bad_format)313 static void test_single_case(data_t *data, enum pipe pipe,
314 igt_output_t *output, igt_plane_t *plane,
315 enum rectangle_type rect,
316 uint32_t format, bool test_bad_format)
317 {
318 igt_display_t *display = &data->display;
319 igt_crc_t crc_output;
320 int ret;
321
322 igt_debug("Testing case %i on pipe %s, format %s\n", rect, kmstest_pipe_name(pipe), igt_format_str(format));
323 prepare_fbs(data, output, plane, rect, format);
324
325 igt_plane_set_rotation(plane, data->rotation);
326 if (data->rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
327 igt_plane_set_size(plane, data->fb.height, data->fb.width);
328
329 ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
330 if (test_bad_format) {
331 igt_assert_eq(ret, -EINVAL);
332 return;
333 }
334
335 /* Verify commit was ok. */
336 igt_assert_eq(ret, 0);
337
338 /* Check CRC */
339 igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc_output);
340 igt_assert_crc_equal(&data->ref_crc, &crc_output);
341
342 /*
343 * If flips are requested flip to a different fb and
344 * check CRC against that one as well.
345 */
346 if (data->fb_flip.fb_id) {
347 igt_plane_set_fb(plane, &data->fb_flip);
348 if (data->rotation == IGT_ROTATION_90 || data->rotation == IGT_ROTATION_270)
349 igt_plane_set_size(plane, data->fb.height, data->fb.width);
350
351 if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
352 igt_display_commit_atomic(display, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, NULL);
353 } else {
354 ret = drmModePageFlip(data->gfx_fd,
355 output->config.crtc->crtc_id,
356 data->fb_flip.fb_id,
357 DRM_MODE_PAGE_FLIP_EVENT,
358 NULL);
359 igt_assert_eq(ret, 0);
360 }
361 kmstest_wait_for_pageflip(data->gfx_fd);
362 igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc_output);
363 igt_assert_crc_equal(&data->flip_crc,
364 &crc_output);
365 }
366 }
367
test_plane_rotation(data_t * data,int plane_type,bool test_bad_format)368 static void test_plane_rotation(data_t *data, int plane_type, bool test_bad_format)
369 {
370 igt_display_t *display = &data->display;
371 igt_output_t *output;
372 enum pipe pipe;
373
374 if (plane_type == DRM_PLANE_TYPE_CURSOR)
375 igt_require(display->has_cursor_plane);
376
377 igt_display_require_output(display);
378
379 for_each_pipe_with_valid_output(display, pipe, output) {
380 igt_plane_t *plane;
381 int i, j;
382
383 if (IS_CHERRYVIEW(data->devid) && pipe != PIPE_B)
384 continue;
385
386 igt_output_set_pipe(output, pipe);
387
388 plane = igt_output_get_plane_type(output, plane_type);
389 igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
390
391 prepare_crtc(data, output, pipe, plane, true);
392
393 for (i = 0; i < num_rectangle_types; i++) {
394 /* Unsupported on i915 */
395 if (plane_type == DRM_PLANE_TYPE_CURSOR &&
396 i != square)
397 continue;
398
399 /* Only support partial covering primary plane on gen9+ */
400 if (plane_type == DRM_PLANE_TYPE_PRIMARY &&
401 i != rectangle && intel_gen(intel_get_drm_devid(data->gfx_fd)) < 9)
402 continue;
403
404 if (!data->override_fmt) {
405 for (j = 0; j < plane->drm_plane->count_formats; j++) {
406 uint32_t format = plane->drm_plane->formats[j];
407
408 if (!igt_fb_supported_format(format))
409 continue;
410
411 test_single_case(data, pipe, output, plane, i,
412 format, test_bad_format);
413 }
414 } else {
415 test_single_case(data, pipe, output, plane, i,
416 data->override_fmt, test_bad_format);
417 }
418 }
419 igt_pipe_crc_stop(data->pipe_crc);
420 }
421 }
422
423 typedef struct {
424 int32_t x1, y1;
425 uint64_t width, height, tiling, planetype, format;
426 igt_rotation_t rotation_sw, rotation_hw;
427 } planeinfos;
428
get_multiplane_crc(data_t * data,igt_output_t * output,igt_crc_t * crc_output,planeinfos * planeinfo,int numplanes)429 static bool get_multiplane_crc(data_t *data, igt_output_t *output,
430 igt_crc_t *crc_output, planeinfos *planeinfo,
431 int numplanes)
432 {
433 uint32_t w, h;
434 igt_display_t *display = &data->display;
435 struct p_struct *planes, *oldplanes;
436 int c, ret;
437
438 oldplanes = data->multiplaneoldview;
439 planes = calloc(sizeof(*planes), numplanes);
440
441 for (c = 0; c < numplanes; c++) {
442 planes[c].plane = igt_output_get_plane_type(output,
443 planeinfo[c].planetype);
444
445 /*
446 * make plane and fb width and height always divisible by 4
447 * due to NV12 support and Intel hw workarounds.
448 */
449 w = planeinfo[c].width & ~3;
450 h = planeinfo[c].height & ~3;
451
452 if (planeinfo[c].rotation_sw & (IGT_ROTATION_90 | IGT_ROTATION_270))
453 igt_swap(w, h);
454
455 if (!igt_plane_has_format_mod(planes[c].plane,
456 planeinfo[c].format,
457 planeinfo[c].tiling))
458 return false;
459
460 igt_create_fb(data->gfx_fd, w, h, planeinfo[c].format,
461 planeinfo[c].tiling, &planes[c].fb);
462
463 paint_squares(data, planeinfo[c].rotation_sw, &planes[c].fb, 1.0f);
464 igt_plane_set_fb(planes[c].plane, &planes[c].fb);
465
466 if (planeinfo[c].rotation_hw & (IGT_ROTATION_90 | IGT_ROTATION_270))
467 igt_plane_set_size(planes[c].plane, h, w);
468
469 igt_plane_set_position(planes[c].plane, planeinfo[c].x1, planeinfo[c].y1);
470 igt_plane_set_rotation(planes[c].plane, planeinfo[c].rotation_hw);
471 }
472
473 ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
474 igt_assert_eq(ret, 0);
475
476 igt_pipe_crc_get_current(data->gfx_fd, data->pipe_crc, crc_output);
477
478 for (c = 0; c < numplanes && oldplanes; c++)
479 igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
480
481 free(oldplanes);
482 data->multiplaneoldview = (void*)planes;
483 return true;
484 }
485
pointlocation(data_t * data,planeinfos * p,drmModeModeInfo * mode,int c)486 static void pointlocation(data_t *data, planeinfos *p, drmModeModeInfo *mode,
487 int c)
488 {
489 if (data->planepos[c].origo & p_right) {
490 p[c].x1 = (int32_t)(data->planepos[c].x * mode->hdisplay
491 + mode->hdisplay);
492 p[c].x1 &= ~3;
493 /*
494 * At this point is handled surface on right side. If display
495 * mode is not divisible by 4 but with 2 point location is
496 * fixed to match requirements. Because of YUV planes here is
497 * intentionally ignored bit 1.
498 */
499 p[c].x1 -= mode->hdisplay & 2;
500 } else {
501 p[c].x1 = (int32_t)(data->planepos[c].x * mode->hdisplay);
502 p[c].x1 &= ~3;
503 }
504
505 if (data->planepos[c].origo & p_bottom) {
506 p[c].y1 = (int32_t)(data->planepos[c].y * mode->vdisplay
507 + mode->vdisplay);
508 p[c].y1 &= ~3;
509 p[c].y1 -= mode->vdisplay & 2;
510 } else {
511 p[c].y1 = (int32_t)(data->planepos[c].y * mode->vdisplay);
512 p[c].y1 &= ~3;
513 }
514 }
515
516 /*
517 * Here is pipe parameter which is now used only for first pipe.
518 * It is left here if this test ever was wanted to be run on
519 * different pipes.
520 */
test_multi_plane_rotation(data_t * data,enum pipe pipe)521 static void test_multi_plane_rotation(data_t *data, enum pipe pipe)
522 {
523 igt_display_t *display = &data->display;
524 igt_output_t *output;
525 igt_crc_t retcrc_sw, retcrc_hw;
526 planeinfos p[2];
527 int c;
528 struct p_struct *oldplanes;
529 drmModeModeInfo *mode;
530
531 static const struct {
532 igt_rotation_t rotation;
533 float_t width;
534 float_t height;
535 uint64_t tiling;
536 } planeconfigs[] = {
537 {IGT_ROTATION_0, .2f, .4f, LOCAL_DRM_FORMAT_MOD_NONE },
538 {IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_X_TILED },
539 {IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
540 {IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
541 {IGT_ROTATION_90, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
542 {IGT_ROTATION_90, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
543 {IGT_ROTATION_180, .2f, .4f, LOCAL_DRM_FORMAT_MOD_NONE },
544 {IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_X_TILED },
545 {IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
546 {IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
547 {IGT_ROTATION_270, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
548 {IGT_ROTATION_270, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
549 };
550
551 /*
552 * These are those modes which are tested. For testing feel interesting
553 * case with tiling are 2 bpp, 4 bpp and NV12.
554 */
555 static const uint32_t formatlist[] = {DRM_FORMAT_RGB565,
556 DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12};
557
558 for_each_valid_output_on_pipe(display, pipe, output) {
559 int i, j, k, l;
560 igt_output_set_pipe(output, pipe);
561 mode = igt_output_get_mode(output);
562 igt_display_require_output(display);
563 igt_display_commit2(display, COMMIT_ATOMIC);
564
565 data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe,
566 INTEL_PIPE_CRC_SOURCE_AUTO);
567 igt_pipe_crc_start(data->pipe_crc);
568
569 for (i = 0; i < ARRAY_SIZE(planeconfigs); i++) {
570 p[0].planetype = DRM_PLANE_TYPE_PRIMARY;
571 p[0].width = (uint64_t)(planeconfigs[i].width * mode->hdisplay);
572 p[0].height = (uint64_t)(planeconfigs[i].height * mode->vdisplay);
573 p[0].tiling = planeconfigs[i].tiling;
574 pointlocation(data, (planeinfos *)&p, mode, 0);
575
576 for (k = 0; k < ARRAY_SIZE(formatlist); k++) {
577 p[0].format = formatlist[k];
578
579 for (j = 0; j < ARRAY_SIZE(planeconfigs); j++) {
580 p[1].planetype = DRM_PLANE_TYPE_OVERLAY;
581 p[1].width = (uint64_t)(planeconfigs[j].width * mode->hdisplay);
582 p[1].height = (uint64_t)(planeconfigs[j].height * mode->vdisplay);
583 p[1].tiling = planeconfigs[j].tiling;
584 pointlocation(data, (planeinfos *)&p,
585 mode, 1);
586
587 for (l = 0; l < ARRAY_SIZE(formatlist); l++) {
588 p[1].format = formatlist[l];
589
590 /*
591 * RGB565 90/270 degrees rotation is supported
592 * from gen11 onwards.
593 */
594 if (p[0].format == DRM_FORMAT_RGB565 &&
595 (planeconfigs[i].rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
596 && intel_gen(data->devid) < 11)
597 continue;
598
599 if (p[1].format == DRM_FORMAT_RGB565 &&
600 (planeconfigs[j].rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
601 && intel_gen(data->devid) < 11)
602 continue;
603
604 p[0].rotation_sw = planeconfigs[i].rotation;
605 p[0].rotation_hw = IGT_ROTATION_0;
606 p[1].rotation_sw = planeconfigs[j].rotation;
607 p[1].rotation_hw = IGT_ROTATION_0;
608 if (!get_multiplane_crc(data, output, &retcrc_sw,
609 (planeinfos *)&p, MAXMULTIPLANESAMOUNT))
610 continue;
611
612 igt_swap(p[0].rotation_sw, p[0].rotation_hw);
613 igt_swap(p[1].rotation_sw, p[1].rotation_hw);
614 if (!get_multiplane_crc(data, output, &retcrc_hw,
615 (planeinfos *)&p, MAXMULTIPLANESAMOUNT))
616 continue;
617
618 igt_assert_crc_equal(&retcrc_sw, &retcrc_hw);
619 }
620 }
621 }
622 }
623 igt_pipe_crc_stop(data->pipe_crc);
624 igt_pipe_crc_free(data->pipe_crc);
625 igt_output_set_pipe(output, PIPE_ANY);
626 }
627
628 /*
629 * Old fbs are deleted only after new ones are set on planes.
630 * This is done to speed up the test
631 */
632 oldplanes = data->multiplaneoldview;
633 for (c = 0; c < MAXMULTIPLANESAMOUNT && oldplanes; c++)
634 igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
635
636 free(oldplanes);
637 data->multiplaneoldview = NULL;
638 data->pipe_crc = NULL;
639 }
640
test_plane_rotation_exhaust_fences(data_t * data,enum pipe pipe,igt_output_t * output,igt_plane_t * plane)641 static void test_plane_rotation_exhaust_fences(data_t *data,
642 enum pipe pipe,
643 igt_output_t *output,
644 igt_plane_t *plane)
645 {
646 igt_display_t *display = &data->display;
647 uint64_t tiling = LOCAL_I915_FORMAT_MOD_Y_TILED;
648 uint32_t format = DRM_FORMAT_XRGB8888;
649 int fd = data->gfx_fd;
650 drmModeModeInfo *mode;
651 struct igt_fb fb[MAX_FENCES+1] = {};
652 uint64_t size;
653 unsigned int stride, w, h;
654 uint64_t total_aperture_size, total_fbs_size;
655 int i;
656
657 igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
658
659 prepare_crtc(data, output, pipe, plane, false);
660
661 mode = igt_output_get_mode(output);
662 w = mode->hdisplay;
663 h = mode->vdisplay;
664
665 igt_calc_fb_size(fd, w, h, format, tiling, &size, &stride);
666
667 /*
668 * Make sure there is atleast 90% of the available GTT space left
669 * for creating (MAX_FENCES+1) framebuffers.
670 */
671 total_fbs_size = size * (MAX_FENCES + 1);
672 total_aperture_size = gem_available_aperture_size(fd);
673 igt_require(total_fbs_size < total_aperture_size * 0.9);
674
675 for (i = 0; i < MAX_FENCES + 1; i++) {
676 igt_create_fb(fd, w, h, format, tiling, &fb[i]);
677
678 igt_plane_set_fb(plane, &fb[i]);
679 igt_plane_set_rotation(plane, IGT_ROTATION_0);
680 igt_display_commit2(display, COMMIT_ATOMIC);
681
682 igt_plane_set_rotation(plane, IGT_ROTATION_90);
683 igt_plane_set_size(plane, h, w);
684 igt_display_commit2(display, COMMIT_ATOMIC);
685 }
686
687 for (i = 0; i < MAX_FENCES + 1; i++)
688 igt_remove_fb(fd, &fb[i]);
689 }
690
plane_test_str(unsigned plane)691 static const char *plane_test_str(unsigned plane)
692 {
693 switch (plane) {
694 case DRM_PLANE_TYPE_PRIMARY:
695 return "primary";
696 case DRM_PLANE_TYPE_OVERLAY:
697 return "sprite";
698 case DRM_PLANE_TYPE_CURSOR:
699 return "cursor";
700 default:
701 igt_assert(0);
702 }
703 }
704
rot_test_str(igt_rotation_t rot)705 static const char *rot_test_str(igt_rotation_t rot)
706 {
707 switch (rot) {
708 case IGT_ROTATION_0:
709 return "0";
710 case IGT_ROTATION_90:
711 return "90";
712 case IGT_ROTATION_180:
713 return "180";
714 case IGT_ROTATION_270:
715 return "270";
716 default:
717 igt_assert(0);
718 }
719 }
720
tiling_test_str(uint64_t tiling)721 static const char *tiling_test_str(uint64_t tiling)
722 {
723 switch (tiling) {
724 case LOCAL_I915_FORMAT_MOD_X_TILED:
725 return "x-tiled";
726 case LOCAL_I915_FORMAT_MOD_Y_TILED:
727 return "y-tiled";
728 case LOCAL_I915_FORMAT_MOD_Yf_TILED:
729 return "yf-tiled";
730 default:
731 igt_assert(0);
732 }
733 }
734
735 igt_main
736 {
737 struct rot_subtest {
738 unsigned plane;
739 igt_rotation_t rot;
740 } *subtest, subtests[] = {
741 { DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_90 },
742 { DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_180 },
743 { DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_270 },
744 { DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_90 },
745 { DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_180 },
746 { DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_270 },
747 { DRM_PLANE_TYPE_CURSOR, IGT_ROTATION_180 },
748 { 0, 0}
749 };
750
751 struct reflect_x {
752 uint64_t tiling;
753 igt_rotation_t rot;
754 } *reflect_x, reflect_x_subtests[] = {
755 { LOCAL_I915_FORMAT_MOD_X_TILED, IGT_ROTATION_0 },
756 { LOCAL_I915_FORMAT_MOD_X_TILED, IGT_ROTATION_180 },
757 { LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_0 },
758 { LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_90 },
759 { LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_180 },
760 { LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_270 },
761 { LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_0 },
762 { LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_90 },
763 { LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_180 },
764 { LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_270 },
765 { 0, 0 }
766 };
767
768 data_t data = {};
769 int gen = 0;
770
771 igt_skip_on_simulation();
772
773 igt_fixture {
774 data.gfx_fd = drm_open_driver_master(DRIVER_INTEL);
775 data.devid = intel_get_drm_devid(data.gfx_fd);
776 gen = intel_gen(data.devid);
777
778 kmstest_set_vt_graphics_mode();
779
780 igt_require_pipe_crc(data.gfx_fd);
781
782 igt_display_require(&data.display, data.gfx_fd);
783 }
784
785 for (subtest = subtests; subtest->rot; subtest++) {
786 igt_subtest_f("%s-rotation-%s",
787 plane_test_str(subtest->plane),
788 rot_test_str(subtest->rot)) {
789 igt_require(!(subtest->rot &
790 (IGT_ROTATION_90 | IGT_ROTATION_270)) ||
791 gen >= 9);
792 data.rotation = subtest->rot;
793 test_plane_rotation(&data, subtest->plane, false);
794 }
795 }
796
797 igt_subtest_f("sprite-rotation-90-pos-100-0") {
798 igt_require(gen >= 9);
799 data.rotation = IGT_ROTATION_90;
800 data.pos_x = 100,
801 data.pos_y = 0;
802 test_plane_rotation(&data, DRM_PLANE_TYPE_OVERLAY, false);
803 }
804 data.pos_x = 0,
805 data.pos_y = 0;
806
807 igt_subtest_f("bad-pixel-format") {
808 /* gen11 enables RGB565 rotation for 90/270 degrees.
809 * so apart from this, any other gen11+ pixel format
810 * can be used which doesn't support 90/270 degree
811 * rotation */
812 igt_require(gen >= 9);
813 data.rotation = IGT_ROTATION_90;
814 data.override_fmt = gen < 11 ? DRM_FORMAT_RGB565 : DRM_FORMAT_Y212;
815 test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, true);
816 }
817 data.override_fmt = 0;
818
819 igt_subtest_f("bad-tiling") {
820 igt_require(gen >= 9);
821 data.rotation = IGT_ROTATION_90;
822 data.override_tiling = LOCAL_I915_FORMAT_MOD_X_TILED;
823 test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, true);
824 }
825 data.override_tiling = 0;
826
827 for (reflect_x = reflect_x_subtests; reflect_x->tiling; reflect_x++) {
828 igt_subtest_f("primary-%s-reflect-x-%s",
829 tiling_test_str(reflect_x->tiling),
830 rot_test_str(reflect_x->rot)) {
831 igt_require(gen >= 10 ||
832 (IS_CHERRYVIEW(data.devid) && reflect_x->rot == IGT_ROTATION_0
833 && reflect_x->tiling == LOCAL_I915_FORMAT_MOD_X_TILED));
834 data.rotation = (IGT_REFLECT_X | reflect_x->rot);
835 data.override_tiling = reflect_x->tiling;
836 test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, false);
837 }
838 }
839
840 igt_subtest_f("multiplane-rotation") {
841 igt_require(gen >= 9);
842 cleanup_crtc(&data);
843 data.planepos[0].origo = p_top | p_left;
844 data.planepos[0].x = .2f;
845 data.planepos[0].y = .1f;
846 data.planepos[1].origo = p_top | p_right;
847 data.planepos[1].x = -.4f;
848 data.planepos[1].y = .1f;
849 test_multi_plane_rotation(&data, 0);
850 }
851
852 igt_subtest_f("multiplane-rotation-cropping-top") {
853 igt_require(gen >= 9);
854 cleanup_crtc(&data);
855 data.planepos[0].origo = p_top | p_left;
856 data.planepos[0].x = -.05f;
857 data.planepos[0].y = -.15f;
858 data.planepos[1].origo = p_top | p_right;
859 data.planepos[1].x = -.15f;
860 data.planepos[1].y = -.15f;
861 test_multi_plane_rotation(&data, 0);
862 }
863
864 igt_subtest_f("multiplane-rotation-cropping-bottom") {
865 igt_require(gen >= 9);
866 cleanup_crtc(&data);
867 data.planepos[0].origo = p_bottom | p_left;
868 data.planepos[0].x = -.05f;
869 data.planepos[0].y = -.20f;
870 data.planepos[1].origo = p_bottom | p_right;
871 data.planepos[1].x = -.15f;
872 data.planepos[1].y = -.20f;
873 test_multi_plane_rotation(&data, 0);
874 }
875
876 /*
877 * exhaust-fences should be last test, if it fails we may OOM in
878 * the following subtests otherwise.
879 */
880 igt_subtest_f("exhaust-fences") {
881 enum pipe pipe;
882 igt_output_t *output;
883
884 igt_require(gen >= 9);
885 igt_display_require_output(&data.display);
886
887 for_each_pipe_with_valid_output(&data.display, pipe, output) {
888 igt_plane_t *primary = &data.display.pipes[pipe].planes[0];
889
890 test_plane_rotation_exhaust_fences(&data, pipe, output, primary);
891 break;
892 }
893 }
894
895 igt_fixture {
896 igt_display_fini(&data.display);
897 }
898 }
899