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