@@ -11,6 +11,16 @@
#include <video.h>
#include <video_console.h>
+#if CONFIG_IS_ENABLED(VIDEO_GLYPH_STATS)
+static int do_font_info(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ printf("glyphs rendered: %u\n", gd->glyph_count);
+
+ return 0;
+}
+#endif
+
static int do_font_list(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
@@ -75,12 +85,22 @@ static int do_font_size(struct cmd_tbl *cmdtp, int flag, int argc,
return 0;
}
+#if CONFIG_IS_ENABLED(VIDEO_GLYPH_STATS)
+#define FONT_INFO_HELP "\nfont info - show glyph rendering statistics"
+#define FONT_INFO_SUB , U_BOOT_SUBCMD_MKENT(info, 1, 1, do_font_info)
+#else
+#define FONT_INFO_HELP
+#define FONT_INFO_SUB
+#endif
+
U_BOOT_LONGHELP(font,
"list - list available fonts\n"
"font select <name> [<size>] - select font to use\n"
- "font size <size> - select font size to");
+ "font size <size> - select font size to"
+ FONT_INFO_HELP);
U_BOOT_CMD_WITH_SUBCMDS(font, "Fonts", font_help_text,
U_BOOT_SUBCMD_MKENT(list, 1, 1, do_font_list),
U_BOOT_SUBCMD_MKENT(select, 3, 1, do_font_select),
- U_BOOT_SUBCMD_MKENT(size, 2, 1, do_font_size));
+ U_BOOT_SUBCMD_MKENT(size, 2, 1, do_font_size)
+ FONT_INFO_SUB);
@@ -14,6 +14,7 @@ Synopsis
font list
font select [<name> [<size>]]
font size [<size>]
+ font info
Description
-----------
@@ -38,6 +39,14 @@ font size
This changes the font size only. With no argument it shows the current size.
+font info
+~~~~~~~~~
+
+This shows glyph rendering statistics, specifically the number of glyphs
+rendered since the video console was set up.
+
+This subcommand requires CONFIG_VIDEO_GLYPH_STATS=y.
+
Examples
--------
@@ -52,7 +61,7 @@ Examples
=> font select cantoraone_regular 20
=>
-This shows an example of selecting a bitmap font Truetype is active::
+This shows an example of selecting a bitmap font when Truetype is active::
=> font list
8x16
@@ -61,12 +70,23 @@ This shows an example of selecting a bitmap font Truetype is active::
cantoraone_regular
=> font sel 8x16
+This shows glyph rendering statistics::
+
+ => font info
+ glyphs rendered: 32705
+
Configuration
-------------
The command is only available if CONFIG_CONSOLE_TRUETYPE=y.
+CONFIG_CONSOLE_TRUETYPE_GLYPH_BUF enables a pre-allocated buffer for glyph
+rendering, avoiding malloc/free per character. The buffer starts at 4KB and
+grows as needed via realloc().
+
+CONFIG_VIDEO_GLYPH_STATS enables tracking of glyph-rendering statistics.
+
Return value
------------
@@ -247,6 +247,28 @@ config CONSOLE_TRUETYPE_MAX_METRICS
font metrics which are expensive to regenerate each time the font
size changes.
+config CONSOLE_TRUETYPE_GLYPH_BUF
+ bool "TrueType glyph buffer to reduce malloc traffic"
+ depends on CONSOLE_TRUETYPE
+ default y
+ help
+ Enable a pre-allocated buffer for rendering glyph bitmaps. This
+ avoids malloc/free for each character rendered, reducing memory
+ fragmentation and improving performance.
+
+ The buffer starts at 4KB and grows via realloc() as needed to
+ accommodate larger glyphs.
+
+config VIDEO_GLYPH_STATS
+ bool "Track glyph rendering statistics"
+ depends on CONSOLE_TRUETYPE
+ default y if SANDBOX
+ help
+ Track cumulative glyph rendering statistics in global_data, so they
+ persist across video device rebinds. This allows seeing the total
+ count of glyphs rendered using the pre-allocated buffer vs. malloc
+ fallback. Use 'font info' to view the statistics.
+
config SYS_WHITE_ON_BLACK
bool "Display console as white on a black background"
default y if ARCH_AT91 || ARCH_EXYNOS || ARCH_ROCKCHIP || ARCH_TEGRA || X86 || ARCH_SUNXI
@@ -180,6 +180,10 @@ struct console_tt_metrics {
* @pos_start: Value of pos_ptr when the cursor is at the start of the text
* being entered by the user
* @pos_count: Maximum value reached by pos_ptr (initially zero)
+ * @glyph_buf: Pre-allocated buffer for rendering glyphs. If a glyph fits,
+ * this avoids malloc/free per character. Allocated lazily after
+ * relocation to avoid using early malloc space.
+ * @glyph_buf_size: Current size of glyph_buf in bytes
*/
struct console_tt_priv {
struct console_tt_metrics *cur_met;
@@ -190,6 +194,8 @@ struct console_tt_priv {
struct video_fontdata *cur_fontdata;
int pos_start;
int pos_count;
+ u8 *glyph_buf;
+ int glyph_buf_size;
};
/**
@@ -365,6 +371,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
int advance;
void *start, *end, *line;
int row, kern;
+ bool use_buf;
/* Use fixed font if selected */
if (priv->cur_fontdata)
@@ -440,13 +447,61 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
* information into the render, which will return a 8-bit-per-pixel
* image of the character. For empty characters, like ' ', data will
* return NULL;
+ *
+ * Use the pre-allocated glyph buffer if large enough, falling back to
+ * malloc for oversized glyphs. This avoids alloc/free traffic for
+ * normal characters.
*/
- data = stbtt_GetCodepointBitmapSubpixel(font, met->scale, met->scale,
- x_shift, 0, cp, &width, &height,
- &xoff, &yoff);
- if (!data)
+ {
+ int ix0, iy0, ix1, iy1;
+
+ stbtt_GetCodepointBitmapBoxSubpixel(font, cp, met->scale,
+ met->scale, x_shift, 0,
+ &ix0, &iy0, &ix1, &iy1);
+ width = ix1 - ix0;
+ height = iy1 - iy0;
+ xoff = ix0;
+ yoff = iy0;
+ }
+ if (!width || !height)
return width_frac;
+ /*
+ * Use the pre-allocated buffer if available and large enough. Allocate
+ * it lazily, but only after relocation to avoid using early malloc.
+ * Use realloc() to grow the buffer as needed.
+ */
+ use_buf = false;
+ if (IS_ENABLED(CONFIG_CONSOLE_TRUETYPE_GLYPH_BUF) &&
+ xpl_phase() >= PHASE_BOARD_R) {
+ int need_size = width * height;
+
+ if (need_size > priv->glyph_buf_size) {
+ int new_size = SZ_4K;
+
+ /* use the next power of 2 */
+ while (new_size < need_size)
+ new_size <<= 1;
+ priv->glyph_buf = realloc(priv->glyph_buf, new_size);
+ if (priv->glyph_buf)
+ priv->glyph_buf_size = new_size;
+ }
+ if (priv->glyph_buf) {
+ data = priv->glyph_buf;
+ use_buf = true;
+ }
+ }
+ if (!use_buf) {
+ data = malloc(width * height);
+ if (!data)
+ return width_frac;
+ }
+ gd_inc_glyph_count();
+
+ stbtt_MakeCodepointBitmapSubpixel(font, data, width, height, width,
+ met->scale, met->scale, x_shift, 0,
+ cp);
+
/* Figure out where to write the character in the frame buffer */
bits = data;
start = vid_priv->fb + y * vid_priv->line_length +
@@ -534,7 +589,8 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
break;
}
default:
- free(data);
+ if (!use_buf)
+ free(data);
return -ENOSYS;
}
@@ -547,7 +603,8 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y,
width,
height);
- free(data);
+ if (!use_buf)
+ free(data);
return width_frac;
}
@@ -365,6 +365,12 @@ struct global_data {
*/
ulong video_bottom;
#endif
+#if CONFIG_IS_ENABLED(VIDEO_GLYPH_STATS)
+ /**
+ * @glyph_count: number of glyphs rendered
+ */
+ uint glyph_count;
+#endif
#ifdef CONFIG_BOOTSTAGE
/**
* @bootstage: boot stage information
@@ -637,6 +643,14 @@ static_assert(sizeof(struct global_data) == GD_SIZE);
#define gd_pager_page_len() 0
#endif
+#if CONFIG_IS_ENABLED(VIDEO_GLYPH_STATS)
+#define gd_glyph_count() gd->glyph_count
+#define gd_inc_glyph_count() gd->glyph_count++
+#else
+#define gd_glyph_count() 0
+#define gd_inc_glyph_count()
+#endif
+
/**
* enum gd_flags - global data flags
*
@@ -98,3 +98,20 @@ static int font_test_base(struct unit_test_state *uts)
}
FONT_TEST(font_test_base, UTF_SCAN_PDATA | UTF_SCAN_FDT | UTF_CONSOLE |
UTF_DM);
+
+/* Test 'font info' command */
+static int font_test_info(struct unit_test_state *uts)
+{
+ int count;
+
+ if (!CONFIG_IS_ENABLED(VIDEO_GLYPH_STATS))
+ return -EAGAIN;
+
+ count = gd_glyph_count();
+ ut_assertok(run_command("font info", 0));
+ ut_assert_nextline("glyphs rendered: %u", count);
+ ut_assert_console_end();
+
+ return 0;
+}
+FONT_TEST(font_test_info, UTF_CONSOLE);