From 4d4bb340c09a616fecaf51067d96edd661c2c615 Mon Sep 17 00:00:00 2001 From: VIFEXT Date: Wed, 20 Mar 2024 19:03:45 +0800 Subject: [PATCH] feat(vg_lite): add radial gradient support (#5836) Signed-off-by: pengyiqiang Co-authored-by: pengyiqiang --- Kconfig | 14 + env_support/cmsis-pack/lv_conf_cmsis.h | 9 +- lv_conf_template.h | 9 +- src/draw/vg_lite/lv_draw_vg_lite.c | 2 +- src/draw/vg_lite/lv_draw_vg_lite_type.h | 10 +- src/draw/vg_lite/lv_draw_vg_lite_vector.c | 40 +-- src/draw/vg_lite/lv_vg_lite_grad.c | 366 +++++++++++++++++++--- src/draw/vg_lite/lv_vg_lite_grad.h | 19 +- src/draw/vg_lite/lv_vg_lite_utils.c | 6 +- src/lv_conf_internal.h | 21 +- src/others/vg_lite_tvg/vg_lite_tvg.cpp | 54 +++- 11 files changed, 458 insertions(+), 92 deletions(-) diff --git a/Kconfig b/Kconfig index 098cdb73a..cdd2a322e 100644 --- a/Kconfig +++ b/Kconfig @@ -335,6 +335,20 @@ menu "LVGL configuration" which usually improves performance, but does not guarantee the same rendering quality as the software. + config LV_VG_LITE_LINEAER_GRAD_CACHE_CNT + int "VG-Lite linear gradient image maximum cache number." + default 32 + depends on LV_USE_DRAW_VG_LITE + help + The memory usage of a single gradient image is 4K bytes. + + config LV_VG_LITE_RADIAL_GRAD_CACHE_CNT + int "VG-Lite radial gradient image maximum cache number." + default 32 + depends on LV_USE_DRAW_VG_LITE + help + The memory usage of a single gradient image is radial grad radius * 4 bytes. + config LV_USE_VECTOR_GRAPHIC bool "Use Vector Graphic APIs" default n diff --git a/env_support/cmsis-pack/lv_conf_cmsis.h b/env_support/cmsis-pack/lv_conf_cmsis.h index 244bcfe8e..72d57118c 100644 --- a/env_support/cmsis-pack/lv_conf_cmsis.h +++ b/env_support/cmsis-pack/lv_conf_cmsis.h @@ -184,10 +184,15 @@ * but does not guarantee the same rendering quality as the software. */ #define LV_VG_LITE_USE_BOX_SHADOW 0 -/* VG-Lite gradient image maximum cache number. +/* VG-Lite linear gradient image maximum cache number. * NOTE: The memory usage of a single gradient image is 4K bytes. */ -#define LV_VG_LITE_GRAD_CACHE_SIZE 32 +#define LV_VG_LITE_LINEAER_GRAD_CACHE_CNT 32 + +/* VG-Lite radial gradient image maximum cache size. + * NOTE: The memory usage of a single gradient image is radial grad radius * 4 bytes. + */ +#define LV_VG_LITE_RADIAL_GRAD_CACHE_CNT 32 #endif diff --git a/lv_conf_template.h b/lv_conf_template.h index 1a2f8535f..ad214d247 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -198,10 +198,15 @@ * but does not guarantee the same rendering quality as the software. */ #define LV_VG_LITE_USE_BOX_SHADOW 0 -/* VG-Lite gradient image maximum cache number. +/* VG-Lite linear gradient image maximum cache number. * NOTE: The memory usage of a single gradient image is 4K bytes. */ -#define LV_VG_LITE_GRAD_CACHE_SIZE 32 +#define LV_VG_LITE_LINEAER_GRAD_CACHE_CNT 32 + +/* VG-Lite radial gradient image maximum cache size. + * NOTE: The memory usage of a single gradient image is radial grad radius * 4 bytes. + */ +#define LV_VG_LITE_RADIAL_GRAD_CACHE_CNT 32 #endif diff --git a/src/draw/vg_lite/lv_draw_vg_lite.c b/src/draw/vg_lite/lv_draw_vg_lite.c index e461550ff..9487ab443 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite.c +++ b/src/draw/vg_lite/lv_draw_vg_lite.c @@ -72,7 +72,7 @@ void lv_draw_vg_lite_init(void) unit->base_unit.delete_cb = draw_delete; lv_vg_lite_image_dsc_init(unit); - lv_vg_lite_grad_init(unit); + lv_vg_lite_grad_init(unit, LV_VG_LITE_LINEAER_GRAD_CACHE_CNT, LV_VG_LITE_RADIAL_GRAD_CACHE_CNT); lv_vg_lite_path_init(unit); lv_vg_lite_decoder_init(); } diff --git a/src/draw/vg_lite/lv_draw_vg_lite_type.h b/src/draw/vg_lite/lv_draw_vg_lite_type.h index 3609f9280..36f096be8 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_type.h +++ b/src/draw/vg_lite/lv_draw_vg_lite_type.h @@ -40,9 +40,15 @@ struct _lv_vg_lite_pending_t; struct _lv_draw_vg_lite_unit_t { lv_draw_unit_t base_unit; lv_draw_task_t * task_act; + struct _lv_vg_lite_pending_t * image_dsc_pending; - lv_cache_t * grad_cache; - struct _lv_vg_lite_pending_t * grad_pending; + + lv_cache_t * linear_grad_cache; + struct _lv_vg_lite_pending_t * linear_grad_pending; + + lv_cache_t * radial_grad_cache; + struct _lv_vg_lite_pending_t * radial_grad_pending; + uint16_t flush_count; vg_lite_buffer_t target_buffer; vg_lite_matrix_t global_matrix; diff --git a/src/draw/vg_lite/lv_draw_vg_lite_vector.c b/src/draw/vg_lite/lv_draw_vg_lite_vector.c index 0485c0b6e..999709f8d 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_vector.c +++ b/src/draw/vg_lite/lv_draw_vg_lite_vector.c @@ -36,7 +36,6 @@ static void lv_path_opa_to_vg(lv_vg_lite_path_t * dest, const lv_vector_draw_dsc static void lv_stroke_to_vg(lv_vg_lite_path_t * dest, const lv_vector_stroke_dsc_t * dsc); static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend); static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule); -static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread); static vg_lite_cap_style_t lv_stroke_cap_to_vg(lv_vector_stroke_cap_t cap); static vg_lite_join_style_t lv_stroke_join_to_vg(lv_vector_stroke_join_t join); @@ -205,8 +204,6 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec case LV_VECTOR_DRAW_STYLE_GRADIENT: { /* draw gradient */ lv_vector_gradient_style_t style = dsc->fill_dsc.gradient.style; - vg_lite_gradient_spreadmode_t spreadmode = lv_spread_to_vg(dsc->fill_dsc.gradient.spread); - LV_UNUSED(spreadmode); if(style == LV_VECTOR_GRADIENT_STYLE_LINEAR) { vg_lite_matrix_t grad_matrix, fill_matrix; @@ -229,12 +226,23 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec blend); } else if(style == LV_VECTOR_GRADIENT_STYLE_RADIAL) { - if(vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) { - /* TODO: radial gradient */ - } - else { - LV_LOG_WARN("radial gradient is not supported"); - } + vg_lite_matrix_t grad_matrix; + lv_matrix_to_vg(&grad_matrix, &dsc->fill_dsc.matrix); + + /* add min_x, min_y to gradient center */ + lv_vector_gradient_t new_grad = dsc->fill_dsc.gradient; + new_grad.cx += min_x; + new_grad.cy += min_y; + + lv_vg_lite_draw_radial_grad( + u, + &u->target_buffer, + vg_path, + &new_grad, + &grad_matrix, + &matrix, + fill, + blend); } } break; @@ -431,20 +439,6 @@ static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule) } } -static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread) -{ - switch(spread) { - case LV_VECTOR_GRADIENT_SPREAD_PAD: - return VG_LITE_GRADIENT_SPREAD_PAD; - case LV_VECTOR_GRADIENT_SPREAD_REPEAT: - return VG_LITE_GRADIENT_SPREAD_REPEAT; - case LV_VECTOR_GRADIENT_SPREAD_REFLECT: - return VG_LITE_GRADIENT_SPREAD_REFLECT; - default: - return VG_LITE_GRADIENT_SPREAD_FILL; - } -} - static vg_lite_cap_style_t lv_stroke_cap_to_vg(lv_vector_stroke_cap_t cap) { switch(cap) { diff --git a/src/draw/vg_lite/lv_vg_lite_grad.c b/src/draw/vg_lite/lv_vg_lite_grad.c index 83b68f858..1eaeb45e4 100644 --- a/src/draw/vg_lite/lv_vg_lite_grad.c +++ b/src/draw/vg_lite/lv_vg_lite_grad.c @@ -13,6 +13,7 @@ #include "lv_draw_vg_lite_type.h" #include "lv_vg_lite_pending.h" +#include "lv_vg_lite_math.h" #include "../../misc/lv_types.h" #include "../../stdlib/lv_string.h" @@ -25,22 +26,47 @@ **********************/ typedef struct { - vg_lite_linear_gradient_t vg_grad; lv_grad_dsc_t lv_grad; -} grad_item_t; + vg_lite_linear_gradient_t vg_grad; +} linear_grad_item_t; + +#if LV_USE_VECTOR_GRAPHIC + +typedef struct { + lv_vector_gradient_t lv_grad; + vg_lite_radial_gradient_t vg_grad; +} radial_grad_item_t; + +#endif /* LV_USE_VECTOR_GRAPHIC */ /********************** * STATIC PROTOTYPES **********************/ -static vg_lite_linear_gradient_t * lv_vg_lite_linear_grad_get(struct _lv_draw_vg_lite_unit_t * u, - const lv_grad_dsc_t * grad); - -static bool grad_create_cb(grad_item_t * item, void * user_data); -static void grad_free_cb(grad_item_t * item, void * user_data); -static lv_cache_compare_res_t grad_compare_cb(const grad_item_t * lhs, const grad_item_t * rhs); static void grad_cache_release_cb(void * entry, void * user_data); +/* Linear gradient */ + +static vg_lite_linear_gradient_t * linear_grad_get(struct _lv_draw_vg_lite_unit_t * u, + const lv_grad_dsc_t * grad); +static bool linear_grad_create_cb(linear_grad_item_t * item, void * user_data); +static void linear_grad_free_cb(linear_grad_item_t * item, void * user_data); +static lv_cache_compare_res_t linear_grad_compare_cb(const linear_grad_item_t * lhs, const linear_grad_item_t * rhs); + +#if LV_USE_VECTOR_GRAPHIC + +/* Radial gradient */ + +static vg_lite_radial_gradient_t * radial_grad_get(struct _lv_draw_vg_lite_unit_t * u, + const lv_vector_gradient_t * grad); +static bool radial_grad_create_cb(radial_grad_item_t * item, void * user_data); +static void radial_grad_free_cb(radial_grad_item_t * item, void * user_data); +static lv_cache_compare_res_t radial_grad_compare_cb(const radial_grad_item_t * lhs, const radial_grad_item_t * rhs); + +static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread); + +#endif /* LV_USE_VECTOR_GRAPHIC */ + /********************** * STATIC VARIABLES **********************/ @@ -53,28 +79,63 @@ static void grad_cache_release_cb(void * entry, void * user_data); * GLOBAL FUNCTIONS **********************/ -void lv_vg_lite_grad_init(struct _lv_draw_vg_lite_unit_t * u) +void lv_vg_lite_grad_init( + struct _lv_draw_vg_lite_unit_t * u, + uint32_t linear_grad_cache_cnt, + uint32_t radial_grad_cache_cnt) { LV_ASSERT_NULL(u); + LV_UNUSED(radial_grad_cache_cnt); - lv_cache_ops_t ops = { - .compare_cb = (lv_cache_compare_cb_t)grad_compare_cb, - .create_cb = (lv_cache_create_cb_t)grad_create_cb, - .free_cb = (lv_cache_free_cb_t)grad_free_cb, - }; + /* Create the cache for linear gradients */ + { + lv_cache_ops_t ops = { + .compare_cb = (lv_cache_compare_cb_t)linear_grad_compare_cb, + .create_cb = (lv_cache_create_cb_t)linear_grad_create_cb, + .free_cb = (lv_cache_free_cb_t)linear_grad_free_cb, + }; - u->grad_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(grad_item_t), LV_VG_LITE_GRAD_CACHE_SIZE, ops); - LV_ASSERT_NULL(u->grad_cache); + u->linear_grad_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(linear_grad_item_t), + linear_grad_cache_cnt, + ops); + u->linear_grad_pending = lv_vg_lite_pending_create(sizeof(lv_cache_entry_t *), 4); + lv_vg_lite_pending_set_free_cb(u->linear_grad_pending, grad_cache_release_cb, u->linear_grad_cache); + } - u->grad_pending = lv_vg_lite_pending_create(sizeof(lv_cache_entry_t *), 4); - lv_vg_lite_pending_set_free_cb(u->grad_pending, grad_cache_release_cb, u->grad_cache); +#if LV_USE_VECTOR_GRAPHIC + + /* Create the cache for radial gradients */ + if(vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) { + lv_cache_ops_t ops = { + .compare_cb = (lv_cache_compare_cb_t)radial_grad_compare_cb, + .create_cb = (lv_cache_create_cb_t)radial_grad_create_cb, + .free_cb = (lv_cache_free_cb_t)radial_grad_free_cb, + }; + + u->radial_grad_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(radial_grad_item_t), + radial_grad_cache_cnt, + ops); + u->radial_grad_pending = lv_vg_lite_pending_create(sizeof(lv_cache_entry_t *), 4); + lv_vg_lite_pending_set_free_cb(u->radial_grad_pending, grad_cache_release_cb, u->radial_grad_cache); + } + +#endif /* LV_USE_VECTOR_GRAPHIC */ } void lv_vg_lite_grad_deinit(struct _lv_draw_vg_lite_unit_t * u) { LV_ASSERT_NULL(u); - lv_vg_lite_pending_destroy(u->grad_pending); - lv_cache_destroy(u->grad_cache, NULL); + lv_vg_lite_pending_destroy(u->linear_grad_pending); + u->linear_grad_pending = NULL; + lv_cache_destroy(u->linear_grad_cache, NULL); + u->linear_grad_cache = NULL; + + if(u->radial_grad_pending) { + lv_vg_lite_pending_destroy(u->radial_grad_pending); + u->radial_grad_pending = NULL; + lv_cache_destroy(u->radial_grad_cache, NULL); + u->radial_grad_cache = NULL; + } } void lv_vg_lite_grad_area_to_matrix(vg_lite_matrix_t * grad_matrix, const lv_area_t * area, lv_grad_dir_t dir) @@ -119,20 +180,20 @@ void lv_vg_lite_draw_linear_grad( LV_PROFILER_BEGIN; - vg_lite_linear_gradient_t * gradient = lv_vg_lite_linear_grad_get(u, grad); - LV_ASSERT_NULL(gradient); - if(!gradient) { + vg_lite_linear_gradient_t * linear_grad = linear_grad_get(u, grad); + LV_ASSERT_NULL(linear_grad); + if(!linear_grad) { LV_LOG_ERROR("Failed to get linear gradient"); LV_PROFILER_END; return; } - vg_lite_matrix_t * grad_mat_p = vg_lite_get_grad_matrix(gradient); + vg_lite_matrix_t * grad_mat_p = vg_lite_get_grad_matrix(linear_grad); LV_ASSERT_NULL(grad_mat_p); *grad_mat_p = *grad_matrix; LV_VG_LITE_ASSERT_DEST_BUFFER(buffer); - LV_VG_LITE_ASSERT_SRC_BUFFER(&gradient->image); + LV_VG_LITE_ASSERT_SRC_BUFFER(&linear_grad->image); LV_VG_LITE_ASSERT_PATH(path); LV_VG_LITE_ASSERT_MATRIX(grad_mat_p); LV_VG_LITE_ASSERT_MATRIX(matrix); @@ -143,37 +204,101 @@ void lv_vg_lite_draw_linear_grad( path, fill, (vg_lite_matrix_t *)matrix, - gradient, + linear_grad, blend)); LV_PROFILER_END_TAG("vg_lite_draw_grad"); LV_PROFILER_END; } +#if LV_USE_VECTOR_GRAPHIC + +void lv_vg_lite_draw_radial_grad( + struct _lv_draw_vg_lite_unit_t * u, + vg_lite_buffer_t * buffer, + vg_lite_path_t * path, + const lv_vector_gradient_t * grad, + const vg_lite_matrix_t * grad_matrix, + const vg_lite_matrix_t * matrix, + vg_lite_fill_t fill, + vg_lite_blend_t blend) +{ + LV_ASSERT_NULL(u); + LV_ASSERT_NULL(buffer); + LV_ASSERT_NULL(path); + LV_ASSERT_NULL(grad); + LV_ASSERT_NULL(grad_matrix); + LV_ASSERT_NULL(matrix); + + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_RADIAL_GRADIENT)) { + LV_LOG_INFO("radial gradient is not supported"); + return; + } + + if(grad->spread == LV_VECTOR_GRADIENT_SPREAD_REPEAT || grad->spread == LV_VECTOR_GRADIENT_SPREAD_REFLECT) { + if(!vg_lite_query_feature(gcFEATURE_BIT_VG_IM_REPEAT_REFLECT)) { + LV_LOG_INFO("repeat/reflect spread(%d) is not supported", (int)grad->spread); + return; + } + } + + LV_PROFILER_BEGIN; + + vg_lite_radial_gradient_t * radial_grad = radial_grad_get(u, grad); + + vg_lite_matrix_t * grad_mat_p = vg_lite_get_radial_grad_matrix(radial_grad); + LV_ASSERT_NULL(grad_mat_p); + *grad_mat_p = *grad_matrix; + + LV_VG_LITE_ASSERT_DEST_BUFFER(buffer); + LV_VG_LITE_ASSERT_SRC_BUFFER(&radial_grad->image); + LV_VG_LITE_ASSERT_PATH(path); + LV_VG_LITE_ASSERT_MATRIX(grad_mat_p); + LV_VG_LITE_ASSERT_MATRIX(matrix); + + LV_PROFILER_BEGIN_TAG("vg_lite_draw_radial_grad"); + LV_VG_LITE_CHECK_ERROR( + vg_lite_draw_radial_grad( + buffer, + path, + fill, + (vg_lite_matrix_t *)matrix, + radial_grad, + 0, + blend, + VG_LITE_FILTER_LINEAR)); + LV_PROFILER_END_TAG("vg_lite_draw_radial_grad"); + + LV_PROFILER_END; +} + +#endif /* LV_USE_VECTOR_GRAPHIC */ + /********************** * STATIC FUNCTIONS **********************/ -static vg_lite_linear_gradient_t * lv_vg_lite_linear_grad_get(struct _lv_draw_vg_lite_unit_t * u, - const lv_grad_dsc_t * grad) +static void * grad_get( + struct _lv_draw_vg_lite_unit_t * u, + lv_cache_t * cache, + lv_vg_lite_pending_t * pending, + const void * key) { LV_ASSERT_NULL(u); - LV_ASSERT_NULL(grad); + LV_ASSERT_NULL(cache); + LV_ASSERT_NULL(pending); + LV_ASSERT_NULL(key); - grad_item_t search_key; - lv_memzero(&search_key, sizeof(grad_item_t)); - search_key.lv_grad = *grad; - - lv_cache_entry_t * cache_node_entry = lv_cache_acquire(u->grad_cache, &search_key, NULL); + lv_cache_entry_t * cache_node_entry = lv_cache_acquire(cache, key, NULL); if(cache_node_entry == NULL) { /* check if the cache is full */ - size_t free_size = lv_cache_get_free_size(u->grad_cache, NULL); + size_t free_size = lv_cache_get_free_size(cache, NULL); if(free_size == 0) { LV_LOG_INFO("grad cache is full, release all pending cache entries"); lv_vg_lite_finish(u); } - cache_node_entry = lv_cache_acquire_or_create(u->grad_cache, &search_key, NULL); + cache_node_entry = lv_cache_acquire_or_create(cache, key, NULL); if(cache_node_entry == NULL) { LV_LOG_ERROR("grad cache creating failed"); return NULL; @@ -181,13 +306,36 @@ static vg_lite_linear_gradient_t * lv_vg_lite_linear_grad_get(struct _lv_draw_vg } /* Add the new entry to the pending list */ - lv_vg_lite_pending_add(u->grad_pending, &cache_node_entry); + lv_vg_lite_pending_add(pending, &cache_node_entry); + + return lv_cache_entry_get_data(cache_node_entry); +} + +static void grad_cache_release_cb(void * entry, void * user_data) +{ + lv_cache_entry_t ** entry_p = entry; + lv_cache_t * cache = user_data; + lv_cache_release(cache, *entry_p, NULL); +} + +/* Linear gradient */ + +static vg_lite_linear_gradient_t * linear_grad_get(struct _lv_draw_vg_lite_unit_t * u, + const lv_grad_dsc_t * grad) +{ + linear_grad_item_t search_key; + lv_memzero(&search_key, sizeof(search_key)); + search_key.lv_grad = *grad; + + linear_grad_item_t * item = grad_get(u, u->linear_grad_cache, u->linear_grad_pending, &search_key); + if(!item) { + return NULL; + } - grad_item_t * item = lv_cache_entry_get_data(cache_node_entry); return &item->vg_grad; } -static bool grad_create_cb(grad_item_t * item, void * user_data) +static bool linear_grad_create_cb(linear_grad_item_t * item, void * user_data) { LV_UNUSED(user_data); @@ -226,13 +374,13 @@ static bool grad_create_cb(grad_item_t * item, void * user_data) return true; } -static void grad_free_cb(grad_item_t * item, void * user_data) +static void linear_grad_free_cb(linear_grad_item_t * item, void * user_data) { LV_UNUSED(user_data); LV_VG_LITE_CHECK_ERROR(vg_lite_clear_grad(&item->vg_grad)); } -static lv_cache_compare_res_t grad_compare_cb(const grad_item_t * lhs, const grad_item_t * rhs) +static lv_cache_compare_res_t linear_grad_compare_cb(const linear_grad_item_t * lhs, const linear_grad_item_t * rhs) { if(lhs->lv_grad.stops_count != rhs->lv_grad.stops_count) { return lhs->lv_grad.stops_count > rhs->lv_grad.stops_count ? 1 : -1; @@ -247,11 +395,139 @@ static lv_cache_compare_res_t grad_compare_cb(const grad_item_t * lhs, const gra return 0; } -static void grad_cache_release_cb(void * entry, void * user_data) +#if LV_USE_VECTOR_GRAPHIC + +/* Radial gradient */ + +static vg_lite_radial_gradient_t * radial_grad_get(struct _lv_draw_vg_lite_unit_t * u, + const lv_vector_gradient_t * grad) { - lv_cache_entry_t ** entry_p = entry; - lv_cache_t * cache = user_data; - lv_cache_release(cache, *entry_p, NULL); + radial_grad_item_t search_key; + lv_memzero(&search_key, sizeof(search_key)); + search_key.lv_grad = *grad; + + radial_grad_item_t * item = grad_get(u, u->radial_grad_cache, u->radial_grad_pending, &search_key); + if(!item) { + return NULL; + } + + return &item->vg_grad; } +static bool radial_grad_create_cb(radial_grad_item_t * item, void * user_data) +{ + LV_UNUSED(user_data); + + LV_PROFILER_BEGIN; + + lv_vector_gradient_t * grad = &item->lv_grad; + uint8_t stops_count = grad->grad.stops_count; + vg_lite_color_ramp_t * color_ramp = lv_malloc(sizeof(vg_lite_color_ramp_t) * stops_count); + LV_ASSERT_MALLOC(color_ramp); + if(!color_ramp) { + LV_LOG_ERROR("malloc failed for color_ramp"); + return false; + } + + for(uint8_t i = 0; i < stops_count; i++) { + color_ramp[i].stop = grad->grad.stops[i].frac / 255.0f; + lv_color_t c = grad->grad.stops[i].color; + + color_ramp[i].red = c.red / 255.0f; + color_ramp[i].green = c.green / 255.0f; + color_ramp[i].blue = c.blue / 255.0f; + color_ramp[i].alpha = grad->grad.stops[i].opa / 255.0f; + } + + const vg_lite_radial_gradient_parameter_t grad_param = { + .cx = grad->cx, + .cy = grad->cy, + .r = grad->cr, + .fx = grad->cx, + .fy = grad->cy, + }; + + vg_lite_radial_gradient_t radial_grad; + lv_memzero(&radial_grad, sizeof(radial_grad)); + + LV_PROFILER_BEGIN_TAG("vg_lite_set_radial_grad"); + LV_VG_LITE_CHECK_ERROR( + vg_lite_set_radial_grad( + &radial_grad, + stops_count, + color_ramp, + grad_param, + lv_spread_to_vg(grad->spread), + 1)); + LV_PROFILER_END_TAG("vg_lite_set_radial_grad"); + + LV_PROFILER_BEGIN_TAG("vg_lite_update_radial_grad"); + vg_lite_error_t err = vg_lite_update_radial_grad(&radial_grad); + LV_PROFILER_END_TAG("vg_lite_update_radial_grad"); + if(!err) { + item->vg_grad = radial_grad; + } + else { + LV_LOG_ERROR("update radial grad error(%d): %s", (int)err, lv_vg_lite_error_string(err)); + } + + lv_free(color_ramp); + + LV_PROFILER_END; + return err == VG_LITE_SUCCESS; +} + +static void radial_grad_free_cb(radial_grad_item_t * item, void * user_data) +{ + LV_UNUSED(user_data); + LV_VG_LITE_CHECK_ERROR(vg_lite_clear_radial_grad(&item->vg_grad)); +} + +static lv_cache_compare_res_t radial_grad_compare_cb(const radial_grad_item_t * lhs, const radial_grad_item_t * rhs) +{ + if(!math_equal(lhs->lv_grad.cx, rhs->lv_grad.cx)) { + return lhs->lv_grad.cx > rhs->lv_grad.cx ? 1 : -1; + } + + if(!math_equal(lhs->lv_grad.cy, rhs->lv_grad.cy)) { + return lhs->lv_grad.cy > rhs->lv_grad.cy ? 1 : -1; + } + + if(!math_equal(lhs->lv_grad.cr, rhs->lv_grad.cr)) { + return lhs->lv_grad.cr > rhs->lv_grad.cr ? 1 : -1; + } + + if(lhs->lv_grad.spread != rhs->lv_grad.spread) { + return lhs->lv_grad.spread > rhs->lv_grad.spread ? 1 : -1; + } + + if(lhs->lv_grad.grad.stops_count != rhs->lv_grad.grad.stops_count) { + return lhs->lv_grad.grad.stops_count > rhs->lv_grad.grad.stops_count ? 1 : -1; + } + + int cmp_res = lv_memcmp(lhs->lv_grad.grad.stops, rhs->lv_grad.grad.stops, + sizeof(lv_gradient_stop_t) * lhs->lv_grad.grad.stops_count); + if(cmp_res != 0) { + return cmp_res > 0 ? 1 : -1; + } + + return 0; +} + +static vg_lite_gradient_spreadmode_t lv_spread_to_vg(lv_vector_gradient_spread_t spread) +{ + switch(spread) { + case LV_VECTOR_GRADIENT_SPREAD_PAD: + return VG_LITE_GRADIENT_SPREAD_PAD; + case LV_VECTOR_GRADIENT_SPREAD_REPEAT: + return VG_LITE_GRADIENT_SPREAD_REPEAT; + case LV_VECTOR_GRADIENT_SPREAD_REFLECT: + return VG_LITE_GRADIENT_SPREAD_REFLECT; + default: + return VG_LITE_GRADIENT_SPREAD_FILL; + } +} + +#endif /* LV_USE_VECTOR_GRAPHIC */ + #endif /*LV_USE_DRAW_VG_LITE*/ diff --git a/src/draw/vg_lite/lv_vg_lite_grad.h b/src/draw/vg_lite/lv_vg_lite_grad.h index d709ade46..e3e4b052d 100644 --- a/src/draw/vg_lite/lv_vg_lite_grad.h +++ b/src/draw/vg_lite/lv_vg_lite_grad.h @@ -32,7 +32,10 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ -void lv_vg_lite_grad_init(struct _lv_draw_vg_lite_unit_t * u); +void lv_vg_lite_grad_init( + struct _lv_draw_vg_lite_unit_t * u, + uint32_t linear_grad_cache_cnt, + uint32_t radial_grad_cache_cnt); void lv_vg_lite_grad_deinit(struct _lv_draw_vg_lite_unit_t * u); @@ -48,7 +51,19 @@ void lv_vg_lite_draw_linear_grad( vg_lite_fill_t fill, vg_lite_blend_t blend); -void lv_vg_lite_linear_grad_release_all(struct _lv_draw_vg_lite_unit_t * u); +#if LV_USE_VECTOR_GRAPHIC + +void lv_vg_lite_draw_radial_grad( + struct _lv_draw_vg_lite_unit_t * u, + vg_lite_buffer_t * buffer, + vg_lite_path_t * path, + const lv_vector_gradient_t * grad, + const vg_lite_matrix_t * grad_matrix, + const vg_lite_matrix_t * matrix, + vg_lite_fill_t fill, + vg_lite_blend_t blend); + +#endif /* LV_USE_VECTOR_GRAPHIC */ /********************** * MACROS diff --git a/src/draw/vg_lite/lv_vg_lite_utils.c b/src/draw/vg_lite/lv_vg_lite_utils.c index cb212fb63..3c4bf45c2 100644 --- a/src/draw/vg_lite/lv_vg_lite_utils.c +++ b/src/draw/vg_lite/lv_vg_lite_utils.c @@ -1064,7 +1064,11 @@ void lv_vg_lite_finish(struct _lv_draw_vg_lite_unit_t * u) LV_VG_LITE_CHECK_ERROR(vg_lite_finish()); /* Clear all gradient caches reference */ - lv_vg_lite_pending_remove_all(u->grad_pending); + lv_vg_lite_pending_remove_all(u->linear_grad_pending); + + if(u->radial_grad_pending) { + lv_vg_lite_pending_remove_all(u->radial_grad_pending); + } /* Clear image decoder dsc reference */ lv_vg_lite_pending_remove_all(u->image_dsc_pending); diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 4feb0edb0..76e4dd3e1 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -538,14 +538,25 @@ #endif #endif -/* VG-Lite gradient image maximum cache number. +/* VG-Lite linear gradient image maximum cache number. * NOTE: The memory usage of a single gradient image is 4K bytes. */ -#ifndef LV_VG_LITE_GRAD_CACHE_SIZE - #ifdef CONFIG_LV_VG_LITE_GRAD_CACHE_SIZE - #define LV_VG_LITE_GRAD_CACHE_SIZE CONFIG_LV_VG_LITE_GRAD_CACHE_SIZE +#ifndef LV_VG_LITE_LINEAER_GRAD_CACHE_CNT + #ifdef CONFIG_LV_VG_LITE_LINEAER_GRAD_CACHE_CNT + #define LV_VG_LITE_LINEAER_GRAD_CACHE_CNT CONFIG_LV_VG_LITE_LINEAER_GRAD_CACHE_CNT #else - #define LV_VG_LITE_GRAD_CACHE_SIZE 32 + #define LV_VG_LITE_LINEAER_GRAD_CACHE_CNT 32 + #endif +#endif + +/* VG-Lite radial gradient image maximum cache size. + * NOTE: The memory usage of a single gradient image is radial grad radius * 4 bytes. + */ +#ifndef LV_VG_LITE_RADIAL_GRAD_CACHE_CNT + #ifdef CONFIG_LV_VG_LITE_RADIAL_GRAD_CACHE_CNT + #define LV_VG_LITE_RADIAL_GRAD_CACHE_CNT CONFIG_LV_VG_LITE_RADIAL_GRAD_CACHE_CNT + #else + #define LV_VG_LITE_RADIAL_GRAD_CACHE_CNT 32 #endif #endif diff --git a/src/others/vg_lite_tvg/vg_lite_tvg.cpp b/src/others/vg_lite_tvg/vg_lite_tvg.cpp index 97c63d71d..1e0bc1f0f 100644 --- a/src/others/vg_lite_tvg/vg_lite_tvg.cpp +++ b/src/others/vg_lite_tvg/vg_lite_tvg.cpp @@ -271,6 +271,7 @@ static FillRule fill_rule_conv(vg_lite_fill_t fill); static BlendMethod blend_method_conv(vg_lite_blend_t blend); static StrokeCap stroke_cap_conv(vg_lite_cap_style_t cap); static StrokeJoin stroke_join_conv(vg_lite_join_style_t join); +static FillSpread fill_spread_conv(vg_lite_gradient_spreadmode_t spread); static Result shape_append_path(std::unique_ptr & shape, vg_lite_path_t * path, vg_lite_matrix_t * matrix); static Result shape_append_rect(std::unique_ptr & shape, const vg_lite_buffer_t * target, const vg_lite_rectangle_t * rect); @@ -808,6 +809,8 @@ extern "C" { case gcFEATURE_BIT_VG_24BIT: case gcFEATURE_BIT_VG_DITHER: case gcFEATURE_BIT_VG_USE_DST: + case gcFEATURE_BIT_VG_RADIAL_GRADIENT: + case gcFEATURE_BIT_VG_IM_REPEAT_REFLECT: #if LV_VG_LITE_THORVG_LVGL_BLEND_SUPPORT case gcFEATURE_BIT_VG_LVGL_SUPPORT: @@ -1736,15 +1739,34 @@ Empty_sequence_handler: vg_lite_blend_t blend, vg_lite_filter_t filter) { - LV_UNUSED(target); - LV_UNUSED(path); - LV_UNUSED(fill_rule); - LV_UNUSED(path_matrix); - LV_UNUSED(grad); - LV_UNUSED(paint_color); - LV_UNUSED(blend); - LV_UNUSED(filter); - return VG_LITE_NOT_SUPPORT; + auto ctx = vg_lite_ctx::get_instance(); + TVG_CHECK_RETURN_VG_ERROR(canvas_set_target(ctx, target)); + + auto shape = Shape::gen(); + TVG_CHECK_RETURN_VG_ERROR(shape_append_path(shape, path, path_matrix)); + TVG_CHECK_RETURN_VG_ERROR(shape->transform(matrix_conv(path_matrix))); + TVG_CHECK_RETURN_VG_ERROR(shape->fill(fill_rule_conv(fill_rule));); + TVG_CHECK_RETURN_VG_ERROR(shape->blend(blend_method_conv(blend))); + + auto radialGrad = RadialGradient::gen(); + TVG_CHECK_RETURN_VG_ERROR(radialGrad->transform(matrix_conv(&grad->matrix))); + TVG_CHECK_RETURN_VG_ERROR(radialGrad->radial(grad->radial_grad.cx, grad->radial_grad.cy, grad->radial_grad.r)); + TVG_CHECK_RETURN_VG_ERROR(radialGrad->spread(fill_spread_conv(grad->spread_mode))); + + tvg::Fill::ColorStop colorStops[VLC_MAX_COLOR_RAMP_STOPS]; + for(vg_lite_uint32_t i = 0; i < grad->ramp_length; i++) { + colorStops[i].offset = grad->color_ramp[i].stop; + colorStops[i].r = grad->color_ramp[i].red * 255.0f; + colorStops[i].g = grad->color_ramp[i].green * 255.0f; + colorStops[i].b = grad->color_ramp[i].blue * 255.0f; + colorStops[i].a = grad->color_ramp[i].alpha * 255.0f; + } + TVG_CHECK_RETURN_VG_ERROR(radialGrad->colorStops(colorStops, grad->ramp_length)); + + TVG_CHECK_RETURN_VG_ERROR(shape->fill(std::move(radialGrad))); + TVG_CHECK_RETURN_VG_ERROR(ctx->canvas->push(std::move(shape))); + + return VG_LITE_SUCCESS; } vg_lite_error_t vg_lite_set_command_buffer_size(vg_lite_uint32_t size) @@ -1979,6 +2001,20 @@ static StrokeJoin stroke_join_conv(vg_lite_join_style_t join) return StrokeJoin::Bevel; } +static FillSpread fill_spread_conv(vg_lite_gradient_spreadmode_t spread) +{ + switch(spread) { + case VG_LITE_GRADIENT_SPREAD_PAD: + return FillSpread::Pad; + case VG_LITE_GRADIENT_SPREAD_REPEAT: + return FillSpread::Repeat; + case VG_LITE_GRADIENT_SPREAD_REFLECT: + return FillSpread::Reflect; + default: + return FillSpread::Pad; + } +} + static float vlc_get_arg(const void * data, vg_lite_format_t format) { switch(format) {