projects/linux·blob master · refs

564 lines · 18.2 KiB

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