drm/format-helper: Store RGB565 in little-endian order
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / tests / drm_format_helper_test.c
1 // SPDX-License-Identifier: GPL-2.0+
2
3 #include <kunit/test.h>
4
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>
14
15 #include "../drm_crtc_internal.h"
16
17 #define TEST_BUF_SIZE 50
18
19 struct convert_to_gray8_result {
20         unsigned int dst_pitch;
21         const u8 expected[TEST_BUF_SIZE];
22 };
23
24 struct convert_to_rgb332_result {
25         unsigned int dst_pitch;
26         const u8 expected[TEST_BUF_SIZE];
27 };
28
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];
33 };
34
35 struct convert_to_rgb888_result {
36         unsigned int dst_pitch;
37         const u8 expected[TEST_BUF_SIZE];
38 };
39
40 struct convert_to_xrgb2101010_result {
41         unsigned int dst_pitch;
42         const u32 expected[TEST_BUF_SIZE];
43 };
44
45 struct convert_xrgb8888_case {
46         const char *name;
47         unsigned int pitch;
48         struct drm_rect clip;
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;
55 };
56
57 static struct convert_xrgb8888_case convert_xrgb8888_cases[] = {
58         {
59                 .name = "single_pixel_source_buffer",
60                 .pitch = 1 * 4,
61                 .clip = DRM_RECT_INIT(0, 0, 1, 1),
62                 .xrgb8888 = { 0x01FF0000 },
63                 .gray8_result = {
64                         .dst_pitch = 0,
65                         .expected = { 0x4C },
66                 },
67                 .rgb332_result = {
68                         .dst_pitch = 0,
69                         .expected = { 0xE0 },
70                 },
71                 .rgb565_result = {
72                         .dst_pitch = 0,
73                         .expected = { 0xF800 },
74                         .expected_swab = { 0x00F8 },
75                 },
76                 .rgb888_result = {
77                         .dst_pitch = 0,
78                         .expected = { 0x00, 0x00, 0xFF },
79                 },
80                 .xrgb2101010_result = {
81                         .dst_pitch = 0,
82                         .expected = { 0x3FF00000 },
83                 },
84         },
85         {
86                 .name = "single_pixel_clip_rectangle",
87                 .pitch = 2 * 4,
88                 .clip = DRM_RECT_INIT(1, 1, 1, 1),
89                 .xrgb8888 = {
90                         0x00000000, 0x00000000,
91                         0x00000000, 0x10FF0000,
92                 },
93                 .gray8_result = {
94                         .dst_pitch = 0,
95                         .expected = { 0x4C },
96                 },
97                 .rgb332_result = {
98                         .dst_pitch = 0,
99                         .expected = { 0xE0 },
100                 },
101                 .rgb565_result = {
102                         .dst_pitch = 0,
103                         .expected = { 0xF800 },
104                         .expected_swab = { 0x00F8 },
105                 },
106                 .rgb888_result = {
107                         .dst_pitch = 0,
108                         .expected = { 0x00, 0x00, 0xFF },
109                 },
110                 .xrgb2101010_result = {
111                         .dst_pitch = 0,
112                         .expected = { 0x3FF00000 },
113                 },
114         },
115         {
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.
119                  */
120                 .name = "well_known_colors",
121                 .pitch = 4 * 4,
122                 .clip = DRM_RECT_INIT(1, 1, 2, 4),
123                 .xrgb8888 = {
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,
129                 },
130                 .gray8_result = {
131                         .dst_pitch = 0,
132                         .expected = {
133                                 0xFF, 0x00,
134                                 0x4C, 0x99,
135                                 0x19, 0x66,
136                                 0xE5, 0xB2,
137                         },
138                 },
139                 .rgb332_result = {
140                         .dst_pitch = 0,
141                         .expected = {
142                                 0xFF, 0x00,
143                                 0xE0, 0x1C,
144                                 0x03, 0xE3,
145                                 0xFC, 0x1F,
146                         },
147                 },
148                 .rgb565_result = {
149                         .dst_pitch = 0,
150                         .expected = {
151                                 0xFFFF, 0x0000,
152                                 0xF800, 0x07E0,
153                                 0x001F, 0xF81F,
154                                 0xFFE0, 0x07FF,
155                         },
156                         .expected_swab = {
157                                 0xFFFF, 0x0000,
158                                 0x00F8, 0xE007,
159                                 0x1F00, 0x1FF8,
160                                 0xE0FF, 0xFF07,
161                         },
162                 },
163                 .rgb888_result = {
164                         .dst_pitch = 0,
165                         .expected = {
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,
170                         },
171                 },
172                 .xrgb2101010_result = {
173                         .dst_pitch = 0,
174                         .expected = {
175                                 0x3FFFFFFF, 0x00000000,
176                                 0x3FF00000, 0x000FFC00,
177                                 0x000003FF, 0x3FF003FF,
178                                 0x3FFFFC00, 0x000FFFFF,
179                         },
180                 },
181         },
182         {
183                 /* Randomly picked colors. Full buffer within the clip area. */
184                 .name = "destination_pitch",
185                 .pitch = 3 * 4,
186                 .clip = DRM_RECT_INIT(0, 0, 3, 3),
187                 .xrgb8888 = {
188                         0xA10E449C, 0xB1114D05, 0xC1A80303,
189                         0xD16C7073, 0xA20E449C, 0xB2114D05,
190                         0xC2A80303, 0xD26C7073, 0xA30E449C,
191                 },
192                 .gray8_result = {
193                         .dst_pitch = 5,
194                         .expected = {
195                                 0x3C, 0x33, 0x34, 0x00, 0x00,
196                                 0x6F, 0x3C, 0x33, 0x00, 0x00,
197                                 0x34, 0x6F, 0x3C, 0x00, 0x00,
198                         },
199                 },
200                 .rgb332_result = {
201                         .dst_pitch = 5,
202                         .expected = {
203                                 0x0A, 0x08, 0xA0, 0x00, 0x00,
204                                 0x6D, 0x0A, 0x08, 0x00, 0x00,
205                                 0xA0, 0x6D, 0x0A, 0x00, 0x00,
206                         },
207                 },
208                 .rgb565_result = {
209                         .dst_pitch = 10,
210                         .expected = {
211                                 0x0A33, 0x1260, 0xA800, 0x0000, 0x0000,
212                                 0x6B8E, 0x0A33, 0x1260, 0x0000, 0x0000,
213                                 0xA800, 0x6B8E, 0x0A33, 0x0000, 0x0000,
214                         },
215                         .expected_swab = {
216                                 0x330A, 0x6012, 0x00A8, 0x0000, 0x0000,
217                                 0x8E6B, 0x330A, 0x6012, 0x0000, 0x0000,
218                                 0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000,
219                         },
220                 },
221                 .rgb888_result = {
222                         .dst_pitch = 15,
223                         .expected = {
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,
230                         },
231                 },
232                 .xrgb2101010_result = {
233                         .dst_pitch = 20,
234                         .expected = {
235                                 0x03844672, 0x0444D414, 0x2A20300C, 0x00000000, 0x00000000,
236                                 0x1B1705CD, 0x03844672, 0x0444D414, 0x00000000, 0x00000000,
237                                 0x2A20300C, 0x1B1705CD, 0x03844672, 0x00000000, 0x00000000,
238                         },
239                 },
240         },
241 };
242
243 /*
244  * conversion_buf_size - Return the destination buffer size required to convert
245  * between formats.
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
249  *
250  * Returns:
251  * The size of the destination buffer or negative value on error.
252  */
253 static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch,
254                                   const struct drm_rect *clip)
255 {
256         const struct drm_format_info *dst_fi = drm_format_info(dst_format);
257
258         if (!dst_fi)
259                 return -EINVAL;
260
261         if (!dst_pitch)
262                 dst_pitch = drm_rect_width(clip) * dst_fi->cpp[0];
263
264         return dst_pitch * drm_rect_height(clip);
265 }
266
267 static u16 *le16buf_to_cpu(struct kunit *test, const __le16 *buf, size_t buf_size)
268 {
269         u16 *dst = NULL;
270         int n;
271
272         dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
273         if (!dst)
274                 return NULL;
275
276         for (n = 0; n < buf_size; n++)
277                 dst[n] = le16_to_cpu(buf[n]);
278
279         return dst;
280 }
281
282 static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size)
283 {
284         u32 *dst = NULL;
285         int n;
286
287         dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
288         if (!dst)
289                 return NULL;
290
291         for (n = 0; n < buf_size; n++)
292                 dst[n] = le32_to_cpu((__force __le32)buf[n]);
293
294         return dst;
295 }
296
297 static __le32 *cpubuf_to_le32(struct kunit *test, const u32 *buf, size_t buf_size)
298 {
299         __le32 *dst = NULL;
300         int n;
301
302         dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL);
303         if (!dst)
304                 return NULL;
305
306         for (n = 0; n < buf_size; n++)
307                 dst[n] = cpu_to_le32(buf[n]);
308
309         return dst;
310 }
311
312 static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t,
313                                        char *desc)
314 {
315         strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
316 }
317
318 KUNIT_ARRAY_PARAM(convert_xrgb8888, convert_xrgb8888_cases,
319                   convert_xrgb8888_case_desc);
320
321 static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
322 {
323         const struct convert_xrgb8888_case *params = test->param_value;
324         const struct convert_to_gray8_result *result = &params->gray8_result;
325         size_t dst_size;
326         __u8 *buf = NULL;
327         __le32 *xrgb8888 = NULL;
328         struct iosys_map dst, src;
329
330         struct drm_framebuffer fb = {
331                 .format = drm_format_info(DRM_FORMAT_XRGB8888),
332                 .pitches = { params->pitch, 0, 0 },
333         };
334
335         dst_size = conversion_buf_size(DRM_FORMAT_R8, result->dst_pitch,
336                                        &params->clip);
337         KUNIT_ASSERT_GT(test, dst_size, 0);
338
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);
342
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);
346
347         drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, &params->clip);
348         KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
349 }
350
351 static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
352 {
353         const struct convert_xrgb8888_case *params = test->param_value;
354         const struct convert_to_rgb332_result *result = &params->rgb332_result;
355         size_t dst_size;
356         __u8 *buf = NULL;
357         __le32 *xrgb8888 = NULL;
358         struct iosys_map dst, src;
359
360         struct drm_framebuffer fb = {
361                 .format = drm_format_info(DRM_FORMAT_XRGB8888),
362                 .pitches = { params->pitch, 0, 0 },
363         };
364
365         dst_size = conversion_buf_size(DRM_FORMAT_RGB332, result->dst_pitch,
366                                        &params->clip);
367         KUNIT_ASSERT_GT(test, dst_size, 0);
368
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);
372
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);
376
377         drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, &params->clip);
378         KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
379 }
380
381 static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
382 {
383         const struct convert_xrgb8888_case *params = test->param_value;
384         const struct convert_to_rgb565_result *result = &params->rgb565_result;
385         size_t dst_size;
386         u16 *buf = NULL;
387         __le32 *xrgb8888 = NULL;
388         struct iosys_map dst, src;
389
390         struct drm_framebuffer fb = {
391                 .format = drm_format_info(DRM_FORMAT_XRGB8888),
392                 .pitches = { params->pitch, 0, 0 },
393         };
394
395         dst_size = conversion_buf_size(DRM_FORMAT_RGB565, result->dst_pitch,
396                                        &params->clip);
397         KUNIT_ASSERT_GT(test, dst_size, 0);
398
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);
402
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);
406
407         drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->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);
410
411         buf = dst.vaddr; /* restore original value of buf */
412         drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, &params->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);
415 }
416
417 static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
418 {
419         const struct convert_xrgb8888_case *params = test->param_value;
420         const struct convert_to_rgb888_result *result = &params->rgb888_result;
421         size_t dst_size;
422         __u8 *buf = NULL;
423         __le32 *xrgb8888 = NULL;
424         struct iosys_map dst, src;
425
426         struct drm_framebuffer fb = {
427                 .format = drm_format_info(DRM_FORMAT_XRGB8888),
428                 .pitches = { params->pitch, 0, 0 },
429         };
430
431         dst_size = conversion_buf_size(DRM_FORMAT_RGB888, result->dst_pitch,
432                                        &params->clip);
433         KUNIT_ASSERT_GT(test, dst_size, 0);
434
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);
438
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);
442
443         /*
444          * RGB888 expected results are already in little-endian
445          * order, so there's no need to convert the test output.
446          */
447         drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, &params->clip);
448         KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
449 }
450
451 static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
452 {
453         const struct convert_xrgb8888_case *params = test->param_value;
454         const struct convert_to_xrgb2101010_result *result = &params->xrgb2101010_result;
455         size_t dst_size;
456         __u32 *buf = NULL;
457         __le32 *xrgb8888 = NULL;
458         struct iosys_map dst, src;
459
460         struct drm_framebuffer fb = {
461                 .format = drm_format_info(DRM_FORMAT_XRGB8888),
462                 .pitches = { params->pitch, 0, 0 },
463         };
464
465         dst_size = conversion_buf_size(DRM_FORMAT_XRGB2101010,
466                                        result->dst_pitch, &params->clip);
467         KUNIT_ASSERT_GT(test, dst_size, 0);
468
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);
472
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);
476
477         drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, &params->clip);
478         buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32));
479         KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
480 }
481
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),
488         {}
489 };
490
491 static struct kunit_suite drm_format_helper_test_suite = {
492         .name = "drm_format_helper_test",
493         .test_cases = drm_format_helper_test_cases,
494 };
495
496 kunit_test_suite(drm_format_helper_test_suite);
497
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>");