1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2014 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7 #include <bzlib.h>
8 #include <dm.h>
9 #include <gzip.h>
10 #include <log.h>
11 #include <malloc.h>
12 #include <mapmem.h>
13 #include <os.h>
14 #include <video.h>
15 #include <video_console.h>
16 #include <asm/test.h>
17 #include <asm/sdl.h>
18 #include <dm/test.h>
19 #include <dm/uclass-internal.h>
20 #include <test/lib.h>
21 #include <test/test.h>
22 #include <test/ut.h>
23 #include <test/video.h>
24
25 /*
26 * These tests use the standard sandbox frame buffer, the resolution of which
27 * is defined in the device tree. This only supports 16bpp so the tests only
28 * test that code path. It would be possible to adjust this fairly easily,
29 * by adjusting the bpix value in struct sandbox_sdl_plat. However the code
30 * in sandbox_sdl_sync() would also need to change to handle the different
31 * surface depth.
32 */
33 /* Basic test of the video uclass */
dm_test_video_base(struct unit_test_state * uts)34 static int dm_test_video_base(struct unit_test_state *uts)
35 {
36 struct video_priv *priv;
37 struct udevice *dev;
38
39 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
40 ut_asserteq(1366, video_get_xsize(dev));
41 ut_asserteq(768, video_get_ysize(dev));
42 priv = dev_get_uclass_priv(dev);
43 ut_asserteq(priv->fb_size, 1366 * 768 * 2);
44
45 return 0;
46 }
47 DM_TEST(dm_test_video_base, UTF_SCAN_PDATA | UTF_SCAN_FDT);
48
video_compress_fb(struct unit_test_state * uts,struct udevice * dev,bool use_copy)49 int video_compress_fb(struct unit_test_state *uts, struct udevice *dev,
50 bool use_copy)
51 {
52 struct video_priv *priv = dev_get_uclass_priv(dev);
53 uint destlen;
54 void *dest;
55 int ret;
56
57 if (!IS_ENABLED(CONFIG_VIDEO_COPY))
58 use_copy = false;
59
60 destlen = priv->fb_size;
61 dest = malloc(priv->fb_size);
62 if (!dest)
63 return -ENOMEM;
64 ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
65 use_copy ? priv->copy_fb : priv->fb,
66 priv->fb_size,
67 3, 0, 0);
68 free(dest);
69 if (ret)
70 return ret;
71
72 return destlen;
73 }
74
video_check_copy_fb(struct unit_test_state * uts,struct udevice * dev)75 int video_check_copy_fb(struct unit_test_state *uts, struct udevice *dev)
76 {
77 struct video_priv *priv = dev_get_uclass_priv(dev);
78
79 if (!IS_ENABLED(CONFIG_VIDEO_COPY))
80 return 0;
81
82 video_sync(dev, false);
83 ut_assertf(!memcmp(priv->fb, priv->copy_fb, priv->fb_size),
84 "Copy framebuffer does not match fb");
85
86 return 0;
87 }
88
89 /*
90 * Call this function at any point to halt and show the current display. Be
91 * sure to run the test with the -l flag.
92 */
see_output(void)93 static void __maybe_unused see_output(void)
94 {
95 video_sync_all();
96 while (1);
97 }
98
99 /* Select the video console driver to use for a video device */
select_vidconsole(struct unit_test_state * uts,const char * drv_name)100 static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
101 {
102 struct sandbox_sdl_plat *plat;
103 struct udevice *dev;
104
105 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
106 ut_assert(!device_active(dev));
107 plat = dev_get_plat(dev);
108 plat->vidconsole_drv_name = "vidconsole0";
109
110 return 0;
111 }
112
113 /**
114 * video_get_nologo() - Disable the logo on the video device and return it
115 *
116 * @uts: Test state
117 * @devp: Returns video device
118 * Return: 0 if OK, -ve on error
119 */
video_get_nologo(struct unit_test_state * uts,struct udevice ** devp)120 static int video_get_nologo(struct unit_test_state *uts, struct udevice **devp)
121 {
122 struct video_uc_plat *uc_plat;
123 struct udevice *dev;
124
125 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
126 ut_assertnonnull(dev);
127 uc_plat = dev_get_uclass_plat(dev);
128 uc_plat->hide_logo = true;
129
130 /* now probe it */
131 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
132 ut_assertnonnull(dev);
133 *devp = dev;
134
135 return 0;
136 }
137
138 /* Test text output works on the video console */
dm_test_video_text(struct unit_test_state * uts)139 static int dm_test_video_text(struct unit_test_state *uts)
140 {
141 struct udevice *dev, *con;
142 int i;
143
144 #define WHITE 0xffff
145 #define SCROLL_LINES 100
146
147 ut_assertok(select_vidconsole(uts, "vidconsole0"));
148 ut_assertok(video_get_nologo(uts, &dev));
149 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
150 ut_assertok(vidconsole_select_font(con, "8x16", 0));
151 ut_asserteq(46, video_compress_fb(uts, dev, false));
152 ut_assertok(video_check_copy_fb(uts, dev));
153
154 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
155 vidconsole_putc_xy(con, 0, 0, 'a');
156 ut_asserteq(79, video_compress_fb(uts, dev, false));
157 ut_assertok(video_check_copy_fb(uts, dev));
158
159 vidconsole_putc_xy(con, 0, 0, ' ');
160 ut_asserteq(46, video_compress_fb(uts, dev, false));
161 ut_assertok(video_check_copy_fb(uts, dev));
162
163 for (i = 0; i < 20; i++)
164 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
165 ut_asserteq(273, video_compress_fb(uts, dev, false));
166 ut_assertok(video_check_copy_fb(uts, dev));
167
168 vidconsole_set_row(con, 0, WHITE);
169 ut_asserteq(46, video_compress_fb(uts, dev, false));
170 ut_assertok(video_check_copy_fb(uts, dev));
171
172 for (i = 0; i < 20; i++)
173 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
174 ut_asserteq(273, video_compress_fb(uts, dev, false));
175 ut_assertok(video_check_copy_fb(uts, dev));
176
177 return 0;
178 }
179 DM_TEST(dm_test_video_text, UTF_SCAN_PDATA | UTF_SCAN_FDT);
180
dm_test_video_text_12x22(struct unit_test_state * uts)181 static int dm_test_video_text_12x22(struct unit_test_state *uts)
182 {
183 struct udevice *dev, *con;
184 int i;
185
186 #define WHITE 0xffff
187 #define SCROLL_LINES 100
188
189 ut_assertok(select_vidconsole(uts, "vidconsole0"));
190 ut_assertok(video_get_nologo(uts, &dev));
191 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
192 ut_assertok(vidconsole_select_font(con, "12x22", 0));
193 ut_asserteq(46, video_compress_fb(uts, dev, false));
194 ut_assertok(video_check_copy_fb(uts, dev));
195
196 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
197 vidconsole_putc_xy(con, 0, 0, 'a');
198 ut_asserteq(89, video_compress_fb(uts, dev, false));
199 ut_assertok(video_check_copy_fb(uts, dev));
200
201 vidconsole_putc_xy(con, 0, 0, ' ');
202 ut_asserteq(46, video_compress_fb(uts, dev, false));
203 ut_assertok(video_check_copy_fb(uts, dev));
204
205 for (i = 0; i < 20; i++)
206 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
207 ut_asserteq(363, video_compress_fb(uts, dev, false));
208 ut_assertok(video_check_copy_fb(uts, dev));
209
210 vidconsole_set_row(con, 0, WHITE);
211 ut_asserteq(46, video_compress_fb(uts, dev, false));
212 ut_assertok(video_check_copy_fb(uts, dev));
213
214 for (i = 0; i < 20; i++)
215 vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
216 ut_asserteq(363, video_compress_fb(uts, dev, false));
217 ut_assertok(video_check_copy_fb(uts, dev));
218
219 return 0;
220 }
221 DM_TEST(dm_test_video_text_12x22, UTF_SCAN_PDATA | UTF_SCAN_FDT);
222
223 /* Test handling of special characters in the console */
dm_test_video_chars(struct unit_test_state * uts)224 static int dm_test_video_chars(struct unit_test_state *uts)
225 {
226 struct udevice *dev, *con;
227 const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very \amodest \bman\n\t\tand Has much to\b\bto be modest about.";
228
229 ut_assertok(select_vidconsole(uts, "vidconsole0"));
230 ut_assertok(video_get_nologo(uts, &dev));
231 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
232 ut_assertok(vidconsole_select_font(con, "8x16", 0));
233 vidconsole_put_string(con, test_string);
234 ut_asserteq(466, video_compress_fb(uts, dev, false));
235 ut_assertok(video_check_copy_fb(uts, dev));
236
237 return 0;
238 }
239 DM_TEST(dm_test_video_chars, UTF_SCAN_PDATA | UTF_SCAN_FDT);
240
241 #ifdef CONFIG_VIDEO_ANSI
242 #define ANSI_ESC "\x1b"
243 /* Test handling of ANSI escape sequences */
dm_test_video_ansi(struct unit_test_state * uts)244 static int dm_test_video_ansi(struct unit_test_state *uts)
245 {
246 struct udevice *dev, *con;
247
248 ut_assertok(select_vidconsole(uts, "vidconsole0"));
249 ut_assertok(video_get_nologo(uts, &dev));
250 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
251 ut_assertok(vidconsole_select_font(con, "8x16", 0));
252
253 /* reference clear: */
254 video_clear(con->parent);
255 video_sync(con->parent, false);
256 ut_asserteq(46, video_compress_fb(uts, dev, false));
257 ut_assertok(video_check_copy_fb(uts, dev));
258
259 /* test clear escape sequence: [2J */
260 vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
261 ut_asserteq(46, video_compress_fb(uts, dev, false));
262 ut_assertok(video_check_copy_fb(uts, dev));
263
264 /* test set-cursor: [%d;%df */
265 vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
266 ut_asserteq(143, video_compress_fb(uts, dev, false));
267 ut_assertok(video_check_copy_fb(uts, dev));
268
269 /* test colors (30-37 fg color, 40-47 bg color) */
270 vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
271 vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
272 ut_asserteq(272, video_compress_fb(uts, dev, false));
273 ut_assertok(video_check_copy_fb(uts, dev));
274
275 return 0;
276 }
277 DM_TEST(dm_test_video_ansi, UTF_SCAN_PDATA | UTF_SCAN_FDT);
278 #endif
279
280 /**
281 * check_vidconsole_output() - Run a text console test
282 *
283 * @uts: Test state
284 * @rot: Console rotation (0=normal orientation, 1=90 degrees clockwise,
285 * 2=upside down, 3=90 degree counterclockwise)
286 * @wrap_size: Expected size of compressed frame buffer for the wrap test
287 * @scroll_size: Same for the scroll test
288 * Return: 0 on success
289 */
check_vidconsole_output(struct unit_test_state * uts,int rot,int wrap_size,int scroll_size)290 static int check_vidconsole_output(struct unit_test_state *uts, int rot,
291 int wrap_size, int scroll_size)
292 {
293 struct udevice *dev, *con;
294 struct sandbox_sdl_plat *plat;
295 int i;
296
297 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
298 ut_assert(!device_active(dev));
299 plat = dev_get_plat(dev);
300 plat->rot = rot;
301
302 ut_assertok(video_get_nologo(uts, &dev));
303 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
304 ut_assertok(vidconsole_select_font(con, "8x16", 0));
305 ut_asserteq(46, video_compress_fb(uts, dev, false));
306 ut_assertok(video_check_copy_fb(uts, dev));
307
308 /* Check display wrap */
309 for (i = 0; i < 120; i++)
310 vidconsole_put_char(con, 'A' + i % 50);
311 ut_asserteq(wrap_size, video_compress_fb(uts, dev, false));
312 ut_assertok(video_check_copy_fb(uts, dev));
313
314 /* Check display scrolling */
315 for (i = 0; i < SCROLL_LINES; i++) {
316 vidconsole_put_char(con, 'A' + i % 50);
317 vidconsole_put_char(con, '\n');
318 }
319 ut_asserteq(scroll_size, video_compress_fb(uts, dev, false));
320 ut_assertok(video_check_copy_fb(uts, dev));
321
322 /* If we scroll enough, the screen becomes blank again */
323 for (i = 0; i < SCROLL_LINES; i++)
324 vidconsole_put_char(con, '\n');
325 ut_asserteq(46, video_compress_fb(uts, dev, false));
326 ut_assertok(video_check_copy_fb(uts, dev));
327
328 return 0;
329 }
330
331 /* Test text output through the console uclass */
dm_test_video_context(struct unit_test_state * uts)332 static int dm_test_video_context(struct unit_test_state *uts)
333 {
334 ut_assertok(select_vidconsole(uts, "vidconsole0"));
335 ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
336
337 return 0;
338 }
339 DM_TEST(dm_test_video_context, UTF_SCAN_PDATA | UTF_SCAN_FDT);
340
341 /* Test rotated text output through the console uclass */
dm_test_video_rotation1(struct unit_test_state * uts)342 static int dm_test_video_rotation1(struct unit_test_state *uts)
343 {
344 ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
345
346 return 0;
347 }
348 DM_TEST(dm_test_video_rotation1, UTF_SCAN_PDATA | UTF_SCAN_FDT);
349
350 /* Test rotated text output through the console uclass */
dm_test_video_rotation2(struct unit_test_state * uts)351 static int dm_test_video_rotation2(struct unit_test_state *uts)
352 {
353 ut_assertok(check_vidconsole_output(uts, 2, 783, 445));
354
355 return 0;
356 }
357 DM_TEST(dm_test_video_rotation2, UTF_SCAN_PDATA | UTF_SCAN_FDT);
358
359 /* Test rotated text output through the console uclass */
dm_test_video_rotation3(struct unit_test_state * uts)360 static int dm_test_video_rotation3(struct unit_test_state *uts)
361 {
362 ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
363
364 return 0;
365 }
366 DM_TEST(dm_test_video_rotation3, UTF_SCAN_PDATA | UTF_SCAN_FDT);
367
368 /* Read a file into memory and return a pointer to it */
read_file(struct unit_test_state * uts,const char * fname,ulong * addrp)369 static int read_file(struct unit_test_state *uts, const char *fname,
370 ulong *addrp)
371 {
372 int buf_size = 100000;
373 ulong addr = 0;
374 int size, fd;
375 char *buf;
376
377 buf = map_sysmem(addr, 0);
378 ut_assert(buf != NULL);
379 fd = os_open(fname, OS_O_RDONLY);
380 ut_assert(fd >= 0);
381 size = os_read(fd, buf, buf_size);
382 os_close(fd);
383 ut_assert(size >= 0);
384 ut_assert(size < buf_size);
385 *addrp = addr;
386
387 return 0;
388 }
389
390 /* Test drawing a bitmap file */
dm_test_video_bmp(struct unit_test_state * uts)391 static int dm_test_video_bmp(struct unit_test_state *uts)
392 {
393 struct udevice *dev;
394 ulong addr;
395
396 ut_assertok(video_get_nologo(uts, &dev));
397 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
398
399 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
400 ut_asserteq(1368, video_compress_fb(uts, dev, false));
401 ut_assertok(video_check_copy_fb(uts, dev));
402
403 return 0;
404 }
405 DM_TEST(dm_test_video_bmp, UTF_SCAN_PDATA | UTF_SCAN_FDT);
406
407 /* Test drawing a bitmap file on a 8bpp display */
dm_test_video_bmp8(struct unit_test_state * uts)408 static int dm_test_video_bmp8(struct unit_test_state *uts)
409 {
410 struct udevice *dev;
411 ulong addr;
412
413 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
414 ut_assertnonnull(dev);
415 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
416
417 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
418
419 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
420 ut_asserteq(1247, video_compress_fb(uts, dev, false));
421 ut_assertok(video_check_copy_fb(uts, dev));
422
423 return 0;
424 }
425 DM_TEST(dm_test_video_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT);
426
427 /* Test drawing a bitmap file on a 16bpp display */
dm_test_video_bmp16(struct unit_test_state * uts)428 static int dm_test_video_bmp16(struct unit_test_state *uts)
429 {
430 ulong src, src_len = ~0UL;
431 uint dst_len = ~0U;
432 struct udevice *dev;
433 ulong dst = 0x10000;
434
435 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
436 ut_assertnonnull(dev);
437 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
438
439 ut_assertok(read_file(uts, "tools/logos/denx-16bpp.bmp.gz", &src));
440 ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
441 &src_len));
442
443 ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
444 ut_asserteq(3700, video_compress_fb(uts, dev, false));
445 ut_assertok(video_check_copy_fb(uts, dev));
446
447 return 0;
448 }
449 DM_TEST(dm_test_video_bmp16, UTF_SCAN_PDATA | UTF_SCAN_FDT);
450
451 /* Test drawing a 24bpp bitmap file on a 16bpp display */
dm_test_video_bmp24(struct unit_test_state * uts)452 static int dm_test_video_bmp24(struct unit_test_state *uts)
453 {
454 ulong src, src_len = ~0UL;
455 uint dst_len = ~0U;
456 struct udevice *dev;
457 ulong dst = 0x10000;
458
459 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
460 ut_assertnonnull(dev);
461 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
462
463 ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
464 ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
465 &src_len));
466
467 ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
468 ut_asserteq(3656, video_compress_fb(uts, dev, false));
469 ut_assertok(video_check_copy_fb(uts, dev));
470
471 return 0;
472 }
473 DM_TEST(dm_test_video_bmp24, UTF_SCAN_PDATA | UTF_SCAN_FDT);
474
475 /* Test drawing a 24bpp bitmap file on a 32bpp display */
dm_test_video_bmp24_32(struct unit_test_state * uts)476 static int dm_test_video_bmp24_32(struct unit_test_state *uts)
477 {
478 ulong src, src_len = ~0UL;
479 uint dst_len = ~0U;
480 struct udevice *dev;
481 ulong dst = 0x10000;
482
483 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
484 ut_assertnonnull(dev);
485 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
486
487 ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
488 ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
489 &src_len));
490
491 ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
492 ut_asserteq(6827, video_compress_fb(uts, dev, false));
493 ut_assertok(video_check_copy_fb(uts, dev));
494
495 return 0;
496 }
497 DM_TEST(dm_test_video_bmp24_32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
498
499 /* Test drawing a bitmap file on a 32bpp display */
dm_test_video_bmp32(struct unit_test_state * uts)500 static int dm_test_video_bmp32(struct unit_test_state *uts)
501 {
502 struct udevice *dev;
503 ulong addr;
504
505 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
506 ut_assertnonnull(dev);
507 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
508 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
509
510 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
511 ut_asserteq(2024, video_compress_fb(uts, dev, false));
512 ut_assertok(video_check_copy_fb(uts, dev));
513
514 return 0;
515 }
516 DM_TEST(dm_test_video_bmp32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
517
518 /* Test drawing a compressed bitmap file */
dm_test_video_bmp_comp(struct unit_test_state * uts)519 static int dm_test_video_bmp_comp(struct unit_test_state *uts)
520 {
521 struct udevice *dev;
522 ulong addr;
523
524 ut_assertok(video_get_nologo(uts, &dev));
525 ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
526
527 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
528 ut_asserteq(1368, video_compress_fb(uts, dev, false));
529 ut_assertok(video_check_copy_fb(uts, dev));
530
531 return 0;
532 }
533 DM_TEST(dm_test_video_bmp_comp, UTF_SCAN_PDATA | UTF_SCAN_FDT);
534
535 /* Test drawing a bitmap file on a 32bpp display */
dm_test_video_comp_bmp32(struct unit_test_state * uts)536 static int dm_test_video_comp_bmp32(struct unit_test_state *uts)
537 {
538 struct udevice *dev;
539 ulong addr;
540
541 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
542 ut_assertnonnull(dev);
543 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
544
545 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
546
547 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
548 ut_asserteq(2024, video_compress_fb(uts, dev, false));
549 ut_assertok(video_check_copy_fb(uts, dev));
550
551 return 0;
552 }
553 DM_TEST(dm_test_video_comp_bmp32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
554
555 /* Test drawing a bitmap file on a 8bpp display */
dm_test_video_comp_bmp8(struct unit_test_state * uts)556 static int dm_test_video_comp_bmp8(struct unit_test_state *uts)
557 {
558 struct udevice *dev;
559 ulong addr;
560
561 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
562 ut_assertnonnull(dev);
563 ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
564
565 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
566
567 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
568 ut_asserteq(1247, video_compress_fb(uts, dev, false));
569 ut_assertok(video_check_copy_fb(uts, dev));
570
571 return 0;
572 }
573 DM_TEST(dm_test_video_comp_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT);
574
575 /* Test TrueType console */
dm_test_video_truetype(struct unit_test_state * uts)576 static int dm_test_video_truetype(struct unit_test_state *uts)
577 {
578 struct udevice *dev, *con;
579 const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
580
581 ut_assertok(video_get_nologo(uts, &dev));
582 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
583 vidconsole_put_string(con, test_string);
584 vidconsole_put_stringn(con, test_string, 30);
585 ut_asserteq(13184, video_compress_fb(uts, dev, false));
586 ut_assertok(video_check_copy_fb(uts, dev));
587
588 return 0;
589 }
590 DM_TEST(dm_test_video_truetype, UTF_SCAN_PDATA | UTF_SCAN_FDT);
591
592 /* Test scrolling TrueType console */
dm_test_video_truetype_scroll(struct unit_test_state * uts)593 static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
594 {
595 struct sandbox_sdl_plat *plat;
596 struct udevice *dev, *con;
597 const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye";
598
599 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
600 ut_assert(!device_active(dev));
601 plat = dev_get_plat(dev);
602 plat->font_size = 100;
603
604 ut_assertok(video_get_nologo(uts, &dev));
605 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
606 vidconsole_put_string(con, test_string);
607 ut_asserteq(34287, video_compress_fb(uts, dev, false));
608 ut_assertok(video_check_copy_fb(uts, dev));
609
610 return 0;
611 }
612 DM_TEST(dm_test_video_truetype_scroll, UTF_SCAN_PDATA | UTF_SCAN_FDT);
613
614 /* Test TrueType backspace, within and across lines */
dm_test_video_truetype_bs(struct unit_test_state * uts)615 static int dm_test_video_truetype_bs(struct unit_test_state *uts)
616 {
617 struct sandbox_sdl_plat *plat;
618 struct udevice *dev, *con;
619 const char *test_string = "...Criticism may or may\b\b\b\b\b\bnot be agreeable, but seldom it is necessary\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bit is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things.";
620
621 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
622 ut_assert(!device_active(dev));
623 plat = dev_get_plat(dev);
624 plat->font_size = 100;
625
626 ut_assertok(video_get_nologo(uts, &dev));
627 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
628 vidconsole_put_string(con, test_string);
629 ut_asserteq(29471, video_compress_fb(uts, dev, false));
630 ut_assertok(video_check_copy_fb(uts, dev));
631
632 return 0;
633 }
634 DM_TEST(dm_test_video_truetype_bs, UTF_SCAN_PDATA | UTF_SCAN_FDT);
635
636 /* Test partial rendering onto hardware frame buffer */
dm_test_video_copy(struct unit_test_state * uts)637 static int dm_test_video_copy(struct unit_test_state *uts)
638 {
639 struct sandbox_sdl_plat *plat;
640 struct video_uc_plat *uc_plat;
641 struct udevice *dev, *con;
642 struct video_priv *priv;
643 const char *test_string = "\n\tCriticism may not be agreeable, but it is necessary.\t";
644 ulong addr;
645
646 if (!IS_ENABLED(CONFIG_VIDEO_COPY))
647 return -EAGAIN;
648
649 ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
650 ut_assertnonnull(dev);
651 uc_plat = dev_get_uclass_plat(dev);
652 uc_plat->hide_logo = true;
653 plat = dev_get_plat(dev);
654 plat->font_size = 32;
655 ut_assert(!device_active(dev));
656 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
657 ut_assertnonnull(dev);
658 priv = dev_get_uclass_priv(dev);
659
660 ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
661 ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
662
663 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
664 vidconsole_put_string(con, "\n\n\n\n\n");
665 vidconsole_put_string(con, test_string);
666 vidconsole_put_string(con, test_string);
667
668 ut_asserteq(6678, video_compress_fb(uts, dev, false));
669 ut_assertok(video_check_copy_fb(uts, dev));
670
671 /*
672 * Secretly clear the hardware frame buffer, but in a different
673 * color (black) to see which parts will be overwritten.
674 */
675 memset(priv->copy_fb, 0, priv->fb_size);
676
677 /*
678 * We should have the full content on the main buffer, but only
679 * 'damage' should have been copied to the copy buffer. This consists
680 * of a while rectangle with the Denx logo and four lines of text. The
681 * rest of the display is black.
682 *
683 * An easy way to try this is by changing video_sync() to call
684 * sandbox_sdl_sync(priv->copy_fb) instead of priv->fb then running the
685 * unit test:
686 *
687 * ./u-boot -Tl
688 * ut dm dm_test_video_copy
689 */
690 vidconsole_put_string(con, test_string);
691 vidconsole_put_string(con, test_string);
692 video_sync(dev, true);
693 ut_asserteq(7589, video_compress_fb(uts, dev, false));
694 ut_asserteq(7704, video_compress_fb(uts, dev, true));
695
696 return 0;
697 }
698 DM_TEST(dm_test_video_copy, UTF_SCAN_PDATA | UTF_SCAN_FDT);
699
700 /* Test video damage tracking */
dm_test_video_damage(struct unit_test_state * uts)701 static int dm_test_video_damage(struct unit_test_state *uts)
702 {
703 struct sandbox_sdl_plat *plat;
704 struct udevice *dev, *con;
705 struct video_priv *priv;
706 const char *test_string_1 = "Criticism may not be agreeable, ";
707 const char *test_string_2 = "but it is necessary.";
708 const char *test_string_3 = "It fulfils the same function as pain in the human body.";
709
710 if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE))
711 return -EAGAIN;
712
713 ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
714 ut_assert(!device_active(dev));
715 plat = dev_get_plat(dev);
716 plat->font_size = 32;
717
718 ut_assertok(video_get_nologo(uts, &dev));
719 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
720 priv = dev_get_uclass_priv(dev);
721
722 vidconsole_position_cursor(con, 14, 10);
723 vidconsole_put_string(con, test_string_2);
724 ut_asserteq(449, priv->damage.xstart);
725 ut_asserteq(325, priv->damage.ystart);
726 ut_asserteq(661, priv->damage.xend);
727 ut_asserteq(350, priv->damage.yend);
728
729 vidconsole_position_cursor(con, 7, 5);
730 vidconsole_put_string(con, test_string_1);
731 ut_asserteq(225, priv->damage.xstart);
732 ut_asserteq(164, priv->damage.ystart);
733 ut_asserteq(661, priv->damage.xend);
734 ut_asserteq(350, priv->damage.yend);
735
736 vidconsole_position_cursor(con, 21, 15);
737 vidconsole_put_string(con, test_string_3);
738 ut_asserteq(225, priv->damage.xstart);
739 ut_asserteq(164, priv->damage.ystart);
740 ut_asserteq(1280, priv->damage.xend);
741 ut_asserteq(510, priv->damage.yend);
742
743 video_sync(dev, true);
744 ut_asserteq(priv->xsize, priv->damage.xstart);
745 ut_asserteq(priv->ysize, priv->damage.ystart);
746 ut_asserteq(0, priv->damage.xend);
747 ut_asserteq(0, priv->damage.yend);
748
749 ut_asserteq(7339, video_compress_fb(uts, dev, false));
750 ut_assertok(video_check_copy_fb(uts, dev));
751
752 return 0;
753 }
754 DM_TEST(dm_test_video_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT);
755
756 /* Test font measurement */
dm_test_font_measure(struct unit_test_state * uts)757 static int dm_test_font_measure(struct unit_test_state *uts)
758 {
759 const char *test_string = "There is always much\nto be said for not "
760 "attempting more than you can do and for making a certainty of "
761 "what you try. But this principle, like others in life and "
762 "war, has its exceptions.";
763 const struct vidconsole_mline *line;
764 struct vidconsole_bbox bbox;
765 struct video_priv *priv;
766 struct udevice *dev, *con;
767 const int limit = 0x320;
768 struct alist lines;
769 int nl;
770
771 ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
772 priv = dev_get_uclass_priv(dev);
773 ut_asserteq(1366, priv->xsize);
774 ut_asserteq(768, priv->ysize);
775
776 /* this is using the Nimbus font with size of 18 pixels */
777 ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
778 vidconsole_position_cursor(con, 0, 0);
779 alist_init_struct(&lines, struct vidconsole_mline);
780 ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, &bbox,
781 &lines));
782 ut_asserteq(0, bbox.x0);
783 ut_asserteq(0, bbox.y0);
784 ut_asserteq(0x3ea, bbox.x1);
785 ut_asserteq(0x24, bbox.y1);
786 ut_asserteq(2, lines.count);
787
788 nl = strchr(test_string, '\n') - test_string;
789
790 line = alist_get(&lines, 0, struct vidconsole_mline);
791 ut_assertnonnull(line);
792 ut_asserteq(0, line->bbox.x0);
793 ut_asserteq(0, line->bbox.y0);
794 ut_asserteq(0x8c, line->bbox.x1);
795 ut_asserteq(0x12, line->bbox.y1);
796 ut_asserteq(0, line->start);
797 ut_asserteq(20, line->len);
798 ut_asserteq(nl, line->len);
799
800 line++;
801 ut_asserteq(0x0, line->bbox.x0);
802 ut_asserteq(0x12, line->bbox.y0);
803 ut_asserteq(0x3ea, line->bbox.x1);
804 ut_asserteq(0x24, line->bbox.y1);
805 ut_asserteq(21, line->start);
806 ut_asserteq(nl + 1, line->start);
807 ut_asserteq(163, line->len);
808 ut_asserteq(strlen(test_string + nl + 1), line->len);
809
810 /* now use a limit on the width */
811 ut_assertok(vidconsole_measure(con, NULL, 0, test_string, limit, &bbox,
812 &lines));
813 ut_asserteq(0, bbox.x0);
814 ut_asserteq(0, bbox.y0);
815 ut_asserteq(0x31e, bbox.x1);
816 ut_asserteq(0x36, bbox.y1);
817 ut_asserteq(3, lines.count);
818
819 nl = strchr(test_string, '\n') - test_string;
820
821 line = alist_get(&lines, 0, struct vidconsole_mline);
822 ut_assertnonnull(line);
823 ut_asserteq(0, line->bbox.x0);
824 ut_asserteq(0, line->bbox.y0);
825 ut_asserteq(0x8c, line->bbox.x1);
826 ut_asserteq(0x12, line->bbox.y1);
827 ut_asserteq(0, line->start);
828 ut_asserteq(20, line->len);
829 ut_asserteq(nl, line->len);
830 printf("line0 '%.*s'\n", line->len, test_string + line->start);
831 ut_asserteq_strn("There is always much",
832 test_string + line->start);
833
834 line++;
835 ut_asserteq(0x0, line->bbox.x0);
836 ut_asserteq(0x12, line->bbox.y0);
837 ut_asserteq(0x31e, line->bbox.x1);
838 ut_asserteq(0x24, line->bbox.y1);
839 ut_asserteq(21, line->start);
840 ut_asserteq(nl + 1, line->start);
841 ut_asserteq(129, line->len);
842 printf("line1 '%.*s'\n", line->len, test_string + line->start);
843 ut_asserteq_strn("to be said for not attempting more than you can do "
844 "and for making a certainty of what you try. But this "
845 "principle, like others in",
846 test_string + line->start);
847
848 line++;
849 ut_asserteq(0x0, line->bbox.x0);
850 ut_asserteq(0x24, line->bbox.y0);
851 ut_asserteq(0xc8, line->bbox.x1);
852 ut_asserteq(0x36, line->bbox.y1);
853 ut_asserteq(21 + 130, line->start);
854 ut_asserteq(33, line->len);
855 printf("line2 '%.*s'\n", line->len, test_string + line->start);
856 ut_asserteq_strn("life and war, has its exceptions.",
857 test_string + line->start);
858
859 /*
860 * all characters should be accounted for, except the newline and the
861 * space which is consumed in the wordwrap
862 */
863 ut_asserteq(strlen(test_string) - 2,
864 line[-2].len + line[-1].len + line->len);
865
866 return 0;
867 }
868 DM_TEST(dm_test_font_measure, UTF_SCAN_FDT);
869
870 /* Test silencing the video console */
dm_test_video_silence(struct unit_test_state * uts)871 static int dm_test_video_silence(struct unit_test_state *uts)
872 {
873 struct udevice *dev, *con;
874 struct stdio_dev *sdev;
875
876 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
877
878 /*
879 * use the old console device from before when dm_test_pre_run() was
880 * called, since that is what is in stdio / console
881 */
882 sdev = stdio_get_by_name("vidconsole");
883 ut_assertnonnull(sdev);
884 con = sdev->priv;
885 ut_assertok(vidconsole_clear_and_reset(con));
886 ut_unsilence_console(uts);
887
888 printf("message 1: console\n");
889 vidconsole_put_string(con, "message 1: video\n");
890
891 vidconsole_set_quiet(con, true);
892 printf("second message: console\n");
893 vidconsole_put_string(con, "second message: video\n");
894
895 vidconsole_set_quiet(con, false);
896 printf("final message: console\n");
897 vidconsole_put_string(con, "final message: video\n");
898
899 ut_asserteq(3892, video_compress_fb(uts, dev, false));
900 ut_assertok(video_check_copy_fb(uts, dev));
901
902 return 0;
903 }
904 DM_TEST(dm_test_video_silence, UTF_SCAN_FDT);
905
906 /* test drawing a box */
dm_test_video_box(struct unit_test_state * uts)907 static int dm_test_video_box(struct unit_test_state *uts)
908 {
909 struct video_priv *priv;
910 struct udevice *dev;
911
912 ut_assertok(video_get_nologo(uts, &dev));
913 priv = dev_get_uclass_priv(dev);
914 video_draw_box(dev, 100, 100, 200, 200, 3,
915 video_index_to_colour(priv, VID_LIGHT_BLUE));
916 video_draw_box(dev, 300, 100, 400, 200, 1,
917 video_index_to_colour(priv, VID_MAGENTA));
918 video_draw_box(dev, 500, 100, 600, 200, 20,
919 video_index_to_colour(priv, VID_LIGHT_RED));
920 ut_asserteq(133, video_compress_fb(uts, dev, false));
921 ut_assertok(video_check_copy_fb(uts, dev));
922
923 return 0;
924 }
925 DM_TEST(dm_test_video_box, UTF_SCAN_FDT);
926