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