1 // SPDX-License-Identifier: GPL-2.0
3 * Test case for drm_damage_helper functions
6 #define pr_fmt(fmt) "drm_damage_helper: " fmt
8 #include <drm/drm_damage_helper.h>
9 #include <drm/drm_framebuffer.h>
10 #include <drm/drm_plane.h>
11 #include <drm/drm_drv.h>
13 #include "test-drm_modeset_common.h"
15 struct drm_driver mock_driver;
16 static struct drm_device mock_device;
17 static struct drm_object_properties mock_obj_props;
18 static struct drm_plane mock_plane;
19 static struct drm_property mock_prop;
21 static void mock_setup(struct drm_plane_state *state)
23 static bool setup_done = false;
25 state->plane = &mock_plane;
30 /* just enough so that drm_plane_enable_fb_damage_clips() works */
31 mock_device.driver = &mock_driver;
32 mock_device.mode_config.prop_fb_damage_clips = &mock_prop;
33 mock_plane.dev = &mock_device;
34 mock_obj_props.count = 0;
35 mock_plane.base.properties = &mock_obj_props;
36 mock_prop.base.id = 1; /* 0 is an invalid id */
37 mock_prop.dev = &mock_device;
39 drm_plane_enable_fb_damage_clips(&mock_plane);
42 static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
51 static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
60 static void set_damage_blob(struct drm_property_blob *damage_blob,
61 struct drm_mode_rect *r, uint32_t size)
63 damage_blob->length = size;
64 damage_blob->data = r;
67 static void set_plane_damage(struct drm_plane_state *state,
68 struct drm_property_blob *damage_blob)
70 state->fb_damage_clips = damage_blob;
73 static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
74 int x1, int y1, int x2, int y2)
77 * Round down x1/y1 and round up x2/y2. This is because damage is not in
78 * 16.16 fixed point so to catch all pixels.
80 int src_x1 = state->src.x1 >> 16;
81 int src_y1 = state->src.y1 >> 16;
82 int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
83 int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
85 if (x1 >= x2 || y1 >= y2) {
86 pr_err("Cannot have damage clip with no dimension.\n");
90 if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
91 pr_err("Damage cannot be outside rounded plane src.\n");
95 if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
96 pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
103 const struct drm_framebuffer fb = {
108 /* common mocked structs many tests need */
109 #define MOCK_VARIABLES() \
110 struct drm_plane_state old_state; \
111 struct drm_plane_state state = { \
112 .crtc = ZERO_SIZE_PTR, \
113 .fb = (struct drm_framebuffer *) &fb, \
116 mock_setup(&old_state); \
119 int igt_damage_iter_no_damage(void *ignored)
121 struct drm_atomic_helper_damage_iter iter;
122 struct drm_rect clip;
123 uint32_t num_hits = 0;
127 /* Plane src same as fb size. */
128 set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
129 set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
130 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
131 drm_atomic_for_each_plane_damage(&iter, &clip)
134 FAIL(num_hits != 1, "Should return plane src as damage.");
135 FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
140 int igt_damage_iter_no_damage_fractional_src(void *ignored)
142 struct drm_atomic_helper_damage_iter iter;
143 struct drm_rect clip;
144 uint32_t num_hits = 0;
148 /* Plane src has fractional part. */
149 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
150 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
151 set_plane_src(&state, 0x3fffe, 0x3fffe,
152 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
153 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
154 drm_atomic_for_each_plane_damage(&iter, &clip)
157 FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
158 FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
163 int igt_damage_iter_no_damage_src_moved(void *ignored)
165 struct drm_atomic_helper_damage_iter iter;
166 struct drm_rect clip;
167 uint32_t num_hits = 0;
171 /* Plane src moved since old plane state. */
172 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
173 set_plane_src(&state, 10 << 16, 10 << 16,
174 (10 + 1024) << 16, (10 + 768) << 16);
175 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
176 drm_atomic_for_each_plane_damage(&iter, &clip)
179 FAIL(num_hits != 1, "Should return plane src as damage.");
180 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
185 int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
187 struct drm_atomic_helper_damage_iter iter;
188 struct drm_rect clip;
189 uint32_t num_hits = 0;
193 /* Plane src has fractional part and it moved since old plane state. */
194 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
195 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
196 set_plane_src(&state, 0x40002, 0x40002,
197 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
198 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
199 drm_atomic_for_each_plane_damage(&iter, &clip)
202 FAIL(num_hits != 1, "Should return plane src as damage.");
203 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
208 int igt_damage_iter_no_damage_not_visible(void *ignored)
210 struct drm_atomic_helper_damage_iter iter;
211 struct drm_rect clip;
212 uint32_t num_hits = 0;
216 state.visible = false;
218 mock_setup(&old_state);
220 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
221 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
222 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
223 drm_atomic_for_each_plane_damage(&iter, &clip)
226 FAIL(num_hits != 0, "Should have no damage.");
231 int igt_damage_iter_no_damage_no_crtc(void *ignored)
233 struct drm_atomic_helper_damage_iter iter;
234 struct drm_rect clip;
235 uint32_t num_hits = 0;
241 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
242 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
243 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
244 drm_atomic_for_each_plane_damage(&iter, &clip)
247 FAIL(num_hits != 0, "Should have no damage.");
252 int igt_damage_iter_no_damage_no_fb(void *ignored)
254 struct drm_atomic_helper_damage_iter iter;
255 struct drm_plane_state old_state;
256 struct drm_rect clip;
257 uint32_t num_hits = 0;
259 struct drm_plane_state state = {
260 .crtc = ZERO_SIZE_PTR,
264 mock_setup(&old_state);
266 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
267 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
268 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
269 drm_atomic_for_each_plane_damage(&iter, &clip)
272 FAIL(num_hits != 0, "Should have no damage.");
277 int igt_damage_iter_simple_damage(void *ignored)
279 struct drm_atomic_helper_damage_iter iter;
280 struct drm_property_blob damage_blob;
281 struct drm_mode_rect damage;
282 struct drm_rect clip;
283 uint32_t num_hits = 0;
287 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
288 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
289 /* Damage set to plane src */
290 set_damage_clip(&damage, 0, 0, 1024, 768);
291 set_damage_blob(&damage_blob, &damage, sizeof(damage));
292 set_plane_damage(&state, &damage_blob);
293 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
294 drm_atomic_for_each_plane_damage(&iter, &clip)
297 FAIL(num_hits != 1, "Should return damage when set.");
298 FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
303 int igt_damage_iter_single_damage(void *ignored)
305 struct drm_atomic_helper_damage_iter iter;
306 struct drm_property_blob damage_blob;
307 struct drm_mode_rect damage;
308 struct drm_rect clip;
309 uint32_t num_hits = 0;
313 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
314 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
315 set_damage_clip(&damage, 256, 192, 768, 576);
316 set_damage_blob(&damage_blob, &damage, sizeof(damage));
317 set_plane_damage(&state, &damage_blob);
318 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
319 drm_atomic_for_each_plane_damage(&iter, &clip)
322 FAIL(num_hits != 1, "Should return damage when set.");
323 FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
328 int igt_damage_iter_single_damage_intersect_src(void *ignored)
330 struct drm_atomic_helper_damage_iter iter;
331 struct drm_property_blob damage_blob;
332 struct drm_mode_rect damage;
333 struct drm_rect clip;
334 uint32_t num_hits = 0;
338 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
339 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
340 /* Damage intersect with plane src. */
341 set_damage_clip(&damage, 256, 192, 1360, 768);
342 set_damage_blob(&damage_blob, &damage, sizeof(damage));
343 set_plane_damage(&state, &damage_blob);
344 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
345 drm_atomic_for_each_plane_damage(&iter, &clip)
348 FAIL(num_hits != 1, "Should return damage clipped to src.");
349 FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
354 int igt_damage_iter_single_damage_outside_src(void *ignored)
356 struct drm_atomic_helper_damage_iter iter;
357 struct drm_property_blob damage_blob;
358 struct drm_mode_rect damage;
359 struct drm_rect clip;
360 uint32_t num_hits = 0;
364 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
365 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
366 /* Damage clip outside plane src */
367 set_damage_clip(&damage, 1360, 1360, 1380, 1380);
368 set_damage_blob(&damage_blob, &damage, sizeof(damage));
369 set_plane_damage(&state, &damage_blob);
370 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
371 drm_atomic_for_each_plane_damage(&iter, &clip)
374 FAIL(num_hits != 0, "Should have no damage.");
379 int igt_damage_iter_single_damage_fractional_src(void *ignored)
381 struct drm_atomic_helper_damage_iter iter;
382 struct drm_property_blob damage_blob;
383 struct drm_mode_rect damage;
384 struct drm_rect clip;
385 uint32_t num_hits = 0;
389 /* Plane src has fractional part. */
390 set_plane_src(&old_state, 0x40002, 0x40002,
391 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
392 set_plane_src(&state, 0x40002, 0x40002,
393 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
394 set_damage_clip(&damage, 10, 10, 256, 330);
395 set_damage_blob(&damage_blob, &damage, sizeof(damage));
396 set_plane_damage(&state, &damage_blob);
397 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
398 drm_atomic_for_each_plane_damage(&iter, &clip)
401 FAIL(num_hits != 1, "Should return damage when set.");
402 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
407 int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
409 struct drm_atomic_helper_damage_iter iter;
410 struct drm_property_blob damage_blob;
411 struct drm_mode_rect damage;
412 struct drm_rect clip;
413 uint32_t num_hits = 0;
417 /* Plane src has fractional part. */
418 set_plane_src(&old_state, 0x40002, 0x40002,
419 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
420 set_plane_src(&state, 0x40002, 0x40002,
421 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
422 /* Damage intersect with plane src. */
423 set_damage_clip(&damage, 10, 1, 1360, 330);
424 set_damage_blob(&damage_blob, &damage, sizeof(damage));
425 set_plane_damage(&state, &damage_blob);
426 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
427 drm_atomic_for_each_plane_damage(&iter, &clip)
430 FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
431 FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
436 int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
438 struct drm_atomic_helper_damage_iter iter;
439 struct drm_property_blob damage_blob;
440 struct drm_mode_rect damage;
441 struct drm_rect clip;
442 uint32_t num_hits = 0;
446 /* Plane src has fractional part. */
447 set_plane_src(&old_state, 0x40002, 0x40002,
448 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
449 set_plane_src(&state, 0x40002, 0x40002,
450 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
451 /* Damage clip outside plane src */
452 set_damage_clip(&damage, 1360, 1360, 1380, 1380);
453 set_damage_blob(&damage_blob, &damage, sizeof(damage));
454 set_plane_damage(&state, &damage_blob);
455 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
456 drm_atomic_for_each_plane_damage(&iter, &clip)
459 FAIL(num_hits != 0, "Should have no damage.");
464 int igt_damage_iter_single_damage_src_moved(void *ignored)
466 struct drm_atomic_helper_damage_iter iter;
467 struct drm_property_blob damage_blob;
468 struct drm_mode_rect damage;
469 struct drm_rect clip;
470 uint32_t num_hits = 0;
474 /* Plane src moved since old plane state. */
475 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
476 set_plane_src(&state, 10 << 16, 10 << 16,
477 (10 + 1024) << 16, (10 + 768) << 16);
478 set_damage_clip(&damage, 20, 30, 256, 256);
479 set_damage_blob(&damage_blob, &damage, sizeof(damage));
480 set_plane_damage(&state, &damage_blob);
481 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
482 drm_atomic_for_each_plane_damage(&iter, &clip)
485 FAIL(num_hits != 1, "Should return plane src as damage.");
486 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
491 int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
493 struct drm_atomic_helper_damage_iter iter;
494 struct drm_property_blob damage_blob;
495 struct drm_mode_rect damage;
496 struct drm_rect clip;
497 uint32_t num_hits = 0;
501 /* Plane src with fractional part moved since old plane state. */
502 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
503 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
504 set_plane_src(&state, 0x40002, 0x40002,
505 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
506 /* Damage intersect with plane src. */
507 set_damage_clip(&damage, 20, 30, 1360, 256);
508 set_damage_blob(&damage_blob, &damage, sizeof(damage));
509 set_plane_damage(&state, &damage_blob);
510 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
511 drm_atomic_for_each_plane_damage(&iter, &clip)
514 FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
515 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
520 int igt_damage_iter_damage(void *ignored)
522 struct drm_atomic_helper_damage_iter iter;
523 struct drm_property_blob damage_blob;
524 struct drm_mode_rect damage[2];
525 struct drm_rect clip;
526 uint32_t num_hits = 0;
530 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
531 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
532 /* 2 damage clips. */
533 set_damage_clip(&damage[0], 20, 30, 200, 180);
534 set_damage_clip(&damage[1], 240, 200, 280, 250);
535 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
536 set_plane_damage(&state, &damage_blob);
537 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
538 drm_atomic_for_each_plane_damage(&iter, &clip) {
540 FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
542 FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
546 FAIL(num_hits != 2, "Should return damage when set.");
551 int igt_damage_iter_damage_one_intersect(void *ignored)
553 struct drm_atomic_helper_damage_iter iter;
554 struct drm_property_blob damage_blob;
555 struct drm_mode_rect damage[2];
556 struct drm_rect clip;
557 uint32_t num_hits = 0;
561 set_plane_src(&old_state, 0x40002, 0x40002,
562 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
563 set_plane_src(&state, 0x40002, 0x40002,
564 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
565 /* 2 damage clips, one intersect plane src. */
566 set_damage_clip(&damage[0], 20, 30, 200, 180);
567 set_damage_clip(&damage[1], 2, 2, 1360, 1360);
568 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
569 set_plane_damage(&state, &damage_blob);
570 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
571 drm_atomic_for_each_plane_damage(&iter, &clip) {
573 FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
575 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
579 FAIL(num_hits != 2, "Should return damage when set.");
584 int igt_damage_iter_damage_one_outside(void *ignored)
586 struct drm_atomic_helper_damage_iter iter;
587 struct drm_property_blob damage_blob;
588 struct drm_mode_rect damage[2];
589 struct drm_rect clip;
590 uint32_t num_hits = 0;
594 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
595 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
596 /* 2 damage clips, one outside plane src. */
597 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
598 set_damage_clip(&damage[1], 240, 200, 280, 250);
599 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
600 set_plane_damage(&state, &damage_blob);
601 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
602 drm_atomic_for_each_plane_damage(&iter, &clip)
605 FAIL(num_hits != 1, "Should return damage when set.");
606 FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
611 int igt_damage_iter_damage_src_moved(void *ignored)
613 struct drm_atomic_helper_damage_iter iter;
614 struct drm_property_blob damage_blob;
615 struct drm_mode_rect damage[2];
616 struct drm_rect clip;
617 uint32_t num_hits = 0;
621 set_plane_src(&old_state, 0x40002, 0x40002,
622 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
623 set_plane_src(&state, 0x3fffe, 0x3fffe,
624 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
625 /* 2 damage clips, one outside plane src. */
626 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
627 set_damage_clip(&damage[1], 240, 200, 280, 250);
628 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
629 set_plane_damage(&state, &damage_blob);
630 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
631 drm_atomic_for_each_plane_damage(&iter, &clip)
634 FAIL(num_hits != 1, "Should return round off plane src as damage.");
635 FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
640 int igt_damage_iter_damage_not_visible(void *ignored)
642 struct drm_atomic_helper_damage_iter iter;
643 struct drm_property_blob damage_blob;
644 struct drm_mode_rect damage[2];
645 struct drm_rect clip;
646 uint32_t num_hits = 0;
650 state.visible = false;
652 set_plane_src(&old_state, 0x40002, 0x40002,
653 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
654 set_plane_src(&state, 0x3fffe, 0x3fffe,
655 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
656 /* 2 damage clips, one outside plane src. */
657 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
658 set_damage_clip(&damage[1], 240, 200, 280, 250);
659 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
660 set_plane_damage(&state, &damage_blob);
661 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
662 drm_atomic_for_each_plane_damage(&iter, &clip)
665 FAIL(num_hits != 0, "Should not return any damage.");