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
15struct 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
26static int drm_damage_helper_init(struct kunit *test)
27{
28 struct drm_damage_mock *mock;
29
30 mock = kunit_kzalloc(test, size: 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(plane: &mock->plane);
53
54 test->priv = mock;
55
56 return 0;
57}
58
59static 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
73static 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
82static 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
89static 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
95static 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
119static 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(state: &mock->old_state, x1: 0, y1: 0, x2: mock->fb.width << 16, y2: mock->fb.height << 16);
128 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: mock->fb.width << 16, y2: mock->fb.height << 16);
129 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 0, y1: 0, x2: 2048, y2: 2048);
135}
136
137static 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(state: &mock->old_state, x1: 0x3fffe, y1: 0x3fffe,
146 x2: 0x3fffe + (1024 << 16), y2: 0x3fffe + (768 << 16));
147 set_plane_src(state: &mock->state, x1: 0x3fffe, y1: 0x3fffe,
148 x2: 0x3fffe + (1024 << 16), y2: 0x3fffe + (768 << 16));
149 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 3, y1: 3, x2: 1028, y2: 772);
156}
157
158static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
167 set_plane_src(state: &mock->state, x1: 10 << 16, y1: 10 << 16,
168 x2: (10 + 1024) << 16, y2: (10 + 768) << 16);
169 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 10, y1: 10, x2: 1034, y2: 778);
175}
176
177static 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(state: &mock->old_state, x1: 0x3fffe, y1: 0x3fffe,
186 x2: 0x3fffe + (1024 << 16), y2: 0x3fffe + (768 << 16));
187 set_plane_src(state: &mock->state, x1: 0x40002, y1: 0x40002,
188 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
189 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 4, y1: 4, x2: 1029, y2: 773);
195}
196
197static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
207 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
208 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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
215static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
225 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
226 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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
233static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
243 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
244 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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
251static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
261 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
262 /* Damage set to plane src */
263 set_damage_clip(r: &damage, x1: 0, y1: 0, x2: 1024, y2: 768);
264 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
265 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
266 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 0, y1: 0, x2: 1024, y2: 768);
272}
273
274static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
284 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
285 set_damage_clip(r: &damage, x1: 256, y1: 192, x2: 768, y2: 576);
286 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
287 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
288 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 256, y1: 192, x2: 768, y2: 576);
294}
295
296static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
306 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
307 /* Damage intersect with plane src. */
308 set_damage_clip(r: &damage, x1: 256, y1: 192, x2: 1360, y2: 768);
309 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
310 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
311 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 256, y1: 192, x2: 1024, y2: 768);
317}
318
319static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
329 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
330 /* Damage clip outside plane src */
331 set_damage_clip(r: &damage, x1: 1360, y1: 1360, x2: 1380, y2: 1380);
332 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
333 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
334 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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
341static 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(state: &mock->old_state, x1: 0x40002, y1: 0x40002,
352 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
353 set_plane_src(state: &mock->state, x1: 0x40002, y1: 0x40002,
354 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
355 set_damage_clip(r: &damage, x1: 10, y1: 10, x2: 256, y2: 330);
356 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
357 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
358 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 10, y1: 10, x2: 256, y2: 330);
364}
365
366static 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(state: &mock->old_state, x1: 0x40002, y1: 0x40002,
377 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
378 set_plane_src(state: &mock->state, x1: 0x40002, y1: 0x40002,
379 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
380 /* Damage intersect with plane src. */
381 set_damage_clip(r: &damage, x1: 10, y1: 1, x2: 1360, y2: 330);
382 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
383 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
384 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 10, y1: 4, x2: 1029, y2: 330);
391}
392
393static 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(state: &mock->old_state, x1: 0x40002, y1: 0x40002,
404 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
405 set_plane_src(state: &mock->state, x1: 0x40002, y1: 0x40002,
406 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
407 /* Damage clip outside plane src */
408 set_damage_clip(r: &damage, x1: 1360, y1: 1360, x2: 1380, y2: 1380);
409 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
410 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
411 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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
418static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
429 set_plane_src(state: &mock->state, x1: 10 << 16, y1: 10 << 16,
430 x2: (10 + 1024) << 16, y2: (10 + 768) << 16);
431 set_damage_clip(r: &damage, x1: 20, y1: 30, x2: 256, y2: 256);
432 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
433 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
434 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 10, y1: 10, x2: 1034, y2: 778);
441}
442
443static 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(state: &mock->old_state, x1: 0x3fffe, y1: 0x3fffe,
454 x2: 0x3fffe + (1024 << 16), y2: 0x3fffe + (768 << 16));
455 set_plane_src(state: &mock->state, x1: 0x40002, y1: 0x40002,
456 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
457 /* Damage intersect with plane src. */
458 set_damage_clip(r: &damage, x1: 20, y1: 30, x2: 1360, y2: 256);
459 set_damage_blob(damage_blob: &damage_blob, r: &damage, size: sizeof(damage));
460 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
461 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 4, y1: 4, x2: 1029, y2: 773);
468}
469
470static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
480 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
481 /* 2 damage clips. */
482 set_damage_clip(r: &damage[0], x1: 20, y1: 30, x2: 200, y2: 180);
483 set_damage_clip(r: &damage[1], x1: 240, y1: 200, x2: 280, y2: 250);
484 set_damage_blob(damage_blob: &damage_blob, r: &damage[0], size: sizeof(damage));
485 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
486 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_state: &mock->state);
487 drm_atomic_for_each_plane_damage(&iter, &clip) {
488 if (num_hits == 0)
489 check_damage_clip(test, r: &clip, x1: 20, y1: 30, x2: 200, y2: 180);
490 if (num_hits == 1)
491 check_damage_clip(test, r: &clip, x1: 240, y1: 200, x2: 280, y2: 250);
492 num_hits++;
493 }
494
495 KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set.");
496}
497
498static 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(state: &mock->old_state, x1: 0x40002, y1: 0x40002,
508 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
509 set_plane_src(state: &mock->state, x1: 0x40002, y1: 0x40002,
510 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
511 /* 2 damage clips, one intersect plane src. */
512 set_damage_clip(r: &damage[0], x1: 20, y1: 30, x2: 200, y2: 180);
513 set_damage_clip(r: &damage[1], x1: 2, y1: 2, x2: 1360, y2: 1360);
514 set_damage_blob(damage_blob: &damage_blob, r: &damage[0], size: sizeof(damage));
515 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
516 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_state: &mock->state);
517 drm_atomic_for_each_plane_damage(&iter, &clip) {
518 if (num_hits == 0)
519 check_damage_clip(test, r: &clip, x1: 20, y1: 30, x2: 200, y2: 180);
520 if (num_hits == 1)
521 check_damage_clip(test, r: &clip, x1: 4, y1: 4, x2: 1029, y2: 773);
522 num_hits++;
523 }
524
525 KUNIT_EXPECT_EQ_MSG(test, num_hits, 2, "Should return damage when set.");
526}
527
528static 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(state: &mock->old_state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
538 set_plane_src(state: &mock->state, x1: 0, y1: 0, x2: 1024 << 16, y2: 768 << 16);
539 /* 2 damage clips, one outside plane src. */
540 set_damage_clip(r: &damage[0], x1: 1360, y1: 1360, x2: 1380, y2: 1380);
541 set_damage_clip(r: &damage[1], x1: 240, y1: 200, x2: 280, y2: 250);
542 set_damage_blob(damage_blob: &damage_blob, r: &damage[0], size: sizeof(damage));
543 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
544 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 240, y1: 200, x2: 280, y2: 250);
550}
551
552static 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(state: &mock->old_state, x1: 0x40002, y1: 0x40002,
562 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
563 set_plane_src(state: &mock->state, x1: 0x3fffe, y1: 0x3fffe,
564 x2: 0x3fffe + (1024 << 16), y2: 0x3fffe + (768 << 16));
565 /* 2 damage clips, one outside plane src. */
566 set_damage_clip(r: &damage[0], x1: 1360, y1: 1360, x2: 1380, y2: 1380);
567 set_damage_clip(r: &damage[1], x1: 240, y1: 200, x2: 280, y2: 250);
568 set_damage_blob(damage_blob: &damage_blob, r: &damage[0], size: sizeof(damage));
569 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
570 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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, r: &clip, x1: 3, y1: 3, x2: 1028, y2: 772);
577}
578
579static 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(state: &mock->old_state, x1: 0x40002, y1: 0x40002,
591 x2: 0x40002 + (1024 << 16), y2: 0x40002 + (768 << 16));
592 set_plane_src(state: &mock->state, x1: 0x3fffe, y1: 0x3fffe,
593 x2: 0x3fffe + (1024 << 16), y2: 0x3fffe + (768 << 16));
594 /* 2 damage clips, one outside plane src. */
595 set_damage_clip(r: &damage[0], x1: 1360, y1: 1360, x2: 1380, y2: 1380);
596 set_damage_clip(r: &damage[1], x1: 240, y1: 200, x2: 280, y2: 250);
597 set_damage_blob(damage_blob: &damage_blob, r: &damage[0], size: sizeof(damage));
598 set_plane_damage(state: &mock->state, damage_blob: &damage_blob);
599 drm_atomic_helper_damage_iter_init(iter: &iter, old_state: &mock->old_state, new_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
606static 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
631static 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
637kunit_test_suite(drm_damage_helper_test_suite);
638
639MODULE_LICENSE("GPL");
640

source code of linux/drivers/gpu/drm/tests/drm_damage_helper_test.c