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_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc);
73 
74 static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
75                                 const lv_point_t * point2);
76 
77 static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords);
78 
79 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);
80 
81 static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
82                                       const lv_area_t * coords);
83 
84 static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
85                                        const lv_area_t * coords);
86 
87 static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
88                                uint16_t radius, uint16_t start_angle, uint16_t end_angle);
89 
90 /**********************
91  *  STATIC VARIABLES
92  **********************/
93 
94 /**********************
95  *      MACROS
96  **********************/
97 
98 /**********************
99  *   GLOBAL FUNCTIONS
100  **********************/
101 
lv_draw_vglite_ctx_init(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)102 void lv_draw_vglite_ctx_init(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
103 {
104     lv_draw_sw_init_ctx(drv, draw_ctx);
105 
106     lv_draw_vglite_ctx_t * vglite_draw_ctx = (lv_draw_sw_ctx_t *)draw_ctx;
107     vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf;
108     vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line;
109     vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc;
110     vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect;
111     vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded;
112     vglite_draw_ctx->blend = lv_draw_vglite_blend;
113     vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish;
114 }
115 
lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv,lv_draw_ctx_t * draw_ctx)116 void lv_draw_vglite_ctx_deinit(lv_disp_drv_t * drv, lv_draw_ctx_t * draw_ctx)
117 {
118     lv_draw_sw_deinit_ctx(drv, draw_ctx);
119 }
120 
121 /**********************
122  *   STATIC FUNCTIONS
123  **********************/
124 
125 /**
126  * During rendering, LVGL might initializes new draw_ctxs and start drawing into
127  * a separate buffer (called layer). If the content to be rendered has "holes",
128  * e.g. rounded corner, LVGL temporarily sets the disp_drv.screen_transp flag.
129  * It means the renderers should draw into an ARGB buffer.
130  * With 32 bit color depth it's not a big problem but with 16 bit color depth
131  * the target pixel format is ARGB8565 which is not supported by the GPU.
132  * In this case, the VG-Lite callbacks should fallback to SW rendering.
133  */
need_argb8565_support()134 static inline bool need_argb8565_support()
135 {
136 #if LV_COLOR_DEPTH != 32
137     lv_disp_t * disp = _lv_refr_get_disp_refreshing();
138 
139     if(disp->driver->screen_transp == 1)
140         return true;
141 #endif
142 
143     return false;
144 }
145 
lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx)146 static void lv_draw_vglite_init_buf(lv_draw_ctx_t * draw_ctx)
147 {
148     lv_gpu_nxp_vglite_init_buf(draw_ctx->buf, draw_ctx->buf_area, lv_area_get_width(draw_ctx->buf_area));
149 }
150 
lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx)151 static void lv_draw_vglite_wait_for_finish(lv_draw_ctx_t * draw_ctx)
152 {
153     vg_lite_finish();
154 
155     lv_draw_sw_wait_for_finish(draw_ctx);
156 }
157 
lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx,const lv_draw_sw_blend_dsc_t * dsc)158 static void lv_draw_vglite_blend(lv_draw_ctx_t * draw_ctx, const lv_draw_sw_blend_dsc_t * dsc)
159 {
160     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
161         return;
162 
163     if(need_argb8565_support()) {
164         lv_draw_sw_blend_basic(draw_ctx, dsc);
165         return;
166     }
167 
168     lv_area_t blend_area;
169     /*Let's get the blend area which is the intersection of the area to draw and the clip area*/
170     if(!_lv_area_intersect(&blend_area, dsc->blend_area, draw_ctx->clip_area))
171         return; /*Fully clipped, nothing to do*/
172 
173     /*Make the blend area relative to the buffer*/
174     lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
175 
176     bool done = false;
177     /*Fill/Blend only non masked, normal blended*/
178     if(dsc->mask_buf == NULL && dsc->blend_mode == LV_BLEND_MODE_NORMAL &&
179        lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT) {
180         const lv_color_t * src_buf = dsc->src_buf;
181 
182         if(src_buf == NULL) {
183             done = (lv_gpu_nxp_vglite_fill(&blend_area, dsc->color, dsc->opa) == LV_RES_OK);
184             if(!done)
185                 VG_LITE_LOG_TRACE("VG-Lite fill failed. Fallback.");
186         }
187         else {
188             lv_color_t * dest_buf = draw_ctx->buf;
189             lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
190 
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             done = (lv_gpu_nxp_vglite_blit(dest_buf, &blend_area, dest_stride,
199                                            src_buf, &src_area, src_stride, dsc->opa) == LV_RES_OK);
200 
201             if(!done)
202                 VG_LITE_LOG_TRACE("VG-Lite blit failed. Fallback.");
203         }
204     }
205 
206     if(!done)
207         lv_draw_sw_blend_basic(draw_ctx, dsc);
208 }
209 
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)210 static void lv_draw_vglite_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
211                                        const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t cf)
212 {
213     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
214         return;
215 
216     if(need_argb8565_support()) {
217         lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
218         return;
219     }
220 
221     const lv_color_t * src_buf = (const lv_color_t *)map_p;
222     if(!src_buf) {
223         lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
224         return;
225     }
226 
227     lv_area_t blend_area;
228     /*Let's get the blend area which is the intersection of the area to draw and the clip area*/
229     if(!_lv_area_intersect(&blend_area, coords, draw_ctx->clip_area))
230         return; /*Fully clipped, nothing to do*/
231 
232     /*Make the blend area relative to the buffer*/
233     lv_area_move(&blend_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
234 
235     bool has_mask = lv_draw_mask_is_any(&blend_area);
236     bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP);
237 
238     bool done = false;
239     if(!has_mask && !has_recolor && !lv_img_cf_is_chroma_keyed(cf) &&
240        lv_area_get_size(&blend_area) >= LV_GPU_NXP_VG_LITE_SIZE_LIMIT
241 #if LV_COLOR_DEPTH != 32
242        && !lv_img_cf_has_alpha(cf)
243 #endif
244       ) {
245         lv_color_t * dest_buf = draw_ctx->buf;
246         lv_coord_t dest_stride = lv_area_get_width(draw_ctx->buf_area);
247 
248         lv_area_t src_area;
249         src_area.x1 = blend_area.x1 - (coords->x1 - draw_ctx->buf_area->x1);
250         src_area.y1 = blend_area.y1 - (coords->y1 - draw_ctx->buf_area->y1);
251         src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1;
252         src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1;
253         lv_coord_t src_stride = lv_area_get_width(coords);
254 
255         done = (lv_gpu_nxp_vglite_blit_transform(dest_buf, &blend_area, dest_stride,
256                                                  src_buf, &src_area, src_stride, dsc) == LV_RES_OK);
257 
258         if(!done)
259             VG_LITE_LOG_TRACE("VG-Lite blit transform failed. Fallback.");
260     }
261 
262     if(!done)
263         lv_draw_sw_img_decoded(draw_ctx, dsc, coords, map_p, cf);
264 }
265 
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)266 static void lv_draw_vglite_line(lv_draw_ctx_t * draw_ctx, const lv_draw_line_dsc_t * dsc, const lv_point_t * point1,
267                                 const lv_point_t * point2)
268 {
269     if(dsc->width == 0)
270         return;
271     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
272         return;
273     if(point1->x == point2->x && point1->y == point2->y)
274         return;
275 
276     if(need_argb8565_support()) {
277         lv_draw_sw_line(draw_ctx, dsc, point1, point2);
278         return;
279     }
280 
281     lv_area_t rel_clip_area;
282     rel_clip_area.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2;
283     rel_clip_area.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2;
284     rel_clip_area.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2;
285     rel_clip_area.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2;
286 
287     bool is_common;
288     is_common = _lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_ctx->clip_area);
289     if(!is_common)
290         return;
291 
292     /* Make coordinates relative to the draw buffer */
293     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
294 
295     lv_point_t rel_point1 = { point1->x - draw_ctx->buf_area->x1, point1->y - draw_ctx->buf_area->y1 };
296     lv_point_t rel_point2 = { point2->x - draw_ctx->buf_area->x1, point2->y - draw_ctx->buf_area->y1 };
297 
298     bool done = false;
299     bool mask_any = lv_draw_mask_is_any(&rel_clip_area);
300 
301     if(!mask_any) {
302         done = (lv_gpu_nxp_vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc) == LV_RES_OK);
303         if(!done)
304             VG_LITE_LOG_TRACE("VG-Lite draw line failed. Fallback.");
305     }
306 
307     if(!done)
308         lv_draw_sw_line(draw_ctx, dsc, point1, point2);
309 }
310 
lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)311 static void lv_draw_vglite_rect(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, const lv_area_t * coords)
312 {
313     if(need_argb8565_support()) {
314         lv_draw_sw_rect(draw_ctx, dsc, coords);
315         return;
316     }
317 
318     lv_draw_rect_dsc_t vglite_dsc;
319 
320     lv_memcpy(&vglite_dsc, dsc, sizeof(vglite_dsc));
321     vglite_dsc.bg_opa = 0;
322     vglite_dsc.bg_img_opa = 0;
323     vglite_dsc.border_opa = 0;
324     vglite_dsc.outline_opa = 0;
325 #if LV_DRAW_COMPLEX
326     /* Draw the shadow with CPU */
327     lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
328     vglite_dsc.shadow_opa = 0;
329 #endif /*LV_DRAW_COMPLEX*/
330 
331     /* Draw the background */
332     vglite_dsc.bg_opa = dsc->bg_opa;
333     if(lv_draw_vglite_bg(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
334         lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
335     vglite_dsc.bg_opa = 0;
336 
337     /* Draw the background image
338      * It will be done once draw_ctx->draw_img_decoded()
339      * callback gets called from lv_draw_sw_rect().
340      */
341     vglite_dsc.bg_img_opa = dsc->bg_img_opa;
342     lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
343     vglite_dsc.bg_img_opa = 0;
344 
345     /* Draw the border */
346     vglite_dsc.border_opa = dsc->border_opa;
347     if(lv_draw_vglite_border(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
348         lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
349     vglite_dsc.border_opa = 0;
350 
351     /* Draw the outline */
352     vglite_dsc.outline_opa = dsc->outline_opa;
353     if(lv_draw_vglite_outline(draw_ctx, &vglite_dsc, coords) != LV_RES_OK)
354         lv_draw_sw_rect(draw_ctx, &vglite_dsc, coords);
355 }
356 
lv_draw_vglite_bg(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)357 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)
358 {
359     if(dsc->bg_opa <= (lv_opa_t)LV_OPA_MIN)
360         return LV_RES_INV;
361 
362     lv_area_t rel_coords;
363     lv_area_copy(&rel_coords, coords);
364 
365     /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/
366     if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) {
367         rel_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0;
368         rel_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0;
369         rel_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0;
370         rel_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0;
371     }
372 
373     /* Make coordinates relative to draw buffer */
374     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
375 
376     lv_area_t rel_clip_area;
377     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
378     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
379 
380     lv_area_t clipped_coords;
381     if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area))
382         return LV_RES_INV;
383 
384     bool mask_any = lv_draw_mask_is_any(&rel_coords);
385     lv_grad_dir_t grad_dir = dsc->bg_grad.dir;
386     lv_color_t bg_color = (grad_dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) ?
387                           dsc->bg_color : dsc->bg_grad.stops[0].color;
388     if(bg_color.full == dsc->bg_grad.stops[1].color.full)
389         grad_dir = LV_GRAD_DIR_NONE;
390 
391     /*
392      * Most simple case: just a plain rectangle (no mask, no radius, no gradient)
393      * shall be handled by draw_ctx->blend().
394      *
395      * Complex case: gradient or radius but no mask.
396      */
397     if(!mask_any && ((dsc->radius != 0) || (grad_dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE))) {
398         lv_res_t res = lv_gpu_nxp_vglite_draw_bg(&rel_coords, &rel_clip_area, dsc);
399         if(res != LV_RES_OK)
400             VG_LITE_LOG_TRACE("VG-Lite draw bg failed. Fallback.");
401 
402         return res;
403     }
404 
405     return LV_RES_INV;
406 }
407 
lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)408 static lv_res_t lv_draw_vglite_border(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
409                                       const lv_area_t * coords)
410 {
411     if(dsc->border_opa <= (lv_opa_t)LV_OPA_MIN)
412         return LV_RES_INV;
413     if(dsc->border_width == 0)
414         return LV_RES_INV;
415     if(dsc->border_post)
416         return LV_RES_INV;
417     if(dsc->border_side != (lv_border_side_t)LV_BORDER_SIDE_FULL)
418         return LV_RES_INV;
419 
420     lv_area_t rel_coords;
421     lv_coord_t border_width = dsc->border_width;
422 
423     /* Move border inwards to align with software rendered border */
424     rel_coords.x1 = coords->x1 + ceil(border_width / 2.0f);
425     rel_coords.x2 = coords->x2 - floor(border_width / 2.0f);
426     rel_coords.y1 = coords->y1 + ceil(border_width / 2.0f);
427     rel_coords.y2 = coords->y2 - floor(border_width / 2.0f);
428 
429     /* Make coordinates relative to the draw buffer */
430     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
431 
432     lv_area_t rel_clip_area;
433     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
434     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
435 
436     lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, true);
437     if(res != LV_RES_OK)
438         VG_LITE_LOG_TRACE("VG-Lite draw border failed. Fallback.");
439 
440     return res;
441 }
442 
lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx,const lv_draw_rect_dsc_t * dsc,const lv_area_t * coords)443 static lv_res_t lv_draw_vglite_outline(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc,
444                                        const lv_area_t * coords)
445 {
446     if(dsc->outline_opa <= (lv_opa_t)LV_OPA_MIN)
447         return LV_RES_INV;
448     if(dsc->outline_width == 0)
449         return LV_RES_INV;
450 
451     /* Move outline outwards to align with software rendered outline */
452     lv_coord_t outline_pad = dsc->outline_pad - 1;
453     lv_area_t rel_coords;
454     rel_coords.x1 = coords->x1 - outline_pad - floor(dsc->outline_width / 2.0f);
455     rel_coords.x2 = coords->x2 + outline_pad + ceil(dsc->outline_width / 2.0f);
456     rel_coords.y1 = coords->y1 - outline_pad - floor(dsc->outline_width / 2.0f);
457     rel_coords.y2 = coords->y2 + outline_pad + ceil(dsc->outline_width / 2.0f);
458 
459     /* Make coordinates relative to the draw buffer */
460     lv_area_move(&rel_coords, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
461 
462     lv_area_t rel_clip_area;
463     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
464     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
465 
466     lv_res_t res = lv_gpu_nxp_vglite_draw_border_generic(&rel_coords, &rel_clip_area, dsc, false);
467     if(res != LV_RES_OK)
468         VG_LITE_LOG_TRACE("VG-Lite draw outline failed. Fallback.");
469 
470     return res;
471 }
472 
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)473 static void lv_draw_vglite_arc(lv_draw_ctx_t * draw_ctx, const lv_draw_arc_dsc_t * dsc, const lv_point_t * center,
474                                uint16_t radius, uint16_t start_angle, uint16_t end_angle)
475 {
476     bool done = false;
477 
478 #if LV_DRAW_COMPLEX
479     if(dsc->opa <= (lv_opa_t)LV_OPA_MIN)
480         return;
481     if(dsc->width == 0)
482         return;
483     if(start_angle == end_angle)
484         return;
485 
486     if(need_argb8565_support()) {
487         lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
488         return;
489     }
490 
491     /* Make coordinates relative to the draw buffer */
492     lv_point_t rel_center = {center->x - draw_ctx->buf_area->x1, center->y - draw_ctx->buf_area->y1};
493 
494     lv_area_t rel_clip_area;
495     lv_area_copy(&rel_clip_area, draw_ctx->clip_area);
496     lv_area_move(&rel_clip_area, -draw_ctx->buf_area->x1, -draw_ctx->buf_area->y1);
497 
498     done = (lv_gpu_nxp_vglite_draw_arc(&rel_center, (int32_t)radius, (int32_t)start_angle, (int32_t)end_angle,
499                                        &rel_clip_area, dsc) == LV_RES_OK);
500     if(!done)
501         VG_LITE_LOG_TRACE("VG-Lite draw arc failed. Fallback.");
502 #endif/*LV_DRAW_COMPLEX*/
503 
504     if(!done)
505         lv_draw_sw_arc(draw_ctx, dsc, center, radius, start_angle, end_angle);
506 }
507 
508 #endif /*LV_USE_GPU_NXP_VG_LITE*/
509