Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Test cases for the drm_plane_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_atomic_helper.h>
 11#include <drm/drm_framebuffer.h>
 12#include <drm/drm_modes.h>
 13#include <drm/drm_rect.h>
 14
 15static const struct drm_crtc_state crtc_state = {
 16	.crtc = ZERO_SIZE_PTR,
 17	.enable = true,
 18	.active = true,
 19	.mode = {
 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)
 23	},
 24};
 25
 26struct drm_check_plane_state_test {
 27	const char *name;
 28	const char *msg;
 29	struct {
 30		unsigned int x;
 31		unsigned int y;
 32		unsigned int w;
 33		unsigned int h;
 34	} src, src_expected;
 35	struct {
 36		int x;
 37		int y;
 38		unsigned int w;
 39		unsigned int h;
 40	} crtc, crtc_expected;
 41	unsigned int rotation;
 42	int min_scale;
 43	int max_scale;
 44	bool can_position;
 45};
 46
 47static int drm_plane_helper_init(struct kunit *test)
 48{
 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;
 53
 54	plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
 55	KUNIT_ASSERT_NOT_NULL(test, plane);
 56
 57	fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
 58	KUNIT_ASSERT_NOT_NULL(test, fb);
 59	fb->width = 2048;
 60	fb->height = 2048;
 61
 62	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
 63	KUNIT_ASSERT_NOT_NULL(test, mock);
 64	mock->plane = plane;
 65	mock->crtc = ZERO_SIZE_PTR;
 66	mock->fb = fb;
 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;
 76
 77	test->priv = mock;
 78
 79	return 0;
 80}
 81
 82static 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)
 85{
 86	struct drm_rect expected = DRM_RECT_INIT(src_x, src_y, src_w, src_h);
 87
 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));
 91
 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));
 95
 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));
 99}
100
101static 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)
104{
105	struct drm_rect expected = DRM_RECT_INIT(crtc_x, crtc_y, crtc_w, crtc_h);
106
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));
110}
111
112static void drm_test_check_plane_state(struct kunit *test)
113{
114	const struct drm_check_plane_state_test *params = test->param_value;
115	struct drm_plane_state *plane_state = test->priv;
116
117	KUNIT_ASSERT_EQ_MSG(test,
118			    drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
119								params->min_scale,
120								params->max_scale,
121								params->can_position, false),
122			    0, params->msg);
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);
128}
129
130static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t,
131				       char *desc)
132{
133	sprintf(desc, "%s", t->name);
134}
135
136static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = {
137	{
138		.name = "clipping_simple",
139		.msg = "Simple clipping check should pass",
140		.src = { 0, 0,
141			 2048 << 16,
142			 2048 << 16 },
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 },
150	},
151	{
152		.name = "clipping_rotate_reflect",
153		.msg = "Rotated clipping check should pass",
154		.src = { 0, 0,
155			 2048 << 16,
156			 2048 << 16 },
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 },
164	},
165	{
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 },
176	},
177	{
178		.name = "upscaling",
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,
183		.min_scale = 0x8000,
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 },
188	},
189	{
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 },
200	},
201	{
202		.name = "rounding1",
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 },
212	},
213	{
214		.name = "rounding2",
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 },
224	},
225	{
226		.name = "rounding3",
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,
231		.min_scale = 0xffff,
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 },
237	},
238	{
239		.name = "rounding4",
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,
244		.min_scale = 0xffff,
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 },
249	},
250};
251
252KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc);
253
254static void drm_test_check_invalid_plane_state(struct kunit *test)
255{
256	const struct drm_check_plane_state_test *params = test->param_value;
257	struct drm_plane_state *plane_state = test->priv;
258
259	KUNIT_ASSERT_LT_MSG(test,
260			    drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
261								params->min_scale,
262								params->max_scale,
263								params->can_position, false),
264			    0, params->msg);
265}
266
267static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = {
268	{
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,
277	},
278	{
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,
284		.min_scale = 0x8001,
285		.max_scale = DRM_PLANE_NO_SCALING,
286		.can_position = false,
287	},
288	{
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,
297	},
298};
299
300KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests,
301		  drm_check_plane_state_desc);
302
303static 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),
307	{}
308};
309
310static 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,
314};
315
316kunit_test_suite(drm_plane_helper_test_suite);
317
318MODULE_DESCRIPTION("Test cases for the drm_plane_helper functions");
319MODULE_LICENSE("GPL");