diff --git a/Kconfig b/Kconfig index cd82433968..36a1fa1d5c 100644 --- a/Kconfig +++ b/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 diff --git a/lv_conf_template.h b/lv_conf_template.h index 7fce501e43..fc91e0b5c6 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -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 diff --git a/src/draw/vg_lite/lv_draw_vg_lite_label.c b/src/draw/vg_lite/lv_draw_vg_lite_label.c index 9ab37bfc4d..2b24849421 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_label.c +++ b/src/draw/vg_lite/lv_draw_vg_lite_label.c @@ -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; diff --git a/src/draw/vg_lite/lv_draw_vg_lite_type.h b/src/draw/vg_lite/lv_draw_vg_lite_type.h index 1afe4ede3f..1dd11790bf 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_type.h +++ b/src/draw/vg_lite/lv_draw_vg_lite_type.h @@ -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; diff --git a/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c b/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c new file mode 100644 index 0000000000..92ef185b8c --- /dev/null +++ b/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.c @@ -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*/ diff --git a/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.h b/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.h new file mode 100644 index 0000000000..dac0c3c870 --- /dev/null +++ b/src/draw/vg_lite/lv_vg_lite_bitmap_font_cache.h @@ -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*/ diff --git a/src/draw/vg_lite/lv_vg_lite_utils.c b/src/draw/vg_lite/lv_vg_lite_utils.c index f57af972c3..dbe169caa6 100644 --- a/src/draw/vg_lite/lv_vg_lite_utils.c +++ b/src/draw/vg_lite/lv_vg_lite_utils.c @@ -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)); diff --git a/src/font/binfont_loader/lv_binfont_loader.c b/src/font/binfont_loader/lv_binfont_loader.c index a911d882b0..c175d859ae 100644 --- a/src/font/binfont_loader/lv_binfont_loader.c +++ b/src/font/binfont_loader/lv_binfont_loader.c @@ -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; diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 72ceb90126..c1748434bb 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -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