1 /**
2 * @file lv_draw_vg_lite_vector.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9
10 #include "../lv_image_decoder_private.h"
11 #include "../lv_draw_vector_private.h"
12 #include "lv_draw_vg_lite.h"
13
14 #if LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC
15
16 #include "lv_draw_vg_lite_type.h"
17 #include "lv_vg_lite_path.h"
18 #include "lv_vg_lite_pending.h"
19 #include "lv_vg_lite_utils.h"
20 #include "lv_vg_lite_grad.h"
21 #include "lv_vg_lite_stroke.h"
22 #include <float.h>
23
24 /*********************
25 * DEFINES
26 *********************/
27
28 /**********************
29 * TYPEDEFS
30 **********************/
31
32 typedef void * path_drop_data_t;
33 typedef void (*path_drop_func_t)(struct _lv_draw_vg_lite_unit_t *, path_drop_data_t);
34
35 /**********************
36 * STATIC PROTOTYPES
37 **********************/
38
39 static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc);
40 static void lv_path_to_vg(lv_vg_lite_path_t * dest, const lv_vector_path_t * src);
41 static vg_lite_path_type_t lv_path_opa_to_path_type(const lv_vector_draw_dsc_t * dsc);
42 static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend);
43 static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule);
44
45 /**********************
46 * STATIC VARIABLES
47 **********************/
48
49 /**********************
50 * MACROS
51 **********************/
52
53 /**********************
54 * GLOBAL FUNCTIONS
55 **********************/
56
lv_draw_vg_lite_vector(lv_draw_unit_t * draw_unit,const lv_draw_vector_task_dsc_t * dsc)57 void lv_draw_vg_lite_vector(lv_draw_unit_t * draw_unit, const lv_draw_vector_task_dsc_t * dsc)
58 {
59 if(dsc->task_list == NULL)
60 return;
61
62 lv_layer_t * layer = dsc->base.layer;
63 if(layer->draw_buf == NULL)
64 return;
65
66 LV_PROFILER_DRAW_BEGIN;
67 lv_vector_for_each_destroy_tasks(dsc->task_list, task_draw_cb, draw_unit);
68 LV_PROFILER_DRAW_END;
69 }
70
71 /**********************
72 * STATIC FUNCTIONS
73 **********************/
74
lv_color32_to_vg(lv_color32_t color,lv_opa_t opa)75 static vg_lite_color_t lv_color32_to_vg(lv_color32_t color, lv_opa_t opa)
76 {
77 uint8_t a = LV_OPA_MIX2(color.alpha, opa);
78 if(a < LV_OPA_COVER) {
79 color.red = LV_UDIV255(color.red * a);
80 color.green = LV_UDIV255(color.green * a);
81 color.blue = LV_UDIV255(color.blue * a);
82 }
83 return (uint32_t)a << 24 | (uint32_t)color.blue << 16 | (uint32_t)color.green << 8 | color.red;
84 }
85
task_draw_cb(void * ctx,const lv_vector_path_t * path,const lv_vector_draw_dsc_t * dsc)86 static void task_draw_cb(void * ctx, const lv_vector_path_t * path, const lv_vector_draw_dsc_t * dsc)
87 {
88 LV_PROFILER_DRAW_BEGIN;
89 lv_draw_vg_lite_unit_t * u = ctx;
90 LV_VG_LITE_ASSERT_DEST_BUFFER(&u->target_buffer);
91
92 /* clear area */
93 if(!path) {
94 /* clear color needs to ignore fill_dsc.opa */
95 vg_lite_color_t c = lv_color32_to_vg(dsc->fill_dsc.color, LV_OPA_COVER);
96 vg_lite_rectangle_t rect;
97 lv_vg_lite_rect(&rect, &dsc->scissor_area);
98 LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_clear");
99 LV_VG_LITE_CHECK_ERROR(vg_lite_clear(&u->target_buffer, &rect, c));
100 LV_PROFILER_DRAW_END_TAG("vg_lite_clear");
101 LV_PROFILER_DRAW_END;
102 return;
103 }
104
105 /* convert color */
106 vg_lite_color_t vg_color = lv_color32_to_vg(dsc->fill_dsc.color, dsc->fill_dsc.opa);
107
108 /* transform matrix */
109 vg_lite_matrix_t matrix;
110 lv_vg_lite_matrix(&matrix, &dsc->matrix);
111 LV_VG_LITE_ASSERT_MATRIX(&matrix);
112
113 /* convert path */
114 lv_vg_lite_path_t * lv_vg_path = lv_vg_lite_path_get(u, VG_LITE_FP32);
115 lv_path_to_vg(lv_vg_path, path);
116
117 /* get path bounds */
118 float min_x, min_y, max_x, max_y;
119 lv_vg_lite_path_get_bounding_box(lv_vg_path, &min_x, &min_y, &max_x, &max_y);
120
121 /* convert path type */
122 vg_lite_path_type_t path_type = lv_path_opa_to_path_type(dsc);
123
124 /* convert blend mode and fill rule */
125 vg_lite_blend_t blend = lv_blend_to_vg(dsc->blend_mode);
126 vg_lite_fill_t fill = lv_fill_to_vg(dsc->fill_dsc.fill_rule);
127
128 /* set default path drop function and data */
129 path_drop_func_t path_drop_func = (path_drop_func_t)lv_vg_lite_path_drop;
130 path_drop_data_t path_drop_data = lv_vg_path;
131
132 /* If it is fill mode, the end op code should be added */
133 if(path_type == VG_LITE_DRAW_ZERO
134 || path_type == VG_LITE_DRAW_FILL_PATH
135 || path_type == VG_LITE_DRAW_FILL_STROKE_PATH) {
136 lv_vg_lite_path_end(lv_vg_path);
137 }
138
139 /* convert stroke style */
140 if(path_type == VG_LITE_DRAW_STROKE_PATH
141 || path_type == VG_LITE_DRAW_FILL_STROKE_PATH) {
142 lv_cache_entry_t * stroke_cache_entey = lv_vg_lite_stroke_get(u, lv_vg_path, &dsc->stroke_dsc);
143
144 if(!stroke_cache_entey) {
145 LV_LOG_ERROR("convert stroke failed");
146
147 /* drop original path */
148 lv_vg_lite_path_drop(u, lv_vg_path);
149 LV_PROFILER_DRAW_END;
150 return;
151 }
152
153 lv_vg_lite_path_t * ori_path = lv_vg_path;
154 const vg_lite_path_t * ori_vg_path = lv_vg_lite_path_get_path(ori_path);
155
156 lv_vg_lite_path_t * stroke_path = lv_vg_lite_stroke_get_path(stroke_cache_entey);
157 vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(stroke_path);
158
159 /* set stroke params */
160 LV_VG_LITE_CHECK_ERROR(vg_lite_set_path_type(vg_path, path_type));
161 vg_path->stroke_color = lv_color32_to_vg(dsc->stroke_dsc.color, dsc->stroke_dsc.opa);
162 vg_path->quality = ori_vg_path->quality;
163 lv_memcpy(vg_path->bounding_box, ori_vg_path->bounding_box, sizeof(ori_vg_path->bounding_box));
164
165 /* change path to stroke path */
166 LV_LOG_TRACE("change path to stroke path: %p -> %p", (void *)lv_vg_path, (void *)stroke_path);
167 lv_vg_path = stroke_path;
168 path_drop_func = (path_drop_func_t)lv_vg_lite_stroke_drop;
169 path_drop_data = stroke_cache_entey;
170
171 /* drop original path */
172 lv_vg_lite_path_drop(u, ori_path);
173 }
174
175 vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(lv_vg_path);
176 LV_VG_LITE_ASSERT_PATH(vg_path);
177
178 if(vg_lite_query_feature(gcFEATURE_BIT_VG_SCISSOR)) {
179 /* set scissor area */
180 lv_vg_lite_set_scissor_area(&dsc->scissor_area);
181
182 /* no bounding box */
183 lv_vg_lite_path_set_bounding_box(lv_vg_path,
184 (float)PATH_COORD_MIN, (float)PATH_COORD_MIN,
185 (float)PATH_COORD_MAX, (float)PATH_COORD_MAX);
186 }
187 else {
188 /* calc inverse matrix */
189 vg_lite_matrix_t result;
190 if(!lv_vg_lite_matrix_inverse(&result, &matrix)) {
191 LV_LOG_ERROR("no inverse matrix");
192 path_drop_func(u, path_drop_data);
193 LV_PROFILER_DRAW_END;
194 return;
195 }
196
197 /* Reverse the clip area on the source */
198 lv_point_precise_t p1 = { dsc->scissor_area.x1, dsc->scissor_area.y1 };
199 lv_point_precise_t p1_res = lv_vg_lite_matrix_transform_point(&result, &p1);
200
201 /* vg-lite bounding_box will crop the pixels on the edge, so +1px is needed here */
202 lv_point_precise_t p2 = { dsc->scissor_area.x2 + 1, dsc->scissor_area.y2 + 1 };
203 lv_point_precise_t p2_res = lv_vg_lite_matrix_transform_point(&result, &p2);
204
205 lv_vg_lite_path_set_bounding_box(lv_vg_path, p1_res.x, p1_res.y, p2_res.x, p2_res.y);
206 }
207
208 switch(dsc->fill_dsc.style) {
209 case LV_VECTOR_DRAW_STYLE_SOLID: {
210 /* normal draw shape */
211 LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw");
212 LV_VG_LITE_CHECK_ERROR(vg_lite_draw(
213 &u->target_buffer,
214 vg_path,
215 fill,
216 &matrix,
217 blend,
218 vg_color));
219 LV_PROFILER_DRAW_END_TAG("vg_lite_draw");
220 }
221 break;
222 case LV_VECTOR_DRAW_STYLE_PATTERN: {
223 /* draw image */
224 vg_lite_buffer_t image_buffer;
225 lv_image_decoder_dsc_t decoder_dsc;
226 if(lv_vg_lite_buffer_open_image(&image_buffer, &decoder_dsc, dsc->fill_dsc.img_dsc.src, false, true)) {
227 /* Calculate pattern matrix. Should start from path bond box, and also apply fill matrix. */
228 lv_matrix_t m = dsc->matrix;
229 lv_matrix_translate(&m, min_x, min_y);
230 lv_matrix_multiply(&m, &dsc->fill_dsc.matrix);
231
232 vg_lite_matrix_t pattern_matrix;
233 lv_vg_lite_matrix(&pattern_matrix, &m);
234
235 vg_lite_color_t recolor = lv_vg_lite_image_recolor(&image_buffer, &dsc->fill_dsc.img_dsc);
236
237 LV_VG_LITE_ASSERT_MATRIX(&pattern_matrix);
238
239 LV_PROFILER_DRAW_BEGIN_TAG("vg_lite_draw_pattern");
240 LV_VG_LITE_CHECK_ERROR(vg_lite_draw_pattern(
241 &u->target_buffer,
242 vg_path,
243 fill,
244 &matrix,
245 &image_buffer,
246 &pattern_matrix,
247 blend,
248 VG_LITE_PATTERN_COLOR,
249 0,
250 recolor,
251 VG_LITE_FILTER_BI_LINEAR));
252 LV_PROFILER_DRAW_END_TAG("vg_lite_draw_pattern");
253
254 lv_vg_lite_pending_add(u->image_dsc_pending, &decoder_dsc);
255 }
256 }
257 break;
258 case LV_VECTOR_DRAW_STYLE_GRADIENT: {
259 vg_lite_matrix_t grad_matrix = matrix;
260
261 #if LV_USE_VG_LITE_THORVG
262 /* Workaround inconsistent radial gradient matrix behavior between device and ThorVG */
263 if(dsc->fill_dsc.gradient.style == LV_VECTOR_GRADIENT_STYLE_RADIAL) {
264 /* Restore matrix to identity */
265 vg_lite_identity(&grad_matrix);
266 }
267 #endif
268 vg_lite_matrix_t fill_matrix;
269 lv_vg_lite_matrix(&fill_matrix, &dsc->fill_dsc.matrix);
270 lv_vg_lite_matrix_multiply(&grad_matrix, &fill_matrix);
271
272 lv_vg_lite_draw_grad(
273 u,
274 &u->target_buffer,
275 vg_path,
276 &dsc->fill_dsc.gradient,
277 &grad_matrix,
278 &matrix,
279 fill,
280 blend);
281 }
282 break;
283 default:
284 LV_LOG_WARN("unknown style: %d", dsc->fill_dsc.style);
285 break;
286 }
287
288 /* Flush in time to avoid accumulation of drawing commands */
289 lv_vg_lite_flush(u);
290
291 /* drop path */
292 path_drop_func(u, path_drop_data);
293
294 if(vg_lite_query_feature(gcFEATURE_BIT_VG_SCISSOR)) {
295 /* disable scissor */
296 lv_vg_lite_disable_scissor();
297 }
298
299 LV_PROFILER_DRAW_END;
300 }
301
lv_quality_to_vg(lv_vector_path_quality_t quality)302 static vg_lite_quality_t lv_quality_to_vg(lv_vector_path_quality_t quality)
303 {
304 switch(quality) {
305 case LV_VECTOR_PATH_QUALITY_LOW:
306 return VG_LITE_LOW;
307 case LV_VECTOR_PATH_QUALITY_MEDIUM:
308 return VG_LITE_MEDIUM;
309 case LV_VECTOR_PATH_QUALITY_HIGH:
310 return VG_LITE_HIGH;
311 default:
312 return VG_LITE_MEDIUM;
313 }
314 }
315
lv_path_to_vg(lv_vg_lite_path_t * dest,const lv_vector_path_t * src)316 static void lv_path_to_vg(lv_vg_lite_path_t * dest, const lv_vector_path_t * src)
317 {
318 LV_PROFILER_DRAW_BEGIN;
319 lv_vg_lite_path_set_quality(dest, lv_quality_to_vg(src->quality));
320
321 /* init bounds */
322 float min_x = FLT_MAX;
323 float min_y = FLT_MAX;
324 float max_x = FLT_MIN;
325 float max_y = FLT_MIN;
326
327 #define CMP_BOUNDS(point) \
328 do { \
329 if((point)->x < min_x) min_x = (point)->x; \
330 if((point)->y < min_y) min_y = (point)->y; \
331 if((point)->x > max_x) max_x = (point)->x; \
332 if((point)->y > max_y) max_y = (point)->y; \
333 } while(0)
334
335 #define COPY_POINT_NEXT() \
336 do { \
337 CMP_BOUNDS(point); \
338 *path_data++ = point->x; \
339 *path_data++ = point->y; \
340 point++; \
341 } while(0)
342
343 const lv_vector_path_op_t * ops = lv_array_front(&src->ops);
344 const lv_fpoint_t * point = lv_array_front(&src->points);
345 const uint32_t op_size = lv_array_size(&src->ops);
346 const uint32_t point_size = lv_array_size(&src->points);
347 const uint32_t path_length = (op_size + point_size * 2) * sizeof(float);
348
349 /* Reserved memory for path data */
350 lv_vg_lite_path_reserve_space(dest, path_length);
351 vg_lite_path_t * vg_path = lv_vg_lite_path_get_path(dest);
352 vg_path->path_length = path_length;
353 float * path_data = vg_path->path;
354
355 for(uint32_t i = 0; i < op_size; i++) {
356 switch(ops[i]) {
357 case LV_VECTOR_PATH_OP_MOVE_TO: {
358 LV_VG_LITE_PATH_SET_OP_CODE(path_data++, uint32_t, VLC_OP_MOVE);
359 COPY_POINT_NEXT();
360 }
361 break;
362 case LV_VECTOR_PATH_OP_LINE_TO: {
363 LV_VG_LITE_PATH_SET_OP_CODE(path_data++, uint32_t, VLC_OP_LINE);
364 COPY_POINT_NEXT();
365 }
366 break;
367 case LV_VECTOR_PATH_OP_QUAD_TO: {
368 LV_VG_LITE_PATH_SET_OP_CODE(path_data++, uint32_t, VLC_OP_QUAD);
369 COPY_POINT_NEXT();
370 COPY_POINT_NEXT();
371 }
372 break;
373 case LV_VECTOR_PATH_OP_CUBIC_TO: {
374 LV_VG_LITE_PATH_SET_OP_CODE(path_data++, uint32_t, VLC_OP_CUBIC);
375 COPY_POINT_NEXT();
376 COPY_POINT_NEXT();
377 COPY_POINT_NEXT();
378 }
379 break;
380 case LV_VECTOR_PATH_OP_CLOSE: {
381 LV_VG_LITE_PATH_SET_OP_CODE(path_data++, uint32_t, VLC_OP_CLOSE);
382 }
383 break;
384 default:
385 LV_LOG_WARN("unknown op: %d", ops[i]);
386 break;
387 }
388 }
389
390 LV_ASSERT_MSG((lv_uintptr_t)path_data - (lv_uintptr_t)vg_path->path == path_length, "path length overflow");
391
392 lv_vg_lite_path_set_bounding_box(dest, min_x, min_y, max_x, max_y);
393 LV_PROFILER_DRAW_END;
394 }
395
lv_path_opa_to_path_type(const lv_vector_draw_dsc_t * dsc)396 static vg_lite_path_type_t lv_path_opa_to_path_type(const lv_vector_draw_dsc_t * dsc)
397 {
398 lv_opa_t fill_opa = dsc->fill_dsc.opa;
399 lv_opa_t stroke_opa = dsc->stroke_dsc.opa;
400
401 if(fill_opa > LV_OPA_0 && stroke_opa > LV_OPA_0) {
402 return VG_LITE_DRAW_FILL_STROKE_PATH;
403 }
404
405 if(fill_opa == LV_OPA_0 && stroke_opa > LV_OPA_0) {
406 return VG_LITE_DRAW_STROKE_PATH;
407 }
408
409 if(fill_opa > LV_OPA_0) {
410 return VG_LITE_DRAW_FILL_PATH;
411 }
412
413 return VG_LITE_DRAW_ZERO;
414 }
415
lv_blend_to_vg(lv_vector_blend_t blend)416 static vg_lite_blend_t lv_blend_to_vg(lv_vector_blend_t blend)
417 {
418 switch(blend) {
419 case LV_VECTOR_BLEND_SRC_OVER:
420 return VG_LITE_BLEND_SRC_OVER;
421 case LV_VECTOR_BLEND_SCREEN:
422 return VG_LITE_BLEND_SCREEN;
423 case LV_VECTOR_BLEND_MULTIPLY:
424 return VG_LITE_BLEND_MULTIPLY;
425 case LV_VECTOR_BLEND_NONE:
426 return VG_LITE_BLEND_NONE;
427 case LV_VECTOR_BLEND_ADDITIVE:
428 return VG_LITE_BLEND_ADDITIVE;
429 case LV_VECTOR_BLEND_SRC_IN:
430 return VG_LITE_BLEND_SRC_IN;
431 case LV_VECTOR_BLEND_DST_OVER:
432 return VG_LITE_BLEND_DST_OVER;
433 case LV_VECTOR_BLEND_DST_IN:
434 return VG_LITE_BLEND_DST_IN;
435 case LV_VECTOR_BLEND_SUBTRACTIVE:
436 return VG_LITE_BLEND_SUBTRACT;
437 default:
438 return VG_LITE_BLEND_SRC_OVER;
439 }
440 }
441
lv_fill_to_vg(lv_vector_fill_t fill_rule)442 static vg_lite_fill_t lv_fill_to_vg(lv_vector_fill_t fill_rule)
443 {
444 switch(fill_rule) {
445 case LV_VECTOR_FILL_NONZERO:
446 return VG_LITE_FILL_NON_ZERO;
447 case LV_VECTOR_FILL_EVENODD:
448 return VG_LITE_FILL_EVEN_ODD;
449 default:
450 return VG_LITE_FILL_NON_ZERO;
451 }
452 }
453
454 #endif /*LV_USE_DRAW_VG_LITE && LV_USE_VECTOR_GRAPHIC*/
455