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/limits.h> 14 #include <linux/string_helpers.h> 15 #include <linux/errno.h> 16 17 static 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 26 static 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 52 static 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 100 static 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 190 static 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 213 struct 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 220 static 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 328 static 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 335 KUNIT_ARRAY_PARAM(drm_rect_intersect, drm_rect_intersect_cases, drm_rect_intersect_case_desc); 336 337 static 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, ¶ms->r2); 344 345 KUNIT_EXPECT_EQ(test, visible, params->should_be_visible); 346 drm_rect_compare(test, &r1_aux, ¶ms->expected_intersection); 347 } 348 349 struct 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 356 static 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 401 static 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 406 KUNIT_ARRAY_PARAM(drm_rect_scale, drm_rect_scale_cases, drm_rect_scale_case_desc); 407 408 static 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(¶ms->src, ¶ms->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 436 static 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(¶ms->src, ¶ms->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 463 struct 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 471 static 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 516 static 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 521 KUNIT_ARRAY_PARAM(drm_rect_rotate, drm_rect_rotate_cases, drm_rect_rotate_case_desc); 522 523 static 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, ¶ms->expected); 531 } 532 533 static 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, ¶ms->rect); 541 } 542 543 static 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 556 static struct kunit_suite drm_rect_test_suite = { 557 .name = "drm_rect", 558 .test_cases = drm_rect_tests, 559 }; 560 561 kunit_test_suite(drm_rect_test_suite); 562 563 MODULE_DESCRIPTION("Test cases for the drm_rect functions"); 564 MODULE_LICENSE("GPL"); 565