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, 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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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(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 | |
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 | |