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
|
||||
: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
|
||||
image descriptor.
|
||||
|
||||
Take caution to free the snapshot but not delete the image object.
|
||||
Before free the memory, be sure to firstly unlink it from image object,
|
||||
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));`.
|
||||
The snapshot image which is the draw buffer returned by :cpp:func:`lv_snapshot_take`
|
||||
normally won't be added to cache because it can be drawn directly. So you don't need
|
||||
to invalidate cache by :cpp:func:`lv_image_cache_drop` before destroy the draw buffer.
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
lv_snapshot_free(snapshot);
|
||||
lv_draw_buf_destroy(snapshot);
|
||||
}
|
||||
snapshot = lv_snapshot_take(obj, LV_COLOR_FORMAT_ARGB8888);
|
||||
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
|
||||
``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);``
|
||||
for this case. It's caller's responsibility to alloc/free the memory.
|
||||
``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 create and destroy the draw buffer.
|
||||
|
||||
If snapshot is generated successfully, the image descriptor is updated
|
||||
and image data will be stored to provided ``buf``.
|
||||
|
||||
Note that snapshot may fail if provided buffer is not enough, which may
|
||||
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
|
||||
firstly and resize the buffer accordingly.
|
||||
:cpp:func:`lv_snapshot_reshape_draw_buf` to prepare the buffer firstly and if it
|
||||
fails, destroy the existing draw buffer and call `lv_snapshot_take` directly.
|
||||
|
||||
.. _snapshot_example:
|
||||
|
||||
|
@ -7,9 +7,9 @@ static void event_cb(lv_event_t * e)
|
||||
lv_obj_t * img = lv_event_get_target(e);
|
||||
|
||||
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) {
|
||||
lv_snapshot_free(snapshot);
|
||||
lv_draw_buf_destroy(snapshot);
|
||||
}
|
||||
|
||||
/*Update the snapshot, we know parent of object is the container.*/
|
||||
|
@ -39,38 +39,41 @@
|
||||
* 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);
|
||||
|
||||
/*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;
|
||||
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,
|
||||
uint32_t buf_size)
|
||||
lv_result_t lv_snapshot_reshape_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf)
|
||||
{
|
||||
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(dsc);
|
||||
LV_ASSERT_NULL(buf);
|
||||
LV_ASSERT_NULL(draw_buf);
|
||||
lv_result_t res;
|
||||
|
||||
switch(cf) {
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t buf_size_needed = lv_snapshot_buf_size_needed(obj, cf);
|
||||
if(buf_size_needed == 0 || buf_size < buf_size_needed) return LV_RESULT_INVALID;
|
||||
res = lv_snapshot_reshape_draw_buf(obj, draw_buf);
|
||||
if(res != LV_RESULT_OK) return res;
|
||||
|
||||
LV_ASSERT_MSG(buf == lv_draw_buf_align(buf, cf), "Buffer is not aligned");
|
||||
|
||||
/*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;
|
||||
/* clear draw buffer*/
|
||||
lv_draw_buf_clear(draw_buf, NULL);
|
||||
|
||||
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_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_memzero(&layer, sizeof(layer));
|
||||
|
||||
lv_draw_buf_t draw_buf;
|
||||
lv_draw_buf_from_image(&draw_buf, dsc);
|
||||
|
||||
layer.draw_buf = &draw_buf;
|
||||
layer.draw_buf = draw_buf;
|
||||
layer.buf_area.x1 = snapshot_area.x1;
|
||||
layer.buf_area.y1 = snapshot_area.y1;
|
||||
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;
|
||||
}
|
||||
|
||||
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_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 NULL;
|
||||
|
||||
lv_draw_buf_t * draw_buf = lv_draw_buf_create(w, h, cf, LV_STRIDE_AUTO);
|
||||
lv_draw_buf_t * draw_buf = lv_snapshot_create_draw_buf(obj, cf);
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (lv_image_dsc_t *)draw_buf;
|
||||
}
|
||||
|
||||
void lv_snapshot_free(lv_image_dsc_t * dsc)
|
||||
{
|
||||
if(!dsc)
|
||||
return;
|
||||
|
||||
lv_draw_buf_destroy((lv_draw_buf_t *)dsc);
|
||||
return draw_buf;
|
||||
}
|
||||
|
||||
/**********************
|
||||
|
@ -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 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
|
||||
* It will firstly free the data image takes, then the image descriptor.
|
||||
* @param dsc the image descriptor generated by lv_snapshot_take.
|
||||
*/
|
||||
void lv_snapshot_free(lv_image_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Get the buffer needed for object snapshot image.
|
||||
* @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);
|
||||
static inline void lv_snapshot_free(lv_image_dsc_t * dsc)
|
||||
{
|
||||
LV_LOG_WARN("Legacy API, use lv_draw_buf_destroy instead.");
|
||||
lv_draw_buf_destroy((lv_draw_buf_t *)dsc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy API, use lv_snapshot_take_to_draw_buf instead.
|
||||
* 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 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.
|
||||
* @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,
|
||||
uint32_t buf_size);
|
||||
static inline 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_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
|
||||
|
@ -14,7 +14,7 @@ void test_snapshot_should_not_leak_memory(void)
|
||||
uint32_t final_available_memory = 0;
|
||||
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);
|
||||
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++) {
|
||||
lv_snapshot_free(snapshots[idx]);
|
||||
lv_draw_buf_destroy(snapshots[idx]);
|
||||
}
|
||||
|
||||
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_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_image_set_src(img_obj, draw_dsc);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user