mirror of
https://github.com/lvgl/lvgl.git
synced 2025-01-28 07:03:00 +08:00
refactor(snapshot): use draw buffer interface (#5487)
Signed-off-by: Xu Xingliang <xuxingliang@xiaomi.com> Co-authored-by: Benign X <1341398182@qq.com>
This commit is contained in:
parent
396d7ae82b
commit
135ad49dce
@ -26,13 +26,13 @@ Free the Image
|
|||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The memory :cpp:func:`lv_snapshot_take` uses are dynamically allocated using
|
The memory :cpp:func:`lv_snapshot_take` uses are dynamically allocated using
|
||||||
:cpp:func:`lv_malloc`. Use API :cpp:func:`lv_snapshot_free` to free the memory it
|
:cpp:func:`lv_draw_buf_create`. Use API :cpp:func:`lv_draw_buf_destroy` to free the memory it
|
||||||
takes. This will firstly free memory the image data takes, then the
|
takes. This will firstly free memory the image data takes, then the
|
||||||
image descriptor.
|
image descriptor.
|
||||||
|
|
||||||
Take caution to free the snapshot but not delete the image object.
|
The snapshot image which is the draw buffer returned by :cpp:func:`lv_snapshot_take`
|
||||||
Before free the memory, be sure to firstly unlink it from image object,
|
normally won't be added to cache because it can be drawn directly. So you don't need
|
||||||
using :cpp:expr:`lv_image_set_src(NULL)` and :cpp:expr:`lv_cache_invalidate(lv_cache_find(src, LV_CACHE_SRC_TYPE_PTR, 0, 0));`.
|
to invalidate cache by :cpp:func:`lv_image_cache_drop` before destroy the draw buffer.
|
||||||
|
|
||||||
Below code snippet explains usage of this API.
|
Below code snippet explains usage of this API.
|
||||||
|
|
||||||
@ -40,9 +40,9 @@ Below code snippet explains usage of this API.
|
|||||||
|
|
||||||
void update_snapshot(lv_obj_t * obj, lv_obj_t * img_snapshot)
|
void update_snapshot(lv_obj_t * obj, lv_obj_t * img_snapshot)
|
||||||
{
|
{
|
||||||
lv_image_dsc_t* snapshot = (void*)lv_image_get_src(img_snapshot);
|
lv_draw_buf_t* snapshot = (void*)lv_image_get_src(img_snapshot);
|
||||||
if(snapshot) {
|
if(snapshot) {
|
||||||
lv_snapshot_free(snapshot);
|
lv_draw_buf_destroy(snapshot);
|
||||||
}
|
}
|
||||||
snapshot = lv_snapshot_take(obj, LV_COLOR_FORMAT_ARGB8888);
|
snapshot = lv_snapshot_take(obj, LV_COLOR_FORMAT_ARGB8888);
|
||||||
lv_image_set_src(img_snapshot, snapshot);
|
lv_image_set_src(img_snapshot, snapshot);
|
||||||
@ -52,16 +52,16 @@ Use Existing Buffer
|
|||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
If the snapshot needs update now and then, or simply caller provides memory, use API
|
If the snapshot needs update now and then, or simply caller provides memory, use API
|
||||||
``lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_image_dsc_t * dsc, void * buf, uint32_t buf_size);``
|
``lv_result_t lv_snapshot_take_to_draw_buf(lv_obj_t * obj, lv_color_format_t cf, lv_draw_buf_t * draw_buf);``
|
||||||
for this case. It's caller's responsibility to alloc/free the memory.
|
for this case. It's caller's responsibility to create and destroy the draw buffer.
|
||||||
|
|
||||||
If snapshot is generated successfully, the image descriptor is updated
|
If snapshot is generated successfully, the image descriptor is updated
|
||||||
and image data will be stored to provided ``buf``.
|
and image data will be stored to provided ``buf``.
|
||||||
|
|
||||||
Note that snapshot may fail if provided buffer is not enough, which may
|
Note that snapshot may fail if provided buffer is not enough, which may
|
||||||
happen when object size changes. It's recommended to use API
|
happen when object size changes. It's recommended to use API
|
||||||
:cpp:func:`lv_snapshot_buf_size_needed` to check the needed buffer size in byte
|
:cpp:func:`lv_snapshot_reshape_draw_buf` to prepare the buffer firstly and if it
|
||||||
firstly and resize the buffer accordingly.
|
fails, destroy the existing draw buffer and call `lv_snapshot_take` directly.
|
||||||
|
|
||||||
.. _snapshot_example:
|
.. _snapshot_example:
|
||||||
|
|
||||||
|
@ -7,9 +7,9 @@ static void event_cb(lv_event_t * e)
|
|||||||
lv_obj_t * img = lv_event_get_target(e);
|
lv_obj_t * img = lv_event_get_target(e);
|
||||||
|
|
||||||
if(snapshot_obj) {
|
if(snapshot_obj) {
|
||||||
lv_image_dsc_t * snapshot = (void *)lv_image_get_src(snapshot_obj);
|
lv_draw_buf_t * snapshot = (lv_draw_buf_t *)lv_image_get_src(snapshot_obj);
|
||||||
if(snapshot) {
|
if(snapshot) {
|
||||||
lv_snapshot_free(snapshot);
|
lv_draw_buf_destroy(snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Update the snapshot, we know parent of object is the container.*/
|
/*Update the snapshot, we know parent of object is the container.*/
|
||||||
|
@ -39,38 +39,41 @@
|
|||||||
* GLOBAL FUNCTIONS
|
* GLOBAL FUNCTIONS
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_color_format_t cf)
|
/**
|
||||||
|
* Create a draw buffer for object to store the snapshot image.
|
||||||
|
*/
|
||||||
|
lv_draw_buf_t * lv_snapshot_create_draw_buf(lv_obj_t * obj, lv_color_format_t cf)
|
||||||
{
|
{
|
||||||
LV_ASSERT_NULL(obj);
|
|
||||||
switch(cf) {
|
|
||||||
case LV_COLOR_FORMAT_RGB565:
|
|
||||||
case LV_COLOR_FORMAT_RGB888:
|
|
||||||
case LV_COLOR_FORMAT_XRGB8888:
|
|
||||||
case LV_COLOR_FORMAT_ARGB8888:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LV_LOG_WARN("Not supported color format");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lv_obj_update_layout(obj);
|
lv_obj_update_layout(obj);
|
||||||
|
|
||||||
/*Width and height determine snapshot image size.*/
|
|
||||||
int32_t w = lv_obj_get_width(obj);
|
int32_t w = lv_obj_get_width(obj);
|
||||||
int32_t h = lv_obj_get_height(obj);
|
int32_t h = lv_obj_get_height(obj);
|
||||||
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
|
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
|
||||||
w += ext_size * 2;
|
w += ext_size * 2;
|
||||||
h += ext_size * 2;
|
h += ext_size * 2;
|
||||||
|
if(w == 0 || h == 0) return NULL;
|
||||||
|
|
||||||
return lv_draw_buf_width_to_stride(w, cf) * h;
|
return lv_draw_buf_create(w, h, cf, LV_STRIDE_AUTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_image_dsc_t * dsc, void * buf,
|
lv_result_t lv_snapshot_reshape_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf)
|
||||||
uint32_t buf_size)
|
{
|
||||||
|
lv_obj_update_layout(obj);
|
||||||
|
int32_t w = lv_obj_get_width(obj);
|
||||||
|
int32_t h = lv_obj_get_height(obj);
|
||||||
|
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
|
||||||
|
w += ext_size * 2;
|
||||||
|
h += ext_size * 2;
|
||||||
|
if(w == 0 || h == 0) return LV_RESULT_INVALID;
|
||||||
|
|
||||||
|
draw_buf = lv_draw_buf_reshape(draw_buf, LV_COLOR_FORMAT_UNKNOWN, w, h, LV_STRIDE_AUTO);
|
||||||
|
return draw_buf == NULL ? LV_RESULT_INVALID : LV_RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_result_t lv_snapshot_take_to_draw_buf(lv_obj_t * obj, lv_color_format_t cf, lv_draw_buf_t * draw_buf)
|
||||||
{
|
{
|
||||||
LV_ASSERT_NULL(obj);
|
LV_ASSERT_NULL(obj);
|
||||||
LV_ASSERT_NULL(dsc);
|
LV_ASSERT_NULL(draw_buf);
|
||||||
LV_ASSERT_NULL(buf);
|
lv_result_t res;
|
||||||
|
|
||||||
switch(cf) {
|
switch(cf) {
|
||||||
case LV_COLOR_FORMAT_RGB565:
|
case LV_COLOR_FORMAT_RGB565:
|
||||||
@ -83,38 +86,23 @@ lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_ima
|
|||||||
return LV_RESULT_INVALID;
|
return LV_RESULT_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t buf_size_needed = lv_snapshot_buf_size_needed(obj, cf);
|
res = lv_snapshot_reshape_draw_buf(obj, draw_buf);
|
||||||
if(buf_size_needed == 0 || buf_size < buf_size_needed) return LV_RESULT_INVALID;
|
if(res != LV_RESULT_OK) return res;
|
||||||
|
|
||||||
LV_ASSERT_MSG(buf == lv_draw_buf_align(buf, cf), "Buffer is not aligned");
|
/* clear draw buffer*/
|
||||||
|
lv_draw_buf_clear(draw_buf, NULL);
|
||||||
/*Width and height determine snapshot image size.*/
|
|
||||||
int32_t w = lv_obj_get_width(obj);
|
|
||||||
int32_t h = lv_obj_get_height(obj);
|
|
||||||
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
|
|
||||||
w += ext_size * 2;
|
|
||||||
h += ext_size * 2;
|
|
||||||
|
|
||||||
lv_area_t snapshot_area;
|
lv_area_t snapshot_area;
|
||||||
|
int32_t w = draw_buf->header.w;
|
||||||
|
int32_t h = draw_buf->header.h;
|
||||||
|
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
|
||||||
lv_obj_get_coords(obj, &snapshot_area);
|
lv_obj_get_coords(obj, &snapshot_area);
|
||||||
lv_area_increase(&snapshot_area, ext_size, ext_size);
|
lv_area_increase(&snapshot_area, ext_size, ext_size);
|
||||||
|
|
||||||
lv_memzero(buf, buf_size);
|
|
||||||
dsc->data = buf;
|
|
||||||
dsc->data_size = buf_size_needed;
|
|
||||||
/*Keep header flags unchanged, because we don't know if it's allocated or not.*/
|
|
||||||
dsc->header.w = w;
|
|
||||||
dsc->header.h = h;
|
|
||||||
dsc->header.cf = cf;
|
|
||||||
dsc->header.magic = LV_IMAGE_HEADER_MAGIC;
|
|
||||||
|
|
||||||
lv_layer_t layer;
|
lv_layer_t layer;
|
||||||
lv_memzero(&layer, sizeof(layer));
|
lv_memzero(&layer, sizeof(layer));
|
||||||
|
|
||||||
lv_draw_buf_t draw_buf;
|
layer.draw_buf = draw_buf;
|
||||||
lv_draw_buf_from_image(&draw_buf, dsc);
|
|
||||||
|
|
||||||
layer.draw_buf = &draw_buf;
|
|
||||||
layer.buf_area.x1 = snapshot_area.x1;
|
layer.buf_area.x1 = snapshot_area.x1;
|
||||||
layer.buf_area.y1 = snapshot_area.y1;
|
layer.buf_area.y1 = snapshot_area.y1;
|
||||||
layer.buf_area.x2 = snapshot_area.x1 + w - 1;
|
layer.buf_area.x2 = snapshot_area.x1 + w - 1;
|
||||||
@ -141,34 +129,18 @@ lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_ima
|
|||||||
return LV_RESULT_OK;
|
return LV_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_image_dsc_t * lv_snapshot_take(lv_obj_t * obj, lv_color_format_t cf)
|
lv_draw_buf_t * lv_snapshot_take(lv_obj_t * obj, lv_color_format_t cf)
|
||||||
{
|
{
|
||||||
LV_ASSERT_NULL(obj);
|
LV_ASSERT_NULL(obj);
|
||||||
lv_obj_update_layout(obj);
|
lv_draw_buf_t * draw_buf = lv_snapshot_create_draw_buf(obj, cf);
|
||||||
int32_t w = lv_obj_get_width(obj);
|
|
||||||
int32_t h = lv_obj_get_height(obj);
|
|
||||||
int32_t ext_size = _lv_obj_get_ext_draw_size(obj);
|
|
||||||
w += ext_size * 2;
|
|
||||||
h += ext_size * 2;
|
|
||||||
if(w == 0 || h == 0) return NULL;
|
|
||||||
|
|
||||||
lv_draw_buf_t * draw_buf = lv_draw_buf_create(w, h, cf, LV_STRIDE_AUTO);
|
|
||||||
if(draw_buf == NULL) return NULL;
|
if(draw_buf == NULL) return NULL;
|
||||||
|
|
||||||
if(lv_snapshot_take_to_buf(obj, cf, (lv_image_dsc_t *)draw_buf, draw_buf->data, draw_buf->data_size) != LV_RESULT_OK) {
|
if(lv_snapshot_take_to_draw_buf(obj, cf, draw_buf) != LV_RESULT_OK) {
|
||||||
lv_draw_buf_destroy(draw_buf);
|
lv_draw_buf_destroy(draw_buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (lv_image_dsc_t *)draw_buf;
|
return draw_buf;
|
||||||
}
|
|
||||||
|
|
||||||
void lv_snapshot_free(lv_image_dsc_t * dsc)
|
|
||||||
{
|
|
||||||
if(!dsc)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lv_draw_buf_destroy((lv_draw_buf_t *)dsc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
|
@ -32,29 +32,54 @@ extern "C" {
|
|||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take snapshot for object with its children, alloc the memory needed.
|
* Take snapshot for object with its children, create the draw buffer as needed.
|
||||||
* @param obj the object to generate snapshot.
|
* @param obj the object to generate snapshot.
|
||||||
* @param cf color format for generated image.
|
* @param cf color format for generated image.
|
||||||
* @return a pointer to an image descriptor, or NULL if failed.
|
* @return a pointer to an draw buffer containing snapshot image, or NULL if failed.
|
||||||
*/
|
*/
|
||||||
lv_image_dsc_t * lv_snapshot_take(lv_obj_t * obj, lv_color_format_t cf);
|
lv_draw_buf_t * lv_snapshot_take(lv_obj_t * obj, lv_color_format_t cf);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Create a draw buffer to store the snapshot image for object.
|
||||||
|
* @param obj the object to generate snapshot.
|
||||||
|
* @param cf color format for generated image.
|
||||||
|
* @return a pointer to an draw buffer ready for taking snapshot, or NULL if failed.
|
||||||
|
*/
|
||||||
|
lv_draw_buf_t * lv_snapshot_create_draw_buf(lv_obj_t * obj, lv_color_format_t cf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reshape the draw buffer to prepare for taking snapshot for obj.
|
||||||
|
* This is usually used to check if the existing draw buffer is enough for
|
||||||
|
* obj snapshot. If return LV_RESULT_INVALID, you should create a new one.
|
||||||
|
* @param draw_buf the draw buffer to reshape.
|
||||||
|
* @param obj the object to generate snapshot.
|
||||||
|
*/
|
||||||
|
lv_result_t lv_snapshot_reshape_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take snapshot for object with its children, save image info to provided buffer.
|
||||||
|
* @param obj the object to generate snapshot.
|
||||||
|
* @param cf color format for new snapshot image.
|
||||||
|
* It could differ with cf of `draw_buf` as long as the new cf will fit in.
|
||||||
|
* @param draw_buf the draw buffer to store the image result. It's reshaped automatically.
|
||||||
|
* @return LV_RESULT_OK on success, LV_RESULT_INVALID on error.
|
||||||
|
*/
|
||||||
|
lv_result_t lv_snapshot_take_to_draw_buf(lv_obj_t * obj, lv_color_format_t cf, lv_draw_buf_t * draw_buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legacy API, use `lv_draw_buf_destroy` instead.
|
||||||
|
*
|
||||||
* Free the snapshot image returned by @ref lv_snapshot_take
|
* Free the snapshot image returned by @ref lv_snapshot_take
|
||||||
* It will firstly free the data image takes, then the image descriptor.
|
|
||||||
* @param dsc the image descriptor generated by lv_snapshot_take.
|
* @param dsc the image descriptor generated by lv_snapshot_take.
|
||||||
*/
|
*/
|
||||||
void lv_snapshot_free(lv_image_dsc_t * dsc);
|
static inline void lv_snapshot_free(lv_image_dsc_t * dsc)
|
||||||
|
{
|
||||||
/**
|
LV_LOG_WARN("Legacy API, use lv_draw_buf_destroy instead.");
|
||||||
* Get the buffer needed for object snapshot image.
|
lv_draw_buf_destroy((lv_draw_buf_t *)dsc);
|
||||||
* @param obj the object to generate snapshot.
|
}
|
||||||
* @param cf color format for generated image.
|
|
||||||
* @return the buffer size needed in bytes
|
|
||||||
*/
|
|
||||||
uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_color_format_t cf);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Legacy API, use lv_snapshot_take_to_draw_buf instead.
|
||||||
* Take snapshot for object with its children, save image info to provided buffer.
|
* Take snapshot for object with its children, save image info to provided buffer.
|
||||||
* @param obj the object to generate snapshot.
|
* @param obj the object to generate snapshot.
|
||||||
* @param cf color format for generated image.
|
* @param cf color format for generated image.
|
||||||
@ -63,8 +88,19 @@ uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_color_format_t cf);
|
|||||||
* @param buf_size provided buffer size in bytes.
|
* @param buf_size provided buffer size in bytes.
|
||||||
* @return LV_RESULT_OK on success, LV_RESULT_INVALID on error.
|
* @return LV_RESULT_OK on success, LV_RESULT_INVALID on error.
|
||||||
*/
|
*/
|
||||||
lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_image_dsc_t * dsc, void * buf,
|
static inline lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_image_dsc_t * dsc,
|
||||||
uint32_t buf_size);
|
void * buf,
|
||||||
|
uint32_t buf_size)
|
||||||
|
{
|
||||||
|
lv_draw_buf_t draw_buf;
|
||||||
|
LV_LOG_WARN("Legacy API, use lv_snapshot_take_to_draw_buf instead.");
|
||||||
|
lv_draw_buf_init(&draw_buf, 1, 1, cf, buf_size, buf, buf_size);
|
||||||
|
lv_result_t res = lv_snapshot_take_to_draw_buf(obj, cf, &draw_buf);
|
||||||
|
if(res == LV_RESULT_OK) {
|
||||||
|
lv_memcpy((void *)dsc, &draw_buf, sizeof(lv_image_dsc_t));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
* MACROS
|
* MACROS
|
||||||
|
@ -14,7 +14,7 @@ void test_snapshot_should_not_leak_memory(void)
|
|||||||
uint32_t final_available_memory = 0;
|
uint32_t final_available_memory = 0;
|
||||||
lv_mem_monitor_t monitor;
|
lv_mem_monitor_t monitor;
|
||||||
|
|
||||||
lv_image_dsc_t * snapshots[NUM_SNAPSHOTS] = {NULL};
|
lv_draw_buf_t * snapshots[NUM_SNAPSHOTS] = {NULL};
|
||||||
|
|
||||||
lv_mem_monitor(&monitor);
|
lv_mem_monitor(&monitor);
|
||||||
initial_available_memory = monitor.free_size;
|
initial_available_memory = monitor.free_size;
|
||||||
@ -25,7 +25,7 @@ void test_snapshot_should_not_leak_memory(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(idx = 0; idx < NUM_SNAPSHOTS; idx++) {
|
for(idx = 0; idx < NUM_SNAPSHOTS; idx++) {
|
||||||
lv_snapshot_free(snapshots[idx]);
|
lv_draw_buf_destroy(snapshots[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_mem_monitor(&monitor);
|
lv_mem_monitor(&monitor);
|
||||||
@ -40,7 +40,7 @@ void test_snapshot_take_snapshot_immidiately_after_obj_create(void)
|
|||||||
lv_obj_set_style_text_font(label, &lv_font_montserrat_28, 0);
|
lv_obj_set_style_text_font(label, &lv_font_montserrat_28, 0);
|
||||||
lv_label_set_text(label, "Wubba lubba dub dub!");
|
lv_label_set_text(label, "Wubba lubba dub dub!");
|
||||||
|
|
||||||
lv_image_dsc_t * draw_dsc = lv_snapshot_take(label, LV_COLOR_FORMAT_ARGB8888);
|
lv_draw_buf_t * draw_dsc = lv_snapshot_take(label, LV_COLOR_FORMAT_ARGB8888);
|
||||||
lv_obj_t * img_obj = lv_image_create(lv_screen_active());
|
lv_obj_t * img_obj = lv_image_create(lv_screen_active());
|
||||||
lv_image_set_src(img_obj, draw_dsc);
|
lv_image_set_src(img_obj, draw_dsc);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user