1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test case for drm_damage_helper functions
4  *
5  * Copyright (c) 2022 Maíra Canal <mairacanal@riseup.net>
6  */
7 
8 #include <kunit/test.h>
9 
10 #include <drm/drm_damage_helper.h>
11 #include <drm/drm_framebuffer.h>
12 #include <drm/drm_plane.h>
13 #include <drm/drm_drv.h>
14 
15 struct drm_damage_mock {
16 	struct drm_driver driver;
17 	struct drm_device device;
18 	struct drm_object_properties obj_props;
19 	struct drm_plane plane;
20 	struct drm_property prop;
21 	struct drm_framebuffer fb;
22 	struct drm_plane_state state;
23 	struct drm_plane_state old_state;
24 };
25 
26 static int drm_damage_helper_init(struct kunit *test)
27 {
28 	struct drm_damage_mock *mock;
29 
30 	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
31 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
32 
33 	mock->fb.width = 2048;
34 	mock->fb.height = 2048;
35 
36 	mock->state.crtc = ZERO_SIZE_PTR;
37 	mock->state.fb = &mock->fb;
38 	mock->state.visible = true;
39 
40 	mock->old_state.plane = &mock->plane;
41 	mock->state.plane = &mock->plane;
42 
43 	/* just enough so that drm_plane_enable_fb_damage_clips() works */
44 	mock->device.driver = &mock->driver;
45 	mock->device.mode_config.prop_fb_damage_clips = &mock->prop;
46 	mock->plane.dev = &mock->device;
47 	mock->obj_props.count = 0;
48 	mock->plane.base.properties = &mock->obj_props;
49 	mock->prop.base.id = 1; /* 0 is an invalid id */
50 	mock->prop.dev = &mock->device;
51 
52 	drm_plane_enable_fb_damage_clips(&mock->plane);
53 
54 	test->priv = mock;
55 
56 	return 0;
57 }
58 
59 static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
60 			  int y2)
61 {
62 	state->src.x1 = x1;
63 	state->src.y1 = y1;
64 	state->src.x2 = x2;
65 	state->src.y2 = y2;
66 }
67 
68 static void set_damage_clip(struct drm_mode_rect *r, int x1, int y1, int x2,
69 			    int y2)
70 {
71 	r->x1 = x1;
72 	r->y1 = y1;
73 	r->x2 = x2;
74 	r->y2 = y2;
75 }
76 
77 static void set_damage_blob(struct drm_property_blob *damage_blob,
78 			    struct drm_mode_rect *r, u32 size)
79 {
80 	damage_blob->length = size;
81 	damage_blob->data = r;
82 }
83 
84 static void set_plane_damage(struct drm_plane_state *state,
85 			     struct drm_property_blob *damage_blob)
86 {
87 	state->fb_damage_clips = damage_blob;
88 }
89 
90 static void check_damage_clip(struct kunit *test, struct drm_rect *r,
91 			      int x1, int y1, int x2, int y2)
92 {
93 	struct drm_damage_mock *mock = test->priv;
94 	struct drm_plane_state state = mock->state;
95 
96 	/*
97 	 * Round down x1/y1 and round up x2/y2. This is because damage is not in
98 	 * 16.16 fixed point so to catch all pixels.
99 	 */
100 	int src_x1 = state.src.x1 >> 16;
101 	int src_y1 = state.src.y1 >> 16;
102 	int src_x2 = (state.src.x2 >> 16) + !!(state.src.x2 & 0xFFFF);
103 	int src_y2 = (state.src.y2 >> 16) + !!(state.src.y2 & 0xFFFF);
104 
105 	if (x1 >= x2 || y1 >= y2)
106 		KUNIT_FAIL(test, "Cannot have damage clip with no dimension.");
107 	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2)
108 		KUNIT_FAIL(test, "Damage cannot be outside rounded plane src.");
109 	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2)
110 		KUNIT_FAIL(test, "Damage = %d %d %d %d, want = %d %d %d %d",
111 			   r->x1, r->y1, r->x2, r->y2, x1, y1, x2, y2);
112 }
113 
114 static void igt_damage_iter_no_damage(struct kunit *test)
115 {
116 	struct drm_damage_mock *mock = test->priv;
117 	struct drm_atomic_helper_damage_iter iter;
118 	struct drm_rect clip;
119 	u32 num_hits = 0;
120 
121 	/* Plane src same as fb size. */
122 	set_plane_src(&mock->old_state, 0, 0, mock->fb.width << 16, mock->fb.height << 16);
123 	set_plane_src(&mock->state, 0, 0, mock->fb.width << 16, mock->fb.height << 16);
124 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
125 	drm_atomic_for_each_plane_damage(&iter, &clip)
126 		num_hits++;
127 
128 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
129 	check_damage_clip(test, &clip, 0, 0, 2048, 2048);
130 }
131 
132 static void igt_damage_iter_no_damage_fractional_src(struct kunit *test)
133 {
134 	struct drm_damage_mock *mock = test->priv;
135 	struct drm_atomic_helper_damage_iter iter;
136 	struct drm_rect clip;
137 	u32 num_hits = 0;
138 
139 	/* Plane src has fractional part. */
140 	set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe,
141 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
142 	set_plane_src(&mock->state, 0x3fffe, 0x3fffe,
143 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
144 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
145 	drm_atomic_for_each_plane_damage(&iter, &clip)
146 		num_hits++;
147 
148 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1,
149 			    "Should return rounded off plane src as damage.");
150 	check_damage_clip(test, &clip, 3, 3, 1028, 772);
151 }
152 
153 static void igt_damage_iter_no_damage_src_moved(struct kunit *test)
154 {
155 	struct drm_damage_mock *mock = test->priv;
156 	struct drm_atomic_helper_damage_iter iter;
157 	struct drm_rect clip;
158 	u32 num_hits = 0;
159 
160 	/* Plane src moved since old plane state. */
161 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
162 	set_plane_src(&mock->state, 10 << 16, 10 << 16,
163 		      (10 + 1024) << 16, (10 + 768) << 16);
164 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
165 	drm_atomic_for_each_plane_damage(&iter, &clip)
166 		num_hits++;
167 
168 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
169 	check_damage_clip(test, &clip, 10, 10, 1034, 778);
170 }
171 
172 static void igt_damage_iter_no_damage_fractional_src_moved(struct kunit *test)
173 {
174 	struct drm_damage_mock *mock = test->priv;
175 	struct drm_atomic_helper_damage_iter iter;
176 	struct drm_rect clip;
177 	u32 num_hits = 0;
178 
179 	/* Plane src has fractional part and it moved since old plane state. */
180 	set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe,
181 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
182 	set_plane_src(&mock->state, 0x40002, 0x40002,
183 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
184 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
185 	drm_atomic_for_each_plane_damage(&iter, &clip)
186 		num_hits++;
187 
188 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
189 	check_damage_clip(test, &clip, 4, 4, 1029, 773);
190 }
191 
192 static void igt_damage_iter_no_damage_not_visible(struct kunit *test)
193 {
194 	struct drm_damage_mock *mock = test->priv;
195 	struct drm_atomic_helper_damage_iter iter;
196 	struct drm_rect clip;
197 	u32 num_hits = 0;
198 
199 	mock->state.visible = false;
200 
201 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
202 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
203 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
204 	drm_atomic_for_each_plane_damage(&iter, &clip)
205 		num_hits++;
206 
207 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
208 }
209 
210 static void igt_damage_iter_no_damage_no_crtc(struct kunit *test)
211 {
212 	struct drm_damage_mock *mock = test->priv;
213 	struct drm_atomic_helper_damage_iter iter;
214 	struct drm_rect clip;
215 	u32 num_hits = 0;
216 
217 	mock->state.crtc = NULL;
218 
219 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
220 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
221 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
222 	drm_atomic_for_each_plane_damage(&iter, &clip)
223 		num_hits++;
224 
225 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
226 }
227 
228 static void igt_damage_iter_no_damage_no_fb(struct kunit *test)
229 {
230 	struct drm_damage_mock *mock = test->priv;
231 	struct drm_atomic_helper_damage_iter iter;
232 	struct drm_rect clip;
233 	u32 num_hits = 0;
234 
235 	mock->state.fb = NULL;
236 
237 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
238 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
239 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
240 	drm_atomic_for_each_plane_damage(&iter, &clip)
241 		num_hits++;
242 
243 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
244 }
245 
246 static void igt_damage_iter_simple_damage(struct kunit *test)
247 {
248 	struct drm_damage_mock *mock = test->priv;
249 	struct drm_atomic_helper_damage_iter iter;
250 	struct drm_property_blob damage_blob;
251 	struct drm_mode_rect damage;
252 	struct drm_rect clip;
253 	u32 num_hits = 0;
254 
255 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
256 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
257 	/* Damage set to plane src */
258 	set_damage_clip(&damage, 0, 0, 1024, 768);
259 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
260 	set_plane_damage(&mock->state, &damage_blob);
261 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
262 	drm_atomic_for_each_plane_damage(&iter, &clip)
263 		num_hits++;
264 
265 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
266 	check_damage_clip(test, &clip, 0, 0, 1024, 768);
267 }
268 
269 static void igt_damage_iter_single_damage(struct kunit *test)
270 {
271 	struct drm_damage_mock *mock = test->priv;
272 	struct drm_atomic_helper_damage_iter iter;
273 	struct drm_property_blob damage_blob;
274 	struct drm_mode_rect damage;
275 	struct drm_rect clip;
276 	u32 num_hits = 0;
277 
278 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
279 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
280 	set_damage_clip(&damage, 256, 192, 768, 576);
281 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
282 	set_plane_damage(&mock->state, &damage_blob);
283 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
284 	drm_atomic_for_each_plane_damage(&iter, &clip)
285 		num_hits++;
286 
287 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
288 	check_damage_clip(test, &clip, 256, 192, 768, 576);
289 }
290 
291 static void igt_damage_iter_single_damage_intersect_src(struct kunit *test)
292 {
293 	struct drm_damage_mock *mock = test->priv;
294 	struct drm_atomic_helper_damage_iter iter;
295 	struct drm_property_blob damage_blob;
296 	struct drm_mode_rect damage;
297 	struct drm_rect clip;
298 	u32 num_hits = 0;
299 
300 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
301 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
302 	/* Damage intersect with plane src. */
303 	set_damage_clip(&damage, 256, 192, 1360, 768);
304 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
305 	set_plane_damage(&mock->state, &damage_blob);
306 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
307 	drm_atomic_for_each_plane_damage(&iter, &clip)
308 		num_hits++;
309 
310 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage clipped to src.");
311 	check_damage_clip(test, &clip, 256, 192, 1024, 768);
312 }
313 
314 static void igt_damage_iter_single_damage_outside_src(struct kunit *test)
315 {
316 	struct drm_damage_mock *mock = test->priv;
317 	struct drm_atomic_helper_damage_iter iter;
318 	struct drm_property_blob damage_blob;
319 	struct drm_mode_rect damage;
320 	struct drm_rect clip;
321 	u32 num_hits = 0;
322 
323 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
324 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
325 	/* Damage clip outside plane src */
326 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
327 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
328 	set_plane_damage(&mock->state, &damage_blob);
329 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
330 	drm_atomic_for_each_plane_damage(&iter, &clip)
331 		num_hits++;
332 
333 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
334 }
335 
336 static void igt_damage_iter_single_damage_fractional_src(struct kunit *test)
337 {
338 	struct drm_damage_mock *mock = test->priv;
339 	struct drm_atomic_helper_damage_iter iter;
340 	struct drm_property_blob damage_blob;
341 	struct drm_mode_rect damage;
342 	struct drm_rect clip;
343 	u32 num_hits = 0;
344 
345 	/* Plane src has fractional part. */
346 	set_plane_src(&mock->old_state, 0x40002, 0x40002,
347 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
348 	set_plane_src(&mock->state, 0x40002, 0x40002,
349 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
350 	set_damage_clip(&damage, 10, 10, 256, 330);
351 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
352 	set_plane_damage(&mock->state, &damage_blob);
353 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
354 	drm_atomic_for_each_plane_damage(&iter, &clip)
355 		num_hits++;
356 
357 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
358 	check_damage_clip(test, &clip, 10, 10, 256, 330);
359 }
360 
361 static void igt_damage_iter_single_damage_intersect_fractional_src(struct kunit *test)
362 {
363 	struct drm_damage_mock *mock = test->priv;
364 	struct drm_atomic_helper_damage_iter iter;
365 	struct drm_property_blob damage_blob;
366 	struct drm_mode_rect damage;
367 	struct drm_rect clip;
368 	u32 num_hits = 0;
369 
370 	/* Plane src has fractional part. */
371 	set_plane_src(&mock->old_state, 0x40002, 0x40002,
372 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
373 	set_plane_src(&mock->state, 0x40002, 0x40002,
374 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
375 	/* Damage intersect with plane src. */
376 	set_damage_clip(&damage, 10, 1, 1360, 330);
377 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
378 	set_plane_damage(&mock->state, &damage_blob);
379 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
380 	drm_atomic_for_each_plane_damage(&iter, &clip)
381 		num_hits++;
382 
383 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1,
384 			    "Should return damage clipped to rounded off src.");
385 	check_damage_clip(test, &clip, 10, 4, 1029, 330);
386 }
387 
388 static void igt_damage_iter_single_damage_outside_fractional_src(struct kunit *test)
389 {
390 	struct drm_damage_mock *mock = test->priv;
391 	struct drm_atomic_helper_damage_iter iter;
392 	struct drm_property_blob damage_blob;
393 	struct drm_mode_rect damage;
394 	struct drm_rect clip;
395 	u32 num_hits = 0;
396 
397 	/* Plane src has fractional part. */
398 	set_plane_src(&mock->old_state, 0x40002, 0x40002,
399 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
400 	set_plane_src(&mock->state, 0x40002, 0x40002,
401 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
402 	/* Damage clip outside plane src */
403 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
404 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
405 	set_plane_damage(&mock->state, &damage_blob);
406 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
407 	drm_atomic_for_each_plane_damage(&iter, &clip)
408 		num_hits++;
409 
410 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
411 }
412 
413 static void igt_damage_iter_single_damage_src_moved(struct kunit *test)
414 {
415 	struct drm_damage_mock *mock = test->priv;
416 	struct drm_atomic_helper_damage_iter iter;
417 	struct drm_property_blob damage_blob;
418 	struct drm_mode_rect damage;
419 	struct drm_rect clip;
420 	u32 num_hits = 0;
421 
422 	/* Plane src moved since old plane state. */
423 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
424 	set_plane_src(&mock->state, 10 << 16, 10 << 16,
425 		      (10 + 1024) << 16, (10 + 768) << 16);
426 	set_damage_clip(&damage, 20, 30, 256, 256);
427 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
428 	set_plane_damage(&mock->state, &damage_blob);
429 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
430 	drm_atomic_for_each_plane_damage(&iter, &clip)
431 		num_hits++;
432 
433 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1,
434 			    "Should return plane src as damage.");
435 	check_damage_clip(test, &clip, 10, 10, 1034, 778);
436 }
437 
438 static void igt_damage_iter_single_damage_fractional_src_moved(struct kunit *test)
439 {
440 	struct drm_damage_mock *mock = test->priv;
441 	struct drm_atomic_helper_damage_iter iter;
442 	struct drm_property_blob damage_blob;
443 	struct drm_mode_rect damage;
444 	struct drm_rect clip;
445 	u32 num_hits = 0;
446 
447 	/* Plane src with fractional part moved since old plane state. */
448 	set_plane_src(&mock->old_state, 0x3fffe, 0x3fffe,
449 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
450 	set_plane_src(&mock->state, 0x40002, 0x40002,
451 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
452 	/* Damage intersect with plane src. */
453 	set_damage_clip(&damage, 20, 30, 1360, 256);
454 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
455 	set_plane_damage(&mock->state, &damage_blob);
456 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
457 	drm_atomic_for_each_plane_damage(&iter, &clip)
458 		num_hits++;
459 
460 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1,
461 			    "Should return rounded off plane as damage.");
462 	check_damage_clip(test, &clip, 4, 4, 1029, 773);
463 }
464 
465 static void igt_damage_iter_damage(struct kunit *test)
466 {
467 	struct drm_damage_mock *mock = test->priv;
468 	struct drm_atomic_helper_damage_iter iter;
469 	struct drm_property_blob damage_blob;
470 	struct drm_mode_rect damage[2];
471 	struct drm_rect clip;
472 	u32 num_hits = 0;
473 
474 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
475 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
476 	/* 2 damage clips. */
477 	set_damage_clip(&damage[0], 20, 30, 200, 180);
478 	set_damage_clip(&damage[1], 240, 200, 280, 250);
479 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
480 	set_plane_damage(&mock->state, &damage_blob);
481 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
482 	drm_atomic_for_each_plane_damage(&iter, &clip) {
483 		if (num_hits == 0)
484 			check_damage_clip(test, &clip, 20, 30, 200, 180);
485 		if (num_hits == 1)
486 			check_damage_clip(test, &clip, 240, 200, 280, 250);
487 		num_hits++;
488 	}
489 
490 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set.");
491 }
492 
493 static void igt_damage_iter_damage_one_intersect(struct kunit *test)
494 {
495 	struct drm_damage_mock *mock = test->priv;
496 	struct drm_atomic_helper_damage_iter iter;
497 	struct drm_property_blob damage_blob;
498 	struct drm_mode_rect damage[2];
499 	struct drm_rect clip;
500 	u32 num_hits = 0;
501 
502 	set_plane_src(&mock->old_state, 0x40002, 0x40002,
503 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
504 	set_plane_src(&mock->state, 0x40002, 0x40002,
505 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
506 	/* 2 damage clips, one intersect plane src. */
507 	set_damage_clip(&damage[0], 20, 30, 200, 180);
508 	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
509 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
510 	set_plane_damage(&mock->state, &damage_blob);
511 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
512 	drm_atomic_for_each_plane_damage(&iter, &clip) {
513 		if (num_hits == 0)
514 			check_damage_clip(test, &clip, 20, 30, 200, 180);
515 		if (num_hits == 1)
516 			check_damage_clip(test, &clip, 4, 4, 1029, 773);
517 		num_hits++;
518 	}
519 
520 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set.");
521 }
522 
523 static void igt_damage_iter_damage_one_outside(struct kunit *test)
524 {
525 	struct drm_damage_mock *mock = test->priv;
526 	struct drm_atomic_helper_damage_iter iter;
527 	struct drm_property_blob damage_blob;
528 	struct drm_mode_rect damage[2];
529 	struct drm_rect clip;
530 	u32 num_hits = 0;
531 
532 	set_plane_src(&mock->old_state, 0, 0, 1024 << 16, 768 << 16);
533 	set_plane_src(&mock->state, 0, 0, 1024 << 16, 768 << 16);
534 	/* 2 damage clips, one outside plane src. */
535 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
536 	set_damage_clip(&damage[1], 240, 200, 280, 250);
537 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
538 	set_plane_damage(&mock->state, &damage_blob);
539 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
540 	drm_atomic_for_each_plane_damage(&iter, &clip)
541 		num_hits++;
542 
543 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
544 	check_damage_clip(test, &clip, 240, 200, 280, 250);
545 }
546 
547 static void igt_damage_iter_damage_src_moved(struct kunit *test)
548 {
549 	struct drm_damage_mock *mock = test->priv;
550 	struct drm_atomic_helper_damage_iter iter;
551 	struct drm_property_blob damage_blob;
552 	struct drm_mode_rect damage[2];
553 	struct drm_rect clip;
554 	u32 num_hits = 0;
555 
556 	set_plane_src(&mock->old_state, 0x40002, 0x40002,
557 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
558 	set_plane_src(&mock->state, 0x3fffe, 0x3fffe,
559 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
560 	/* 2 damage clips, one outside plane src. */
561 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
562 	set_damage_clip(&damage[1], 240, 200, 280, 250);
563 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
564 	set_plane_damage(&mock->state, &damage_blob);
565 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
566 	drm_atomic_for_each_plane_damage(&iter, &clip)
567 		num_hits++;
568 
569 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1,
570 			    "Should return round off plane src as damage.");
571 	check_damage_clip(test, &clip, 3, 3, 1028, 772);
572 }
573 
574 static void igt_damage_iter_damage_not_visible(struct kunit *test)
575 {
576 	struct drm_damage_mock *mock = test->priv;
577 	struct drm_atomic_helper_damage_iter iter;
578 	struct drm_property_blob damage_blob;
579 	struct drm_mode_rect damage[2];
580 	struct drm_rect clip;
581 	u32 num_hits = 0;
582 
583 	mock->state.visible = false;
584 
585 	set_plane_src(&mock->old_state, 0x40002, 0x40002,
586 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
587 	set_plane_src(&mock->state, 0x3fffe, 0x3fffe,
588 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
589 	/* 2 damage clips, one outside plane src. */
590 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
591 	set_damage_clip(&damage[1], 240, 200, 280, 250);
592 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
593 	set_plane_damage(&mock->state, &damage_blob);
594 	drm_atomic_helper_damage_iter_init(&iter, &mock->old_state, &mock->state);
595 	drm_atomic_for_each_plane_damage(&iter, &clip)
596 		num_hits++;
597 
598 	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should not return any damage.");
599 }
600 
601 static struct kunit_case drm_damage_helper_tests[] = {
602 	KUNIT_CASE(igt_damage_iter_no_damage),
603 	KUNIT_CASE(igt_damage_iter_no_damage_fractional_src),
604 	KUNIT_CASE(igt_damage_iter_no_damage_src_moved),
605 	KUNIT_CASE(igt_damage_iter_no_damage_fractional_src_moved),
606 	KUNIT_CASE(igt_damage_iter_no_damage_not_visible),
607 	KUNIT_CASE(igt_damage_iter_no_damage_no_crtc),
608 	KUNIT_CASE(igt_damage_iter_no_damage_no_fb),
609 	KUNIT_CASE(igt_damage_iter_simple_damage),
610 	KUNIT_CASE(igt_damage_iter_single_damage),
611 	KUNIT_CASE(igt_damage_iter_single_damage_intersect_src),
612 	KUNIT_CASE(igt_damage_iter_single_damage_outside_src),
613 	KUNIT_CASE(igt_damage_iter_single_damage_fractional_src),
614 	KUNIT_CASE(igt_damage_iter_single_damage_intersect_fractional_src),
615 	KUNIT_CASE(igt_damage_iter_single_damage_outside_fractional_src),
616 	KUNIT_CASE(igt_damage_iter_single_damage_src_moved),
617 	KUNIT_CASE(igt_damage_iter_single_damage_fractional_src_moved),
618 	KUNIT_CASE(igt_damage_iter_damage),
619 	KUNIT_CASE(igt_damage_iter_damage_one_intersect),
620 	KUNIT_CASE(igt_damage_iter_damage_one_outside),
621 	KUNIT_CASE(igt_damage_iter_damage_src_moved),
622 	KUNIT_CASE(igt_damage_iter_damage_not_visible),
623 	{ }
624 };
625 
626 static struct kunit_suite drm_damage_helper_test_suite = {
627 	.name = "drm_damage_helper",
628 	.init = drm_damage_helper_init,
629 	.test_cases = drm_damage_helper_tests,
630 };
631 
632 kunit_test_suite(drm_damage_helper_test_suite);
633 
634 MODULE_LICENSE("GPL");
635