video: truetype: Use pre-allocated buffer for glyph rendering
The TrueType console driver calls malloc/free for every character rendered, which causes significant memory fragmentation and allocation traffic. Add CONFIG_CONSOLE_TRUETYPE_GLYPH_BUF to enable a pre-allocated buffer in the driver's private data. The buffer starts at 4KB and grows via realloc() as needed. When rendering a glyph, use this buffer to avoid malloc/free for normal characters. The buffer is allocated lazily after relocation to avoid consuming early malloc space before the full heap is available. Add CONFIG_VIDEO_GLYPH_STATS (default y on sandbox) to track the number of glyphs rendered. Use 'font info' to view the count. Series-changes: 2 - Rename the Kconfig to just enable the feature: always allocate Co-developed-by: Claude Opus 4 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
24
cmd/font.c
24
cmd/font.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user