mirror of
https://github.com/lvgl/lvgl.git
synced 2024-11-27 03:33:48 +08:00
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:
parent
efbb983c16
commit
42eec5fb42
5
Kconfig
5
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
|
||||
|
@ -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
|
||||
|
||||
/*=======================
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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*/
|
||||
|
@ -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
|
||||
**********************/
|
||||
|
@ -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);
|
||||
|
309
src/draw/vg_lite/lv_vg_lite_stroke.c
Normal file
309
src/draw/vg_lite/lv_vg_lite_stroke.c
Normal 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*/
|
84
src/draw/vg_lite/lv_vg_lite_stroke.h
Normal file
84
src/draw/vg_lite/lv_vg_lite_stroke.h
Normal 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*/
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
/*=======================
|
||||
|
Loading…
Reference in New Issue
Block a user