1 /**
2 * @file lv_draw_vglite_rect.c
3 *
4 */
5
6 /**
7 * MIT License
8 *
9 * Copyright 2021-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_rect.h"
35
36 #if LV_USE_GPU_NXP_VG_LITE
37 #include "lv_vglite_buf.h"
38 #include <math.h>
39
40 /*********************
41 * DEFINES
42 *********************/
43 /*********************
44 * DEFINES
45 *********************/
46
47 /* Path data sizes for different elements */
48 #define CUBIC_PATH_DATA_SIZE 7 /* 1 opcode, 6 arguments */
49 #define LINE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */
50 #define MOVE_PATH_DATA_SIZE 3 /* 1 opcode, 2 arguments */
51 #define END_PATH_DATA_SIZE 1 /* 1 opcode, 0 arguments */
52 /* Maximum possible rectangle path size
53 * is in the rounded rectangle case:
54 * - 1 move for the path start
55 * - 4 cubics for the corners
56 * - 4 lines for the sides
57 * - 1 end for the path end */
58 #define RECT_PATH_DATA_MAX_SIZE 1 * MOVE_PATH_DATA_SIZE + 4 * CUBIC_PATH_DATA_SIZE + 4 * LINE_PATH_DATA_SIZE + 1 * END_PATH_DATA_SIZE
59
60 /**********************
61 * TYPEDEFS
62 **********************/
63
64 /**********************
65 * STATIC PROTOTYPES
66 **********************/
67
68 /**
69 * Generates path data for rectangle drawing.
70 *
71 * @param[in/out] path The path data to initialize
72 * @param[in/out] path_size The resulting size of the created path data
73 * @param[in] dsc The style descriptor for the rectangle to be drawn
74 * @param[in] coords The coordinates of the rectangle to be drawn
75 */
76 static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
77 lv_coord_t radius,
78 const lv_area_t * coords);
79
80 /**********************
81 * STATIC VARIABLES
82 **********************/
83
84 /**********************
85 * MACROS
86 **********************/
87
88 /**********************
89 * GLOBAL FUNCTIONS
90 **********************/
91
lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords,const lv_area_t * clip_area,const lv_draw_rect_dsc_t * dsc)92 lv_res_t lv_gpu_nxp_vglite_draw_bg(const lv_area_t * coords, const lv_area_t * clip_area,
93 const lv_draw_rect_dsc_t * dsc)
94 {
95 vg_lite_error_t err = VG_LITE_SUCCESS;
96 lv_coord_t width = lv_area_get_width(coords);
97 lv_coord_t height = lv_area_get_height(coords);
98 vg_lite_color_t vgcol;
99 lv_coord_t radius = dsc->radius;
100 vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
101
102 if(dsc->radius < 0)
103 return LV_RES_INV;
104
105 /*** Init path ***/
106 int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
107 uint32_t path_data_size;
108 lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
109 vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW;
110
111 vg_lite_path_t path;
112 err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
113 (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
114 ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
115 VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
116
117 vg_lite_matrix_t matrix;
118 vg_lite_identity(&matrix);
119
120 vg_lite_matrix_t * grad_matrix;
121 vg_lite_linear_gradient_t gradient;
122
123 /*** Init Color/Gradient ***/
124 if(dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE) {
125 uint32_t colors[2];
126 uint32_t stops[2];
127 lv_color32_t col32[2];
128
129 /* Gradient setup */
130 uint8_t cnt = LV_MAX(dsc->bg_grad.stops_count, 2);
131 for(uint8_t i = 0; i < cnt; i++) {
132 col32[i].full = lv_color_to32(dsc->bg_grad.stops[i].color); /*Convert color to RGBA8888*/
133 stops[i] = dsc->bg_grad.stops[i].frac;
134
135 vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_ABGR8888 : VG_LITE_ARGB8888;
136 if(lv_vglite_premult_and_swizzle(&colors[i], col32[i], dsc->bg_opa, color_format) != LV_RES_OK)
137 VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
138 }
139
140 lv_memset_00(&gradient, sizeof(vg_lite_linear_gradient_t));
141
142 err = vg_lite_init_grad(&gradient);
143 VG_LITE_ERR_RETURN_INV(err, "Init gradient failed");
144
145 err = vg_lite_set_grad(&gradient, cnt, colors, stops);
146 VG_LITE_ERR_RETURN_INV(err, "Set gradient failed.");
147
148 err = vg_lite_update_grad(&gradient);
149 VG_LITE_ERR_RETURN_INV(err, "Update gradient failed.");
150
151 grad_matrix = vg_lite_get_grad_matrix(&gradient);
152 vg_lite_identity(grad_matrix);
153 vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix);
154
155 if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) {
156 vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix);
157 vg_lite_rotate(90.0f, grad_matrix);
158 }
159 else { /*LV_GRAD_DIR_HOR*/
160 vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix);
161 }
162 }
163
164 lv_color32_t bg_col32 = {.full = lv_color_to32(dsc->bg_color)}; /*Convert color to RGBA8888*/
165 vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
166 if(lv_vglite_premult_and_swizzle(&vgcol, bg_col32, dsc->bg_opa, color_format) != LV_RES_OK)
167 VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
168
169 lv_vglite_set_scissor(clip_area);
170
171 /*** Draw rectangle ***/
172 if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE) {
173 err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
174 }
175 else {
176 err = vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER);
177 }
178 VG_LITE_ERR_RETURN_INV(err, "Draw gradient failed.");
179
180 if(lv_vglite_run() != LV_RES_OK)
181 VG_LITE_RETURN_INV("Run failed.");
182
183 lv_vglite_disable_scissor();
184
185 err = vg_lite_clear_path(&path);
186 VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
187
188 if(dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE) {
189 err = vg_lite_clear_grad(&gradient);
190 VG_LITE_ERR_RETURN_INV(err, "Clear gradient failed.");
191 }
192
193 return LV_RES_OK;
194 }
195
lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords,const lv_area_t * clip_area,const lv_draw_rect_dsc_t * dsc,bool border)196 lv_res_t lv_gpu_nxp_vglite_draw_border_generic(const lv_area_t * coords, const lv_area_t * clip_area,
197 const lv_draw_rect_dsc_t * dsc, bool border)
198 {
199 vg_lite_error_t err = VG_LITE_SUCCESS;
200 vg_lite_color_t vgcol; /* vglite takes ABGR */
201 lv_coord_t radius = dsc->radius;
202 vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
203
204 if(radius < 0)
205 return LV_RES_INV;
206
207 if(border) {
208 /* Draw border - only has radius if object has radius*/
209 lv_coord_t border_half = (lv_coord_t)floor(dsc->border_width / 2.0f);
210 if(radius > border_half)
211 radius = radius - border_half;
212 }
213 else {
214 /* Draw outline - always has radius, leave the same radius in the circle case */
215 lv_coord_t outline_half = (lv_coord_t)ceil(dsc->outline_width / 2.0f);
216 if(radius < (lv_coord_t)LV_RADIUS_CIRCLE - outline_half)
217 radius = radius + outline_half;
218 }
219
220 vg_lite_cap_style_t cap_style = (radius) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT;
221 vg_lite_join_style_t join_style = (radius) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER;
222
223 /* Choose vglite blend mode based on given lvgl blend mode */
224 vg_lite_blend_t vglite_blend_mode = lv_vglite_get_blend_mode(dsc->blend_mode);
225
226 /*** Init path ***/
227 int32_t path_data[RECT_PATH_DATA_MAX_SIZE];
228 uint32_t path_data_size;
229 lv_vglite_create_rect_path_data(path_data, &path_data_size, radius, coords);
230 vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_LOW;
231
232 vg_lite_path_t path;
233 err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data,
234 (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1,
235 ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f);
236 VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
237
238 vg_lite_matrix_t matrix;
239 vg_lite_identity(&matrix);
240
241 lv_opa_t opa;
242 lv_color32_t col32;
243 lv_coord_t line_width;
244
245 if(border) {
246 opa = dsc->border_opa;
247 col32.full = lv_color_to32(dsc->border_color); /*Convert color to RGBA8888*/
248 line_width = dsc->border_width;
249 }
250 else {
251 opa = dsc->outline_opa;
252 col32.full = lv_color_to32(dsc->outline_color); /*Convert color to RGBA8888*/
253 line_width = dsc->outline_width;
254 }
255
256 vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
257 if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK)
258 VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
259
260 /*** Draw border ***/
261 err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH);
262 VG_LITE_ERR_RETURN_INV(err, "Set draw path type failed.");
263
264 err = vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol);
265 VG_LITE_ERR_RETURN_INV(err, "Set stroke failed.");
266
267 err = vg_lite_update_stroke(&path);
268 VG_LITE_ERR_RETURN_INV(err, "Update stroke failed.");
269
270 lv_vglite_set_scissor(clip_area);
271
272 err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol);
273 VG_LITE_ERR_RETURN_INV(err, "Draw border failed.");
274
275 if(lv_vglite_run() != LV_RES_OK)
276 VG_LITE_RETURN_INV("Run failed.");
277
278 lv_vglite_disable_scissor();
279
280 err = vg_lite_clear_path(&path);
281 VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
282
283 return LV_RES_OK;
284
285 }
286
287 /**********************
288 * STATIC FUNCTIONS
289 **********************/
290
lv_vglite_create_rect_path_data(int32_t * path_data,uint32_t * path_data_size,lv_coord_t radius,const lv_area_t * coords)291 static void lv_vglite_create_rect_path_data(int32_t * path_data, uint32_t * path_data_size,
292 lv_coord_t radius,
293 const lv_area_t * coords)
294 {
295 lv_coord_t rect_width = lv_area_get_width(coords);
296 lv_coord_t rect_height = lv_area_get_height(coords);
297
298 /* Get the final radius. Can't be larger than the half of the shortest side */
299 int32_t shortest_side = LV_MIN(rect_width, rect_height);
300 int32_t final_radius = LV_MIN(radius, shortest_side / 2);
301
302 /* Path data element index */
303 uint8_t pidx = 0;
304
305 if((radius == (lv_coord_t)LV_RADIUS_CIRCLE) && (rect_width == rect_height)) {
306
307 /* Get the control point offset for rounded cases */
308 int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE);
309
310 /* Circle case */
311 /* Starting point */
312 path_data[pidx++] = VLC_OP_MOVE;
313 path_data[pidx++] = coords->x1 + final_radius;
314 path_data[pidx++] = coords->y1;
315
316 /* Top-right arc */
317 path_data[pidx++] = VLC_OP_CUBIC_REL;
318 path_data[pidx++] = cpoff;
319 path_data[pidx++] = 0;
320 path_data[pidx++] = final_radius;
321 path_data[pidx++] = final_radius - cpoff;
322 path_data[pidx++] = final_radius;
323 path_data[pidx++] = final_radius;
324
325 /* Bottom-right arc*/
326 path_data[pidx++] = VLC_OP_CUBIC_REL;
327 path_data[pidx++] = 0;
328 path_data[pidx++] = cpoff;
329 path_data[pidx++] = cpoff - final_radius;
330 path_data[pidx++] = final_radius;
331 path_data[pidx++] = 0 - final_radius;
332 path_data[pidx++] = final_radius;
333
334 /* Bottom-left arc */
335 path_data[pidx++] = VLC_OP_CUBIC_REL;
336 path_data[pidx++] = 0 - cpoff;
337 path_data[pidx++] = 0;
338 path_data[pidx++] = 0 - final_radius;
339 path_data[pidx++] = cpoff - final_radius;
340 path_data[pidx++] = 0 - final_radius;
341 path_data[pidx++] = 0 - final_radius;
342
343 /* Top-left arc*/
344 path_data[pidx++] = VLC_OP_CUBIC_REL;
345 path_data[pidx++] = 0;
346 path_data[pidx++] = 0 - cpoff;
347 path_data[pidx++] = final_radius - cpoff;
348 path_data[pidx++] = 0 - final_radius;
349 path_data[pidx++] = final_radius;
350 path_data[pidx++] = 0 - final_radius;
351
352 /* Ending point */
353 path_data[pidx++] = VLC_OP_END;
354 }
355 else if(radius > 0) {
356 /* Get the control point offset for rounded cases */
357 int32_t cpoff = (int32_t)((float)final_radius * BEZIER_OPTIM_CIRCLE);
358
359 /* Rounded rectangle case */
360 /* Starting point */
361 path_data[pidx++] = VLC_OP_MOVE;
362 path_data[pidx++] = coords->x1 + final_radius;
363 path_data[pidx++] = coords->y1;
364
365 /* Top side */
366 path_data[pidx++] = VLC_OP_LINE;
367 path_data[pidx++] = coords->x2 - final_radius + 1; // Extended for VGLite
368 path_data[pidx++] = coords->y1;
369
370 /* Top-right corner */
371 path_data[pidx++] = VLC_OP_CUBIC_REL;
372 path_data[pidx++] = cpoff;
373 path_data[pidx++] = 0;
374 path_data[pidx++] = final_radius;
375 path_data[pidx++] = final_radius - cpoff;
376 path_data[pidx++] = final_radius;
377 path_data[pidx++] = final_radius;
378
379 /* Right side */
380 path_data[pidx++] = VLC_OP_LINE;
381 path_data[pidx++] = coords->x2 + 1; // Extended for VGLite
382 path_data[pidx++] = coords->y2 - final_radius + 1; // Extended for VGLite
383
384 /* Bottom-right corner*/
385 path_data[pidx++] = VLC_OP_CUBIC_REL;
386 path_data[pidx++] = 0;
387 path_data[pidx++] = cpoff;
388 path_data[pidx++] = cpoff - final_radius;
389 path_data[pidx++] = final_radius;
390 path_data[pidx++] = 0 - final_radius;
391 path_data[pidx++] = final_radius;
392
393 /* Bottom side */
394 path_data[pidx++] = VLC_OP_LINE;
395 path_data[pidx++] = coords->x1 + final_radius;
396 path_data[pidx++] = coords->y2 + 1; // Extended for VGLite
397
398 /* Bottom-left corner */
399 path_data[pidx++] = VLC_OP_CUBIC_REL;
400 path_data[pidx++] = 0 - cpoff;
401 path_data[pidx++] = 0;
402 path_data[pidx++] = 0 - final_radius;
403 path_data[pidx++] = cpoff - final_radius;
404 path_data[pidx++] = 0 - final_radius;
405 path_data[pidx++] = 0 - final_radius;
406
407 /* Left side*/
408 path_data[pidx++] = VLC_OP_LINE;
409 path_data[pidx++] = coords->x1;
410 path_data[pidx++] = coords->y1 + final_radius;
411
412 /* Top-left corner */
413 path_data[pidx++] = VLC_OP_CUBIC_REL;
414 path_data[pidx++] = 0;
415 path_data[pidx++] = 0 - cpoff;
416 path_data[pidx++] = final_radius - cpoff;
417 path_data[pidx++] = 0 - final_radius;
418 path_data[pidx++] = final_radius;
419 path_data[pidx++] = 0 - final_radius;
420
421 /* Ending point */
422 path_data[pidx++] = VLC_OP_END;
423 }
424 else {
425 /* Non-rounded rectangle case */
426 /* Starting point */
427 path_data[pidx++] = VLC_OP_MOVE;
428 path_data[pidx++] = coords->x1;
429 path_data[pidx++] = coords->y1;
430
431 /* Top side */
432 path_data[pidx++] = VLC_OP_LINE;
433 path_data[pidx++] = coords->x2 + 1; // Extended for VGLite
434 path_data[pidx++] = coords->y1;
435
436 /* Right side */
437 path_data[pidx++] = VLC_OP_LINE;
438 path_data[pidx++] = coords->x2 + 1; // Extended for VGLite
439 path_data[pidx++] = coords->y2 + 1; // Extended for VGLite
440
441 /* Bottom side */
442 path_data[pidx++] = VLC_OP_LINE;
443 path_data[pidx++] = coords->x1;
444 path_data[pidx++] = coords->y2 + 1; // Extended for VGLite
445
446 /* Left side*/
447 path_data[pidx++] = VLC_OP_LINE;
448 path_data[pidx++] = coords->x1;
449 path_data[pidx++] = coords->y1;
450
451 /* Ending point */
452 path_data[pidx++] = VLC_OP_END;
453 }
454
455 /* Resulting path size */
456 *path_data_size = pidx * sizeof(int32_t);
457 }
458
459 #endif /*LV_USE_GPU_NXP_VG_LITE*/
460