162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Test cases for the drm_rect functions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <kunit/test.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <drm/drm_rect.h>
1162306a36Sopenharmony_ci#include <drm/drm_mode.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/string_helpers.h>
1462306a36Sopenharmony_ci#include <linux/errno.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic void drm_rect_compare(struct kunit *test, const struct drm_rect *r,
1762306a36Sopenharmony_ci			     const struct drm_rect *expected)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, r->x1, expected->x1);
2062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, r->y1, expected->y1);
2162306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, drm_rect_width(r), drm_rect_width(expected));
2262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, drm_rect_height(r), drm_rect_height(expected));
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	struct drm_rect src, dst, clip;
2862306a36Sopenharmony_ci	bool visible;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	/*
3162306a36Sopenharmony_ci	 * Make sure we don't divide by zero when dst
3262306a36Sopenharmony_ci	 * width/height is zero and dst and clip do not intersect.
3362306a36Sopenharmony_ci	 */
3462306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 0, 0);
3562306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 0, 0);
3662306a36Sopenharmony_ci	drm_rect_init(&clip, 1, 1, 1, 1);
3762306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
4062306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 0, 0);
4362306a36Sopenharmony_ci	drm_rect_init(&dst, 3, 3, 0, 0);
4462306a36Sopenharmony_ci	drm_rect_init(&clip, 1, 1, 1, 1);
4562306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
4862306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic void drm_test_rect_clip_scaled_not_clipped(struct kunit *test)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct drm_rect src, dst, clip;
5462306a36Sopenharmony_ci	bool visible;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* 1:1 scaling */
5762306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
5862306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 1, 1);
5962306a36Sopenharmony_ci	drm_rect_init(&clip, 0, 0, 1, 1);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
6462306a36Sopenharmony_ci			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
6562306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
6662306a36Sopenharmony_ci			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
6762306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
6862306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* 2:1 scaling */
7162306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
7262306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 1, 1);
7362306a36Sopenharmony_ci	drm_rect_init(&clip, 0, 0, 1, 1);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
7862306a36Sopenharmony_ci			       src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
7962306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
8062306a36Sopenharmony_ci			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
8162306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
8262306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* 1:2 scaling */
8562306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
8662306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 2, 2);
8762306a36Sopenharmony_ci	drm_rect_init(&clip, 0, 0, 2, 2);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
9262306a36Sopenharmony_ci			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
9362306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 ||
9462306a36Sopenharmony_ci			       dst.y1 != 0 || dst.y2 != 2, "Destination badly clipped\n");
9562306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
9662306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic void drm_test_rect_clip_scaled_clipped(struct kunit *test)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	struct drm_rect src, dst, clip;
10262306a36Sopenharmony_ci	bool visible;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* 1:1 scaling top/left clip */
10562306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
10662306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 2, 2);
10762306a36Sopenharmony_ci	drm_rect_init(&clip, 0, 0, 1, 1);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
11262306a36Sopenharmony_ci			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
11362306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
11462306a36Sopenharmony_ci			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
11562306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
11662306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* 1:1 scaling bottom/right clip */
11962306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
12062306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 2, 2);
12162306a36Sopenharmony_ci	drm_rect_init(&clip, 1, 1, 1, 1);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
12662306a36Sopenharmony_ci			       src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
12762306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
12862306a36Sopenharmony_ci			       dst.y2 != 2, "Destination badly clipped\n");
12962306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
13062306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* 2:1 scaling top/left clip */
13362306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
13462306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 2, 2);
13562306a36Sopenharmony_ci	drm_rect_init(&clip, 0, 0, 1, 1);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
14062306a36Sopenharmony_ci			       src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
14162306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || dst.y1 != 0 ||
14262306a36Sopenharmony_ci			       dst.y2 != 1, "Destination badly clipped\n");
14362306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
14462306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/* 2:1 scaling bottom/right clip */
14762306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
14862306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 2, 2);
14962306a36Sopenharmony_ci	drm_rect_init(&clip, 1, 1, 1, 1);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
15462306a36Sopenharmony_ci			       src.y1 != 2 << 16 || src.y2 != 4 << 16, "Source badly clipped\n");
15562306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
15662306a36Sopenharmony_ci			       dst.y2 != 2, "Destination badly clipped\n");
15762306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
15862306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* 1:2 scaling top/left clip */
16162306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
16262306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 4, 4);
16362306a36Sopenharmony_ci	drm_rect_init(&clip, 0, 0, 2, 2);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
16862306a36Sopenharmony_ci			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
16962306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 || dst.y1 != 0 ||
17062306a36Sopenharmony_ci			       dst.y2 != 2, "Destination badly clipped\n");
17162306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
17262306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* 1:2 scaling bottom/right clip */
17562306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
17662306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 4, 4);
17762306a36Sopenharmony_ci	drm_rect_init(&clip, 2, 2, 2, 2);
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
18262306a36Sopenharmony_ci			       src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
18362306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 2 || dst.x2 != 4 || dst.y1 != 2 ||
18462306a36Sopenharmony_ci			       dst.y2 != 4, "Destination badly clipped\n");
18562306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
18662306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct drm_rect src, dst, clip;
19262306a36Sopenharmony_ci	bool visible;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/*
19562306a36Sopenharmony_ci	 * 'clip.x2 - dst.x1 >= dst width' could result a negative
19662306a36Sopenharmony_ci	 * src rectangle width which is no longer expected by the
19762306a36Sopenharmony_ci	 * code as it's using unsigned types. This could lead to
19862306a36Sopenharmony_ci	 * the clipped source rectangle appering visible when it
19962306a36Sopenharmony_ci	 * should have been fully clipped. Make sure both rectangles
20062306a36Sopenharmony_ci	 * end up invisible.
20162306a36Sopenharmony_ci	 */
20262306a36Sopenharmony_ci	drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX);
20362306a36Sopenharmony_ci	drm_rect_init(&dst, 0, 0, 2, 2);
20462306a36Sopenharmony_ci	drm_rect_init(&clip, 3, 3, 1, 1);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	visible = drm_rect_clip_scaled(&src, &dst, &clip);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible\n");
20962306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct drm_rect_intersect_case {
21362306a36Sopenharmony_ci	const char *description;
21462306a36Sopenharmony_ci	struct drm_rect r1, r2;
21562306a36Sopenharmony_ci	bool should_be_visible;
21662306a36Sopenharmony_ci	struct drm_rect expected_intersection;
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic const struct drm_rect_intersect_case drm_rect_intersect_cases[] = {
22062306a36Sopenharmony_ci	{
22162306a36Sopenharmony_ci		.description = "top-left x bottom-right",
22262306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(1, 1, 2, 2),
22362306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(0, 0, 2, 2),
22462306a36Sopenharmony_ci		.should_be_visible = true,
22562306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
22662306a36Sopenharmony_ci	},
22762306a36Sopenharmony_ci	{
22862306a36Sopenharmony_ci		.description = "top-right x bottom-left",
22962306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
23062306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(1, -1, 2, 2),
23162306a36Sopenharmony_ci		.should_be_visible = true,
23262306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
23362306a36Sopenharmony_ci	},
23462306a36Sopenharmony_ci	{
23562306a36Sopenharmony_ci		.description = "bottom-left x top-right",
23662306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(1, -1, 2, 2),
23762306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(0, 0, 2, 2),
23862306a36Sopenharmony_ci		.should_be_visible = true,
23962306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
24062306a36Sopenharmony_ci	},
24162306a36Sopenharmony_ci	{
24262306a36Sopenharmony_ci		.description = "bottom-right x top-left",
24362306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
24462306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(1, 1, 2, 2),
24562306a36Sopenharmony_ci		.should_be_visible = true,
24662306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
24762306a36Sopenharmony_ci	},
24862306a36Sopenharmony_ci	{
24962306a36Sopenharmony_ci		.description = "right x left",
25062306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 2, 1),
25162306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(1, 0, 3, 1),
25262306a36Sopenharmony_ci		.should_be_visible = true,
25362306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
25462306a36Sopenharmony_ci	},
25562306a36Sopenharmony_ci	{
25662306a36Sopenharmony_ci		.description = "left x right",
25762306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(1, 0, 3, 1),
25862306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(0, 0, 2, 1),
25962306a36Sopenharmony_ci		.should_be_visible = true,
26062306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
26162306a36Sopenharmony_ci	},
26262306a36Sopenharmony_ci	{
26362306a36Sopenharmony_ci		.description = "up x bottom",
26462306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 1, 2),
26562306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(0, -1, 1, 3),
26662306a36Sopenharmony_ci		.should_be_visible = true,
26762306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
26862306a36Sopenharmony_ci	},
26962306a36Sopenharmony_ci	{
27062306a36Sopenharmony_ci		.description = "bottom x up",
27162306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, -1, 1, 3),
27262306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(0, 0, 1, 2),
27362306a36Sopenharmony_ci		.should_be_visible = true,
27462306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
27562306a36Sopenharmony_ci	},
27662306a36Sopenharmony_ci	{
27762306a36Sopenharmony_ci		.description = "touching corner",
27862306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 1, 1),
27962306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(1, 1, 2, 2),
28062306a36Sopenharmony_ci		.should_be_visible = false,
28162306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 1, 0, 0),
28262306a36Sopenharmony_ci	},
28362306a36Sopenharmony_ci	{
28462306a36Sopenharmony_ci		.description = "touching side",
28562306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 1, 1),
28662306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(1, 0, 1, 1),
28762306a36Sopenharmony_ci		.should_be_visible = false,
28862306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 0, 0, 1),
28962306a36Sopenharmony_ci	},
29062306a36Sopenharmony_ci	{
29162306a36Sopenharmony_ci		.description = "equal rects",
29262306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
29362306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(0, 0, 2, 2),
29462306a36Sopenharmony_ci		.should_be_visible = true,
29562306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(0, 0, 2, 2),
29662306a36Sopenharmony_ci	},
29762306a36Sopenharmony_ci	{
29862306a36Sopenharmony_ci		.description = "inside another",
29962306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 2, 2),
30062306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(1, 1, 1, 1),
30162306a36Sopenharmony_ci		.should_be_visible = true,
30262306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
30362306a36Sopenharmony_ci	},
30462306a36Sopenharmony_ci	{
30562306a36Sopenharmony_ci		.description = "far away",
30662306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 1, 1),
30762306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(3, 6, 1, 1),
30862306a36Sopenharmony_ci		.should_be_visible = false,
30962306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(3, 6, -2, -5),
31062306a36Sopenharmony_ci	},
31162306a36Sopenharmony_ci	{
31262306a36Sopenharmony_ci		.description = "points intersecting",
31362306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(5, 10, 0, 0),
31462306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(5, 10, 0, 0),
31562306a36Sopenharmony_ci		.should_be_visible = false,
31662306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(5, 10, 0, 0),
31762306a36Sopenharmony_ci	},
31862306a36Sopenharmony_ci	{
31962306a36Sopenharmony_ci		.description = "points not intersecting",
32062306a36Sopenharmony_ci		.r1 = DRM_RECT_INIT(0, 0, 0, 0),
32162306a36Sopenharmony_ci		.r2 = DRM_RECT_INIT(5, 10, 0, 0),
32262306a36Sopenharmony_ci		.should_be_visible = false,
32362306a36Sopenharmony_ci		.expected_intersection = DRM_RECT_INIT(5, 10, -5, -10),
32462306a36Sopenharmony_ci	},
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void drm_rect_intersect_case_desc(const struct drm_rect_intersect_case *t, char *desc)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	snprintf(desc, KUNIT_PARAM_DESC_SIZE,
33062306a36Sopenharmony_ci		 "%s: " DRM_RECT_FMT " x " DRM_RECT_FMT,
33162306a36Sopenharmony_ci		 t->description, DRM_RECT_ARG(&t->r1), DRM_RECT_ARG(&t->r2));
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(drm_rect_intersect, drm_rect_intersect_cases, drm_rect_intersect_case_desc);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic void drm_test_rect_intersect(struct kunit *test)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	const struct drm_rect_intersect_case *params = test->param_value;
33962306a36Sopenharmony_ci	struct drm_rect r1_aux = params->r1;
34062306a36Sopenharmony_ci	bool visible;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	visible = drm_rect_intersect(&r1_aux, &params->r2);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, visible, params->should_be_visible);
34562306a36Sopenharmony_ci	drm_rect_compare(test, &r1_aux, &params->expected_intersection);
34662306a36Sopenharmony_ci}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_cistruct drm_rect_scale_case {
34962306a36Sopenharmony_ci	const char *name;
35062306a36Sopenharmony_ci	struct drm_rect src, dst;
35162306a36Sopenharmony_ci	int min_range, max_range;
35262306a36Sopenharmony_ci	int expected_scaling_factor;
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic const struct drm_rect_scale_case drm_rect_scale_cases[] = {
35662306a36Sopenharmony_ci	{
35762306a36Sopenharmony_ci		.name = "normal use",
35862306a36Sopenharmony_ci		.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
35962306a36Sopenharmony_ci		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
36062306a36Sopenharmony_ci		.min_range = 0, .max_range = INT_MAX,
36162306a36Sopenharmony_ci		.expected_scaling_factor = 2,
36262306a36Sopenharmony_ci	},
36362306a36Sopenharmony_ci	{
36462306a36Sopenharmony_ci		.name = "out of max range",
36562306a36Sopenharmony_ci		.src = DRM_RECT_INIT(0, 0, 10 << 16, 10 << 16),
36662306a36Sopenharmony_ci		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
36762306a36Sopenharmony_ci		.min_range = 3, .max_range = 5,
36862306a36Sopenharmony_ci		.expected_scaling_factor = -ERANGE,
36962306a36Sopenharmony_ci	},
37062306a36Sopenharmony_ci	{
37162306a36Sopenharmony_ci		.name = "out of min range",
37262306a36Sopenharmony_ci		.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
37362306a36Sopenharmony_ci		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
37462306a36Sopenharmony_ci		.min_range = 3, .max_range = 5,
37562306a36Sopenharmony_ci		.expected_scaling_factor = -ERANGE,
37662306a36Sopenharmony_ci	},
37762306a36Sopenharmony_ci	{
37862306a36Sopenharmony_ci		.name = "zero dst",
37962306a36Sopenharmony_ci		.src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
38062306a36Sopenharmony_ci		.dst = DRM_RECT_INIT(0, 0, 0 << 16, 0 << 16),
38162306a36Sopenharmony_ci		.min_range = 0, .max_range = INT_MAX,
38262306a36Sopenharmony_ci		.expected_scaling_factor = 0,
38362306a36Sopenharmony_ci	},
38462306a36Sopenharmony_ci	{
38562306a36Sopenharmony_ci		.name = "negative src",
38662306a36Sopenharmony_ci		.src = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
38762306a36Sopenharmony_ci		.dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
38862306a36Sopenharmony_ci		.min_range = 0, .max_range = INT_MAX,
38962306a36Sopenharmony_ci		.expected_scaling_factor = -EINVAL,
39062306a36Sopenharmony_ci	},
39162306a36Sopenharmony_ci	{
39262306a36Sopenharmony_ci		.name = "negative dst",
39362306a36Sopenharmony_ci		.src = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
39462306a36Sopenharmony_ci		.dst = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
39562306a36Sopenharmony_ci		.min_range = 0, .max_range = INT_MAX,
39662306a36Sopenharmony_ci		.expected_scaling_factor = -EINVAL,
39762306a36Sopenharmony_ci	},
39862306a36Sopenharmony_ci};
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistatic void drm_rect_scale_case_desc(const struct drm_rect_scale_case *t, char *desc)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void drm_test_rect_calc_hscale(struct kunit *test)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	const struct drm_rect_scale_case *params = test->param_value;
41062306a36Sopenharmony_ci	int scaling_factor;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	scaling_factor = drm_rect_calc_hscale(&params->src, &params->dst,
41362306a36Sopenharmony_ci					      params->min_range, params->max_range);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic void drm_test_rect_calc_vscale(struct kunit *test)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	const struct drm_rect_scale_case *params = test->param_value;
42162306a36Sopenharmony_ci	int scaling_factor;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	scaling_factor = drm_rect_calc_vscale(&params->src, &params->dst,
42462306a36Sopenharmony_ci					      params->min_range, params->max_range);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistruct drm_rect_rotate_case {
43062306a36Sopenharmony_ci	const char *name;
43162306a36Sopenharmony_ci	unsigned int rotation;
43262306a36Sopenharmony_ci	struct drm_rect rect;
43362306a36Sopenharmony_ci	int width, height;
43462306a36Sopenharmony_ci	struct drm_rect expected;
43562306a36Sopenharmony_ci};
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic const struct drm_rect_rotate_case drm_rect_rotate_cases[] = {
43862306a36Sopenharmony_ci	{
43962306a36Sopenharmony_ci		.name = "reflect-x",
44062306a36Sopenharmony_ci		.rotation = DRM_MODE_REFLECT_X,
44162306a36Sopenharmony_ci		.rect = DRM_RECT_INIT(0, 0, 5, 5),
44262306a36Sopenharmony_ci		.width = 5, .height = 10,
44362306a36Sopenharmony_ci		.expected = DRM_RECT_INIT(0, 0, 5, 5),
44462306a36Sopenharmony_ci	},
44562306a36Sopenharmony_ci	{
44662306a36Sopenharmony_ci		.name = "reflect-y",
44762306a36Sopenharmony_ci		.rotation = DRM_MODE_REFLECT_Y,
44862306a36Sopenharmony_ci		.rect = DRM_RECT_INIT(2, 0, 5, 5),
44962306a36Sopenharmony_ci		.width = 5, .height = 10,
45062306a36Sopenharmony_ci		.expected = DRM_RECT_INIT(2, 5, 5, 5),
45162306a36Sopenharmony_ci	},
45262306a36Sopenharmony_ci	{
45362306a36Sopenharmony_ci		.name = "rotate-0",
45462306a36Sopenharmony_ci		.rotation = DRM_MODE_ROTATE_0,
45562306a36Sopenharmony_ci		.rect = DRM_RECT_INIT(0, 2, 5, 5),
45662306a36Sopenharmony_ci		.width = 5, .height = 10,
45762306a36Sopenharmony_ci		.expected = DRM_RECT_INIT(0, 2, 5, 5),
45862306a36Sopenharmony_ci	},
45962306a36Sopenharmony_ci	{
46062306a36Sopenharmony_ci		.name = "rotate-90",
46162306a36Sopenharmony_ci		.rotation = DRM_MODE_ROTATE_90,
46262306a36Sopenharmony_ci		.rect = DRM_RECT_INIT(0, 0, 5, 10),
46362306a36Sopenharmony_ci		.width = 5, .height = 10,
46462306a36Sopenharmony_ci		.expected = DRM_RECT_INIT(0, 0, 10, 5),
46562306a36Sopenharmony_ci	},
46662306a36Sopenharmony_ci	{
46762306a36Sopenharmony_ci		.name = "rotate-180",
46862306a36Sopenharmony_ci		.rotation = DRM_MODE_ROTATE_180,
46962306a36Sopenharmony_ci		.rect = DRM_RECT_INIT(11, 3, 5, 10),
47062306a36Sopenharmony_ci		.width = 5, .height = 10,
47162306a36Sopenharmony_ci		.expected = DRM_RECT_INIT(-11, -3, 5, 10),
47262306a36Sopenharmony_ci	},
47362306a36Sopenharmony_ci	{
47462306a36Sopenharmony_ci		.name = "rotate-270",
47562306a36Sopenharmony_ci		.rotation = DRM_MODE_ROTATE_270,
47662306a36Sopenharmony_ci		.rect = DRM_RECT_INIT(6, 3, 5, 10),
47762306a36Sopenharmony_ci		.width = 5, .height = 10,
47862306a36Sopenharmony_ci		.expected = DRM_RECT_INIT(-3, 6, 10, 5),
47962306a36Sopenharmony_ci	},
48062306a36Sopenharmony_ci};
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic void drm_rect_rotate_case_desc(const struct drm_rect_rotate_case *t, char *desc)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(drm_rect_rotate, drm_rect_rotate_cases, drm_rect_rotate_case_desc);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic void drm_test_rect_rotate(struct kunit *test)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	const struct drm_rect_rotate_case *params = test->param_value;
49262306a36Sopenharmony_ci	struct drm_rect r = params->rect;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	drm_rect_rotate(&r, params->width, params->height, params->rotation);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	drm_rect_compare(test, &r, &params->expected);
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic void drm_test_rect_rotate_inv(struct kunit *test)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	const struct drm_rect_rotate_case *params = test->param_value;
50262306a36Sopenharmony_ci	struct drm_rect r = params->expected;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	drm_rect_rotate_inv(&r, params->width, params->height, params->rotation);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	drm_rect_compare(test, &r, &params->rect);
50762306a36Sopenharmony_ci}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cistatic struct kunit_case drm_rect_tests[] = {
51062306a36Sopenharmony_ci	KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero),
51162306a36Sopenharmony_ci	KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped),
51262306a36Sopenharmony_ci	KUNIT_CASE(drm_test_rect_clip_scaled_clipped),
51362306a36Sopenharmony_ci	KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned),
51462306a36Sopenharmony_ci	KUNIT_CASE_PARAM(drm_test_rect_intersect, drm_rect_intersect_gen_params),
51562306a36Sopenharmony_ci	KUNIT_CASE_PARAM(drm_test_rect_calc_hscale, drm_rect_scale_gen_params),
51662306a36Sopenharmony_ci	KUNIT_CASE_PARAM(drm_test_rect_calc_vscale, drm_rect_scale_gen_params),
51762306a36Sopenharmony_ci	KUNIT_CASE_PARAM(drm_test_rect_rotate, drm_rect_rotate_gen_params),
51862306a36Sopenharmony_ci	KUNIT_CASE_PARAM(drm_test_rect_rotate_inv, drm_rect_rotate_gen_params),
51962306a36Sopenharmony_ci	{ }
52062306a36Sopenharmony_ci};
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic struct kunit_suite drm_rect_test_suite = {
52362306a36Sopenharmony_ci	.name = "drm_rect",
52462306a36Sopenharmony_ci	.test_cases = drm_rect_tests,
52562306a36Sopenharmony_ci};
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cikunit_test_suite(drm_rect_test_suite);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
530