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

Kim, Sung joon Sungjoon.Kim at amd.com
Wed Dec 16 22:43:02 UTC 2020


Sorry this didn't send completely. I will send a new set.

-----Original Message-----
From: Kim, Sung joon <Sungjoon.Kim at amd.com> 
Sent: Wednesday, December 16, 2020 5:13 PM
To: igt-dev at lists.freedesktop.org
Cc: Kazlauskas, Nicholas <Nicholas.Kazlauskas at amd.com>; sunpengli at amd.com; Wentland, Harry <Harry.Wentland at amd.com>; Cornij, Nikola <Nikola.Cornij at amd.com>; Kim, Sung joon <Sungjoon.Kim at amd.com>
Subject: [PATCH] kms_rotation_crc:Add HW rotation test case for amdgpu

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