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:
30
Kconfig
30
Kconfig
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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)
|
||||
|
||||
/*-------------
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
**********************/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user