From 1f9d3892a372a9d84b36d76550792773de5374f0 Mon Sep 17 00:00:00 2001 From: X-Ryl669 Date: Sat, 22 Jan 2022 15:43:37 +0100 Subject: [PATCH] fix(draw): rendering issues for vertical gradient with and without dithering (#3034) --- src/draw/sw/lv_draw_sw_dither.c | 10 +++++----- src/draw/sw/lv_draw_sw_gradient.c | 25 ++++++++++++++----------- src/draw/sw/lv_draw_sw_gradient.h | 3 ++- src/draw/sw/lv_draw_sw_rect.c | 11 +++++++---- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/draw/sw/lv_draw_sw_dither.c b/src/draw/sw/lv_draw_sw_dither.c index f34aa660e..eb4553d39 100644 --- a/src/draw/sw/lv_draw_sw_dither.c +++ b/src/draw/sw/lv_draw_sw_dither.c @@ -54,7 +54,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_gradient_cache_t * grad, lv_ /*The apply the algorithm for this patch*/ for(lv_coord_t j = 0; j < w; j++) { int8_t factor = dither_ordered_threshold_matrix[(y & 7) * 8 + ((j) & 7)] - 32; - lv_color32_t tmp = grad->hmap[LV_CLAMP(0, j - 4, grad->hmap_size)]; + lv_color32_t tmp = grad->hmap[LV_CLAMP(0, j - 4, grad->size)]; lv_color32_t t; t.ch.red = LV_CLAMP(0, tmp.ch.red + factor, 255); t.ch.green = LV_CLAMP(0, tmp.ch.green + factor, 255); @@ -74,7 +74,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_gradient_cache_t * grad, lv_ Then we compute a complete row of ordered dither and store it in out. */ /*Extract patch for working with, selected pseudo randomly*/ - lv_color32_t tmp = grad->hmap[LV_CLAMP(0, y - 4, grad->hmap_size)]; + lv_color32_t tmp = grad->hmap[LV_CLAMP(0, y - 4, grad->size)]; /*The apply the algorithm for this patch*/ for(lv_coord_t j = 0; j < 8; j++) { @@ -116,10 +116,10 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_gradient_cache_t * grad, lv #define FS_COMPUTE_ERROR(e) { coef[0] = (e<<3) - e; coef[1] = (e<<2) - e; coef[2] = (e<<2) + e; coef[3] = e; } #define FS_COMPONENTS(A, OP, B, C) A.ch.red = LV_CLAMP(0, A.ch.red OP B.r OP C.r, 255); A.ch.green = LV_CLAMP(0, A.ch.green OP B.g OP C.g, 255); A.ch.blue = LV_CLAMP(0, A.ch.blue OP B.b OP C.b, 255); #define FS_QUANT_ERROR(e, t, q) { lv_color32_t u; u.full = lv_color_to32(q); e.r = (int8_t)(t.ch.red - u.ch.red); e.g = (int8_t)(t.ch.green - u.ch.green); e.b = (int8_t)(t.ch.blue - u.ch.blue); } - lv_scolor24_t next_px_err = {0}, next_l = grad->error_acc[1], error; + lv_scolor24_t next_px_err = {0}, next_l = {0}, error; /*First last pixel are not dithered */ grad->map[0] = lv_color_hex(grad->hmap[0].full); - for(lv_coord_t x = 1; x < grad->hmap_size - 1; x++) { + for(lv_coord_t x = 1; x < grad->size - 1; x++) { lv_color32_t t = grad->hmap[x]; lv_color_t q; /*Add error term*/ @@ -150,7 +150,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_gradient_cache_t * grad, lv grad->map[x] = q; } - grad->map[grad->hmap_size - 1] = lv_color_hex(grad->hmap[grad->hmap_size - 1].full); + 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) diff --git a/src/draw/sw/lv_draw_sw_gradient.c b/src/draw/sw/lv_draw_sw_gradient.c index d0159dab7..1ed2b2574 100644 --- a/src/draw/sw/lv_draw_sw_gradient.c +++ b/src/draw/sw/lv_draw_sw_gradient.c @@ -72,11 +72,11 @@ static uint32_t compute_key(const lv_gradient_t * g, lv_coord_t size, lv_coord_t static size_t get_cache_item_size(lv_gradient_cache_t * c) { - size_t s = sizeof(*c) + c->size * sizeof(lv_color_t) + size_t s = sizeof(*c) + c->alloc_size * sizeof(lv_color_t) #if _DITHER_GRADIENT - + c->hmap_size * sizeof(lv_color32_t) + + c->size * sizeof(lv_color32_t) #if LV_DITHER_ERROR_DIFFUSION == 1 - + c->size * sizeof(lv_scolor24_t) + + c->w * sizeof(lv_scolor24_t) #endif #endif ; @@ -159,7 +159,9 @@ static lv_res_t find_item(lv_gradient_cache_t * c, void * ctx) static lv_gradient_cache_t * allocate_item(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; - size_t req_size = sizeof(lv_gradient_cache_t) + w * sizeof(lv_color_t) + 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) #if _DITHER_GRADIENT + size * sizeof(lv_color32_t) #if LV_DITHER_ERROR_DIFFUSION == 1 @@ -186,14 +188,15 @@ static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w item->key = compute_key(g, size, w); item->life = 1; item->filled = 0; - item->size = w; + item->alloc_size = map_size; + item->size = size; item->map = (lv_color_t *)(grad_cache_end + sizeof(*item)); #if _DITHER_GRADIENT - item->hmap = (lv_color32_t *)(grad_cache_end + sizeof(*item) + w * sizeof(lv_color_t)); - item->hmap_size = size; + item->hmap = (lv_color32_t *)(grad_cache_end + sizeof(*item) + 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) + w * sizeof( - lv_color_t)); + 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; #endif #endif grad_cache_end += req_size; @@ -244,8 +247,8 @@ lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * g, lv_coord_t /* Step 3: Fill it with the gradient, as expected */ #if _DITHER_GRADIENT - for(lv_coord_t i = 0; i < item->hmap_size; i++) { - item->hmap[i] = lv_grad_get(g, item->hmap_size, i); + for(lv_coord_t i = 0; i < item->size; i++) { + item->hmap[i] = lv_grad_get(g, item->size, i); } #if LV_DITHER_ERROR_DIFFUSION == 1 lv_memset_00(item->error_acc, w * sizeof(lv_scolor24_t)); diff --git a/src/draw/sw/lv_draw_sw_gradient.h b/src/draw/sw/lv_draw_sw_gradient.h index 617cf3ad3..262240874 100644 --- a/src/draw/sw/lv_draw_sw_gradient.h +++ b/src/draw/sw/lv_draw_sw_gradient.h @@ -45,14 +45,15 @@ typedef struct _lv_gradient_cache_t { uint32_t filled : 1; /**< Used to skip dithering in it if already done */ 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 */ lv_coord_t size; /**< The computed gradient color map size, in colors */ #if _DITHER_GRADIENT lv_color32_t * hmap; /**< If dithering, we need to store the current, high bitdepth gradient * map too, points to the cache's buffer, no free needed */ - lv_coord_t hmap_size; /**< The array size in pixels */ #if LV_DITHER_ERROR_DIFFUSION == 1 lv_scolor24_t * error_acc; /**< Error diffusion dithering algorithm requires storing the last error * drawn, points to the cache's buffer, no free needed */ + lv_coord_t w; /**< The error array width in pixels */ #endif #endif } lv_gradient_cache_t; diff --git a/src/draw/sw/lv_draw_sw_rect.c b/src/draw/sw/lv_draw_sw_rect.c index 63bd9252e..18f23bd44 100644 --- a/src/draw/sw/lv_draw_sw_rect.c +++ b/src/draw/sw/lv_draw_sw_rect.c @@ -177,6 +177,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co #if _DITHER_GRADIENT lv_dither_mode_t dither_mode = dsc->bg_grad.dither; lv_dither_func_t dither_func = &lv_dither_none; + lv_coord_t grad_size = coords_bg_w; if(grad_dir == LV_GRAD_DIR_VER && dither_mode != LV_DITHER_NONE) { /* When dithering, we are still using a map that's changing from line to line*/ blend_dsc.src_buf = grad->map; @@ -184,6 +185,8 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co if(grad && dither_mode == LV_DITHER_NONE) { grad->filled = 0; /*Should we force refilling it each draw call ?*/ + if(grad_dir == LV_GRAD_DIR_VER) + grad_size = coords_bg_h; } else #if LV_DITHER_ERROR_DIFFUSION @@ -209,7 +212,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, coords_bg_w); + 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); @@ -235,7 +238,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, coords_bg_w); + 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); @@ -246,7 +249,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, coords_bg_w); + 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); @@ -285,7 +288,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, coords_bg_w); + 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);