perf(draw) reimplement circle drawing algorithms (#2374)

* perf(draw) reimplement circle drawing algorithms

Imporve the speed of circle drawing
Add circle draw caching
Various other speed improvements

* docs describe how to use masks

* fix(draw) add missing GC root usage
This commit is contained in:
Gabor Kiss-Vamosi
2021-07-27 19:16:00 +02:00
committed by GitHub
parent e23701e2c2
commit 637b706ddc
25 changed files with 517 additions and 323 deletions
+23 -4
View File
@@ -54,13 +54,13 @@ The difference between buffering modes regarding the drawing mechanism is the fo
To use LVGL it's not required to know about the mechanisms described here, but you might find interesting to know how drawing works under hood.
Knowing about masking comes in handy if you want to customize drawing.
To learn masking let's learn the steps of drawing first.
To learn masking let's see the steps of drawing first.
LVGL performs the following steps to render any shape, image or text. It can be considered as a drawing pipeline.
1. **Prepare the draw descriptors** Create a draw descriptor from an object's styles (e.g. `lv_draw_rect_dsc_t`). This gives us the parameters for drawing, for example the colors, widths, opacity, fonts, radius, etc.
2. **Call the draw function** Call the draw function with the draw descriptor and some other parameters (e.g. `lv_draw_rect()`). It renders the primitive shape to the current draw buffer.
3. **Create masks** If the shape is very simple and doesn't require masks go to #5. Else create the required masks (e.g. a rounded rectangle mask)
4. **Calculate all the added mask**. It creates 0..255 values into a *mask buffer* with the "shape" of the created masks.
2. **Call the draw function** Call the draw function with the draw descriptor and some other parameters (e.g. `lv_draw_rect()`). It will render the primitive shape to the current draw buffer.
3. **Create masks** If the shape is very simple and doesn't require masks go to #5. Else create the required masks in the draw function. (e.g. a rounded rectangle mask)
4. **Calculate all the added mask** It creates 0..255 values into a *mask buffer* with the "shape" of the created masks.
E.g. in case of a "line mask" according to the parameters of the mask, keep one side of the buffer as it is (255 by default) and set the rest to 0 to indicate that this side should be removed.
5. **Blend a color or image** During blending masks (make some pixels transparent or opaque), blending modes (additive, subtractive, etc) and opacity are handled.
@@ -81,6 +81,25 @@ Masks are used the create almost every basic primitives:
- **arc drawing** A circle border is drawn, but an arc mask is applied too.
- **ARGB images** The alpha channel is separated into a mask and the image is drawn as a normal RGB image.
### Using masks
Every mask type has a related paramter to describe the mask's data. The following paramater types exist:
- `lv_draw_mask_line_param_t`
- `lv_draw_mask_radius_param_t`
- `lv_draw_mask_angle_param_t`
- `lv_draw_mask_fade_param_t`
- `lv_draw_mask_map_param_t`
1. Initialize a mask parameter with `lv_draw_mask_<type>_init`. See `lv_draw_mask.h` for the whole API.
2. Add the mask parameter to the draw engine with `int16_t mask_id = lv_draw_mask_add(&param, ptr)`. `ptr` can be any pointer to identify the mask, (`NULL` if unused).
3. Call the draw functions
4. Remove the mask from the draw engine with `lv_draw_mask_remove_id(mask_id)` of `lv_draw_mask_remove_custom(ptr)`.
5. Free the parameter with `lv_draw_mask_free_param(&param)`.
A parameter can be added and removed any number of times but it needs to be freed when not required anymore.
`lv_draw_mask_add` saves only the pointer of the mask so the parameter needs to be valid while in use.
## Hook drawing
Although widgets can be very well customized by styles there might be cases when something really custom is required.
To ensure a great level of flexibility LVGL sends a lot events during drawing with parameters that tell what LVGL is about to draw.
@@ -39,6 +39,8 @@ static void draw_event_cb(lv_event_t * e)
lv_draw_rect(&a, dsc->clip_area, &draw_rect_dsc);
/*Remove the masks*/
lv_draw_mask_free_param(&line_mask_param);
lv_draw_mask_free_param(&fade_mask_param);
lv_draw_mask_remove_id(line_mask_id);
lv_draw_mask_remove_id(fade_mask_id);
}
@@ -43,6 +43,8 @@ static void mask_event_cb(lv_event_t * e)
lv_draw_mask_fade_param_t * fade_mask_bottom = lv_draw_mask_remove_id(mask_bottom_id);
lv_mem_buf_release(fade_mask_top);
lv_mem_buf_release(fade_mask_bottom);
lv_draw_mask_free_param(&fade_mask_top);
lv_draw_mask_free_param(&fade_mask_bottom);
mask_top_id = -1;
mask_bottom_id = -1;
}
+7
View File
@@ -95,6 +95,13 @@
*LV_SHADOW_CACHE_SIZE is the max. shadow size to buffer, where shadow size is `shadow_width + radius`
*Caching has LV_SHADOW_CACHE_SIZE^2 RAM cost*/
#define LV_SHADOW_CACHE_SIZE 0
/* Set number of maximally cached circle data.
* The circumference of 1/4 circle are saved for anti-aliasing
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
* 0: to disable caching */
#define LV_CIRCLE_CACHE_SIZE 4
#endif /*LV_DRAW_COMPLEX*/
/*Default image cache size. Image caching keeps the images opened.
+3 -2
View File
@@ -290,8 +290,9 @@ lv_obj_t * lv_indev_search_obj(lv_obj_t * obj, lv_point_t * point)
/*If the point is on this object check its children too*/
if(lv_obj_hit_test(obj, point)) {
int32_t i;
for(i = lv_obj_get_child_cnt(obj) - 1; i >= 0; i--) {
lv_obj_t * child = lv_obj_get_child(obj, i);
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = child_cnt - 1; i >= 0; i--) {
lv_obj_t * child = obj->spec_attr->children[i];
found_p = lv_indev_search_obj(child, point);
/*If a child was found then break*/
+2 -2
View File
@@ -421,7 +421,7 @@ static lv_coord_t find_snap_point_x(const lv_obj_t * obj, lv_coord_t min, lv_coo
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
if(lv_obj_has_flag(child, LV_OBJ_FLAG_SNAPPABLE)) {
lv_coord_t x_child = 0;
@@ -476,7 +476,7 @@ static lv_coord_t find_snap_point_y(const lv_obj_t * obj, lv_coord_t min, lv_coo
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
if(lv_obj_has_flag(child, LV_OBJ_FLAG_SNAPPABLE)) {
lv_coord_t y_child = 0;
+2 -1
View File
@@ -533,6 +533,7 @@ static void lv_obj_draw(lv_event_t * e)
#if LV_DRAW_COMPLEX
if(lv_obj_get_style_clip_corner(obj, LV_PART_MAIN)) {
lv_draw_mask_radius_param_t * param = lv_draw_mask_remove_custom(obj + 8);
lv_draw_mask_free_param(param);
lv_mem_buf_release(param);
}
#endif
@@ -781,7 +782,7 @@ static void lv_obj_event(const lv_obj_class_t * class_p, lv_event_t * e)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
lv_obj_mark_layout_as_dirty(child);
}
}
+3 -3
View File
@@ -754,7 +754,7 @@ void lv_obj_move_children_by(lv_obj_t * obj, lv_coord_t x_diff, lv_coord_t y_dif
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
if(ignore_floating && lv_obj_has_flag(child, LV_OBJ_FLAG_FLOATING)) continue;
child->coords.x1 += x_diff;
child->coords.y1 += y_diff;
@@ -937,7 +937,7 @@ static void layout_update_core(lv_obj_t * obj)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
layout_update_core(child);
}
@@ -948,7 +948,7 @@ static void layout_update_core(lv_obj_t * obj)
lv_obj_refr_size(obj);
lv_obj_refr_pos(obj);
if(lv_obj_get_child_cnt(obj) > 0) {
if(child_cnt > 0) {
uint32_t layout_id = lv_obj_get_style_layout(obj, LV_PART_MAIN);
if(layout_id > 0 && layout_id <= layout_cnt) {
void * user_data = LV_GC_ROOT(_lv_layout_list)[layout_id -1].user_data;
+4 -4
View File
@@ -139,7 +139,7 @@ lv_coord_t lv_obj_get_scroll_bottom(lv_obj_t * obj)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
child_res = LV_MAX(child_res, child->coords.y2);
}
@@ -180,8 +180,8 @@ lv_coord_t lv_obj_get_scroll_left(lv_obj_t * obj)
lv_coord_t x1 = LV_COORD_MAX;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
lv_obj_t * child = obj->spec_attr->children[i];
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
x1 = LV_MIN(x1, child->coords.x1);
}
@@ -216,7 +216,7 @@ lv_coord_t lv_obj_get_scroll_right(lv_obj_t * obj)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
if(lv_obj_has_flag_any(child, LV_OBJ_FLAG_HIDDEN | LV_OBJ_FLAG_FLOATING)) continue;
child_res = LV_MAX(child_res, child->coords.x2);
}
+2 -2
View File
@@ -623,7 +623,7 @@ static void report_style_change_core(void * style, lv_obj_t * obj)
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
report_style_change_core(style, lv_obj_get_child(obj, i));
report_style_change_core(style, obj->spec_attr->children[i]);
}
}
@@ -637,7 +637,7 @@ static void refresh_children_style(lv_obj_t * obj)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
lv_obj_invalidate(child);
lv_event_send(child, LV_EVENT_STYLE_CHANGED, NULL);
lv_obj_invalidate(child);
+7 -3
View File
@@ -236,6 +236,10 @@ void _lv_disp_refr_timer(lv_timer_t * tmr)
lv_mem_buf_free_all();
_lv_font_clean_up_fmt_txt();
#if LV_DRAW_COMPLEX
_lv_draw_mask_cleanup();
#endif
#if LV_USE_PERF_MONITOR && LV_USE_LABEL
static lv_obj_t * perf_label = NULL;
if(perf_label == NULL) {
@@ -586,7 +590,7 @@ static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
found_p = lv_refr_get_top_obj(area_p, child);
/*If a children is ok then break*/
@@ -634,7 +638,7 @@ static void lv_refr_obj_and_children(lv_obj_t * top_p, const lv_area_t * mask_p)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(par);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(par, i);
lv_obj_t * child = par->spec_attr->children[i];
if(!go) {
if(child == border_p) go = true;
} else {
@@ -707,7 +711,7 @@ static void lv_refr_obj(lv_obj_t * obj, const lv_area_t * mask_ori_p)
uint32_t i;
uint32_t child_cnt = lv_obj_get_child_cnt(obj);
for(i = 0; i < child_cnt; i++) {
lv_obj_t * child = lv_obj_get_child(obj, i);
lv_obj_t * child = obj->spec_attr->children[i];
lv_obj_get_coords(child, &child_area);
ext_size = _lv_obj_get_ext_draw_size(child);
child_area.x1 -= ext_size;
+7
View File
@@ -159,6 +159,11 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uin
else {
lv_draw_rect(&area_out, clip_area, &cir_dsc);
}
lv_draw_mask_free_param(&mask_angle_param);
lv_draw_mask_free_param(&mask_out_param);
lv_draw_mask_free_param(&mask_in_param);
lv_draw_mask_remove_id(mask_angle_id);
lv_draw_mask_remove_id(mask_out_id);
lv_draw_mask_remove_id(mask_in_id);
@@ -180,6 +185,7 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uin
lv_draw_rect(&area_out, &clip_area2, &cir_dsc);
lv_draw_mask_remove_id(mask_end_id);
lv_draw_mask_free_param(&mask_end_param);
}
get_rounded_area(end_angle, radius, width, &round_area);
@@ -193,6 +199,7 @@ void lv_draw_arc(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uin
lv_draw_rect(&area_out, &clip_area2, &cir_dsc);
lv_draw_mask_remove_id(mask_end_id);
lv_draw_mask_free_param(&mask_end_param);
}
}
#else
+62 -86
View File
@@ -73,22 +73,21 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co
/**********************
* MACROS
**********************/
#if LV_COLOR_SCREEN_TRANSP == 0
#define FILL_NORMAL_MASK_PX(color) \
if(*mask == LV_OPA_COVER) *disp_buf_first = color; \
else *disp_buf_first = lv_color_mix(color, *disp_buf_first, *mask); \
mask++; \
disp_buf_first++;
#define FILL_NORMAL_MASK_PX(out_x, color) \
if(*mask_tmp_x) { \
if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[out_x] = color; \
else disp_buf_first[out_x] = lv_color_mix(color, disp_buf_first[out_x], *mask_tmp_x); \
} \
mask_tmp_x++;
#define FILL_NORMAL_MASK_PX_SCR_TRANSP(out_x, color) \
if(*mask_tmp_x) { \
if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[out_x] = color; \
else if(disp->driver->screen_transp) lv_color_mix_with_alpha(disp_buf_first[out_x], disp_buf_first[out_x].ch.alpha, \
color, *mask_tmp_x, &disp_buf_first[out_x], &disp_buf_first[out_x].ch.alpha); \
else disp_buf_first[out_x] = lv_color_mix(color, disp_buf_first[out_x], *mask_tmp_x); \
} \
mask_tmp_x++;
#else
#define FILL_NORMAL_MASK_PX(color) \
if(*mask == LV_OPA_COVER) *disp_buf_first = color; \
else if(disp->driver->screen_transp) lv_color_mix_with_alpha(*disp_buf_first, disp_buf_first->ch.alpha, color, *mask, disp_buf_first, &disp_buf_first->ch.alpha); \
else *disp_buf_first = lv_color_mix(color, *disp_buf_first, *mask); \
mask++; \
disp_buf_first++;
#endif
#define MAP_NORMAL_MASK_PX(x) \
if(*mask_tmp_x) { \
@@ -326,7 +325,6 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co
if(lv_gpu_nxp_vglite_fill(disp_buf, disp_w, lv_area_get_height(disp_area), draw_area, color, opa) == LV_RES_OK) {
return;
}
/*Fall down to SW render in case of error*/
}
#elif LV_USE_GPU_STM32_DMA2D
if(lv_area_get_size(draw_area) >= 240) {
@@ -401,65 +399,55 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co
int32_t x_end4 = draw_area_w - 4;
#if LV_COLOR_DEPTH == 16
uint32_t c32 = color.full + ((uint32_t)color.full << 16);
#endif
/*Only the mask matters*/
if(opa > LV_OPA_MAX) {
for(y = 0; y < draw_area_h; y++) {
const lv_opa_t * mask_tmp_x = mask;
#if 0
for(x = 0; x < draw_area_w; x++) {
#if LV_COLOR_SCREEN_TRANSP
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
#else
FILL_NORMAL_MASK_PX(x, color)
#endif
}
#else
for(x = 0; x < draw_area_w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) {
#if LV_COLOR_SCREEN_TRANSP
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
#else
FILL_NORMAL_MASK_PX(x, color)
#endif
for(x = 0; x < draw_area_w && ((lv_uintptr_t)(mask) & 0x3); x++) {
FILL_NORMAL_MASK_PX(color)
}
uint32_t * mask32 = (uint32_t *)mask_tmp_x;
for(; x <= x_end4; x += 4) {
if(*mask32) {
if((*mask32) == 0xFFFFFFFF) {
disp_buf_first[x] = color;
disp_buf_first[x + 1] = color;
disp_buf_first[x + 2] = color;
disp_buf_first[x + 3] = color;
uint32_t mask32 = *((uint32_t *)mask);
if(mask32 == 0xFFFFFFFF) {
#if LV_COLOR_DEPTH == 16
if((lv_uintptr_t)disp_buf_first & 0x3) {
*(disp_buf_first + 0) = color;
uint32_t * d = (uint32_t * )(disp_buf_first + 1);
*d = c32;
*(disp_buf_first + 3) = color;
} else {
uint32_t * d = (uint32_t * )disp_buf_first;
*d = c32;
*(d + 1) = c32;
}
else {
mask_tmp_x = (const lv_opa_t *)mask32;
#if LV_COLOR_SCREEN_TRANSP
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
FILL_NORMAL_MASK_PX_SCR_TRANSP(x + 1, color)
FILL_NORMAL_MASK_PX_SCR_TRANSP(x + 2, color)
FILL_NORMAL_MASK_PX_SCR_TRANSP(x + 3, color)
#else
FILL_NORMAL_MASK_PX(x, color)
FILL_NORMAL_MASK_PX(x + 1, color)
FILL_NORMAL_MASK_PX(x + 2, color)
FILL_NORMAL_MASK_PX(x + 3, color)
disp_buf_first[0] = color;
disp_buf_first[1] = color;
disp_buf_first[2] = color;
disp_buf_first[3] = color;
#endif
}
disp_buf_first+= 4;
mask += 4;
}
else if(mask32) {
FILL_NORMAL_MASK_PX(color)
FILL_NORMAL_MASK_PX(color)
FILL_NORMAL_MASK_PX(color)
FILL_NORMAL_MASK_PX(color)
} else {
mask += 4;
disp_buf_first += 4;
}
mask32++;
}
mask_tmp_x = (const lv_opa_t *)mask32;
for(; x < draw_area_w ; x++) {
#if LV_COLOR_SCREEN_TRANSP
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
#else
FILL_NORMAL_MASK_PX(x, color)
#endif
FILL_NORMAL_MASK_PX(color)
}
#endif
disp_buf_first += disp_w;
mask += draw_area_w;
disp_buf_first += (disp_w-draw_area_w);
}
}
/*Handle opa and mask values too*/
@@ -701,8 +689,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
blit.src_stride = lv_area_get_width(map_area) * sizeof(lv_color_t);
blit.src_area.x1 = (draw_area->x1 - (map_area->x1 - disp_area->x1));
blit.src_area.y1 = (draw_area->y1 - (map_area->y1 - disp_area->y1));
blit.src_area.x2 = blit.src_area.x1 + draw_area_w - 1;
blit.src_area.y2 = blit.src_area.y1 + draw_area_h - 1;
blit.src_area.x2 = blit.src_area.x1 + draw_area_w;
blit.src_area.y2 = blit.src_area.y1 + draw_area_h;
blit.dst = disp_buf;
blit.dst_width = lv_area_get_width(disp_area);
@@ -710,8 +698,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
blit.dst_stride = lv_area_get_width(disp_area) * sizeof(lv_color_t);
blit.dst_area.x1 = draw_area->x1;
blit.dst_area.y1 = draw_area->y1;
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w - 1;
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h - 1;
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w;
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h;
blit.opa = opa;
@@ -751,8 +739,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
blit.src_stride = lv_area_get_width(map_area) * sizeof(lv_color_t);
blit.src_area.x1 = (draw_area->x1 - (map_area->x1 - disp_area->x1));
blit.src_area.y1 = (draw_area->y1 - (map_area->y1 - disp_area->y1));
blit.src_area.x2 = blit.src_area.x1 + draw_area_w - 1;
blit.src_area.y2 = blit.src_area.y1 + draw_area_h - 1;
blit.src_area.x2 = blit.src_area.x1 + draw_area_w;
blit.src_area.y2 = blit.src_area.y1 + draw_area_h;
blit.dst = disp_buf;
blit.dst_width = lv_area_get_width(disp_area);
@@ -760,8 +748,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col
blit.dst_stride = lv_area_get_width(disp_area) * sizeof(lv_color_t);
blit.dst_area.x1 = draw_area->x1;
blit.dst_area.y1 = draw_area->y1;
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w - 1;
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h - 1;
blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w;
blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h;
blit.opa = opa;
@@ -933,13 +921,7 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
for(y = draw_area->y1; y <= draw_area->y2; y++) {
for(x = draw_area->x1; x <= draw_area->x2; x++) {
#if LV_COLOR_DEPTH == 32
if(map_buf_tmp[x].full != 0xff000000) {
#else
if(map_buf_tmp[x].full != 0) {
#endif
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa);
}
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa);
}
disp_buf_tmp += disp_w;
map_buf_tmp += map_w;
@@ -957,14 +939,7 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
for(x = draw_area->x1; x <= draw_area->x2; x++) {
if(mask_tmp[x] == 0) continue;
lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : ((opa * mask_tmp[x]) >> 8);
#if LV_COLOR_DEPTH == 32
if(map_buf_tmp[x].full != 0xff000000) {
#else
if(map_buf_tmp[x].full != 0) {
#endif
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp);
}
disp_buf_tmp[x] = blend_fp(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp);
}
disp_buf_tmp += disp_w;
mask_tmp += draw_area_w;
@@ -975,6 +950,9 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa)
{
if(opa <= LV_OPA_MIN) return bg;
uint32_t tmp;
#if LV_COLOR_DEPTH == 1
tmp = bg.full + fg.full;
@@ -990,7 +968,6 @@ static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color
#endif
#if LV_COLOR_DEPTH == 8
tmp = bg.ch.green + fg.ch.green;
fg.ch.green = LV_MIN(tmp, 7);
#elif LV_COLOR_DEPTH == 16
#if LV_COLOR_16_SWAP == 0
@@ -1004,7 +981,6 @@ static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color
#endif
#elif LV_COLOR_DEPTH == 32
tmp = bg.ch.green + fg.ch.green;
fg.ch.green = LV_MIN(tmp, 255);
#endif
+4
View File
@@ -474,6 +474,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(const lv_point_t * point1, cons
lv_mem_buf_release(mask_buf);
lv_draw_mask_free_param(&mask_left_param);
lv_draw_mask_free_param(&mask_right_param);
if(mask_top_id != LV_MASK_ID_INV) lv_draw_mask_free_param(&mask_top_param);
if(mask_bottom_id != LV_MASK_ID_INV) lv_draw_mask_free_param(&mask_bottom_param);
lv_draw_mask_remove_id(mask_left_id);
lv_draw_mask_remove_id(mask_right_id);
lv_draw_mask_remove_id(mask_top_id);
+317 -209
View File
File diff suppressed because it is too large Load Diff
+28 -2
View File
@@ -147,6 +147,18 @@ typedef struct {
uint16_t delta_deg;
} lv_draw_mask_angle_param_t;
typedef struct {
uint8_t * buf;
lv_opa_t * cir_opa; /*Opacity of values on the circumference of an 1/4 circle*/
uint16_t * x_start_on_y; /*The x coordinate of the circle for each y value*/
uint16_t * opa_start_on_y; /*The index of `cir_opa` for each y value*/
int32_t life; /*How many times the entry way used*/
uint32_t used_cnt; /*Like a semaphore to count the referencing masks*/
lv_coord_t radius; /*The radius of the entry*/
} _lv_draw_mask_radius_circle_dsc_t;
typedef _lv_draw_mask_radius_circle_dsc_t _lv_draw_mask_radius_circle_dsc_arr_t[LV_CIRCLE_CACHE_SIZE];
typedef struct {
/*The first element must be the common descriptor*/
_lv_draw_mask_common_dsc_t dsc;
@@ -157,9 +169,8 @@ typedef struct {
/*Invert the mask. 0: Keep the pixels inside.*/
uint8_t outer: 1;
} cfg;
int32_t y_prev;
lv_sqrt_res_t y_prev_x;
_lv_draw_mask_radius_circle_dsc_t * circle;
} lv_draw_mask_radius_param_t;
@@ -235,6 +246,21 @@ void * lv_draw_mask_remove_id(int16_t id);
*/
void * lv_draw_mask_remove_custom(void * custom_id);
/**
* Free the data from the parameter.
* It's called inside `lv_draw_mask_remove_id` and `lv_draw_mask_remove_custom`
* Needs to be called only in special cases when the mask is not added by `lv_draw_mask_add`
* and not removed by `lv_draw_mask_remove_id` or `lv_draw_mask_remove_custom`
* @param p pointer to a mask parameter
*/
void lv_draw_mask_free_param(void * p);
/**
* Called by LVGL the rendering of a screen is ready to clean up
* the temporal (cache) data of the masks
*/
void _lv_draw_mask_cleanup(void);
//! @cond Doxygen_Suppress
/**
+11 -3
View File
@@ -228,7 +228,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are
y < coords_bg.y2 - rout - 1) {
mask_res = LV_DRAW_MASK_RES_FULL_COVER;
if(simple_mode == false) {
lv_memset(mask_buf, opa, draw_area_w);
lv_memset(mask_buf, 0xff, draw_area_w);
mask_res = lv_draw_mask_apply(mask_buf, draw_buf->area.x1 + draw_area.x1, draw_buf->area.y1 + h, draw_area_w);
}
}
@@ -240,7 +240,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are
/*If mask will taken into account its base opacity was already set by memset above*/
if(mask_res == LV_DRAW_MASK_RES_CHANGED) {
opa2 = LV_OPA_COVER;
// opa2 = LV_OPA_COVER;
}
/*Get the current line color*/
@@ -329,6 +329,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_are
if(grad_map) lv_mem_buf_release(grad_map);
if(mask_buf) lv_mem_buf_release(mask_buf);
lv_draw_mask_remove_id(mask_rout_id);
if(mask_rout_id != LV_MASK_ID_INV) lv_draw_mask_free_param(&mask_rout_param);
}
#endif
@@ -509,8 +510,10 @@ LV_ATTRIBUTE_FAST_MEM static void draw_border(const lv_area_t * coords, const lv
fill_area.y2++;
}
lv_draw_mask_free_param(&mask_rin_param);
lv_draw_mask_free_param(&mask_rout_param);
lv_draw_mask_remove_id(mask_rin_id);
lv_draw_mask_remove_id(mask_rout_id);
if(mask_rout_id != LV_MASK_ID_INV) lv_draw_mask_remove_id(mask_rout_id);
lv_mem_buf_release(mask_buf);
}
#else /*LV_DRAW_COMPLEX*/
@@ -1007,6 +1010,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_shadow(const lv_area_t * coords, const lv
}
}
lv_draw_mask_free_param(&mask_rout_param);
lv_draw_mask_remove_id(mask_rout_id);
lv_mem_buf_release(mask_buf);
lv_mem_buf_release(sh_buf);
@@ -1064,6 +1068,8 @@ LV_ATTRIBUTE_FAST_MEM static void shadow_draw_corner_buf(const lv_area_t * coord
}
lv_mem_buf_release(mask_line);
lv_draw_mask_free_param(&mask_param);
if(sw == 1) {
int32_t i;
lv_opa_t * res_buf = (lv_opa_t *)sh_buf;
@@ -1394,6 +1400,8 @@ static void draw_full_border(const lv_area_t * area_inner, const lv_area_t * are
}
}
lv_draw_mask_free_param(&mask_rin_param);
lv_draw_mask_free_param(&mask_rout_param);
lv_draw_mask_remove_id(mask_rin_id);
lv_draw_mask_remove_id(mask_rout_id);
lv_mem_buf_release(mask_buf);
@@ -287,6 +287,8 @@ static void draw_disc_grad(lv_event_t * e)
}
#if LV_DRAW_COMPLEX
lv_draw_mask_free_param(&mask_out_param);
lv_draw_mask_free_param(&mask_in_param);
lv_draw_mask_remove_id(mask_out_id);
lv_draw_mask_remove_id(mask_in_id);
#endif
+4 -1
View File
@@ -414,7 +414,7 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c
lv_draw_mask_radius_init(&outer_mask, &area_outer, LV_RADIUS_CIRCLE, false);
int16_t outer_mask_id = lv_draw_mask_add(&outer_mask, NULL);
int16_t inner_act_mask_id = -1; /*Will be added later*/
int16_t inner_act_mask_id = LV_MASK_ID_INV; /*Will be added later*/
uint32_t minor_cnt = scale->tick_major_nth ? scale->tick_major_nth - 1 : 0xFFFF;
for(i = 0; i < scale->tick_cnt; i++) {
@@ -530,6 +530,9 @@ static void draw_ticks_and_labels(lv_obj_t * obj, const lv_area_t * clip_area, c
line_dsc.width = line_width_ori;
}
lv_draw_mask_free_param(&inner_minor_mask);
lv_draw_mask_free_param(&inner_major_mask);
lv_draw_mask_free_param(&outer_mask);
lv_draw_mask_remove_id(outer_mask_id);
}
}
+13
View File
@@ -250,6 +250,19 @@
# define LV_SHADOW_CACHE_SIZE 0
# endif
#endif
/* Set number of maximally cached circle data.
* The circumference of 1/4 circle are saved for anti-aliasing
* radius * 4 bytes are used per circle (the most often used radiuses are saved)
* 0: to disable caching */
#ifndef LV_CIRCLE_CACHE_SIZE
# ifdef CONFIG_LV_CIRCLE_CACHE_SIZE
# define LV_CIRCLE_CACHE_SIZE CONFIG_LV_CIRCLE_CACHE_SIZE
# else
# define LV_CIRCLE_CACHE_SIZE 4
# endif
#endif
#endif /*LV_DRAW_COMPLEX*/
/*Default image cache size. Image caching keeps the images opened.
+9 -1
View File
@@ -459,7 +459,15 @@ static inline uint32_t lv_color_to32(lv_color_t color)
LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
{
lv_color_t ret;
#if LV_COLOR_DEPTH != 1
#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0
/*Source: https://stackoverflow.com/a/50012418/1999969*/
mix = ( mix + 4 ) >> 3;
uint32_t bg = (c2.full | (c2.full << 16)) & 0x7E0F81F; /*0b00000111111000001111100000011111*/
uint32_t fg = (c1.full | (c1.full << 16)) & 0x7E0F81F;
uint32_t result = ((((fg - bg) * mix) >> 5) + bg) & 0x7E0F81F;
ret.full = (uint16_t)((result >> 16) | result);
#elif LV_COLOR_DEPTH != 1
/*LV_COLOR_DEPTH == 8, 16 or 32*/
LV_COLOR_SET_R(ret, LV_UDIV255((uint16_t) LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) *
(255 - mix) + LV_COLOR_MIX_ROUND_OFS));
+1
View File
@@ -53,6 +53,7 @@ extern "C" {
LV_DISPATCH_COND(f, _lv_img_cache_entry_t, _lv_img_cache_single, LV_IMG_CACHE_DEF, 0) \
LV_DISPATCH(f, lv_timer_t*, _lv_timer_act) \
LV_DISPATCH(f, lv_mem_buf_arr_t , lv_mem_buf) \
LV_DISPATCH_COND(f, _lv_draw_mask_radius_circle_dsc_arr_t , _lv_circle_cache, LV_DRAW_COMPLEX, 1) \
LV_DISPATCH_COND(f, _lv_draw_mask_saved_arr_t , _lv_draw_mask_list, LV_DRAW_COMPLEX, 1) \
LV_DISPATCH(f, void * , _lv_theme_default_styles) \
LV_DISPATCH_COND(f, uint8_t *, _lv_font_decompr_buf, LV_USE_FONT_COMPRESSED, 1)
+2
View File
@@ -486,6 +486,8 @@ static void draw_indic(lv_event_t * e)
lv_draw_rect(&bar->indic_area, clip_area, &draw_rect_dsc);
#if LV_DRAW_COMPLEX
lv_draw_mask_free_param(&mask_indic_param);
lv_draw_mask_free_param(&mask_bg_param);
lv_draw_mask_remove_id(mask_indic_id);
lv_draw_mask_remove_id(mask_bg_id);
#endif
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB