1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test cases for the drm_rect functions
4  *
5  * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>
6  */
7 
8 #include <kunit/test.h>
9 
10 #include <drm/drm_rect.h>
11 
12 static void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test)
13 {
14 	struct drm_rect src, dst, clip;
15 	bool visible;
16 
17 	/*
18 	 * Make sure we don't divide by zero when dst
19 	 * width/height is zero and dst and clip do not intersect.
20 	 */
21 	drm_rect_init(&src, 0, 0, 0, 0);
22 	drm_rect_init(&dst, 0, 0, 0, 0);
23 	drm_rect_init(&clip, 1, 1, 1, 1);
24 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
25 
26 	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
27 	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
28 
29 	drm_rect_init(&src, 0, 0, 0, 0);
30 	drm_rect_init(&dst, 3, 3, 0, 0);
31 	drm_rect_init(&clip, 1, 1, 1, 1);
32 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
33 
34 	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
35 	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
36 }
37 
38 static void drm_test_rect_clip_scaled_not_clipped(struct kunit *test)
39 {
40 	struct drm_rect src, dst, clip;
41 	bool visible;
42 
43 	/* 1:1 scaling */
44 	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
45 	drm_rect_init(&dst, 0, 0, 1, 1);
46 	drm_rect_init(&clip, 0, 0, 1, 1);
47 
48 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
49 
50 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
51 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
52 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
53 			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
54 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
55 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
56 
57 	/* 2:1 scaling */
58 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
59 	drm_rect_init(&dst, 0, 0, 1, 1);
60 	drm_rect_init(&clip, 0, 0, 1, 1);
61 
62 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
63 
64 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
65 			       src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
66 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
67 			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
68 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
69 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
70 
71 	/* 1:2 scaling */
72 	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
73 	drm_rect_init(&dst, 0, 0, 2, 2);
74 	drm_rect_init(&clip, 0, 0, 2, 2);
75 
76 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
77 
78 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
79 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
80 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 ||
81 			       dst.y1 != 0 || dst.y2 != 2, "Destination badly clipped\n");
82 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
83 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
84 }
85 
86 static void drm_test_rect_clip_scaled_clipped(struct kunit *test)
87 {
88 	struct drm_rect src, dst, clip;
89 	bool visible;
90 
91 	/* 1:1 scaling top/left clip */
92 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
93 	drm_rect_init(&dst, 0, 0, 2, 2);
94 	drm_rect_init(&clip, 0, 0, 1, 1);
95 
96 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
97 
98 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
99 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
100 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
101 			       dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
102 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
103 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
104 
105 	/* 1:1 scaling bottom/right clip */
106 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
107 	drm_rect_init(&dst, 0, 0, 2, 2);
108 	drm_rect_init(&clip, 1, 1, 1, 1);
109 
110 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
111 
112 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
113 			       src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
114 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
115 			       dst.y2 != 2, "Destination badly clipped\n");
116 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
117 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
118 
119 	/* 2:1 scaling top/left clip */
120 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
121 	drm_rect_init(&dst, 0, 0, 2, 2);
122 	drm_rect_init(&clip, 0, 0, 1, 1);
123 
124 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
125 
126 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
127 			       src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
128 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || dst.y1 != 0 ||
129 			       dst.y2 != 1, "Destination badly clipped\n");
130 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
131 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
132 
133 	/* 2:1 scaling bottom/right clip */
134 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
135 	drm_rect_init(&dst, 0, 0, 2, 2);
136 	drm_rect_init(&clip, 1, 1, 1, 1);
137 
138 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
139 
140 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
141 			       src.y1 != 2 << 16 || src.y2 != 4 << 16, "Source badly clipped\n");
142 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
143 			       dst.y2 != 2, "Destination badly clipped\n");
144 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
145 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
146 
147 	/* 1:2 scaling top/left clip */
148 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
149 	drm_rect_init(&dst, 0, 0, 4, 4);
150 	drm_rect_init(&clip, 0, 0, 2, 2);
151 
152 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
153 
154 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
155 			       src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
156 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 || dst.y1 != 0 ||
157 			       dst.y2 != 2, "Destination badly clipped\n");
158 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
159 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
160 
161 	/* 1:2 scaling bottom/right clip */
162 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
163 	drm_rect_init(&dst, 0, 0, 4, 4);
164 	drm_rect_init(&clip, 2, 2, 2, 2);
165 
166 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
167 
168 	KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
169 			       src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
170 	KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 2 || dst.x2 != 4 || dst.y1 != 2 ||
171 			       dst.y2 != 4, "Destination badly clipped\n");
172 	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
173 	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
174 }
175 
176 static void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
177 {
178 	struct drm_rect src, dst, clip;
179 	bool visible;
180 
181 	/*
182 	 * 'clip.x2 - dst.x1 >= dst width' could result a negative
183 	 * src rectangle width which is no longer expected by the
184 	 * code as it's using unsigned types. This could lead to
185 	 * the clipped source rectangle appering visible when it
186 	 * should have been fully clipped. Make sure both rectangles
187 	 * end up invisible.
188 	 */
189 	drm_rect_init(&src, 0, 0, INT_MAX, INT_MAX);
190 	drm_rect_init(&dst, 0, 0, 2, 2);
191 	drm_rect_init(&clip, 3, 3, 1, 1);
192 
193 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
194 
195 	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible\n");
196 	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
197 }
198 
199 static struct kunit_case drm_rect_tests[] = {
200 	KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero),
201 	KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped),
202 	KUNIT_CASE(drm_test_rect_clip_scaled_clipped),
203 	KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned),
204 	{ }
205 };
206 
207 static struct kunit_suite drm_rect_test_suite = {
208 	.name = "drm_rect",
209 	.test_cases = drm_rect_tests,
210 };
211 
212 kunit_test_suite(drm_rect_test_suite);
213 
214 MODULE_LICENSE("GPL");
215