[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