mirror of
https://github.com/lvgl/lvgl.git
synced 2026-02-06 06:02:10 +08:00
perf(vg_lite): add bitmap font cache for non-aligned fonts (#9343)
This commit is contained in:
5
Kconfig
5
Kconfig
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
204
src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c
Normal file
204
src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c
Normal 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*/
|
||||
69
src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.h
Normal file
69
src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.h
Normal 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*/
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user