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