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#include <drm/drm_mode.h>
12
13#include <linux/string_helpers.h>
14#include <linux/errno.h>
15
16static void drm_rect_compare(struct kunit *test, const struct drm_rect *r,
17 const struct drm_rect *expected)
18{
19 KUNIT_EXPECT_EQ(test, r->x1, expected->x1);
20 KUNIT_EXPECT_EQ(test, r->y1, expected->y1);
21 KUNIT_EXPECT_EQ(test, drm_rect_width(r), drm_rect_width(expected));
22 KUNIT_EXPECT_EQ(test, drm_rect_height(r), drm_rect_height(expected));
23}
24
25static void drm_test_rect_clip_scaled_div_by_zero(struct kunit *test)
26{
27 struct drm_rect src, dst, clip;
28 bool visible;
29
30 /*
31 * Make sure we don't divide by zero when dst
32 * width/height is zero and dst and clip do not intersect.
33 */
34 drm_rect_init(r: &src, x: 0, y: 0, width: 0, height: 0);
35 drm_rect_init(r: &dst, x: 0, y: 0, width: 0, height: 0);
36 drm_rect_init(r: &clip, x: 1, y: 1, width: 1, height: 1);
37 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
38
39 KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
40 KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
41
42 drm_rect_init(r: &src, x: 0, y: 0, width: 0, height: 0);
43 drm_rect_init(r: &dst, x: 3, y: 3, width: 0, height: 0);
44 drm_rect_init(r: &clip, x: 1, y: 1, width: 1, height: 1);
45 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
46
47 KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible\n");
48 KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
49}
50
51static void drm_test_rect_clip_scaled_not_clipped(struct kunit *test)
52{
53 struct drm_rect src, dst, clip;
54 bool visible;
55
56 /* 1:1 scaling */
57 drm_rect_init(r: &src, x: 0, y: 0, width: 1 << 16, height: 1 << 16);
58 drm_rect_init(r: &dst, x: 0, y: 0, width: 1, height: 1);
59 drm_rect_init(r: &clip, x: 0, y: 0, width: 1, height: 1);
60
61 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
62
63 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
64 src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
65 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
66 dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
67 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
68 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
69
70 /* 2:1 scaling */
71 drm_rect_init(r: &src, x: 0, y: 0, width: 2 << 16, height: 2 << 16);
72 drm_rect_init(r: &dst, x: 0, y: 0, width: 1, height: 1);
73 drm_rect_init(r: &clip, x: 0, y: 0, width: 1, height: 1);
74
75 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
76
77 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
78 src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
79 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
80 dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
81 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
82 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
83
84 /* 1:2 scaling */
85 drm_rect_init(r: &src, x: 0, y: 0, width: 1 << 16, height: 1 << 16);
86 drm_rect_init(r: &dst, x: 0, y: 0, width: 2, height: 2);
87 drm_rect_init(r: &clip, x: 0, y: 0, width: 2, height: 2);
88
89 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
90
91 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
92 src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
93 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 ||
94 dst.y1 != 0 || dst.y2 != 2, "Destination badly clipped\n");
95 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
96 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
97}
98
99static void drm_test_rect_clip_scaled_clipped(struct kunit *test)
100{
101 struct drm_rect src, dst, clip;
102 bool visible;
103
104 /* 1:1 scaling top/left clip */
105 drm_rect_init(r: &src, x: 0, y: 0, width: 2 << 16, height: 2 << 16);
106 drm_rect_init(r: &dst, x: 0, y: 0, width: 2, height: 2);
107 drm_rect_init(r: &clip, x: 0, y: 0, width: 1, height: 1);
108
109 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
110
111 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
112 src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
113 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 ||
114 dst.y1 != 0 || dst.y2 != 1, "Destination badly clipped\n");
115 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
116 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
117
118 /* 1:1 scaling bottom/right clip */
119 drm_rect_init(r: &src, x: 0, y: 0, width: 2 << 16, height: 2 << 16);
120 drm_rect_init(r: &dst, x: 0, y: 0, width: 2, height: 2);
121 drm_rect_init(r: &clip, x: 1, y: 1, width: 1, height: 1);
122
123 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
124
125 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
126 src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
127 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
128 dst.y2 != 2, "Destination badly clipped\n");
129 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
130 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
131
132 /* 2:1 scaling top/left clip */
133 drm_rect_init(r: &src, x: 0, y: 0, width: 4 << 16, height: 4 << 16);
134 drm_rect_init(r: &dst, x: 0, y: 0, width: 2, height: 2);
135 drm_rect_init(r: &clip, x: 0, y: 0, width: 1, height: 1);
136
137 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
138
139 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 2 << 16 ||
140 src.y1 != 0 || src.y2 != 2 << 16, "Source badly clipped\n");
141 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 1 || dst.y1 != 0 ||
142 dst.y2 != 1, "Destination badly clipped\n");
143 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
144 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
145
146 /* 2:1 scaling bottom/right clip */
147 drm_rect_init(r: &src, x: 0, y: 0, width: 4 << 16, height: 4 << 16);
148 drm_rect_init(r: &dst, x: 0, y: 0, width: 2, height: 2);
149 drm_rect_init(r: &clip, x: 1, y: 1, width: 1, height: 1);
150
151 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
152
153 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
154 src.y1 != 2 << 16 || src.y2 != 4 << 16, "Source badly clipped\n");
155 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 1 || dst.x2 != 2 || dst.y1 != 1 ||
156 dst.y2 != 2, "Destination badly clipped\n");
157 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
158 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
159
160 /* 1:2 scaling top/left clip */
161 drm_rect_init(r: &src, x: 0, y: 0, width: 2 << 16, height: 2 << 16);
162 drm_rect_init(r: &dst, x: 0, y: 0, width: 4, height: 4);
163 drm_rect_init(r: &clip, x: 0, y: 0, width: 2, height: 2);
164
165 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
166
167 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 0 || src.x2 != 1 << 16 ||
168 src.y1 != 0 || src.y2 != 1 << 16, "Source badly clipped\n");
169 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 0 || dst.x2 != 2 || dst.y1 != 0 ||
170 dst.y2 != 2, "Destination badly clipped\n");
171 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
172 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
173
174 /* 1:2 scaling bottom/right clip */
175 drm_rect_init(r: &src, x: 0, y: 0, width: 2 << 16, height: 2 << 16);
176 drm_rect_init(r: &dst, x: 0, y: 0, width: 4, height: 4);
177 drm_rect_init(r: &clip, x: 2, y: 2, width: 2, height: 2);
178
179 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
180
181 KUNIT_EXPECT_FALSE_MSG(test, src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
182 src.y1 != 1 << 16 || src.y2 != 2 << 16, "Source badly clipped\n");
183 KUNIT_EXPECT_FALSE_MSG(test, dst.x1 != 2 || dst.x2 != 4 || dst.y1 != 2 ||
184 dst.y2 != 4, "Destination badly clipped\n");
185 KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible\n");
186 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible\n");
187}
188
189static void drm_test_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
190{
191 struct drm_rect src, dst, clip;
192 bool visible;
193
194 /*
195 * 'clip.x2 - dst.x1 >= dst width' could result a negative
196 * src rectangle width which is no longer expected by the
197 * code as it's using unsigned types. This could lead to
198 * the clipped source rectangle appering visible when it
199 * should have been fully clipped. Make sure both rectangles
200 * end up invisible.
201 */
202 drm_rect_init(r: &src, x: 0, y: 0, INT_MAX, INT_MAX);
203 drm_rect_init(r: &dst, x: 0, y: 0, width: 2, height: 2);
204 drm_rect_init(r: &clip, x: 3, y: 3, width: 1, height: 1);
205
206 visible = drm_rect_clip_scaled(src: &src, dst: &dst, clip: &clip);
207
208 KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible\n");
209 KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible\n");
210}
211
212struct drm_rect_intersect_case {
213 const char *description;
214 struct drm_rect r1, r2;
215 bool should_be_visible;
216 struct drm_rect expected_intersection;
217};
218
219static const struct drm_rect_intersect_case drm_rect_intersect_cases[] = {
220 {
221 .description = "top-left x bottom-right",
222 .r1 = DRM_RECT_INIT(1, 1, 2, 2),
223 .r2 = DRM_RECT_INIT(0, 0, 2, 2),
224 .should_be_visible = true,
225 .expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
226 },
227 {
228 .description = "top-right x bottom-left",
229 .r1 = DRM_RECT_INIT(0, 0, 2, 2),
230 .r2 = DRM_RECT_INIT(1, -1, 2, 2),
231 .should_be_visible = true,
232 .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
233 },
234 {
235 .description = "bottom-left x top-right",
236 .r1 = DRM_RECT_INIT(1, -1, 2, 2),
237 .r2 = DRM_RECT_INIT(0, 0, 2, 2),
238 .should_be_visible = true,
239 .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
240 },
241 {
242 .description = "bottom-right x top-left",
243 .r1 = DRM_RECT_INIT(0, 0, 2, 2),
244 .r2 = DRM_RECT_INIT(1, 1, 2, 2),
245 .should_be_visible = true,
246 .expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
247 },
248 {
249 .description = "right x left",
250 .r1 = DRM_RECT_INIT(0, 0, 2, 1),
251 .r2 = DRM_RECT_INIT(1, 0, 3, 1),
252 .should_be_visible = true,
253 .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
254 },
255 {
256 .description = "left x right",
257 .r1 = DRM_RECT_INIT(1, 0, 3, 1),
258 .r2 = DRM_RECT_INIT(0, 0, 2, 1),
259 .should_be_visible = true,
260 .expected_intersection = DRM_RECT_INIT(1, 0, 1, 1),
261 },
262 {
263 .description = "up x bottom",
264 .r1 = DRM_RECT_INIT(0, 0, 1, 2),
265 .r2 = DRM_RECT_INIT(0, -1, 1, 3),
266 .should_be_visible = true,
267 .expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
268 },
269 {
270 .description = "bottom x up",
271 .r1 = DRM_RECT_INIT(0, -1, 1, 3),
272 .r2 = DRM_RECT_INIT(0, 0, 1, 2),
273 .should_be_visible = true,
274 .expected_intersection = DRM_RECT_INIT(0, 0, 1, 2),
275 },
276 {
277 .description = "touching corner",
278 .r1 = DRM_RECT_INIT(0, 0, 1, 1),
279 .r2 = DRM_RECT_INIT(1, 1, 2, 2),
280 .should_be_visible = false,
281 .expected_intersection = DRM_RECT_INIT(1, 1, 0, 0),
282 },
283 {
284 .description = "touching side",
285 .r1 = DRM_RECT_INIT(0, 0, 1, 1),
286 .r2 = DRM_RECT_INIT(1, 0, 1, 1),
287 .should_be_visible = false,
288 .expected_intersection = DRM_RECT_INIT(1, 0, 0, 1),
289 },
290 {
291 .description = "equal rects",
292 .r1 = DRM_RECT_INIT(0, 0, 2, 2),
293 .r2 = DRM_RECT_INIT(0, 0, 2, 2),
294 .should_be_visible = true,
295 .expected_intersection = DRM_RECT_INIT(0, 0, 2, 2),
296 },
297 {
298 .description = "inside another",
299 .r1 = DRM_RECT_INIT(0, 0, 2, 2),
300 .r2 = DRM_RECT_INIT(1, 1, 1, 1),
301 .should_be_visible = true,
302 .expected_intersection = DRM_RECT_INIT(1, 1, 1, 1),
303 },
304 {
305 .description = "far away",
306 .r1 = DRM_RECT_INIT(0, 0, 1, 1),
307 .r2 = DRM_RECT_INIT(3, 6, 1, 1),
308 .should_be_visible = false,
309 .expected_intersection = DRM_RECT_INIT(3, 6, -2, -5),
310 },
311 {
312 .description = "points intersecting",
313 .r1 = DRM_RECT_INIT(5, 10, 0, 0),
314 .r2 = DRM_RECT_INIT(5, 10, 0, 0),
315 .should_be_visible = false,
316 .expected_intersection = DRM_RECT_INIT(5, 10, 0, 0),
317 },
318 {
319 .description = "points not intersecting",
320 .r1 = DRM_RECT_INIT(0, 0, 0, 0),
321 .r2 = DRM_RECT_INIT(5, 10, 0, 0),
322 .should_be_visible = false,
323 .expected_intersection = DRM_RECT_INIT(5, 10, -5, -10),
324 },
325};
326
327static void drm_rect_intersect_case_desc(const struct drm_rect_intersect_case *t, char *desc)
328{
329 snprintf(buf: desc, KUNIT_PARAM_DESC_SIZE,
330 fmt: "%s: " DRM_RECT_FMT " x " DRM_RECT_FMT,
331 t->description, DRM_RECT_ARG(&t->r1), DRM_RECT_ARG(&t->r2));
332}
333
334KUNIT_ARRAY_PARAM(drm_rect_intersect, drm_rect_intersect_cases, drm_rect_intersect_case_desc);
335
336static void drm_test_rect_intersect(struct kunit *test)
337{
338 const struct drm_rect_intersect_case *params = test->param_value;
339 struct drm_rect r1_aux = params->r1;
340 bool visible;
341
342 visible = drm_rect_intersect(r: &r1_aux, clip: &params->r2);
343
344 KUNIT_EXPECT_EQ(test, visible, params->should_be_visible);
345 drm_rect_compare(test, r: &r1_aux, expected: &params->expected_intersection);
346}
347
348struct drm_rect_scale_case {
349 const char *name;
350 struct drm_rect src, dst;
351 int min_range, max_range;
352 int expected_scaling_factor;
353};
354
355static const struct drm_rect_scale_case drm_rect_scale_cases[] = {
356 {
357 .name = "normal use",
358 .src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
359 .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
360 .min_range = 0, .max_range = INT_MAX,
361 .expected_scaling_factor = 2,
362 },
363 {
364 .name = "out of max range",
365 .src = DRM_RECT_INIT(0, 0, 10 << 16, 10 << 16),
366 .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
367 .min_range = 3, .max_range = 5,
368 .expected_scaling_factor = -ERANGE,
369 },
370 {
371 .name = "out of min range",
372 .src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
373 .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
374 .min_range = 3, .max_range = 5,
375 .expected_scaling_factor = -ERANGE,
376 },
377 {
378 .name = "zero dst",
379 .src = DRM_RECT_INIT(0, 0, 2 << 16, 2 << 16),
380 .dst = DRM_RECT_INIT(0, 0, 0 << 16, 0 << 16),
381 .min_range = 0, .max_range = INT_MAX,
382 .expected_scaling_factor = 0,
383 },
384 {
385 .name = "negative src",
386 .src = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
387 .dst = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
388 .min_range = 0, .max_range = INT_MAX,
389 .expected_scaling_factor = -EINVAL,
390 },
391 {
392 .name = "negative dst",
393 .src = DRM_RECT_INIT(0, 0, 1 << 16, 1 << 16),
394 .dst = DRM_RECT_INIT(0, 0, -(1 << 16), -(1 << 16)),
395 .min_range = 0, .max_range = INT_MAX,
396 .expected_scaling_factor = -EINVAL,
397 },
398};
399
400static void drm_rect_scale_case_desc(const struct drm_rect_scale_case *t, char *desc)
401{
402 strscpy(p: desc, q: t->name, KUNIT_PARAM_DESC_SIZE);
403}
404
405KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc);
406
407static void drm_test_rect_calc_hscale(struct kunit *test)
408{
409 const struct drm_rect_scale_case *params = test->param_value;
410 int scaling_factor;
411
412 scaling_factor = drm_rect_calc_hscale(src: &params->src, dst: &params->dst,
413 min_hscale: params->min_range, max_hscale: params->max_range);
414
415 KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
416}
417
418static void drm_test_rect_calc_vscale(struct kunit *test)
419{
420 const struct drm_rect_scale_case *params = test->param_value;
421 int scaling_factor;
422
423 scaling_factor = drm_rect_calc_vscale(src: &params->src, dst: &params->dst,
424 min_vscale: params->min_range, max_vscale: params->max_range);
425
426 KUNIT_EXPECT_EQ(test, scaling_factor, params->expected_scaling_factor);
427}
428
429struct drm_rect_rotate_case {
430 const char *name;
431 unsigned int rotation;
432 struct drm_rect rect;
433 int width, height;
434 struct drm_rect expected;
435};
436
437static const struct drm_rect_rotate_case drm_rect_rotate_cases[] = {
438 {
439 .name = "reflect-x",
440 .rotation = DRM_MODE_REFLECT_X,
441 .rect = DRM_RECT_INIT(0, 0, 5, 5),
442 .width = 5, .height = 10,
443 .expected = DRM_RECT_INIT(0, 0, 5, 5),
444 },
445 {
446 .name = "reflect-y",
447 .rotation = DRM_MODE_REFLECT_Y,
448 .rect = DRM_RECT_INIT(2, 0, 5, 5),
449 .width = 5, .height = 10,
450 .expected = DRM_RECT_INIT(2, 5, 5, 5),
451 },
452 {
453 .name = "rotate-0",
454 .rotation = DRM_MODE_ROTATE_0,
455 .rect = DRM_RECT_INIT(0, 2, 5, 5),
456 .width = 5, .height = 10,
457 .expected = DRM_RECT_INIT(0, 2, 5, 5),
458 },
459 {
460 .name = "rotate-90",
461 .rotation = DRM_MODE_ROTATE_90,
462 .rect = DRM_RECT_INIT(0, 0, 5, 10),
463 .width = 5, .height = 10,
464 .expected = DRM_RECT_INIT(0, 0, 10, 5),
465 },
466 {
467 .name = "rotate-180",
468 .rotation = DRM_MODE_ROTATE_180,
469 .rect = DRM_RECT_INIT(11, 3, 5, 10),
470 .width = 5, .height = 10,
471 .expected = DRM_RECT_INIT(-11, -3, 5, 10),
472 },
473 {
474 .name = "rotate-270",
475 .rotation = DRM_MODE_ROTATE_270,
476 .rect = DRM_RECT_INIT(6, 3, 5, 10),
477 .width = 5, .height = 10,
478 .expected = DRM_RECT_INIT(-3, 6, 10, 5),
479 },
480};
481
482static void drm_rect_rotate_case_desc(const struct drm_rect_rotate_case *t, char *desc)
483{
484 strscpy(p: desc, q: t->name, KUNIT_PARAM_DESC_SIZE);
485}
486
487KUNIT_ARRAY_PARAM(drm_rect_rotate, drm_rect_rotate_cases, drm_rect_rotate_case_desc);
488
489static void drm_test_rect_rotate(struct kunit *test)
490{
491 const struct drm_rect_rotate_case *params = test->param_value;
492 struct drm_rect r = params->rect;
493
494 drm_rect_rotate(r: &r, width: params->width, height: params->height, rotation: params->rotation);
495
496 drm_rect_compare(test, r: &r, expected: &params->expected);
497}
498
499static void drm_test_rect_rotate_inv(struct kunit *test)
500{
501 const struct drm_rect_rotate_case *params = test->param_value;
502 struct drm_rect r = params->expected;
503
504 drm_rect_rotate_inv(r: &r, width: params->width, height: params->height, rotation: params->rotation);
505
506 drm_rect_compare(test, r: &r, expected: &params->rect);
507}
508
509static struct kunit_case drm_rect_tests[] = {
510 KUNIT_CASE(drm_test_rect_clip_scaled_div_by_zero),
511 KUNIT_CASE(drm_test_rect_clip_scaled_not_clipped),
512 KUNIT_CASE(drm_test_rect_clip_scaled_clipped),
513 KUNIT_CASE(drm_test_rect_clip_scaled_signed_vs_unsigned),
514 KUNIT_CASE_PARAM(drm_test_rect_intersect, drm_rect_intersect_gen_params),
515 KUNIT_CASE_PARAM(drm_test_rect_calc_hscale, drm_rect_scale_gen_params),
516 KUNIT_CASE_PARAM(drm_test_rect_calc_vscale, drm_rect_scale_gen_params),
517 KUNIT_CASE_PARAM(drm_test_rect_rotate, drm_rect_rotate_gen_params),
518 KUNIT_CASE_PARAM(drm_test_rect_rotate_inv, drm_rect_rotate_gen_params),
519 { }
520};
521
522static struct kunit_suite drm_rect_test_suite = {
523 .name = "drm_rect",
524 .test_cases = drm_rect_tests,
525};
526
527kunit_test_suite(drm_rect_test_suite);
528
529MODULE_LICENSE("GPL");
530

source code of linux/drivers/gpu/drm/tests/drm_rect_test.c