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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user