From 3ee8763838e66a8d84574cdb66e698dfb9ac4575 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 19 Mar 2020 15:29:03 +0100 Subject: [PATCH] blending a color mixing speed up --- src/lv_draw/lv_draw_blend.c | 142 +++++++++++++++++++----------------- src/lv_draw/lv_draw_img.c | 8 +- src/lv_draw/lv_draw_rect.c | 22 +++--- src/lv_misc/lv_area.h | 1 + src/lv_misc/lv_misc.mk | 1 + 5 files changed, 99 insertions(+), 75 deletions(-) diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index 454a653c0..67eb1cf03 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -268,18 +268,18 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con } for(; x <= draw_area->x2; x += FILL_DIRECT_LEN) { - memcpy(&disp_buf_tmp[x], &disp_buf_tmp[draw_area->x1], FILL_DIRECT_LEN * sizeof(lv_color_t)); + lv_memcpy(&disp_buf_tmp[x], &disp_buf_tmp[draw_area->x1], FILL_DIRECT_LEN * sizeof(lv_color_t)); } disp_buf_tmp += disp_w; for(y = draw_area->y1 + 1; y <= draw_area->y2; y++) { - memcpy(&disp_buf_tmp[draw_area->x1], &disp_buf_tmp_ori[draw_area->x1], draw_area_w * sizeof(lv_color_t)); + lv_memcpy(&disp_buf_tmp[draw_area->x1], &disp_buf_tmp_ori[draw_area->x1], draw_area_w * sizeof(lv_color_t)); disp_buf_tmp += disp_w; } } + /*No mask with opacity*/ else { - #if LV_USE_GPU if(disp->driver.gpu_blend_cb && draw_area_w > GPU_WIDTH_LIMIT) { static lv_color_t blend_buf[LV_HOR_RES_MAX]; @@ -294,6 +294,11 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con #endif lv_color_t last_dest_color = LV_COLOR_BLACK; lv_color_t last_res_color = lv_color_mix(color, last_dest_color, opa); + + uint16_t color_premult[3]; + lv_color_premult(color, opa, color_premult); + lv_opa_t opa_inv = 255 - opa; + for(y = draw_area->y1; y <= draw_area->y2; y++) { for(x = draw_area->x1; x <= draw_area->x2; x++) { if(last_dest_color.full != disp_buf_tmp[x].full) { @@ -307,7 +312,7 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con else #endif { - last_res_color = lv_color_mix(color, disp_buf_tmp[x], opa); + last_res_color = lv_color_mix_premult(color_premult, disp_buf_tmp[x], opa_inv); } } disp_buf_tmp[x] = last_res_color; @@ -333,26 +338,28 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con /*Only the mask matters*/ if(opa > LV_OPA_MAX) { for(y = draw_area->y1; y <= draw_area->y2; y++) { + const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; for(x = draw_area->x1; x <= draw_area->x2; x++) { - if(mask_tmp[x] == 0) continue; - if(mask_tmp[x] != last_mask || last_dest_color.full != disp_buf_tmp[x].full) { -#if LV_COLOR_SCREEN_TRANSP - if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, color, mask_tmp[x], &last_res_color, - &last_res_color.ch.alpha); - } - else -#endif - { - if(mask_tmp[x] == LV_OPA_COVER) last_res_color = color; - else if(mask_tmp[x] == LV_OPA_TRANSP) last_res_color = disp_buf_tmp[x]; - else if(disp_buf_tmp[x].full == color.full) last_res_color = color; - else last_res_color = lv_color_mix(color, disp_buf_tmp[x], mask_tmp[x]); - } - last_mask = mask_tmp[x]; - last_dest_color.full = disp_buf_tmp[x].full; + if(*mask_tmp_x) { + if(*mask_tmp_x != last_mask || last_dest_color.full != disp_buf_tmp[x].full) { + #if LV_COLOR_SCREEN_TRANSP + if(disp->driver.screen_transp) { + lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, color, *mask_tmp_x, &last_res_color, + &last_res_color.ch.alpha); + } + else + #endif + { + if(*mask_tmp_x == LV_OPA_COVER) last_res_color = color; + else if(disp_buf_tmp[x].full == color.full) last_res_color = color; + else last_res_color = lv_color_mix(color, disp_buf_tmp[x], *mask_tmp_x); + } + last_mask = *mask_tmp_x; + last_dest_color.full = disp_buf_tmp[x].full; + } + disp_buf_tmp[x] = last_res_color; } - disp_buf_tmp[x] = last_res_color; + mask_tmp_x++; } disp_buf_tmp += disp_w; mask_tmp += draw_area_w; @@ -360,27 +367,30 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con } /*Handle opa and mask values too*/ else { + lv_opa_t opa_tmp = LV_OPA_TRANSP; for(y = draw_area->y1; y <= draw_area->y2; y++) { - for(x = draw_area->x1; x <= draw_area->x2; x++) { - if(mask_tmp[x] == 0) continue; - if(mask_tmp[x] != last_mask || last_dest_color.full != disp_buf_tmp[x].full) { - lv_opa_t opa_tmp = mask_tmp[x] == LV_OPA_COVER ? opa : (uint32_t)((uint32_t)mask_tmp[x] * opa) >> 8; + const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; + for(x = draw_area->x1; x <= draw_area->x2; x++) { + if(*mask_tmp_x) { + if(*mask_tmp_x != last_mask) opa_tmp = *mask_tmp_x == LV_OPA_COVER ? opa : (uint32_t)((uint32_t)(*mask_tmp_x) * opa) >> 8; + if(*mask_tmp_x != last_mask || last_dest_color.full != disp_buf_tmp[x].full) { #if LV_COLOR_SCREEN_TRANSP - if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, color, opa_tmp, &last_res_color, - &last_res_color.ch.alpha); - } - else + if(disp->driver.screen_transp) { + lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, color, opa_tmp, &last_res_color, + &last_res_color.ch.alpha); + } + else #endif - { - if(opa_tmp == LV_OPA_COVER) last_res_color = lv_color_mix(color, disp_buf_tmp[x], mask_tmp[x]); - else if(opa_tmp == LV_OPA_TRANSP) last_res_color = disp_buf_tmp[x]; - else last_res_color = lv_color_mix(color, disp_buf_tmp[x], opa_tmp); - } - last_mask = mask_tmp[x]; - last_dest_color.full = disp_buf_tmp[x].full; - } - disp_buf_tmp[x] = last_res_color; + { + if(opa_tmp == LV_OPA_COVER) last_res_color = color; + else last_res_color = lv_color_mix(color, disp_buf_tmp[x], opa_tmp); + } + last_mask = *mask_tmp_x; + last_dest_color.full = disp_buf_tmp[x].full; + } + disp_buf_tmp[x] = last_res_color; + } + mask_tmp_x++; } disp_buf_tmp += disp_w; mask_tmp += draw_area_w; @@ -567,7 +577,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons if(opa > LV_OPA_MAX) { for(y = draw_area->y1; y <= draw_area->y2; y++) { - memcpy(&disp_buf_tmp[draw_area->x1], map_buf_tmp, draw_area_w * sizeof(lv_color_t)); + lv_memcpy(&disp_buf_tmp[draw_area->x1], map_buf_tmp, draw_area_w * sizeof(lv_color_t)); disp_buf_tmp += disp_w; map_buf_tmp += map_w; } @@ -612,20 +622,21 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons for(y = draw_area->y1; y <= draw_area->y2; y++) { for(x = draw_area->x1; x <= draw_area->x2; x++) { - if(mask_tmp[x] < LV_OPA_MIN) continue; -#if LV_COLOR_SCREEN_TRANSP - if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, map_buf_tmp[x], mask_tmp[x], &res_color, - &opa_composed); - res_color.ch.alpha = opa_composed; + if(mask_tmp[x]) { + #if LV_COLOR_SCREEN_TRANSP + if(disp->driver.screen_transp) { + lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, map_buf_tmp[x], mask_tmp[x], &res_color, + &opa_composed); + res_color.ch.alpha = opa_composed; + } + else + #endif + { + if(mask_tmp[x] > LV_OPA_MAX) res_color = map_buf_tmp[x]; + else res_color = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], mask_tmp[x]); + } + disp_buf_tmp[x] = res_color; } - else -#endif - { - if(mask_tmp[x] > LV_OPA_MAX) res_color = map_buf_tmp[x]; - else res_color = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], mask_tmp[x]); - } - disp_buf_tmp[x] = res_color;//lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], mask_tmp[x]); } disp_buf_tmp += disp_w; mask_tmp += draw_area_w; @@ -637,17 +648,18 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons map_buf_tmp -= draw_area->x1; for(y = draw_area->y1; y <= draw_area->y2; y++) { 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_SCREEN_TRANSP - if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, map_buf_tmp[x], opa_tmp, &disp_buf_tmp[x], - &disp_buf_tmp[x].ch.alpha); - } - else -#endif - { - disp_buf_tmp[x] = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp); + if(mask_tmp[x]) { + lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : ((opa * mask_tmp[x]) >> 8); + #if LV_COLOR_SCREEN_TRANSP + if(disp->driver.screen_transp) { + lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, map_buf_tmp[x], opa_tmp, &disp_buf_tmp[x], + &disp_buf_tmp[x].ch.alpha); + } + else + #endif + { + disp_buf_tmp[x] = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp); + } } } disp_buf_tmp += disp_w; diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 91c2f6a59..f0439b1a9 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -417,6 +417,12 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, lv_img_buf_transform_init(&trans_dsc); } + uint16_t recolor_premult[3] = {0}; + lv_opa_t recolor_opa_inv = 255 - draw_dsc->recolor_opa; + if(draw_dsc->recolor_opa != 0) { + lv_color_premult(draw_dsc->recolor, draw_dsc->recolor_opa, recolor_premult); + } + lv_draw_mask_res_t mask_res; mask_res = (alpha_byte || chroma_key || draw_dsc->angle) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER; int32_t x; @@ -473,7 +479,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, } if(draw_dsc->recolor_opa != 0) { - c = lv_color_mix(draw_dsc->recolor, c, draw_dsc->recolor_opa); + c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv); } map2[px_i].full = c.full; diff --git a/src/lv_draw/lv_draw_rect.c b/src/lv_draw/lv_draw_rect.c index 71d6cdccc..e325a02bf 100644 --- a/src/lv_draw/lv_draw_rect.c +++ b/src/lv_draw/lv_draw_rect.c @@ -19,6 +19,7 @@ *********************/ #define SHADOW_UPSACALE_SHIFT 6 #define SHADOW_ENHANCE 1 +#define SPLIT_LIMIT 50 /********************** * TYPEDEFS @@ -216,6 +217,9 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, lv_draw_re } } + bool split = false; + if(lv_area_get_width(&coords_bg) - 2 * rout > SPLIT_LIMIT) split = true; + lv_area_t fill_area; fill_area.x1 = coords_bg.x1; fill_area.x2 = coords_bg.x2; @@ -246,7 +250,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, lv_draw_re /* If there is not other mask and drawing the corner area split the drawing to corner and middle areas * because it the middle mask shuldn't be taken into account (therefore its faster)*/ - if(simple_mode && + if(simple_mode && split && (y < coords_bg.y1 + rout + 1 || y > coords_bg.y2 - rout - 1)) { @@ -277,7 +281,7 @@ static void draw_bg(const lv_area_t * coords, const lv_area_t * clip, lv_draw_re lv_blend_fill(clip, &fill_area, grad_color, mask_buf, mask_res, opa, dsc->bg_blend_mode); } - else if(other_mask_cnt != 0) { + else if(other_mask_cnt != 0 || !split) { lv_blend_fill(clip, &fill_area, grad_color, mask_buf, mask_res, opa, dsc->bg_blend_mode); } @@ -666,7 +670,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra int32_t y; for(y = 0; y < corner_size - ver_mid_dist + ver_mid_corr; y++) { - memcpy(mask_buf, sh_buf_tmp, corner_size); + lv_memcpy(mask_buf, sh_buf_tmp, corner_size); mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a)); if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; @@ -684,7 +688,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra sh_buf_tmp = sh_buf ; for(y = 0; y < corner_size - ver_mid_dist; y++) { - memcpy(mask_buf, sh_buf_tmp, corner_size); + lv_memcpy(mask_buf, sh_buf_tmp, corner_size); mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a)); if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; @@ -725,7 +729,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra } else { for(y = corner_size; y < lv_area_get_height(&sh_area) - corner_size; y++) { - memcpy(mask_buf, sh_buf_tmp, corner_size); + lv_memcpy(mask_buf, sh_buf_tmp, corner_size); mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a)); if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; @@ -765,7 +769,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra sh_buf_tmp = sh_buf ; for(y = 0; y < corner_size - ver_mid_dist + ver_mid_corr; y++) { - memcpy(mask_buf, sh_buf_tmp, corner_size); + lv_memcpy(mask_buf, sh_buf_tmp, corner_size); mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a)); if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; @@ -783,7 +787,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra sh_buf_tmp = sh_buf ; for(y = 0; y < corner_size - ver_mid_dist; y++) { - memcpy(mask_buf, sh_buf_tmp, corner_size); + lv_memcpy(mask_buf, sh_buf_tmp, corner_size); mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a)); if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; @@ -821,7 +825,7 @@ static void draw_shadow(const lv_area_t * coords, const lv_area_t * clip, lv_dra } else { for(y = corner_size; y < lv_area_get_height(&sh_area) - corner_size; y++) { - memcpy(mask_buf, sh_buf_tmp, corner_size); + lv_memcpy(mask_buf, sh_buf_tmp, corner_size); mask_res = lv_draw_mask_apply(mask_buf + first_px, a.x1, a.y1, lv_area_get_width(&a)); if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) mask_res = LV_DRAW_MASK_RES_CHANGED; @@ -1041,7 +1045,7 @@ static void shadow_blur_corner(lv_coord_t size, lv_coord_t sw, uint16_t * sh_ups else left_val = sh_ups_tmp_buf[x - s_left - 1]; v += left_val; } - memcpy(sh_ups_tmp_buf, sh_ups_blur_buf, size * sizeof(uint16_t)); + lv_memcpy(sh_ups_tmp_buf, sh_ups_blur_buf, size * sizeof(uint16_t)); sh_ups_tmp_buf += size; } diff --git a/src/lv_misc/lv_area.h b/src/lv_misc/lv_area.h index aa6de6fa6..898183f1d 100644 --- a/src/lv_misc/lv_area.h +++ b/src/lv_misc/lv_area.h @@ -17,6 +17,7 @@ extern "C" { #include #include #include +#include "lv_memcpy.h" /********************* * DEFINES diff --git a/src/lv_misc/lv_misc.mk b/src/lv_misc/lv_misc.mk index c8c60c3e5..f801cce0d 100644 --- a/src/lv_misc/lv_misc.mk +++ b/src/lv_misc/lv_misc.mk @@ -14,6 +14,7 @@ CSRCS += lv_utils.c CSRCS += lv_async.c CSRCS += lv_printf.c CSRCS += lv_bidi.c +CSRCS += lv_memcpy.c DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc