1 /**
2  * @file lv_draw_vglite.c
3  *
4  */
5 
6 /**
7  * MIT License
8  *
9  * Copyright 2022, 2023 NXP
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights to
14  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
15  * the Software, and to permit persons to whom the Software is furnished to do so,
16  * subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice (including the next paragraph)
19  * shall be included in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
22  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
25  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
26  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  *
28  */
29 
30 /*********************
31  *      INCLUDES
32  *********************/
33 
34 #include "lv_draw_vglite.h"
35 
36 #if LV_USE_GPU_NXP_VG_LITE
37 #include <math.h>
38 #include "lv_draw_vglite_blend.h"
39 #include "lv_draw_vglite_line.h"
40 #include "lv_draw_vglite_rect.h"
41 #include "lv_draw_vglite_arc.h"
42 #include "lv_vglite_buf.h"
43 
44 #if LV_COLOR_DEPTH != 32
45     #include "../../../core/lv_refr.h"
46 #endif
47 
48 /*********************
49  *      DEFINES
50  *********************/
51 
52 /* Minimum area (in pixels) for VG-Lite blit/fill processing. */
53 #ifndef LV_GPU_NXP_VG_LITE_SIZE_LIMIT
54     #define LV_GPU_NXP_VG_LITE_SIZE_LIMIT 5000
55 #endif
56 
57 /**********************
58  *      TYPEDEFS
59  **********************/
60 
61 /**********************
62  *  STATIC PROTOTYPES
63  **********************/
64 
65 static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx);
66 
67 static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx);
68 
69 static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
70                                        const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf);
71 
72 static void lv_draw_vglite_buffer_copy(lv_draw_ctx_t * draw_ctx,
73                                        void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area,
74                                        void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area);
75 
76 static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
77 
78 static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
79                                 const lv_point_t * point2);
80 
81 static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
82 
83 static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
84 
85 static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
86                                       const lv_area_t * coords);
87 
88 static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
89                                        const lv_area_t * coords);
90 
91 static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
92                                uint16_t radius, uint16_t start_angle, uint16_t end_angle);
93 
94 /**********************
95  *  STATIC VARIABLES
96  **********************/
97 
98 /**********************
99  *      MACROS
100  **********************/
101 
102 /**********************
103  *   GLOBAL FUNCTIONS
104  **********************/
105 
lv_draw_vglite_ctx_init(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)106 void lv_draw_vglite_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
107 {
108     lv_draw_sw_init_ctx(drv, draw_ctx);
109 
110     lv_draw_vglite_ctx_t * vglite_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
111     vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf;
112     vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line;
113     vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc;
114     vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect;
115     vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded;
116     vglite_draw_ctx->blend = lv_draw_vglite_blend;
117     vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish;
118     vglite_draw_ctx->base_draw.buffer_copy = lv_draw_vglite_buffer_copy;
119 }
120 
lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)121 void lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
122 {
123     lv_draw_sw_deinit_ctx(drv, draw_ctx);
124 }
125 
126 /**********************
127  *   STATIC FUNCTIONS
128  **********************/
129 
130 /**
131  * During rendering, LVGL might initializes new draw_ctxs and start drawing into
132  * a separate buffer (called layer). If the content to be rendered has "holes",
133  * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag.
134  * It means the renderers should draw into an ARGB buffer.
135  * With 32 bit color depth it's not a big problem but with 16 bit color depth
136  * the target pixel format is ARGB8565 which is not supported by the GPU.
137  * In this case, the VG-Lite callbacks should fallback to SW rendering.
138  */
need_argb8565_support()139 static inline bool need_argb8565_support()
140 {
141 #if LV_COLOR_DEPTH != 32
142     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
143 
144     if(disp->driver->screen_transp == 1)
145         return true;
146 #endif
147 
148     return false;
149 }
150 
lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx)151 static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx)
152 {
153     lv_gpu_nxp_vglite_init_buf(draw_ctx->buf, draw_ctx->buf_area, lv_area_get_width(draw_ctx->buf_area));
154 }
155 
lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx)156 static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx)
157 {
158     vg_lite_finish();
159 
160     lv_draw_sw_wait_for_finish(draw_ctx);
161 }
162 
lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)163 static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
164 {
165     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
166         return;
167 
168     if(need_argb8565_support()) {
169         lv_draw_sw_blend_basic(draw_ctx, dsc);
170         return;
171     }
172 
173     lv_area_t blend_area;
174     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area))
175         return; /*Fully clipped, nothing to do*/
176 
177     lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
178 
179     bool done = false;
180     /*Fill/Blend only non masked, normal blended*/
181     if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL &&
182        lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT) {
183         const lv_color_t * src_buf = dsc->src_buf;
184 
185         if(src_buf == NULL) {
186             done = (lv_gpu_nxp_vglite_fill(&blend_area, dsc->color, dsc->opa) == LV_RES_OK);
187             if(!done)
188                 VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback.");
189         }
190         else {
191             lv_area_t src_area;
192             src_area.x1 = blend_area.x1 - (dsc->blend_area->x1 - draw_ctx->buf_area->x1);
193             src_area.y1 = blend_area.y1 - (dsc->blend_area->y1 - draw_ctx->buf_area->y1);
194             src_area.x2 = src_area.x1 + lv_area_get_width(dsc->blend_area) - 1;
195             src_area.y2 = src_area.y1 + lv_area_get_height(dsc->blend_area) - 1;
196             lv_coord_t src_stride = lv_area_get_width(dsc->blend_area);
197 
198 #if VG_LITE_BLIT_SPLIT_ENABLED
199             lv_color_t * dest_buf = draw_ctx->buf;
200             lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
201 
202             done = (lv_gpu_nxp_vglite_blit_split(dest_buf, &blend_area, dest_stride,
203                                                  src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK);
204 #else
205             done = (lv_gpu_nxp_vglite_blit(&blend_area, src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK);
206 #endif
207 
208             if(!done)
209                 VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback.");
210         }
211     }
212 
213     if(!done)
214         lv_draw_sw_blend_basic(draw_ctx, dsc);
215 }
216 
lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx,const lv_draw_img_dsc_t * dsc,const lv_area_t * coords,const uint8_t * map_p,lv_img_cf_t cf)217 static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
218                                        const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf)
219 {
220     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
221         return;
222 
223     if(need_argb8565_support()) {
224         lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
225         return;
226     }
227 
228     const lv_color_t * src_buf = (const lv_color_t *)map_p;
229     if(!src_buf) {
230         lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
231         return;
232     }
233 
234     lv_area_t rel_coords;
235     lv_area_copy(&rel_coords, coords);
236     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
237 
238     lv_area_t rel_clip_area;
239     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
240     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
241 
242     lv_area_t blend_area;
243     bool has_transform = dsc->angle != 0 || dsc->zoom != LV_IMG_ZOOM_NONE;
244 
245     if(has_transform)
246         lv_area_copy(&blend_area, &rel_coords);
247     else if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area))
248         return; /*Fully clipped, nothing to do*/
249 
250     bool has_mask = lv_draw_mask_is_any(&blend_area);
251     bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
252 
253     bool done = false;
254     if(!has_mask && !has_recolor && !lv_img_cf_is_chroma_keyed(cf) &&
255        lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT
256 #if LV_COLOR_DEPTH != 32
257        && !lv_img_cf_has_alpha(cf)
258 #endif
259       ) {
260         lv_area_t src_area;
261         src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1);
262         src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1);
263         src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1;
264         src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1;
265         lv_coord_t src_stride = lv_area_get_width(coords);
266 
267 #if VG_LITE_BLIT_SPLIT_ENABLED
268         lv_color_t * dest_buf = draw_ctx->buf;
269         lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
270 
271         if(has_transform)
272             /* VG-Lite blit split with transformation is not supported! */
273             done = false;
274         else
275             done = (lv_gpu_nxp_vglite_blit_split(dest_buf, &blend_area, dest_stride,
276                                                  src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK);
277 #else
278         if(has_transform)
279             done = (lv_gpu_nxp_vglite_blit_transform(&blend_area, &rel_clip_area,
280                                                      src_buf, &src_area, src_stride, dsc) == LV_RES_OK);
281         else
282             done = (lv_gpu_nxp_vglite_blit(&blend_area, src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK);
283 #endif
284 
285         if(!done)
286             VG_LITE_LOG_TRACE("VG-Lite blit %sfailed. Fallback.", has_transform ? "transform " : "");
287     }
288 
289     if(!done)
290         lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
291 }
292 
lv_draw_vglite_buffer_copy(lv_draw_ctx_t * draw_ctx,void * dest_buf,lv_coord_t dest_stride,const lv_area_t * dest_area,void * src_buf,lv_coord_t src_stride,const lv_area_t * src_area)293 static void lv_draw_vglite_buffer_copy(lv_draw_ctx_t * draw_ctx,
294                                        void * dest_buf, lv_coord_t dest_stride, const lv_area_t * dest_area,
295                                        void * src_buf, lv_coord_t src_stride, const lv_area_t * src_area)
296 {
297     bool done = false;
298 
299     if(lv_area_get_size(dest_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT) {
300         done = lv_gpu_nxp_vglite_buffer_copy(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride);
301         if(!done)
302             VG_LITE_LOG_TRACE("VG-Lite buffer copy failed. Fallback.");
303     }
304 
305     if(!done)
306         lv_draw_sw_buffer_copy(draw_ctx, dest_buf, dest_stride, dest_area, src_buf, src_stride, src_area);
307 }
308 
lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx,const lv_draw_line_dsc_t * dsc,const lv_point_t * point1,const lv_point_t * point2)309 static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
310                                 const lv_point_t * point2)
311 {
312     if(dsc->width == 0)
313         return;
314     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
315         return;
316     if(point1->x == point2->x && point1->y == point2->y)
317         return;
318 
319     if(need_argb8565_support()) {
320         lv_draw_sw_line(draw_ctx, dsc, point1, point2);
321         return;
322     }
323 
324     lv_area_t rel_clip_area;
325     rel_clip_area.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2;
326     rel_clip_area.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2;
327     rel_clip_area.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2;
328     rel_clip_area.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2;
329 
330     lv_area_t clipped_coords;
331     if(!_lv_area_intersect(&clipped_coords, &rel_clip_area, draw_ctx->clip_area))
332         return; /*Fully clipped, nothing to do*/
333 
334     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
335 
336     lv_point_t rel_point1 = { point1->x - draw_ctx->buf_area->x1, point1->y - draw_ctx->buf_area->y1 };
337     lv_point_t rel_point2 = { point2->x - draw_ctx->buf_area->x1, point2->y - draw_ctx->buf_area->y1 };
338 
339     bool done = false;
340     bool has_mask = lv_draw_mask_is_any(&rel_clip_area);
341 
342     if(!has_mask) {
343         done = (lv_gpu_nxp_vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc) == LV_RES_OK);
344         if(!done)
345             VG_LITE_LOG_TRACE("VG-Lite draw line failed. Fallback.");
346     }
347 
348     if(!done)
349         lv_draw_sw_line(draw_ctx, dsc, point1, point2);
350 }
351 
lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)352 static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
353 {
354     if(need_argb8565_support()) {
355         lv_draw_sw_rect(draw_ctx, dsc, coords);
356         return;
357     }
358 
359     lv_draw_rect_dsc_t vglite_dsc;
360 
361     lv_memcpy(&vglite_dsc, dsc, sizeof(vglite_dsc));
362     vglite_dsc.bg_opa = 0;
363     vglite_dsc.bg_img_opa = 0;
364     vglite_dsc.border_opa = 0;
365     vglite_dsc.outline_opa = 0;
366 #if LV_DRAW_COMPLEX
367     /* Draw the shadow with CPU */
368     lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
369     vglite_dsc.shadow_opa = 0;
370 #endif /*LV_DRAW_COMPLEX*/
371 
372     /* Draw the background */
373     vglite_dsc.bg_opa = dsc->bg_opa;
374     if(lv_draw_vglite_bg(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
375         lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
376     vglite_dsc.bg_opa = 0;
377 
378     /* Draw the background image
379      * It will be done once draw_ctx->draw_img_decoded()
380      * callback gets called from lv_draw_sw_rect().
381      */
382     vglite_dsc.bg_img_opa = dsc->bg_img_opa;
383     lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
384     vglite_dsc.bg_img_opa = 0;
385 
386     /* Draw the border */
387     vglite_dsc.border_opa = dsc->border_opa;
388     if(lv_draw_vglite_border(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
389         lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
390     vglite_dsc.border_opa = 0;
391 
392     /* Draw the outline */
393     vglite_dsc.outline_opa = dsc->outline_opa;
394     if(lv_draw_vglite_outline(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
395         lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
396 }
397 
lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)398 static lv_res_t lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
399 {
400     if(dsc->bg_opa <= (lv_opa_t)LV_OPA_MIN)
401         return LV_RES_INV;
402 
403     lv_area_t rel_coords;
404     lv_area_copy(&rel_coords, coords);
405 
406     /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
407     if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) {
408         rel_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
409         rel_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
410         rel_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
411         rel_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
412     }
413     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
414 
415     lv_area_t rel_clip_area;
416     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
417     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
418 
419     lv_area_t clipped_coords;
420     if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
421         return LV_RES_OK; /*Fully clipped, nothing to do*/
422 
423     bool has_mask = lv_draw_mask_is_any(&rel_coords);
424     lv_grad_dir_t grad_dir = dsc->bg_grad.dir;
425     lv_color_t bg_color = (grad_dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) ?
426                           dsc->bg_color : dsc->bg_grad.stops[0].color;
427     if(bg_color.full == dsc->bg_grad.stops[1].color.full)
428         grad_dir = LV_GRAD_DIR_NONE;
429 
430     /*
431      * Most simple case: just a plain rectangle (no mask, no radius, no gradient)
432      * shall be handled by draw_ctx->blend().
433      *
434      * Complex case: gradient or radius but no mask.
435      */
436     if(!has_mask && ((dsc->radius != 0) || (grad_dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))) {
437         lv_res_t res = lv_gpu_nxp_vglite_draw_bg(&rel_coords, &rel_clip_area, dsc);
438         if(res != LV_RES_OK)
439             VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback.");
440 
441         return res;
442     }
443 
444     return LV_RES_INV;
445 }
446 
lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)447 static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
448                                       const lv_area_t * coords)
449 {
450     if(dsc->border_opa <= (lv_opa_t)LV_OPA_MIN)
451         return LV_RES_INV;
452     if(dsc->border_width == 0)
453         return LV_RES_INV;
454     if(dsc->border_post)
455         return LV_RES_INV;
456     if(dsc->border_side != (lv_border_side_t)LV_BORDER_SIDE_FULL)
457         return LV_RES_INV;
458 
459     lv_area_t rel_coords;
460     lv_coord_t border_width = dsc->border_width;
461 
462     /* Move border inwards to align with software rendered border */
463     rel_coords.x1 = coords->x1 + ceil(border_width / 2.0f);
464     rel_coords.x2 = coords->x2 - floor(border_width / 2.0f);
465     rel_coords.y1 = coords->y1 + ceil(border_width / 2.0f);
466     rel_coords.y2 = coords->y2 - floor(border_width / 2.0f);
467 
468     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
469 
470     lv_area_t rel_clip_area;
471     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
472     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
473 
474     lv_area_t clipped_coords;
475     if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
476         return LV_RES_OK; /*Fully clipped, nothing to do*/
477 
478     lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, true);
479     if(res != LV_RES_OK)
480         VG_LITE_LOG_TRACE("VG-Lite draw border failed. Fallback.");
481 
482     return res;
483 }
484 
lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)485 static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
486                                        const lv_area_t * coords)
487 {
488     if(dsc->outline_opa <= (lv_opa_t)LV_OPA_MIN)
489         return LV_RES_INV;
490     if(dsc->outline_width == 0)
491         return LV_RES_INV;
492 
493     /* Move outline outwards to align with software rendered outline */
494     lv_coord_t outline_pad = dsc->outline_pad - 1;
495     lv_area_t rel_coords;
496     rel_coords.x1 = coords->x1 - outline_pad - floor(dsc->outline_width / 2.0f);
497     rel_coords.x2 = coords->x2 + outline_pad + ceil(dsc->outline_width / 2.0f);
498     rel_coords.y1 = coords->y1 - outline_pad - floor(dsc->outline_width / 2.0f);
499     rel_coords.y2 = coords->y2 + outline_pad + ceil(dsc->outline_width / 2.0f);
500 
501     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
502 
503     lv_area_t rel_clip_area;
504     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
505     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
506 
507     lv_area_t clipped_coords;
508     if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
509         return LV_RES_OK; /*Fully clipped, nothing to do*/
510 
511     lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, false);
512     if(res != LV_RES_OK)
513         VG_LITE_LOG_TRACE("VG-Lite draw outline failed. Fallback.");
514 
515     return res;
516 }
517 
lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx,const lv_draw_arc_dsc_t * dsc,const lv_point_t * center,uint16_t radius,uint16_t start_angle,uint16_t end_angle)518 static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
519                                uint16_t radius, uint16_t start_angle, uint16_t end_angle)
520 {
521     bool done = false;
522 
523 #if LV_DRAW_COMPLEX
524     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
525         return;
526     if(dsc->width == 0)
527         return;
528     if(start_angle == end_angle)
529         return;
530 
531     if(need_argb8565_support()) {
532         lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
533         return;
534     }
535 
536     lv_point_t rel_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1};
537 
538     lv_area_t rel_clip_area;
539     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
540     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
541 
542     bool has_mask = lv_draw_mask_is_any(&rel_clip_area);
543 
544     if(!has_mask) {
545         done = (lv_gpu_nxp_vglite_draw_arc(&rel_center, (int32_t)radius, (int32_t)start_angle, (int32_t)end_angle,
546                                            &rel_clip_area, dsc) == LV_RES_OK);
547         if(!done)
548             VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback.");
549     }
550 
551 #endif/*LV_DRAW_COMPLEX*/
552 
553     if(!done)
554         lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
555 }
556 
557 #endif /*LV_USE_GPU_NXP_VG_LITE*/
558