perf(vg_lite): add stroke path cache to improve drawing performance (#6502)

Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com>
Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
This commit is contained in:
VIFEX 2024-07-25 04:40:00 +08:00 committed by GitHub
parent efbb983c16
commit 42eec5fb42
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 606 additions and 83 deletions

View File

@ -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

View File

@ -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
/*=======================

View File

@ -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();

View File

@ -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;

View File

@ -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 <float.h>
/*********************
@ -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*/

View File

@ -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
**********************/

View File

@ -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);

View File

@ -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*/

View File

@ -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*/

View File

@ -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;

View File

@ -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);

View File

@ -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
/*=======================