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_rgb332_result { 20 unsigned int dst_pitch; 21 const u8 expected[TEST_BUF_SIZE]; 22 }; 23 24 struct convert_to_rgb565_result { 25 unsigned int dst_pitch; 26 const u16 expected[TEST_BUF_SIZE]; 27 const u16 expected_swab[TEST_BUF_SIZE]; 28 }; 29 30 struct convert_xrgb8888_case { 31 const char *name; 32 unsigned int pitch; 33 struct drm_rect clip; 34 const u32 xrgb8888[TEST_BUF_SIZE]; 35 struct convert_to_rgb332_result rgb332_result; 36 struct convert_to_rgb565_result rgb565_result; 37 }; 38 39 static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 40 { 41 .name = "single_pixel_source_buffer", 42 .pitch = 1 * 4, 43 .clip = DRM_RECT_INIT(0, 0, 1, 1), 44 .xrgb8888 = { 0x01FF0000 }, 45 .rgb332_result = { 46 .dst_pitch = 0, 47 .expected = { 0xE0 }, 48 }, 49 .rgb565_result = { 50 .dst_pitch = 0, 51 .expected = { 0xF800 }, 52 .expected_swab = { 0x00F8 }, 53 }, 54 }, 55 { 56 .name = "single_pixel_clip_rectangle", 57 .pitch = 2 * 4, 58 .clip = DRM_RECT_INIT(1, 1, 1, 1), 59 .xrgb8888 = { 60 0x00000000, 0x00000000, 61 0x00000000, 0x10FF0000, 62 }, 63 .rgb332_result = { 64 .dst_pitch = 0, 65 .expected = { 0xE0 }, 66 }, 67 .rgb565_result = { 68 .dst_pitch = 0, 69 .expected = { 0xF800 }, 70 .expected_swab = { 0x00F8 }, 71 }, 72 }, 73 { 74 /* Well known colors: White, black, red, green, blue, magenta, 75 * yellow and cyan. Different values for the X in XRGB8888 to 76 * make sure it is ignored. Partial clip area. 77 */ 78 .name = "well_known_colors", 79 .pitch = 4 * 4, 80 .clip = DRM_RECT_INIT(1, 1, 2, 4), 81 .xrgb8888 = { 82 0x00000000, 0x00000000, 0x00000000, 0x00000000, 83 0x00000000, 0x11FFFFFF, 0x22000000, 0x00000000, 84 0x00000000, 0x33FF0000, 0x4400FF00, 0x00000000, 85 0x00000000, 0x550000FF, 0x66FF00FF, 0x00000000, 86 0x00000000, 0x77FFFF00, 0x8800FFFF, 0x00000000, 87 }, 88 .rgb332_result = { 89 .dst_pitch = 0, 90 .expected = { 91 0xFF, 0x00, 92 0xE0, 0x1C, 93 0x03, 0xE3, 94 0xFC, 0x1F, 95 }, 96 }, 97 .rgb565_result = { 98 .dst_pitch = 0, 99 .expected = { 100 0xFFFF, 0x0000, 101 0xF800, 0x07E0, 102 0x001F, 0xF81F, 103 0xFFE0, 0x07FF, 104 }, 105 .expected_swab = { 106 0xFFFF, 0x0000, 107 0x00F8, 0xE007, 108 0x1F00, 0x1FF8, 109 0xE0FF, 0xFF07, 110 }, 111 }, 112 }, 113 { 114 /* Randomly picked colors. Full buffer within the clip area. */ 115 .name = "destination_pitch", 116 .pitch = 3 * 4, 117 .clip = DRM_RECT_INIT(0, 0, 3, 3), 118 .xrgb8888 = { 119 0xA10E449C, 0xB1114D05, 0xC1A80303, 120 0xD16C7073, 0xA20E449C, 0xB2114D05, 121 0xC2A80303, 0xD26C7073, 0xA30E449C, 122 }, 123 .rgb332_result = { 124 .dst_pitch = 5, 125 .expected = { 126 0x0A, 0x08, 0xA0, 0x00, 0x00, 127 0x6D, 0x0A, 0x08, 0x00, 0x00, 128 0xA0, 0x6D, 0x0A, 0x00, 0x00, 129 }, 130 }, 131 .rgb565_result = { 132 .dst_pitch = 10, 133 .expected = { 134 0x0A33, 0x1260, 0xA800, 0x0000, 0x0000, 135 0x6B8E, 0x0A33, 0x1260, 0x0000, 0x0000, 136 0xA800, 0x6B8E, 0x0A33, 0x0000, 0x0000, 137 }, 138 .expected_swab = { 139 0x330A, 0x6012, 0x00A8, 0x0000, 0x0000, 140 0x8E6B, 0x330A, 0x6012, 0x0000, 0x0000, 141 0x00A8, 0x8E6B, 0x330A, 0x0000, 0x0000, 142 }, 143 }, 144 }, 145 }; 146 147 /* 148 * conversion_buf_size - Return the destination buffer size required to convert 149 * between formats. 150 * @dst_format: destination buffer pixel format (DRM_FORMAT_*) 151 * @dst_pitch: Number of bytes between two consecutive scanlines within dst 152 * @clip: Clip rectangle area to convert 153 * 154 * Returns: 155 * The size of the destination buffer or negative value on error. 156 */ 157 static size_t conversion_buf_size(u32 dst_format, unsigned int dst_pitch, 158 const struct drm_rect *clip) 159 { 160 const struct drm_format_info *dst_fi = drm_format_info(dst_format); 161 162 if (!dst_fi) 163 return -EINVAL; 164 165 if (!dst_pitch) 166 dst_pitch = drm_rect_width(clip) * dst_fi->cpp[0]; 167 168 return dst_pitch * drm_rect_height(clip); 169 } 170 171 static u32 *le32buf_to_cpu(struct kunit *test, const u32 *buf, size_t buf_size) 172 { 173 u32 *dst = NULL; 174 int n; 175 176 dst = kunit_kzalloc(test, sizeof(*dst) * buf_size, GFP_KERNEL); 177 if (!dst) 178 return NULL; 179 180 for (n = 0; n < buf_size; n++) 181 dst[n] = le32_to_cpu((__force __le32)buf[n]); 182 183 return dst; 184 } 185 186 static void convert_xrgb8888_case_desc(struct convert_xrgb8888_case *t, 187 char *desc) 188 { 189 strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 190 } 191 192 KUNIT_ARRAY_PARAM(convert_xrgb8888, convert_xrgb8888_cases, 193 convert_xrgb8888_case_desc); 194 195 static void xrgb8888_to_rgb332_test(struct kunit *test) 196 { 197 const struct convert_xrgb8888_case *params = test->param_value; 198 const struct convert_to_rgb332_result *result = ¶ms->rgb332_result; 199 size_t dst_size; 200 __u8 *buf = NULL; 201 __u32 *xrgb8888 = NULL; 202 struct iosys_map dst, src; 203 204 struct drm_framebuffer fb = { 205 .format = drm_format_info(DRM_FORMAT_XRGB8888), 206 .pitches = { params->pitch, 0, 0 }, 207 }; 208 209 dst_size = conversion_buf_size(DRM_FORMAT_RGB332, result->dst_pitch, 210 ¶ms->clip); 211 KUNIT_ASSERT_GT(test, dst_size, 0); 212 213 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); 214 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); 215 iosys_map_set_vaddr(&dst, buf); 216 217 xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); 218 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); 219 iosys_map_set_vaddr(&src, xrgb8888); 220 221 drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip); 222 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); 223 } 224 225 static void xrgb8888_to_rgb565_test(struct kunit *test) 226 { 227 const struct convert_xrgb8888_case *params = test->param_value; 228 const struct convert_to_rgb565_result *result = ¶ms->rgb565_result; 229 size_t dst_size; 230 __u16 *buf = NULL; 231 __u32 *xrgb8888 = NULL; 232 struct iosys_map dst, src; 233 234 struct drm_framebuffer fb = { 235 .format = drm_format_info(DRM_FORMAT_XRGB8888), 236 .pitches = { params->pitch, 0, 0 }, 237 }; 238 239 dst_size = conversion_buf_size(DRM_FORMAT_RGB565, result->dst_pitch, 240 ¶ms->clip); 241 KUNIT_ASSERT_GT(test, dst_size, 0); 242 243 buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); 244 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); 245 iosys_map_set_vaddr(&dst, buf); 246 247 xrgb8888 = le32buf_to_cpu(test, params->xrgb8888, TEST_BUF_SIZE); 248 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); 249 iosys_map_set_vaddr(&src, xrgb8888); 250 251 drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, false); 252 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0); 253 254 drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true); 255 KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0); 256 } 257 258 static struct kunit_case drm_format_helper_test_cases[] = { 259 KUNIT_CASE_PARAM(xrgb8888_to_rgb332_test, convert_xrgb8888_gen_params), 260 KUNIT_CASE_PARAM(xrgb8888_to_rgb565_test, convert_xrgb8888_gen_params), 261 {} 262 }; 263 264 static struct kunit_suite drm_format_helper_test_suite = { 265 .name = "drm_format_helper_test", 266 .test_cases = drm_format_helper_test_cases, 267 }; 268 269 kunit_test_suite(drm_format_helper_test_suite); 270 271 MODULE_DESCRIPTION("KUnit tests for the drm_format_helper APIs"); 272 MODULE_LICENSE("GPL"); 273 MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>"); 274