feat(decoder): remove img_data and use decoded draw buffer instead (#4985)

Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com>
This commit is contained in:
Neo Xu
2024-01-03 20:08:38 +08:00
committed by GitHub
parent 398e181dd3
commit b902600b83
10 changed files with 55 additions and 107 deletions

View File

@@ -258,7 +258,7 @@ open/close the PNG files. It should look like this:
}
/**
* Open a PNG image and decode it into dsc.img_data
* Open a PNG image and decode it into dsc.decoded
* @param decoder pointer to the decoder where this function belongs
* @param dsc image descriptor
* @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
@@ -270,11 +270,11 @@ open/close the PNG files. It should look like this:
/*Check whether the type `src` is known by the decoder*/
if(is_png(dsc->src) == false) return LV_RESULT_INVALID;
/*Decode and store the image. If `dsc->img_data` is `NULL`, the `read_line` function will be called to get the image data line-by-line*/
dsc->img_data = my_png_decoder(dsc->src);
/*Decode and store the image. If `dsc->decoded` is `NULL`, the `read_line` function will be called to get the image data line-by-line*/
dsc->decoded = my_png_decoder(dsc->src);
/*Change the color format if required. For PNG usually 'Raw' is fine*/
dsc->header.cf = LV_COLOR_FORMAT_...
/*Change the color format if decoded image format is different than original format. For PNG it's usually decoded to ARGB8888 format*/
dsc->decoded.header.cf = LV_COLOR_FORMAT_...
/*Call a binary image decoder function if required. It's not required if `my_png_decoder` opened the image in true color format.*/
lv_result_t res = lv_bin_decoder_open(decoder, dsc);
@@ -316,13 +316,13 @@ So in summary:
- In ``decoder_open``, you should try to open the image source pointed by
``dsc->src``. Its type is already in ``dsc->src_type == LV_IMG_SRC_FILE/VARIABLE``.
If this format/type is not supported by the decoder, return :cpp:enumerator:`LV_RESULT_INVALID`.
However, if you can open the image, a pointer to the decoded *True color* image should be
set in ``dsc->img_data``. If the format is known, but you don't want to
decode the entire image (e.g. no memory for it), set ``dsc->img_data = NULL`` and
However, if you can open the image, a pointer to the decoded image should be
set in ``dsc->decoded``. If the format is known, but you don't want to
decode the entire image (e.g. no memory for it), set ``dsc->decoded = NULL`` and
use ``decoder_get_area`` to get the image area pixels.
- In ``decoder_close`` you should free all allocated resources.
- ``decoder_get_area`` is optional. In this case you should decode the whole image In
``decoder_open`` function and store image data in ``dsc->img_data``.
``decoder_open`` function and store image data in ``dsc->decoded``.
Decoding the whole image requires extra memory and some computational overhead.
@@ -346,7 +346,7 @@ images to tell color of the image.
res = lv_image_decoder_open(&dsc, &my_img_dsc, &args);
if(res == LV_RESULT_OK) {
/*Do something with `dsc->img_data`*/
/*Do something with `dsc->decoded`. You can copy out the decoded image by `lv_draw_buf_dup(dsc.decoded)`*/
lv_image_decoder_close(&dsc);
}
@@ -385,61 +385,26 @@ See the detailed code below:
lv_cache_entry_t * entry = dsc->cache_entry;
if(!(entry->process_state & IMAGE_PROCESS_STATE_PREMULTIPLIED_ALPHA)) {
lv_color32_t * image = (lv_color32_t *)dsc->img_data;
uint32_t px_cnt = dsc->header.w * dsc->header.h;
/* premultiply alpha */
while(px_cnt--) {
image->red = LV_UDIV255(image->red * image->alpha);
image->green = LV_UDIV255(image->green * image->alpha);
image->blue = LV_UDIV255(image->blue * image->alpha);
image++;
}
lv_draw_buf_premultiply(dsc->decoded);
LV_LOG_USER("premultiplied alpha OK");
entry->process_state |= IMAGE_PROCESS_STATE_PREMULTIPLIED_ALPHA;
}
if(!(entry->process_state & IMAGE_PROCESS_STATE_STRIDE_ALIGNED)) {
int32_t image_w = dsc->header.w;
int32_t image_h = dsc->header.h;
uint32_t width_byte = image_w * lv_color_format_get_size(color_format);
uint32_t stride = lv_draw_buf_width_to_stride(image_w, color_format);
uint32_t stride_expect = lv_draw_buf_width_to_stride(decoded->header.w, decoded->header.cf);
if(decoded->header.stride != stride_expect) {
LV_LOG_WARN("Stride mismatch");
lv_draw_buf_t * aligned = lv_draw_buf_adjust_stride(decoded, stride_expect);
if(aligned == NULL) {
LV_LOG_ERROR("No memory for Stride adjust.");
return NULL;
}
/* Check stride alignment requirements */
if(stride != width_byte) {
LV_LOG_USER("need to realign stride: %" LV_PRIu32 " -> %" LV_PRIu32, width_byte, stride);
decoded = aligned;
}
const uint8_t * ori_image = lv_cache_get_data(entry);
size_t size_bytes = stride * dsc->header.h;
uint8_t * new_image = lv_draw_buf_malloc(size_bytes, color_format);
if(!new_image) {
LV_LOG_ERROR("alloc failed");
res = LV_RESULT_INVALID;
goto alloc_failed;
}
/* Replace the image data pointer */
entry->data = new_image;
dsc->img_data = new_image;
/* Copy image data */
const uint8_t * cur = ori_image;
for(int32_t y = 0; y < image_h; y++) {
lv_memcpy(new_image, cur, width_byte);
new_image += stride;
cur += width_byte;
}
/* free memory for old image */
lv_draw_buf_free((void *)ori_image);
}
else {
LV_LOG_USER("no need to realign stride: %" LV_PRIu32, stride);
}
entry->process_state |= IMAGE_PROCESS_STATE_STRIDE_ALIGNED;
entry->process_state |= IMAGE_PROCESS_STATE_STRIDE_ALIGNED;
}
alloc_failed:
@@ -482,7 +447,7 @@ inefficient and detrimental to the user experience.
Therefore, LVGL caches image data. Caching means some
images will be left open, hence LVGL can quickly access them from
``dsc->img_data`` instead of needing to decode them again.
``dsc->decoded`` instead of needing to decode them again.
Of course, caching images is resource intensive as it uses more RAM to
store the decoded image. LVGL tries to optimize the process as much as