diff --git a/Kconfig b/Kconfig index cdacefa2e..ff8ab620f 100644 --- a/Kconfig +++ b/Kconfig @@ -407,6 +407,11 @@ menu "LVGL configuration" linear: 4K bytes. radial: radius * 4K bytes. + config LV_VG_LITE_STROKE_CACHE_CNT + int "VG-Lite stroke maximum cache number." + default 32 + depends on LV_USE_DRAW_VG_LITE + config LV_USE_VECTOR_GRAPHIC bool "Use Vector Graphic APIs" default n diff --git a/lv_conf_template.h b/lv_conf_template.h index d9e457483..14a9e3014 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -230,6 +230,10 @@ */ #define LV_VG_LITE_GRAD_CACHE_CNT 32 +/* VG-Lite stroke maximum cache number. + */ +#define LV_VG_LITE_STROKE_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 be30fbd6b..9057f31c7 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite.c +++ b/src/draw/vg_lite/lv_draw_vg_lite.c @@ -18,6 +18,7 @@ #include "lv_vg_lite_decoder.h" #include "lv_vg_lite_grad.h" #include "lv_vg_lite_pending.h" +#include "lv_vg_lite_stroke.h" /********************* * DEFINES @@ -74,6 +75,7 @@ void lv_draw_vg_lite_init(void) lv_vg_lite_image_dsc_init(unit); #if LV_USE_VECTOR_GRAPHIC lv_vg_lite_grad_init(unit, LV_VG_LITE_GRAD_CACHE_CNT); + lv_vg_lite_stroke_init(unit, LV_VG_LITE_STROKE_CACHE_CNT); #endif lv_vg_lite_path_init(unit); lv_vg_lite_decoder_init(); @@ -254,6 +256,7 @@ static int32_t draw_delete(lv_draw_unit_t * draw_unit) lv_vg_lite_image_dsc_deinit(unit); #if LV_USE_VECTOR_GRAPHIC lv_vg_lite_grad_deinit(unit); + lv_vg_lite_stroke_deinit(unit); #endif lv_vg_lite_path_deinit(unit); lv_vg_lite_decoder_deinit(); 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 8767491cd..a4d24d20d 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_type.h +++ b/src/draw/vg_lite/lv_draw_vg_lite_type.h @@ -46,6 +46,8 @@ struct _lv_draw_vg_lite_unit_t { lv_cache_t * grad_cache; struct _lv_vg_lite_pending_t * grad_pending; + lv_cache_t * stroke_cache; + 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 501367d79..cbf96badc 100644 --- a/src/draw/vg_lite/lv_draw_vg_lite_vector.c +++ b/src/draw/vg_lite/lv_draw_vg_lite_vector.c @@ -16,6 +16,7 @@ #include "lv_vg_lite_pending.h" #include "lv_vg_lite_utils.h" #include "lv_vg_lite_grad.h" +#include "lv_vg_lite_stroke.h" #include /********************* @@ -26,6 +27,9 @@ * TYPEDEFS **********************/ +typedef void * path_drop_data_t; +typedef void (*path_drop_func_t)(struct _lv_draw_vg_lite_unit_t *, path_drop_data_t); + /********************** * STATIC PROTOTYPES **********************/ @@ -33,12 +37,9 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc); static void lv_matrix_to_vg(vg_lite_matrix_t * desy, const lv_matrix_t * src); static void lv_path_to_vg(lv_vg_lite_path_t * dest, const lv_vector_path_t * src); -static void lv_path_opa_to_vg(lv_vg_lite_path_t * dest, const lv_vector_draw_dsc_t * dsc); -static void lv_stroke_to_vg(lv_vg_lite_path_t * dest, const lv_vector_stroke_dsc_t * dsc); +static vg_lite_path_type_t lv_path_opa_to_path_type(const lv_vector_draw_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_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); /********************** * STATIC VARIABLES @@ -111,22 +112,66 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec /* convert path */ lv_vg_lite_path_t * lv_vg_path = lv_vg_lite_path_get(u, VG_LITE_FP32); lv_path_to_vg(lv_vg_path, path); - vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(lv_vg_path); - LV_VG_LITE_ASSERT_PATH(vg_path); + + /* get path bounds */ + float min_x, min_y, max_x, max_y; + lv_vg_lite_path_get_bonding_box(lv_vg_path, &min_x, &min_y, &max_x, &max_y); /* convert path type */ - lv_path_opa_to_vg(lv_vg_path, dsc); + vg_lite_path_type_t path_type = lv_path_opa_to_path_type(dsc); /* convert blend mode and fill rule */ vg_lite_blend_t blend = lv_blend_to_vg(dsc->blend_mode); vg_lite_fill_t fill = lv_fill_to_vg(dsc->fill_dsc.fill_rule); - /* convert stroke style */ - lv_stroke_to_vg(lv_vg_path, &dsc->stroke_dsc); + /* set default path drop function and data */ + path_drop_func_t path_drop_func = (path_drop_func_t)lv_vg_lite_path_drop; + path_drop_data_t path_drop_data = lv_vg_path; - /* get path bounds */ - float min_x, min_y, max_x, max_y; - lv_vg_lite_path_get_bonding_box(lv_vg_path, &min_x, &min_y, &max_x, &max_y); + /* If it is fill mode, the end op code should be added */ + if(path_type == VG_LITE_DRAW_ZERO + || path_type == VG_LITE_DRAW_FILL_PATH + || path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { + lv_vg_lite_path_end(lv_vg_path); + } + + /* convert stroke style */ + if(path_type == VG_LITE_DRAW_STROKE_PATH + || path_type == VG_LITE_DRAW_FILL_STROKE_PATH) { + lv_cache_entry_t * stroke_cache_entey = lv_vg_lite_stroke_get(u, lv_vg_path, &dsc->stroke_dsc); + + if(!stroke_cache_entey) { + LV_LOG_ERROR("convert stroke failed"); + + /* drop original path */ + lv_vg_lite_path_drop(u, lv_vg_path); + return; + } + + lv_vg_lite_path_t * ori_path = lv_vg_path; + const vg_lite_path_t * ori_vg_path = lv_vg_lite_path_get_path(ori_path); + + lv_vg_lite_path_t * stroke_path = lv_vg_lite_stroke_get_path(stroke_cache_entey); + vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(stroke_path); + + /* set stroke params */ + LV_VG_LITE_CHECK_ERROR(vg_lite_set_path_type(vg_path, path_type)); + vg_path->stroke_color = lv_color32_to_vg(dsc->stroke_dsc.color, dsc->stroke_dsc.opa); + vg_path->quality = ori_vg_path->quality; + lv_memcpy(vg_path->bounding_box, ori_vg_path->bounding_box, sizeof(ori_vg_path->bounding_box)); + + /* change path to stroke path */ + LV_LOG_TRACE("change path to stroke path: %p -> %p", (void *)lv_vg_path, (void *)stroke_path); + lv_vg_path = stroke_path; + path_drop_func = (path_drop_func_t)lv_vg_lite_stroke_drop; + path_drop_data = stroke_cache_entey; + + /* drop original path */ + lv_vg_lite_path_drop(u, ori_path); + } + + vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(lv_vg_path); + LV_VG_LITE_ASSERT_PATH(vg_path); if(vg_lite_query_feature(gcFEATURE_BIT_VG_SCISSOR)) { /* set scissor area */ @@ -137,7 +182,7 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec vg_lite_matrix_t result; if(!lv_vg_lite_matrix_inverse(&result, &matrix)) { LV_LOG_ERROR("no inverse matrix"); - lv_vg_lite_path_drop(u, lv_vg_path); + path_drop_func(u, path_drop_data); LV_PROFILER_END; return; } @@ -227,7 +272,7 @@ static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vec lv_vg_lite_flush(u); /* drop path */ - lv_vg_lite_path_drop(u, lv_vg_path); + path_drop_func(u, path_drop_data); if(vg_lite_query_feature(gcFEATURE_BIT_VG_SCISSOR)) { /* disable scissor */ @@ -321,56 +366,28 @@ static void lv_path_to_vg(lv_vg_lite_path_t * dest, const lv_vector_path_t * src } } - lv_vg_lite_path_end(dest); lv_vg_lite_path_set_bonding_box(dest, min_x, min_y, max_x, max_y); LV_PROFILER_END; } -static void lv_path_opa_to_vg(lv_vg_lite_path_t * dest, const lv_vector_draw_dsc_t * dsc) +static vg_lite_path_type_t lv_path_opa_to_path_type(const lv_vector_draw_dsc_t * dsc) { - vg_lite_path_type_t path_type = VG_LITE_DRAW_ZERO; lv_opa_t fill_opa = dsc->fill_dsc.opa; lv_opa_t stroke_opa = dsc->stroke_dsc.opa; if(fill_opa > LV_OPA_0 && stroke_opa > LV_OPA_0) { - path_type = VG_LITE_DRAW_FILL_STROKE_PATH; - } - else if(fill_opa == LV_OPA_0 && stroke_opa > LV_OPA_0) { - path_type = VG_LITE_DRAW_STROKE_PATH; - } - else if(fill_opa > LV_OPA_0) { - path_type = VG_LITE_DRAW_FILL_PATH; + return VG_LITE_DRAW_FILL_STROKE_PATH; } - LV_VG_LITE_CHECK_ERROR(vg_lite_set_path_type(lv_vg_lite_path_get_path(dest), path_type)); -} - -static void lv_stroke_to_vg(lv_vg_lite_path_t * dest, const lv_vector_stroke_dsc_t * dsc) -{ - LV_ASSERT_NULL(dest); - LV_ASSERT_NULL(dsc); - - /* if stroke opa is 0, no need to set stroke */ - if(dsc->opa == LV_OPA_0) { - return; + if(fill_opa == LV_OPA_0 && stroke_opa > LV_OPA_0) { + return VG_LITE_DRAW_STROKE_PATH; } - vg_lite_path_t * path = lv_vg_lite_path_get_path(dest); + if(fill_opa > LV_OPA_0) { + return VG_LITE_DRAW_FILL_PATH; + } - LV_VG_LITE_CHECK_ERROR( - vg_lite_set_stroke( - path, - lv_stroke_cap_to_vg(dsc->cap), - lv_stroke_join_to_vg(dsc->join), - dsc->width, - dsc->miter_limit, - lv_array_front(&dsc->dash_pattern), - dsc->dash_pattern.size, - dsc->width / 2, - lv_color32_to_vg(dsc->color, dsc->opa)) - ); - - LV_VG_LITE_CHECK_ERROR(vg_lite_update_stroke(path)); + return VG_LITE_DRAW_ZERO; } static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend) @@ -411,32 +428,4 @@ static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule) } } -static vg_lite_cap_style_t lv_stroke_cap_to_vg(lv_vector_stroke_cap_t cap) -{ - switch(cap) { - case LV_VECTOR_STROKE_CAP_SQUARE: - return VG_LITE_CAP_SQUARE; - case LV_VECTOR_STROKE_CAP_ROUND: - return VG_LITE_CAP_ROUND; - case LV_VECTOR_STROKE_CAP_BUTT: - return VG_LITE_CAP_BUTT; - default: - return VG_LITE_CAP_SQUARE; - } -} - -static vg_lite_join_style_t lv_stroke_join_to_vg(lv_vector_stroke_join_t join) -{ - switch(join) { - case LV_VECTOR_STROKE_JOIN_BEVEL: - return VG_LITE_JOIN_BEVEL; - case LV_VECTOR_STROKE_JOIN_ROUND: - return VG_LITE_JOIN_ROUND; - case LV_VECTOR_STROKE_JOIN_MITER: - return VG_LITE_JOIN_MITER; - default: - return VG_LITE_JOIN_BEVEL; - } -} - #endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/ diff --git a/src/draw/vg_lite/lv_vg_lite_path.c b/src/draw/vg_lite/lv_vg_lite_path.c index 4c6c9921f..62f5ad969 100644 --- a/src/draw/vg_lite/lv_vg_lite_path.c +++ b/src/draw/vg_lite/lv_vg_lite_path.c @@ -327,6 +327,7 @@ void lv_vg_lite_path_end(lv_vg_lite_path_t * path) { LV_ASSERT_NULL(path); lv_vg_lite_path_append_op(path, VLC_OP_END); + path->base.add_end = 1; } void lv_vg_lite_path_append_rect( @@ -589,6 +590,15 @@ void lv_vg_lite_path_for_each_data(const vg_lite_path_t * path, lv_vg_lite_path_ } } +void lv_vg_lite_path_append_path(lv_vg_lite_path_t * dest, const lv_vg_lite_path_t * src) +{ + LV_ASSERT_NULL(dest); + LV_ASSERT_NULL(src); + + LV_ASSERT(dest->base.format == dest->base.format); + lv_vg_lite_path_append_data(dest, src->base.path, src->base.path_length); +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/draw/vg_lite/lv_vg_lite_path.h b/src/draw/vg_lite/lv_vg_lite_path.h index c7172e6fe..f8c224717 100644 --- a/src/draw/vg_lite/lv_vg_lite_path.h +++ b/src/draw/vg_lite/lv_vg_lite_path.h @@ -105,6 +105,8 @@ void lv_vg_lite_path_append_arc(lv_vg_lite_path_t * path, float sweep, bool pie); +void lv_vg_lite_path_append_path(lv_vg_lite_path_t * dest, const lv_vg_lite_path_t * src); + uint8_t lv_vg_lite_vlc_op_arg_len(uint8_t vlc_op); uint8_t lv_vg_lite_path_format_len(vg_lite_format_t format); diff --git a/src/draw/vg_lite/lv_vg_lite_stroke.c b/src/draw/vg_lite/lv_vg_lite_stroke.c new file mode 100644 index 000000000..f438d6c5f --- /dev/null +++ b/src/draw/vg_lite/lv_vg_lite_stroke.c @@ -0,0 +1,309 @@ +/** + * @file lv_vg_lite_stroke.c + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_vg_lite_stroke.h" + +#if LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC + +#include "lv_vg_lite_path.h" +#include "lv_draw_vg_lite_type.h" +#include "lv_vg_lite_math.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + /* stroke path */ + lv_vg_lite_path_t * path; + + /* stroke parameters */ + float width; + lv_vector_stroke_cap_t cap; + lv_vector_stroke_join_t join; + uint16_t miter_limit; + lv_array_t dash_pattern; +} stroke_item_t; + +/********************** + * STATIC PROTOTYPES + **********************/ + +static bool stroke_create_cb(stroke_item_t * item, void * user_data); +static void stroke_free_cb(stroke_item_t * item, void * user_data); +static lv_cache_compare_res_t stroke_compare_cb(const stroke_item_t * lhs, const stroke_item_t * rhs); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_vg_lite_stroke_init(struct _lv_draw_vg_lite_unit_t * unit, uint32_t cache_cnt) +{ + LV_ASSERT_NULL(unit); + + const lv_cache_ops_t ops = { + .compare_cb = (lv_cache_compare_cb_t)stroke_compare_cb, + .create_cb = (lv_cache_create_cb_t)stroke_create_cb, + .free_cb = (lv_cache_free_cb_t)stroke_free_cb, + }; + + unit->stroke_cache = lv_cache_create(&lv_cache_class_lru_rb_count, sizeof(stroke_item_t), cache_cnt, ops); + lv_cache_set_name(unit->stroke_cache, "VG_STROKE"); +} + +void lv_vg_lite_stroke_deinit(struct _lv_draw_vg_lite_unit_t * unit) +{ + LV_ASSERT_NULL(unit); + LV_ASSERT_NULL(unit->stroke_cache); + lv_cache_destroy(unit->stroke_cache, NULL); + unit->stroke_cache = NULL; +} + +static vg_lite_cap_style_t lv_stroke_cap_to_vg(lv_vector_stroke_cap_t cap) +{ + switch(cap) { + case LV_VECTOR_STROKE_CAP_SQUARE: + return VG_LITE_CAP_SQUARE; + case LV_VECTOR_STROKE_CAP_ROUND: + return VG_LITE_CAP_ROUND; + case LV_VECTOR_STROKE_CAP_BUTT: + return VG_LITE_CAP_BUTT; + default: + return VG_LITE_CAP_SQUARE; + } +} + +static vg_lite_join_style_t lv_stroke_join_to_vg(lv_vector_stroke_join_t join) +{ + switch(join) { + case LV_VECTOR_STROKE_JOIN_BEVEL: + return VG_LITE_JOIN_BEVEL; + case LV_VECTOR_STROKE_JOIN_ROUND: + return VG_LITE_JOIN_ROUND; + case LV_VECTOR_STROKE_JOIN_MITER: + return VG_LITE_JOIN_MITER; + default: + return VG_LITE_JOIN_BEVEL; + } +} + +lv_cache_entry_t * lv_vg_lite_stroke_get(struct _lv_draw_vg_lite_unit_t * unit, + struct _lv_vg_lite_path_t * path, + const lv_vector_stroke_dsc_t * dsc) +{ + LV_ASSERT_NULL(unit); + LV_ASSERT_NULL(path); + LV_ASSERT_NULL(dsc); + + vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(path); + + if(vg_path->format != VG_LITE_FP32) { + LV_LOG_ERROR("only support VG_LITE_FP32 format"); + return NULL; + } + + /* prepare search key */ + stroke_item_t search_key; + lv_memzero(&search_key, sizeof(search_key)); + search_key.cap = dsc->cap; + search_key.join = dsc->join; + search_key.width = dsc->width; + search_key.miter_limit = dsc->miter_limit; + + /* A one-time read-only array that only copies the pointer but not the content */ + search_key.dash_pattern = dsc->dash_pattern; + search_key.path = path; + + lv_cache_entry_t * cache_node_entry = lv_cache_acquire(unit->stroke_cache, &search_key, &search_key); + if(cache_node_entry) { + return cache_node_entry; + } + + cache_node_entry = lv_cache_acquire_or_create(unit->stroke_cache, &search_key, &search_key); + if(cache_node_entry == NULL) { + LV_LOG_ERROR("stroke cache creating failed"); + return NULL; + } + + return cache_node_entry; +} + +struct _lv_vg_lite_path_t * lv_vg_lite_stroke_get_path(lv_cache_entry_t * cache_entry) +{ + LV_ASSERT_NULL(cache_entry); + + stroke_item_t * stroke_item = lv_cache_entry_get_data(cache_entry); + LV_ASSERT_NULL(stroke_item); + return stroke_item->path; +} + +void lv_vg_lite_stroke_drop(struct _lv_draw_vg_lite_unit_t * unit, + lv_cache_entry_t * cache_entry) +{ + LV_ASSERT_NULL(unit); + LV_ASSERT_NULL(cache_entry); + lv_cache_release(unit->stroke_cache, cache_entry, NULL); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static bool stroke_create_cb(stroke_item_t * item, void * user_data) +{ + LV_ASSERT_NULL(item); + + stroke_item_t * src = user_data; + LV_ASSERT_NULL(src); + + lv_memzero(item, sizeof(stroke_item_t)); + + /* copy path */ + item->path = lv_vg_lite_path_create(VG_LITE_FP32); + lv_vg_lite_path_append_path(item->path, src->path); + + /* copy parameters */ + item->cap = src->cap; + item->join = src->join; + item->width = src->width; + item->miter_limit = src->miter_limit; + + /* copy dash pattern */ + uint32_t size = lv_array_size(&src->dash_pattern); + if(size) { + lv_array_init(&item->dash_pattern, size, sizeof(float)); + lv_array_copy(&item->dash_pattern, &src->dash_pattern); + } + + /* update parameters */ + vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(item->path); + LV_VG_LITE_CHECK_ERROR(vg_lite_set_path_type(vg_path, VG_LITE_DRAW_STROKE_PATH)); + + vg_lite_error_t error = vg_lite_set_stroke( + vg_path, + lv_stroke_cap_to_vg(item->cap), + lv_stroke_join_to_vg(item->join), + item->width, + item->miter_limit, + lv_array_front(&item->dash_pattern), + size, + item->width / 2, + 0); + + if(error != VG_LITE_SUCCESS) { + LV_LOG_ERROR("vg_lite_set_stroke failed: %d(%s)", (int)error, lv_vg_lite_error_string(error)); + stroke_free_cb(item, NULL); + return false; + } + + const vg_lite_pointer * ori_path = vg_path->path; + const vg_lite_uint32_t ori_path_length = vg_path->path_length; + + LV_PROFILER_BEGIN_TAG("vg_lite_update_stroke"); + error = vg_lite_update_stroke(vg_path); + LV_PROFILER_END_TAG("vg_lite_update_stroke"); + + /* check if path is changed */ + LV_ASSERT_MSG(vg_path->path_length == ori_path_length, "vg_path->path_length should not change"); + LV_ASSERT_MSG(vg_path->path == ori_path, "vg_path->path should not change"); + + if(error != VG_LITE_SUCCESS) { + LV_LOG_ERROR("vg_lite_update_stroke failed: %d(%s)", (int)error, lv_vg_lite_error_string(error)); + stroke_free_cb(item, NULL); + return false; + } + + return true; +} + +static void stroke_free_cb(stroke_item_t * item, void * user_data) +{ + LV_UNUSED(user_data); + LV_ASSERT_NULL(item); + + lv_array_deinit(&item->dash_pattern); + lv_vg_lite_path_destroy(item->path); + lv_memzero(item, sizeof(stroke_item_t)); +} + +static lv_cache_compare_res_t path_compare(const vg_lite_path_t * lhs, const vg_lite_path_t * rhs) +{ + LV_VG_LITE_ASSERT_PATH(lhs); + LV_VG_LITE_ASSERT_PATH(rhs); + + LV_ASSERT(lhs->format == VG_LITE_FP32); + LV_ASSERT(rhs->format == VG_LITE_FP32); + + if(lhs->path_length != rhs->path_length) { + return lhs->path_length > rhs->path_length ? 1 : -1; + } + + int cmp_res = lv_memcmp(lhs->path, rhs->path, lhs->path_length); + if(cmp_res != 0) { + return cmp_res > 0 ? 1 : -1; + } + + return 0; +} + +static lv_cache_compare_res_t stroke_compare_cb(const stroke_item_t * lhs, const stroke_item_t * rhs) +{ + if(lhs->width != lhs->width) { + return lhs->width > lhs->width ? 1 : -1; + } + + if(lhs->cap != rhs->cap) { + return lhs->cap > rhs->cap ? 1 : -1; + } + + if(lhs->join != rhs->join) { + return lhs->join > rhs->join ? 1 : -1; + } + + if(lhs->miter_limit != rhs->miter_limit) { + return lhs->miter_limit > rhs->miter_limit ? 1 : -1; + } + + uint32_t lhs_dash_pattern_size = lv_array_size(&lhs->dash_pattern); + uint32_t rhs_dash_pattern_size = lv_array_size(&rhs->dash_pattern); + + if(lhs_dash_pattern_size != rhs_dash_pattern_size) { + return lhs_dash_pattern_size > rhs_dash_pattern_size ? 1 : -1; + } + + if(lhs_dash_pattern_size > 0 && rhs_dash_pattern_size > 0) { + LV_ASSERT(lhs->dash_pattern.element_size == sizeof(float)); + LV_ASSERT(rhs->dash_pattern.element_size == sizeof(float)); + + const float * lhs_dash_pattern = lv_array_front(&lhs->dash_pattern); + const float * rhs_dash_pattern = lv_array_front(&rhs->dash_pattern); + + /* compare dash pattern */ + int cmp_res = lv_memcmp(lhs_dash_pattern, rhs_dash_pattern, lhs_dash_pattern_size * sizeof(float)); + if(cmp_res != 0) { + return cmp_res > 0 ? 1 : -1; + } + } + + return path_compare(lv_vg_lite_path_get_path(lhs->path), lv_vg_lite_path_get_path(rhs->path)); +} + +#endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/ diff --git a/src/draw/vg_lite/lv_vg_lite_stroke.h b/src/draw/vg_lite/lv_vg_lite_stroke.h new file mode 100644 index 000000000..81c7e510d --- /dev/null +++ b/src/draw/vg_lite/lv_vg_lite_stroke.h @@ -0,0 +1,84 @@ +/** + * @file lv_vg_lite_stroke.h + * + */ + +#ifndef LV_VG_LITE_STROKE_H +#define LV_VG_LITE_STROKE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_vg_lite_utils.h" + +#if LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +struct _lv_vg_lite_path_t; + +struct _lv_draw_vg_lite_unit_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Initialize the stroke module + * @param unit pointer to the unit + */ +void lv_vg_lite_stroke_init(struct _lv_draw_vg_lite_unit_t * unit, uint32_t cache_cnt); + +/** + * Deinitialize the stroke module + * @param unit pointer to the unit + */ +void lv_vg_lite_stroke_deinit(struct _lv_draw_vg_lite_unit_t * unit); + +/** + * Get the stroke cache entry + * @param unit pointer to the unit + * @param path pointer to the path + * @param dsc pointer to the stroke descriptor + * @return pointer to the stroke cache entry + */ +lv_cache_entry_t * lv_vg_lite_stroke_get(struct _lv_draw_vg_lite_unit_t * unit, + struct _lv_vg_lite_path_t * path, + const lv_vector_stroke_dsc_t * dsc); + +/** + * Get the path of a stroke + * @param cache_entry pointer to the stroke cache entry + * @return pointer to the path + */ +struct _lv_vg_lite_path_t * lv_vg_lite_stroke_get_path(lv_cache_entry_t * cache_entry); + +/** + * Drop the stroke cache entry + * @param unit pointer to the unit + * @param stroke pointer to the stroke + */ +void lv_vg_lite_stroke_drop(struct _lv_draw_vg_lite_unit_t * unit, lv_cache_entry_t * cache_entry); + +/********************** + * MACROS + **********************/ + +#endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_VG_LITE_STROKE_H*/ diff --git a/src/draw/vg_lite/lv_vg_lite_utils.c b/src/draw/vg_lite/lv_vg_lite_utils.c index f7db6098e..16fb29531 100644 --- a/src/draw/vg_lite/lv_vg_lite_utils.c +++ b/src/draw/vg_lite/lv_vg_lite_utils.c @@ -275,15 +275,102 @@ void lv_vg_lite_path_dump_info(const vg_lite_path_t * path) LV_ASSERT(len > 0); - LV_LOG_USER("address: %p", path->path); + LV_LOG_USER("address: %p", (void *)path->path); LV_LOG_USER("length: %d", (int)len); LV_LOG_USER("bonding box: (%0.2f, %0.2f) - (%0.2f, %0.2f)", path->bounding_box[0], path->bounding_box[1], path->bounding_box[2], path->bounding_box[3]); LV_LOG_USER("format: %d", (int)path->format); LV_LOG_USER("quality: %d", (int)path->quality); + LV_LOG_USER("path_changed: %d", (int)path->path_changed); + LV_LOG_USER("pdata_internal: %d", (int)path->pdata_internal); + LV_LOG_USER("type: %d", (int)path->path_type); + LV_LOG_USER("add_end: %d", (int)path->add_end); lv_vg_lite_path_for_each_data(path, path_data_print_cb, NULL); + + if(path->stroke) { + LV_LOG_USER("stroke_path: %p", (void *)path->stroke_path); + LV_LOG_USER("stroke_size: %d", (int)path->stroke_size); + LV_LOG_USER("stroke_color: 0x%X", (int)path->stroke_color); + lv_vg_lite_stroke_dump_info(path->stroke); + } +} + +void lv_vg_lite_stroke_dump_info(const vg_lite_stroke_t * stroke) +{ + LV_ASSERT(stroke != NULL); + LV_LOG_USER("stroke: %p", (void *)stroke); + + /* Stroke parameters */ + LV_LOG_USER("cap_style: 0x%X", (int)stroke->cap_style); + LV_LOG_USER("join_style: 0x%X", (int)stroke->join_style); + LV_LOG_USER("line_width: %f", stroke->line_width); + LV_LOG_USER("miter_limit: %f", stroke->miter_limit); + + LV_LOG_USER("dash_pattern: %p", (void *)stroke->dash_pattern); + LV_LOG_USER("pattern_count: %d", (int)stroke->pattern_count); + if(stroke->dash_pattern) { + for(int i = 0; i < (int)stroke->pattern_count; i++) { + LV_LOG_USER("dash_pattern[%d]: %f", i, stroke->dash_pattern[i]); + } + } + + LV_LOG_USER("dash_phase: %f", stroke->dash_phase); + LV_LOG_USER("dash_length: %f", stroke->dash_length); + LV_LOG_USER("dash_index: %d", (int)stroke->dash_index); + LV_LOG_USER("half_width: %f", stroke->half_width); + + /* Total length of stroke dash patterns. */ + LV_LOG_USER("pattern_length: %f", stroke->pattern_length); + + /* For fast checking. */ + LV_LOG_USER("miter_square: %f", stroke->miter_square); + + /* Temp storage of stroke subPath. */ + LV_LOG_USER("path_points: %p", (void *)stroke->path_points); + LV_LOG_USER("path_end: %p", (void *)stroke->path_end); + LV_LOG_USER("point_count: %d", (int)stroke->point_count); + + LV_LOG_USER("left_point: %p", (void *)stroke->left_point); + LV_LOG_USER("right_point: %p", (void *)stroke->right_point); + LV_LOG_USER("stroke_points: %p", (void *)stroke->stroke_points); + LV_LOG_USER("stroke_end: %p", (void *)stroke->stroke_end); + LV_LOG_USER("stroke_count: %d", (int)stroke->stroke_count); + + /* Divide stroke path according to move or move_rel for avoiding implicit closure. */ + LV_LOG_USER("path_list_divide: %p", (void *)stroke->path_list_divide); + + /* pointer to current divided path data. */ + LV_LOG_USER("cur_list: %p", (void *)stroke->cur_list); + + /* Flag that add end_path in driver. */ + LV_LOG_USER("add_end: %d", (int)stroke->add_end); + LV_LOG_USER("dash_reset: %d", (int)stroke->dash_reset); + + /* Sub path list. */ + LV_LOG_USER("stroke_paths: %p", (void *)stroke->stroke_paths); + + /* Last sub path. */ + LV_LOG_USER("last_stroke: %p", (void *)stroke->last_stroke); + + /* Swing area handling. */ + LV_LOG_USER("swing_handling: %d", (int)stroke->swing_handling); + LV_LOG_USER("swing_deltax: %f", stroke->swing_deltax); + LV_LOG_USER("swing_deltay: %f", stroke->swing_deltay); + LV_LOG_USER("swing_start: %p", (void *)stroke->swing_start); + LV_LOG_USER("swing_stroke: %p", (void *)stroke->swing_stroke); + LV_LOG_USER("swing_length: %f", stroke->swing_length); + LV_LOG_USER("swing_centlen: %f", stroke->swing_centlen); + LV_LOG_USER("swing_count: %d", (int)stroke->swing_count); + LV_LOG_USER("need_swing: %d", (int)stroke->need_swing); + LV_LOG_USER("swing_ccw: %d", (int)stroke->swing_ccw); + + LV_LOG_USER("stroke_length: %f", stroke->stroke_length); + LV_LOG_USER("stroke_size: %d", (int)stroke->stroke_size); + + LV_LOG_USER("fattened: %d", (int)stroke->fattened); + LV_LOG_USER("closed: %d", (int)stroke->closed); } void lv_vg_lite_buffer_dump_info(const vg_lite_buffer_t * buffer) @@ -899,10 +986,26 @@ bool lv_vg_lite_path_check(const vg_lite_path_t * path) return false; } - uint8_t end_op_code = VLC_GET_OP_CODE(end - fmt_len); - if(end_op_code != VLC_OP_END) { - LV_LOG_ERROR("%d (%s) -> is NOT VLC_OP_END", end_op_code, lv_vg_lite_vlc_op_string(end_op_code)); - return false; + switch(path->path_type) { + case VG_LITE_DRAW_ZERO: + case VG_LITE_DRAW_FILL_PATH: + case VG_LITE_DRAW_FILL_STROKE_PATH: { + /* Check end op code */ + uint8_t end_op_code = VLC_GET_OP_CODE(end - fmt_len); + if(end_op_code != VLC_OP_END) { + LV_LOG_ERROR("%d (%s) -> is NOT VLC_OP_END", end_op_code, lv_vg_lite_vlc_op_string(end_op_code)); + return false; + } + } + break; + + case VG_LITE_DRAW_STROKE_PATH: + /* No need to check stroke path end */ + break; + + default: + LV_LOG_ERROR("path type(%d) is invalid", (int)path->path_type); + return false; } return true; diff --git a/src/draw/vg_lite/lv_vg_lite_utils.h b/src/draw/vg_lite/lv_vg_lite_utils.h index 96ff3261b..9e62ae448 100644 --- a/src/draw/vg_lite/lv_vg_lite_utils.h +++ b/src/draw/vg_lite/lv_vg_lite_utils.h @@ -91,6 +91,8 @@ const char * lv_vg_lite_vlc_op_string(uint8_t vlc_op); void lv_vg_lite_path_dump_info(const vg_lite_path_t * path); +void lv_vg_lite_stroke_dump_info(const vg_lite_stroke_t * stroke); + void lv_vg_lite_buffer_dump_info(const vg_lite_buffer_t * buffer); void lv_vg_lite_matrix_dump_info(const vg_lite_matrix_t * matrix); diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 2c1986092..eea40934c 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -679,6 +679,16 @@ #endif #endif +/* VG-Lite stroke maximum cache number. + */ +#ifndef LV_VG_LITE_STROKE_CACHE_CNT + #ifdef CONFIG_LV_VG_LITE_STROKE_CACHE_CNT + #define LV_VG_LITE_STROKE_CACHE_CNT CONFIG_LV_VG_LITE_STROKE_CACHE_CNT + #else + #define LV_VG_LITE_STROKE_CACHE_CNT 32 + #endif +#endif + #endif /*=======================