1 // SPDX-License-Identifier: GPL-2.0
3 * Test cases for the drm_plane_helper functions
8 #include <kunit/test.h>
10 #include <drm/drm_atomic_helper.h>
11 #include <drm/drm_framebuffer.h>
12 #include <drm/drm_modes.h>
13 #include <drm/drm_rect.h>
15 static const struct drm_crtc_state crtc_state = {
16 .crtc = ZERO_SIZE_PTR,
20 DRM_MODE("1024x768", 0, 65000, 1024, 1048,
21 1184, 1344, 0, 768, 771, 777, 806, 0,
22 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
26 struct drm_check_plane_state_test {
40 } crtc, crtc_expected;
41 unsigned int rotation;
47 static int drm_plane_helper_init(struct kunit *test)
49 const struct drm_check_plane_state_test *params = test->param_value;
50 struct drm_plane *plane;
51 struct drm_framebuffer *fb;
52 struct drm_plane_state *mock;
54 plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
55 KUNIT_ASSERT_NOT_NULL(test, plane);
57 fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
58 KUNIT_ASSERT_NOT_NULL(test, fb);
62 mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
63 KUNIT_ASSERT_NOT_NULL(test, mock);
65 mock->crtc = ZERO_SIZE_PTR;
67 mock->rotation = params->rotation;
68 mock->src_x = params->src.x;
69 mock->src_y = params->src.y;
70 mock->src_w = params->src.w;
71 mock->src_h = params->src.h;
72 mock->crtc_x = params->crtc.x;
73 mock->crtc_y = params->crtc.y;
74 mock->crtc_w = params->crtc.w;
75 mock->crtc_h = params->crtc.h;
82 static void check_src_eq(struct kunit *test, struct drm_plane_state *plane_state,
83 unsigned int src_x, unsigned int src_y,
84 unsigned int src_w, unsigned int src_h)
86 struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h);
88 KUNIT_ASSERT_GE_MSG(test, plane_state->src.x1, 0,
89 "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
90 plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src));
92 KUNIT_ASSERT_GE_MSG(test, plane_state->src.y1, 0,
93 "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
94 plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src));
96 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->src, &expected),
97 "dst: " DRM_RECT_FP_FMT ", expected: " DRM_RECT_FP_FMT,
98 DRM_RECT_FP_ARG(&plane_state->src), DRM_RECT_FP_ARG(&expected));
101 static void check_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state,
102 int crtc_x, int crtc_y,
103 unsigned int crtc_w, unsigned int crtc_h)
105 struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h);
107 KUNIT_EXPECT_TRUE_MSG(test, drm_rect_equals(&plane_state->dst, &expected),
108 "dst: " DRM_RECT_FMT ", expected: " DRM_RECT_FMT,
109 DRM_RECT_ARG(&plane_state->dst), DRM_RECT_ARG(&expected));
112 static void drm_test_check_plane_state(struct kunit *test)
114 const struct drm_check_plane_state_test *params = test->param_value;
115 struct drm_plane_state *plane_state = test->priv;
117 KUNIT_ASSERT_EQ_MSG(test,
118 drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
121 params->can_position, false),
123 KUNIT_EXPECT_TRUE(test, plane_state->visible);
124 check_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y,
125 params->src_expected.w, params->src_expected.h);
126 check_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y,
127 params->crtc_expected.w, params->crtc_expected.h);
130 static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t,
133 sprintf(desc, "%s", t->name);
136 static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = {
138 .name = "clipping_simple",
139 .msg = "Simple clipping check should pass",
143 .crtc = { 0, 0, 2048, 2048 },
144 .rotation = DRM_MODE_ROTATE_0,
145 .min_scale = DRM_PLANE_NO_SCALING,
146 .max_scale = DRM_PLANE_NO_SCALING,
147 .can_position = false,
148 .src_expected = { 0, 0, 1024 << 16, 768 << 16 },
149 .crtc_expected = { 0, 0, 1024, 768 },
152 .name = "clipping_rotate_reflect",
153 .msg = "Rotated clipping check should pass",
157 .crtc = { 0, 0, 2048, 2048 },
158 .rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X,
159 .min_scale = DRM_PLANE_NO_SCALING,
160 .max_scale = DRM_PLANE_NO_SCALING,
161 .can_position = false,
162 .src_expected = { 0, 0, 768 << 16, 1024 << 16 },
163 .crtc_expected = { 0, 0, 1024, 768 },
166 .name = "positioning_simple",
167 .msg = "Simple positioning should work",
168 .src = { 0, 0, 1023 << 16, 767 << 16 },
169 .crtc = { 0, 0, 1023, 767 },
170 .rotation = DRM_MODE_ROTATE_0,
171 .min_scale = DRM_PLANE_NO_SCALING,
172 .max_scale = DRM_PLANE_NO_SCALING,
173 .can_position = true,
174 .src_expected = { 0, 0, 1023 << 16, 767 << 16 },
175 .crtc_expected = { 0, 0, 1023, 767 },
179 .msg = "Upscaling exactly 2x should work",
180 .src = { 0, 0, 512 << 16, 384 << 16 },
181 .crtc = { 0, 0, 1024, 768 },
182 .rotation = DRM_MODE_ROTATE_0,
184 .max_scale = DRM_PLANE_NO_SCALING,
185 .can_position = false,
186 .src_expected = { 0, 0, 512 << 16, 384 << 16 },
187 .crtc_expected = { 0, 0, 1024, 768 },
190 .name = "downscaling",
191 .msg = "Should succeed with exact scaling limit",
192 .src = { 0, 0, 2048 << 16, 1536 << 16 },
193 .crtc = { 0, 0, 1024, 768 },
194 .rotation = DRM_MODE_ROTATE_0,
195 .min_scale = DRM_PLANE_NO_SCALING,
196 .max_scale = 0x20000,
197 .can_position = false,
198 .src_expected = { 0, 0, 2048 << 16, 1536 << 16 },
199 .crtc_expected = { 0, 0, 1024, 768 },
203 .msg = "Should succeed by clipping to exact multiple",
204 .src = { 0, 0, 0x40001, 0x40001 },
205 .crtc = { 1022, 766, 4, 4 },
206 .rotation = DRM_MODE_ROTATE_0,
207 .min_scale = DRM_PLANE_NO_SCALING,
208 .max_scale = 0x10001,
209 .can_position = true,
210 .src_expected = { 0, 0, 2 << 16, 2 << 16 },
211 .crtc_expected = { 1022, 766, 2, 2 },
215 .msg = "Should succeed by clipping to exact multiple",
216 .src = { 0x20001, 0x20001, 0x4040001, 0x3040001 },
217 .crtc = { -2, -2, 1028, 772 },
218 .rotation = DRM_MODE_ROTATE_0,
219 .min_scale = DRM_PLANE_NO_SCALING,
220 .max_scale = 0x10001,
221 .can_position = false,
222 .src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 },
223 .crtc_expected = { 0, 0, 1024, 768 },
227 .msg = "Should succeed by clipping to exact multiple",
228 .src = { 0, 0, 0x3ffff, 0x3ffff },
229 .crtc = { 1022, 766, 4, 4 },
230 .rotation = DRM_MODE_ROTATE_0,
232 .max_scale = DRM_PLANE_NO_SCALING,
233 .can_position = true,
234 /* Should not be rounded to 0x20001, which would be upscaling. */
235 .src_expected = { 0, 0, 2 << 16, 2 << 16 },
236 .crtc_expected = { 1022, 766, 2, 2 },
240 .msg = "Should succeed by clipping to exact multiple",
241 .src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff },
242 .crtc = { -2, -2, 1028, 772 },
243 .rotation = DRM_MODE_ROTATE_0,
245 .max_scale = DRM_PLANE_NO_SCALING,
246 .can_position = false,
247 .src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 },
248 .crtc_expected = { 0, 0, 1024, 768 },
252 KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc);
254 static void drm_test_check_invalid_plane_state(struct kunit *test)
256 const struct drm_check_plane_state_test *params = test->param_value;
257 struct drm_plane_state *plane_state = test->priv;
259 KUNIT_ASSERT_LT_MSG(test,
260 drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
263 params->can_position, false),
267 static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = {
269 .name = "positioning_invalid",
270 .msg = "Should not be able to position on the crtc with can_position=false",
271 .src = { 0, 0, 1023 << 16, 767 << 16 },
272 .crtc = { 0, 0, 1023, 767 },
273 .rotation = DRM_MODE_ROTATE_0,
274 .min_scale = DRM_PLANE_NO_SCALING,
275 .max_scale = DRM_PLANE_NO_SCALING,
276 .can_position = false,
279 .name = "upscaling_invalid",
280 .msg = "Upscaling out of range should fail",
281 .src = { 0, 0, 512 << 16, 384 << 16 },
282 .crtc = { 0, 0, 1024, 768 },
283 .rotation = DRM_MODE_ROTATE_0,
285 .max_scale = DRM_PLANE_NO_SCALING,
286 .can_position = false,
289 .name = "downscaling_invalid",
290 .msg = "Downscaling out of range should fail",
291 .src = { 0, 0, 2048 << 16, 1536 << 16 },
292 .crtc = { 0, 0, 1024, 768 },
293 .rotation = DRM_MODE_ROTATE_0,
294 .min_scale = DRM_PLANE_NO_SCALING,
295 .max_scale = 0x1ffff,
296 .can_position = false,
300 KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests,
301 drm_check_plane_state_desc);
303 static struct kunit_case drm_plane_helper_test[] = {
304 KUNIT_CASE_PARAM(drm_test_check_plane_state, drm_check_plane_state_gen_params),
305 KUNIT_CASE_PARAM(drm_test_check_invalid_plane_state,
306 drm_check_invalid_plane_state_gen_params),
310 static struct kunit_suite drm_plane_helper_test_suite = {
311 .name = "drm_plane_helper",
312 .init = drm_plane_helper_init,
313 .test_cases = drm_plane_helper_test,
316 kunit_test_suite(drm_plane_helper_test_suite);
318 MODULE_LICENSE("GPL");