1 /**
2 * @file lv_vg_lite_decoder.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "../lv_image_decoder_private.h"
11 #include "lv_vg_lite_decoder.h"
12
13 #if LV_USE_DRAW_VG_LITE
14
15 #include "lv_vg_lite_utils.h"
16 #include <stdlib.h>
17 #include <string.h>
18 #include "../../core/lv_global.h"
19
20 /*********************
21 * DEFINES
22 *********************/
23
24 #define DECODER_NAME "VG_LITE"
25
26 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
27
28 /* VG_LITE_INDEX1, 2, and 4 require endian flipping + bit flipping,
29 * so for simplicity, they are uniformly converted to I8 for display.
30 */
31 #define DEST_IMG_FORMAT LV_COLOR_FORMAT_I8
32 #define IS_CONV_INDEX_FORMAT(cf) (cf == LV_COLOR_FORMAT_I1 || cf == LV_COLOR_FORMAT_I2 || cf == LV_COLOR_FORMAT_I4)
33
34 /* Since the palette and index image are next to each other,
35 * the palette size needs to be aligned to ensure that the image is aligned.
36 */
37 #define DEST_IMG_OFFSET \
38 LV_VG_LITE_ALIGN(LV_COLOR_INDEXED_PALETTE_SIZE(DEST_IMG_FORMAT) * sizeof(lv_color32_t), LV_DRAW_BUF_ALIGN)
39
40 /**********************
41 * TYPEDEFS
42 **********************/
43
44 /**********************
45 * STATIC PROTOTYPES
46 **********************/
47
48 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * src, lv_image_header_t * header);
49 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
50 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
51 static void image_color32_pre_mul(lv_color32_t * img_data, uint32_t px_size);
52
53 /**********************
54 * STATIC VARIABLES
55 **********************/
56
57 /**********************
58 * MACROS
59 **********************/
60
61 /**********************
62 * GLOBAL FUNCTIONS
63 **********************/
64
lv_vg_lite_decoder_init(void)65 void lv_vg_lite_decoder_init(void)
66 {
67 lv_image_decoder_t * decoder = lv_image_decoder_create();
68 lv_image_decoder_set_info_cb(decoder, decoder_info);
69 lv_image_decoder_set_open_cb(decoder, decoder_open);
70 lv_image_decoder_set_close_cb(decoder, decoder_close);
71
72 decoder->name = DECODER_NAME;
73 }
74
lv_vg_lite_decoder_deinit(void)75 void lv_vg_lite_decoder_deinit(void)
76 {
77 lv_image_decoder_t * dec = NULL;
78 while((dec = lv_image_decoder_get_next(dec)) != NULL) {
79 if(dec->info_cb == decoder_info) {
80 lv_image_decoder_delete(dec);
81 break;
82 }
83 }
84 }
85
86 /**********************
87 * STATIC FUNCTIONS
88 **********************/
89
image_color32_pre_mul(lv_color32_t * img_data,uint32_t px_size)90 static void image_color32_pre_mul(lv_color32_t * img_data, uint32_t px_size)
91 {
92 while(px_size--) {
93 lv_color_premultiply(img_data);
94 img_data++;
95 }
96 }
97
image_stride(const lv_image_header_t * header)98 static uint32_t image_stride(const lv_image_header_t * header)
99 {
100 /* use stride in header */
101 if(header->stride) {
102 return header->stride;
103 }
104
105 /* guess stride */
106 uint32_t ori_stride = header->w * lv_color_format_get_bpp(header->cf);
107 ori_stride = (ori_stride + 7) >> 3; /*Round up*/
108 return ori_stride;
109 }
110
image_decode_to_index8_line(uint8_t * dest,const uint8_t * src,int32_t w_px,lv_color_format_t color_format)111 static void image_decode_to_index8_line(uint8_t * dest, const uint8_t * src, int32_t w_px,
112 lv_color_format_t color_format)
113 {
114 uint8_t px_size;
115 uint16_t mask;
116
117 int8_t shift = 0;
118 switch(color_format) {
119 case LV_COLOR_FORMAT_I1:
120 px_size = 1;
121 shift = 7;
122 break;
123 case LV_COLOR_FORMAT_I2:
124 px_size = 2;
125 shift = 6;
126 break;
127 case LV_COLOR_FORMAT_I4:
128 px_size = 4;
129 shift = 4;
130 break;
131 case LV_COLOR_FORMAT_I8:
132 lv_memcpy(dest, src, w_px);
133 return;
134 default:
135 LV_ASSERT_FORMAT_MSG(false, "Unsupported color format: %d", color_format);
136 return;
137 }
138
139 mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
140
141 for(int32_t i = 0; i < w_px; i++) {
142 uint8_t val_act = (*src >> shift) & mask;
143 dest[i] = val_act;
144
145 shift -= px_size;
146 if(shift < 0) {
147 shift = 8 - px_size;
148 src++;
149 }
150 }
151 }
152
decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)153 static lv_result_t decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
154 {
155 lv_result_t res = lv_bin_decoder_info(decoder, dsc, header);
156 if(res != LV_RESULT_OK) {
157 return res;
158 }
159
160 if(!IS_CONV_INDEX_FORMAT(header->cf)) {
161 return LV_RESULT_INVALID;
162 }
163
164 if(header->flags & LV_IMAGE_FLAGS_COMPRESSED) {
165 LV_LOG_WARN("NOT Supported compressed index format: %d", header->cf);
166 return LV_RESULT_INVALID;
167 }
168
169 header->cf = DEST_IMG_FORMAT;
170 return LV_RESULT_OK;
171 }
172
decoder_open_variable(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)173 static lv_result_t decoder_open_variable(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
174 {
175 LV_UNUSED(decoder); /*Unused*/
176
177 lv_draw_buf_t src_img_buf;
178 lv_draw_buf_from_image(&src_img_buf, dsc->src);
179
180 /* Since dsc->header.cf is uniformly set to I8,
181 * the original format is obtained from src for conversion.
182 */
183 lv_color_format_t src_cf = src_img_buf.header.cf;
184
185 int32_t width = dsc->header.w;
186 int32_t height = dsc->header.h;
187
188 /* create draw buf */
189 lv_draw_buf_t * draw_buf = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, width, height, DEST_IMG_FORMAT,
190 LV_STRIDE_AUTO);
191 if(draw_buf == NULL) {
192 return LV_RESULT_INVALID;
193 }
194
195 lv_draw_buf_clear(draw_buf, NULL);
196 dsc->decoded = draw_buf;
197
198 uint32_t src_stride = image_stride(&src_img_buf.header);
199 uint32_t dest_stride = draw_buf->header.stride;
200
201 /*In case of uncompressed formats the image stored in the ROM/RAM.
202 *So simply give its pointer*/
203 const uint8_t * src = ((lv_image_dsc_t *)dsc->src)->data;
204 uint8_t * dest = draw_buf->data;
205
206 /* index format only */
207 uint32_t palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(src_cf);
208 LV_ASSERT(palette_size > 0);
209
210 uint32_t palette_size_bytes = palette_size * sizeof(lv_color32_t);
211
212 /* copy palette */
213 lv_memcpy(dest, src, palette_size_bytes);
214
215 if(dsc->args.premultiply) {
216 /* pre-multiply palette */
217 image_color32_pre_mul((lv_color32_t *)dest, palette_size);
218 draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;
219 }
220
221 /* move to index image map */
222 src += palette_size_bytes;
223 dest += DEST_IMG_OFFSET;
224
225 /* copy index image */
226 for(int32_t y = 0; y < height; y++) {
227 image_decode_to_index8_line(dest, src, width, src_cf);
228 src += src_stride;
229 dest += dest_stride;
230 }
231
232 return LV_RESULT_OK;
233 }
234
decoder_open_file(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)235 static lv_result_t decoder_open_file(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
236 {
237 LV_UNUSED(decoder); /*Unused*/
238
239 uint32_t width = dsc->header.w;
240 uint32_t height = dsc->header.h;
241 const char * path = dsc->src;
242 uint8_t * src_temp = NULL;
243
244 lv_fs_file_t file;
245 lv_fs_res_t res = lv_fs_open(&file, path, LV_FS_MODE_RD);
246 if(res != LV_FS_RES_OK) {
247 LV_LOG_ERROR("open %s failed", path);
248 return LV_RESULT_INVALID;
249 }
250
251 /* get real src header */
252 lv_image_header_t src_header;
253 uint32_t header_br = 0;
254 res = lv_fs_read(&file, &src_header, sizeof(src_header), &header_br);
255 if(res != LV_FS_RES_OK || header_br != sizeof(src_header)) {
256 LV_LOG_ERROR("read %s lv_image_header_t failed", path);
257 lv_fs_close(&file);
258 return LV_RESULT_INVALID;
259 }
260
261 lv_draw_buf_t * draw_buf = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, width, height, DEST_IMG_FORMAT,
262 LV_STRIDE_AUTO);
263 if(draw_buf == NULL) {
264 lv_fs_close(&file);
265 return LV_RESULT_INVALID;
266 }
267
268 lv_draw_buf_clear(draw_buf, NULL);
269
270 /* get stride */
271 uint32_t src_stride = image_stride(&src_header);
272 uint32_t dest_stride = draw_buf->header.stride;
273
274 dsc->decoded = draw_buf;
275 uint8_t * dest = draw_buf->data;
276
277 /* index format only */
278 uint32_t palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(src_header.cf);
279 if(palette_size == 0) {
280 LV_LOG_ERROR("file %s invalid palette size: %" LV_PRIu32, path, palette_size);
281 goto failed;
282 }
283
284 uint32_t palette_size_bytes = palette_size * sizeof(lv_color32_t);
285
286 /* read palette */
287 uint32_t palette_br = 0;
288 res = lv_fs_read(&file, dest, palette_size_bytes, &palette_br);
289 if(res != LV_FS_RES_OK || palette_br != palette_size_bytes) {
290 LV_LOG_ERROR("read %s (palette: %" LV_PRIu32 ", br: %" LV_PRIu32 ") failed",
291 path, palette_size_bytes, palette_br);
292 goto failed;
293 }
294
295 if(dsc->args.premultiply) {
296 /* pre-multiply palette */
297 image_color32_pre_mul((lv_color32_t *)dest, palette_size);
298 draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;
299 }
300
301 src_temp = lv_malloc(src_stride);
302 if(src_temp == NULL) {
303 LV_LOG_ERROR("malloc src_temp failed");
304 goto failed;
305 }
306
307 /* move to index image map */
308 dest += DEST_IMG_OFFSET;
309
310 for(uint32_t y = 0; y < height; y++) {
311 uint32_t br = 0;
312 res = lv_fs_read(&file, src_temp, src_stride, &br);
313 if(res != LV_FS_RES_OK || br != src_stride) {
314 LV_LOG_ERROR("read %s (y: %" LV_PRIu32 ", src_stride: %" LV_PRIu32 ", br: %" LV_PRIu32 ") failed",
315 path, y, src_stride, br);
316 goto failed;
317 }
318
319 /* convert to index8 */
320 image_decode_to_index8_line(dest, src_temp, width, src_header.cf);
321 dest += dest_stride;
322 }
323
324 lv_free(src_temp);
325
326 lv_fs_close(&file);
327 return LV_RESULT_OK;
328
329 failed:
330 if(src_temp) {
331 lv_free(src_temp);
332 }
333 lv_fs_close(&file);
334 lv_draw_buf_destroy(draw_buf);
335 dsc->decoded = NULL;
336
337 return LV_RESULT_INVALID;
338 }
339
340 /**
341 * Decode an image using the vg_lite gpu.
342 * @param decoder pointer to the decoder
343 * @param dsc pointer to the decoder descriptor
344 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
345 */
decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)346 static lv_result_t decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
347 {
348 lv_result_t res = LV_RESULT_INVALID;
349
350 switch(dsc->src_type) {
351 case LV_IMAGE_SRC_VARIABLE:
352 res = decoder_open_variable(decoder, dsc);
353 break;
354 case LV_IMAGE_SRC_FILE:
355 res = decoder_open_file(decoder, dsc);
356 break;
357 default:
358 break;
359 }
360
361 if(dsc->args.no_cache) return res;
362
363 /*If the image cache is disabled, just return the decoded image*/
364 if(!lv_image_cache_is_enabled()) return res;
365
366 /*Add the decoded image to the cache*/
367 if(res == LV_RESULT_OK) {
368 lv_image_cache_data_t search_key;
369 search_key.src_type = dsc->src_type;
370 search_key.src = dsc->src;
371 search_key.slot.size = dsc->decoded->data_size;
372
373 lv_cache_entry_t * entry = lv_image_decoder_add_to_cache(decoder, &search_key, dsc->decoded, NULL);
374
375 if(entry == NULL) {
376 lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded);
377 dsc->decoded = NULL;
378 return LV_RESULT_INVALID;
379 }
380 dsc->cache_entry = entry;
381 }
382
383 return res;
384 }
385
decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)386 static void decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
387 {
388 LV_UNUSED(decoder); /*Unused*/
389
390 if(dsc->args.no_cache || !lv_image_cache_is_enabled()) lv_draw_buf_destroy((lv_draw_buf_t *)dsc->decoded);
391 }
392
393 #endif /*LV_USE_DRAW_VG_LITE*/
394