[PATCH 1/1] video: support colors in truetype console
Simon Glass
sjg at chromium.org
Mon Oct 12 05:34:15 CEST 2020
Hi Heinrich,
On Wed, 30 Sep 2020 at 16:59, Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
>
> In the UEFI context we use colored output. When printing truetype letters
> we have to interpolate the pixel color between the foreground and
> background color according to the gray value of the font pixel.
>
> We could speed up the output a by writing a lookup table in the uclass
> whenever a color changes but this would impose a burden on all console
> drivers. So this is not implemented.
Well you could make it conditional based on a flag in the uclass priv.
>
> For testing the sandbox can be used when enabling CONFIG_EFI_SELFTEST.
>
> $ ./u-boot -D -l
> => setenv efi_selftest text output
> => bootefi selftest
>
> This test writes text in all combinations of foreground and background
> colors to the console.
>
> To test 16bit mode modify arch/sandbox/dts/sandbox.dtsi. Set
>
> /lcd/log2-depth = <4>;
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
> For testing the following patches for the sandbox are needed:
>
> [PATCH v2 1/1] sandbox: redefine getc()
> https://lists.denx.de/pipermail/u-boot/2020-September/428082.html
>
> [PATCH 1/1] sandbox: add missing SDL key scan codes
> https://lists.denx.de/pipermail/u-boot/2020-September/428007.html
> ---
> drivers/video/console_truetype.c | 156 ++++++++++++++++++++-----------
> test/dm/video.c | 6 +-
> 2 files changed, 104 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c
> index 22b2ea7191..f50bb9df2f 100644
> --- a/drivers/video/console_truetype.c
> +++ b/drivers/video/console_truetype.c
> @@ -212,8 +212,10 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
> struct pos_info *pos;
> u8 *bits, *data;
> int advance;
> - void *start, *end, *line;
> + void *start, *line, *sync_start, *sync_end;
> int row, ret;
> + int bg_r, bg_g, bg_b;
> + int fg_r, fg_g, fg_b;
>
> /* First get some basic metrics about this character */
> stbtt_GetCodepointHMetrics(font, ch, &advance, &lsb);
> @@ -257,82 +259,126 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
> data = stbtt_GetCodepointBitmapSubpixel(font, priv->scale, priv->scale,
> x_shift, 0, ch, &width, &height,
> &xoff, &yoff);
> - if (!data)
> - return width_frac;
> + bits = data;
>
> /* Figure out where to write the character in the frame buffer */
> - bits = data;
> - start = vid_priv->fb + y * vid_priv->line_length +
> - VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
> + sync_start = vid_priv->fb + y * vid_priv->line_length;
> + sync_end = sync_start + vc_priv->y_charsize * vid_priv->line_length;
> + start = sync_start + VID_TO_PIXEL(x) * VNBYTES(vid_priv->bpix);
> linenum = priv->baseline + yoff;
> - if (linenum > 0)
> - start += linenum * vid_priv->line_length;
> - line = start;
> + line = start + linenum * vid_priv->line_length;
> +
> + /* Decompose foreground and background color */
> + switch (vid_priv->bpix) {
> +#ifdef CONFIG_VIDEO_BPP16
I believe you can use if() for everything in this patch.
> + case VIDEO_BPP16:
> + bg_r = (vid_priv->colour_bg >> 11) & 0x1f;
> + bg_g = (vid_priv->colour_bg >> 5) & 0x3f;
> + bg_b = (vid_priv->colour_bg >> 0) & 0x1f;
> +
> + fg_r = (vid_priv->colour_fg >> 11) & 0x1f;
> + fg_g = (vid_priv->colour_fg >> 5) & 0x3f;
> + fg_b = (vid_priv->colour_fg >> 0) & 0x1f;
> + break;
> +#endif
> +#ifdef CONFIG_VIDEO_BPP32
> + case VIDEO_BPP32:
> + bg_r = (vid_priv->colour_bg >> 16) & 0xff;
> + bg_g = (vid_priv->colour_bg >> 8) & 0xff;
> + bg_b = (vid_priv->colour_bg >> 0) & 0xff;
> +
> + fg_r = (vid_priv->colour_fg >> 16) & 0xff;
> + fg_g = (vid_priv->colour_fg >> 8) & 0xff;
> + fg_b = (vid_priv->colour_fg >> 0) & 0xff;
> + break;
> +#endif
> + default:
> + free(data);
> + return -ENOSYS;
> + }
>
> /*
> * Write a row at a time, converting the 8bpp image into the colour
> - * depth of the display. We only expect white-on-black or the reverse
> - * so the code only handles this simple case.
> + * depth of the display.
> */
> - for (row = 0; row < height; row++) {
> - switch (vid_priv->bpix) {
> + switch (vid_priv->bpix) {
> #ifdef CONFIG_VIDEO_BPP16
> - case VIDEO_BPP16: {
> - uint16_t *dst = (uint16_t *)line + xoff;
> + case VIDEO_BPP16:
> + for (row = 0; row < vc_priv->y_charsize; row++) {
> + u16 *dst = (u16 *)start;
> int i;
>
> - for (i = 0; i < width; i++) {
> - int val = *bits;
> - int out;
> -
> - if (vid_priv->colour_bg)
> - val = 255 - val;
> - out = val >> 3 |
> - (val >> 2) << 5 |
> - (val >> 3) << 11;
> - if (vid_priv->colour_fg)
> - *dst++ |= out;
> - else
> - *dst++ &= out;
> - bits++;
> + for (i = 0; i < xpos; ++i)
> + *dst++ = vid_priv->colour_bg;
> + start += vid_priv->line_length;
> + }
> + if (data) {
> + for (row = 0; row < height; row++) {
> + u16 *dst = (u16 *)line + xoff;
> + int i;
> +
> + for (i = 0; i < width; i++) {
> + int fg, bg, r, g, b, out;
> +
> + /*
> + * Interpolate between foreground and
> + * background color.
> + */
> + fg = 1 + *bits++;
> + bg = 0x101 - fg;
> + r = (fg_r * fg + bg_r * bg) >> 8;
> + g = (fg_g * fg + bg_g * bg) >> 8;
> + b = (fg_b * fg + bg_b * bg) >> 8;
> + out = b | g << 5 | r << 11;
> + *dst++ = out;
> + }
> + line += vid_priv->line_length;
> }
> - end = dst;
> - break;
> }
> + break;
> #endif
> #ifdef CONFIG_VIDEO_BPP32
> - case VIDEO_BPP32: {
> - u32 *dst = (u32 *)line + xoff;
> + case VIDEO_BPP32:
> + for (row = 0; row < vc_priv->y_charsize; row++) {
> + u32 *dst = (u32 *)start;
> int i;
>
> - for (i = 0; i < width; i++) {
> - int val = *bits;
> - int out;
> -
> - if (vid_priv->colour_bg)
> - val = 255 - val;
> - out = val | val << 8 | val << 16;
> - if (vid_priv->colour_fg)
> - *dst++ |= out;
> - else
> - *dst++ &= out;
> - bits++;
> + for (i = 0; i < xpos; ++i)
> + *dst++ = vid_priv->colour_bg;
> + start += vid_priv->line_length;
> + }
> + if (data) {
> + for (row = 0; row < height; row++) {
> + u32 *dst = (u32 *)line + xoff;
> + int i;
> +
> + for (i = 0; i < width; i++) {
> + int fg, bg, r, g, b, out;
> +
> + /*
> + * Interpolate between foreground and
> + * background color.
Perhaps this should be in a function?
> + */
> + fg = 1 + *bits++;
> + bg = 0x101 - fg;
> + r = (fg_r * fg + bg_r * bg) >> 8;
> + g = (fg_g * fg + bg_g * bg) >> 8;
> + b = (fg_b * fg + bg_b * bg) >> 8;
> + out = b | g << 8 | r << 16;
> + *dst++ = out;
> + }
> + line += vid_priv->line_length;
> }
> - end = dst;
> - break;
> }
> + break;
> #endif
> - default:
> - free(data);
> - return -ENOSYS;
> - }
> -
> - line += vid_priv->line_length;
> + default:
> + break;
> }
> - ret = vidconsole_sync_copy(dev, start, line);
> + ret = vidconsole_sync_copy(dev, sync_start, sync_end);
> + free(data);
> if (ret)
> return ret;
> - free(data);
>
> return width_frac;
> }
> diff --git a/test/dm/video.c b/test/dm/video.c
> index 1af948dca3..dd9da3213e 100644
> --- a/test/dm/video.c
> +++ b/test/dm/video.c
> @@ -344,7 +344,7 @@ static int dm_test_video_truetype(struct unit_test_state *uts)
> ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
> ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
> vidconsole_put_string(con, test_string);
> - ut_asserteq(12237, compress_frame_buffer(uts, dev));
> + ut_asserteq(13001, compress_frame_buffer(uts, dev));
>
> return 0;
> }
> @@ -365,7 +365,7 @@ static int dm_test_video_truetype_scroll(struct unit_test_state *uts)
> ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
> ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
> vidconsole_put_string(con, test_string);
> - ut_asserteq(35030, compress_frame_buffer(uts, dev));
> + ut_asserteq(36952, compress_frame_buffer(uts, dev));
>
> return 0;
> }
> @@ -386,7 +386,7 @@ static int dm_test_video_truetype_bs(struct unit_test_state *uts)
> ut_assertok(uclass_get_device(UCLASS_VIDEO, 0, &dev));
> ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con));
> vidconsole_put_string(con, test_string);
> - ut_asserteq(29018, compress_frame_buffer(uts, dev));
> + ut_asserteq(30747, compress_frame_buffer(uts, dev));
>
> return 0;
> }
> --
> 2.28.0
>
Regards,
Simon
More information about the U-Boot
mailing list