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_plane.h>
10 #include <drm/drm_drv.h>
12 #include "test-drm_modeset_common.h"
14 struct drm_driver mock_driver;
15 static struct drm_device mock_device;
16 static struct drm_object_properties mock_obj_props;
17 static struct drm_plane mock_plane;
18 static struct drm_property mock_prop;
20 static void mock_setup(struct drm_plane_state *state)
22 static bool setup_done = false;
24 state->plane = &mock_plane;
29 /* just enough so that drm_plane_enable_fb_damage_clips() works */
30 mock_device.driver = &mock_driver;
31 mock_device.mode_config.prop_fb_damage_clips = &mock_prop;
32 mock_plane.dev = &mock_device;
33 mock_plane.base.properties = &mock_obj_props;
34 mock_prop.base.id = 1; /* 0 is an invalid id */
35 mock_prop.dev = &mock_device;
37 drm_plane_enable_fb_damage_clips(&mock_plane);
40 static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
49 static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
58 static void set_damage_blob(struct drm_property_blob *damage_blob,
59 struct drm_mode_rect *r, uint32_t size)
61 damage_blob->length = size;
62 damage_blob->data = r;
65 static void set_plane_damage(struct drm_plane_state *state,
66 struct drm_property_blob *damage_blob)
68 state->fb_damage_clips = damage_blob;
71 static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
72 int x1, int y1, int x2, int y2)
75 * Round down x1/y1 and round up x2/y2. This is because damage is not in
76 * 16.16 fixed point so to catch all pixels.
78 int src_x1 = state->src.x1 >> 16;
79 int src_y1 = state->src.y1 >> 16;
80 int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
81 int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
83 if (x1 >= x2 || y1 >= y2) {
84 pr_err("Cannot have damage clip with no dimension.\n");
88 if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
89 pr_err("Damage cannot be outside rounded plane src.\n");
93 if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
94 pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
101 const struct drm_framebuffer fb = {
106 /* common mocked structs many tests need */
107 #define MOCK_VARIABLES() \
108 struct drm_plane_state old_state; \
109 struct drm_plane_state state = { \
110 .crtc = ZERO_SIZE_PTR, \
111 .fb = (struct drm_framebuffer *) &fb, \
114 mock_setup(&old_state); \
117 int igt_damage_iter_no_damage(void *ignored)
119 struct drm_atomic_helper_damage_iter iter;
120 struct drm_rect clip;
121 uint32_t num_hits = 0;
125 /* Plane src same as fb size. */
126 set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
127 set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
128 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
129 drm_atomic_for_each_plane_damage(&iter, &clip)
132 FAIL(num_hits != 1, "Should return plane src as damage.");
133 FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
138 int igt_damage_iter_no_damage_fractional_src(void *ignored)
140 struct drm_atomic_helper_damage_iter iter;
141 struct drm_rect clip;
142 uint32_t num_hits = 0;
146 /* Plane src has fractional part. */
147 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
148 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
149 set_plane_src(&state, 0x3fffe, 0x3fffe,
150 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
151 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
152 drm_atomic_for_each_plane_damage(&iter, &clip)
155 FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
156 FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
161 int igt_damage_iter_no_damage_src_moved(void *ignored)
163 struct drm_atomic_helper_damage_iter iter;
164 struct drm_rect clip;
165 uint32_t num_hits = 0;
169 /* Plane src moved since old plane state. */
170 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
171 set_plane_src(&state, 10 << 16, 10 << 16,
172 (10 + 1024) << 16, (10 + 768) << 16);
173 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
174 drm_atomic_for_each_plane_damage(&iter, &clip)
177 FAIL(num_hits != 1, "Should return plane src as damage.");
178 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
183 int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
185 struct drm_atomic_helper_damage_iter iter;
186 struct drm_rect clip;
187 uint32_t num_hits = 0;
191 /* Plane src has fractional part and it moved since old plane state. */
192 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
193 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
194 set_plane_src(&state, 0x40002, 0x40002,
195 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
196 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
197 drm_atomic_for_each_plane_damage(&iter, &clip)
200 FAIL(num_hits != 1, "Should return plane src as damage.");
201 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
206 int igt_damage_iter_no_damage_not_visible(void *ignored)
208 struct drm_atomic_helper_damage_iter iter;
209 struct drm_rect clip;
210 uint32_t num_hits = 0;
214 state.visible = false;
216 mock_setup(&old_state);
218 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
219 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
220 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
221 drm_atomic_for_each_plane_damage(&iter, &clip)
224 FAIL(num_hits != 0, "Should have no damage.");
229 int igt_damage_iter_no_damage_no_crtc(void *ignored)
231 struct drm_atomic_helper_damage_iter iter;
232 struct drm_rect clip;
233 uint32_t num_hits = 0;
239 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
240 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
241 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
242 drm_atomic_for_each_plane_damage(&iter, &clip)
245 FAIL(num_hits != 0, "Should have no damage.");
250 int igt_damage_iter_no_damage_no_fb(void *ignored)
252 struct drm_atomic_helper_damage_iter iter;
253 struct drm_plane_state old_state;
254 struct drm_rect clip;
255 uint32_t num_hits = 0;
257 struct drm_plane_state state = {
258 .crtc = ZERO_SIZE_PTR,
262 mock_setup(&old_state);
264 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
265 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
266 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
267 drm_atomic_for_each_plane_damage(&iter, &clip)
270 FAIL(num_hits != 0, "Should have no damage.");
275 int igt_damage_iter_simple_damage(void *ignored)
277 struct drm_atomic_helper_damage_iter iter;
278 struct drm_property_blob damage_blob;
279 struct drm_mode_rect damage;
280 struct drm_rect clip;
281 uint32_t num_hits = 0;
285 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
286 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
287 /* Damage set to plane src */
288 set_damage_clip(&damage, 0, 0, 1024, 768);
289 set_damage_blob(&damage_blob, &damage, sizeof(damage));
290 set_plane_damage(&state, &damage_blob);
291 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
292 drm_atomic_for_each_plane_damage(&iter, &clip)
295 FAIL(num_hits != 1, "Should return damage when set.");
296 FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
301 int igt_damage_iter_single_damage(void *ignored)
303 struct drm_atomic_helper_damage_iter iter;
304 struct drm_property_blob damage_blob;
305 struct drm_mode_rect damage;
306 struct drm_rect clip;
307 uint32_t num_hits = 0;
311 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
312 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
313 set_damage_clip(&damage, 256, 192, 768, 576);
314 set_damage_blob(&damage_blob, &damage, sizeof(damage));
315 set_plane_damage(&state, &damage_blob);
316 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
317 drm_atomic_for_each_plane_damage(&iter, &clip)
320 FAIL(num_hits != 1, "Should return damage when set.");
321 FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
326 int igt_damage_iter_single_damage_intersect_src(void *ignored)
328 struct drm_atomic_helper_damage_iter iter;
329 struct drm_property_blob damage_blob;
330 struct drm_mode_rect damage;
331 struct drm_rect clip;
332 uint32_t num_hits = 0;
336 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
337 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
338 /* Damage intersect with plane src. */
339 set_damage_clip(&damage, 256, 192, 1360, 768);
340 set_damage_blob(&damage_blob, &damage, sizeof(damage));
341 set_plane_damage(&state, &damage_blob);
342 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
343 drm_atomic_for_each_plane_damage(&iter, &clip)
346 FAIL(num_hits != 1, "Should return damage clipped to src.");
347 FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
352 int igt_damage_iter_single_damage_outside_src(void *ignored)
354 struct drm_atomic_helper_damage_iter iter;
355 struct drm_property_blob damage_blob;
356 struct drm_mode_rect damage;
357 struct drm_rect clip;
358 uint32_t num_hits = 0;
362 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
363 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
364 /* Damage clip outside plane src */
365 set_damage_clip(&damage, 1360, 1360, 1380, 1380);
366 set_damage_blob(&damage_blob, &damage, sizeof(damage));
367 set_plane_damage(&state, &damage_blob);
368 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
369 drm_atomic_for_each_plane_damage(&iter, &clip)
372 FAIL(num_hits != 0, "Should have no damage.");
377 int igt_damage_iter_single_damage_fractional_src(void *ignored)
379 struct drm_atomic_helper_damage_iter iter;
380 struct drm_property_blob damage_blob;
381 struct drm_mode_rect damage;
382 struct drm_rect clip;
383 uint32_t num_hits = 0;
387 /* Plane src has fractional part. */
388 set_plane_src(&old_state, 0x40002, 0x40002,
389 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
390 set_plane_src(&state, 0x40002, 0x40002,
391 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
392 set_damage_clip(&damage, 10, 10, 256, 330);
393 set_damage_blob(&damage_blob, &damage, sizeof(damage));
394 set_plane_damage(&state, &damage_blob);
395 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
396 drm_atomic_for_each_plane_damage(&iter, &clip)
399 FAIL(num_hits != 1, "Should return damage when set.");
400 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
405 int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
407 struct drm_atomic_helper_damage_iter iter;
408 struct drm_property_blob damage_blob;
409 struct drm_mode_rect damage;
410 struct drm_rect clip;
411 uint32_t num_hits = 0;
415 /* Plane src has fractional part. */
416 set_plane_src(&old_state, 0x40002, 0x40002,
417 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
418 set_plane_src(&state, 0x40002, 0x40002,
419 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
420 /* Damage intersect with plane src. */
421 set_damage_clip(&damage, 10, 1, 1360, 330);
422 set_damage_blob(&damage_blob, &damage, sizeof(damage));
423 set_plane_damage(&state, &damage_blob);
424 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
425 drm_atomic_for_each_plane_damage(&iter, &clip)
428 FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
429 FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
434 int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
436 struct drm_atomic_helper_damage_iter iter;
437 struct drm_property_blob damage_blob;
438 struct drm_mode_rect damage;
439 struct drm_rect clip;
440 uint32_t num_hits = 0;
444 /* Plane src has fractional part. */
445 set_plane_src(&old_state, 0x40002, 0x40002,
446 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
447 set_plane_src(&state, 0x40002, 0x40002,
448 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
449 /* Damage clip outside plane src */
450 set_damage_clip(&damage, 1360, 1360, 1380, 1380);
451 set_damage_blob(&damage_blob, &damage, sizeof(damage));
452 set_plane_damage(&state, &damage_blob);
453 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
454 drm_atomic_for_each_plane_damage(&iter, &clip)
457 FAIL(num_hits != 0, "Should have no damage.");
462 int igt_damage_iter_single_damage_src_moved(void *ignored)
464 struct drm_atomic_helper_damage_iter iter;
465 struct drm_property_blob damage_blob;
466 struct drm_mode_rect damage;
467 struct drm_rect clip;
468 uint32_t num_hits = 0;
472 /* Plane src moved since old plane state. */
473 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
474 set_plane_src(&state, 10 << 16, 10 << 16,
475 (10 + 1024) << 16, (10 + 768) << 16);
476 set_damage_clip(&damage, 20, 30, 256, 256);
477 set_damage_blob(&damage_blob, &damage, sizeof(damage));
478 set_plane_damage(&state, &damage_blob);
479 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
480 drm_atomic_for_each_plane_damage(&iter, &clip)
483 FAIL(num_hits != 1, "Should return plane src as damage.");
484 FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
489 int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
491 struct drm_atomic_helper_damage_iter iter;
492 struct drm_property_blob damage_blob;
493 struct drm_mode_rect damage;
494 struct drm_rect clip;
495 uint32_t num_hits = 0;
499 /* Plane src with fractional part moved since old plane state. */
500 set_plane_src(&old_state, 0x3fffe, 0x3fffe,
501 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
502 set_plane_src(&state, 0x40002, 0x40002,
503 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
504 /* Damage intersect with plane src. */
505 set_damage_clip(&damage, 20, 30, 1360, 256);
506 set_damage_blob(&damage_blob, &damage, sizeof(damage));
507 set_plane_damage(&state, &damage_blob);
508 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
509 drm_atomic_for_each_plane_damage(&iter, &clip)
512 FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
513 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
518 int igt_damage_iter_damage(void *ignored)
520 struct drm_atomic_helper_damage_iter iter;
521 struct drm_property_blob damage_blob;
522 struct drm_mode_rect damage[2];
523 struct drm_rect clip;
524 uint32_t num_hits = 0;
528 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
529 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
530 /* 2 damage clips. */
531 set_damage_clip(&damage[0], 20, 30, 200, 180);
532 set_damage_clip(&damage[1], 240, 200, 280, 250);
533 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
534 set_plane_damage(&state, &damage_blob);
535 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
536 drm_atomic_for_each_plane_damage(&iter, &clip) {
538 FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
540 FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
544 FAIL(num_hits != 2, "Should return damage when set.");
549 int igt_damage_iter_damage_one_intersect(void *ignored)
551 struct drm_atomic_helper_damage_iter iter;
552 struct drm_property_blob damage_blob;
553 struct drm_mode_rect damage[2];
554 struct drm_rect clip;
555 uint32_t num_hits = 0;
559 set_plane_src(&old_state, 0x40002, 0x40002,
560 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
561 set_plane_src(&state, 0x40002, 0x40002,
562 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
563 /* 2 damage clips, one intersect plane src. */
564 set_damage_clip(&damage[0], 20, 30, 200, 180);
565 set_damage_clip(&damage[1], 2, 2, 1360, 1360);
566 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
567 set_plane_damage(&state, &damage_blob);
568 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
569 drm_atomic_for_each_plane_damage(&iter, &clip) {
571 FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
573 FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
577 FAIL(num_hits != 2, "Should return damage when set.");
582 int igt_damage_iter_damage_one_outside(void *ignored)
584 struct drm_atomic_helper_damage_iter iter;
585 struct drm_property_blob damage_blob;
586 struct drm_mode_rect damage[2];
587 struct drm_rect clip;
588 uint32_t num_hits = 0;
592 set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
593 set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
594 /* 2 damage clips, one outside plane src. */
595 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
596 set_damage_clip(&damage[1], 240, 200, 280, 250);
597 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
598 set_plane_damage(&state, &damage_blob);
599 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
600 drm_atomic_for_each_plane_damage(&iter, &clip)
603 FAIL(num_hits != 1, "Should return damage when set.");
604 FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
609 int igt_damage_iter_damage_src_moved(void *ignored)
611 struct drm_atomic_helper_damage_iter iter;
612 struct drm_property_blob damage_blob;
613 struct drm_mode_rect damage[2];
614 struct drm_rect clip;
615 uint32_t num_hits = 0;
619 set_plane_src(&old_state, 0x40002, 0x40002,
620 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
621 set_plane_src(&state, 0x3fffe, 0x3fffe,
622 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
623 /* 2 damage clips, one outside plane src. */
624 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
625 set_damage_clip(&damage[1], 240, 200, 280, 250);
626 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
627 set_plane_damage(&state, &damage_blob);
628 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
629 drm_atomic_for_each_plane_damage(&iter, &clip)
632 FAIL(num_hits != 1, "Should return round off plane src as damage.");
633 FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
638 int igt_damage_iter_damage_not_visible(void *ignored)
640 struct drm_atomic_helper_damage_iter iter;
641 struct drm_property_blob damage_blob;
642 struct drm_mode_rect damage[2];
643 struct drm_rect clip;
644 uint32_t num_hits = 0;
648 state.visible = false;
650 set_plane_src(&old_state, 0x40002, 0x40002,
651 0x40002 + (1024 << 16), 0x40002 + (768 << 16));
652 set_plane_src(&state, 0x3fffe, 0x3fffe,
653 0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
654 /* 2 damage clips, one outside plane src. */
655 set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
656 set_damage_clip(&damage[1], 240, 200, 280, 250);
657 set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
658 set_plane_damage(&state, &damage_blob);
659 drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
660 drm_atomic_for_each_plane_damage(&iter, &clip)
663 FAIL(num_hits != 0, "Should not return any damage.");