Add an image which represents a locked disk. Signed-off-by: Simon Glass <simon.glass@canonical.com>
1496 lines
46 KiB
C
1496 lines
46 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2014 Google, Inc
|
|
* Written by Simon Glass <sjg@chromium.org>
|
|
*/
|
|
|
|
#include <bmp_layout.h>
|
|
#include <bzlib.h>
|
|
#include <dm.h>
|
|
#include <gzip.h>
|
|
#include <log.h>
|
|
#include <malloc.h>
|
|
#include <mapmem.h>
|
|
#include <os.h>
|
|
#include <video.h>
|
|
#include <video_console.h>
|
|
#include <asm/test.h>
|
|
#include <asm/sdl.h>
|
|
#include <dm/test.h>
|
|
#include <dm/uclass-internal.h>
|
|
#include <linux/delay.h>
|
|
#include <test/lib.h>
|
|
#include <test/test.h>
|
|
#include <test/ut.h>
|
|
#include <test/video.h>
|
|
|
|
/*
|
|
* These tests use the standard sandbox frame buffer, the resolution of which
|
|
* is defined in the device tree. This only supports 16bpp so the tests only
|
|
* test that code path. It would be possible to adjust this fairly easily,
|
|
* by adjusting the bpix value in struct sandbox_sdl_plat. However the code
|
|
* in sandbox_sdl_sync() would also need to change to handle the different
|
|
* surface depth.
|
|
*/
|
|
/* Basic test of the video uclass */
|
|
static int dm_test_video_base(struct unit_test_state *uts)
|
|
{
|
|
struct video_priv *priv;
|
|
struct udevice *dev;
|
|
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
|
|
ut_asserteq(1366, video_get_xsize(dev));
|
|
ut_asserteq(768, video_get_ysize(dev));
|
|
priv = dev_get_uclass_priv(dev);
|
|
ut_asserteq(priv->fb_size, 1366 * 768 * 2);
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_base, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/**
|
|
* video_write_bmp() - Write framebuffer to BMP file
|
|
*
|
|
* This writes the current framebuffer contents to a BMP file on the host
|
|
* filesystem. Useful for debugging video tests.
|
|
*
|
|
* @uts: Test state
|
|
* @dev: Video device
|
|
* @fname: Filename to write to
|
|
* Return: 0 if OK, -ve on error
|
|
*/
|
|
static int video_write_bmp(struct unit_test_state *uts, struct udevice *dev,
|
|
const char *fname)
|
|
{
|
|
struct video_priv *priv = dev_get_uclass_priv(dev);
|
|
struct bmp_image *bmp;
|
|
u32 width = priv->xsize;
|
|
u32 height = priv->ysize;
|
|
u32 row_bytes, bmp_size, bpp, bytes_per_pixel;
|
|
void *bmp_data;
|
|
int ret, y;
|
|
|
|
/* Support 16bpp (converted to 15bpp for BMP) and 32bpp */
|
|
switch (priv->bpix) {
|
|
case VIDEO_BPP16:
|
|
bpp = 16;
|
|
bytes_per_pixel = 2;
|
|
break;
|
|
case VIDEO_BPP32:
|
|
bpp = 32;
|
|
bytes_per_pixel = 4;
|
|
break;
|
|
default:
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/* BMP rows are padded to 4-byte boundary */
|
|
row_bytes = ALIGN(width * bytes_per_pixel, BMP_DATA_ALIGN);
|
|
bmp_size = sizeof(struct bmp_header) + row_bytes * height;
|
|
|
|
bmp = malloc(bmp_size);
|
|
if (!bmp)
|
|
return -ENOMEM;
|
|
|
|
memset(bmp, 0, bmp_size);
|
|
|
|
/* Fill in BMP header */
|
|
bmp->header.signature[0] = 'B';
|
|
bmp->header.signature[1] = 'M';
|
|
bmp->header.file_size = cpu_to_le32(bmp_size);
|
|
bmp->header.data_offset = cpu_to_le32(sizeof(struct bmp_header));
|
|
bmp->header.size = cpu_to_le32(40);
|
|
bmp->header.width = cpu_to_le32(width);
|
|
bmp->header.height = cpu_to_le32(height);
|
|
bmp->header.planes = cpu_to_le16(1);
|
|
bmp->header.bit_count = cpu_to_le16(bpp);
|
|
bmp->header.compression = cpu_to_le32(BMP_BI_RGB);
|
|
|
|
/* Copy framebuffer data (BMP is bottom-up) */
|
|
bmp_data = (void *)bmp + sizeof(struct bmp_header);
|
|
for (y = 0; y < height; y++) {
|
|
void *src = priv->fb + (height - 1 - y) * priv->line_length;
|
|
void *dst = bmp_data + y * row_bytes;
|
|
|
|
if (bpp == 16) {
|
|
/* Convert RGB565 to RGB555 for BMP format */
|
|
u16 *src16 = (u16 *)src;
|
|
u16 *dst16 = (u16 *)dst;
|
|
int x;
|
|
|
|
for (x = 0; x < width; x++) {
|
|
u16 pixel = src16[x];
|
|
/* Extract RGB565 components */
|
|
u16 r = (pixel >> 11) & 0x1f; /* 5 bits */
|
|
u16 g = (pixel >> 5) & 0x3f; /* 6 bits */
|
|
u16 b = pixel & 0x1f; /* 5 bits */
|
|
/* Convert to RGB555: drop LSB of green */
|
|
dst16[x] = (r << 10) | ((g >> 1) << 5) | b;
|
|
}
|
|
} else {
|
|
memcpy(dst, src, width * bytes_per_pixel);
|
|
}
|
|
}
|
|
|
|
ret = os_write_file(fname, bmp, bmp_size);
|
|
free(bmp);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int video_compress_fb(struct unit_test_state *uts, struct udevice *dev,
|
|
bool use_copy)
|
|
{
|
|
struct sandbox_state *state = state_get_current();
|
|
struct video_priv *priv = dev_get_uclass_priv(dev);
|
|
uint destlen;
|
|
void *dest;
|
|
int ret;
|
|
|
|
if (!IS_ENABLED(CONFIG_VIDEO_COPY))
|
|
use_copy = false;
|
|
|
|
destlen = priv->fb_size;
|
|
dest = malloc(priv->fb_size);
|
|
if (!dest)
|
|
return -ENOMEM;
|
|
ret = BZ2_bzBuffToBuffCompress(dest, &destlen,
|
|
use_copy ? priv->copy_fb : priv->fb,
|
|
priv->fb_size,
|
|
3, 0, 0);
|
|
free(dest);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* Write frame to file if --video-frames option is set */
|
|
if (state->video_frames_dir) {
|
|
char filename[256];
|
|
|
|
snprintf(filename, sizeof(filename), "%s/frame%d.bmp",
|
|
state->video_frames_dir, state->video_frame_count++);
|
|
ret = video_write_bmp(uts, dev, filename);
|
|
if (ret) {
|
|
ut_reportf("Failed to write frame to %s: %d",
|
|
filename, ret);
|
|
}
|
|
}
|
|
|
|
/* provide a useful delay if -V flag is used or LOG_DEBUG is set */
|
|
if (state->video_test)
|
|
mdelay(state->video_test);
|
|
else if (_DEBUG)
|
|
mdelay(300);
|
|
|
|
return destlen;
|
|
}
|
|
|
|
int video_check_copy_fb(struct unit_test_state *uts, struct udevice *dev)
|
|
{
|
|
struct video_priv *priv = dev_get_uclass_priv(dev);
|
|
|
|
if (!IS_ENABLED(CONFIG_VIDEO_COPY))
|
|
return 0;
|
|
|
|
video_sync(dev, false);
|
|
ut_assertf(!memcmp(priv->fb, priv->copy_fb, priv->fb_size),
|
|
"Copy framebuffer does not match fb");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Call this function at any point to halt and show the current display. Be
|
|
* sure to run the test with the -l flag.
|
|
*/
|
|
static void __maybe_unused see_output(void)
|
|
{
|
|
video_sync_all();
|
|
while (1);
|
|
}
|
|
|
|
/* Select the video console driver to use for a video device */
|
|
static int select_vidconsole(struct unit_test_state *uts, const char *drv_name)
|
|
{
|
|
struct sandbox_sdl_plat *plat;
|
|
struct udevice *dev;
|
|
|
|
ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
|
|
ut_assert(!device_active(dev));
|
|
plat = dev_get_plat(dev);
|
|
plat->vidconsole_drv_name = "vidconsole0";
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* video_get_nologo() - Disable the logo on the video device and return it
|
|
*
|
|
* @uts: Test state
|
|
* @devp: Returns video device
|
|
* Return: 0 if OK, -ve on error
|
|
*/
|
|
static int video_get_nologo(struct unit_test_state *uts, struct udevice **devp)
|
|
{
|
|
struct video_uc_plat *uc_plat;
|
|
struct udevice *dev;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
uc_plat = dev_get_uclass_plat(dev);
|
|
uc_plat->hide_logo = true;
|
|
|
|
/* now probe it */
|
|
ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
*devp = dev;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Test text output works on the video console */
|
|
static int dm_test_video_text(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
int i;
|
|
|
|
#define WHITE 0xffff
|
|
#define SCROLL_LINES 100
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_putc_xy(con, 0, 0, 'a');
|
|
ut_asserteq(79, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
vidconsole_putc_xy(con, 0, 0, ' ');
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
for (i = 0; i < 20; i++)
|
|
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
|
|
ut_asserteq(273, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
vidconsole_set_row(con, 0, WHITE);
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
for (i = 0; i < 20; i++)
|
|
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
|
|
ut_asserteq(273, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_text, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
static int dm_test_video_text_12x22(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
int i;
|
|
|
|
#define WHITE 0xffff
|
|
#define SCROLL_LINES 100
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "12x22", 0));
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_putc_xy(con, 0, 0, 'a');
|
|
ut_asserteq(89, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
vidconsole_putc_xy(con, 0, 0, ' ');
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
for (i = 0; i < 20; i++)
|
|
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
|
|
ut_asserteq(363, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
vidconsole_set_row(con, 0, WHITE);
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
for (i = 0; i < 20; i++)
|
|
vidconsole_putc_xy(con, VID_TO_POS(i * 8), 0, ' ' + i);
|
|
ut_asserteq(363, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_text_12x22, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test handling of special characters in the console */
|
|
static int dm_test_video_chars(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
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.";
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
vidconsole_put_string(con, test_string);
|
|
ut_asserteq(466, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_chars, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
#ifdef CONFIG_VIDEO_ANSI
|
|
#define ANSI_ESC "\x1b"
|
|
/* Test handling of ANSI escape sequences */
|
|
static int dm_test_video_ansi(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
|
|
/* reference clear: */
|
|
video_clear(con->parent);
|
|
video_sync(con->parent, false);
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* test clear escape sequence: [2J */
|
|
vidconsole_put_string(con, "A\tB\tC"ANSI_ESC"[2J");
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* test set-cursor: [%d;%df */
|
|
vidconsole_put_string(con, "abc"ANSI_ESC"[2;2fab"ANSI_ESC"[4;4fcd");
|
|
ut_asserteq(143, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* test colors (30-37 fg color, 40-47 bg color) */
|
|
vidconsole_put_string(con, ANSI_ESC"[30;41mfoo"); /* black on red */
|
|
vidconsole_put_string(con, ANSI_ESC"[33;44mbar"); /* yellow on blue */
|
|
ut_asserteq(272, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_ansi, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
#endif
|
|
|
|
/**
|
|
* check_vidconsole_output() - Run a text console test
|
|
*
|
|
* @uts: Test state
|
|
* @rot: Console rotation (0=normal orientation, 1=90 degrees clockwise,
|
|
* 2=upside down, 3=90 degree counterclockwise)
|
|
* @wrap_size: Expected size of compressed frame buffer for the wrap test
|
|
* @scroll_size: Same for the scroll test
|
|
* Return: 0 on success
|
|
*/
|
|
static int check_vidconsole_output(struct unit_test_state *uts, int rot,
|
|
int wrap_size, int scroll_size)
|
|
{
|
|
struct udevice *dev, *con;
|
|
struct sandbox_sdl_plat *plat;
|
|
int i;
|
|
|
|
ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
|
|
ut_assert(!device_active(dev));
|
|
plat = dev_get_plat(dev);
|
|
plat->rot = rot;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* Check display wrap */
|
|
for (i = 0; i < 120; i++)
|
|
vidconsole_put_char(con, 'A' + i % 50);
|
|
ut_asserteq(wrap_size, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* Check display scrolling */
|
|
for (i = 0; i < SCROLL_LINES; i++) {
|
|
vidconsole_put_char(con, 'A' + i % 50);
|
|
vidconsole_put_char(con, '\n');
|
|
}
|
|
ut_asserteq(scroll_size, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* If we scroll enough, the screen becomes blank again */
|
|
for (i = 0; i < SCROLL_LINES; i++)
|
|
vidconsole_put_char(con, '\n');
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Test text output through the console uclass */
|
|
static int dm_test_video_context(struct unit_test_state *uts)
|
|
{
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(check_vidconsole_output(uts, 0, 788, 453));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_context, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test rotated text output through the console uclass */
|
|
static int dm_test_video_rotation1(struct unit_test_state *uts)
|
|
{
|
|
ut_assertok(check_vidconsole_output(uts, 1, 1112, 680));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_rotation1, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test rotated text output through the console uclass */
|
|
static int dm_test_video_rotation2(struct unit_test_state *uts)
|
|
{
|
|
ut_assertok(check_vidconsole_output(uts, 2, 783, 445));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_rotation2, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test rotated text output through the console uclass */
|
|
static int dm_test_video_rotation3(struct unit_test_state *uts)
|
|
{
|
|
ut_assertok(check_vidconsole_output(uts, 3, 1134, 681));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_rotation3, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Read a file into memory and return a pointer to it */
|
|
static int read_file(struct unit_test_state *uts, const char *fname,
|
|
ulong *addrp)
|
|
{
|
|
int buf_size = 100000;
|
|
ulong addr = 0;
|
|
int size, fd;
|
|
char *buf;
|
|
|
|
buf = map_sysmem(addr, 0);
|
|
ut_assert(buf != NULL);
|
|
fd = os_open(fname, OS_O_RDONLY);
|
|
ut_assert(fd >= 0);
|
|
size = os_read(fd, buf, buf_size);
|
|
os_close(fd);
|
|
ut_assert(size >= 0);
|
|
ut_assert(size < buf_size);
|
|
*addrp = addr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Test drawing a bitmap file */
|
|
static int dm_test_video_bmp(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
ulong addr;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
|
|
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
ut_asserteq(1368, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a bitmap file on a 8bpp display */
|
|
static int dm_test_video_bmp8(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
ulong addr;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
|
|
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
ut_asserteq(1247, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a bitmap file on a 16bpp display */
|
|
static int dm_test_video_bmp16(struct unit_test_state *uts)
|
|
{
|
|
ulong src, src_len = ~0UL;
|
|
uint dst_len = ~0U;
|
|
struct udevice *dev;
|
|
ulong dst = 0x10000;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx-16bpp.bmp.gz", &src));
|
|
ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
|
|
&src_len));
|
|
|
|
ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
|
|
ut_asserteq(3700, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp16, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a 24bpp bitmap file on a 16bpp display */
|
|
static int dm_test_video_bmp24(struct unit_test_state *uts)
|
|
{
|
|
ulong src, src_len = ~0UL;
|
|
uint dst_len = ~0U;
|
|
struct udevice *dev;
|
|
ulong dst = 0x10000;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP16));
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
|
|
ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
|
|
&src_len));
|
|
|
|
ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
|
|
ut_asserteq(3656, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp24, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a 24bpp bitmap file on a 32bpp display */
|
|
static int dm_test_video_bmp24_32(struct unit_test_state *uts)
|
|
{
|
|
ulong src, src_len = ~0UL;
|
|
uint dst_len = ~0U;
|
|
struct udevice *dev;
|
|
ulong dst = 0x10000;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx-24bpp.bmp.gz", &src));
|
|
ut_assertok(gunzip(map_sysmem(dst, 0), dst_len, map_sysmem(src, 0),
|
|
&src_len));
|
|
|
|
ut_assertok(video_bmp_display(dev, dst, 0, 0, false));
|
|
ut_asserteq(6827, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp24_32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a bitmap file on a 32bpp display */
|
|
static int dm_test_video_bmp32(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
ulong addr;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
|
|
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
|
|
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
ut_asserteq(2024, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a compressed bitmap file */
|
|
static int dm_test_video_bmp_comp(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
ulong addr;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(read_file(uts, "tools/logos/denx-comp.bmp", &addr));
|
|
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
ut_asserteq(1368, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp_comp, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a bitmap file on a 32bpp display */
|
|
static int dm_test_video_comp_bmp32(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
ulong addr;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
|
|
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
ut_asserteq(2024, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_comp_bmp32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing a bitmap file on a 8bpp display */
|
|
static int dm_test_video_comp_bmp8(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
ulong addr;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP8));
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
|
|
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
ut_asserteq(1247, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_comp_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/**
|
|
* check_bmp_alpha() - Test drawing the riscos pointer with transparency
|
|
*
|
|
* Draws the riscos pointer BMP in various positions with and without
|
|
* transparency to verify alpha blending works correctly
|
|
*
|
|
* @uts: Test state
|
|
* @dev: Video device
|
|
* @first: Expected compression after first pointer draw
|
|
* @second: Expected compression after second pointer draw
|
|
* @trans: Expected compression after drawing with transparency
|
|
* Return: 0 if OK, -ve on error
|
|
*/
|
|
static int check_bmp_alpha(struct unit_test_state *uts, struct udevice *dev,
|
|
int first, int second, int trans)
|
|
{
|
|
struct video_priv *priv = dev_get_uclass_priv(dev);
|
|
ulong addr;
|
|
|
|
addr = map_to_sysmem(video_image_getptr(riscos_arrow));
|
|
|
|
/* Draw a black rectangle first */
|
|
video_draw_box(dev, 100, 100, 200, 200, 0,
|
|
video_index_to_colour(priv, VID_BLACK), true);
|
|
|
|
/* Draw the pointer on top of the black rectangle */
|
|
ut_assertok(video_bmp_display(dev, addr, 110, 110, false));
|
|
ut_asserteq(first, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* Draw the pointer on top of the white background */
|
|
ut_assertok(video_bmp_display(dev, addr, 350, 110, false));
|
|
ut_asserteq(second, video_compress_fb(uts, dev, false));
|
|
|
|
/* Draw the pointer with white (0xffffff) as transparent */
|
|
ut_assertok(video_bmp_displaya(dev, addr, 110, 160, false, true,
|
|
0xffffff));
|
|
ut_assertok(video_bmp_displaya(dev, addr, 350, 160, false, true,
|
|
0xffffff));
|
|
ut_asserteq(trans, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Test drawing the riscos pointer on a 16bpp display */
|
|
static int dm_test_video_bmp_alpha16(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(check_bmp_alpha(uts, dev, 174, 249, 358));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp_alpha16, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test drawing the riscos pointer on 32bpp display */
|
|
static int dm_test_video_bmp_alpha32(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
ut_assertok(sandbox_sdl_set_bpp(dev, VIDEO_BPP32));
|
|
ut_assertok(check_bmp_alpha(uts, dev, 641, 710, 869));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_bmp_alpha32, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test TrueType console */
|
|
static int dm_test_video_truetype(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
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";
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_put_string(con, test_string);
|
|
vidconsole_put_stringn(con, test_string, 30);
|
|
ut_asserteq(13073, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_truetype, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test scrolling TrueType console */
|
|
static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
|
|
{
|
|
struct sandbox_sdl_plat *plat;
|
|
struct udevice *dev, *con;
|
|
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";
|
|
|
|
ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
|
|
ut_assert(!device_active(dev));
|
|
plat = dev_get_plat(dev);
|
|
plat->font_size = 100;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_put_string(con, test_string);
|
|
ut_asserteq(34248, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_truetype_scroll, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test TrueType backspace, within and across lines */
|
|
static int dm_test_video_truetype_bs(struct unit_test_state *uts)
|
|
{
|
|
struct sandbox_sdl_plat *plat;
|
|
struct udevice *dev, *con;
|
|
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.";
|
|
|
|
ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
|
|
ut_assert(!device_active(dev));
|
|
plat = dev_get_plat(dev);
|
|
plat->font_size = 100;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_put_string(con, test_string);
|
|
ut_asserteq(29310, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_truetype_bs, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test partial rendering onto hardware frame buffer */
|
|
static int dm_test_video_copy(struct unit_test_state *uts)
|
|
{
|
|
struct sandbox_sdl_plat *plat;
|
|
struct video_uc_plat *uc_plat;
|
|
struct udevice *dev, *con;
|
|
struct video_priv *priv;
|
|
const char *test_string = "\n\tCriticism may not be agreeable, but it "
|
|
"is necessary.\t";
|
|
ulong addr;
|
|
|
|
if (!IS_ENABLED(CONFIG_VIDEO_COPY))
|
|
return -EAGAIN;
|
|
|
|
ut_assertok(uclass_find_first_device(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
uc_plat = dev_get_uclass_plat(dev);
|
|
uc_plat->hide_logo = true;
|
|
plat = dev_get_plat(dev);
|
|
plat->font_size = 32;
|
|
ut_assert(!device_active(dev));
|
|
ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
|
|
ut_assertnonnull(dev);
|
|
priv = dev_get_uclass_priv(dev);
|
|
|
|
ut_assertok(read_file(uts, "tools/logos/denx.bmp", &addr));
|
|
ut_assertok(video_bmp_display(dev, addr, 0, 0, false));
|
|
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_put_string(con, "\n\n\n\n\n");
|
|
vidconsole_put_string(con, test_string);
|
|
vidconsole_put_string(con, test_string);
|
|
|
|
ut_asserteq(6884, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/*
|
|
* Secretly clear the hardware frame buffer, but in a different
|
|
* color (black) to see which parts will be overwritten.
|
|
*/
|
|
memset(priv->copy_fb, 0, priv->fb_size);
|
|
|
|
/*
|
|
* We should have the full content on the main buffer, but only
|
|
* 'damage' should have been copied to the copy buffer. This consists
|
|
* of a while rectangle with the Denx logo and four lines of text. The
|
|
* rest of the display is black.
|
|
*
|
|
* An easy way to try this is by changing video_sync() to call
|
|
* sandbox_sdl_sync(priv->copy_fb) instead of priv->fb then running the
|
|
* unit test:
|
|
*
|
|
* ./u-boot -Tl
|
|
* ut dm dm_test_video_copy
|
|
*/
|
|
vidconsole_put_string(con, test_string);
|
|
vidconsole_put_string(con, test_string);
|
|
video_sync(dev, true);
|
|
ut_asserteq(7621, video_compress_fb(uts, dev, false));
|
|
ut_asserteq(7741, video_compress_fb(uts, dev, true));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_copy, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test video damage tracking */
|
|
static int dm_test_video_damage(struct unit_test_state *uts)
|
|
{
|
|
struct sandbox_sdl_plat *plat;
|
|
struct udevice *dev, *con;
|
|
struct video_priv *priv;
|
|
struct vid_bbox *damage;
|
|
const char *test_string_1 = "Criticism may not be agreeable, ";
|
|
const char *test_string_2 = "but it is necessary.";
|
|
const char *test_string_3 = "It fulfils the same function as pain in "
|
|
"the human body.";
|
|
|
|
if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE))
|
|
return -EAGAIN;
|
|
|
|
ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev));
|
|
ut_assert(!device_active(dev));
|
|
plat = dev_get_plat(dev);
|
|
plat->font_size = 32;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
priv = dev_get_uclass_priv(dev);
|
|
|
|
damage = &priv->damage;
|
|
|
|
vidconsole_position_cursor(con, 14, 10);
|
|
vidconsole_put_string(con, test_string_2);
|
|
ut_asserteq(449, damage->x0);
|
|
ut_asserteq(325, damage->y0);
|
|
ut_asserteq(661, damage->x1);
|
|
ut_asserteq(350, damage->y1);
|
|
|
|
vidconsole_position_cursor(con, 7, 5);
|
|
vidconsole_put_string(con, test_string_1);
|
|
ut_asserteq(225, damage->x0);
|
|
ut_asserteq(164, damage->y0);
|
|
ut_asserteq(661, damage->x1);
|
|
ut_asserteq(350, damage->y1);
|
|
|
|
vidconsole_position_cursor(con, 21, 15);
|
|
vidconsole_put_string(con, test_string_3);
|
|
ut_asserteq(225, damage->x0);
|
|
ut_asserteq(164, damage->y0);
|
|
ut_asserteq(1280, damage->x1);
|
|
ut_asserteq(510, damage->y1);
|
|
|
|
video_sync(dev, true);
|
|
ut_asserteq(priv->xsize, damage->x0);
|
|
ut_asserteq(priv->ysize, damage->y0);
|
|
ut_asserteq(0, damage->x1);
|
|
ut_asserteq(0, damage->y1);
|
|
|
|
ut_asserteq(7335, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test font measurement */
|
|
static int dm_test_font_measure(struct unit_test_state *uts)
|
|
{
|
|
const char *test_string = "There is always much\nto be said for not "
|
|
"attempting more than you can do and for making a certainty of "
|
|
"what you try. But this principle, like others in life and "
|
|
"war, has its exceptions.";
|
|
const struct vidconsole_mline *line;
|
|
struct vidconsole_bbox bbox;
|
|
struct video_priv *priv;
|
|
struct udevice *dev, *con;
|
|
const int limit = 0x320;
|
|
struct alist lines;
|
|
int nl;
|
|
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
|
|
priv = dev_get_uclass_priv(dev);
|
|
ut_asserteq(1366, priv->xsize);
|
|
ut_asserteq(768, priv->ysize);
|
|
|
|
/* this is using the Nimbus font with size of 18 pixels */
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
vidconsole_position_cursor(con, 0, 0);
|
|
alist_init_struct(&lines, struct vidconsole_mline);
|
|
ut_assertok(vidconsole_measure(con, NULL, 0, test_string, -1, &bbox,
|
|
&lines));
|
|
ut_asserteq(0, bbox.x0);
|
|
ut_asserteq(0, bbox.y0);
|
|
ut_asserteq(0x3ea, bbox.x1);
|
|
ut_asserteq(0x24, bbox.y1);
|
|
ut_asserteq(2, lines.count);
|
|
|
|
nl = strchr(test_string, '\n') - test_string;
|
|
|
|
line = alist_get(&lines, 0, struct vidconsole_mline);
|
|
ut_assertnonnull(line);
|
|
ut_asserteq(0, line->bbox.x0);
|
|
ut_asserteq(0, line->bbox.y0);
|
|
ut_asserteq(0x8c, line->bbox.x1);
|
|
ut_asserteq(0x12, line->bbox.y1);
|
|
ut_asserteq(0, line->start);
|
|
ut_asserteq(20, line->len);
|
|
ut_asserteq(nl, line->len);
|
|
|
|
line++;
|
|
ut_asserteq(0x0, line->bbox.x0);
|
|
ut_asserteq(0x12, line->bbox.y0);
|
|
ut_asserteq(0x3ea, line->bbox.x1);
|
|
ut_asserteq(0x24, line->bbox.y1);
|
|
ut_asserteq(21, line->start);
|
|
ut_asserteq(nl + 1, line->start);
|
|
ut_asserteq(163, line->len);
|
|
ut_asserteq(strlen(test_string + nl + 1), line->len);
|
|
|
|
/* now use a limit on the width */
|
|
ut_assertok(vidconsole_measure(con, NULL, 0, test_string, limit, &bbox,
|
|
&lines));
|
|
ut_asserteq(0, bbox.x0);
|
|
ut_asserteq(0, bbox.y0);
|
|
ut_asserteq(0x31e, bbox.x1);
|
|
ut_asserteq(0x36, bbox.y1);
|
|
ut_asserteq(3, lines.count);
|
|
|
|
nl = strchr(test_string, '\n') - test_string;
|
|
|
|
line = alist_get(&lines, 0, struct vidconsole_mline);
|
|
ut_assertnonnull(line);
|
|
ut_asserteq(0, line->bbox.x0);
|
|
ut_asserteq(0, line->bbox.y0);
|
|
ut_asserteq(0x8c, line->bbox.x1);
|
|
ut_asserteq(0x12, line->bbox.y1);
|
|
ut_asserteq(0, line->start);
|
|
ut_asserteq(20, line->len);
|
|
ut_asserteq(nl, line->len);
|
|
printf("line0 '%.*s'\n", line->len, test_string + line->start);
|
|
ut_asserteq_strn("There is always much",
|
|
test_string + line->start);
|
|
|
|
line++;
|
|
ut_asserteq(0x0, line->bbox.x0);
|
|
ut_asserteq(0x12, line->bbox.y0);
|
|
ut_asserteq(0x31e, line->bbox.x1);
|
|
ut_asserteq(0x24, line->bbox.y1);
|
|
ut_asserteq(21, line->start);
|
|
ut_asserteq(nl + 1, line->start);
|
|
ut_asserteq(129, line->len);
|
|
printf("line1 '%.*s'\n", line->len, test_string + line->start);
|
|
ut_asserteq_strn("to be said for not attempting more than you can do "
|
|
"and for making a certainty of what you try. But this "
|
|
"principle, like others in",
|
|
test_string + line->start);
|
|
|
|
line++;
|
|
ut_asserteq(0x0, line->bbox.x0);
|
|
ut_asserteq(0x24, line->bbox.y0);
|
|
ut_asserteq(0xc8, line->bbox.x1);
|
|
ut_asserteq(0x36, line->bbox.y1);
|
|
ut_asserteq(21 + 130, line->start);
|
|
ut_asserteq(33, line->len);
|
|
printf("line2 '%.*s'\n", line->len, test_string + line->start);
|
|
ut_asserteq_strn("life and war, has its exceptions.",
|
|
test_string + line->start);
|
|
|
|
/*
|
|
* all characters should be accounted for, except the newline and the
|
|
* space which is consumed in the wordwrap
|
|
*/
|
|
ut_asserteq(strlen(test_string) - 2,
|
|
line[-2].len + line[-1].len + line->len);
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_font_measure, UTF_SCAN_FDT);
|
|
|
|
/* Test silencing the video console */
|
|
static int dm_test_video_silence(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
struct stdio_dev *sdev;
|
|
|
|
ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
|
|
|
|
/*
|
|
* use the old console device from before when dm_test_pre_run() was
|
|
* called, since that is what is in stdio / console
|
|
*/
|
|
sdev = stdio_get_by_name("vidconsole");
|
|
ut_assertnonnull(sdev);
|
|
con = sdev->priv;
|
|
ut_assertok(vidconsole_clear_and_reset(con));
|
|
ut_unsilence_console(uts);
|
|
|
|
printf("message 1: console\n");
|
|
vidconsole_put_string(con, "message 1: video\n");
|
|
|
|
vidconsole_set_quiet(con, true);
|
|
printf("second message: console\n");
|
|
vidconsole_put_string(con, "second message: video\n");
|
|
|
|
vidconsole_set_quiet(con, false);
|
|
printf("final message: console\n");
|
|
vidconsole_put_string(con, "final message: video\n");
|
|
|
|
ut_asserteq(3944, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_silence, UTF_SCAN_FDT);
|
|
|
|
/* test drawing a box */
|
|
static int dm_test_video_box(struct unit_test_state *uts)
|
|
{
|
|
struct video_priv *priv;
|
|
struct udevice *dev;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
priv = dev_get_uclass_priv(dev);
|
|
|
|
/* test outline boxes */
|
|
video_draw_box(dev, 100, 100, 200, 200, 3,
|
|
video_index_to_colour(priv, VID_LIGHT_BLUE), false);
|
|
video_draw_box(dev, 300, 100, 400, 200, 1,
|
|
video_index_to_colour(priv, VID_MAGENTA), false);
|
|
video_draw_box(dev, 500, 100, 600, 200, 20,
|
|
video_index_to_colour(priv, VID_LIGHT_RED), false);
|
|
ut_asserteq(133, video_compress_fb(uts, dev, false));
|
|
|
|
/* test filled boxes */
|
|
video_draw_box(dev, 150, 250, 200, 300, 0,
|
|
video_index_to_colour(priv, VID_GREEN), true);
|
|
video_draw_box(dev, 350, 250, 400, 300, 0,
|
|
video_index_to_colour(priv, VID_YELLOW), true);
|
|
ut_asserteq(175, video_compress_fb(uts, dev, false));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_box, UTF_SCAN_FDT);
|
|
|
|
/* font switching between TrueType and bitmap fonts */
|
|
static int dm_test_video_font_switch(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
const char *truetype_text =
|
|
"This is a long line of text written with TrueType font that "
|
|
"should wrap to multiple lines to test the multi-line "
|
|
"functionality properly. This is the second part of TrueType "
|
|
"text that should also be long enough to wrap and test the "
|
|
"line handling.";
|
|
const char *bitmap_text =
|
|
"Now this is bitmap font text that spans multiple lines and "
|
|
"should be rendered with the standard 8x16 bitmap font instead "
|
|
"of TrueType. More of the line of-bitmap text for testing "
|
|
"purposes.";
|
|
const char *final_truetype_text =
|
|
"Finally back to TrueType font for this concluding multi-line "
|
|
"text that demonstrates the font switching functionality "
|
|
"working correctly.\nFinal line of TrueType text to complete "
|
|
"the test.\n";
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
|
|
/* Start with TrueType font and write multi-line text */
|
|
vidconsole_put_string(con, truetype_text);
|
|
|
|
/* Switch to bitmap font */
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
vidconsole_put_string(con, bitmap_text);
|
|
|
|
/* Switch back to TrueType font */
|
|
ut_assertok(vidconsole_select_font(con, NULL, 0));
|
|
vidconsole_put_string(con, final_truetype_text);
|
|
|
|
ut_asserteq(14892, video_compress_fb(uts, dev, false));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_font_switch, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* cursor backspace without artifacts */
|
|
static int check_cursor_backspace(struct unit_test_state *uts,
|
|
struct udevice *dev, struct udevice *con,
|
|
int exp_height)
|
|
{
|
|
int with_a, with_cursor, after_backspace, after_idle, after_hide;
|
|
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(con);
|
|
struct vidconsole_cursor *curs = &vc_priv->curs;
|
|
|
|
/* Output chars without cursor */
|
|
ut_assert(!curs->visible);
|
|
ut_assert(!curs->enabled);
|
|
ut_assert(!curs->saved);
|
|
ut_assert(!curs->height);
|
|
ut_assertok(vidconsole_put_char(con, ' '));
|
|
ut_assertok(vidconsole_put_char(con, 'a'));
|
|
with_a = video_compress_fb(uts, dev, false);
|
|
|
|
/* Show cursor at current position (after 'a') */
|
|
ut_assertok(vidconsole_show_cursor(con));
|
|
ut_assert(curs->visible);
|
|
ut_assert(curs->saved);
|
|
ut_asserteq(exp_height, curs->height);
|
|
with_cursor = video_compress_fb(uts, dev, false);
|
|
|
|
/* Enable the cursor so that backspace will move it */
|
|
curs->enabled = true;
|
|
|
|
/* Do backspace - the cursor will be hidden */
|
|
ut_assertok(vidconsole_put_char(con, '\b'));
|
|
ut_assert(!curs->visible);
|
|
ut_assert(!curs->saved);
|
|
after_backspace = video_compress_fb(uts, dev, false);
|
|
ut_asserteq(with_a, after_backspace);
|
|
ut_assert(curs->enabled);
|
|
|
|
/* Run idle function - this should show the cursor */
|
|
vidconsole_idle(con);
|
|
ut_assert(curs->visible);
|
|
ut_assert(curs->saved);
|
|
after_idle = video_compress_fb(uts, dev, false);
|
|
ut_assert(after_idle != with_a);
|
|
|
|
/* Hide the cursor */
|
|
ut_assertok(vidconsole_hide_cursor(con));
|
|
ut_assert(curs->enabled);
|
|
ut_assert(!curs->visible);
|
|
ut_assert(!curs->saved);
|
|
after_hide = video_compress_fb(uts, dev, false);
|
|
|
|
ut_asserteq(with_a, after_hide);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* cursor backspace without artifacts */
|
|
static int dm_test_video_backspace_normal(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
ut_assertok(check_cursor_backspace(uts, dev, con, 16));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_backspace_normal, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* cursor backspace without artifacts on truetype */
|
|
static int dm_test_video_backspace_truetype(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, NULL, 30));
|
|
ut_assertok(check_cursor_backspace(uts, dev, con, 30));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_backspace_truetype, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* video commands */
|
|
static int dm_test_video_cmd(struct unit_test_state *uts)
|
|
{
|
|
struct udevice *dev, *con;
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
|
|
ut_assertok(run_command("setcurs 10 5", 0));
|
|
|
|
ut_assertok(run_command("lcdputs \"Test string\"", 0));
|
|
ut_asserteq(187, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
ut_assertok(run_command("video setcursor 0 0", 0));
|
|
ut_assertok(run_command("video puts \"Top left\"", 0));
|
|
ut_asserteq(272, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
ut_assertok(run_command(
|
|
"video write 14:6 \"Multi\" 19:7 \"Write\"", 0));
|
|
ut_asserteq(381, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
ut_assertok(run_command("video write -p a3:34 \"Pixels\"", 0));
|
|
ut_asserteq(440, video_compress_fb(uts, dev, false));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_cmd, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* video images command */
|
|
static int dm_test_video_images(struct unit_test_state *uts)
|
|
{
|
|
ut_assertok(run_command("video images", 0));
|
|
ut_assert_nextline("Name Size");
|
|
ut_assert_nextline("-------------------- ----------");
|
|
ut_assert_nextline("bgrt 43926");
|
|
ut_assert_nextline("canonical 14258");
|
|
ut_assert_nextline("help 1782");
|
|
ut_assert_nextline("lock 2454");
|
|
ut_assert_nextline("multipass 4378");
|
|
ut_assert_nextline("riscos_arrow 3798");
|
|
ut_assert_nextline("settings 1782");
|
|
ut_assert_nextline("tick 822");
|
|
ut_assert_nextline("u_boot 6932");
|
|
ut_assert_skip_to_line("");
|
|
ut_assert_nextline("Total images: 9");
|
|
ut_assert_console_end();
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_images, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE);
|
|
|
|
/* Test manual-sync mode suppresses auto-sync */
|
|
static int dm_test_video_manual_sync(struct unit_test_state *uts)
|
|
{
|
|
struct video_priv *priv;
|
|
struct udevice *dev, *con;
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
priv = dev_get_uclass_priv(dev);
|
|
|
|
/* Write some text and verify it appears in the framebuffer */
|
|
vidconsole_put_string(con, "Test");
|
|
ut_asserteq(118, video_compress_fb(uts, dev, false));
|
|
|
|
/* Sync to copy buffer before enabling manual-sync mode */
|
|
ut_assertok(video_sync(dev, true));
|
|
|
|
/* Enable manual-sync mode - sync should be suppressed */
|
|
video_set_manual_sync(true);
|
|
|
|
/* Clear and write new text - auto-sync should not happen */
|
|
video_clear(dev);
|
|
vidconsole_put_string(con, "Manual Sync");
|
|
|
|
/* should do nothing in manual-sync mode */
|
|
ut_assertok(video_sync(dev, false));
|
|
|
|
/* The copy framebuffer should still show old content */
|
|
if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
|
|
ut_assertf(memcmp(priv->fb, priv->copy_fb, priv->fb_size),
|
|
"Copy fb should not match fb in manual-sync mode");
|
|
}
|
|
|
|
/*
|
|
* video_sync() with force=true should still do nothing, except of
|
|
* course that without a copy framebuffer the string will be present on
|
|
* (only) framebuffer
|
|
*/
|
|
ut_assertok(video_sync(dev, true));
|
|
if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
|
|
ut_asserteq(118, video_compress_fb(uts, dev, true));
|
|
ut_assertf(memcmp(priv->fb, priv->copy_fb, priv->fb_size),
|
|
"Copy fb should not match fb in manual-sync mode");
|
|
} else {
|
|
ut_asserteq(183, video_compress_fb(uts, dev, true));
|
|
}
|
|
|
|
/* Now test video_manual_sync() directly with VIDSYNC_FORCE and COPY */
|
|
ut_assertok(video_manual_sync(dev, VIDSYNC_FORCE | VIDSYNC_FLUSH |
|
|
VIDSYNC_COPY));
|
|
ut_asserteq(183, video_compress_fb(uts, dev, false));
|
|
|
|
/* The copy framebuffer should now match since we forced the sync */
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* Write new text again */
|
|
vidconsole_put_string(con, "Test2");
|
|
|
|
/* without VIDSYNC_FLUSH or COPY - should do nothing */
|
|
ut_assertok(video_manual_sync(dev, 0));
|
|
|
|
/* Copy fb should not match since neither flush nor copy occurred */
|
|
if (IS_ENABLED(CONFIG_VIDEO_COPY)) {
|
|
ut_assertf(memcmp(priv->fb, priv->copy_fb, priv->fb_size),
|
|
"Copy fb shouldn't match fb w/o VIDSYNC_FLUSH/COPY");
|
|
}
|
|
|
|
/* video_manual_sync() with full flags - should perform full sync */
|
|
ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
|
|
ut_assertok(video_check_copy_fb(uts, dev));
|
|
|
|
/* Disable manual-sync mode */
|
|
video_set_manual_sync(false);
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_manual_sync, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|
|
|
|
/* Test that sync() receives the correct damage rectangle */
|
|
static int dm_test_video_sync_damage(struct unit_test_state *uts)
|
|
{
|
|
struct vid_bbox damage;
|
|
struct udevice *dev, *con;
|
|
struct video_priv *priv;
|
|
|
|
if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE))
|
|
return -EAGAIN;
|
|
|
|
ut_assertok(select_vidconsole(uts, "vidconsole0"));
|
|
ut_assertok(video_get_nologo(uts, &dev));
|
|
ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
|
|
ut_assertok(vidconsole_select_font(con, "8x16", 0));
|
|
priv = dev_get_uclass_priv(dev);
|
|
|
|
/* Use manual sync to prevent interference with the test */
|
|
video_set_manual_sync(true);
|
|
|
|
/* Clear the display - this creates a full-screen damage and syncs */
|
|
video_clear(dev);
|
|
ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
|
|
ut_asserteq(46, video_compress_fb(uts, dev, false));
|
|
|
|
/* Get the damage rectangle that was passed to sync() */
|
|
ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
|
|
|
|
/* Should be the full screen */
|
|
ut_assert(vid_bbox_valid(&damage));
|
|
ut_asserteq(0, damage.x0);
|
|
ut_asserteq(0, damage.y0);
|
|
ut_asserteq(priv->xsize, damage.x1);
|
|
ut_asserteq(priv->ysize, damage.y1);
|
|
|
|
/* Sync again with no changes - should have empty damage */
|
|
ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
|
|
ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
|
|
ut_assert(!vid_bbox_valid(&damage));
|
|
|
|
/* Check that priv->damage is still reset to empty */
|
|
ut_assert(!vid_bbox_valid(&priv->damage));
|
|
|
|
/* Write a small piece of text at a specific position */
|
|
vidconsole_putc_xy(con, VID_TO_POS(400), 67, 'T');
|
|
|
|
/* Check priv->damage before sync - should have text damage */
|
|
ut_assert(vid_bbox_valid(&priv->damage));
|
|
ut_asserteq(400, priv->damage.x0);
|
|
ut_asserteq(67, priv->damage.y0);
|
|
ut_asserteq(400 + 8, priv->damage.x1); /* 8x16 font */
|
|
ut_asserteq(67 + 16, priv->damage.y1);
|
|
|
|
ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
|
|
|
|
/* Get the damage rectangle that was passed to sync() */
|
|
ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
|
|
|
|
/* The damage should cover just the character */
|
|
ut_assert(vid_bbox_valid(&damage));
|
|
ut_asserteq(400, damage.x0);
|
|
ut_asserteq(67, damage.y0);
|
|
ut_asserteq(400 + 8, damage.x1);
|
|
ut_asserteq(67 + 16, damage.y1);
|
|
|
|
/* Check priv->damage after sync - should be reset to empty */
|
|
ut_assert(!vid_bbox_valid(&priv->damage));
|
|
|
|
/* Draw a filled box at a different position */
|
|
ut_assertok(video_draw_box(dev, 200, 300, 250, 340, 1, 0xffffff, true));
|
|
|
|
/* Check priv->damage before sync - should have box damage */
|
|
ut_assert(vid_bbox_valid(&priv->damage));
|
|
ut_asserteq(200, priv->damage.x0);
|
|
ut_asserteq(300, priv->damage.y0);
|
|
ut_asserteq(250, priv->damage.x1);
|
|
ut_asserteq(340, priv->damage.y1);
|
|
|
|
ut_assertok(video_manual_sync(dev, VIDSYNC_FLUSH | VIDSYNC_COPY));
|
|
|
|
/* Get the damage rectangle for the box */
|
|
ut_assertok(sandbox_sdl_get_sync_damage(dev, &damage));
|
|
|
|
/* The damage should cover the box area */
|
|
ut_assert(vid_bbox_valid(&damage));
|
|
ut_asserteq(200, damage.x0);
|
|
ut_asserteq(300, damage.y0);
|
|
ut_asserteq(250, damage.x1);
|
|
ut_asserteq(340, damage.y1);
|
|
|
|
/* Check priv->damage after sync - should be reset to inverted/empty */
|
|
ut_assert(!vid_bbox_valid(&priv->damage));
|
|
|
|
return 0;
|
|
}
|
|
DM_TEST(dm_test_video_sync_damage, UTF_SCAN_PDATA | UTF_SCAN_FDT);
|