From 64bd9053a25297f7a442ca831c7da5b44bd33f84 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 12 Jun 2024 17:54:40 +1000 Subject: Update LVGL to v9.1.0 --- lib/lvgl/src/misc/cache/_lv_cache_lru_rb.c | 464 +++++++++++++++++++++++ lib/lvgl/src/misc/cache/_lv_cache_lru_rb.h | 44 +++ lib/lvgl/src/misc/cache/lv_cache.c | 275 ++++++++++++++ lib/lvgl/src/misc/cache/lv_cache.h | 206 ++++++++++ lib/lvgl/src/misc/cache/lv_cache_entry.c | 167 ++++++++ lib/lvgl/src/misc/cache/lv_cache_entry.h | 116 ++++++ lib/lvgl/src/misc/cache/lv_cache_entry_private.h | 51 +++ lib/lvgl/src/misc/cache/lv_cache_private.h | 190 ++++++++++ lib/lvgl/src/misc/cache/lv_image_cache.c | 109 ++++++ lib/lvgl/src/misc/cache/lv_image_cache.h | 69 ++++ 10 files changed, 1691 insertions(+) create mode 100644 lib/lvgl/src/misc/cache/_lv_cache_lru_rb.c create mode 100644 lib/lvgl/src/misc/cache/_lv_cache_lru_rb.h create mode 100644 lib/lvgl/src/misc/cache/lv_cache.c create mode 100644 lib/lvgl/src/misc/cache/lv_cache.h create mode 100644 lib/lvgl/src/misc/cache/lv_cache_entry.c create mode 100644 lib/lvgl/src/misc/cache/lv_cache_entry.h create mode 100644 lib/lvgl/src/misc/cache/lv_cache_entry_private.h create mode 100644 lib/lvgl/src/misc/cache/lv_cache_private.h create mode 100644 lib/lvgl/src/misc/cache/lv_image_cache.c create mode 100644 lib/lvgl/src/misc/cache/lv_image_cache.h (limited to 'lib/lvgl/src/misc/cache') diff --git a/lib/lvgl/src/misc/cache/_lv_cache_lru_rb.c b/lib/lvgl/src/misc/cache/_lv_cache_lru_rb.c new file mode 100644 index 00000000..097f764f --- /dev/null +++ b/lib/lvgl/src/misc/cache/_lv_cache_lru_rb.c @@ -0,0 +1,464 @@ +/** +* @file _lv_cache_lru_rb.c +* +*/ + +/***************************************************************************\ +* * +* ┏ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ┓ * +* ┏ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ┌ ─ ─ ─ ┐ * +* ┌ ─ ─ ─ ─ ─ ─ ─ ┃ ┃ Cache insert ┃ * +* ┃ RB Tree │ │Hitting│ head * +* └ ─ ─ ─ ─ ─ ─ ─ ┃ ┃ ─ ─ ─ ─ ┃ * +* ┃ ┌─┬─┬─┬─┐ ┌─────┐ * +* ┌──│◄│B│►│ │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┃─ ─ ╋ ─ ─▶│ B │ ┃ * +* ┃ │ └─┴─┴─┴─┘ └──▲──┘ * +* │ │ ┃ ┃ │ ┃ * +* ┃ │ │ ┌──┴──┐ * +* │ └──────┐ ┌ ─┃─ ─ ╋ ─ ─▶│ E │ ┃ * +* ┃ ▼ ┌ ─ ─│─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ └──▲──┘ * +* ┌─┬─┬─┬─┐ ▼ │ ┃ ┃ │ ┃ * +* ┃│◄│A│►│ │─ ─ ┘ ┌─┬─┬─┬─┐ │ ┌──┴──┐ * +* └─┴─┴─┴─┘ ┌───│◄│D│►│ │─ ─ ─ ─ ─ ─│─ ╋ ┐ ┃ ─ ▶│ A │ ┌ ─ ─ ─ ─ ─ ┐ ┃ * +* ┃ │ └─┴─┴─┴─┘ └──▲──┘ LRU * +* │ │ │ ┃ │ ┃ │ │ Cache │ ┃ * +* ┃ ▼ └──────┐ ┌──┴──┐ ─ ─ ─ ─ ─ ─ * +* ┌─┬─┬─┬─┐ ▼ │ ┃ └ ─┃─ ─ ▶│ D │ ┃ * +* ┃ │◄│C│►│ │─ ─ ┌─┬─┬─┬─┐ └──▲──┘ * +* └─┴─┴─┴─┘ │ │◄│E│►│ │─ ┘ ┃ ┃ │ ┃ * +* ┃ └─┴─┴─┴─┘ ┌──┴──┐ * +* │ │ ─ ╋ ─ ─┃─ ─ ▶│ C │ ┃ * +* ┃ ─ ─ ─ ─ ┼ ─ ─ ┘ └──▲──┘ * +* ▼ ┃ ┃ ┌ ─ ─│─ ─ ┐ ┃ * +* ┃ ┌─┬─┬─┬─┐ ┌──┴──┐ * +* │◄│F│►│ │─ ─┃─ ─ ╋ ─ ┼▶│ F │ │ ┃ * +* ┃ └─┴─┴─┴─┘ └─────┘ * +* ┃ ┃ └ ─ ─ ─ ─ ┘ ┃ * +* ┃ remove * +* ┃ ┃ tail ┃ * +* ┗ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ ━ * +* * +\***************************************************************************/ + +/********************* + * INCLUDES + *********************/ +#include "_lv_cache_lru_rb.h" +#include "../../stdlib/lv_sprintf.h" +#include "../../stdlib/lv_string.h" +#include "../lv_ll.h" +#include "../lv_rb.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +typedef uint32_t (get_data_size_cb_t)(const void * data); + +struct _lv_lru_rb_t { + lv_cache_t cache; + + lv_rb_t rb; + lv_ll_t ll; + + get_data_size_cb_t * get_data_size_cb; +}; +typedef struct _lv_lru_rb_t lv_lru_rb_t_; +/********************** + * STATIC PROTOTYPES + **********************/ + +static void * alloc_cb(void); +static bool init_cnt_cb(lv_cache_t * cache); +static bool init_size_cb(lv_cache_t * cache); +static void destroy_cb(lv_cache_t * cache, void * user_data); + +static lv_cache_entry_t * get_cb(lv_cache_t * cache, const void * key, void * user_data); +static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * user_data); +static void remove_cb(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); +static void drop_cb(lv_cache_t * cache, const void * key, void * user_data); +static void drop_all_cb(lv_cache_t * cache, void * user_data); +static lv_cache_entry_t * get_victim_cb(lv_cache_t * cache, void * user_data); +static lv_cache_reserve_cond_res_t reserve_cond_cb(lv_cache_t * cache, const void * key, size_t reserved_size, + void * user_data); + +static void * alloc_new_node(lv_lru_rb_t_ * lru, void * key, void * user_data); +inline static void ** get_lru_node(lv_lru_rb_t_ * lru, lv_rb_node_t * node); + +static uint32_t cnt_get_data_size_cb(const void * data); +static uint32_t size_get_data_size_cb(const void * data); + +/********************** + * GLOBAL VARIABLES + **********************/ +const lv_cache_class_t lv_cache_class_lru_rb_count = { + .alloc_cb = alloc_cb, + .init_cb = init_cnt_cb, + .destroy_cb = destroy_cb, + + .get_cb = get_cb, + .add_cb = add_cb, + .remove_cb = remove_cb, + .drop_cb = drop_cb, + .drop_all_cb = drop_all_cb, + .get_victim_cb = get_victim_cb, + .reserve_cond_cb = reserve_cond_cb +}; + +const lv_cache_class_t lv_cache_class_lru_rb_size = { + .alloc_cb = alloc_cb, + .init_cb = init_size_cb, + .destroy_cb = destroy_cb, + + .get_cb = get_cb, + .add_cb = add_cb, + .remove_cb = remove_cb, + .drop_cb = drop_cb, + .drop_all_cb = drop_all_cb, + .get_victim_cb = get_victim_cb, + .reserve_cond_cb = reserve_cond_cb +}; +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ +static void * alloc_new_node(lv_lru_rb_t_ * lru, void * key, void * user_data) +{ + LV_UNUSED(user_data); + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return NULL; + } + + lv_rb_node_t * node = lv_rb_insert(&lru->rb, key); + if(node == NULL) + goto FAILED_HANDLER2; + + void * data = node->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, lru->cache.node_size); + lv_memcpy(data, key, lru->cache.node_size); + + void * lru_node = _lv_ll_ins_head(&lru->ll); + if(lru_node == NULL) + goto FAILED_HANDLER1; + + lv_memcpy(lru_node, &node, sizeof(void *)); + lv_memcpy(get_lru_node(lru, node), &lru_node, sizeof(void *)); + + lv_cache_entry_init(entry, &lru->cache, lru->cache.node_size); + goto FAILED_HANDLER2; + +FAILED_HANDLER1: + lv_rb_drop_node(&lru->rb, node); + node = NULL; +FAILED_HANDLER2: + return node; +} + +inline static void ** get_lru_node(lv_lru_rb_t_ * lru, lv_rb_node_t * node) +{ + return (void **)((char *)node->data + lru->rb.size - sizeof(void *)); +} + +static void * alloc_cb(void) +{ + void * res = lv_malloc(sizeof(lv_lru_rb_t_)); + LV_ASSERT_MALLOC(res); + if(res == NULL) { + LV_LOG_ERROR("malloc failed"); + return NULL; + } + + lv_memzero(res, sizeof(lv_lru_rb_t_)); + return res; +} + +static bool init_cnt_cb(lv_cache_t * cache) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru->cache.ops.compare_cb); + LV_ASSERT_NULL(lru->cache.ops.free_cb); + LV_ASSERT(lru->cache.node_size > 0); + + if(lru->cache.node_size <= 0 || lru->cache.max_size <= 0 + || lru->cache.ops.compare_cb == NULL || lru->cache.ops.free_cb == NULL) { + return false; + } + + /*add void* to store the ll node pointer*/ + if(!lv_rb_init(&lru->rb, lru->cache.ops.compare_cb, lv_cache_entry_get_size(lru->cache.node_size) + sizeof(void *))) { + return false; + } + _lv_ll_init(&lru->ll, sizeof(void *)); + + lru->get_data_size_cb = cnt_get_data_size_cb; + + return true; +} + +static bool init_size_cb(lv_cache_t * cache) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru->cache.ops.compare_cb); + LV_ASSERT_NULL(lru->cache.ops.free_cb); + LV_ASSERT(lru->cache.node_size > 0); + + if(lru->cache.node_size <= 0 || lru->cache.max_size <= 0 + || lru->cache.ops.compare_cb == NULL || lru->cache.ops.free_cb == NULL) { + return false; + } + + /*add void* to store the ll node pointer*/ + if(!lv_rb_init(&lru->rb, lru->cache.ops.compare_cb, lv_cache_entry_get_size(lru->cache.node_size) + sizeof(void *))) { + return false; + } + _lv_ll_init(&lru->ll, sizeof(void *)); + + lru->get_data_size_cb = size_get_data_size_cb; + + return true; +} + +static void destroy_cb(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + if(lru == NULL) { + return; + } + + cache->clz->drop_all_cb(cache, user_data); +} + +static lv_cache_entry_t * get_cb(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return NULL; + } + + /*try the first ll node first*/ + void * head = _lv_ll_get_head(&lru->ll); + if(head) { + lv_rb_node_t * node = *(lv_rb_node_t **)head; + void * data = node->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, cache->node_size); + if(lru->cache.ops.compare_cb(data, key) == 0) { + return entry; + } + } + + lv_rb_node_t * node = lv_rb_find(&lru->rb, key); + /*cache hit*/ + if(node) { + void * lru_node = *get_lru_node(lru, node); + head = _lv_ll_get_head(&lru->ll); + _lv_ll_move_before(&lru->ll, lru_node, head); + + lv_cache_entry_t * entry = lv_cache_entry_get_entry(node->data, cache->node_size); + return entry; + } + return NULL; +} + +static lv_cache_entry_t * add_cb(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return NULL; + } + + lv_rb_node_t * new_node = alloc_new_node(lru, (void *)key, user_data); + if(new_node == NULL) { + return NULL; + } + + lv_cache_entry_t * entry = lv_cache_entry_get_entry(new_node->data, cache->node_size); + + cache->size += lru->get_data_size_cb(key); + + return entry; +} + +static void remove_cb(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(entry); + + if(lru == NULL || entry == NULL) { + return; + } + + void * data = lv_cache_entry_get_data(entry); + lv_rb_node_t * node = lv_rb_find(&lru->rb, data); + if(node == NULL) { + return; + } + + void * lru_node = *get_lru_node(lru, node); + lv_rb_remove_node(&lru->rb, node); + _lv_ll_remove(&lru->ll, lru_node); + lv_free(lru_node); + + cache->size -= lru->get_data_size_cb(data); +} + +static void drop_cb(lv_cache_t * cache, const void * key, void * user_data) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + LV_ASSERT_NULL(key); + + if(lru == NULL || key == NULL) { + return; + } + + lv_rb_node_t * node = lv_rb_find(&lru->rb, key); + if(node == NULL) { + return; + } + + void * data = node->data; + + lru->cache.ops.free_cb(data, user_data); + cache->size -= lru->get_data_size_cb(data); + + lv_cache_entry_t * entry = lv_cache_entry_get_entry(data, cache->node_size); + void * lru_node = *get_lru_node(lru, node); + + lv_rb_remove_node(&lru->rb, node); + lv_cache_entry_delete(entry); + + _lv_ll_remove(&lru->ll, lru_node); + lv_free(lru_node); +} + +static void drop_all_cb(lv_cache_t * cache, void * user_data) +{ + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + if(lru == NULL) { + return; + } + + uint32_t used_cnt = 0; + lv_rb_node_t ** node; + _LV_LL_READ(&lru->ll, node) { + /*free user handled data and do other clean up*/ + void * search_key = (*node)->data; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(search_key, cache->node_size); + if(lv_cache_entry_get_ref(entry) == 0) { + lru->cache.ops.free_cb(search_key, user_data); + } + else { + LV_LOG_WARN("entry (%p) is still referenced (%" LV_PRId32 ")", (void *)entry, lv_cache_entry_get_ref(entry)); + used_cnt++; + } + } + if(used_cnt > 0) { + LV_LOG_WARN("%" LV_PRId32 " entries are still referenced", used_cnt); + } + + lv_rb_destroy(&lru->rb); + _lv_ll_clear(&lru->ll); + + cache->size = 0; +} + +static lv_cache_entry_t * get_victim_cb(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + lv_rb_node_t ** tail; + _LV_LL_READ_BACK(&lru->ll, tail) { + lv_rb_node_t * tail_node = *tail; + lv_cache_entry_t * entry = lv_cache_entry_get_entry(tail_node->data, cache->node_size); + if(lv_cache_entry_get_ref(entry) == 0) { + return entry; + } + } + + return NULL; +} + +static lv_cache_reserve_cond_res_t reserve_cond_cb(lv_cache_t * cache, const void * key, size_t reserved_size, + void * user_data) +{ + LV_UNUSED(user_data); + + lv_lru_rb_t_ * lru = (lv_lru_rb_t_ *)cache; + + LV_ASSERT_NULL(lru); + + if(lru == NULL) { + return LV_CACHE_RESERVE_COND_ERROR; + } + + uint32_t data_size = key ? lru->get_data_size_cb(key) : 0; + if(data_size > lru->cache.max_size) { + LV_LOG_ERROR("data size (%" LV_PRIu32 ") is larger than max size (%" LV_PRIu32 ")", data_size, lru->cache.max_size); + return LV_CACHE_RESERVE_COND_TOO_LARGE; + } + + return cache->size + reserved_size + data_size > lru->cache.max_size + ? LV_CACHE_RESERVE_COND_NEED_VICTIM + : LV_CACHE_RESERVE_COND_OK; +} + +static uint32_t cnt_get_data_size_cb(const void * data) +{ + LV_UNUSED(data); + return 1; +} + +static uint32_t size_get_data_size_cb(const void * data) +{ + lv_cache_slot_size_t * slot = (lv_cache_slot_size_t *)data; + return slot->size; +} diff --git a/lib/lvgl/src/misc/cache/_lv_cache_lru_rb.h b/lib/lvgl/src/misc/cache/_lv_cache_lru_rb.h new file mode 100644 index 00000000..a27110b9 --- /dev/null +++ b/lib/lvgl/src/misc/cache/_lv_cache_lru_rb.h @@ -0,0 +1,44 @@ +/** +* @file _lv_cache_lru_rb.h +* +*/ + +#ifndef LV_CACHE_LRU_RB_H +#define LV_CACHE_LRU_RB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_entry.h" +#include "lv_cache_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/************************* + * GLOBAL VARIABLES + *************************/ +LV_ATTRIBUTE_EXTERN_DATA extern const lv_cache_class_t lv_cache_class_lru_rb_count; +LV_ATTRIBUTE_EXTERN_DATA extern const lv_cache_class_t lv_cache_class_lru_rb_size; +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_LRU_RB_H*/ diff --git a/lib/lvgl/src/misc/cache/lv_cache.c b/lib/lvgl/src/misc/cache/lv_cache.c new file mode 100644 index 00000000..e22cd9e4 --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_cache.c @@ -0,0 +1,275 @@ +/** +* @file lv_cache.c +* +*/ + +/********************* + * INCLUDES + *********************/ +#include "lv_cache.h" +#include "../../stdlib/lv_sprintf.h" +#include "../lv_assert.h" +#include "lv_cache_entry_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data); +static bool cache_evict_one_internal_no_lock(lv_cache_t * cache, void * user_data); +static lv_cache_entry_t * cache_add_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data); +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_cache_t * lv_cache_create(const lv_cache_class_t * cache_class, + size_t node_size, size_t max_size, + lv_cache_ops_t ops) +{ + lv_cache_t * cache = cache_class->alloc_cb(); + LV_ASSERT_MALLOC(cache); + + cache->clz = cache_class; + cache->node_size = node_size; + cache->max_size = max_size; + cache->size = 0; + cache->ops = ops; + + if(cache->clz->init_cb(cache) == false) { + LV_LOG_ERROR("Cache init failed"); + lv_free(cache); + return NULL; + } + + lv_mutex_init(&cache->lock); + + return cache; +} + +void lv_cache_destroy(lv_cache_t * cache, void * user_data) +{ + LV_ASSERT_NULL(cache); + + lv_mutex_lock(&cache->lock); + cache->clz->destroy_cb(cache, user_data); + lv_mutex_unlock(&cache->lock); + lv_mutex_delete(&cache->lock); + lv_free(cache); +} + +lv_cache_entry_t * lv_cache_acquire(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); + if(entry != NULL) { + lv_cache_entry_acquire_data(entry); + } + lv_mutex_unlock(&cache->lock); + return entry; +} +void lv_cache_release(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data) +{ + LV_ASSERT_NULL(entry); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_release_data(entry, user_data); + + if(lv_cache_entry_get_ref(entry) == 0 && lv_cache_entry_is_invalid(entry)) { + cache->ops.free_cb(lv_cache_entry_get_data(entry), user_data); + lv_cache_entry_delete(entry); + } + lv_mutex_unlock(&cache->lock); +} +lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_t * entry = cache_add_internal_no_lock(cache, key, user_data); + if(entry != NULL) { + lv_cache_entry_acquire_data(entry); + } + lv_mutex_unlock(&cache->lock); + + return entry; +} +lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); + if(entry != NULL) { + lv_cache_entry_acquire_data(entry); + lv_mutex_unlock(&cache->lock); + return entry; + } + entry = cache_add_internal_no_lock(cache, key, user_data); + if(entry == NULL) { + lv_mutex_unlock(&cache->lock); + return NULL; + } + bool create_res = cache->ops.create_cb(lv_cache_entry_get_data(entry), user_data); + if(create_res == false) { + cache->clz->remove_cb(cache, entry, user_data); + lv_cache_entry_delete(entry); + entry = NULL; + } + else { + lv_cache_entry_acquire_data(entry); + } + lv_mutex_unlock(&cache->lock); + return entry; +} +void lv_cache_reserve(lv_cache_t * cache, uint32_t reserved_size, void * user_data) +{ + LV_ASSERT_NULL(cache); + + for(lv_cache_reserve_cond_res_t reserve_cond_res = cache->clz->reserve_cond_cb(cache, NULL, reserved_size, user_data); + reserve_cond_res == LV_CACHE_RESERVE_COND_NEED_VICTIM; + reserve_cond_res = cache->clz->reserve_cond_cb(cache, NULL, reserved_size, user_data)) + cache_evict_one_internal_no_lock(cache, user_data); + +} +void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data) +{ + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(key); + + lv_mutex_lock(&cache->lock); + cache_drop_internal_no_lock(cache, key, user_data); + lv_mutex_unlock(&cache->lock); +} +bool lv_cache_evict_one(lv_cache_t * cache, void * user_data) +{ + LV_ASSERT_NULL(cache); + + lv_mutex_lock(&cache->lock); + bool res = cache_evict_one_internal_no_lock(cache, user_data); + lv_mutex_unlock(&cache->lock); + + return res; +} +void lv_cache_drop_all(lv_cache_t * cache, void * user_data) +{ + LV_ASSERT_NULL(cache); + + lv_mutex_lock(&cache->lock); + cache->clz->drop_all_cb(cache, user_data); + lv_mutex_unlock(&cache->lock); +} + +void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data) +{ + LV_UNUSED(user_data); + cache->max_size = max_size; +} +size_t lv_cache_get_max_size(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + return cache->max_size; +} +size_t lv_cache_get_size(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + return cache->size; +} +size_t lv_cache_get_free_size(lv_cache_t * cache, void * user_data) +{ + LV_UNUSED(user_data); + return cache->max_size - cache->size; +} +void lv_cache_set_compare_cb(lv_cache_t * cache, lv_cache_compare_cb_t compare_cb, void * user_data) +{ + LV_UNUSED(user_data); + cache->ops.compare_cb = compare_cb; +} +void lv_cache_set_create_cb(lv_cache_t * cache, lv_cache_create_cb_t alloc_cb, void * user_data) +{ + LV_UNUSED(user_data); + cache->ops.create_cb = alloc_cb; +} +void lv_cache_set_free_cb(lv_cache_t * cache, lv_cache_free_cb_t free_cb, void * user_data) +{ + LV_UNUSED(user_data); + cache->ops.free_cb = free_cb; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void cache_drop_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data) +{ + lv_cache_entry_t * entry = cache->clz->get_cb(cache, key, user_data); + if(entry == NULL) { + return; + } + + if(lv_cache_entry_get_ref(entry) == 0) { + cache->clz->remove_cb(cache, entry, user_data); + cache->ops.free_cb(lv_cache_entry_get_data(entry), user_data); + lv_cache_entry_delete(entry); + } + else { + lv_cache_entry_set_invalid(entry, true); + cache->clz->remove_cb(cache, entry, user_data); + } +} + +static bool cache_evict_one_internal_no_lock(lv_cache_t * cache, void * user_data) +{ + lv_cache_entry_t * victim = cache->clz->get_victim_cb(cache, user_data); + + if(victim == NULL) { + LV_LOG_ERROR("No victim found"); + return false; + } + + cache->clz->remove_cb(cache, victim, user_data); + cache->ops.free_cb(lv_cache_entry_get_data(victim), user_data); + lv_cache_entry_delete(victim); + return true; +} + +static lv_cache_entry_t * cache_add_internal_no_lock(lv_cache_t * cache, const void * key, void * user_data) +{ + lv_cache_reserve_cond_res_t reserve_cond_res = cache->clz->reserve_cond_cb(cache, key, 0, user_data); + if(reserve_cond_res == LV_CACHE_RESERVE_COND_TOO_LARGE) { + LV_LOG_ERROR("data %p is too large that exceeds max size (%" LV_PRIu32 ")", key, cache->max_size); + return NULL; + } + + for(; reserve_cond_res == LV_CACHE_RESERVE_COND_NEED_VICTIM; + reserve_cond_res = cache->clz->reserve_cond_cb(cache, key, 0, user_data)) + if(cache_evict_one_internal_no_lock(cache, user_data) == false) + return NULL; + + lv_cache_entry_t * entry = cache->clz->add_cb(cache, key, user_data); + + return entry; +} diff --git a/lib/lvgl/src/misc/cache/lv_cache.h b/lib/lvgl/src/misc/cache/lv_cache.h new file mode 100644 index 00000000..25db6fce --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_cache.h @@ -0,0 +1,206 @@ +/** +* @file lv_cache.h +* +*/ + +#ifndef LV_CACHE1_H +#define LV_CACHE1_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_entry.h" +#include "lv_cache_private.h" +#include +#include + +#include "_lv_cache_lru_rb.h" + +#include "lv_image_cache.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Create a cache object with the given parameters. + * @param cache_class The class of the cache. Currently only support one two builtin classes: + * @lv_cache_class_lru_rb_count for LRU-based cache with count-based eviction policy. + * @lv_cache_class_lru_rb_size for LRU-based cache with size-based eviction policy. + * @param node_size The node size is the size of the data stored in the cache.. + * @param max_size The max size is the maximum amount of memory or count that the cache can hold. + * @lv_cache_class_lru_rb_count: max_size is the maximum count of nodes in the cache. + * @lv_cache_class_lru_rb_size: max_size is the maximum size of the cache in bytes. + * @param ops A set of operations that can be performed on the cache. See @lv_cache_ops_t for details. + * @return Returns a pointer to the created cache object on success, @NULL on error. + */ +lv_cache_t * lv_cache_create(const lv_cache_class_t * cache_class, + size_t node_size, size_t max_size, + lv_cache_ops_t ops); + +/** + * Destroy a cache object. + * @param cache The cache object pointer to destroy. + * @param user_data A user data pointer that will be passed to the free callback. + */ +void lv_cache_destroy(lv_cache_t * cache, void * user_data); + +/** + * Acquire a cache entry with the given key. If the entry is not in the cache, it will return @NULL as it is not found. + * If the entry is found, it's priority will be changed by the cache's policy. And the @lv_entry_t::ref count will be incremented. + * @param cache The cache object pointer to acquire the entry. + * @param key The key of the entry to acquire. + * @param user_data A user data pointer that will be passed to the create callback. + * @return Returns a pointer to the acquired cache entry on success with @lv_entry_t::ref count incremented, @NULL on error. + */ +lv_cache_entry_t * lv_cache_acquire(lv_cache_t * cache, const void * key, void * user_data); + +/** + * Acquire a cache entry with the given key. If the entry is not in the cache, it will create a new entry with the given key. + * If the entry is found, it's priority will be changed by the cache's policy. And the @lv_entry_t::ref count will be incremented. + * If you want to use this API to simplify the code, you should provide a @lv_cache_ops_t::create_cb that creates a new entry with the given key. + * This API is a combination of @lv_cache_acquire and @lv_cache_add. The effect is the same as calling @lv_cache_acquire and @lv_cache_add separately. + * And the internal impact on cache is also consistent with these two APIs. + * @param cache The cache object pointer to acquire the entry. + * @param key The key of the entry to acquire or create. + * @param user_data A user data pointer that will be passed to the create callback. + * @return Returns a pointer to the acquired or created cache entry on success with @lv_entry_t::ref count incremented, @NULL on error. + */ +lv_cache_entry_t * lv_cache_acquire_or_create(lv_cache_t * cache, const void * key, void * user_data); + +/** + * Add a new cache entry with the given key and data. If the cache is full, the cache's policy will be used to evict an entry. + * @param cache The cache object pointer to add the entry. + * @param key The key of the entry to add. + * @param user_data A user data pointer that will be passed to the create callback. + * @return Returns a pointer to the added cache entry on success with @lv_entry_t::ref count incremented, @NULL on error. + */ +lv_cache_entry_t * lv_cache_add(lv_cache_t * cache, const void * key, void * user_data); + +/** + * Release a cache entry. The @lv_entry_t::ref count will be decremented. If the @lv_entry_t::ref count is zero, it will issue an error. + * If the entry passed to this function is the last reference to the data and the entry is marked as invalid, the cache's policy will be used to evict the entry. + * @param cache The cache object pointer to release the entry. + * @param entry The cache entry pointer to release. + * @param user_data A user data pointer that will be passed to the free callback. + */ +void lv_cache_release(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); + +/** + * Reserve a certain amount of memory/count in the cache. This function is useful when you want to reserve a certain amount of memory/count in advance, + * for example, when you know that you will need it later. + * When the current cache size is max than the reserved size, the function will evict entries until the reserved size is reached. + * @param cache The cache object pointer to reserve. + * @param reserved_size The amount of memory/count to reserve. + * @param user_data A user data pointer that will be passed to the free callback. + */ +void lv_cache_reserve(lv_cache_t * cache, uint32_t reserved_size, void * user_data); + +/** + * Drop a cache entry with the given key. If the entry is not in the cache, nothing will happen to it. + * If the entry is found, it will be removed from the cache and its data will be freed when the last reference to it is released. + * @note The data will not be freed immediately but when the last reference to it is released. But this entry will not be found by @lv_cache_acquire. + * If you want cache a same key again, you should use @lv_cache_add or @lv_cache_acquire_or_create. + * @param cache The cache object pointer to drop the entry. + * @param key The key of the entry to drop. + * @param user_data A user data pointer that will be passed to the free callback. + */ +void lv_cache_drop(lv_cache_t * cache, const void * key, void * user_data); + +/** + * Drop all cache entries. All entries will be removed from the cache and their data will be freed when the last reference to them is released. + * @note If some entries are still referenced by other objects, it will issue an error. And this case shouldn't happen in normal cases.. + * @param cache The cache object pointer to drop all entries. + * @param user_data A user data pointer that will be passed to the free callback. + */ +void lv_cache_drop_all(lv_cache_t * cache, void * user_data); + +/** + * Evict one entry from the cache. The eviction policy will be used to select the entry to evict. + * @param cache The cache object pointer to evict an entry. + * @param user_data A user data pointer that will be passed to the free callback. + * @return Returns true if an entry is evicted, false if no entry is evicted. + */ +bool lv_cache_evict_one(lv_cache_t * cache, void * user_data); + +/** + * Set the maximum size of the cache. + * If the current cache size is greater than the new maximum size, the cache's policy will be used to evict entries until the new maximum size is reached. + * @note But this behavior will happen only new entries are added to the cache. + * @param cache The cache object pointer to set the maximum size. + * @param max_size The new maximum size of the cache. + * @param user_data A user data pointer that will be passed to the free callback. + */ +void lv_cache_set_max_size(lv_cache_t * cache, size_t max_size, void * user_data); + +/** + * Get the maximum size of the cache. + * @param cache The cache object pointer to get the maximum size. + * @param user_data A user data pointer that will be passed to the free callback. + * @return Returns the maximum size of the cache. + */ +size_t lv_cache_get_max_size(lv_cache_t * cache, void * user_data); + +/** + * Get the current size of the cache. + * @param cache The cache object pointer to get the current size. + * @param user_data A user data pointer that will be passed to the free callback. + * @return Returns the current size of the cache. + */ +size_t lv_cache_get_size(lv_cache_t * cache, void * user_data); + +/** + * Get the free size of the cache. + * @param cache The cache object pointer to get the free size. + * @param user_data A user data pointer that will be passed to the free callback. + * @return Returns the free size of the cache. + */ +size_t lv_cache_get_free_size(lv_cache_t * cache, void * user_data); + +/** + * Set the compare callback of the cache. + * @param cache The cache object pointer to set the compare callback. + * @param compare_cb The compare callback to set. + * @param user_data A user data pointer. + */ +void lv_cache_set_compare_cb(lv_cache_t * cache, lv_cache_compare_cb_t compare_cb, void * user_data); + +/** + * Set the create callback of the cache. + * @param cache The cache object pointer to set the create callback. + * @param alloc_cb The create callback to set. + * @param user_data A user data pointer. + */ +void lv_cache_set_create_cb(lv_cache_t * cache, lv_cache_create_cb_t alloc_cb, void * user_data); + +/** + * Set the free callback of the cache. + * @param cache The cache object pointer to set the free callback. + * @param free_cb The free callback to set. + * @param user_data A user data pointer. + */ +void lv_cache_set_free_cb(lv_cache_t * cache, lv_cache_free_cb_t free_cb, void * user_data); +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_H*/ diff --git a/lib/lvgl/src/misc/cache/lv_cache_entry.c b/lib/lvgl/src/misc/cache/lv_cache_entry.c new file mode 100644 index 00000000..242e1a0f --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_cache_entry.c @@ -0,0 +1,167 @@ +/** +* @file lv_cache_entry.c +* + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_entry.h" +#include "../../stdlib/lv_sprintf.h" +#include "../lv_assert.h" +#include "lv_cache.h" +#include "lv_cache_entry_private.h" +#include "lv_cache_private.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ +struct _lv_cache_entry_t { + const lv_cache_t * cache; + int32_t ref_cnt; + uint32_t node_size; + + bool is_invalid; +}; +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_cache_entry_reset_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + entry->ref_cnt = 0; +} +void lv_cache_entry_inc_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + entry->ref_cnt++; +} +void lv_cache_entry_dec_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + entry->ref_cnt--; + if(entry->ref_cnt < 0) { + LV_LOG_WARN("ref_cnt(%" LV_PRIu32 ") < 0", entry->ref_cnt); + entry->ref_cnt = 0; + } +} +int32_t lv_cache_entry_get_ref(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return entry->ref_cnt; +} +uint32_t lv_cache_entry_get_node_size(lv_cache_entry_t * entry) +{ + return entry->node_size; +} +void lv_cache_entry_set_node_size(lv_cache_entry_t * entry, uint32_t node_size) +{ + LV_ASSERT_NULL(entry); + entry->node_size = node_size; +} +void lv_cache_entry_set_invalid(lv_cache_entry_t * entry, bool is_invalid) +{ + LV_ASSERT_NULL(entry); + entry->is_invalid = is_invalid; +} +bool lv_cache_entry_is_invalid(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return entry->is_invalid; +} +void * lv_cache_entry_get_data(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return (uint8_t *)entry - entry->node_size; +} +void * lv_cache_entry_acquire_data(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + + lv_cache_entry_inc_ref(entry); + return lv_cache_entry_get_data(entry); +} +void lv_cache_entry_release_data(lv_cache_entry_t * entry, void * user_data) +{ + LV_UNUSED(user_data); + + LV_ASSERT_NULL(entry); + if(lv_cache_entry_get_ref(entry) == 0) { + LV_LOG_ERROR("ref_cnt(%" LV_PRIu32 ") == 0", entry->ref_cnt); + return; + } + + lv_cache_entry_dec_ref(entry); +} +lv_cache_entry_t * lv_cache_entry_get_entry(void * data, const uint32_t node_size) +{ + LV_ASSERT_NULL(data); + return (lv_cache_entry_t *)((uint8_t *)data + node_size); +} +void lv_cache_entry_set_cache(lv_cache_entry_t * entry, const lv_cache_t * cache) +{ + LV_ASSERT_NULL(entry); + entry->cache = cache; +} +const lv_cache_t * lv_cache_entry_get_cache(const lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + return entry->cache; +} + +uint32_t lv_cache_entry_get_size(const uint32_t node_size) +{ + return node_size + sizeof(lv_cache_entry_t); +} +lv_cache_entry_t * lv_cache_entry_alloc(const uint32_t node_size, const lv_cache_t * cache) +{ + void * res = lv_malloc_zeroed(lv_cache_entry_get_size(node_size)); + LV_ASSERT_MALLOC(res) + if(res == NULL) { + LV_LOG_ERROR("malloc failed"); + return NULL; + } + lv_cache_entry_t * entry = (lv_cache_entry_t *)res; + lv_cache_entry_init(entry, cache, node_size); + return (lv_cache_entry_t *)((uint8_t *)entry + node_size); +} +void lv_cache_entry_init(lv_cache_entry_t * entry, const lv_cache_t * cache, const uint32_t node_size) +{ + LV_ASSERT_NULL(entry); + LV_ASSERT_NULL(cache); + + entry->cache = cache; + entry->node_size = node_size; + entry->ref_cnt = 0; + entry->is_invalid = false; +} +void lv_cache_entry_delete(lv_cache_entry_t * entry) +{ + LV_ASSERT_NULL(entry); + + void * data = lv_cache_entry_get_data(entry); + lv_free(data); +} +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/lib/lvgl/src/misc/cache/lv_cache_entry.h b/lib/lvgl/src/misc/cache/lv_cache_entry.h new file mode 100644 index 00000000..0cd2fb2e --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_cache_entry.h @@ -0,0 +1,116 @@ +/** +* @file lv_cache_entry.h +* + */ + +#ifndef LV_CACHE_ENTRY_H +#define LV_CACHE_ENTRY_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../../osal/lv_os.h" +#include "../lv_types.h" +#include "lv_cache_private.h" +#include +#include +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Get the size of a cache entry. + * @param node_size The size of the node in the cache. + * @return The size of the cache entry. + */ +uint32_t lv_cache_entry_get_size(const uint32_t node_size); + +/** + * Get the reference count of a cache entry. + * @param entry The cache entry to get the reference count of. + * @return The reference count of the cache entry. + */ +int32_t lv_cache_entry_get_ref(lv_cache_entry_t * entry); + +/** + * Get the node size of a cache entry. Which is the same size with @lv_cache_entry_get_size's node_size parameter. + * @param entry The cache entry to get the node size of. + * @return The node size of the cache entry. + */ +uint32_t lv_cache_entry_get_node_size(lv_cache_entry_t * entry); + +/** + * Check if a cache entry is invalid. + * @param entry The cache entry to check. + * @return True: the cache entry is invalid. False: the cache entry is valid. + */ +bool lv_cache_entry_is_invalid(lv_cache_entry_t * entry); + +/** + * Get the data of a cache entry. + * @param entry The cache entry to get the data of. + * @return The pointer to the data of the cache entry. + */ +void * lv_cache_entry_get_data(lv_cache_entry_t * entry); + +/** + * Get the cache instance of a cache entry. + * @param entry The cache entry to get the cache instance of. + * @return The pointer to the cache instance of the cache entry. + */ +const lv_cache_t * lv_cache_entry_get_cache(const lv_cache_entry_t * entry); + +/** + * Get the cache entry of a data. The data should be allocated by the cache instance. + * @param data The data to get the cache entry of. + * @param node_size The size of the node in the cache. + * @return The pointer to the cache entry of the data. + */ +lv_cache_entry_t * lv_cache_entry_get_entry(void * data, const uint32_t node_size); + +/** + * Allocate a cache entry. + * @param node_size The size of the node in the cache. + * @param cache The cache instance to allocate the cache entry from. + * @return The pointer to the allocated cache entry. + */ +lv_cache_entry_t * lv_cache_entry_alloc(const uint32_t node_size, const lv_cache_t * cache); + +/** + * Initialize a cache entry. + * @param entry The cache entry to initialize. + * @param cache The cache instance to allocate the cache entry from. + * @param node_size The size of the node in the cache. + */ +void lv_cache_entry_init(lv_cache_entry_t * entry, const lv_cache_t * cache, const uint32_t node_size); + +/** + * Deallocate a cache entry. And the data of the cache entry will be freed. + * @param entry The cache entry to deallocate. + */ +void lv_cache_entry_delete(lv_cache_entry_t * entry); +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_ENTRY_H*/ diff --git a/lib/lvgl/src/misc/cache/lv_cache_entry_private.h b/lib/lvgl/src/misc/cache/lv_cache_entry_private.h new file mode 100644 index 00000000..227585e1 --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_cache_entry_private.h @@ -0,0 +1,51 @@ +/** +* @file lv_cache_entry_private.h +* + */ + +#ifndef LV_CACHE_ENTRY_PRIVATE +#define LV_CACHE_ENTRY_PRIVATE + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_types.h" +#include +#include +#include "../../osal/lv_os.h" +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void lv_cache_entry_reset_ref(lv_cache_entry_t * entry); +void lv_cache_entry_inc_ref(lv_cache_entry_t * entry); +void lv_cache_entry_dec_ref(lv_cache_entry_t * entry); +void lv_cache_entry_set_node_size(lv_cache_entry_t * entry, uint32_t node_size); +void lv_cache_entry_set_invalid(lv_cache_entry_t * entry, bool is_invalid); +void lv_cache_entry_set_cache(lv_cache_entry_t * entry, const lv_cache_t * cache); +void * lv_cache_entry_acquire_data(lv_cache_entry_t * entry); +void lv_cache_entry_release_data(lv_cache_entry_t * entry, void * user_data); +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_ENTRY_PRIVATE*/ diff --git a/lib/lvgl/src/misc/cache/lv_cache_private.h b/lib/lvgl/src/misc/cache/lv_cache_private.h new file mode 100644 index 00000000..4dbafd17 --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_cache_private.h @@ -0,0 +1,190 @@ +/** +* @file lv_cache_private.h +* +*/ + +#ifndef LV_CACHE_PRIVATE_H +#define LV_CACHE_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_types.h" +#include +#include +#include "../../osal/lv_os.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/** + * The result of the cache reserve condition callback + */ +typedef enum { + LV_CACHE_RESERVE_COND_OK, /**< The condition is met and no entries need to be evicted */ + LV_CACHE_RESERVE_COND_TOO_LARGE, /**< The condition is not met and the reserve size is too large */ + LV_CACHE_RESERVE_COND_NEED_VICTIM, /**< The condition is not met and a victim is needed to be evicted */ + LV_CACHE_RESERVE_COND_ERROR /**< An error occurred while checking the condition */ +} lv_cache_reserve_cond_res_t; + +struct _lv_cache_ops_t; +struct _lv_cache_t; +struct _lv_cache_class_t; +struct _lv_cache_entry_t; + +typedef struct _lv_cache_ops_t lv_cache_ops_t; +typedef struct _lv_cache_t lv_cache_t; +typedef struct _lv_cache_class_t lv_cache_class_t; +typedef struct _lv_cache_entry_t lv_cache_entry_t; + +typedef int8_t lv_cache_compare_res_t; +typedef bool (*lv_cache_create_cb_t)(void * node, void * user_data); +typedef void (*lv_cache_free_cb_t)(void * node, void * user_data); +typedef lv_cache_compare_res_t (*lv_cache_compare_cb_t)(const void * a, const void * b); + +/** + * The cache instance allocation function, used by the cache class to allocate memory for cache instances. + * @return It should return a pointer to the allocated instance. + */ +typedef void * (*lv_cache_alloc_cb_t)(void); + +/** + * The cache instance initialization function, used by the cache class to initialize the cache instance. + * @return It should return true if the initialization is successful, false otherwise. + */ +typedef bool (*lv_cache_init_cb_t)(lv_cache_t * cache); + +/** + * The cache instance destruction function, used by the cache class to destroy the cache instance. + */ +typedef void (*lv_cache_destroy_cb_t)(lv_cache_t * cache, void * user_data); + +/** + * The cache get function, used by the cache class to get a cache entry by its key. + * @return @NULL if the key is not found. + */ +typedef lv_cache_entry_t * (*lv_cache_get_cb_t)(lv_cache_t * cache, const void * key, void * user_data); + +/** + * The cache add function, used by the cache class to add a cache entry with a given key. + * This function only cares about how to add the entry, it doesn't check if the entry already exists and doesn't care about is it a victim or not. + * @return the added cache entry, or NULL if the entry is not added. + */ +typedef lv_cache_entry_t * (*lv_cache_add_cb_t)(lv_cache_t * cache, const void * key, void * user_data); + +/** + * The cache remove function, used by the cache class to remove a cache entry from the cache but doesn't free the memory.. + * This function only cares about how to remove the entry, it doesn't care about is it a victim or not. + */ +typedef void (*lv_cache_remove_cb_t)(lv_cache_t * cache, lv_cache_entry_t * entry, void * user_data); + +/** + * The cache drop function, used by the cache class to remove a cache entry from the cache and free the memory. + */ +typedef void (*lv_cache_drop_cb_t)(lv_cache_t * cache, const void * key, void * user_data); + +/** + * The cache drop all function, used by the cache class to remove all cache entries from the cache and free the memory. + */ +typedef void (*lv_cache_drop_all_cb_t)(lv_cache_t * cache, void * user_data); + +/** + * The cache get victim function, used by the cache class to get a victim entry to be evicted. + */ +typedef lv_cache_entry_t * (*lv_cache_get_victim_cb)(lv_cache_t * cache, void * user_data); + +/** + * The cache reserve condition function, used by the cache class to check if a new entry can be added to the cache without exceeding its maximum size. + * See @lv_cache_reserve_cond_res_t for the possible results. + */ +typedef lv_cache_reserve_cond_res_t (*lv_cache_reserve_cond_cb)(lv_cache_t * cache, const void * key, size_t size, + void * user_data); + +/** + * The cache operations struct + */ +struct _lv_cache_ops_t { + lv_cache_compare_cb_t compare_cb; /**< Compare function for keys */ + lv_cache_create_cb_t create_cb; /**< Create function for nodes */ + lv_cache_free_cb_t free_cb; /**< Free function for nodes */ +}; + +/** + * The cache entry struct + */ +struct _lv_cache_t { + const lv_cache_class_t * clz; /**< The cache class. There are two built-in classes: + * @lv_cache_class_lru_rb_count for LRU-based cache with count-based eviction policy. + * @lv_cache_class_lru_rb_size for LRU-based cache with size-based eviction policy. */ + + uint32_t node_size; /**< The size of a node */ + + uint32_t max_size; /**< The maximum size of the cache */ + uint32_t size; /**< The current size of the cache */ + + lv_cache_ops_t ops; /**< The cache operations struct @lv_cache_ops_t */ + + lv_mutex_t lock; /**< The cache lock used to protect the cache in multithreading environments */ +}; + +/** + * The cache class struct for building custom cache classes, and there are two built-in classes for examples: + * @lv_cache_class_lru_rb_count for LRU-based cache with count-based eviction policy. + * @lv_cache_class_lru_rb_size for LRU-based cache with size-based eviction policy. + */ +struct _lv_cache_class_t { + lv_cache_alloc_cb_t alloc_cb; /**< The allocation function for cache entries */ + lv_cache_init_cb_t init_cb; /**< The initialization function for cache entries */ + lv_cache_destroy_cb_t destroy_cb; /**< The destruction function for cache entries */ + + lv_cache_get_cb_t get_cb; /**< The get function for cache entries */ + lv_cache_add_cb_t add_cb; /**< The add function for cache entries */ + lv_cache_remove_cb_t remove_cb; /**< The remove function for cache entries */ + lv_cache_drop_cb_t drop_cb; /**< The drop function for cache entries */ + lv_cache_drop_all_cb_t drop_all_cb; /**< The drop all function for cache entries */ + lv_cache_get_victim_cb get_victim_cb; /**< The get victim function for cache entries */ + lv_cache_reserve_cond_cb reserve_cond_cb; /**< The reserve condition function for cache entries */ +}; + +/*----------------- + * Cache entry slot + *----------------*/ + +struct _lv_cache_slot_size_t; + +typedef struct _lv_cache_slot_size_t lv_cache_slot_size_t; + +/** + * The cache entry slot struct + * To add new fields to the cache entry, add them to a new struct and add it to the first field of the cache data struct. + * And this one is a size slot for the cache entry. + */ +struct _lv_cache_slot_size_t { + size_t size; +}; +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CACHE_PRIVATE_H*/ diff --git a/lib/lvgl/src/misc/cache/lv_image_cache.c b/lib/lvgl/src/misc/cache/lv_image_cache.c new file mode 100644 index 00000000..28f0aec7 --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_image_cache.c @@ -0,0 +1,109 @@ +/** +* @file lv_image_cache.c +* + */ + +/********************* + * INCLUDES + *********************/ +#include "../lv_assert.h" +#include "lv_image_cache.h" +#include "../../core/lv_global.h" +/********************* + * DEFINES + *********************/ +#define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache) +#define img_header_cache_p (LV_GLOBAL_DEFAULT()->img_header_cache) +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * GLOBAL VARIABLES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +void lv_image_cache_drop(const void * src) +{ + /*If user invalidate image, the header cache should be invalidated too.*/ + lv_image_header_cache_drop(src); + +#if LV_CACHE_DEF_SIZE > 0 + if(src == NULL) { + lv_cache_drop_all(img_cache_p, NULL); + return; + } + + lv_image_cache_data_t search_key = { + .src = src, + .src_type = lv_image_src_get_type(src), + }; + + lv_cache_drop(img_cache_p, &search_key, NULL); +#else + LV_UNUSED(src); +#endif +} + +void lv_image_cache_resize(uint32_t new_size, bool evict_now) +{ +#if LV_CACHE_DEF_SIZE > 0 + lv_cache_set_max_size(img_cache_p, new_size, NULL); + if(evict_now) { + lv_cache_reserve(img_cache_p, new_size, NULL); + } +#else + LV_UNUSED(new_size); + LV_UNUSED(evict_now); +#endif +} + +void lv_image_header_cache_drop(const void * src) +{ +#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0 + if(src == NULL) { + lv_cache_drop_all(img_header_cache_p, NULL); + return; + } + + lv_image_header_cache_data_t search_key = { + .src = src, + .src_type = lv_image_src_get_type(src), + }; + + lv_cache_drop(img_header_cache_p, &search_key, NULL); +#else + LV_UNUSED(src); +#endif +} + +void lv_image_header_cache_resize(uint32_t new_size, bool evict_now) +{ +#if LV_IMAGE_HEADER_CACHE_DEF_CNT > 0 + lv_cache_set_max_size(img_header_cache_p, new_size, NULL); + if(evict_now) { + lv_cache_reserve(img_header_cache_p, new_size, NULL); + } +#else + LV_UNUSED(new_size); + LV_UNUSED(evict_now); +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ diff --git a/lib/lvgl/src/misc/cache/lv_image_cache.h b/lib/lvgl/src/misc/cache/lv_image_cache.h new file mode 100644 index 00000000..f8a59034 --- /dev/null +++ b/lib/lvgl/src/misc/cache/lv_image_cache.h @@ -0,0 +1,69 @@ +/** +* @file lv_image_cache.h +* + */ + +#ifndef LV_IMAGE_CACHE_H +#define LV_IMAGE_CACHE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_cache_private.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Invalidate image cache. Use NULL to invalidate all images. + * @param src pointer to an image source. + */ +void lv_image_cache_drop(const void * src); + +/** + * Resize image cache. + * @param new_size new size of the cache in bytes. + * @param evict_now true: evict the images should be removed by the eviction policy, false: wait for the next cache cleanup. + */ +void lv_image_cache_resize(uint32_t new_size, bool evict_now); + +/** + * Invalidate image header cache. Use NULL to invalidate all image headers. + * It's also automatically called when an image is invalidated. + * @param src pointer to an image source. + */ +void lv_image_header_cache_drop(const void * src); + +/** + * Resize image header cache. + * @param new_size new size of the cache in count of image headers. + * @param evict_now true: evict the image headers should be removed by the eviction policy, false: wait for the next cache cleanup. + */ +void lv_image_header_cache_resize(uint32_t new_size, bool evict_now); + +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_IMAGE_CACHE_H*/ -- cgit v1.2.3