mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-22 15:24:16 +08:00
feat(NemaGFX): add vector draw task support (#8938)
This commit is contained in:
@@ -75,6 +75,36 @@ provided implementations by setting :c:macro:`LV_USE_NEMA_HAL` to a value other
|
||||
:c:macro:`LV_NEMA_HAL_CUSTOM`.
|
||||
|
||||
|
||||
Vector Graphics
|
||||
***************
|
||||
|
||||
The NeoChrom VG driver in LVGL can render vector graphics Widgets using NeoChrom VG's
|
||||
hardware support for vector graphics drawing. You can display SVG files in your application.
|
||||
See the SVG examples for usage.
|
||||
|
||||
To use vector graphics with NeoChrom, you should enable the following configs in ``lv_conf.h``.
|
||||
|
||||
.. code-block::
|
||||
|
||||
LV_USE_NEMA_GFX 1
|
||||
LV_USE_NEMA_VG 1
|
||||
LV_USE_VECTOR_GRAPHIC 1
|
||||
LV_USE_MATRIX 1
|
||||
LV_USE_FLOAT 1
|
||||
|
||||
To use the SVG widget, additionally enable ``LV_USE_SVG``.
|
||||
|
||||
If there is RAM available, SVG performance can be increased by enabling the image cache,
|
||||
``LV_CACHE_DEF_SIZE``.
|
||||
``LV_CACHE_DEF_SIZE`` is a cache size in bytes. If it is large enough for your SVGs,
|
||||
it will cache decoded SVG data so it does not need to be parsed every refresh, significantly
|
||||
reducing SVG redraw time.
|
||||
|
||||
``LV_USE_DEMO_VECTOR_GRAPHIC`` is a demo you can enable which draws some vector graphics shapes.
|
||||
Gradient and image fills are not supported yet, as well as dashed strokes. These are
|
||||
missing from the demo when it is run with the NeoChrom driver.
|
||||
|
||||
|
||||
TSC Images
|
||||
**********
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
<svg width="12cm" height="4cm" viewBox="0 0 1200 400">
|
||||
<circle cx="600" cy="200" r="100" fill="red" stroke="blue" stroke-width="10"/></svg>
|
||||
|
After Width: | Height: | Size: 139 B |
@@ -1,6 +1,17 @@
|
||||
Load and render SVG data
|
||||
---------------------------------------
|
||||
------------------------
|
||||
|
||||
.. lv_example:: libs/svg/lv_example_svg_1
|
||||
:language: c
|
||||
|
||||
Load and render SVG data from a file
|
||||
------------------------------------
|
||||
|
||||
.. lv_example:: libs/svg/lv_example_svg_2
|
||||
:language: c
|
||||
|
||||
Load and render SVG data in a draw event
|
||||
----------------------------------------
|
||||
|
||||
.. lv_example:: libs/svg/lv_example_svg_3
|
||||
:language: c
|
||||
|
||||
@@ -26,6 +26,8 @@ extern "C" {
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
void lv_example_svg_1(void);
|
||||
void lv_example_svg_2(void);
|
||||
void lv_example_svg_3(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
/**
|
||||
* Load an SVG data
|
||||
* Load an SVG from data
|
||||
*/
|
||||
static void event_cb(lv_event_t * e)
|
||||
{
|
||||
static char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
|
||||
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
|
||||
|
||||
lv_layer_t * layer = lv_event_get_layer(e);
|
||||
lv_svg_node_t * svg = lv_svg_load_data(svg_data, sizeof(svg_data) / sizeof(char));
|
||||
lv_draw_svg(layer, svg);
|
||||
lv_svg_node_delete(svg);
|
||||
}
|
||||
|
||||
void lv_example_svg_1(void)
|
||||
{
|
||||
lv_obj_add_event_cb(lv_screen_active(), event_cb, LV_EVENT_DRAW_MAIN, NULL);
|
||||
static const char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
|
||||
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
|
||||
|
||||
static lv_image_dsc_t svg_dsc;
|
||||
svg_dsc.header.magic = LV_IMAGE_HEADER_MAGIC;
|
||||
svg_dsc.header.w = 450;
|
||||
svg_dsc.header.h = 150;
|
||||
svg_dsc.data_size = sizeof(svg_data) - 1;
|
||||
svg_dsc.data = (const uint8_t *) svg_data;
|
||||
|
||||
lv_obj_t * svg = lv_image_create(lv_screen_active());
|
||||
lv_image_set_src(svg, &svg_dsc);
|
||||
}
|
||||
#else
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_BUILD_EXAMPLES
|
||||
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
/**
|
||||
* Load an SVG from a file
|
||||
*/
|
||||
void lv_example_svg_2(void)
|
||||
{
|
||||
lv_obj_t * svg = lv_image_create(lv_screen_active());
|
||||
lv_image_set_src(svg, "A:lvgl/examples/assets/circle.svg");
|
||||
}
|
||||
#else
|
||||
|
||||
void lv_example_svg_2(void)
|
||||
{
|
||||
/*TODO
|
||||
*fallback for online examples*/
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "SVG is not enabled");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "../../lv_examples.h"
|
||||
#if LV_BUILD_EXAMPLES
|
||||
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
/**
|
||||
* Draw SVG data in a draw event
|
||||
*/
|
||||
static void event_cb(lv_event_t * e)
|
||||
{
|
||||
static const char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
|
||||
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
|
||||
|
||||
lv_layer_t * layer = lv_event_get_layer(e);
|
||||
lv_svg_node_t * svg = lv_svg_load_data(svg_data, sizeof(svg_data) / sizeof(char));
|
||||
lv_draw_svg(layer, svg);
|
||||
lv_svg_node_delete(svg);
|
||||
}
|
||||
|
||||
void lv_example_svg_3(void)
|
||||
{
|
||||
lv_obj_add_event_cb(lv_screen_active(), event_cb, LV_EVENT_DRAW_MAIN, NULL);
|
||||
}
|
||||
#else
|
||||
|
||||
void lv_example_svg_3(void)
|
||||
{
|
||||
/*TODO
|
||||
*fallback for online examples*/
|
||||
|
||||
lv_obj_t * label = lv_label_create(lv_screen_active());
|
||||
lv_label_set_text(label, "SVG is not enabled");
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
|
||||
#if !((LV_USE_DRAW_SW && LV_USE_THORVG) || LV_USE_DRAW_VG_LITE)
|
||||
#error "LV_USE_VECTOR_GRAPHIC requires either (LV_USE_DRAW_SW and LV_USE_THORVG) or LV_USE_DRAW_VG_LITE"
|
||||
#if !((LV_USE_DRAW_SW && LV_USE_THORVG) || LV_USE_DRAW_VG_LITE || (LV_USE_NEMA_GFX && LV_USE_NEMA_VG))
|
||||
#error "LV_USE_VECTOR_GRAPHIC requires (LV_USE_DRAW_SW and LV_USE_THORVG) or LV_USE_DRAW_VG_LITE or (LV_USE_NEMA_GFX and LV_USE_NEMA_VG)"
|
||||
#endif
|
||||
|
||||
#include "../misc/lv_ll.h"
|
||||
|
||||
@@ -243,12 +243,18 @@ static int32_t nema_gfx_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * ta
|
||||
}
|
||||
break;
|
||||
}
|
||||
#if LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||
case LV_DRAW_TASK_TYPE_VECTOR: {
|
||||
if(task->preference_score > 80) {
|
||||
task->preference_score = 80;
|
||||
task->preferred_draw_unit_id = DRAW_UNIT_ID_NEMA_GFX;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
case LV_DRAW_TASK_TYPE_BOX_SHADOW:
|
||||
case LV_DRAW_TASK_TYPE_MASK_RECTANGLE:
|
||||
case LV_DRAW_TASK_TYPE_MASK_BITMAP:
|
||||
#if LV_USE_VECTOR_GRAPHIC
|
||||
case LV_DRAW_TASK_TYPE_VECTOR:
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -328,6 +334,11 @@ static void nema_gfx_execute_drawing(lv_draw_nema_gfx_unit_t * u)
|
||||
case LV_DRAW_TASK_TYPE_BORDER:
|
||||
lv_draw_nema_gfx_border(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
#if LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||
case LV_DRAW_TASK_TYPE_VECTOR:
|
||||
lv_draw_nema_gfx_vector(t, t->draw_dsc, &t->area);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -110,6 +110,11 @@ void lv_draw_nema_gfx_border(lv_draw_task_t * t, const lv_draw_border_dsc_t * ds
|
||||
void lv_draw_nema_gfx_arc(lv_draw_task_t * t, const lv_draw_arc_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
|
||||
#if LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||
void lv_draw_nema_gfx_vector(lv_draw_task_t * t, const lv_draw_vector_dsc_t * dsc,
|
||||
const lv_area_t * coords);
|
||||
#endif
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* @file lv_draw_nema_gfx_vector.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "lv_draw_nema_gfx.h"
|
||||
#if LV_USE_NEMA_GFX && LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG
|
||||
|
||||
#include "lv_nema_gfx_path.h"
|
||||
#include "../lv_draw_vector_private.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_draw_nema_gfx_unit_t * u;
|
||||
float rel_translate_x;
|
||||
float rel_translate_y;
|
||||
} ctx_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_path_ctx_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_nema_gfx_vector(lv_draw_task_t * t, const lv_draw_vector_dsc_t * dsc,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
ctx_t c;
|
||||
c.u = (lv_draw_nema_gfx_unit_t *) t->draw_unit;
|
||||
|
||||
lv_layer_t * layer = t->target_layer;
|
||||
lv_area_t rel_clip_area;
|
||||
lv_area_copy(&rel_clip_area, &t->clip_area);
|
||||
lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1);
|
||||
|
||||
c.rel_translate_x = -layer->buf_area.x1;
|
||||
c.rel_translate_y = -layer->buf_area.y1;
|
||||
|
||||
nema_set_clip(rel_clip_area.x1, rel_clip_area.y1, lv_area_get_width(&rel_clip_area),
|
||||
lv_area_get_height(&rel_clip_area));
|
||||
|
||||
lv_color_format_t dst_cf = layer->draw_buf->header.cf;
|
||||
uint32_t dst_nema_cf = lv_nemagfx_cf_to_nema(dst_cf);
|
||||
|
||||
/* the stride should be computed internally for NEMA_TSC images and images missing a stride value */
|
||||
int32_t stride = (dst_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && dst_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) ?
|
||||
-1 : lv_area_get_width(&(layer->buf_area)) * lv_color_format_get_size(dst_cf);
|
||||
|
||||
nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)),
|
||||
lv_area_get_height(&(layer->buf_area)), dst_nema_cf, stride);
|
||||
|
||||
nema_vg_set_blend(NEMA_BL_SRC_OVER | NEMA_BLOP_SRC_PREMULT);
|
||||
|
||||
lv_vector_for_each_destroy_tasks(dsc->task_list, task_draw_cb, &c);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_path_ctx_t * dsc)
|
||||
{
|
||||
ctx_t * c = ctx;
|
||||
lv_draw_nema_gfx_unit_t * u = c->u;
|
||||
|
||||
if(!path) return;
|
||||
|
||||
nema_vg_path_clear(u->path);
|
||||
nema_vg_paint_clear(u->paint);
|
||||
|
||||
nema_vg_paint_set_type(u->paint, NEMA_VG_PAINT_COLOR);
|
||||
|
||||
lv_matrix_t matrix = dsc->matrix;
|
||||
matrix.m[0][2] += c->rel_translate_x;
|
||||
matrix.m[1][2] += c->rel_translate_y;
|
||||
nema_vg_path_set_matrix(c->u->path, (void *) &matrix);
|
||||
|
||||
/* the path ops array needs to be translated to nema's opcodes */
|
||||
lv_vector_path_op_t * ops = lv_array_front(&path->ops);
|
||||
uint32_t op_count = lv_array_size(&path->ops);
|
||||
uint8_t * nema_ops = lv_malloc(op_count * sizeof(*nema_ops));
|
||||
LV_ASSERT_MALLOC(nema_ops);
|
||||
for(uint32_t i = 0; i < op_count; i++) {
|
||||
nema_ops[i] = ops[i] == LV_VECTOR_PATH_OP_MOVE_TO ? NEMA_VG_PRIM_MOVE :
|
||||
ops[i] == LV_VECTOR_PATH_OP_LINE_TO ? NEMA_VG_PRIM_LINE :
|
||||
ops[i] == LV_VECTOR_PATH_OP_QUAD_TO ? NEMA_VG_PRIM_BEZIER_QUAD :
|
||||
ops[i] == LV_VECTOR_PATH_OP_CUBIC_TO ? NEMA_VG_PRIM_BEZIER_CUBIC :
|
||||
/*LV_VECTOR_PATH_OP_CLOSE*/ NEMA_VG_PRIM_CLOSE;
|
||||
}
|
||||
|
||||
/* the path points array is in the right format for nema to use as-is */
|
||||
uint32_t point_count = lv_array_size(&path->points);
|
||||
float * points = lv_array_front(&path->points);
|
||||
|
||||
nema_vg_path_set_shape(u->path, op_count, nema_ops, point_count, points);
|
||||
|
||||
nema_vg_set_quality(path->quality == LV_VECTOR_PATH_QUALITY_LOW ? NEMA_VG_QUALITY_FASTER :
|
||||
path->quality == LV_VECTOR_PATH_QUALITY_MEDIUM ? NEMA_VG_QUALITY_BETTER :
|
||||
/*LV_VECTOR_PATH_QUALITY_HIGH*/ NEMA_VG_QUALITY_MAXIMUM);
|
||||
|
||||
if(dsc->fill_dsc.opa) {
|
||||
nema_vg_set_fill_rule(dsc->fill_dsc.fill_rule == LV_VECTOR_FILL_NONZERO ? NEMA_VG_FILL_NON_ZERO :
|
||||
/*LV_VECTOR_FILL_EVENODD*/ NEMA_VG_FILL_EVEN_ODD);
|
||||
|
||||
uint32_t nema_dsc_color = nema_rgba(dsc->fill_dsc.color.red, dsc->fill_dsc.color.green,
|
||||
dsc->fill_dsc.color.blue, dsc->fill_dsc.color.alpha);
|
||||
nema_vg_paint_set_paint_color(u->paint, nema_dsc_color);
|
||||
|
||||
nema_vg_draw_path(u->path, u->paint);
|
||||
}
|
||||
|
||||
if(dsc->stroke_dsc.opa) {
|
||||
nema_vg_set_fill_rule(NEMA_VG_STROKE);
|
||||
nema_vg_stroke_set_width(dsc->stroke_dsc.width);
|
||||
uint8_t cap = dsc->stroke_dsc.cap == LV_VECTOR_STROKE_CAP_BUTT ? NEMA_VG_CAP_BUTT :
|
||||
dsc->stroke_dsc.cap == LV_VECTOR_STROKE_CAP_SQUARE ? NEMA_VG_CAP_SQUARE :
|
||||
/*LV_VECTOR_STROKE_CAP_ROUND*/ NEMA_VG_CAP_ROUND;
|
||||
nema_vg_stroke_set_cap_style(cap, cap);
|
||||
uint8_t join = dsc->stroke_dsc.join == LV_VECTOR_STROKE_JOIN_MITER ? NEMA_VG_JOIN_MITER :
|
||||
dsc->stroke_dsc.join == LV_VECTOR_STROKE_JOIN_BEVEL ? NEMA_VG_JOIN_BEVEL :
|
||||
/*LV_VECTOR_STROKE_JOIN_ROUND*/ NEMA_VG_JOIN_ROUND;
|
||||
nema_vg_stroke_set_join_style(join);
|
||||
nema_vg_stroke_set_miter_limit(dsc->stroke_dsc.miter_limit);
|
||||
|
||||
uint32_t nema_dsc_color = nema_rgba(dsc->stroke_dsc.color.red, dsc->stroke_dsc.color.green,
|
||||
dsc->stroke_dsc.color.blue, dsc->stroke_dsc.color.alpha);
|
||||
nema_vg_paint_set_paint_color(u->paint, nema_dsc_color);
|
||||
|
||||
nema_vg_draw_path(u->path, u->paint);
|
||||
}
|
||||
|
||||
nema_cl_submit(&c->u->cl);
|
||||
nema_cl_wait(&u->cl);
|
||||
|
||||
lv_free(nema_ops);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_NEMA_GFX && LV_USE_VECTOR_GRAPHIC && LV_USE_NEMA_VG*/
|
||||
Reference in New Issue
Block a user