fix(gradient): general cleanup and fix for alignment issues (#3036)

* Try to fix ASAN behavior

* improve alignments

* fix buffer overflow and various other fixes

* minor fixes

* formatting

Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
X-Ryl669
2022-01-24 15:47:47 +01:00
committed by GitHub
parent ba083dfd6d
commit 923defd6b6
20 changed files with 314 additions and 193 deletions

30
Kconfig
View File

@@ -167,6 +167,36 @@ menu "LVGL configuration"
save the continuous open/decode of images.
However the opened images might consume additional RAM.
config LV_GRADIENT_MAX_STOPS
int "Number of stops allowed per gradient."
default 2
help
Increase this to allow more stops.
This adds (sizeof(lv_color_t) + 1) bytes per additional stop
config LV_GRAD_CACHE_DEF_SIZE
int "Default gradient buffer size."
default 0
help
When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again.
LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes.
If the cache is too small the map will be allocated only while it's required for the drawing.
0 mean no caching.
config LV_DITHER_GRADIENT
bool "Allow dithering the gradients"
help
Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display)
LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion
config LV_DITHER_ERROR_DIFFUSION
bool "Add support for error diffusion dithering"
depends on LV_DITHER_GRADIENT
help
Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing.
The increase in memory consumption is (24 bits * object's width)
config LV_DISP_ROT_MAX_BUF
int "Maximum buffer size to allocate for rotation"
default 10240

View File

@@ -252,8 +252,8 @@ Set the point from which the background's gradient color should start. 0 means t
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
</ul>
### bg_gradient
Set the gradient definition for the body. The pointed instance must exist while the object is alive. NULL to disable
### bg_grad
Set the gradient definition. The pointed instance must exist while the object is alive. NULL to disable. It wraps `BG_GRAD_COLOR`, `BG_GRAD_DIR`, `BG_MAIN_STOP` and `BG_GRAD_STOP` into one descriptor and allows craeting gradients with more colors too.
<ul>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> `NULL`</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> No</li>

View File

@@ -12,7 +12,7 @@ void lv_example_style_2(void)
/*Make a gradient*/
lv_style_set_bg_opa(&style, LV_OPA_COVER);
static lv_gradient_t grad;
static lv_grad_dsc_t grad;
grad.dir = LV_GRAD_DIR_VER;
grad.stops_count = 2;
grad.stops[0].color = lv_palette_lighten(LV_PALETTE_GREY, 1);
@@ -22,7 +22,7 @@ void lv_example_style_2(void)
grad.stops[0].frac = 128;
grad.stops[1].frac = 192;
lv_style_set_bg_gradient(&style, &grad);
lv_style_set_bg_grad(&style, &grad);
/*Create an object with the new style*/
lv_obj_t * obj = lv_obj_create(lv_scr_act());

View File

@@ -118,21 +118,6 @@
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
* 0: to disable caching */
#define LV_CIRCLE_CACHE_SIZE 4
/*Allow dithering gradient (to achieve visual smooth color gradients on limited color depth display)
*LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
*The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */
#define LV_DITHER_GRADIENT 1
/*Add support for error diffusion dithering.
*Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing.
*The increase in memory consumption is (24 bits * object's width)*/
#define LV_DITHER_ERROR_DIFFUSION 1
/**Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2
#endif /*LV_DRAW_COMPLEX*/
/*Default image cache size. Image caching keeps the images opened.
@@ -140,9 +125,32 @@
*With complex image decoders (e.g. PNG or JPG) caching can save the continuous open/decode of images.
*However the opened images might consume additional RAM.
*0: to disable caching*/
#define LV_IMG_CACHE_DEF_SIZE 0
#define LV_IMG_CACHE_DEF_SIZE 0
/*Maximum buffer size to allocate for rotation. Only used if software rotation is enabled in the display driver.*/
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#define LV_GRADIENT_MAX_STOPS 2
/*Default gradient buffer size.
*When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again.
*LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes.
*If the cache is too small the map will be allocated only while it's required for the drawing.
*0 mean no caching.*/
#define LV_GRAD_CACHE_DEF_SIZE 0
/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display)
*LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
*The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */
#define LV_DITHER_GRADIENT 0
#if LV_DITHER_GRADIENT
/*Add support for error diffusion dithering.
*Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing.
*The increase in memory consumption is (24 bits * object's width)*/
#define LV_DITHER_ERROR_DIFFUSION 0
#endif
/*Maximum buffer size to allocate for rotation.
*Only used if software rotation is enabled in the display driver.*/
#define LV_DISP_ROT_MAX_BUF (10*1024)
/*-------------

View File

@@ -120,9 +120,9 @@ props = [
'style_type': 'num', 'var_type': 'lv_coord_t', 'default':255, 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "Set the point from which the background's gradient color should start. 0 means to top/left side, 255 the bottom/right side, 128 the center, and so on"},
{'name': 'BG_GRADIENT',
'style_type': 'ptr', 'var_type': 'const lv_gradient_t *', 'default':'`NULL`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "Set the gradient definition for the body. The pointed instance must exist while the object is alive. NULL to disable"},
{'name': 'BG_GRAD',
'style_type': 'ptr', 'var_type': 'const lv_grad_dsc_t *', 'default':'`NULL`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "Set the gradient definition. The pointed instance must exist while the object is alive. NULL to disable. It wraps `BG_GRAD_COLOR`, `BG_GRAD_DIR`, `BG_MAIN_STOP` and `BG_GRAD_STOP` into one descriptor and allows creating gradients with more colors too."},
{'name': 'BG_DITHER_MODE',
'style_type': 'num', 'var_type': 'lv_dither_mode_t', 'default':'`LV_DITHER_NONE`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,

View File

@@ -58,7 +58,7 @@ void lv_obj_init_draw_rect_dsc(lv_obj_t * obj, uint32_t part, lv_draw_rect_dsc_t
draw_dsc->bg_opa = lv_obj_get_style_bg_opa(obj, part);
if(draw_dsc->bg_opa > LV_OPA_MIN) {
draw_dsc->bg_color = lv_obj_get_style_bg_color_filtered(obj, part);
const lv_gradient_t * grad = lv_obj_get_style_bg_gradient(obj, part);
const lv_grad_dsc_t * grad = lv_obj_get_style_bg_grad(obj, part);
if(grad && grad->dir != LV_GRAD_DIR_NONE) {
lv_memcpy(&draw_dsc->bg_grad, grad, sizeof(*grad));
}

View File

@@ -232,12 +232,12 @@ void lv_obj_set_style_bg_grad_stop(struct _lv_obj_t * obj, lv_coord_t value, lv_
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD_STOP, v, selector);
}
void lv_obj_set_style_bg_gradient(struct _lv_obj_t * obj, const lv_gradient_t * value, lv_style_selector_t selector)
void lv_obj_set_style_bg_grad(struct _lv_obj_t * obj, const lv_grad_dsc_t * value, lv_style_selector_t selector)
{
lv_style_value_t v = {
.ptr = value
};
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRADIENT, v, selector);
lv_obj_set_local_style_prop(obj, LV_STYLE_BG_GRAD, v, selector);
}
void lv_obj_set_style_bg_dither_mode(struct _lv_obj_t * obj, lv_dither_mode_t value, lv_style_selector_t selector)

View File

@@ -172,10 +172,10 @@ static inline lv_coord_t lv_obj_get_style_bg_grad_stop(const struct _lv_obj_t *
return (lv_coord_t)v.num;
}
static inline const lv_gradient_t * lv_obj_get_style_bg_gradient(const struct _lv_obj_t * obj, uint32_t part)
static inline const lv_grad_dsc_t * lv_obj_get_style_bg_grad(const struct _lv_obj_t * obj, uint32_t part)
{
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRADIENT);
return (const lv_gradient_t *)v.ptr;
lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_BG_GRAD);
return (const lv_grad_dsc_t *)v.ptr;
}
static inline lv_dither_mode_t lv_obj_get_style_bg_dither_mode(const struct _lv_obj_t * obj, uint32_t part)
@@ -574,7 +574,7 @@ void lv_obj_set_style_bg_grad_color_filtered(struct _lv_obj_t * obj, lv_color_t
void lv_obj_set_style_bg_grad_dir(struct _lv_obj_t * obj, lv_grad_dir_t value, lv_style_selector_t selector);
void lv_obj_set_style_bg_main_stop(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_bg_grad_stop(struct _lv_obj_t * obj, lv_coord_t value, lv_style_selector_t selector);
void lv_obj_set_style_bg_gradient(struct _lv_obj_t * obj, const lv_gradient_t * value, lv_style_selector_t selector);
void lv_obj_set_style_bg_grad(struct _lv_obj_t * obj, const lv_grad_dsc_t * value, lv_style_selector_t selector);
void lv_obj_set_style_bg_dither_mode(struct _lv_obj_t * obj, lv_dither_mode_t value, lv_style_selector_t selector);
void lv_obj_set_style_bg_img_src(struct _lv_obj_t * obj, const void * value, lv_style_selector_t selector);
void lv_obj_set_style_bg_img_opa(struct _lv_obj_t * obj, lv_opa_t value, lv_style_selector_t selector);

View File

@@ -39,7 +39,7 @@ typedef struct {
union {
#endif
lv_color_t bg_color; /**< First element of a gradient is a color, so it maps well here*/
lv_gradient_t bg_grad;
lv_grad_dsc_t bg_grad;
#if __STDC_VERSION__ >= 201112L
};
#endif

View File

@@ -17,7 +17,7 @@
#if _DITHER_GRADIENT
LV_ATTRIBUTE_FAST_MEM void lv_dither_none(lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_none(lv_grad_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
{
LV_UNUSED(x);
LV_UNUSED(y);
@@ -40,7 +40,7 @@ static const uint8_t dither_ordered_threshold_matrix[8 * 8] = {
}; /* Shift by 6 to normalize */
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_grad_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
{
LV_UNUSED(x);
/* For vertical dithering, the error is spread on the next column (and not next line).
@@ -63,7 +63,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_gradient_cache_t * grad, lv_
grad->map[j] = lv_color_hex(t.full);
}
}
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_grad_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
{
/* For vertical dithering, the error is spread on the next column (and not next line).
Since the renderer is scanline based, it's not obvious what could be used to perform the rendering efficiently.
@@ -99,7 +99,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_gradient_cache_t * grad, lv_
#if LV_DITHER_ERROR_DIFFUSION == 1
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_gradient_cache_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_grad_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
{
LV_UNUSED(xs);
LV_UNUSED(y);
@@ -153,7 +153,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_gradient_cache_t * grad, lv
grad->map[grad->size - 1] = lv_color_hex(grad->hmap[grad->size - 1].full);
}
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_ver(lv_gradient_cache_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_ver(lv_grad_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
{
/* Try to implement error diffusion on a vertical gradient and an horizontal map using those tricks:
Since the given hi-resolution gradient (in src) is vertical, the Floyd Steinberg algorithm pass need to be rotated,

View File

@@ -19,13 +19,12 @@ extern "C" {
/*********************
* DEFINES
*********************/
#if LV_COLOR_DEPTH < 32 && LV_DRAW_COMPLEX == 1 && LV_DITHER_GRADIENT == 1
#if LV_COLOR_DEPTH < 32 && LV_DITHER_GRADIENT == 1
#define _DITHER_GRADIENT 1
#else
#define _DITHER_GRADIENT 0
#endif
/**********************
* TYPEDEFS
**********************/

View File

@@ -8,6 +8,7 @@
*********************/
#include "lv_draw_sw_gradient.h"
#include "../../misc/lv_gc.h"
#include "../../misc/lv_types.h"
/*********************
* DEFINES
@@ -20,6 +21,12 @@
#define GRAD_CONV(t, x) t = x
#endif
#if defined(LV_ARCH_64)
#define ALIGN(X) (((X) + 7) & ~7)
#else
#define ALIGN(X) (((X) + 3) & ~3)
#endif
#define MAX_WIN_RES 1024 /**TODO: Find a way to get this information: max(horz_res, vert_res)*/
#if _DITHER_GRADIENT
@@ -35,17 +42,17 @@
/**********************
* STATIC PROTOTYPES
**********************/
static lv_gradient_cache_t * next_in_cache(lv_gradient_cache_t * first);
static lv_grad_t * next_in_cache(lv_grad_t * item);
typedef lv_res_t (*op_cache_t)(lv_gradient_cache_t * c, void * ctx);
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_gradient_cache_t ** out);
static size_t get_cache_item_size(lv_gradient_cache_t * c);
static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h);
static lv_res_t find_oldest_item_life(lv_gradient_cache_t * c, void * ctx);
static lv_res_t kill_oldest_item(lv_gradient_cache_t * c, void * ctx);
static lv_res_t find_item(lv_gradient_cache_t * c, void * ctx);
static void free_item(lv_gradient_cache_t * c);
static uint32_t compute_key(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h);
typedef lv_res_t (*op_cache_t)(lv_grad_t * c, void * ctx);
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_grad_t ** out);
static size_t get_cache_item_size(lv_grad_t * c);
static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h);
static lv_res_t find_oldest_item_life(lv_grad_t * c, void * ctx);
static lv_res_t kill_oldest_item(lv_grad_t * c, void * ctx);
static lv_res_t find_item(lv_grad_t * c, void * ctx);
static void free_item(lv_grad_t * c);
static uint32_t compute_key(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h);
/**********************
@@ -62,45 +69,44 @@ union void_cast {
const uint32_t value;
};
static uint32_t compute_key(const lv_gradient_t * g, lv_coord_t size, lv_coord_t w)
static uint32_t compute_key(const lv_grad_dsc_t * g, lv_coord_t size, lv_coord_t w)
{
union void_cast v;
v.ptr = g;
return (v.value ^ size ^ (w >> 1)); /*Yes, this is correct, it's like a hash that changes if the width changes*/
}
static size_t get_cache_item_size(lv_gradient_cache_t * c)
static size_t get_cache_item_size(lv_grad_t * c)
{
size_t s = sizeof(*c) + c->alloc_size * sizeof(lv_color_t)
size_t s = ALIGN(sizeof(*c)) + ALIGN(c->alloc_size * sizeof(lv_color_t));
#if _DITHER_GRADIENT
+ c->size * sizeof(lv_color32_t)
s += ALIGN(c->size * sizeof(lv_color32_t));
#if LV_DITHER_ERROR_DIFFUSION == 1
+ c->w * sizeof(lv_scolor24_t)
s += ALIGN(c->w * sizeof(lv_scolor24_t));
#endif
#endif
;
return s; /* TODO: Should we align this ? */
return s;
}
static lv_gradient_cache_t * next_in_cache(lv_gradient_cache_t * first)
static lv_grad_t * next_in_cache(lv_grad_t * item)
{
if(first == NULL)
return (lv_gradient_cache_t *)LV_GC_ROOT(_lv_grad_cache_mem);
if(first == NULL)
if(grad_cache_size == 0) return NULL;
if(item == NULL)
return (lv_grad_t *)LV_GC_ROOT(_lv_grad_cache_mem);
if(item == NULL)
return NULL;
size_t s = get_cache_item_size(first);
size_t s = get_cache_item_size(item);
/*Compute the size for this cache item*/
if((uint8_t *)first + s > grad_cache_end)
return NULL;
return (lv_gradient_cache_t *)((uint8_t *)first + s);
if((uint8_t *)item + s >= grad_cache_end) return NULL;
else return (lv_grad_t *)((uint8_t *)item + s);
}
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_gradient_cache_t ** out)
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_grad_t ** out)
{
lv_gradient_cache_t * first = next_in_cache(NULL);
while(first != NULL) {
lv_grad_t * first = next_in_cache(NULL);
while(first != NULL && first->life) {
if((*func)(first, ctx) == LV_RES_OK) {
if(out != NULL) *out = first;
return LV_RES_OK;
@@ -110,19 +116,20 @@ static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_gradient_cache_t *
return LV_RES_INV;
}
static lv_res_t find_oldest_item_life(lv_gradient_cache_t * c, void * ctx)
static lv_res_t find_oldest_item_life(lv_grad_t * c, void * ctx)
{
uint32_t * min_life = (uint32_t *)ctx;
if(c->life < *min_life) *min_life = c->life;
return LV_RES_INV;
}
static void free_item(lv_gradient_cache_t * c)
static void free_item(lv_grad_t * c)
{
size_t size = get_cache_item_size(c);
size_t next_items_size = (size_t)(grad_cache_end - (uint8_t *)c) - size;
grad_cache_end -= size;
if(next_items_size) {
uint8_t * old = (uint8_t *)c;
lv_memcpy(c, ((uint8_t *)c) + size, next_items_size);
/* Then need to fix all internal pointers too */
while((uint8_t *)c != grad_cache_end) {
@@ -133,12 +140,13 @@ static void free_item(lv_gradient_cache_t * c)
c->error_acc = (lv_scolor24_t *)(((uint8_t *)c->error_acc) - size);
#endif
#endif
c = (lv_gradient_cache_t *)(((uint8_t *)c) + get_cache_item_size(c));
c = (lv_grad_t *)(((uint8_t *)c) + get_cache_item_size(c));
}
lv_memset_00(old + next_items_size, size);
}
}
static lv_res_t kill_oldest_item(lv_gradient_cache_t * c, void * ctx)
static lv_res_t kill_oldest_item(lv_grad_t * c, void * ctx)
{
uint32_t * min_life = (uint32_t *)ctx;
if(c->life == *min_life) {
@@ -148,58 +156,84 @@ static lv_res_t kill_oldest_item(lv_gradient_cache_t * c, void * ctx)
}
return LV_RES_INV;
}
static lv_res_t find_item(lv_gradient_cache_t * c, void * ctx)
static lv_res_t find_item(lv_grad_t * c, void * ctx)
{
uint32_t * k = (uint32_t *)ctx;
if(c->key == *k) return LV_RES_OK;
return LV_RES_INV;
}
static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h)
static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h)
{
lv_coord_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
lv_coord_t map_size = LV_MAX(w, h); /* The map is being used horizontally (width) unless
no dithering is selected where it's used vertically */
size_t req_size = sizeof(lv_gradient_cache_t) + map_size * sizeof(lv_color_t)
size_t req_size = ALIGN(sizeof(lv_grad_t)) + ALIGN(map_size * sizeof(lv_color_t));
#if _DITHER_GRADIENT
+ size * sizeof(lv_color32_t)
req_size += ALIGN(size * sizeof(lv_color32_t));
#if LV_DITHER_ERROR_DIFFUSION == 1
+ w * sizeof(lv_scolor24_t)
req_size += ALIGN(w * sizeof(lv_scolor24_t));
#endif
#endif
;
size_t act_size = (size_t)(grad_cache_end - LV_GC_ROOT(_lv_grad_cache_mem));
if(req_size + act_size > grad_cache_size) {
/*Need to evict items from cache until we find enough space to allocate this one */
if(req_size > grad_cache_size) {
LV_LOG_WARN("Gradient cache too small, failed to allocate");
return NULL; /*No magic here, if the empty cache is still too small*/
}
while(act_size + req_size < grad_cache_size) {
uint32_t oldest_life = UINT32_MAX;
iterate_cache(&find_oldest_item_life, &oldest_life, NULL);
iterate_cache(&kill_oldest_item, &oldest_life, NULL);
act_size = (size_t)(grad_cache_end - LV_GC_ROOT(_lv_grad_cache_mem));
}
/*Ok, now we have space to allocate*/
lv_grad_t * item = NULL;
if(req_size + act_size < grad_cache_size) {
item = (lv_grad_t *)grad_cache_end;
item->not_cached = 0;
}
lv_gradient_cache_t * item = (lv_gradient_cache_t *)grad_cache_end;
else {
/*Need to evict items from cache until we find enough space to allocate this one */
if(req_size <= grad_cache_size) {
while(act_size + req_size > grad_cache_size) {
uint32_t oldest_life = UINT32_MAX;
iterate_cache(&find_oldest_item_life, &oldest_life, NULL);
iterate_cache(&kill_oldest_item, &oldest_life, NULL);
act_size = (size_t)(grad_cache_end - LV_GC_ROOT(_lv_grad_cache_mem));
}
item = (lv_grad_t *)grad_cache_end;
item->not_cached = 0;
}
else {
/*The cache is too small. Allocate the item manually and free it later.*/
item = lv_mem_alloc(req_size);
LV_ASSERT_MALLOC(item);
if(item == NULL) return NULL;
item->not_cached = 1;
}
}
item->key = compute_key(g, size, w);
item->life = 1;
item->filled = 0;
item->alloc_size = map_size;
item->size = size;
item->map = (lv_color_t *)(grad_cache_end + sizeof(*item));
if(item->not_cached) {
uint8_t * p = (uint8_t *)item;
item->map = (lv_color_t *)(p + ALIGN(sizeof(*item)));
#if _DITHER_GRADIENT
item->hmap = (lv_color32_t *)(grad_cache_end + sizeof(*item) + map_size * sizeof(lv_color_t));
item->hmap = (lv_color32_t *)(p + ALIGN(sizeof(*item)) + ALIGN(map_size * sizeof(lv_color_t)));
#if LV_DITHER_ERROR_DIFFUSION == 1
item->error_acc = (lv_scolor24_t *)(grad_cache_end + sizeof(*item) + size * sizeof(lv_grad_color_t) +
map_size * sizeof(lv_color_t));
item->w = w;
item->error_acc = (lv_scolor24_t *)(p + ALIGN(sizeof(*item)) + ALIGN(size * sizeof(lv_grad_color_t)) +
ALIGN(map_size * sizeof(lv_color_t)));
item->w = w;
#endif
#endif
grad_cache_end += req_size;
}
else {
item->map = (lv_color_t *)(grad_cache_end + ALIGN(sizeof(*item)));
#if _DITHER_GRADIENT
item->hmap = (lv_color32_t *)(grad_cache_end + ALIGN(sizeof(*item)) + ALIGN(map_size * sizeof(lv_color_t)));
#if LV_DITHER_ERROR_DIFFUSION == 1
item->error_acc = (lv_scolor24_t *)(grad_cache_end + ALIGN(sizeof(*item)) + ALIGN(size * sizeof(lv_grad_color_t)) +
ALIGN(map_size * sizeof(lv_color_t)));
item->w = w;
#endif
#endif
grad_cache_end += req_size;
}
return item;
}
@@ -207,35 +241,38 @@ static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w
/**********************
* FUNCTIONS
**********************/
void lv_grad_free_cache()
void lv_gradient_free_cache(void)
{
lv_mem_free(LV_GC_ROOT(_lv_grad_cache_mem));
LV_GC_ROOT(_lv_grad_cache_mem) = grad_cache_end = NULL;
grad_cache_size = 0;
}
void lv_grad_set_cache_size(size_t max_bytes)
void lv_gradient_set_cache_size(size_t max_bytes)
{
lv_mem_free(LV_GC_ROOT(_lv_grad_cache_mem));
grad_cache_end = LV_GC_ROOT(_lv_grad_cache_mem) = lv_mem_alloc(max_bytes);
LV_ASSERT_MALLOC(LV_GC_ROOT(_lv_grad_cache_mem));
lv_memset_00(LV_GC_ROOT(_lv_grad_cache_mem), max_bytes);
grad_cache_size = max_bytes;
}
lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h)
lv_grad_t * lv_gradient_get(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h)
{
/* No gradient, no cache */
if(g->dir == LV_GRAD_DIR_NONE) return NULL;
/* Step 0: Check if the cache exist (else create it) */
if(!grad_cache_size) {
lv_grad_set_cache_size(LV_DEFAULT_GRAD_CACHE_SIZE);
static bool inited = false;
if(!inited) {
lv_gradient_set_cache_size(LV_GRAD_CACHE_DEF_SIZE);
inited = true;
}
/* Step 1: Search cache for the given key */
lv_coord_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
uint32_t key = compute_key(g, size, w);
lv_gradient_cache_t * item = NULL;
lv_grad_t * item = NULL;
if(iterate_cache(&find_item, &key, &item) == LV_RES_OK) {
item->life++; /* Don't forget to bump the counter */
return item;
@@ -243,39 +280,30 @@ lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * g, lv_coord_t
/* Step 2: Need to allocate an item for it */
item = allocate_item(g, w, h);
if(item == NULL) return item;
if(item == NULL) {
LV_LOG_WARN("Faild to allcoate item for teh gradient");
return item;
}
/* Step 3: Fill it with the gradient, as expected */
#if _DITHER_GRADIENT
for(lv_coord_t i = 0; i < item->size; i++) {
item->hmap[i] = lv_grad_get(g, item->size, i);
item->hmap[i] = lv_gradient_calculate(g, item->size, i);
}
#if LV_DITHER_ERROR_DIFFUSION == 1
lv_memset_00(item->error_acc, w * sizeof(lv_scolor24_t));
#endif
#else
for(lv_coord_t i = 0; i < item->size; i++) {
item->map[i] = lv_grad_get(g, item->size, i);
item->map[i] = lv_gradient_calculate(g, item->size, i);
}
#endif
return item;
}
void lv_grad_pop_from_cache(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h)
{
lv_coord_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
uint32_t key = compute_key(g, size, w);
lv_gradient_cache_t * item = NULL;
if(iterate_cache(&find_item, &key, &item) == LV_RES_OK) {
free_item(item);
}
}
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_grad_get(const lv_gradient_t * dsc, lv_coord_t range, lv_coord_t frac)
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_gradient_calculate(const lv_grad_dsc_t * dsc, lv_coord_t range,
lv_coord_t frac)
{
lv_grad_color_t tmp;
lv_color32_t one, two;
@@ -316,3 +344,10 @@ LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_grad_get(const lv_gradient_t * dsc, lv_
LV_UDIV255(two.ch.blue * mix + one.ch.blue * imix));
return r;
}
void lv_gradient_cleanup(lv_grad_t * grad)
{
if(grad->not_cached) {
lv_mem_free(grad);
}
}

View File

@@ -40,9 +40,10 @@ typedef lv_color_t lv_grad_color_t;
typedef struct _lv_gradient_cache_t {
uint32_t key; /**< A discriminating key that's built from the drawing operation.
* If the key does not match, the cache item is not used */
uint32_t life : 31; /**< A life counter that's incremented on usage. Higher counter is
uint32_t life : 30; /**< A life counter that's incremented on usage. Higher counter is
* less likely to be evicted from the cache */
uint32_t filled : 1; /**< Used to skip dithering in it if already done */
uint32_t not_cached: 1; /**< The cache was too small so this item is not managed by the cache*/
lv_color_t * map; /**< The computed gradient low bitdepth color map, points into the
* cache's buffer, no free needed */
lv_coord_t alloc_size; /**< The map allocated size in colors */
@@ -56,7 +57,7 @@ typedef struct _lv_gradient_cache_t {
lv_coord_t w; /**< The error array width in pixels */
#endif
#endif
} lv_gradient_cache_t;
} lv_grad_t;
/**********************
@@ -68,22 +69,26 @@ typedef struct _lv_gradient_cache_t {
* @param range The range to use in computation.
* @param frac The current part used in the range. frac is in [0; range]
*/
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_grad_get(const lv_gradient_t * dsc, lv_coord_t range, lv_coord_t frac);
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_gradient_calculate(const lv_grad_dsc_t * dsc, lv_coord_t range,
lv_coord_t frac);
/** Set the gradient cache size */
void lv_grad_set_cache_size(size_t max_bytes);
/** Get a gradient cache from the given parameters */
lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * gradient, lv_coord_t w, lv_coord_t h);
/** Evict item from the gradient cache (not used anymore).
* This bypass the life counter on the item to remove this item.
/**
* Set the gradient cache size
* @param max_bytes Max cahce size
*/
void lv_grad_pop_from_cache(const lv_gradient_t * gradient, lv_coord_t w, lv_coord_t h);
void lv_gradient_set_cache_size(size_t max_bytes);
/** Free the gradient cache */
void lv_grad_free_cache(void);
void lv_gradient_free_cache(void);
/** Get a gradient cache from the given parameters */
lv_grad_t * lv_gradient_get(const lv_grad_dsc_t * gradient, lv_coord_t w, lv_coord_t h);
/**
* Clean up the gradient item after it was get with `lv_grad_get_from_cache`.
* @param grad pointer to a gradient
*/
void lv_gradient_cleanup(lv_grad_t * grad);
#ifdef __cplusplus
} /*extern "C"*/

View File

@@ -169,7 +169,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
/*Get gradient if appropriate*/
lv_gradient_cache_t * grad = lv_grad_get_from_cache(&dsc->bg_grad, coords_bg_w, coords_bg_h);
lv_grad_t * grad = lv_gradient_get(&dsc->bg_grad, coords_bg_w, coords_bg_h);
if(grad && grad_dir == LV_GRAD_DIR_HOR) {
blend_dsc.src_buf = grad->map + clipped_coords.x1 - bg_coords.x1;
}
@@ -192,10 +192,29 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
#if LV_DITHER_ERROR_DIFFUSION
if(dither_mode == LV_DITHER_ORDERED)
#endif
dither_func = grad_dir == LV_GRAD_DIR_HOR ? &lv_dither_ordered_hor : &lv_dither_ordered_ver;
switch(grad_dir) {
case LV_GRAD_DIR_HOR:
dither_func = lv_dither_ordered_hor;
break;
case LV_GRAD_DIR_VER:
dither_func = lv_dither_ordered_ver;
break;
default:
dither_func = NULL;
}
#if LV_DITHER_ERROR_DIFFUSION
else if(dither_mode == LV_DITHER_ERR_DIFF)
dither_func = grad_dir == LV_GRAD_DIR_HOR ? &lv_dither_err_diff_hor : &lv_dither_err_diff_ver;
switch(grad_dir) {
case LV_GRAD_DIR_HOR:
dither_func = lv_dither_err_diff_hor;
break;
case LV_GRAD_DIR_VER:
dither_func = lv_dither_err_diff_ver;
break;
default:
dither_func = NULL;
}
#endif
#endif
@@ -212,7 +231,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[h - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -238,7 +257,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
blend_area.y2 = top_y;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, top_y - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, top_y - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[top_y - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -249,7 +268,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
blend_area.y2 = bottom_y;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, bottom_y - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, bottom_y - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[bottom_y - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -288,7 +307,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
blend_area.y2 = h;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[h - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -302,6 +321,9 @@ bg_clean_up:
lv_draw_mask_remove_id(mask_rout_id);
lv_draw_mask_free_param(&mask_rout_param);
}
if(grad) {
lv_gradient_cleanup(grad);
}
#endif
}

View File

@@ -293,47 +293,6 @@
#define LV_CIRCLE_CACHE_SIZE 4
#endif
#endif
/*Allow dithering gradient (to achieve visual smooth color gradients on limited color depth display)
*LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
*The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */
#ifndef LV_DITHER_GRADIENT
#ifdef _LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_DITHER_GRADIENT
#define LV_DITHER_GRADIENT CONFIG_LV_DITHER_GRADIENT
#else
#define LV_DITHER_GRADIENT 0
#endif
#else
#define LV_DITHER_GRADIENT 1
#endif
#endif
/*Add support for error diffusion dithering.
*Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing.
*The increase in memory consumption is (24 bits * object's width)*/
#ifndef LV_DITHER_ERROR_DIFFUSION
#ifdef _LV_KCONFIG_PRESENT
#ifdef CONFIG_LV_DITHER_ERROR_DIFFUSION
#define LV_DITHER_ERROR_DIFFUSION CONFIG_LV_DITHER_ERROR_DIFFUSION
#else
#define LV_DITHER_ERROR_DIFFUSION 0
#endif
#else
#define LV_DITHER_ERROR_DIFFUSION 1
#endif
#endif
/**Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#ifndef LV_GRADIENT_MAX_STOPS
#ifdef CONFIG_LV_GRADIENT_MAX_STOPS
#define LV_GRADIENT_MAX_STOPS CONFIG_LV_GRADIENT_MAX_STOPS
#else
#define LV_GRADIENT_MAX_STOPS 2
#endif
#endif
#endif /*LV_DRAW_COMPLEX*/
/*Default image cache size. Image caching keeps the images opened.
@@ -345,11 +304,58 @@
#ifdef CONFIG_LV_IMG_CACHE_DEF_SIZE
#define LV_IMG_CACHE_DEF_SIZE CONFIG_LV_IMG_CACHE_DEF_SIZE
#else
#define LV_IMG_CACHE_DEF_SIZE 0
#define LV_IMG_CACHE_DEF_SIZE 0
#endif
#endif
/*Maximum buffer size to allocate for rotation. Only used if software rotation is enabled in the display driver.*/
/*Number of stops allowed per gradient. Increase this to allow more stops.
*This adds (sizeof(lv_color_t) + 1) bytes per additional stop*/
#ifndef LV_GRADIENT_MAX_STOPS
#ifdef CONFIG_LV_GRADIENT_MAX_STOPS
#define LV_GRADIENT_MAX_STOPS CONFIG_LV_GRADIENT_MAX_STOPS
#else
#define LV_GRADIENT_MAX_STOPS 2
#endif
#endif
/*Default gradient buffer size.
*When LVGL calculates the gradient "maps" it can save them into a cache to avoid calculating them again.
*LV_GRAD_CACHE_DEF_SIZE sets the size of this cache in bytes.
*If the cache is too small the map will be allocated only while it's required for the drawing.
*0 mean no caching.*/
#ifndef LV_GRAD_CACHE_DEF_SIZE
#ifdef CONFIG_LV_GRAD_CACHE_DEF_SIZE
#define LV_GRAD_CACHE_DEF_SIZE CONFIG_LV_GRAD_CACHE_DEF_SIZE
#else
#define LV_GRAD_CACHE_DEF_SIZE 0
#endif
#endif
/*Allow dithering the gradients (to achieve visual smooth color gradients on limited color depth display)
*LV_DITHER_GRADIENT implies allocating one or two more lines of the object's rendering surface
*The increase in memory consumption is (32 bits * object width) plus 24 bits * object width if using error diffusion */
#ifndef LV_DITHER_GRADIENT
#ifdef CONFIG_LV_DITHER_GRADIENT
#define LV_DITHER_GRADIENT CONFIG_LV_DITHER_GRADIENT
#else
#define LV_DITHER_GRADIENT 0
#endif
#endif
#if LV_DITHER_GRADIENT
/*Add support for error diffusion dithering.
*Error diffusion dithering gets a much better visual result, but implies more CPU consumption and memory when drawing.
*The increase in memory consumption is (24 bits * object's width)*/
#ifndef LV_DITHER_ERROR_DIFFUSION
#ifdef CONFIG_LV_DITHER_ERROR_DIFFUSION
#define LV_DITHER_ERROR_DIFFUSION CONFIG_LV_DITHER_ERROR_DIFFUSION
#else
#define LV_DITHER_ERROR_DIFFUSION 0
#endif
#endif
#endif
/*Maximum buffer size to allocate for rotation.
*Only used if software rotation is enabled in the display driver.*/
#ifndef LV_DISP_ROT_MAX_BUF
#ifdef CONFIG_LV_DISP_ROT_MAX_BUF
#define LV_DISP_ROT_MAX_BUF CONFIG_LV_DISP_ROT_MAX_BUF

View File

@@ -140,7 +140,7 @@ typedef struct {
* Any of LV_GRAD_DIR_HOR, LV_GRAD_DIR_VER, LV_GRAD_DIR_NONE */
lv_dither_mode_t dither : 3; /**< Whether to dither the gradient or not.
* Any of LV_DITHER_NONE, LV_DITHER_ORDERED, LV_DITHER_ERR_DIFF */
} lv_gradient_t;
} lv_grad_dsc_t;
/**
* A common type to handle all the property types in the same way.
@@ -191,7 +191,7 @@ typedef enum {
LV_STYLE_BG_GRAD_DIR = 35,
LV_STYLE_BG_MAIN_STOP = 36,
LV_STYLE_BG_GRAD_STOP = 37,
LV_STYLE_BG_GRADIENT = 38,
LV_STYLE_BG_GRAD = 38,
LV_STYLE_BG_DITHER_MODE = 39,

View File

@@ -232,12 +232,12 @@ void lv_style_set_bg_grad_stop(lv_style_t * style, lv_coord_t value)
lv_style_set_prop(style, LV_STYLE_BG_GRAD_STOP, v);
}
void lv_style_set_bg_gradient(lv_style_t * style, const lv_gradient_t * value)
void lv_style_set_bg_grad(lv_style_t * style, const lv_grad_dsc_t * value)
{
lv_style_value_t v = {
.ptr = value
};
lv_style_set_prop(style, LV_STYLE_BG_GRADIENT, v);
lv_style_set_prop(style, LV_STYLE_BG_GRAD, v);
}
void lv_style_set_bg_dither_mode(lv_style_t * style, lv_dither_mode_t value)

View File

@@ -27,7 +27,7 @@ void lv_style_set_bg_grad_color_filtered(lv_style_t * style, lv_color_t value);
void lv_style_set_bg_grad_dir(lv_style_t * style, lv_grad_dir_t value);
void lv_style_set_bg_main_stop(lv_style_t * style, lv_coord_t value);
void lv_style_set_bg_grad_stop(lv_style_t * style, lv_coord_t value);
void lv_style_set_bg_gradient(lv_style_t * style, const lv_gradient_t * value);
void lv_style_set_bg_grad(lv_style_t * style, const lv_grad_dsc_t * value);
void lv_style_set_bg_dither_mode(lv_style_t * style, lv_dither_mode_t value);
void lv_style_set_bg_img_src(lv_style_t * style, const void * value);
void lv_style_set_bg_img_opa(lv_style_t * style, lv_opa_t value);
@@ -235,9 +235,9 @@ void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value);
.prop = LV_STYLE_BG_GRAD_STOP, .value = { .num = (int32_t)val } \
}
#define LV_STYLE_CONST_BG_GRADIENT(val) \
#define LV_STYLE_CONST_BG_GRAD(val) \
{ \
.prop = LV_STYLE_BG_GRADIENT, .value = { .ptr = val } \
.prop = LV_STYLE_BG_GRAD, .value = { .ptr = val } \
}
#define LV_STYLE_CONST_BG_DITHER_MODE(val) \

View File

@@ -68,6 +68,7 @@ set(LVGL_TEST_OPTIONS_16BIT
-DLV_MEM_SIZE=65536
-DLV_DPI_DEF=40
-DLV_DRAW_COMPLEX=1
-DLV_DITHER_GRADIENT=1
-DLV_USE_LOG=1
-DLV_USE_ASSERT_NULL=0
-DLV_USE_ASSERT_MALLOC=0
@@ -94,6 +95,9 @@ set(LVGL_TEST_OPTIONS_16BIT_SWAP
-DLV_MEM_SIZE=65536
-DLV_DPI_DEF=40
-DLV_DRAW_COMPLEX=1
-DLV_DITHER_GRADIENT=1
-DLV_DITHER_ERROR_DIFFUSION=1
-DLV_GRAD_CACHE_DEF_SIZE=8*1024
-DLV_USE_LOG=1
-DLV_USE_ASSERT_NULL=0
-DLV_USE_ASSERT_MALLOC=0
@@ -185,6 +189,9 @@ set(LVGL_TEST_OPTIONS_TEST_COMMON
-DLV_MEM_SIZE=2097152
-DLV_SHADOW_CACHE_SIZE=10240
-DLV_IMG_CACHE_DEF_SIZE=32
-DLV_DITHER_GRADIENT=1
-DLV_DITHER_ERROR_DIFFUSION=1
-DLV_GRAD_CACHE_DEF_SIZE=8*1024
-DLV_USE_LOG=1
-DLV_LOG_PRINTF=1
-DLV_USE_FONT_SUBPX=1
@@ -228,6 +235,7 @@ set(LVGL_TEST_OPTIONS_TEST_DEFHEAP
${LVGL_TEST_OPTIONS_TEST_COMMON}
-DLVGL_CI_USING_DEF_HEAP
-DLV_MEM_SIZE=2097152
-fsanitize=address
)
if (OPTIONS_MINIMAL_MONOCHROME)
@@ -245,7 +253,7 @@ elseif (OPTIONS_TEST_SYSHEAP)
set (TEST_LIBS --coverage -fsanitize=address)
elseif (OPTIONS_TEST_DEFHEAP)
set (BUILD_OPTIONS ${LVGL_TEST_OPTIONS_TEST_DEFHEAP})
set (TEST_LIBS --coverage)
set (TEST_LIBS --coverage -fsanitize=address)
else()
message(FATAL_ERROR "Must provide a known options value (check main.py?).")
endif()

View File

@@ -2,6 +2,7 @@
#include "../lvgl.h"
#include "unity/unity.h"
#include <unistd.h>
static void obj_set_height_helper(void * obj, int32_t height)
{
@@ -30,6 +31,13 @@ void test_gradient_vertical_misalignment(void)
lv_anim_set_repeat_count(&a, 100);
lv_anim_set_values(&a, 0, 300);
lv_anim_start(&a);
uint32_t i;
for(i = 0; i < 1000; i++) {
lv_timer_handler();
lv_tick_inc(100);
usleep(1000);
}
}
#endif