From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by gabe.freedesktop.org (Postfix) with ESMTPS id 070CC6E6DD for ; Fri, 16 Nov 2018 12:28:12 +0000 (UTC) From: "Nautiyal, Ankit K" References: <1540473975-32669-1-git-send-email-juhapekka.heikkila@gmail.com> <1540558693-28252-1-git-send-email-juhapekka.heikkila@gmail.com> Message-ID: Date: Fri, 16 Nov 2018 17:58:06 +0530 MIME-Version: 1.0 In-Reply-To: <1540558693-28252-1-git-send-email-juhapekka.heikkila@gmail.com> Subject: Re: [igt-dev] [PATCH i-g-t] tests/kms_rotation_crc: Add multi plane tests. List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: multipart/mixed; boundary="===============1182282719==" Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" To: Juha-Pekka Heikkila , "igt-dev@lists.freedesktop.org" List-ID: This is a multi-part message in MIME format. --===============1182282719== Content-Type: multipart/alternative; boundary="------------1CADA74B083C053BFAD726AD" This is a multi-part message in MIME format. --------------1CADA74B083C053BFAD726AD Content-Type: text/plain; charset=iso-8859-15; format=flowed Content-Transfer-Encoding: 7bit Hi Juha-Pekka, The new test added do cover the gap of having multiple-plane rotation together, along with the top and bottom cropping scenarios. The test work well for square figures i.e. the width = height =512, but for rectangular figure, the test needs some fix in get_multiplane_crc(), as this function does not assume that the width and height are same. Please find suggestions inline. Other than that, I could only nitpick some of the styling issues given inline. On 10/26/2018 6:28 PM, Juha-Pekka Heikkila wrote: > Add three new tests which try primary and sprite planes > next to each other with different plane formats, rotations > and tiling modes. > > multiplane-rotation subtest run test through with both planes > fully visible. > > multiplane-rotation-cropping-top will crop primary plane to > left/top corner and sprite plane to right/top corner while running > rotation tests. > > multiplane-rotation-cropping-bottom will crop primary plane to > left/bottom corner and sprite plane to right/bottom corner while > running rotation tests. > > Signed-off-by: Juha-Pekka Heikkila > --- > tests/kms_rotation_crc.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 249 insertions(+) > > diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c > index 366c254..df9ac91 100644 > --- a/tests/kms_rotation_crc.c > +++ b/tests/kms_rotation_crc.c > @@ -26,6 +26,25 @@ > #include > > #define MAX_FENCES 32 > +#define MAXMULTIPLANESAMOUNT 2 > + > +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; > + int32_t x; > + int32_t y; > +}; > > typedef struct { > int gfx_fd; > @@ -43,6 +62,9 @@ typedef struct { > uint32_t override_fmt; > uint64_t override_tiling; > int devid; > + > + struct p_struct *multiplaneoldview; > + struct p_point planepos[MAXMULTIPLANESAMOUNT]; > } data_t; > > typedef struct { > @@ -395,6 +417,197 @@ static void test_plane_rotation(data_t *data, int plane_type, bool test_bad_form > } > } > > +typedef struct { > + int32_t x1, y1; > + uint64_t width, height, tiling, planetype, format; > + igt_rotation_t rotation_sw, rotation_hw; > +} planeinfos; > + > +static void 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 = malloc(sizeof(*planes)*numplanes); > + > + for (c = 0; c < numplanes; c++) { > + planes[c].plane = igt_output_get_plane_type(output, > + planeinfo[c].planetype); > + > + w = planeinfo[c].width; > + h = planeinfo[c].height; > + > + if ((planeinfo[c].rotation_hw|planeinfo[c].rotation_sw) > + &(IGT_ROTATION_90|IGT_ROTATION_270)) > + igt_swap(w, h); > + In case of an actual hardware rotation 90 and 270, the width and height should not be swapped. The 'if condition' should have only check for rotation_sw, and not for rotation_hw. > + igt_plane_set_size(planes[c].plane, w, h); For 90 and 270 degree rotation (i.e. rotation_hw) , igt_plane_set_size() should have height in place of width and vice-versa. if (rotation_hw & (IGT_ROTATION_90 | IGT_ROTATION_270) igt_plane_set_size(plane[c].plane, h, w); Further more this function igt_plane_set_size should be called after igt_plane_set_fb(), because igt_plane_set_fb sets the plane size with fb.width and fb.height, thereby overwriting our values. > + > + 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); > + 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; > +} > + > +static void pointlocation(data_t *data, planeinfos* p, drmModeModeInfo *mode, > + int c) > +{ > + p[c].x1 = data->planepos[c].x > + +((data->planepos[c].origo&p_right)?mode->hdisplay:0); > + p[c].y1 = data->planepos[c].y > + +((data->planepos[c].origo&p_bottom)?mode->vdisplay:0); > +} Space around '&' and '?' > + > +/* > + * 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; > + struct p_struct *oldplanes; > + drmModeModeInfo *mode; > + > + const static struct { > + igt_rotation_t rotation; > + uint64_t width; > + uint64_t height; > + uint64_t tiling; > + } planeconfigs[] = { > + {IGT_ROTATION_0, 512, 512, LOCAL_DRM_FORMAT_MOD_NONE }, In my humble opinion, we can use a rectangle content, instead of a square content. The function get_muliplane_crc already takes care of different width and height. Only change will be required in function point_location. > + {IGT_ROTATION_0, 512, 512, LOCAL_I915_FORMAT_MOD_X_TILED }, > + {IGT_ROTATION_0, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED }, > + {IGT_ROTATION_0, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED }, > + {IGT_ROTATION_90, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED }, > + {IGT_ROTATION_90, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED }, > + {IGT_ROTATION_180, 512, 512, LOCAL_DRM_FORMAT_MOD_NONE }, > + {IGT_ROTATION_180, 512, 512, LOCAL_I915_FORMAT_MOD_X_TILED }, > + {IGT_ROTATION_180, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED }, > + {IGT_ROTATION_180, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED }, > + {IGT_ROTATION_270, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED }, > + {IGT_ROTATION_270, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED }, > + }; > + > + /* > + * These are those modes which are tested. For testing feel interesting > + * case with tiling are 2 byte wide and 4 byte wide. > + * > + * TODO: > + * Built support for NV12 here. > + */ > + const static uint32_t formatlist[] = {DRM_FORMAT_RGB565, > + DRM_FORMAT_XRGB8888}; > + > + > + 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); > + > + 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 = planeconfigs[i].width; > + p[0].height = planeconfigs[i].height; > + 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 = planeconfigs[j].width; > + p[1].height = planeconfigs[j].height; > + 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)) Space around '&' and '|' > + && 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; > + get_multiplane_crc(data, output, &retcrc_sw, > + (planeinfos*)&p, MAXMULTIPLANESAMOUNT); > + > + igt_swap(p[0].rotation_sw, p[0].rotation_hw); > + igt_swap(p[1].rotation_sw, p[1].rotation_hw); > + get_multiplane_crc(data, output, &retcrc_hw, > + (planeinfos*)&p, MAXMULTIPLANESAMOUNT); > + > + 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, > @@ -595,6 +808,42 @@ igt_main > } > } > > + igt_subtest_f("multiplane-rotation") { > + igt_require(gen >= 9); > + cleanup_crtc(&data); > + data.planepos[0].origo = p_top|p_left; > + data.planepos[0].x = 128; > + data.planepos[0].y = 128; > + data.planepos[1].origo = p_top|p_right; > + data.planepos[1].x = -128-512; Space around '|' and '-' operators. Valid for few more lines below. Not sure if we will ever hit a case where there is a lower resolution e.g. 640x480, the figure will be cropped, which is not desired, the test however would still pass as crc would match. Perhaps we can skip if resolution is less than some threshold. > + data.planepos[1].y = 128; > + 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 = -128; > + data.planepos[0].y = -128; > + data.planepos[1].origo = p_top|p_right; > + data.planepos[1].x = -512+128; > + data.planepos[1].y = -128; > + 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 = -128; > + data.planepos[0].y = -512+128; > + data.planepos[1].origo = p_bottom|p_right; > + data.planepos[1].x = -512+128; > + data.planepos[1].y = -512+128; > + test_multi_plane_rotation(&data, 0); > + } > + > /* > * exhaust-fences should be last test, if it fails we may OOM in > * the following subtests otherwise. > > > --------------1CADA74B083C053BFAD726AD Content-Type: text/html; charset="iso-8859-15" Content-Transfer-Encoding: quoted-printable

Hi Juha-Pekka,

The new test added do cover the gap of having multiple-plane rotation together, along with the top and bottom cropping scenarios.

The test work well for square figures i.e. the width =3D height =3D512, but for rectangular figure, the test needs some fix in get_multiplane_crc(), as this function does not assume that the width and height are same.

Please find suggestions inline.

Other than that, I could only nitpick some of the styling issues given inline.

On 10/26/2018 6:28 PM, Juha-Pekka Heikkila wrote:
Add three new tests which try primary and sprite planes
next to each other with different plane formats, rotations
and tiling modes.

multiplane-rotation subtest run test through with both planes
fully visible.

multiplane-rotation-cropping-top will crop primary plane to
left/top corner and sprite plane to right/top corner while running
rotation tests.

multiplane-rotation-cropping-bottom will crop primary plane to
left/bottom corner and sprite plane to right/bottom corner while
running rotation tests.

Signed-off-by: Juha-Pekka Heikkila <juhapekka.heikkila@gmail.com&g=
t;
---
 tests/kms_rotation_crc.c | 249 +++++++++++++++++++++++++++++++++++++++++++=
++++
 1 file changed, 249 insertions(+)

diff --git a/tests/kms_rotation_crc.c b/tests/kms_rotation_crc.c
index 366c254..df9ac91 100644
--- a/tests/kms_rotation_crc.c
+++ b/tests/kms_rotation_crc.c
@@ -26,6 +26,25 @@
 #include <math.h>
=20
 #define MAX_FENCES 32
+#define MAXMULTIPLANESAMOUNT 2
+
+struct p_struct {
+	igt_plane_t *plane;
+	struct igt_fb fb;
+};
+
+enum p_pointorigo {
+	p_top =3D 1 << 0,
+	p_bottom =3D 1 << 1,
+	p_left =3D 1 << 2,
+	p_right =3D 1 << 3
+};
+
+struct p_point{
+	enum p_pointorigo origo;
+	int32_t x;
+	int32_t y;
+};
=20
 typedef struct {
 	int gfx_fd;
@@ -43,6 +62,9 @@ typedef struct {
 	uint32_t override_fmt;
 	uint64_t override_tiling;
 	int devid;
+
+	struct p_struct *multiplaneoldview;
+	struct p_point planepos[MAXMULTIPLANESAMOUNT];
 } data_t;
=20
 typedef struct {
@@ -395,6 +417,197 @@ static void test_plane_rotation(data_t *data, int pla=
ne_type, bool test_bad_form
 	}
 }
=20
+typedef struct {
+	int32_t x1, y1;
+	uint64_t width, height, tiling, planetype, format;
+	igt_rotation_t rotation_sw, rotation_hw;
+} planeinfos;
+
+static void 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 =3D &data->display;
+	struct p_struct *planes, *oldplanes;
+	int c, ret;
+
+	oldplanes =3D data->multiplaneoldview;
+	planes =3D malloc(sizeof(*planes)*numplanes);
+
+	for (c =3D 0; c < numplanes; c++) {
+		planes[c].plane =3D igt_output_get_plane_type(output,
+							    planeinfo[c].planetype);
+
+		w =3D planeinfo[c].width;
+		h =3D planeinfo[c].height;
+
+		if ((planeinfo[c].rotation_hw|planeinfo[c].rotation_sw)
+		    &(IGT_ROTATION_90|IGT_ROTATION_270))
+			igt_swap(w, h);
+
In case of an actual hardware rotation 90 and 270, the width and height should not be swapped.
The 'if condition' should have only check for rotation_sw, and not for rotation_hw.

+		igt_plane_set_size(planes[c].plane, w, h);
For 90 and 270 degree rotation (i.e. rotation_hw) ,=A0 igt_plane_set_size() should have height in place of width and vice-versa.

if (rotation_hw & (IGT_ROTATION_90 | IGT_ROTATION_270)
=A0=A0=A0 =A0=A0=A0 igt_plane_set_size(plane[c].plane, h, w);

Further more this function igt_plane_set_size should be called after igt_plane_set_fb(), because igt_plane_set_fb sets the plane size with fb.width and fb.height, thereby overwriting our values.

+
+		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);
+		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 =3D 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 =3D 0; c < numplanes && oldplanes; c++)
+		igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
+
+	free(oldplanes);
+	data->multiplaneoldview =3D (void*)planes;
+}
+
+static void pointlocation(data_t *data, planeinfos* p, drmModeModeInfo *mo=
de,
+			  int c)
+{
+	p[c].x1 =3D data->planepos[c].x
+			+((data->planepos[c].origo&p_right)?mode->hdisplay:0);
+	p[c].y1 =3D data->planepos[c].y
+			+((data->planepos[c].origo&p_bottom)?mode->vdisplay:0);
+}

Space around '&' and '?'

+
+/*
+ * 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 =3D &data->display;
+	igt_output_t *output;
+	igt_crc_t retcrc_sw, retcrc_hw;
+	planeinfos p[2];
+	int c;
+	struct p_struct *oldplanes;
+	drmModeModeInfo *mode;
+
+	const static struct {
+		igt_rotation_t	rotation;
+		uint64_t	width;
+		uint64_t	height;
+		uint64_t	tiling;
+	} planeconfigs[] =3D {
+	{IGT_ROTATION_0, 512, 512, LOCAL_DRM_FORMAT_MOD_NONE },

In my humble opinion, we can use a rectangle content, instead of a square content. The function get_muliplane_crc already takes care of different width and height.
Only change will be required in function point_location.

+	{IGT_ROTATION_0, 512, 512, LOCAL_I915_FORMAT_MOD_X_T=
ILED },
+	{IGT_ROTATION_0, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_0, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	{IGT_ROTATION_90, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_90, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	{IGT_ROTATION_180, 512, 512, LOCAL_DRM_FORMAT_MOD_NONE },
+	{IGT_ROTATION_180, 512, 512, LOCAL_I915_FORMAT_MOD_X_TILED },
+	{IGT_ROTATION_180, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_180, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	{IGT_ROTATION_270, 512, 512, LOCAL_I915_FORMAT_MOD_Y_TILED },
+	{IGT_ROTATION_270, 512, 512, LOCAL_I915_FORMAT_MOD_Yf_TILED },
+	};
+
+	/*
+	* These are those modes which are tested. For testing feel interesting
+	* case with tiling are 2 byte wide and 4 byte wide.
+	*
+	* TODO:
+	* Built support for NV12 here.
+	*/
+	const static uint32_t  formatlist[] =3D {DRM_FORMAT_RGB565,
+					       DRM_FORMAT_XRGB8888};
+
+
+	for_each_valid_output_on_pipe(display, pipe, output) {
+		int i, j, k, l;
+		igt_output_set_pipe(output, pipe);
+
+		mode =3D igt_output_get_mode(output);
+
+		igt_display_require_output(display);
+		igt_display_commit2(display, COMMIT_ATOMIC);
+
+		data->pipe_crc =3D igt_pipe_crc_new(data->gfx_fd, pipe,
+						  INTEL_PIPE_CRC_SOURCE_AUTO);
+		igt_pipe_crc_start(data->pipe_crc);
+
+		for (i =3D 0; i < ARRAY_SIZE(planeconfigs); i++) {
+			p[0].planetype =3D DRM_PLANE_TYPE_PRIMARY;
+			p[0].width =3D planeconfigs[i].width;
+			p[0].height =3D planeconfigs[i].height;
+			p[0].tiling =3D planeconfigs[i].tiling;
+			pointlocation(data, (planeinfos*)&p, mode, 0);
+
+			for (k =3D 0; k < ARRAY_SIZE(formatlist); k++) {
+				p[0].format =3D formatlist[k];
+
+				for (j =3D 0; j < ARRAY_SIZE(planeconfigs); j++) {
+					p[1].planetype =3D DRM_PLANE_TYPE_OVERLAY;
+					p[1].width =3D planeconfigs[j].width;
+					p[1].height =3D planeconfigs[j].height;
+					p[1].tiling =3D planeconfigs[j].tiling;
+					pointlocation(data, (planeinfos*)&p,
+						      mode, 1);
+
+					for (l =3D 0; l < ARRAY_SIZE(formatlist); l++) {
+						p[1].format =3D formatlist[l];
+
+						/*
+						 * RGB565 90/270 degrees rotation is supported
+						 * from gen11 onwards.
+						 */
+						if (p[0].format =3D=3D DRM_FORMAT_RGB565 &&
+						     (planeconfigs[i].rotation&(IGT_ROTATION_90|IGT_ROTATION_270=
))
+						     && intel_gen(data->devid) < 11)
+							continue;
+
+						if (p[1].format =3D=3D DRM_FORMAT_RGB565 &&
+						     (planeconfigs[j].rotation&(IGT_ROTATION_90|IGT_ROTATION_270=
))
Space around '&' and '|'
+						     && intel_gen(data->devid) < =
11)
+							continue;
+
+
+						p[0].rotation_sw =3D planeconfigs[i].rotation;
+						p[0].rotation_hw =3D IGT_ROTATION_0;
+						p[1].rotation_sw =3D planeconfigs[j].rotation;
+						p[1].rotation_hw =3D IGT_ROTATION_0;
+						get_multiplane_crc(data, output, &retcrc_sw,
+								   (planeinfos*)&p, MAXMULTIPLANESAMOUNT);
+
+						igt_swap(p[0].rotation_sw, p[0].rotation_hw);
+						igt_swap(p[1].rotation_sw, p[1].rotation_hw);
+						get_multiplane_crc(data, output, &retcrc_hw,
+								   (planeinfos*)&p, MAXMULTIPLANESAMOUNT);
+
+						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 =3D data->multiplaneoldview;
+	for (c =3D 0; c < MAXMULTIPLANESAMOUNT && oldplanes; c++)
+		igt_remove_fb(data->gfx_fd, &oldplanes[c].fb);
+
+	free(oldplanes);
+	data->multiplaneoldview =3D NULL;
+	data->pipe_crc =3D NULL;
+}
+
 static void test_plane_rotation_exhaust_fences(data_t *data,
 					       enum pipe pipe,
 					       igt_output_t *output,
@@ -595,6 +808,42 @@ igt_main
 		}
 	}
=20
+	igt_subtest_f("multiplane-rotation") {
+		igt_require(gen >=3D 9);
+		cleanup_crtc(&data);
+		data.planepos[0].origo =3D p_top|p_left;
+		data.planepos[0].x =3D 128;
+		data.planepos[0].y =3D 128;
+		data.planepos[1].origo =3D p_top|p_right;
+		data.planepos[1].x =3D -128-512;
Space around '|' and '-' operators. Valid for few more lines below.
Not sure if we will ever hit a case where there is a lower resolution e.g. 640x480, the figure will be cropped, which is not desired, the test however would still pass as crc would match.
Perhaps we can skip if resolution is less than some threshold.

+		data.planepos[1].y =3D 128;
+		test_multi_plane_rotation(&data, 0);
+	}
+
+	igt_subtest_f("multiplane-rotation-cropping-top") {
+		igt_require(gen >=3D 9);
+		cleanup_crtc(&data);
+		data.planepos[0].origo =3D p_top|p_left;
+		data.planepos[0].x =3D -128;
+		data.planepos[0].y =3D -128;
+		data.planepos[1].origo =3D p_top|p_right;
+		data.planepos[1].x =3D -512+128;
+		data.planepos[1].y =3D -128;
+		test_multi_plane_rotation(&data, 0);
+	}
+
+	igt_subtest_f("multiplane-rotation-cropping-bottom") {
+		igt_require(gen >=3D 9);
+		cleanup_crtc(&data);
+		data.planepos[0].origo =3D p_bottom|p_left;
+		data.planepos[0].x =3D -128;
+		data.planepos[0].y =3D -512+128;
+		data.planepos[1].origo =3D p_bottom|p_right;
+		data.planepos[1].x =3D -512+128;
+		data.planepos[1].y =3D -512+128;
+		test_multi_plane_rotation(&data, 0);
+	}
+
 	/*
 	 * exhaust-fences should be last test, if it fails we may OOM in
 	 * the following subtests otherwise.

 =20

--------------1CADA74B083C053BFAD726AD-- --===============1182282719== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: base64 Content-Disposition: inline X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KaWd0LWRldiBt YWlsaW5nIGxpc3QKaWd0LWRldkBsaXN0cy5mcmVlZGVza3RvcC5vcmcKaHR0cHM6Ly9saXN0cy5m cmVlZGVza3RvcC5vcmcvbWFpbG1hbi9saXN0aW5mby9pZ3QtZGV2Cg== --===============1182282719==--