xref: /openbmc/linux/drivers/gpu/drm/tests/drm_rect_test.c (revision 0791faebfe750292a8a842b64795a390ca4a3b51)
193de485cSMaíra Canal // SPDX-License-Identifier: GPL-2.0
293de485cSMaíra Canal /*
393de485cSMaíra Canal  * Test cases for the drm_rect functions
493de485cSMaíra Canal  *
593de485cSMaíra Canal  * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>
693de485cSMaíra Canal  */
793de485cSMaíra Canal 
893de485cSMaíra Canal #include <kunit/test.h>
993de485cSMaíra Canal 
1093de485cSMaíra Canal #include <drm/drm_rect.h>
11b5d88ec0SArthur Grillo #include <drm/drm_mode.h>
1293de485cSMaíra Canal 
1396c31619SArthur Grillo #include <linux/string_helpers.h>
141f01f224SArthur Grillo #include <linux/errno.h>
1596c31619SArthur Grillo 
drm_rect_compare(struct kunit * test,const struct drm_rect * r,const struct drm_rect * expected)1696c31619SArthur Grillo static void drm_rect_compare(struct kunit *test, const struct drm_rect *r,
1796c31619SArthur Grillo 			     const struct drm_rect *expected)
1896c31619SArthur Grillo {
1996c31619SArthur Grillo 	KUNIT_EXPECT_EQ(test, r->x1, expected->x1);
2096c31619SArthur Grillo 	KUNIT_EXPECT_EQ(test, r->y1, expected->y1);
2196c31619SArthur Grillo 	KUNIT_EXPECT_EQ(test, drm_rect_width(r), drm_rect_width(expected));
2296c31619SArthur Grillo 	KUNIT_EXPECT_EQ(test, drm_rect_height(r), drm_rect_height(expected));
2396c31619SArthur Grillo }
2496c31619SArthur Grillo 
drm_test_rect_clip_scaled_div_by_zero(struct kunit * test)25961bcdf9SMaíra Canal static void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test)
2693de485cSMaíra Canal {
2793de485cSMaíra Canal 	struct drm_rect src, dst, clip;
2893de485cSMaíra Canal 	bool visible;
2993de485cSMaíra Canal 
3093de485cSMaíra Canal 	/*
3193de485cSMaíra Canal 	 * Make sure we don't divide by zero when dst
3293de485cSMaíra Canal 	 * width/height is zero and dst and clip do not intersect.
3393de485cSMaíra Canal 	 */
3493de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 0, 0);
3593de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 0, 0);
3693de485cSMaíra Canal 	drm_rect_init(&clip, 1, 1, 1, 1);
3793de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
3893de485cSMaíra Canal 
3993de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
4093de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
4193de485cSMaíra Canal 
4293de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 0, 0);
4393de485cSMaíra Canal 	drm_rect_init(&dst, 3, 3, 0, 0);
4493de485cSMaíra Canal 	drm_rect_init(&clip, 1, 1, 1, 1);
4593de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
4693de485cSMaíra Canal 
4793de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
4893de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
4993de485cSMaíra Canal }
5093de485cSMaíra Canal 
drm_test_rect_clip_scaled_not_clipped(struct kunit * test)51961bcdf9SMaíra Canal static void drm_test_rect_clip_scaled_not_clipped(struct kunit *test)
5293de485cSMaíra Canal {
5393de485cSMaíra Canal 	struct drm_rect src, dst, clip;
5493de485cSMaíra Canal 	bool visible;
5593de485cSMaíra Canal 
5693de485cSMaíra Canal 	/* 1:1 scaling */
5793de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
5893de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 1, 1);
5993de485cSMaíra Canal 	drm_rect_init(&clip, 0, 0, 1, 1);
6093de485cSMaíra Canal 
6193de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
6293de485cSMaíra Canal 
6393de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
6493de485cSMaíra Canal 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
6593de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
6693de485cSMaíra Canal 			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
6793de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
6893de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
6993de485cSMaíra Canal 
7093de485cSMaíra Canal 	/* 2:1 scaling */
7193de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
7293de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 1, 1);
7393de485cSMaíra Canal 	drm_rect_init(&clip, 0, 0, 1, 1);
7493de485cSMaíra Canal 
7593de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
7693de485cSMaíra Canal 
7793de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
7893de485cSMaíra Canal 			       src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
7993de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
8093de485cSMaíra Canal 			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
8193de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
8293de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
8393de485cSMaíra Canal 
8493de485cSMaíra Canal 	/* 1:2 scaling */
8593de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
8693de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 2, 2);
8793de485cSMaíra Canal 	drm_rect_init(&clip, 0, 0, 2, 2);
8893de485cSMaíra Canal 
8993de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
9093de485cSMaíra Canal 
9193de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
9293de485cSMaíra Canal 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
9393de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 ||
9493de485cSMaíra Canal 			       dst.y1 != 0 || dst.y2 != 2, "Destination badly clipped\n");
9593de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
9693de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
9793de485cSMaíra Canal }
9893de485cSMaíra Canal 
drm_test_rect_clip_scaled_clipped(struct kunit * test)99961bcdf9SMaíra Canal static void drm_test_rect_clip_scaled_clipped(struct kunit *test)
10093de485cSMaíra Canal {
10193de485cSMaíra Canal 	struct drm_rect src, dst, clip;
10293de485cSMaíra Canal 	bool visible;
10393de485cSMaíra Canal 
10493de485cSMaíra Canal 	/* 1:1 scaling top/left clip */
10593de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
10693de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 2, 2);
10793de485cSMaíra Canal 	drm_rect_init(&clip, 0, 0, 1, 1);
10893de485cSMaíra Canal 
10993de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
11093de485cSMaíra Canal 
11193de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
11293de485cSMaíra Canal 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
11393de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
11493de485cSMaíra Canal 			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
11593de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
11693de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
11793de485cSMaíra Canal 
11893de485cSMaíra Canal 	/* 1:1 scaling bottom/right clip */
11993de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
12093de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 2, 2);
12193de485cSMaíra Canal 	drm_rect_init(&clip, 1, 1, 1, 1);
12293de485cSMaíra Canal 
12393de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
12493de485cSMaíra Canal 
12593de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
12693de485cSMaíra Canal 			       src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
12793de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
12893de485cSMaíra Canal 			       dst.y2 != 2, "Destination badly clipped\n");
12993de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
13093de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
13193de485cSMaíra Canal 
13293de485cSMaíra Canal 	/* 2:1 scaling top/left clip */
13393de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
13493de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 2, 2);
13593de485cSMaíra Canal 	drm_rect_init(&clip, 0, 0, 1, 1);
13693de485cSMaíra Canal 
13793de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
13893de485cSMaíra Canal 
13993de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
14093de485cSMaíra Canal 			       src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
14193de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || dst.y1 != 0 ||
14293de485cSMaíra Canal 			       dst.y2 != 1, "Destination badly clipped\n");
14393de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
14493de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
14593de485cSMaíra Canal 
14693de485cSMaíra Canal 	/* 2:1 scaling bottom/right clip */
14793de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
14893de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 2, 2);
14993de485cSMaíra Canal 	drm_rect_init(&clip, 1, 1, 1, 1);
15093de485cSMaíra Canal 
15193de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
15293de485cSMaíra Canal 
15393de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
15493de485cSMaíra Canal 			       src.y1 != 2 << 16 || src.y2 != 4 << 16, "Source badly clipped\n");
15593de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
15693de485cSMaíra Canal 			       dst.y2 != 2, "Destination badly clipped\n");
15793de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
15893de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
15993de485cSMaíra Canal 
16093de485cSMaíra Canal 	/* 1:2 scaling top/left clip */
16193de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
16293de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 4, 4);
16393de485cSMaíra Canal 	drm_rect_init(&clip, 0, 0, 2, 2);
16493de485cSMaíra Canal 
16593de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
16693de485cSMaíra Canal 
16793de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
16893de485cSMaíra Canal 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
16993de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 || dst.y1 != 0 ||
17093de485cSMaíra Canal 			       dst.y2 != 2, "Destination badly clipped\n");
17193de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
17293de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
17393de485cSMaíra Canal 
17493de485cSMaíra Canal 	/* 1:2 scaling bottom/right clip */
17593de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
17693de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 4, 4);
17793de485cSMaíra Canal 	drm_rect_init(&clip, 2, 2, 2, 2);
17893de485cSMaíra Canal 
17993de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
18093de485cSMaíra Canal 
18193de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
18293de485cSMaíra Canal 			       src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
18393de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 2 || dst.x2 != 4 || dst.y1 != 2 ||
18493de485cSMaíra Canal 			       dst.y2 != 4, "Destination badly clipped\n");
18593de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
18693de485cSMaíra Canal 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
18793de485cSMaíra Canal }
18893de485cSMaíra Canal 
drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit * test)189961bcdf9SMaíra Canal static void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
19093de485cSMaíra Canal {
19193de485cSMaíra Canal 	struct drm_rect src, dst, clip;
19293de485cSMaíra Canal 	bool visible;
19393de485cSMaíra Canal 
19493de485cSMaíra Canal 	/*
19593de485cSMaíra Canal 	 * 'clip.x2 - dst.x1 >= dst width' could result a negative
19693de485cSMaíra Canal 	 * src rectangle width which is no longer expected by the
19793de485cSMaíra Canal 	 * code as it's using unsigned types. This could lead to
19893de485cSMaíra Canal 	 * the clipped source rectangle appering visible when it
19993de485cSMaíra Canal 	 * should have been fully clipped. Make sure both rectangles
20093de485cSMaíra Canal 	 * end up invisible.
20193de485cSMaíra Canal 	 */
20293de485cSMaíra Canal 	drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX);
20393de485cSMaíra Canal 	drm_rect_init(&dst, 0, 0, 2, 2);
20493de485cSMaíra Canal 	drm_rect_init(&clip, 3, 3, 1, 1);
20593de485cSMaíra Canal 
20693de485cSMaíra Canal 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
20793de485cSMaíra Canal 
20893de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible\n");
20993de485cSMaíra Canal 	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
21093de485cSMaíra Canal }
21193de485cSMaíra Canal 
21296c31619SArthur Grillo struct drm_rect_intersect_case {
21396c31619SArthur Grillo 	const char *description;
21496c31619SArthur Grillo 	struct drm_rect r1, r2;
21596c31619SArthur Grillo 	bool should_be_visible;
21696c31619SArthur Grillo 	struct drm_rect expected_intersection;
21796c31619SArthur Grillo };
21896c31619SArthur Grillo 
21996c31619SArthur Grillo static const struct drm_rect_intersect_case drm_rect_intersect_cases[] = {
22096c31619SArthur Grillo 	{
22196c31619SArthur Grillo 		.description = "top-left x bottom-right",
22296c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(1, 1, 2, 2),
22396c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(0, 0, 2, 2),
22496c31619SArthur Grillo 		.should_be_visible = true,
22596c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
22696c31619SArthur Grillo 	},
22796c31619SArthur Grillo 	{
22896c31619SArthur Grillo 		.description = "top-right x bottom-left",
22996c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
23096c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(1, -1, 2, 2),
23196c31619SArthur Grillo 		.should_be_visible = true,
23296c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
23396c31619SArthur Grillo 	},
23496c31619SArthur Grillo 	{
23596c31619SArthur Grillo 		.description = "bottom-left x top-right",
23696c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(1, -1, 2, 2),
23796c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(0, 0, 2, 2),
23896c31619SArthur Grillo 		.should_be_visible = true,
23996c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
24096c31619SArthur Grillo 	},
24196c31619SArthur Grillo 	{
24296c31619SArthur Grillo 		.description = "bottom-right x top-left",
24396c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
24496c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(1, 1, 2, 2),
24596c31619SArthur Grillo 		.should_be_visible = true,
24696c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
24796c31619SArthur Grillo 	},
24896c31619SArthur Grillo 	{
24996c31619SArthur Grillo 		.description = "right x left",
25096c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 2, 1),
25196c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(1, 0, 3, 1),
25296c31619SArthur Grillo 		.should_be_visible = true,
25396c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
25496c31619SArthur Grillo 	},
25596c31619SArthur Grillo 	{
25696c31619SArthur Grillo 		.description = "left x right",
25796c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(1, 0, 3, 1),
25896c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(0, 0, 2, 1),
25996c31619SArthur Grillo 		.should_be_visible = true,
26096c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
26196c31619SArthur Grillo 	},
26296c31619SArthur Grillo 	{
26396c31619SArthur Grillo 		.description = "up x bottom",
26496c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 1, 2),
26596c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(0, -1, 1, 3),
26696c31619SArthur Grillo 		.should_be_visible = true,
26796c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
26896c31619SArthur Grillo 	},
26996c31619SArthur Grillo 	{
27096c31619SArthur Grillo 		.description = "bottom x up",
27196c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, -1, 1, 3),
27296c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(0, 0, 1, 2),
27396c31619SArthur Grillo 		.should_be_visible = true,
27496c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
27596c31619SArthur Grillo 	},
27696c31619SArthur Grillo 	{
27796c31619SArthur Grillo 		.description = "touching corner",
27896c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 1, 1),
27996c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(1, 1, 2, 2),
28096c31619SArthur Grillo 		.should_be_visible = false,
28196c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 1, 0, 0),
28296c31619SArthur Grillo 	},
28396c31619SArthur Grillo 	{
28496c31619SArthur Grillo 		.description = "touching side",
28596c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 1, 1),
28696c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(1, 0, 1, 1),
28796c31619SArthur Grillo 		.should_be_visible = false,
28896c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 0, 0, 1),
28996c31619SArthur Grillo 	},
29096c31619SArthur Grillo 	{
29196c31619SArthur Grillo 		.description = "equal rects",
29296c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
29396c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(0, 0, 2, 2),
29496c31619SArthur Grillo 		.should_be_visible = true,
29596c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(0, 0, 2, 2),
29696c31619SArthur Grillo 	},
29796c31619SArthur Grillo 	{
29896c31619SArthur Grillo 		.description = "inside another",
29996c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
30096c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(1, 1, 1, 1),
30196c31619SArthur Grillo 		.should_be_visible = true,
30296c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
30396c31619SArthur Grillo 	},
30496c31619SArthur Grillo 	{
30596c31619SArthur Grillo 		.description = "far away",
30696c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 1, 1),
30796c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(3, 6, 1, 1),
30896c31619SArthur Grillo 		.should_be_visible = false,
30996c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(3, 6, -2, -5),
31096c31619SArthur Grillo 	},
31196c31619SArthur Grillo 	{
31296c31619SArthur Grillo 		.description = "points intersecting",
31396c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(5, 10, 0, 0),
31496c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(5, 10, 0, 0),
31596c31619SArthur Grillo 		.should_be_visible = false,
31696c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(5, 10, 0, 0),
31796c31619SArthur Grillo 	},
31896c31619SArthur Grillo 	{
31996c31619SArthur Grillo 		.description = "points not intersecting",
32096c31619SArthur Grillo 		.r1 = DRM_RECT_INIT(0, 0, 0, 0),
32196c31619SArthur Grillo 		.r2 = DRM_RECT_INIT(5, 10, 0, 0),
32296c31619SArthur Grillo 		.should_be_visible = false,
32396c31619SArthur Grillo 		.expected_intersection = DRM_RECT_INIT(5, 10, -5, -10),
32496c31619SArthur Grillo 	},
32596c31619SArthur Grillo };
32696c31619SArthur Grillo 
drm_rect_intersect_case_desc(const struct drm_rect_intersect_case * t,char * desc)32796c31619SArthur Grillo static void drm_rect_intersect_case_desc(const struct drm_rect_intersect_case *t, char *desc)
32896c31619SArthur Grillo {
32996c31619SArthur Grillo 	snprintf(desc, KUNIT_PARAM_DESC_SIZE,
33096c31619SArthur Grillo 		 "%s: " DRM_RECT_FMT " x " DRM_RECT_FMT,
33196c31619SArthur Grillo 		 t->description, DRM_RECT_ARG(&t->r1), DRM_RECT_ARG(&t->r2));
33296c31619SArthur Grillo }
33396c31619SArthur Grillo 
33496c31619SArthur Grillo KUNIT_ARRAY_PARAM(drm_rect_intersect, drm_rect_intersect_cases, drm_rect_intersect_case_desc);
33596c31619SArthur Grillo 
drm_test_rect_intersect(struct kunit * test)33696c31619SArthur Grillo static void drm_test_rect_intersect(struct kunit *test)
33796c31619SArthur Grillo {
33896c31619SArthur Grillo 	const struct drm_rect_intersect_case *params = test->param_value;
33996c31619SArthur Grillo 	struct drm_rect r1_aux = params->r1;
34096c31619SArthur Grillo 	bool visible;
34196c31619SArthur Grillo 
34296c31619SArthur Grillo 	visible = drm_rect_intersect(&r1_aux, &params->r2);
34396c31619SArthur Grillo 
34496c31619SArthur Grillo 	KUNIT_EXPECT_EQ(test, visible, params->should_be_visible);
34596c31619SArthur Grillo 	drm_rect_compare(test, &r1_aux, &params->expected_intersection);
34696c31619SArthur Grillo }
34796c31619SArthur Grillo 
3481f01f224SArthur Grillo struct drm_rect_scale_case {
3491f01f224SArthur Grillo 	const char *name;
3501f01f224SArthur Grillo 	struct drm_rect src, dst;
3511f01f224SArthur Grillo 	int min_range, max_range;
3521f01f224SArthur Grillo 	int expected_scaling_factor;
3531f01f224SArthur Grillo };
3541f01f224SArthur Grillo 
3551f01f224SArthur Grillo static const struct drm_rect_scale_case drm_rect_scale_cases[] = {
3561f01f224SArthur Grillo 	{
3571f01f224SArthur Grillo 		.name = "normal use",
3581f01f224SArthur Grillo 		.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
3591f01f224SArthur Grillo 		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
3601f01f224SArthur Grillo 		.min_range = 0, .max_range = INT_MAX,
3611f01f224SArthur Grillo 		.expected_scaling_factor = 2,
3621f01f224SArthur Grillo 	},
3631f01f224SArthur Grillo 	{
3641f01f224SArthur Grillo 		.name = "out of max range",
3651f01f224SArthur Grillo 		.src = DRM_RECT_INIT(0, 0, 10 << 16, 10 << 16),
3661f01f224SArthur Grillo 		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
3671f01f224SArthur Grillo 		.min_range = 3, .max_range = 5,
3681f01f224SArthur Grillo 		.expected_scaling_factor = -ERANGE,
3691f01f224SArthur Grillo 	},
3701f01f224SArthur Grillo 	{
3711f01f224SArthur Grillo 		.name = "out of min range",
3721f01f224SArthur Grillo 		.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
3731f01f224SArthur Grillo 		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
3741f01f224SArthur Grillo 		.min_range = 3, .max_range = 5,
3751f01f224SArthur Grillo 		.expected_scaling_factor = -ERANGE,
3761f01f224SArthur Grillo 	},
3771f01f224SArthur Grillo 	{
3781f01f224SArthur Grillo 		.name = "zero dst",
3791f01f224SArthur Grillo 		.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
3801f01f224SArthur Grillo 		.dst = DRM_RECT_INIT(0, 0, 0 << 16, 0 << 16),
3811f01f224SArthur Grillo 		.min_range = 0, .max_range = INT_MAX,
3821f01f224SArthur Grillo 		.expected_scaling_factor = 0,
3831f01f224SArthur Grillo 	},
3841f01f224SArthur Grillo 	{
3851f01f224SArthur Grillo 		.name = "negative src",
3861f01f224SArthur Grillo 		.src = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
3871f01f224SArthur Grillo 		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
3881f01f224SArthur Grillo 		.min_range = 0, .max_range = INT_MAX,
3891f01f224SArthur Grillo 		.expected_scaling_factor = -EINVAL,
3901f01f224SArthur Grillo 	},
3911f01f224SArthur Grillo 	{
3921f01f224SArthur Grillo 		.name = "negative dst",
3931f01f224SArthur Grillo 		.src = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
3941f01f224SArthur Grillo 		.dst = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
3951f01f224SArthur Grillo 		.min_range = 0, .max_range = INT_MAX,
3961f01f224SArthur Grillo 		.expected_scaling_factor = -EINVAL,
3971f01f224SArthur Grillo 	},
3981f01f224SArthur Grillo };
3991f01f224SArthur Grillo 
drm_rect_scale_case_desc(const struct drm_rect_scale_case * t,char * desc)4001f01f224SArthur Grillo static void drm_rect_scale_case_desc(const struct drm_rect_scale_case *t, char *desc)
4011f01f224SArthur Grillo {
4021f01f224SArthur Grillo 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
4031f01f224SArthur Grillo }
4041f01f224SArthur Grillo 
4051f01f224SArthur Grillo KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc);
4061f01f224SArthur Grillo 
drm_test_rect_calc_hscale(struct kunit * test)4071f01f224SArthur Grillo static void drm_test_rect_calc_hscale(struct kunit *test)
4081f01f224SArthur Grillo {
4091f01f224SArthur Grillo 	const struct drm_rect_scale_case *params = test->param_value;
4101f01f224SArthur Grillo 	int scaling_factor;
4111f01f224SArthur Grillo 
4121f01f224SArthur Grillo 	scaling_factor = drm_rect_calc_hscale(&params->src, &params->dst,
4131f01f224SArthur Grillo 					      params->min_range, params->max_range);
4141f01f224SArthur Grillo 
4151f01f224SArthur Grillo 	KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
4161f01f224SArthur Grillo }
4171f01f224SArthur Grillo 
drm_test_rect_calc_vscale(struct kunit * test)418881e2a9cSArthur Grillo static void drm_test_rect_calc_vscale(struct kunit *test)
419881e2a9cSArthur Grillo {
420881e2a9cSArthur Grillo 	const struct drm_rect_scale_case *params = test->param_value;
421881e2a9cSArthur Grillo 	int scaling_factor;
422881e2a9cSArthur Grillo 
423881e2a9cSArthur Grillo 	scaling_factor = drm_rect_calc_vscale(&params->src, &params->dst,
424881e2a9cSArthur Grillo 					      params->min_range, params->max_range);
425881e2a9cSArthur Grillo 
426881e2a9cSArthur Grillo 	KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
427881e2a9cSArthur Grillo }
428881e2a9cSArthur Grillo 
429b5d88ec0SArthur Grillo struct drm_rect_rotate_case {
430b5d88ec0SArthur Grillo 	const char *name;
431b5d88ec0SArthur Grillo 	unsigned int rotation;
432b5d88ec0SArthur Grillo 	struct drm_rect rect;
433b5d88ec0SArthur Grillo 	int width, height;
434b5d88ec0SArthur Grillo 	struct drm_rect expected;
435b5d88ec0SArthur Grillo };
436b5d88ec0SArthur Grillo 
437b5d88ec0SArthur Grillo static const struct drm_rect_rotate_case drm_rect_rotate_cases[] = {
438b5d88ec0SArthur Grillo 	{
439b5d88ec0SArthur Grillo 		.name = "reflect-x",
440b5d88ec0SArthur Grillo 		.rotation = DRM_MODE_REFLECT_X,
441b5d88ec0SArthur Grillo 		.rect = DRM_RECT_INIT(0, 0, 5, 5),
442b5d88ec0SArthur Grillo 		.width = 5, .height = 10,
443b5d88ec0SArthur Grillo 		.expected = DRM_RECT_INIT(0, 0, 5, 5),
444b5d88ec0SArthur Grillo 	},
445b5d88ec0SArthur Grillo 	{
446b5d88ec0SArthur Grillo 		.name = "reflect-y",
447b5d88ec0SArthur Grillo 		.rotation = DRM_MODE_REFLECT_Y,
448b5d88ec0SArthur Grillo 		.rect = DRM_RECT_INIT(2, 0, 5, 5),
449b5d88ec0SArthur Grillo 		.width = 5, .height = 10,
450b5d88ec0SArthur Grillo 		.expected = DRM_RECT_INIT(2, 5, 5, 5),
451b5d88ec0SArthur Grillo 	},
452b5d88ec0SArthur Grillo 	{
453b5d88ec0SArthur Grillo 		.name = "rotate-0",
454b5d88ec0SArthur Grillo 		.rotation = DRM_MODE_ROTATE_0,
455b5d88ec0SArthur Grillo 		.rect = DRM_RECT_INIT(0, 2, 5, 5),
456b5d88ec0SArthur Grillo 		.width = 5, .height = 10,
457b5d88ec0SArthur Grillo 		.expected = DRM_RECT_INIT(0, 2, 5, 5),
458b5d88ec0SArthur Grillo 	},
459b5d88ec0SArthur Grillo 	{
460b5d88ec0SArthur Grillo 		.name = "rotate-90",
461b5d88ec0SArthur Grillo 		.rotation = DRM_MODE_ROTATE_90,
462b5d88ec0SArthur Grillo 		.rect = DRM_RECT_INIT(0, 0, 5, 10),
463b5d88ec0SArthur Grillo 		.width = 5, .height = 10,
464b5d88ec0SArthur Grillo 		.expected = DRM_RECT_INIT(0, 0, 10, 5),
465b5d88ec0SArthur Grillo 	},
466b5d88ec0SArthur Grillo 	{
467b5d88ec0SArthur Grillo 		.name = "rotate-180",
468b5d88ec0SArthur Grillo 		.rotation = DRM_MODE_ROTATE_180,
469b5d88ec0SArthur Grillo 		.rect = DRM_RECT_INIT(11, 3, 5, 10),
470b5d88ec0SArthur Grillo 		.width = 5, .height = 10,
471b5d88ec0SArthur Grillo 		.expected = DRM_RECT_INIT(-11, -3, 5, 10),
472b5d88ec0SArthur Grillo 	},
473b5d88ec0SArthur Grillo 	{
474b5d88ec0SArthur Grillo 		.name = "rotate-270",
475b5d88ec0SArthur Grillo 		.rotation = DRM_MODE_ROTATE_270,
476b5d88ec0SArthur Grillo 		.rect = DRM_RECT_INIT(6, 3, 5, 10),
477b5d88ec0SArthur Grillo 		.width = 5, .height = 10,
478b5d88ec0SArthur Grillo 		.expected = DRM_RECT_INIT(-3, 6, 10, 5),
479b5d88ec0SArthur Grillo 	},
480b5d88ec0SArthur Grillo };
481b5d88ec0SArthur Grillo 
drm_rect_rotate_case_desc(const struct drm_rect_rotate_case * t,char * desc)482b5d88ec0SArthur Grillo static void drm_rect_rotate_case_desc(const struct drm_rect_rotate_case *t, char *desc)
483b5d88ec0SArthur Grillo {
484b5d88ec0SArthur Grillo 	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
485b5d88ec0SArthur Grillo }
486b5d88ec0SArthur Grillo 
487b5d88ec0SArthur Grillo KUNIT_ARRAY_PARAM(drm_rect_rotate, drm_rect_rotate_cases, drm_rect_rotate_case_desc);
488b5d88ec0SArthur Grillo 
drm_test_rect_rotate(struct kunit * test)489b5d88ec0SArthur Grillo static void drm_test_rect_rotate(struct kunit *test)
490b5d88ec0SArthur Grillo {
491b5d88ec0SArthur Grillo 	const struct drm_rect_rotate_case *params = test->param_value;
492b5d88ec0SArthur Grillo 	struct drm_rect r = params->rect;
493b5d88ec0SArthur Grillo 
494b5d88ec0SArthur Grillo 	drm_rect_rotate(&r, params->width, params->height, params->rotation);
495b5d88ec0SArthur Grillo 
496b5d88ec0SArthur Grillo 	drm_rect_compare(test, &r, &params->expected);
497b5d88ec0SArthur Grillo }
498b5d88ec0SArthur Grillo 
drm_test_rect_rotate_inv(struct kunit * test)499*8356b979SArthur Grillo static void drm_test_rect_rotate_inv(struct kunit *test)
500*8356b979SArthur Grillo {
501*8356b979SArthur Grillo 	const struct drm_rect_rotate_case *params = test->param_value;
502*8356b979SArthur Grillo 	struct drm_rect r = params->expected;
503*8356b979SArthur Grillo 
504*8356b979SArthur Grillo 	drm_rect_rotate_inv(&r, params->width, params->height, params->rotation);
505*8356b979SArthur Grillo 
506*8356b979SArthur Grillo 	drm_rect_compare(test, &r, &params->rect);
507*8356b979SArthur Grillo }
508*8356b979SArthur Grillo 
50993de485cSMaíra Canal static struct kunit_case drm_rect_tests[] = {
510961bcdf9SMaíra Canal 	KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero),
511961bcdf9SMaíra Canal 	KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped),
512961bcdf9SMaíra Canal 	KUNIT_CASE(drm_test_rect_clip_scaled_clipped),
513961bcdf9SMaíra Canal 	KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned),
51496c31619SArthur Grillo 	KUNIT_CASE_PARAM(drm_test_rect_intersect, drm_rect_intersect_gen_params),
5151f01f224SArthur Grillo 	KUNIT_CASE_PARAM(drm_test_rect_calc_hscale, drm_rect_scale_gen_params),
516881e2a9cSArthur Grillo 	KUNIT_CASE_PARAM(drm_test_rect_calc_vscale, drm_rect_scale_gen_params),
517b5d88ec0SArthur Grillo 	KUNIT_CASE_PARAM(drm_test_rect_rotate, drm_rect_rotate_gen_params),
518*8356b979SArthur Grillo 	KUNIT_CASE_PARAM(drm_test_rect_rotate_inv, drm_rect_rotate_gen_params),
51993de485cSMaíra Canal 	{ }
52093de485cSMaíra Canal };
52193de485cSMaíra Canal 
52293de485cSMaíra Canal static struct kunit_suite drm_rect_test_suite = {
52393de485cSMaíra Canal 	.name = "drm_rect",
52493de485cSMaíra Canal 	.test_cases = drm_rect_tests,
52593de485cSMaíra Canal };
52693de485cSMaíra Canal 
52793de485cSMaíra Canal kunit_test_suite(drm_rect_test_suite);
52893de485cSMaíra Canal 
52993de485cSMaíra Canal MODULE_LICENSE("GPL");
530