1 // SPDX-License-Identifier: GPL-2.0+
3 #include <kunit/test.h>
5 #include <drm/drm_device.h>
6 #include <drm/drm_file.h>
7 #include <drm/drm_format_helper.h>
8 #include <drm/drm_fourcc.h>
9 #include <drm/drm_framebuffer.h>
10 #include <drm/drm_gem_framebuffer_helper.h>
11 #include <drm/drm_mode.h>
12 #include <drm/drm_print.h>
13 #include <drm/drm_rect.h>
15 #include "../drm_crtc_internal.h"
17 #define TEST_BUF_SIZE 50
19 struct convert_to_gray8_result {
20 unsigned int dst_pitch;
21 const u8 expected[TEST_BUF_SIZE];
24 struct convert_to_rgb332_result {
25 unsigned int dst_pitch;
26 const u8 expected[TEST_BUF_SIZE];
29 struct convert_to_rgb565_result {
30 unsigned int dst_pitch;
31 const u16 expected[TEST_BUF_SIZE];
32 const u16 expected_swab[TEST_BUF_SIZE];
35 struct convert_to_rgb888_result {
36 unsigned int dst_pitch;
37 const u8 expected[TEST_BUF_SIZE];
40 struct convert_to_xrgb2101010_result {
41 unsigned int dst_pitch;
42 const u32 expected[TEST_BUF_SIZE];
45 struct convert_xrgb8888_case {
49 const u32 xrgb8888[TEST_BUF_SIZE];
50 struct convert_to_gray8_result gray8_result;
51 struct convert_to_rgb332_result rgb332_result;
52 struct convert_to_rgb565_result rgb565_result;
53 struct convert_to_rgb888_result rgb888_result;
54 struct convert_to_xrgb2101010_result xrgb2101010_result;
57 static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
59 .name = "single_pixel_source_buffer",
61 .clip = DRM_RECT_INIT(0, 0, 1, 1),
62 .xrgb8888 = { 0x01FF0000 },
73 .expected = { 0xF800 },
74 .expected_swab = { 0x00F8 },
78 .expected = { 0x00, 0x00, 0xFF },
80 .xrgb2101010_result = {
82 .expected = { 0x3FF00000 },
86 .name = "single_pixel_clip_rectangle",
88 .clip = DRM_RECT_INIT(1, 1, 1, 1),
90 0x00000000, 0x00000000,
91 0x00000000, 0x10FF0000,
103 .expected = { 0xF800 },
104 .expected_swab = { 0x00F8 },
108 .expected = { 0x00, 0x00, 0xFF },
110 .xrgb2101010_result = {
112 .expected = { 0x3FF00000 },
116 /* Well known colors: White, black, red, green, blue, magenta,
117 * yellow and cyan. Different values for the X in XRGB8888 to
118 * make sure it is ignored. Partial clip area.
120 .name = "well_known_colors",
122 .clip = DRM_RECT_INIT(1, 1, 2, 4),
124 0x00000000, 0x00000000, 0x00000000, 0x00000000,
125 0x00000000, 0x11FFFFFF, 0x22000000, 0x00000000,
126 0x00000000, 0x33FF0000, 0x4400FF00, 0x00000000,
127 0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000,
128 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000,
166 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
167 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00,
168 0xFF, 0x00, 0x00, 0xFF, 0x00, 0xFF,
169 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
172 .xrgb2101010_result = {
175 0x3FFFFFFF, 0x00000000,
176 0x3FF00000, 0x000FFC00,
177 0x000003FF, 0x3FF003FF,
178 0x3FFFFC00, 0x000FFFFF,
183 /* Randomly picked colors. Full buffer within the clip area. */
184 .name = "destination_pitch",
186 .clip = DRM_RECT_INIT(0, 0, 3, 3),
188 0xA10E449C, 0xB1114D05, 0xC1A80303,
189 0xD16C7073, 0xA20E449C, 0xB2114D05,
190 0xC2A80303, 0xD26C7073, 0xA30E449C,
195 0x3C, 0x33, 0x34, 0x00, 0x00,
196 0x6F, 0x3C, 0x33, 0x00, 0x00,
197 0x34, 0x6F, 0x3C, 0x00, 0x00,
203 0x0A, 0x08, 0xA0, 0x00, 0x00,
204 0x6D, 0x0A, 0x08, 0x00, 0x00,
205 0xA0, 0x6D, 0x0A, 0x00, 0x00,
211 0x0A33, 0x1260, 0xA800, 0x0000, 0x0000,
212 0x6B8E, 0x0A33, 0x1260, 0x0000, 0x0000,
213 0xA800, 0x6B8E, 0x0A33, 0x0000, 0x0000,
216 0x330A, 0x6012, 0x00A8, 0x0000, 0x0000,
217 0x8E6B, 0x330A, 0x6012, 0x0000, 0x0000,
218 0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000,
224 0x9C, 0x44, 0x0E, 0x05, 0x4D, 0x11, 0x03, 0x03, 0xA8,
225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226 0x73, 0x70, 0x6C, 0x9C, 0x44, 0x0E, 0x05, 0x4D, 0x11,
227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x03, 0x03, 0xA8, 0x73, 0x70, 0x6C, 0x9C, 0x44, 0x0E,
229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232 .xrgb2101010_result = {
235 0x03844672, 0x0444D414, 0x2A20300C, 0x00000000, 0x00000000,
236 0x1B1705CD, 0x03844672, 0x0444D414, 0x00000000, 0x00000000,
237 0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000,
244 * conversion_buf_size - Return the destination buffer size required to convert
246 * @dst_format: destination buffer pixel format (DRM_FORMAT_*)
247 * @dst_pitch: Number of bytes between two consecutive scanlines within dst
248 * @clip: Clip rectangle area to convert
251 * The size of the destination buffer or negative value on error.
253 static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch,
254 const struct drm_rect *clip)
256 const struct drm_format_info *dst_fi = drm_format_info(dst_format);
262 dst_pitch = drm_rect_width(clip) * dst_fi->cpp[0];
264 return dst_pitch * drm_rect_height(clip);
267 static u16 *le16buf_to_cpu(struct kunit *test, const __le16 *buf, size_t buf_size)
272 dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
276 for (n = 0; n < buf_size; n++)
277 dst[n] = le16_to_cpu(buf[n]);
282 static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size)
287 dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
291 for (n = 0; n < buf_size; n++)
292 dst[n] = le32_to_cpu((__force __le32)buf[n]);
297 static __le32 *cpubuf_to_le32(struct kunit *test, const u32 *buf, size_t buf_size)
302 dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
306 for (n = 0; n < buf_size; n++)
307 dst[n] = cpu_to_le32(buf[n]);
312 static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t,
315 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
318 KUNIT_ARRAY_PARAM(convert_xrgb8888, convert_xrgb8888_cases,
319 convert_xrgb8888_case_desc);
321 static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
323 const struct convert_xrgb8888_case *params = test->param_value;
324 const struct convert_to_gray8_result *result = ¶ms->gray8_result;
327 __le32 *xrgb8888 = NULL;
328 struct iosys_map dst, src;
330 struct drm_framebuffer fb = {
331 .format = drm_format_info(DRM_FORMAT_XRGB8888),
332 .pitches = { params->pitch, 0, 0 },
335 dst_size = conversion_buf_size(DRM_FORMAT_R8, result->dst_pitch,
337 KUNIT_ASSERT_GT(test, dst_size, 0);
339 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
340 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
341 iosys_map_set_vaddr(&dst, buf);
343 xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
344 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
345 iosys_map_set_vaddr(&src, xrgb8888);
347 drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
348 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
351 static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
353 const struct convert_xrgb8888_case *params = test->param_value;
354 const struct convert_to_rgb332_result *result = ¶ms->rgb332_result;
357 __le32 *xrgb8888 = NULL;
358 struct iosys_map dst, src;
360 struct drm_framebuffer fb = {
361 .format = drm_format_info(DRM_FORMAT_XRGB8888),
362 .pitches = { params->pitch, 0, 0 },
365 dst_size = conversion_buf_size(DRM_FORMAT_RGB332, result->dst_pitch,
367 KUNIT_ASSERT_GT(test, dst_size, 0);
369 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
370 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
371 iosys_map_set_vaddr(&dst, buf);
373 xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
374 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
375 iosys_map_set_vaddr(&src, xrgb8888);
377 drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
378 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
381 static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
383 const struct convert_xrgb8888_case *params = test->param_value;
384 const struct convert_to_rgb565_result *result = ¶ms->rgb565_result;
387 __le32 *xrgb8888 = NULL;
388 struct iosys_map dst, src;
390 struct drm_framebuffer fb = {
391 .format = drm_format_info(DRM_FORMAT_XRGB8888),
392 .pitches = { params->pitch, 0, 0 },
395 dst_size = conversion_buf_size(DRM_FORMAT_RGB565, result->dst_pitch,
397 KUNIT_ASSERT_GT(test, dst_size, 0);
399 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
400 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
401 iosys_map_set_vaddr(&dst, buf);
403 xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
404 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
405 iosys_map_set_vaddr(&src, xrgb8888);
407 drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, false);
408 buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
409 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
411 buf = dst.vaddr; /* restore original value of buf */
412 drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true);
413 buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16));
414 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0);
417 static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
419 const struct convert_xrgb8888_case *params = test->param_value;
420 const struct convert_to_rgb888_result *result = ¶ms->rgb888_result;
423 __le32 *xrgb8888 = NULL;
424 struct iosys_map dst, src;
426 struct drm_framebuffer fb = {
427 .format = drm_format_info(DRM_FORMAT_XRGB8888),
428 .pitches = { params->pitch, 0, 0 },
431 dst_size = conversion_buf_size(DRM_FORMAT_RGB888, result->dst_pitch,
433 KUNIT_ASSERT_GT(test, dst_size, 0);
435 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
436 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
437 iosys_map_set_vaddr(&dst, buf);
439 xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
440 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
441 iosys_map_set_vaddr(&src, xrgb8888);
444 * RGB888 expected results are already in little-endian
445 * order, so there's no need to convert the test output.
447 drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
448 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
451 static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
453 const struct convert_xrgb8888_case *params = test->param_value;
454 const struct convert_to_xrgb2101010_result *result = ¶ms->xrgb2101010_result;
457 __le32 *xrgb8888 = NULL;
458 struct iosys_map dst, src;
460 struct drm_framebuffer fb = {
461 .format = drm_format_info(DRM_FORMAT_XRGB8888),
462 .pitches = { params->pitch, 0, 0 },
465 dst_size = conversion_buf_size(DRM_FORMAT_XRGB2101010,
466 result->dst_pitch, ¶ms->clip);
467 KUNIT_ASSERT_GT(test, dst_size, 0);
469 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL);
470 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
471 iosys_map_set_vaddr(&dst, buf);
473 xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE);
474 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888);
475 iosys_map_set_vaddr(&src, xrgb8888);
477 drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
478 buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32));
479 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
482 static struct kunit_case drm_format_helper_test_cases[] = {
483 KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_gray8, convert_xrgb8888_gen_params),
484 KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb332, convert_xrgb8888_gen_params),
485 KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb565, convert_xrgb8888_gen_params),
486 KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_rgb888, convert_xrgb8888_gen_params),
487 KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xrgb2101010, convert_xrgb8888_gen_params),
491 static struct kunit_suite drm_format_helper_test_suite = {
492 .name = "drm_format_helper_test",
493 .test_cases = drm_format_helper_test_cases,
496 kunit_test_suite(drm_format_helper_test_suite);
498 MODULE_DESCRIPTION("KUnit tests for the drm_format_helper APIs");
499 MODULE_LICENSE("GPL");
500 MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");