1 /**
2 * @file lv_nuttx_image_cache.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "lv_nuttx_image_cache.h"
11 #include "../../core/lv_global.h"
12 #include "../../../lvgl.h"
13
14 #if LV_USE_NUTTX
15
16 #include "../../draw/lv_draw_buf_private.h"
17 #include <nuttx/mm/mm.h>
18
19 /*********************
20 * DEFINES
21 *********************/
22
23 #define HEAP_NAME "GImageCache"
24
25 #define img_cache_p (LV_GLOBAL_DEFAULT()->img_cache)
26 #define img_header_cache_p (LV_GLOBAL_DEFAULT()->img_header_cache)
27 #define ctx (*(lv_nuttx_ctx_image_cache_t **)&LV_GLOBAL_DEFAULT()->nuttx_ctx->image_cache)
28 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
29
30 /**********************
31 * TYPEDEFS
32 **********************/
33 typedef struct {
34 uint8_t * mem;
35 uint32_t mem_size;
36
37 char name[sizeof(HEAP_NAME) + 10]; /**< +10 characters to store task pid. */
38
39 struct mm_heap_s * heap;
40 uint32_t heap_size;
41
42 bool initialized;
43 bool independent_image_heap;
44
45 lv_draw_buf_malloc_cb malloc_cb;
46 lv_draw_buf_free_cb free_cb;
47 } lv_nuttx_ctx_image_cache_t;
48 /**********************
49 * STATIC PROTOTYPES
50 **********************/
51
52 static void * malloc_cb(size_t size_bytes, lv_color_format_t color_format);
53 static void free_cb(void * draw_buf);
54
55 /**********************
56 * STATIC VARIABLES
57 **********************/
58
59 /**********************
60 * MACROS
61 **********************/
62
63 /**********************
64 * GLOBAL FUNCTIONS
65 **********************/
66
lv_nuttx_image_cache_init(bool use_independent_image_heap)67 void lv_nuttx_image_cache_init(bool use_independent_image_heap)
68 {
69 lv_draw_buf_handlers_t * handlers = image_cache_draw_buf_handlers;
70
71 ctx = lv_malloc_zeroed(sizeof(lv_nuttx_ctx_image_cache_t));
72 LV_ASSERT_MALLOC(ctx);
73
74 ctx->malloc_cb = handlers->buf_malloc_cb;
75 ctx->free_cb = handlers->buf_free_cb;
76
77 handlers->buf_malloc_cb = malloc_cb;
78 handlers->buf_free_cb = free_cb;
79
80 ctx->initialized = false;
81 ctx->independent_image_heap = use_independent_image_heap;
82 }
83
lv_nuttx_image_cache_deinit(void)84 void lv_nuttx_image_cache_deinit(void)
85 {
86 if(ctx->independent_image_heap == false) goto FREE_CONTEXT;
87 if(ctx->initialized == false) goto FREE_CONTEXT;
88
89 mm_uninitialize(ctx->heap);
90 free(ctx->mem);
91
92 FREE_CONTEXT:
93 lv_draw_buf_handlers_t * handlers = image_cache_draw_buf_handlers;
94 handlers->buf_malloc_cb = ctx->malloc_cb;
95 handlers->buf_free_cb = ctx->free_cb;
96 lv_free(ctx);
97
98 ctx = NULL;
99 }
100
101 /**********************
102 * STATIC FUNCTIONS
103 **********************/
104
defer_init(void)105 static bool defer_init(void)
106 {
107 if(ctx->mem != NULL && ctx->heap != NULL) {
108 return true;
109 }
110
111 if(lv_image_cache_is_enabled() == false) {
112 LV_LOG_INFO("Image cache is not initialized yet. Skipping deferred initialization. Because max_size is 0.");
113 return false;
114 }
115
116 ctx->mem_size = img_cache_p->max_size;
117 ctx->mem = malloc(ctx->mem_size);
118 LV_ASSERT_MALLOC(ctx->mem);
119
120 if(ctx->mem == NULL) {
121 LV_LOG_ERROR("Failed to allocate memory for image cache");
122 ctx->initialized = false;
123 return false;
124 }
125
126 lv_snprintf(ctx->name, sizeof(ctx->name), HEAP_NAME "[%-4" LV_PRIu32 "]", (uint32_t)gettid());
127
128 ctx->heap = mm_initialize(
129 ctx->name,
130 ctx->mem,
131 ctx->mem_size
132 );
133
134 struct mallinfo info = mm_mallinfo(ctx->heap);
135 ctx->heap_size = info.arena;
136
137 LV_LOG_USER("heap info:");
138 LV_LOG_USER(" heap: %p", ctx->heap);
139 LV_LOG_USER(" mem: %p", ctx->mem);
140 LV_LOG_USER(" mem_size: %" LV_PRIu32, ctx->mem_size);
141 LV_LOG_USER(" arena: %d", info.arena);
142 LV_LOG_USER(" ordblks: %d", info.ordblks);
143 LV_LOG_USER(" aordblks: %d", info.aordblks);
144 LV_LOG_USER(" mxordblk: %d", info.mxordblk);
145 LV_LOG_USER(" uordblks: %d", info.uordblks);
146 LV_LOG_USER(" fordblks: %d", info.fordblks);
147
148 ctx->initialized = true;
149 return true;
150 }
151
heap_memdump(struct mm_heap_s * heap)152 static void heap_memdump(struct mm_heap_s * heap)
153 {
154 struct mm_memdump_s dump = {
155 PID_MM_ALLOC,
156 #if CONFIG_MM_BACKTRACE >= 0
157 0,
158 ULONG_MAX
159 #endif
160 };
161
162 mm_memdump(heap, &dump);
163 }
164
malloc_cb(size_t size_bytes,lv_color_format_t color_format)165 static void * malloc_cb(size_t size_bytes, lv_color_format_t color_format)
166 {
167 LV_UNUSED(color_format);
168 if(ctx->independent_image_heap == true && ctx->initialized == false) {
169 if(defer_init() == false) return NULL;
170 }
171
172 /*Allocate larger memory to be sure it can be aligned as needed*/
173 size_bytes += LV_DRAW_BUF_ALIGN - 1;
174 uint32_t cache_max_size = lv_cache_get_max_size(img_cache_p, NULL);
175
176 if(lv_cache_is_enabled(img_cache_p) && size_bytes > cache_max_size) {
177 LV_LOG_ERROR("data size (%" LV_PRIu32 ") is larger than max size (%" LV_PRIu32 ")",
178 (uint32_t)size_bytes,
179 cache_max_size);
180 return NULL;
181 }
182
183 while(1) {
184 void * mem = NULL;
185 if(ctx->independent_image_heap) {
186 mem = mm_malloc(ctx->heap, size_bytes);
187 }
188 else if((!lv_cache_is_enabled(img_cache_p)) || (lv_cache_get_size(img_cache_p, NULL) + size_bytes < cache_max_size)) {
189 mem = ctx->malloc_cb(size_bytes, color_format);
190 }
191 if(mem) return mem;
192 LV_LOG_INFO("appears to be out of memory. attempting to evict one cache entry. with allocated size %" LV_PRIu32,
193 (uint32_t)size_bytes);
194 bool evict_res = lv_cache_evict_one(img_cache_p, NULL);
195 if(evict_res == false) {
196 LV_LOG_ERROR("failed to evict one cache entry");
197 heap_memdump(ctx->heap);
198 return NULL;
199 }
200 }
201 }
202
free_cb(void * draw_buf)203 static void free_cb(void * draw_buf)
204 {
205 if(ctx->independent_image_heap == true) {
206 mm_free(ctx->heap, draw_buf);
207 }
208 else {
209 ctx->free_cb(draw_buf);
210 }
211 }
212
213 #endif /* LV_USE_NUTTX */
214