[igt-dev] [PATCH] kms_rotation_crc:Add HW rotation test case for amdgpu

Sung Joon Kim sungkim at amd.com
Wed Dec 16 22:12:31 UTC 2020


Added Hw rotation case specifically for amdgpu. Currently, kms_rotation_crc tests intel gpus. Added conditions to bypass all the requirements needed for intel when testing amdgpu.

Signed-off-by: Sung Joon Kim <sungkim at amd.com>
---
 tests/kms_rotation_crc.c | 1971 +++++++++++++++++++-------------------
 1 file changed, 1011 insertions(+), 960 deletions(-)

diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c
index ffcc2cc2..f4f36144 100644
--- a/tests/kms_rotation_crc.c
+++ b/tests/kms_rotation_crc.c
@@ -1,960 +1,1011 @@
-/*
- * Copyright © 2013,2014 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- */
-
-#include "igt.h"
-#include "igt_vec.h"
-#include <math.h>
-
-#define MAX_FENCES 32
-#define MAXMULTIPLANESAMOUNT 2
-#define TEST_MAX_WIDTH 640
-#define TEST_MAX_HEIGHT 480
-
-struct p_struct {
-	igt_plane_t *plane;
-	struct igt_fb fb;
-};
-
-enum p_pointorigo {
-	p_top = 1 << 0,
-	p_bottom = 1 << 1,
-	p_left = 1 << 2,
-	p_right = 1 << 3
-};
-
-struct p_point{
-	enum p_pointorigo origo;
-	float_t x;
-	float_t y;
-};
-
-typedef struct {
-	int gfx_fd;
-	igt_display_t display;
-	struct igt_fb fb;
-	struct igt_fb fb_reference;
-	struct igt_fb fb_flip;
-	igt_crc_t ref_crc;
-	igt_crc_t flip_crc;
-	igt_pipe_crc_t *pipe_crc;
-	igt_rotation_t rotation;
-	int pos_x;
-	int pos_y;
-	uint32_t override_fmt;
-	uint64_t override_tiling;
-	int devid;
-
-	struct p_struct *multiplaneoldview;
-	struct p_point planepos[MAXMULTIPLANESAMOUNT];
-
-	bool use_native_resolution;
-	bool extended;
-} data_t;
-
-typedef struct {
-	float r;
-	float g;
-	float b;
-} rgb_color_t;
-
-static void set_color(rgb_color_t *color, float r, float g, float b)
-{
-	color->r = r;
-	color->g = g;
-	color->b = b;
-}
-
-static void rotate_colors(rgb_color_t *tl, rgb_color_t *tr, rgb_color_t *br,
-			  rgb_color_t *bl, igt_rotation_t rotation)
-{
-	rgb_color_t bl_tmp, br_tmp, tl_tmp, tr_tmp;
-
-	if (rotation & IGT_REFLECT_X) {
-		igt_swap(*tl, *tr);
-		igt_swap(*bl, *br);
-	}
-
-	if (rotation & IGT_ROTATION_90) {
-		bl_tmp = *bl;
-		br_tmp = *br;
-		tl_tmp = *tl;
-		tr_tmp = *tr;
-		*tl = tr_tmp;
-		*bl = tl_tmp;
-		*tr = br_tmp;
-		*br = bl_tmp;
-	} else if (rotation & IGT_ROTATION_180) {
-		igt_swap(*tl, *br);
-		igt_swap(*tr, *bl);
-	} else if (rotation & IGT_ROTATION_270) {
-		bl_tmp = *bl;
-		br_tmp = *br;
-		tl_tmp = *tl;
-		tr_tmp = *tr;
-		*tl = bl_tmp;
-		*bl = br_tmp;
-		*tr = tl_tmp;
-		*br = tr_tmp;
-	}
-}
-
-#define RGB_COLOR(color) \
-	color.r, color.g, color.b
-
-static void
-paint_squares(data_t *data, igt_rotation_t rotation,
-	      struct igt_fb *fb, float o)
-{
-	cairo_t *cr;
-	unsigned int w = fb->width;
-	unsigned int h = fb->height;
-	rgb_color_t tl, tr, bl, br;
-
-	igt_assert_f(!(w&1), "rotation image must be even width, now attempted %d\n", w);
-	igt_assert_f(!(h&1), "rotation image must be even height, now attempted %d\n", h);
-
-	cr = igt_get_cairo_ctx(data->gfx_fd, fb);
-
-	set_color(&tl, o, 0.0f, 0.0f);
-	set_color(&tr, 0.0f, o, 0.0f);
-	set_color(&br, o, o, o);
-	set_color(&bl, 0.0f, 0.0f, o);
-
-	rotate_colors(&tl, &tr, &br, &bl, rotation);
-
-	igt_paint_color(cr, 0, 0, w / 2, h / 2, RGB_COLOR(tl));
-	igt_paint_color(cr, w / 2, 0, w / 2, h / 2, RGB_COLOR(tr));
-	igt_paint_color(cr, 0, h / 2, w / 2, h / 2, RGB_COLOR(bl));
-	igt_paint_color(cr, w / 2, h / 2, w / 2, h / 2, RGB_COLOR(br));
-
-	igt_put_cairo_ctx(cr);
-}
-
-static void remove_fbs(data_t *data)
-{
-	igt_remove_fb(data->gfx_fd, &data->fb);
-	igt_remove_fb(data->gfx_fd, &data->fb_reference);
-	igt_remove_fb(data->gfx_fd, &data->fb_flip);
-}
-
-static void cleanup_crtc(data_t *data)
-{
-	igt_display_t *display = &data->display;
-
-	igt_pipe_crc_free(data->pipe_crc);
-	data->pipe_crc = NULL;
-
-	remove_fbs(data);
-
-	igt_display_reset(display);
-}
-
-static void prepare_crtc(data_t *data, igt_output_t *output, enum pipe pipe,
-			 igt_plane_t *plane, bool start_crc)
-{
-	igt_display_t *display = &data->display;
-
-	cleanup_crtc(data);
-
-	igt_output_set_pipe(output, pipe);
-	igt_plane_set_rotation(plane, IGT_ROTATION_0);
-
-	/* create the pipe_crc object for this pipe */
-	igt_pipe_crc_free(data->pipe_crc);
-
-	igt_display_commit2(display, COMMIT_ATOMIC);
-	data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
-
-	if (start_crc)
-		igt_pipe_crc_start(data->pipe_crc);
-}
-
-enum rectangle_type {
-	rectangle,
-	square,
-	portrait,
-	landscape,
-	num_rectangle_types /* must be last */
-};
-
-static void prepare_fbs(data_t *data, igt_output_t *output,
-			igt_plane_t *plane, enum rectangle_type rect, uint32_t format)
-{
-	drmModeModeInfo *mode;
-	igt_display_t *display = &data->display;
-	unsigned int w, h, ref_w, ref_h, min_w, min_h;
-	uint64_t tiling = data->override_tiling ?: LOCAL_DRM_FORMAT_MOD_NONE;
-	uint32_t pixel_format = data->override_fmt ?: DRM_FORMAT_XRGB8888;
-	const float flip_opacity = 0.75;
-
-	remove_fbs(data);
-
-	igt_plane_set_rotation(plane, IGT_ROTATION_0);
-
-	mode = igt_output_get_mode(output);
-	if (plane->type != DRM_PLANE_TYPE_CURSOR) {
-		if (data->use_native_resolution) {
-			w = mode->hdisplay;
-			h = mode->vdisplay;
-		} else {
-			w = min(TEST_MAX_WIDTH, mode->hdisplay);
-			h = min(TEST_MAX_HEIGHT, mode->vdisplay);
-		}
-
-		min_w = 256;
-		min_h = 256;
-	} else {
-		pixel_format = data->override_fmt ?: DRM_FORMAT_ARGB8888;
-
-		w = h = 256;
-		min_w = min_h = 64;
-	}
-
-	switch (rect) {
-	case rectangle:
-		break;
-	case square:
-		w = h = min(h, w);
-		break;
-	case portrait:
-		w = min_w;
-		break;
-	case landscape:
-		h = min_h;
-		break;
-	case num_rectangle_types:
-		igt_assert(0);
-	}
-
-	ref_w = w;
-	ref_h = h;
-
-	/*
-	 * For 90/270, we will use create smaller fb so that the rotated
-	 * frame can fit in
-	 */
-	if (data->rotation & (IGT_ROTATION_90 | IGT_ROTATION_270)) {
-		tiling = data->override_tiling ?: LOCAL_I915_FORMAT_MOD_Y_TILED;
-
-		igt_swap(w, h);
-	}
-
-	/*
-	 * Just try here if requested tiling format is generally available,
-	 * if one format fail it will skip entire subtest.
-	 */
-	igt_require(igt_display_has_format_mod(display, pixel_format, tiling));
-
-	/*
-	 * Create a reference software rotated flip framebuffer.
-	 */
-	igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format, tiling,
-		      &data->fb_flip);
-	paint_squares(data, data->rotation, &data->fb_flip,
-		      flip_opacity);
-	igt_plane_set_fb(plane, &data->fb_flip);
-	if (plane->type != DRM_PLANE_TYPE_CURSOR)
-		igt_plane_set_position(plane, data->pos_x, data->pos_y);
-	igt_display_commit2(display, COMMIT_ATOMIC);
-
-	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &data->flip_crc);
-
-	/*
-	  * Prepare the non-rotated flip fb.
-	  */
-	igt_remove_fb(data->gfx_fd, &data->fb_flip);
-	igt_create_fb(data->gfx_fd, w, h, pixel_format, tiling,
-		      &data->fb_flip);
-	paint_squares(data, IGT_ROTATION_0, &data->fb_flip,
-		      flip_opacity);
-
-	/*
-	 * Create a reference CRC for a software-rotated fb.
-	 */
-	igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format,
-		      data->override_tiling ?: LOCAL_DRM_FORMAT_MOD_NONE, &data->fb_reference);
-	paint_squares(data, data->rotation, &data->fb_reference, 1.0);
-
-	igt_plane_set_fb(plane, &data->fb_reference);
-	if (plane->type != DRM_PLANE_TYPE_CURSOR)
-		igt_plane_set_position(plane, data->pos_x, data->pos_y);
-	igt_display_commit2(display, COMMIT_ATOMIC);
-
-	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &data->ref_crc);
-
-	/*
-	 * Prepare the plane with an non-rotated fb let the hw rotate it.
-	 */
-	igt_create_fb(data->gfx_fd, w, h, pixel_format, tiling, &data->fb);
-	paint_squares(data, IGT_ROTATION_0, &data->fb, 1.0);
-	igt_plane_set_fb(plane, &data->fb);
-
-	if (plane->type != DRM_PLANE_TYPE_CURSOR)
-		igt_plane_set_position(plane, data->pos_x, data->pos_y);
-}
-
-static void 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)
-{
-	igt_display_t *display = &data->display;
-	igt_crc_t crc_output;
-	int ret;
-
-	igt_debug("Testing case %i on pipe %s, format %s\n", rect, kmstest_pipe_name(pipe), igt_format_str(format));
-	prepare_fbs(data, output, plane, rect, format);
-
-	igt_plane_set_rotation(plane, data->rotation);
-	if (data->rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
-		igt_plane_set_size(plane, data->fb.height, data->fb.width);
-
-	ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
-	if (test_bad_format) {
-		igt_assert_eq(ret, -EINVAL);
-		return;
-	}
-
-	/* Verify commit was ok. */
-	igt_assert_eq(ret, 0);
-
-	/* Check CRC */
-	igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc_output);
-	igt_assert_crc_equal(&data->ref_crc, &crc_output);
-
-	/*
-	 * If flips are requested flip to a different fb and
-	 * check CRC against that one as well.
-	 */
-	if (data->fb_flip.fb_id) {
-		igt_plane_set_fb(plane, &data->fb_flip);
-		if (data->rotation == IGT_ROTATION_90 || data->rotation == IGT_ROTATION_270)
-			igt_plane_set_size(plane, data->fb.height, data->fb.width);
-
-		if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
-			igt_display_commit_atomic(display, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, NULL);
-		} else {
-			ret = drmModePageFlip(data->gfx_fd,
-					output->config.crtc->crtc_id,
-					data->fb_flip.fb_id,
-					DRM_MODE_PAGE_FLIP_EVENT,
-					NULL);
-			igt_assert_eq(ret, 0);
-		}
-		kmstest_wait_for_pageflip(data->gfx_fd);
-		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc_output);
-		igt_assert_crc_equal(&data->flip_crc,
-				     &crc_output);
-	}
-}
-
-static bool test_format(data_t *data,
-			struct igt_vec *tested_formats,
-			uint32_t format)
-{
-	if (!igt_fb_supported_format(format))
-		return false;
-
-	if (!is_i915_device(data->gfx_fd) ||
-	    data->extended)
-		return true;
-
-	format = igt_reduce_format(format);
-
-	/* only test each format "class" once */
-	if (igt_vec_index(tested_formats, &format) >= 0)
-		return false;
-
-	igt_vec_push(tested_formats, &format);
-
-	return true;
-}
-
-static void test_plane_rotation(data_t *data, int plane_type, bool test_bad_format)
-{
-	igt_display_t *display = &data->display;
-	igt_output_t *output;
-	enum pipe pipe;
-
-	if (plane_type == DRM_PLANE_TYPE_CURSOR)
-		igt_require(display->has_cursor_plane);
-
-	igt_display_require_output(display);
-
-	for_each_pipe_with_valid_output(display, pipe, output) {
-		igt_plane_t *plane;
-		int i, j;
-
-		if (IS_CHERRYVIEW(data->devid) && pipe != PIPE_B)
-			continue;
-
-		igt_output_set_pipe(output, pipe);
-
-		plane = igt_output_get_plane_type(output, plane_type);
-		igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
-
-		prepare_crtc(data, output, pipe, plane, true);
-
-		for (i = 0; i < num_rectangle_types; i++) {
-			/* Unsupported on i915 */
-			if (plane_type == DRM_PLANE_TYPE_CURSOR &&
-			    i != square)
-				continue;
-
-			/* Only support partial covering primary plane on gen9+ */
-			if (plane_type == DRM_PLANE_TYPE_PRIMARY &&
-			    intel_gen(intel_get_drm_devid(data->gfx_fd)) < 9) {
-				if (i != rectangle)
-					continue;
-				else
-					data->use_native_resolution = true;
-			} else {
-				data->use_native_resolution = false;
-			}
-
-			if (!data->override_fmt) {
-				struct igt_vec tested_formats;
-
-				igt_vec_init(&tested_formats, sizeof(uint32_t));
-
-				for (j = 0; j < plane->drm_plane->count_formats; j++) {
-					uint32_t format = plane->drm_plane->formats[j];
-
-					if (!test_format(data, &tested_formats, format))
-						continue;
-
-					test_single_case(data, pipe, output, plane, i,
-							 format, test_bad_format);
-				}
-
-				igt_vec_fini(&tested_formats);
-			} else {
-				test_single_case(data, pipe, output, plane, i,
-						 data->override_fmt, test_bad_format);
-			}
-		}
-		igt_pipe_crc_stop(data->pipe_crc);
-	}
-}
-
-typedef struct {
-	int32_t x1, y1;
-	uint64_t width, height, tiling, planetype, format;
-	igt_rotation_t rotation_sw, rotation_hw;
-} planeinfos;
-
-static bool get_multiplane_crc(data_t *data, igt_output_t *output,
-			       igt_crc_t *crc_output, planeinfos *planeinfo,
-			       int numplanes)
-{
-	uint32_t w, h;
-	igt_display_t *display = &data->display;
-	struct p_struct *planes, *oldplanes;
-	int c, ret;
-
-	oldplanes = data->multiplaneoldview;
-	planes = calloc(sizeof(*planes), numplanes);
-
-	for (c = 0; c < numplanes; c++) {
-		planes[c].plane = igt_output_get_plane_type(output,
-							    planeinfo[c].planetype);
-
-		/*
-		 * make plane and fb width and height always divisible by 4
-		 * due to NV12 support and Intel hw workarounds.
-		 */
-		w = planeinfo[c].width & ~3;
-		h = planeinfo[c].height & ~3;
-
-		if (planeinfo[c].rotation_sw & (IGT_ROTATION_90 | IGT_ROTATION_270))
-			igt_swap(w, h);
-
-		if (!igt_plane_has_format_mod(planes[c].plane,
-					      planeinfo[c].format,
-					      planeinfo[c].tiling))
-			return false;
-
-		igt_create_fb(data->gfx_fd, w, h, planeinfo[c].format,
-			      planeinfo[c].tiling, &planes[c].fb);
-
-		paint_squares(data, planeinfo[c].rotation_sw, &planes[c].fb, 1.0f);
-		igt_plane_set_fb(planes[c].plane, &planes[c].fb);
-
-		if (planeinfo[c].rotation_hw & (IGT_ROTATION_90 | IGT_ROTATION_270))
-			igt_plane_set_size(planes[c].plane, h, w);
-
-		igt_plane_set_position(planes[c].plane, planeinfo[c].x1, planeinfo[c].y1);
-		igt_plane_set_rotation(planes[c].plane, planeinfo[c].rotation_hw);
-	}
-
-	ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
-	igt_assert_eq(ret, 0);
-
-	igt_pipe_crc_get_current(data->gfx_fd, data->pipe_crc, crc_output);
-
-	for (c = 0; c < numplanes && oldplanes; c++)
-		igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
-
-	free(oldplanes);
-	data->multiplaneoldview = (void*)planes;
-	return true;
-}
-
-static void pointlocation(data_t *data, planeinfos *p, drmModeModeInfo *mode,
-			  int c)
-{
-	if (data->planepos[c].origo & p_right) {
-		p[c].x1 = (int32_t)(data->planepos[c].x * min(TEST_MAX_WIDTH, mode->hdisplay)
-				+ mode->hdisplay);
-		p[c].x1 &= ~3;
-		/*
-		 * At this point is handled surface on right side. If display
-		 * mode is not divisible by 4 but with 2 point location is
-		 * fixed to match requirements. Because of YUV planes here is
-		 * intentionally ignored bit 1.
-		 */
-		p[c].x1 -= mode->hdisplay & 2;
-	} else {
-		p[c].x1 = (int32_t)(data->planepos[c].x * min(TEST_MAX_WIDTH, mode->hdisplay));
-		p[c].x1 &= ~3;
-	}
-
-	if (data->planepos[c].origo & p_bottom) {
-		p[c].y1 = (int32_t)(data->planepos[c].y * min(TEST_MAX_HEIGHT, mode->vdisplay)
-				+ mode->vdisplay);
-		p[c].y1 &= ~3;
-		p[c].y1 -= mode->vdisplay & 2;
-	} else {
-		p[c].y1 = (int32_t)(data->planepos[c].y * min(TEST_MAX_HEIGHT, mode->vdisplay));
-		p[c].y1 &= ~3;
-	}
-}
-
-/*
- * Here is pipe parameter which is now used only for first pipe.
- * It is left here if this test ever was wanted to be run on
- * different pipes.
- */
-static void test_multi_plane_rotation(data_t *data, enum pipe pipe)
-{
-	igt_display_t *display = &data->display;
-	igt_output_t *output;
-	igt_crc_t retcrc_sw, retcrc_hw;
-	planeinfos p[2];
-	int c, used_w, used_h;
-	struct p_struct *oldplanes;
-	drmModeModeInfo *mode;
-
-	static const struct {
-		igt_rotation_t rotation;
-		float_t width;
-		float_t height;
-		uint64_t tiling;
-	} planeconfigs[] = {
-	{IGT_ROTATION_0, .2f, .4f, LOCAL_DRM_FORMAT_MOD_NONE },
-	{IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_X_TILED },
-	{IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
-	{IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
-	{IGT_ROTATION_90, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
-	{IGT_ROTATION_90, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
-	{IGT_ROTATION_180, .2f, .4f, LOCAL_DRM_FORMAT_MOD_NONE },
-	{IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_X_TILED },
-	{IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
-	{IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
-	{IGT_ROTATION_270, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
-	{IGT_ROTATION_270, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
-	};
-
-	/*
-	* These are those modes which are tested. For testing feel interesting
-	* case with tiling are 2 bpp, 4 bpp and NV12.
-	*/
-	static const uint32_t formatlist[] = {DRM_FORMAT_RGB565,
-		DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12};
-
-	for_each_valid_output_on_pipe(display, pipe, output) {
-		int i, j, k, l;
-		igt_output_set_pipe(output, pipe);
-		mode = igt_output_get_mode(output);
-		igt_display_require_output(display);
-		igt_display_commit2(display, COMMIT_ATOMIC);
-
-		used_w = min(TEST_MAX_WIDTH, mode->hdisplay);
-		used_h = min(TEST_MAX_HEIGHT, mode->vdisplay);
-
-		data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe,
-						  INTEL_PIPE_CRC_SOURCE_AUTO);
-		igt_pipe_crc_start(data->pipe_crc);
-
-		for (i = 0; i < ARRAY_SIZE(planeconfigs); i++) {
-			p[0].planetype = DRM_PLANE_TYPE_PRIMARY;
-			p[0].width = (uint64_t)(planeconfigs[i].width * used_w);
-			p[0].height = (uint64_t)(planeconfigs[i].height * used_h);
-			p[0].tiling = planeconfigs[i].tiling;
-			pointlocation(data, (planeinfos *)&p, mode, 0);
-
-			for (k = 0; k < ARRAY_SIZE(formatlist); k++) {
-				p[0].format = formatlist[k];
-
-				for (j = 0; j < ARRAY_SIZE(planeconfigs); j++) {
-					p[1].planetype = DRM_PLANE_TYPE_OVERLAY;
-					p[1].width = (uint64_t)(planeconfigs[j].width * used_w);
-					p[1].height = (uint64_t)(planeconfigs[j].height * used_h);
-					p[1].tiling = planeconfigs[j].tiling;
-					pointlocation(data, (planeinfos *)&p,
-						      mode, 1);
-
-					for (l = 0; l < ARRAY_SIZE(formatlist); l++) {
-						p[1].format = formatlist[l];
-
-						/*
-						 * RGB565 90/270 degrees rotation is supported
-						 * from gen11 onwards.
-						 */
-						if (p[0].format == DRM_FORMAT_RGB565 &&
-						     (planeconfigs[i].rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
-						     && intel_gen(data->devid) < 11)
-							continue;
-
-						if (p[1].format == DRM_FORMAT_RGB565 &&
-						     (planeconfigs[j].rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
-						     && intel_gen(data->devid) < 11)
-							continue;
-
-						p[0].rotation_sw = planeconfigs[i].rotation;
-						p[0].rotation_hw = IGT_ROTATION_0;
-						p[1].rotation_sw = planeconfigs[j].rotation;
-						p[1].rotation_hw = IGT_ROTATION_0;
-						if (!get_multiplane_crc(data, output, &retcrc_sw,
-								   (planeinfos *)&p, MAXMULTIPLANESAMOUNT))
-							continue;
-
-						igt_swap(p[0].rotation_sw, p[0].rotation_hw);
-						igt_swap(p[1].rotation_sw, p[1].rotation_hw);
-						if (!get_multiplane_crc(data, output, &retcrc_hw,
-								   (planeinfos *)&p, MAXMULTIPLANESAMOUNT))
-							continue;
-
-						igt_assert_crc_equal(&retcrc_sw, &retcrc_hw);
-					}
-				}
-			}
-		}
-		igt_pipe_crc_stop(data->pipe_crc);
-		igt_pipe_crc_free(data->pipe_crc);
-		igt_output_set_pipe(output, PIPE_ANY);
-	}
-
-	/*
-	* Old fbs are deleted only after new ones are set on planes.
-	* This is done to speed up the test
-	*/
-	oldplanes = data->multiplaneoldview;
-	for (c = 0; c < MAXMULTIPLANESAMOUNT && oldplanes; c++)
-		igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
-
-	free(oldplanes);
-	data->multiplaneoldview = NULL;
-	data->pipe_crc = NULL;
-}
-
-static void test_plane_rotation_exhaust_fences(data_t *data,
-					       enum pipe pipe,
-					       igt_output_t *output,
-					       igt_plane_t *plane)
-{
-	igt_display_t *display = &data->display;
-	uint64_t tiling = LOCAL_I915_FORMAT_MOD_Y_TILED;
-	uint32_t format = DRM_FORMAT_XRGB8888;
-	int fd = data->gfx_fd;
-	drmModeModeInfo *mode;
-	struct igt_fb fb[MAX_FENCES+1] = {};
-	uint64_t size;
-	unsigned int stride, w, h;
-	uint64_t total_aperture_size, total_fbs_size;
-	int i;
-
-	igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
-
-	prepare_crtc(data, output, pipe, plane, false);
-
-	mode = igt_output_get_mode(output);
-	w = mode->hdisplay;
-	h = mode->vdisplay;
-
-	igt_calc_fb_size(fd, w, h, format, tiling, &size, &stride);
-
-	/*
-	 * Make sure there is atleast 90% of the available GTT space left
-	 * for creating (MAX_FENCES+1) framebuffers.
-	 */
-	total_fbs_size = size * (MAX_FENCES + 1);
-	total_aperture_size = gem_available_aperture_size(fd);
-	igt_require(total_fbs_size < total_aperture_size * 0.9);
-
-	for (i = 0; i < MAX_FENCES + 1; i++) {
-		igt_create_fb(fd, w, h, format, tiling, &fb[i]);
-
-		igt_plane_set_fb(plane, &fb[i]);
-		igt_plane_set_rotation(plane, IGT_ROTATION_0);
-		igt_display_commit2(display, COMMIT_ATOMIC);
-
-		igt_plane_set_rotation(plane, IGT_ROTATION_90);
-		igt_plane_set_size(plane, h, w);
-		igt_display_commit2(display, COMMIT_ATOMIC);
-	}
-
-	for (i = 0; i < MAX_FENCES + 1; i++)
-		igt_remove_fb(fd, &fb[i]);
-}
-
-static const char *plane_test_str(unsigned plane)
-{
-	switch (plane) {
-	case DRM_PLANE_TYPE_PRIMARY:
-		return "primary";
-	case DRM_PLANE_TYPE_OVERLAY:
-		return "sprite";
-	case DRM_PLANE_TYPE_CURSOR:
-		return "cursor";
-	default:
-		igt_assert(0);
-	}
-}
-
-static const char *rot_test_str(igt_rotation_t rot)
-{
-	switch (rot) {
-	case IGT_ROTATION_0:
-		return "0";
-	case IGT_ROTATION_90:
-		return "90";
-	case IGT_ROTATION_180:
-		return "180";
-	case IGT_ROTATION_270:
-		return "270";
-	default:
-		igt_assert(0);
-	}
-}
-
-static const char *tiling_test_str(uint64_t tiling)
-{
-	switch (tiling) {
-	case LOCAL_I915_FORMAT_MOD_X_TILED:
-		return "x-tiled";
-	case LOCAL_I915_FORMAT_MOD_Y_TILED:
-		return "y-tiled";
-	case LOCAL_I915_FORMAT_MOD_Yf_TILED:
-		return "yf-tiled";
-	default:
-		igt_assert(0);
-	}
-}
-
-static int opt_handler(int opt, int opt_index, void *_data)
-{
-	data_t *data = _data;
-
-	switch (opt) {
-	case 'e':
-		data->extended = true;
-		break;
-	}
-
-	return IGT_OPT_HANDLER_SUCCESS;
-}
-
-static const struct option long_opts[] = {
-	{ .name = "extended", .has_arg = false, .val = 'e', },
-	{}
-};
-
-static const char help_str[] =
-	"  --extended\t\tRun the extended tests\n";
-
-static data_t data;
-
-igt_main_args("", long_opts, help_str, opt_handler, &data)
-{
-	struct rot_subtest {
-		unsigned plane;
-		igt_rotation_t rot;
-	} *subtest, subtests[] = {
-		{ DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_90 },
-		{ DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_180 },
-		{ DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_270 },
-		{ DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_90 },
-		{ DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_180 },
-		{ DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_270 },
-		{ DRM_PLANE_TYPE_CURSOR, IGT_ROTATION_180 },
-		{ 0, 0}
-	};
-
-	struct reflect_x {
-		uint64_t tiling;
-		igt_rotation_t rot;
-	} *reflect_x, reflect_x_subtests[] = {
-		{ LOCAL_I915_FORMAT_MOD_X_TILED, IGT_ROTATION_0 },
-		{ LOCAL_I915_FORMAT_MOD_X_TILED, IGT_ROTATION_180 },
-		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_0 },
-		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_90 },
-		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_180 },
-		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_270 },
-		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_0 },
-		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_90 },
-		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_180 },
-		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_270 },
-		{ 0, 0 }
-	};
-
-	int gen = 0;
-
-	igt_fixture {
-		data.gfx_fd = drm_open_driver_master(DRIVER_INTEL);
-		data.devid = intel_get_drm_devid(data.gfx_fd);
-		gen = intel_gen(data.devid);
-
-		kmstest_set_vt_graphics_mode();
-
-		igt_require_pipe_crc(data.gfx_fd);
-
-		igt_display_require(&data.display, data.gfx_fd);
-		igt_require(data.display.is_atomic);
-	}
-
-	for (subtest = subtests; subtest->rot; subtest++) {
-		igt_subtest_f("%s-rotation-%s",
-			      plane_test_str(subtest->plane),
-			      rot_test_str(subtest->rot)) {
-			igt_require(!(subtest->rot &
-				    (IGT_ROTATION_90 | IGT_ROTATION_270)) ||
-				    gen >= 9);
-			data.rotation = subtest->rot;
-			test_plane_rotation(&data, subtest->plane, false);
-		}
-	}
-
-	igt_subtest_f("sprite-rotation-90-pos-100-0") {
-		igt_require(gen >= 9);
-		data.rotation = IGT_ROTATION_90;
-		data.pos_x = 100,
-		data.pos_y = 0;
-		test_plane_rotation(&data, DRM_PLANE_TYPE_OVERLAY, false);
-	}
-	data.pos_x = 0,
-	data.pos_y = 0;
-
-	igt_subtest_f("bad-pixel-format") {
-		 /* gen11 enables RGB565 rotation for 90/270 degrees.
-		  * so apart from this, any other gen11+ pixel format
-		  * can be used which doesn't support 90/270 degree
-		  * rotation */
-		igt_require(gen >= 9);
-		data.rotation = IGT_ROTATION_90;
-		data.override_fmt = gen < 11 ? DRM_FORMAT_RGB565 : DRM_FORMAT_Y212;
-		test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, true);
-	}
-	data.override_fmt = 0;
-
-	igt_subtest_f("bad-tiling") {
-		igt_require(gen >= 9);
-		data.rotation = IGT_ROTATION_90;
-		data.override_tiling = LOCAL_I915_FORMAT_MOD_X_TILED;
-		test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, true);
-	}
-	data.override_tiling = 0;
-
-	for (reflect_x = reflect_x_subtests; reflect_x->tiling; reflect_x++) {
-		igt_subtest_f("primary-%s-reflect-x-%s",
-			      tiling_test_str(reflect_x->tiling),
-			      rot_test_str(reflect_x->rot)) {
-			igt_require(gen >= 10 ||
-				    (IS_CHERRYVIEW(data.devid) && reflect_x->rot == IGT_ROTATION_0
-				     && reflect_x->tiling == LOCAL_I915_FORMAT_MOD_X_TILED));
-			data.rotation = (IGT_REFLECT_X | reflect_x->rot);
-			data.override_tiling = reflect_x->tiling;
-			test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, false);
-		}
-	}
-
-	igt_subtest_f("multiplane-rotation") {
-		igt_require(gen >= 9);
-		cleanup_crtc(&data);
-		data.planepos[0].origo = p_top | p_left;
-		data.planepos[0].x = .2f;
-		data.planepos[0].y = .1f;
-		data.planepos[1].origo = p_top | p_right;
-		data.planepos[1].x = -.4f;
-		data.planepos[1].y = .1f;
-		test_multi_plane_rotation(&data, 0);
-	}
-
-	igt_subtest_f("multiplane-rotation-cropping-top") {
-		igt_require(gen >= 9);
-		cleanup_crtc(&data);
-		data.planepos[0].origo = p_top | p_left;
-		data.planepos[0].x = -.05f;
-		data.planepos[0].y = -.15f;
-		data.planepos[1].origo = p_top | p_right;
-		data.planepos[1].x = -.15f;
-		data.planepos[1].y = -.15f;
-		test_multi_plane_rotation(&data, 0);
-	}
-
-	igt_subtest_f("multiplane-rotation-cropping-bottom") {
-		igt_require(gen >= 9);
-		cleanup_crtc(&data);
-		data.planepos[0].origo = p_bottom | p_left;
-		data.planepos[0].x = -.05f;
-		data.planepos[0].y = -.20f;
-		data.planepos[1].origo = p_bottom | p_right;
-		data.planepos[1].x = -.15f;
-		data.planepos[1].y = -.20f;
-		test_multi_plane_rotation(&data, 0);
-	}
-
-	/*
-	 * exhaust-fences should be last test, if it fails we may OOM in
-	 * the following subtests otherwise.
-	 */
-	igt_subtest_f("exhaust-fences") {
-		enum pipe pipe;
-		igt_output_t *output;
-
-		igt_require(gen >= 9);
-		igt_display_require_output(&data.display);
-
-		for_each_pipe_with_valid_output(&data.display, pipe, output) {
-			igt_plane_t *primary = &data.display.pipes[pipe].planes[0];
-
-			test_plane_rotation_exhaust_fences(&data, pipe, output, primary);
-			break;
-		}
-	}
-
-	igt_fixture {
-		igt_display_fini(&data.display);
-	}
-}
+/*
+ * Copyright © 2013,2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "igt.h"
+#include "igt_vec.h"
+#include <math.h>
+
+#define MAX_FENCES 32
+#define MAXMULTIPLANESAMOUNT 2
+#define TEST_MAX_WIDTH 640
+#define TEST_MAX_HEIGHT 480
+
+struct p_struct {
+	igt_plane_t *plane;
+	struct igt_fb fb;
+};
+
+enum p_pointorigo {
+	p_top = 1 << 0,
+	p_bottom = 1 << 1,
+	p_left = 1 << 2,
+	p_right = 1 << 3
+};
+
+struct p_point{
+	enum p_pointorigo origo;
+	float_t x;
+	float_t y;
+};
+
+typedef struct {
+	int gfx_fd;
+	igt_display_t display;
+	struct igt_fb fb;
+	struct igt_fb fb_reference;
+	struct igt_fb fb_flip;
+	igt_crc_t ref_crc;
+	igt_crc_t flip_crc;
+	igt_pipe_crc_t *pipe_crc;
+	igt_rotation_t rotation;
+	int pos_x;
+	int pos_y;
+	uint32_t override_fmt;
+	uint64_t override_tiling;
+	int devid;
+
+	struct p_struct *multiplaneoldview;
+	struct p_point planepos[MAXMULTIPLANESAMOUNT];
+
+	bool use_native_resolution;
+	bool extended;
+} data_t;
+
+typedef struct {
+	float r;
+	float g;
+	float b;
+} rgb_color_t;
+
+static void set_color(rgb_color_t *color, float r, float g, float b)
+{
+	color->r = r;
+	color->g = g;
+	color->b = b;
+}
+
+static void rotate_colors(rgb_color_t *tl, rgb_color_t *tr, rgb_color_t *br,
+			  rgb_color_t *bl, igt_rotation_t rotation)
+{
+	rgb_color_t bl_tmp, br_tmp, tl_tmp, tr_tmp;
+
+	if (rotation & IGT_REFLECT_X) {
+		igt_swap(*tl, *tr);
+		igt_swap(*bl, *br);
+	}
+
+	if (rotation & IGT_ROTATION_90) {
+		bl_tmp = *bl;
+		br_tmp = *br;
+		tl_tmp = *tl;
+		tr_tmp = *tr;
+		*tl = tr_tmp;
+		*bl = tl_tmp;
+		*tr = br_tmp;
+		*br = bl_tmp;
+	} else if (rotation & IGT_ROTATION_180) {
+		igt_swap(*tl, *br);
+		igt_swap(*tr, *bl);
+	} else if (rotation & IGT_ROTATION_270) {
+		bl_tmp = *bl;
+		br_tmp = *br;
+		tl_tmp = *tl;
+		tr_tmp = *tr;
+		*tl = bl_tmp;
+		*bl = br_tmp;
+		*tr = tl_tmp;
+		*br = tr_tmp;
+	}
+}
+
+#define RGB_COLOR(color) \
+	color.r, color.g, color.b
+
+static void
+paint_squares(data_t *data, igt_rotation_t rotation,
+	      struct igt_fb *fb, float o)
+{
+	cairo_t *cr;
+	unsigned int w = fb->width;
+	unsigned int h = fb->height;
+	rgb_color_t tl, tr, bl, br;
+
+	igt_assert_f(!(w&1), "rotation image must be even width, now attempted %d\n", w);
+	igt_assert_f(!(h&1), "rotation image must be even height, now attempted %d\n", h);
+
+	cr = igt_get_cairo_ctx(data->gfx_fd, fb);
+
+	set_color(&tl, o, 0.0f, 0.0f);
+	set_color(&tr, 0.0f, o, 0.0f);
+	set_color(&br, o, o, o);
+	set_color(&bl, 0.0f, 0.0f, o);
+
+	rotate_colors(&tl, &tr, &br, &bl, rotation);
+
+	igt_paint_color(cr, 0, 0, w / 2, h / 2, RGB_COLOR(tl));
+	igt_paint_color(cr, w / 2, 0, w / 2, h / 2, RGB_COLOR(tr));
+	igt_paint_color(cr, 0, h / 2, w / 2, h / 2, RGB_COLOR(bl));
+	igt_paint_color(cr, w / 2, h / 2, w / 2, h / 2, RGB_COLOR(br));
+
+	igt_put_cairo_ctx(cr);
+}
+
+static void remove_fbs(data_t *data)
+{
+	igt_remove_fb(data->gfx_fd, &data->fb);
+	igt_remove_fb(data->gfx_fd, &data->fb_reference);
+	igt_remove_fb(data->gfx_fd, &data->fb_flip);
+}
+
+static void cleanup_crtc(data_t *data)
+{
+	igt_display_t *display = &data->display;
+
+	igt_pipe_crc_free(data->pipe_crc);
+	data->pipe_crc = NULL;
+
+	remove_fbs(data);
+
+	igt_display_reset(display);
+}
+
+static void prepare_crtc(data_t *data, igt_output_t *output, enum pipe pipe,
+			 igt_plane_t *plane, bool start_crc)
+{
+	igt_display_t *display = &data->display;
+
+	cleanup_crtc(data);
+
+	igt_output_set_pipe(output, pipe);
+	igt_plane_set_rotation(plane, IGT_ROTATION_0);
+
+	/* create the pipe_crc object for this pipe */
+	igt_pipe_crc_free(data->pipe_crc);
+
+	if (is_amdgpu_device(data->gfx_fd)) {
+		igt_fb_t fb_temp;
+
+		igt_create_fb(data->gfx_fd, 1280, 800, DRM_FORMAT_XRGB8888, 0, &fb_temp);
+		igt_plane_set_fb(plane, &fb_temp);
+	}
+	igt_display_commit2(display, COMMIT_ATOMIC);
+	data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe, INTEL_PIPE_CRC_SOURCE_AUTO);
+
+	if (start_crc)
+		igt_pipe_crc_start(data->pipe_crc);
+}
+
+enum rectangle_type {
+	rectangle,
+	square,
+	portrait,
+	landscape,
+	num_rectangle_types /* must be last */
+};
+
+static void prepare_fbs(data_t *data, igt_output_t *output,
+			igt_plane_t *plane, enum rectangle_type rect, uint32_t format)
+{
+	drmModeModeInfo *mode;
+	igt_display_t *display = &data->display;
+	unsigned int w, h, ref_w, ref_h, min_w, min_h;
+	uint64_t tiling = data->override_tiling ?: LOCAL_DRM_FORMAT_MOD_NONE;
+	uint32_t pixel_format = data->override_fmt ?: DRM_FORMAT_XRGB8888;
+	const float flip_opacity = 0.75;
+	bool amd_gpu = is_amdgpu_device(data->gfx_fd);
+	bool intel_gpu = is_i915_device(data->gfx_fd);
+
+	remove_fbs(data);
+
+	igt_plane_set_rotation(plane, IGT_ROTATION_0);
+
+	mode = igt_output_get_mode(output);
+	if (plane->type != DRM_PLANE_TYPE_CURSOR) {
+		if (amd_gpu) {
+			w = mode->hdisplay;
+			h = mode->vdisplay;
+		} else if (intel_gpu) {
+			if (data->use_native_resolution) {
+				w = mode->hdisplay;
+				h = mode->vdisplay;
+			} else {
+				w = min(TEST_MAX_WIDTH, mode->hdisplay);
+				h = min(TEST_MAX_HEIGHT, mode->vdisplay);
+			}
+
+			min_w = 256;
+			min_h = 256;
+		}
+	} else {
+		pixel_format = data->override_fmt ?: DRM_FORMAT_ARGB8888;
+
+		w = h = 256;
+		min_w = min_h = 64;
+	}
+
+	switch (rect) {
+	case rectangle:
+		break;
+	case square:
+		w = h = min(h, w);
+		break;
+	case portrait:
+		w = min_w;
+		break;
+	case landscape:
+		h = min_h;
+		break;
+	case num_rectangle_types:
+		igt_assert(0);
+	}
+
+	ref_w = w;
+	ref_h = h;
+
+	/*
+	 * For 90/270, we will use create smaller fb so that the rotated
+	 * frame can fit in
+	 */
+	if (data->rotation & (IGT_ROTATION_90 | IGT_ROTATION_270)) {
+		if (intel_gpu)
+			tiling = data->override_tiling ?: LOCAL_I915_FORMAT_MOD_Y_TILED;
+
+		igt_swap(w, h);
+	}
+
+	/*
+	 * Just try here if requested tiling format is generally available,
+	 * if one format fail it will skip entire subtest.
+	 */
+	igt_require(igt_display_has_format_mod(display, pixel_format, tiling));
+
+	if (intel_gpu) {
+		/*
+		 * Create a reference software rotated flip framebuffer.
+		 */
+		igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format, tiling,
+			      &data->fb_flip);
+		paint_squares(data, data->rotation, &data->fb_flip,
+			      flip_opacity);
+		igt_plane_set_fb(plane, &data->fb_flip);
+		if (plane->type != DRM_PLANE_TYPE_CURSOR)
+			igt_plane_set_position(plane, data->pos_x, data->pos_y);
+		igt_display_commit2(display, COMMIT_ATOMIC);
+
+		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &data->flip_crc);
+
+		/*
+		  * Prepare the non-rotated flip fb.
+		  */
+		igt_remove_fb(data->gfx_fd, &data->fb_flip);
+		igt_create_fb(data->gfx_fd, w, h, pixel_format, tiling,
+			      &data->fb_flip);
+		paint_squares(data, IGT_ROTATION_0, &data->fb_flip,
+			      flip_opacity);
+
+		/*
+		 * Create a reference CRC for a software-rotated fb.
+		 */
+		igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format,
+			      data->override_tiling ?: LOCAL_DRM_FORMAT_MOD_NONE, &data->fb_reference);
+	} else if (amd_gpu) {
+		tiling = 0x1900;
+		igt_create_fb(data->gfx_fd, ref_w, ref_h, pixel_format,
+				  tiling, &data->fb_reference);
+	}
+	paint_squares(data, data->rotation, &data->fb_reference, 1.0);
+
+	igt_plane_set_fb(plane, &data->fb_reference);
+	if (plane->type != DRM_PLANE_TYPE_CURSOR)
+		igt_plane_set_position(plane, data->pos_x, data->pos_y);
+	igt_display_commit2(display, COMMIT_ATOMIC);
+
+	if (intel_gpu)
+		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &data->ref_crc);
+	else if (amd_gpu)
+		igt_pipe_crc_collect_crc(data->pipe_crc, &data->ref_crc);
+
+	/*
+	 * Prepare the plane with an non-rotated fb let the hw rotate it.
+	 */
+	igt_create_fb(data->gfx_fd, w, h, pixel_format, tiling, &data->fb);
+	paint_squares(data, IGT_ROTATION_0, &data->fb, 1.0);
+	igt_plane_set_fb(plane, &data->fb);
+
+	if (plane->type != DRM_PLANE_TYPE_CURSOR)
+		igt_plane_set_position(plane, data->pos_x, data->pos_y);
+}
+
+static void 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)
+{
+	igt_display_t *display = &data->display;
+	igt_crc_t crc_output;
+	int ret;
+
+	igt_debug("Testing case %i on pipe %s, format %s\n", rect, kmstest_pipe_name(pipe), igt_format_str(format));
+	prepare_fbs(data, output, plane, rect, format);
+
+	igt_plane_set_rotation(plane, data->rotation);
+	if (data->rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
+		igt_plane_set_size(plane, data->fb.height, data->fb.width);
+
+	ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
+	if (test_bad_format) {
+		igt_assert_eq(ret, -EINVAL);
+		return;
+	}
+
+	/* Verify commit was ok. */
+	igt_assert_eq(ret, 0);
+
+	if (is_i915_device(data->gfx_fd)) {
+		/* Check CRC */
+		igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc_output);
+		igt_assert_crc_equal(&data->ref_crc, &crc_output);
+
+		/*
+		 * If flips are requested flip to a different fb and
+		 * check CRC against that one as well.
+		 */
+		if (data->fb_flip.fb_id) {
+			igt_plane_set_fb(plane, &data->fb_flip);
+			if (data->rotation == IGT_ROTATION_90 || data->rotation == IGT_ROTATION_270)
+				igt_plane_set_size(plane, data->fb.height, data->fb.width);
+
+			if (plane->type != DRM_PLANE_TYPE_PRIMARY) {
+				igt_display_commit_atomic(display, DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK, NULL);
+			} else {
+				ret = drmModePageFlip(data->gfx_fd,
+						output->config.crtc->crtc_id,
+						data->fb_flip.fb_id,
+						DRM_MODE_PAGE_FLIP_EVENT,
+						NULL);
+				igt_assert_eq(ret, 0);
+			}
+			kmstest_wait_for_pageflip(data->gfx_fd);
+			igt_pipe_crc_get_current(display->drm_fd, data->pipe_crc, &crc_output);
+			igt_assert_crc_equal(&data->flip_crc,
+					     &crc_output);
+		}
+	} else if (is_amdgpu_device(data->gfx_fd)) {
+		igt_pipe_crc_collect_crc(data->pipe_crc, &crc_output);
+	}
+}
+
+static bool test_format(data_t *data,
+			struct igt_vec *tested_formats,
+			uint32_t format)
+{
+	if (!igt_fb_supported_format(format))
+		return false;
+
+	if (!is_i915_device(data->gfx_fd) ||
+	    data->extended)
+		return true;
+
+	format = igt_reduce_format(format);
+
+	/* only test each format "class" once */
+	if (igt_vec_index(tested_formats, &format) >= 0)
+		return false;
+
+	igt_vec_push(tested_formats, &format);
+
+	return true;
+}
+
+static void test_plane_rotation(data_t *data, int plane_type, bool test_bad_format)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output;
+	enum pipe pipe;
+
+	if (plane_type == DRM_PLANE_TYPE_CURSOR)
+		igt_require(display->has_cursor_plane);
+
+	igt_display_require_output(display);
+
+	for_each_pipe_with_valid_output(display, pipe, output) {
+		igt_plane_t *plane;
+		int i, j;
+
+		if (is_i915_device(data->gfx_fd)) {
+			if (IS_CHERRYVIEW(data->devid) && pipe != PIPE_B)
+				continue;
+
+			igt_output_set_pipe(output, pipe);
+
+			plane = igt_output_get_plane_type(output, plane_type);
+			igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
+
+			prepare_crtc(data, output, pipe, plane, true);
+
+			for (i = 0; i < num_rectangle_types; i++) {
+				/* Unsupported on i915 */
+				if (plane_type == DRM_PLANE_TYPE_CURSOR &&
+				    i != square)
+					continue;
+
+				/* Only support partial covering primary plane on gen9+ */
+				if (plane_type == DRM_PLANE_TYPE_PRIMARY &&
+				    intel_gen(intel_get_drm_devid(data->gfx_fd)) < 9) {
+					if (i != rectangle)
+						continue;
+					else
+						data->use_native_resolution = true;
+				} else {
+					data->use_native_resolution = false;
+				}
+
+				if (!data->override_fmt) {
+					struct igt_vec tested_formats;
+
+					igt_vec_init(&tested_formats, sizeof(uint32_t));
+
+					for (j = 0; j < plane->drm_plane->count_formats; j++) {
+						uint32_t format = plane->drm_plane->formats[j];
+
+						if (!test_format(data, &tested_formats, format))
+							continue;
+
+						test_single_case(data, pipe, output, plane, i,
+								 format, test_bad_format);
+					}
+
+					igt_vec_fini(&tested_formats);
+				} else {
+					test_single_case(data, pipe, output, plane, i,
+							 data->override_fmt, test_bad_format);
+				}
+			}
+		} else if (is_amdgpu_device(data->gfx_fd)) {
+			uint32_t format = DRM_FORMAT_XRGB8888;
+
+			igt_output_set_pipe(output, pipe);
+
+			plane = igt_output_get_plane_type(output, DRM_PLANE_TYPE_PRIMARY);
+			igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
+
+			prepare_crtc(data, output, pipe, plane, false);
+
+			if (plane_type != DRM_PLANE_TYPE_PRIMARY) {
+				plane = igt_output_get_plane_type(output, plane_type);
+				igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
+			}
+
+			test_single_case(data, pipe, output, plane,
+					 rectangle, format, test_bad_format);
+		}
+
+		igt_pipe_crc_stop(data->pipe_crc);
+	}
+}
+
+typedef struct {
+	int32_t x1, y1;
+	uint64_t width, height, tiling, planetype, format;
+	igt_rotation_t rotation_sw, rotation_hw;
+} planeinfos;
+
+static bool get_multiplane_crc(data_t *data, igt_output_t *output,
+			       igt_crc_t *crc_output, planeinfos *planeinfo,
+			       int numplanes)
+{
+	uint32_t w, h;
+	igt_display_t *display = &data->display;
+	struct p_struct *planes, *oldplanes;
+	int c, ret;
+
+	oldplanes = data->multiplaneoldview;
+	planes = calloc(sizeof(*planes), numplanes);
+
+	for (c = 0; c < numplanes; c++) {
+		planes[c].plane = igt_output_get_plane_type(output,
+							    planeinfo[c].planetype);
+
+		/*
+		 * make plane and fb width and height always divisible by 4
+		 * due to NV12 support and Intel hw workarounds.
+		 */
+		w = planeinfo[c].width & ~3;
+		h = planeinfo[c].height & ~3;
+
+		if (planeinfo[c].rotation_sw & (IGT_ROTATION_90 | IGT_ROTATION_270))
+			igt_swap(w, h);
+
+		if (!igt_plane_has_format_mod(planes[c].plane,
+					      planeinfo[c].format,
+					      planeinfo[c].tiling))
+			return false;
+
+		igt_create_fb(data->gfx_fd, w, h, planeinfo[c].format,
+			      planeinfo[c].tiling, &planes[c].fb);
+
+		paint_squares(data, planeinfo[c].rotation_sw, &planes[c].fb, 1.0f);
+		igt_plane_set_fb(planes[c].plane, &planes[c].fb);
+
+		if (planeinfo[c].rotation_hw & (IGT_ROTATION_90 | IGT_ROTATION_270))
+			igt_plane_set_size(planes[c].plane, h, w);
+
+		igt_plane_set_position(planes[c].plane, planeinfo[c].x1, planeinfo[c].y1);
+		igt_plane_set_rotation(planes[c].plane, planeinfo[c].rotation_hw);
+	}
+
+	ret = igt_display_try_commit2(display, COMMIT_ATOMIC);
+	igt_assert_eq(ret, 0);
+
+	igt_pipe_crc_get_current(data->gfx_fd, data->pipe_crc, crc_output);
+
+	for (c = 0; c < numplanes && oldplanes; c++)
+		igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
+
+	free(oldplanes);
+	data->multiplaneoldview = (void*)planes;
+	return true;
+}
+
+static void pointlocation(data_t *data, planeinfos *p, drmModeModeInfo *mode,
+			  int c)
+{
+	if (data->planepos[c].origo & p_right) {
+		p[c].x1 = (int32_t)(data->planepos[c].x * min(TEST_MAX_WIDTH, mode->hdisplay)
+				+ mode->hdisplay);
+		p[c].x1 &= ~3;
+		/*
+		 * At this point is handled surface on right side. If display
+		 * mode is not divisible by 4 but with 2 point location is
+		 * fixed to match requirements. Because of YUV planes here is
+		 * intentionally ignored bit 1.
+		 */
+		p[c].x1 -= mode->hdisplay & 2;
+	} else {
+		p[c].x1 = (int32_t)(data->planepos[c].x * min(TEST_MAX_WIDTH, mode->hdisplay));
+		p[c].x1 &= ~3;
+	}
+
+	if (data->planepos[c].origo & p_bottom) {
+		p[c].y1 = (int32_t)(data->planepos[c].y * min(TEST_MAX_HEIGHT, mode->vdisplay)
+				+ mode->vdisplay);
+		p[c].y1 &= ~3;
+		p[c].y1 -= mode->vdisplay & 2;
+	} else {
+		p[c].y1 = (int32_t)(data->planepos[c].y * min(TEST_MAX_HEIGHT, mode->vdisplay));
+		p[c].y1 &= ~3;
+	}
+}
+
+/*
+ * Here is pipe parameter which is now used only for first pipe.
+ * It is left here if this test ever was wanted to be run on
+ * different pipes.
+ */
+static void test_multi_plane_rotation(data_t *data, enum pipe pipe)
+{
+	igt_display_t *display = &data->display;
+	igt_output_t *output;
+	igt_crc_t retcrc_sw, retcrc_hw;
+	planeinfos p[2];
+	int c, used_w, used_h;
+	struct p_struct *oldplanes;
+	drmModeModeInfo *mode;
+
+	static const struct {
+		igt_rotation_t rotation;
+		float_t width;
+		float_t height;
+		uint64_t tiling;
+	} planeconfigs[] = {
+	{IGT_ROTATION_0, .2f, .4f, LOCAL_DRM_FORMAT_MOD_NONE },
+	{IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_X_TILED },
+	{IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_0, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	{IGT_ROTATION_90, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_90, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	{IGT_ROTATION_180, .2f, .4f, LOCAL_DRM_FORMAT_MOD_NONE },
+	{IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_X_TILED },
+	{IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_180, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	{IGT_ROTATION_270, .2f, .4f, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_270, .2f, .4f, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	};
+
+	/*
+	* These are those modes which are tested. For testing feel interesting
+	* case with tiling are 2 bpp, 4 bpp and NV12.
+	*/
+	static const uint32_t formatlist[] = {DRM_FORMAT_RGB565,
+		DRM_FORMAT_XRGB8888, DRM_FORMAT_NV12};
+
+	for_each_valid_output_on_pipe(display, pipe, output) {
+		int i, j, k, l;
+		igt_output_set_pipe(output, pipe);
+		mode = igt_output_get_mode(output);
+		igt_display_require_output(display);
+		igt_display_commit2(display, COMMIT_ATOMIC);
+
+		used_w = min(TEST_MAX_WIDTH, mode->hdisplay);
+		used_h = min(TEST_MAX_HEIGHT, mode->vdisplay);
+
+		data->pipe_crc = igt_pipe_crc_new(data->gfx_fd, pipe,
+						  INTEL_PIPE_CRC_SOURCE_AUTO);
+		igt_pipe_crc_start(data->pipe_crc);
+
+		for (i = 0; i < ARRAY_SIZE(planeconfigs); i++) {
+			p[0].planetype = DRM_PLANE_TYPE_PRIMARY;
+			p[0].width = (uint64_t)(planeconfigs[i].width * used_w);
+			p[0].height = (uint64_t)(planeconfigs[i].height * used_h);
+			p[0].tiling = planeconfigs[i].tiling;
+			pointlocation(data, (planeinfos *)&p, mode, 0);
+
+			for (k = 0; k < ARRAY_SIZE(formatlist); k++) {
+				p[0].format = formatlist[k];
+
+				for (j = 0; j < ARRAY_SIZE(planeconfigs); j++) {
+					p[1].planetype = DRM_PLANE_TYPE_OVERLAY;
+					p[1].width = (uint64_t)(planeconfigs[j].width * used_w);
+					p[1].height = (uint64_t)(planeconfigs[j].height * used_h);
+					p[1].tiling = planeconfigs[j].tiling;
+					pointlocation(data, (planeinfos *)&p,
+						      mode, 1);
+
+					for (l = 0; l < ARRAY_SIZE(formatlist); l++) {
+						p[1].format = formatlist[l];
+
+						/*
+						 * RGB565 90/270 degrees rotation is supported
+						 * from gen11 onwards.
+						 */
+						if (p[0].format == DRM_FORMAT_RGB565 &&
+						     (planeconfigs[i].rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
+						     && intel_gen(data->devid) < 11)
+							continue;
+
+						if (p[1].format == DRM_FORMAT_RGB565 &&
+						     (planeconfigs[j].rotation & (IGT_ROTATION_90 | IGT_ROTATION_270))
+						     && intel_gen(data->devid) < 11)
+							continue;
+
+						p[0].rotation_sw = planeconfigs[i].rotation;
+						p[0].rotation_hw = IGT_ROTATION_0;
+						p[1].rotation_sw = planeconfigs[j].rotation;
+						p[1].rotation_hw = IGT_ROTATION_0;
+						if (!get_multiplane_crc(data, output, &retcrc_sw,
+								   (planeinfos *)&p, MAXMULTIPLANESAMOUNT))
+							continue;
+
+						igt_swap(p[0].rotation_sw, p[0].rotation_hw);
+						igt_swap(p[1].rotation_sw, p[1].rotation_hw);
+						if (!get_multiplane_crc(data, output, &retcrc_hw,
+								   (planeinfos *)&p, MAXMULTIPLANESAMOUNT))
+							continue;
+
+						igt_assert_crc_equal(&retcrc_sw, &retcrc_hw);
+					}
+				}
+			}
+		}
+		igt_pipe_crc_stop(data->pipe_crc);
+		igt_pipe_crc_free(data->pipe_crc);
+		igt_output_set_pipe(output, PIPE_ANY);
+	}
+
+	/*
+	* Old fbs are deleted only after new ones are set on planes.
+	* This is done to speed up the test
+	*/
+	oldplanes = data->multiplaneoldview;
+	for (c = 0; c < MAXMULTIPLANESAMOUNT && oldplanes; c++)
+		igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
+
+	free(oldplanes);
+	data->multiplaneoldview = NULL;
+	data->pipe_crc = NULL;
+}
+
+static void test_plane_rotation_exhaust_fences(data_t *data,
+					       enum pipe pipe,
+					       igt_output_t *output,
+					       igt_plane_t *plane)
+{
+	igt_display_t *display = &data->display;
+	uint64_t tiling = LOCAL_I915_FORMAT_MOD_Y_TILED;
+	uint32_t format = DRM_FORMAT_XRGB8888;
+	int fd = data->gfx_fd;
+	drmModeModeInfo *mode;
+	struct igt_fb fb[MAX_FENCES+1] = {};
+	uint64_t size;
+	unsigned int stride, w, h;
+	uint64_t total_aperture_size, total_fbs_size;
+	int i;
+
+	igt_require(igt_plane_has_prop(plane, IGT_PLANE_ROTATION));
+
+	prepare_crtc(data, output, pipe, plane, false);
+
+	mode = igt_output_get_mode(output);
+	w = mode->hdisplay;
+	h = mode->vdisplay;
+
+	igt_calc_fb_size(fd, w, h, format, tiling, &size, &stride);
+
+	/*
+	 * Make sure there is atleast 90% of the available GTT space left
+	 * for creating (MAX_FENCES+1) framebuffers.
+	 */
+	total_fbs_size = size * (MAX_FENCES + 1);
+	total_aperture_size = gem_available_aperture_size(fd);
+	igt_require(total_fbs_size < total_aperture_size * 0.9);
+
+	for (i = 0; i < MAX_FENCES + 1; i++) {
+		igt_create_fb(fd, w, h, format, tiling, &fb[i]);
+
+		igt_plane_set_fb(plane, &fb[i]);
+		igt_plane_set_rotation(plane, IGT_ROTATION_0);
+		igt_display_commit2(display, COMMIT_ATOMIC);
+
+		igt_plane_set_rotation(plane, IGT_ROTATION_90);
+		igt_plane_set_size(plane, h, w);
+		igt_display_commit2(display, COMMIT_ATOMIC);
+	}
+
+	for (i = 0; i < MAX_FENCES + 1; i++)
+		igt_remove_fb(fd, &fb[i]);
+}
+
+static const char *plane_test_str(unsigned plane)
+{
+	switch (plane) {
+	case DRM_PLANE_TYPE_PRIMARY:
+		return "primary";
+	case DRM_PLANE_TYPE_OVERLAY:
+		return "sprite";
+	case DRM_PLANE_TYPE_CURSOR:
+		return "cursor";
+	default:
+		igt_assert(0);
+	}
+}
+
+static const char *rot_test_str(igt_rotation_t rot)
+{
+	switch (rot) {
+	case IGT_ROTATION_0:
+		return "0";
+	case IGT_ROTATION_90:
+		return "90";
+	case IGT_ROTATION_180:
+		return "180";
+	case IGT_ROTATION_270:
+		return "270";
+	default:
+		igt_assert(0);
+	}
+}
+
+static const char *tiling_test_str(uint64_t tiling)
+{
+	switch (tiling) {
+	case LOCAL_I915_FORMAT_MOD_X_TILED:
+		return "x-tiled";
+	case LOCAL_I915_FORMAT_MOD_Y_TILED:
+		return "y-tiled";
+	case LOCAL_I915_FORMAT_MOD_Yf_TILED:
+		return "yf-tiled";
+	default:
+		igt_assert(0);
+	}
+}
+
+static int opt_handler(int opt, int opt_index, void *_data)
+{
+	data_t *data = _data;
+
+	switch (opt) {
+	case 'e':
+		data->extended = true;
+		break;
+	}
+
+	return IGT_OPT_HANDLER_SUCCESS;
+}
+
+static const struct option long_opts[] = {
+	{ .name = "extended", .has_arg = false, .val = 'e', },
+	{}
+};
+
+static const char help_str[] =
+	"  --extended\t\tRun the extended tests\n";
+
+static data_t data;
+
+igt_main_args("", long_opts, help_str, opt_handler, &data)
+{
+	struct rot_subtest {
+		unsigned plane;
+		igt_rotation_t rot;
+	} *subtest, subtests[] = {
+		{ DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_90 },
+		{ DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_180 },
+		{ DRM_PLANE_TYPE_PRIMARY, IGT_ROTATION_270 },
+		{ DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_90 },
+		{ DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_180 },
+		{ DRM_PLANE_TYPE_OVERLAY, IGT_ROTATION_270 },
+		{ DRM_PLANE_TYPE_CURSOR, IGT_ROTATION_180 },
+		{ 0, 0}
+	};
+
+	struct reflect_x {
+		uint64_t tiling;
+		igt_rotation_t rot;
+	} *reflect_x, reflect_x_subtests[] = {
+		{ LOCAL_I915_FORMAT_MOD_X_TILED, IGT_ROTATION_0 },
+		{ LOCAL_I915_FORMAT_MOD_X_TILED, IGT_ROTATION_180 },
+		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_0 },
+		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_90 },
+		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_180 },
+		{ LOCAL_I915_FORMAT_MOD_Y_TILED, IGT_ROTATION_270 },
+		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_0 },
+		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_90 },
+		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_180 },
+		{ LOCAL_I915_FORMAT_MOD_Yf_TILED, IGT_ROTATION_270 },
+		{ 0, 0 }
+	};
+
+	int gen = 0;
+
+	igt_fixture {
+		data.gfx_fd = drm_open_driver_master(DRIVER_INTEL | DRIVER_AMDGPU);
+		if (is_i915_device(data.gfx_fd)) {
+			data.devid = intel_get_drm_devid(data.gfx_fd);
+			gen = intel_gen(data.devid);
+		}
+
+		kmstest_set_vt_graphics_mode();
+
+		igt_require_pipe_crc(data.gfx_fd);
+
+		igt_display_require(&data.display, data.gfx_fd);
+		igt_require(data.display.is_atomic);
+	}
+
+	for (subtest = subtests; subtest->rot; subtest++) {
+		igt_subtest_f("%s-rotation-%s",
+			      plane_test_str(subtest->plane),
+			      rot_test_str(subtest->rot)) {
+			if (is_i915_device(data.gfx_fd)) {
+				igt_require(!(subtest->rot &
+					    (IGT_ROTATION_90 | IGT_ROTATION_270)) ||
+					    gen >= 9);
+			}
+			data.rotation = subtest->rot;
+			test_plane_rotation(&data, subtest->plane, false);
+		}
+	}
+
+	igt_subtest_f("sprite-rotation-90-pos-100-0") {
+		igt_require(gen >= 9);
+		data.rotation = IGT_ROTATION_90;
+		data.pos_x = 100,
+		data.pos_y = 0;
+		test_plane_rotation(&data, DRM_PLANE_TYPE_OVERLAY, false);
+	}
+	data.pos_x = 0,
+	data.pos_y = 0;
+
+	igt_subtest_f("bad-pixel-format") {
+		 /* gen11 enables RGB565 rotation for 90/270 degrees.
+		  * so apart from this, any other gen11+ pixel format
+		  * can be used which doesn't support 90/270 degree
+		  * rotation */
+		igt_require(gen >= 9);
+		data.rotation = IGT_ROTATION_90;
+		data.override_fmt = gen < 11 ? DRM_FORMAT_RGB565 : DRM_FORMAT_Y212;
+		test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, true);
+	}
+	data.override_fmt = 0;
+
+	igt_subtest_f("bad-tiling") {
+		igt_require(gen >= 9);
+		data.rotation = IGT_ROTATION_90;
+		data.override_tiling = LOCAL_I915_FORMAT_MOD_X_TILED;
+		test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, true);
+	}
+	data.override_tiling = 0;
+
+	for (reflect_x = reflect_x_subtests; reflect_x->tiling; reflect_x++) {
+		igt_subtest_f("primary-%s-reflect-x-%s",
+			      tiling_test_str(reflect_x->tiling),
+			      rot_test_str(reflect_x->rot)) {
+			igt_require(gen >= 10 ||
+				    (IS_CHERRYVIEW(data.devid) && reflect_x->rot == IGT_ROTATION_0
+				     && reflect_x->tiling == LOCAL_I915_FORMAT_MOD_X_TILED));
+			data.rotation = (IGT_REFLECT_X | reflect_x->rot);
+			data.override_tiling = reflect_x->tiling;
+			test_plane_rotation(&data, DRM_PLANE_TYPE_PRIMARY, false);
+		}
+	}
+
+	igt_subtest_f("multiplane-rotation") {
+		igt_require(gen >= 9);
+		cleanup_crtc(&data);
+		data.planepos[0].origo = p_top | p_left;
+		data.planepos[0].x = .2f;
+		data.planepos[0].y = .1f;
+		data.planepos[1].origo = p_top | p_right;
+		data.planepos[1].x = -.4f;
+		data.planepos[1].y = .1f;
+		test_multi_plane_rotation(&data, 0);
+	}
+
+	igt_subtest_f("multiplane-rotation-cropping-top") {
+		igt_require(gen >= 9);
+		cleanup_crtc(&data);
+		data.planepos[0].origo = p_top | p_left;
+		data.planepos[0].x = -.05f;
+		data.planepos[0].y = -.15f;
+		data.planepos[1].origo = p_top | p_right;
+		data.planepos[1].x = -.15f;
+		data.planepos[1].y = -.15f;
+		test_multi_plane_rotation(&data, 0);
+	}
+
+	igt_subtest_f("multiplane-rotation-cropping-bottom") {
+		igt_require(gen >= 9);
+		cleanup_crtc(&data);
+		data.planepos[0].origo = p_bottom | p_left;
+		data.planepos[0].x = -.05f;
+		data.planepos[0].y = -.20f;
+		data.planepos[1].origo = p_bottom | p_right;
+		data.planepos[1].x = -.15f;
+		data.planepos[1].y = -.20f;
+		test_multi_plane_rotation(&data, 0);
+	}
+
+	/*
+	 * exhaust-fences should be last test, if it fails we may OOM in
+	 * the following subtests otherwise.
+	 */
+	igt_subtest_f("exhaust-fences") {
+		enum pipe pipe;
+		igt_output_t *output;
+
+		igt_require(gen >= 9);
+		igt_display_require_output(&data.display);
+
+		for_each_pipe_with_valid_output(&data.display, pipe, output) {
+			igt_plane_t *primary = &data.display.pipes[pipe].planes[0];
+
+			test_plane_rotation_exhaust_fences(&data, pipe, output, primary);
+			break;
+		}
+	}
+
+	igt_fixture {
+		igt_display_fini(&data.display);
+	}
+}
-- 
2.25.1



More information about the igt-dev mailing list