perf(vg_lite): add bitmap font cache for non-aligned fonts (#9343)

This commit is contained in:
VIFEX
2025-12-05 01:31:03 +08:00
committed by GitHub
parent a8b4599486
commit 7d3cc8d337
9 changed files with 323 additions and 12 deletions

View File

@@ -487,6 +487,11 @@ menu "LVGL configuration"
default 8
depends on LV_USE_DRAW_VG_LITE
config LV_VG_LITE_BITMAP_FONT_CACHE_CNT
int "VG-Lite unaligned bitmap font maximum cache number."
default 256
depends on LV_USE_DRAW_VG_LITE
config LV_VG_LITE_DISABLE_VLC_OP_CLOSE
bool "Remove VLC_OP_CLOSE path instruction (Workaround for NXP)"
default n

View File

@@ -322,6 +322,9 @@
/** VG-Lite stroke maximum cache number. */
#define LV_VG_LITE_STROKE_CACHE_CNT 32
/** VG-Lite unaligned bitmap font maximum cache number. */
#define LV_VG_LITE_BITMAP_FONT_CACHE_CNT 256
/** Remove VLC_OP_CLOSE path instruction (Workaround for NXP) **/
#define LV_VG_LITE_DISABLE_VLC_OP_CLOSE 0

View File

@@ -16,6 +16,7 @@
#include "lv_vg_lite_utils.h"
#include "lv_vg_lite_path.h"
#include "lv_vg_lite_pending.h"
#include "lv_vg_lite_bitmap_font_cache.h"
#include "../../misc/cache/lv_cache_entry_private.h"
#include "../../misc/lv_area_private.h"
#include "../../libs/freetype/lv_freetype_private.h"
@@ -85,16 +86,19 @@ void lv_draw_vg_lite_label_init(struct _lv_draw_vg_lite_unit_t * u)
lv_freetype_outline_add_event(freetype_outline_event_cb, LV_EVENT_ALL, u);
#endif /* LV_USE_FREETYPE */
u->bitmap_font_pending = lv_vg_lite_pending_create(sizeof(lv_font_glyph_dsc_t), 8);
lv_vg_lite_pending_set_free_cb(u->bitmap_font_pending, bitmap_cache_release_cb, NULL);
lv_vg_lite_bitmap_font_cache_init(u, LV_VG_LITE_BITMAP_FONT_CACHE_CNT);
u->letter_pending = lv_vg_lite_pending_create(sizeof(lv_font_glyph_dsc_t), 8);
lv_vg_lite_pending_set_free_cb(u->letter_pending, bitmap_cache_release_cb, NULL);
}
void lv_draw_vg_lite_label_deinit(struct _lv_draw_vg_lite_unit_t * u)
{
LV_ASSERT_NULL(u);
LV_ASSERT_NULL(u->bitmap_font_pending)
lv_vg_lite_pending_destroy(u->bitmap_font_pending);
u->bitmap_font_pending = NULL;
LV_ASSERT_NULL(u->letter_pending);
lv_vg_lite_pending_destroy(u->letter_pending);
u->letter_pending = NULL;
lv_vg_lite_bitmap_font_cache_deinit(u);
}
void lv_draw_vg_lite_letter(lv_draw_task_t * t, const lv_draw_letter_dsc_t * dsc, const lv_area_t * coords)
@@ -169,14 +173,23 @@ static void draw_letter_cb(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_
case LV_FONT_GLYPH_FORMAT_A3:
case LV_FONT_GLYPH_FORMAT_A4:
case LV_FONT_GLYPH_FORMAT_A8: {
const lv_font_t * resolved_font = glyph_draw_dsc->g->resolved_font;
vg_lite_buffer_t src_buf;
if(lv_font_has_static_bitmap(glyph_draw_dsc->g->resolved_font)) {
if(lv_font_has_static_bitmap(resolved_font)) {
if(!init_buffer_from_glyph_dsc(&src_buf, glyph_draw_dsc->g)) {
return;
}
}
else {
glyph_draw_dsc->glyph_data = lv_font_get_glyph_bitmap(glyph_draw_dsc->g, glyph_draw_dsc->_draw_buf);
if(resolved_font->release_glyph) {
/* For dynamic fonts, its internal implementation already supports cache management. */
glyph_draw_dsc->glyph_data = lv_font_get_glyph_bitmap(glyph_draw_dsc->g, glyph_draw_dsc->_draw_buf);
}
else {
/* For non-cached unaligned fonts, we need to manage the cache manually. */
glyph_draw_dsc->glyph_data = lv_vg_lite_bitmap_font_cache_get(u, glyph_draw_dsc->g);
}
if(!glyph_draw_dsc->glyph_data) {
return;
}
@@ -365,11 +378,7 @@ static void draw_letter_bitmap(lv_draw_task_t * t, const lv_draw_glyph_dsc_t * d
if(dsc->g->entry) {
/* Increment the cache reference count */
lv_cache_entry_acquire_data(dsc->g->entry);
lv_vg_lite_pending_add(u->bitmap_font_pending, dsc->g);
}
else if(!lv_font_has_static_bitmap(dsc->g->resolved_font)) {
/* If there is no caching or no static bitmap is used, wait for the GPU to finish before releasing the data. */
lv_vg_lite_finish(u);
lv_vg_lite_pending_add(u->letter_pending, dsc->g);
}
LV_PROFILER_DRAW_END;

View File

@@ -53,7 +53,9 @@ struct _lv_draw_vg_lite_unit_t {
lv_cache_t * stroke_cache;
lv_cache_t * bitmap_font_cache;
struct _lv_vg_lite_pending_t * bitmap_font_pending;
struct _lv_vg_lite_pending_t * letter_pending;
uint16_t flush_count;
uint16_t letter_count;

View File

@@ -0,0 +1,204 @@
/**
* @file lv_vg_lite_bitmap_font_cache.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_vg_lite_bitmap_font_cache.h"
#if LV_USE_DRAW_VG_LITE
#include "lv_draw_vg_lite_type.h"
#include "lv_vg_lite_pending.h"
#include "lv_vg_lite_utils.h"
#include "../../core/lv_global.h"
/*********************
* DEFINES
*********************/
#define font_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->font_draw_buf_handlers)
/**********************
* TYPEDEFS
**********************/
typedef struct {
/* key */
lv_font_glyph_dsc_t g_dsc;
/* value */
lv_draw_buf_t * draw_buf;
} cache_item_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void cache_release_cb(void * entry, void * user_data);
static bool cache_create_cb(cache_item_t * item, void * user_data);
static void cache_free_cb(cache_item_t * item, void * user_data);
static lv_cache_compare_res_t cache_compare_cb(const cache_item_t * lhs, const cache_item_t * rhs);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_vg_lite_bitmap_font_cache_init(struct _lv_draw_vg_lite_unit_t * unit, uint32_t cache_cnt)
{
LV_ASSERT_NULL(unit);
LV_ASSERT(unit->bitmap_font_cache == NULL);
LV_ASSERT(unit->bitmap_font_pending == NULL);
LV_ASSERT(cache_cnt > 0);
const lv_cache_ops_t ops = {
.compare_cb = (lv_cache_compare_cb_t)cache_compare_cb,
.create_cb = (lv_cache_create_cb_t)cache_create_cb,
.free_cb = (lv_cache_free_cb_t)cache_free_cb,
};
unit->bitmap_font_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(cache_item_t), cache_cnt, ops);
lv_cache_set_name(unit->bitmap_font_cache, "VG_BITMAP_FONT");
unit->bitmap_font_pending = lv_vg_lite_pending_create(sizeof(lv_cache_entry_t *), 8);
lv_vg_lite_pending_set_free_cb(unit->bitmap_font_pending, cache_release_cb, unit->bitmap_font_cache);
}
void lv_vg_lite_bitmap_font_cache_deinit(struct _lv_draw_vg_lite_unit_t * unit)
{
LV_ASSERT_NULL(unit);
LV_ASSERT_NULL(unit->bitmap_font_cache);
LV_ASSERT_NULL(unit->bitmap_font_pending);
lv_vg_lite_pending_destroy(unit->bitmap_font_pending);
unit->bitmap_font_pending = NULL;
lv_cache_destroy(unit->bitmap_font_cache, NULL);
unit->bitmap_font_cache = NULL;
}
lv_draw_buf_t * lv_vg_lite_bitmap_font_cache_get(struct _lv_draw_vg_lite_unit_t * unit,
const lv_font_glyph_dsc_t * g_dsc)
{
LV_PROFILER_FONT_BEGIN;
LV_ASSERT_NULL(unit);
LV_ASSERT_NULL(g_dsc);
uint32_t gid = g_dsc->gid.index;
if(!gid) {
LV_PROFILER_FONT_END;
return NULL;
}
cache_item_t search_key = { 0 };
search_key.g_dsc = *g_dsc;
lv_cache_entry_t * cache_node_entry = lv_cache_acquire(unit->bitmap_font_cache, &search_key, NULL);
if(cache_node_entry == NULL) {
/* check if the cache is full */
size_t free_size = lv_cache_get_free_size(unit->bitmap_font_cache, NULL);
if(free_size == 0) {
LV_LOG_INFO("bitmap font cache is full, release all pending cache entries");
lv_vg_lite_finish(unit);
}
cache_node_entry = lv_cache_acquire_or_create(unit->bitmap_font_cache, &search_key, NULL);
if(cache_node_entry == NULL) {
LV_LOG_ERROR("bitmap cache creating failed");
LV_PROFILER_FONT_END;
return NULL;
}
}
/* Add the new entry to the pending list */
lv_vg_lite_pending_add(unit->bitmap_font_pending, &cache_node_entry);
cache_item_t * cache_item = lv_cache_entry_get_data(cache_node_entry);
LV_PROFILER_FONT_END;
return cache_item->draw_buf;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void cache_release_cb(void * entry, void * user_data)
{
lv_cache_entry_t ** entry_p = entry;
lv_cache_t * cache = user_data;
lv_cache_release(cache, *entry_p, NULL);
}
static bool cache_create_cb(cache_item_t * item, void * user_data)
{
LV_UNUSED(user_data);
LV_PROFILER_FONT_BEGIN;
LV_LOG_TRACE("gid: %" LV_PRIu32 ", W%" LV_PRIu32 "xH%" LV_PRIu32,
item->g_dsc.gid.index, item->g_dsc.box_w, item->g_dsc.box_h);
lv_draw_buf_t * draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers,
item->g_dsc.box_w,
item->g_dsc.box_h,
LV_COLOR_FORMAT_A8,
LV_STRIDE_AUTO);
if(!draw_buf) {
LV_LOG_ERROR("Failed to create draw buffer for bitmap font cache");
LV_PROFILER_FONT_END;
return false;
}
if(!lv_font_get_glyph_bitmap(&item->g_dsc, draw_buf)) {
LV_LOG_WARN("Failed to get glyph bitmap for bitmap font cache");
lv_draw_buf_destroy(draw_buf);
LV_PROFILER_FONT_END;
return false;
}
item->draw_buf = draw_buf;
LV_PROFILER_FONT_END;
return true;
}
static void cache_free_cb(cache_item_t * item, void * user_data)
{
LV_UNUSED(user_data);
LV_PROFILER_FONT_BEGIN;
LV_LOG_TRACE("gid: %" LV_PRIu32 ", W%" LV_PRIu32 "xH%" LV_PRIu32,
item->g_dsc.gid.index, item->g_dsc.box_w, item->g_dsc.box_h);
lv_draw_buf_destroy(item->draw_buf);
item->draw_buf = NULL;
LV_PROFILER_FONT_END;
}
static lv_cache_compare_res_t cache_compare_cb(const cache_item_t * lhs, const cache_item_t * rhs)
{
/* Because const font pointers are unique, matching can be performed using only the pointer. */
if(lhs->g_dsc.resolved_font != rhs->g_dsc.resolved_font) {
return lhs->g_dsc.resolved_font > rhs->g_dsc.resolved_font ? 1 : -1;
}
if(lhs->g_dsc.gid.index != rhs->g_dsc.gid.index) {
return lhs->g_dsc.gid.index > rhs->g_dsc.gid.index ? 1 : -1;
}
return 0;
}
#endif /*LV_USE_DRAW_VG_LITE*/

View File

@@ -0,0 +1,69 @@
/**
* @file lv_vg_lite_bitmap_font_cache.h
*
*/
#ifndef LV_VG_LITE_BITMAP_FONT_CACHE_H
#define LV_VG_LITE_BITMAP_FONT_CACHE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_DRAW_VG_LITE
#include "../../font/lv_font.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct _lv_draw_vg_lite_unit_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Initialize the bitmap font cache for VG-Lite draw unit
* @param unit pointer to the VG-Lite draw unit
* @param cache_cnt number of cache entries to allocate
*/
void lv_vg_lite_bitmap_font_cache_init(struct _lv_draw_vg_lite_unit_t * unit, uint32_t cache_cnt);
/**
* @brief Deinitialize the bitmap font cache for VG-Lite draw unit
* @param unit pointer to the VG-Lite draw unit
*/
void lv_vg_lite_bitmap_font_cache_deinit(struct _lv_draw_vg_lite_unit_t * unit);
/**
* @brief Get the bitmap font cache entry for a given font and letter
* @param unit pointer to the VG-Lite draw unit
* @param g_dsc pointer to the glyph descriptor
* @return pointer to the draw buffer containing the cached bitmap font glyph, or NULL if the glyph ID is 0 or if cache creation fails
*/
lv_draw_buf_t * lv_vg_lite_bitmap_font_cache_get(struct _lv_draw_vg_lite_unit_t * unit,
const lv_font_glyph_dsc_t * g_dsc);
/**********************
* MACROS
**********************/
#endif /*LV_USE_DRAW_VG_LITE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_VG_LITE_BITMAP_FONT_CACHE_H*/

View File

@@ -1386,6 +1386,7 @@ void lv_vg_lite_flush(struct _lv_draw_vg_lite_unit_t * u)
lv_vg_lite_pending_swap(u->image_dsc_pending);
lv_vg_lite_pending_swap(u->bitmap_font_pending);
lv_vg_lite_pending_swap(u->letter_pending);
u->flush_count = 0;
LV_PROFILER_DRAW_END;
@@ -1408,6 +1409,7 @@ void lv_vg_lite_finish(struct _lv_draw_vg_lite_unit_t * u)
/* Clear bitmap font dsc reference */
lv_vg_lite_pending_remove_all(u->bitmap_font_pending);
lv_vg_lite_pending_remove_all(u->letter_pending);
/* Reset scissor area */
lv_memzero(&u->current_scissor_area, sizeof(u->current_scissor_area));

View File

@@ -461,6 +461,13 @@ static int32_t load_glyph(lv_fs_file_t * fp, lv_font_fmt_txt_dsc_t * font_dsc,
return glyph_length;
}
static void release_glyph_cb(const lv_font_t * font, lv_font_glyph_dsc_t * glyph_dsc)
{
LV_UNUSED(font);
LV_UNUSED(glyph_dsc);
/*No custom memory management needed*/
}
/*
* Loads a `lv_font_t` from a binary file, given a `lv_fs_file_t`.
*
@@ -497,6 +504,7 @@ static bool lvgl_load_font(lv_fs_file_t * fp, lv_font_t * font)
font->line_height = font_header.ascent - font_header.descent;
font->get_glyph_dsc = lv_font_get_glyph_dsc_fmt_txt;
font->get_glyph_bitmap = lv_font_get_bitmap_fmt_txt;
font->release_glyph = release_glyph_cb;
font->subpx = font_header.subpixels_mode;
font->underline_position = (int8_t) font_header.underline_position;
font->underline_thickness = (int8_t) font_header.underline_thickness;

View File

@@ -913,6 +913,15 @@
#endif
#endif
/** VG-Lite unaligned bitmap font maximum cache number. */
#ifndef LV_VG_LITE_BITMAP_FONT_CACHE_CNT
#ifdef CONFIG_LV_VG_LITE_BITMAP_FONT_CACHE_CNT
#define LV_VG_LITE_BITMAP_FONT_CACHE_CNT CONFIG_LV_VG_LITE_BITMAP_FONT_CACHE_CNT
#else
#define LV_VG_LITE_BITMAP_FONT_CACHE_CNT 256
#endif
#endif
/** Remove VLC_OP_CLOSE path instruction (Workaround for NXP) **/
#ifndef LV_VG_LITE_DISABLE_VLC_OP_CLOSE
#ifdef CONFIG_LV_VG_LITE_DISABLE_VLC_OP_CLOSE