1 /**
2 * @file lv_draw_vglite_blend.c
3 *
4 */
5
6 /**
7 * MIT License
8 *
9 * Copyright 2020-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_blend.h"
35
36 #if LV_USE_GPU_NXP_VG_LITE
37 #include "lv_vglite_buf.h"
38 #include "lv_vglite_utils.h"
39
40 /*********************
41 * DEFINES
42 *********************/
43
44 /** Stride in px required by VG-Lite HW*/
45 #define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U
46
47 #if VG_LITE_BLIT_SPLIT_ENABLED
48 /**
49 * BLIT split threshold - BLITs with width or height higher than this value will be done
50 * in multiple steps. Value must be 16-aligned. Don't change.
51 */
52 #define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352
53 #endif
54
55 /**********************
56 * TYPEDEFS
57 **********************/
58
59 /**********************
60 * STATIC PROTOTYPES
61 **********************/
62
63 /**
64 * Blit image, with optional opacity.
65 *
66 * @param[in] src_area Source area with relative coordinates of source buffer
67 * @param[in] opa Opacity
68 *
69 * @retval LV_RES_OK Transfer complete
70 * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
71 */
72 static lv_res_t lv_vglite_blit(const lv_area_t * src_area, lv_opa_t opa);
73
74 /**
75 * Check source memory and stride alignment.
76 *
77 * @param[in] src_buf Source buffer
78 * @param[in] src_stride Stride of source buffer in pixels
79 *
80 * @retval LV_RES_OK Alignment OK
81 * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
82 */
83 static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride);
84
85 /**
86 * Creates matrix that translates to origin of given destination area.
87 *
88 * @param[in] dest_area Area with relative coordinates of destination buffer
89 */
90 static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area);
91
92 /**
93 * Creates matrix that translates to origin of given destination area with transformation (scale or rotate).
94 *
95 * @param[in] dest_area Area with relative coordinates of destination buffer
96 * @param[in] dsc Image descriptor
97 */
98 static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc);
99
100 #if VG_LITE_BLIT_SPLIT_ENABLED
101 /**
102 * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only.
103 *
104 * @param[in/out] area Area to be updated
105 * @param[in/out] buf Pointer to be updated
106 */
107 static void align_x(lv_area_t * area, lv_color_t ** buf);
108
109 /**
110 * Move buffer pointer to the area start and update variables, Y-axis only.
111 *
112 * @param[in/out] area Area to be updated
113 * @param[in/out] buf Pointer to be updated
114 * @param[in] stride Buffer stride in pixels
115 */
116 static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride);
117
118 /**
119 * Blit image split in tiles, with optional opacity.
120 *
121 * @param[in/out] dest_buf Destination buffer
122 * @param[in] dest_area Area with relative coordinates of destination buffer
123 * @param[in] dest_stride Stride of destination buffer in pixels
124 * @param[in] src_buf Source buffer
125 * @param[in] src_area Source area with relative coordinates of source buffer
126 * @param[in] src_stride Stride of source buffer in pixels
127 * @param[in] opa Opacity
128 *
129 * @retval LV_RES_OK Transfer complete
130 * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
131 */
132 static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
133 const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
134 lv_opa_t opa);
135 #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/
136
137 /**********************
138 * STATIC VARIABLES
139 **********************/
140
141 static vg_lite_matrix_t vgmatrix;
142
143 /**********************
144 * MACROS
145 **********************/
146
147 /**********************
148 * GLOBAL FUNCTIONS
149 **********************/
150
lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area,lv_color_t color,lv_opa_t opa)151 lv_res_t lv_gpu_nxp_vglite_fill(const lv_area_t * dest_area, lv_color_t color, lv_opa_t opa)
152 {
153 vg_lite_error_t err = VG_LITE_SUCCESS;
154 lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/
155 vg_lite_color_t vgcol; /* vglite takes ABGR */
156 vg_lite_buffer_t * vgbuf = lv_vglite_get_dest_buf();
157
158 vg_lite_buffer_format_t color_format = LV_COLOR_DEPTH == 16 ? VG_LITE_BGRA8888 : VG_LITE_ABGR8888;
159 if(lv_vglite_premult_and_swizzle(&vgcol, col32, opa, color_format) != LV_RES_OK)
160 VG_LITE_RETURN_INV("Premultiplication and swizzle failed.");
161
162 if(opa >= (lv_opa_t)LV_OPA_MAX) { /*Opaque fill*/
163 vg_lite_rectangle_t rect = {
164 .x = dest_area->x1,
165 .y = dest_area->y1,
166 .width = lv_area_get_width(dest_area),
167 .height = lv_area_get_height(dest_area)
168 };
169
170 err = vg_lite_clear(vgbuf, &rect, vgcol);
171 VG_LITE_ERR_RETURN_INV(err, "Clear failed.");
172
173 if(lv_vglite_run() != LV_RES_OK)
174 VG_LITE_RETURN_INV("Run failed.");
175 }
176 else { /*fill with transparency*/
177
178 vg_lite_path_t path;
179 int32_t path_data[] = { /*VG rectangular path*/
180 VLC_OP_MOVE, dest_area->x1, dest_area->y1,
181 VLC_OP_LINE, dest_area->x2 + 1, dest_area->y1,
182 VLC_OP_LINE, dest_area->x2 + 1, dest_area->y2 + 1,
183 VLC_OP_LINE, dest_area->x1, dest_area->y2 + 1,
184 VLC_OP_LINE, dest_area->x1, dest_area->y1,
185 VLC_OP_END
186 };
187
188 err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_LOW, sizeof(path_data), path_data,
189 (vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1,
190 ((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f);
191 VG_LITE_ERR_RETURN_INV(err, "Init path failed.");
192
193 vg_lite_matrix_t matrix;
194 vg_lite_identity(&matrix);
195
196 /*Draw rectangle*/
197 err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol);
198 VG_LITE_ERR_RETURN_INV(err, "Draw rectangle failed.");
199
200 if(lv_vglite_run() != LV_RES_OK)
201 VG_LITE_RETURN_INV("Run failed.");
202
203 err = vg_lite_clear_path(&path);
204 VG_LITE_ERR_RETURN_INV(err, "Clear path failed.");
205 }
206
207 return LV_RES_OK;
208 }
209
210 #if VG_LITE_BLIT_SPLIT_ENABLED
lv_gpu_nxp_vglite_blit_split(lv_color_t * dest_buf,lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_area_t * src_area,lv_coord_t src_stride,lv_opa_t opa)211 lv_res_t lv_gpu_nxp_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
212 const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
213 lv_opa_t opa)
214 {
215 /* Set src_vgbuf structure. */
216 lv_vglite_set_src_buf(src_buf, src_area, src_stride);
217
218 lv_color_t * orig_dest_buf = dest_buf;
219
220 lv_res_t rv = lv_vglite_blit_split(dest_buf, dest_area, dest_stride, src_buf, src_area, src_stride, opa);
221
222 /* Restore the original dest_vgbuf memory address. */
223 lv_vglite_set_dest_buf_ptr(orig_dest_buf);
224
225 return rv;
226 }
227 #else
lv_gpu_nxp_vglite_blit(const lv_area_t * dest_area,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,lv_opa_t opa)228 lv_res_t lv_gpu_nxp_vglite_blit(const lv_area_t * dest_area,
229 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
230 lv_opa_t opa)
231 {
232 if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
233 VG_LITE_RETURN_INV("Check src alignment failed.");
234
235 /* Set src_vgbuf structure. */
236 lv_vglite_set_src_buf(src_buf, src_area, src_stride);
237
238 /* Set scissor. */
239 lv_vglite_set_scissor(dest_area);
240
241 /* Set vgmatrix. */
242 lv_vglite_set_translation_matrix(dest_area);
243
244 /* Start blit. */
245 lv_res_t rv = lv_vglite_blit(src_area, opa);
246
247 /* Disable scissor. */
248 lv_vglite_disable_scissor();
249
250 return rv;
251 }
252
lv_gpu_nxp_vglite_blit_transform(const lv_area_t * dest_area,const lv_area_t * clip_area,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride,const lv_draw_img_dsc_t * dsc)253 lv_res_t lv_gpu_nxp_vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * clip_area,
254 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride,
255 const lv_draw_img_dsc_t * dsc)
256 {
257 lv_res_t rv = LV_RES_INV;
258
259 if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
260 VG_LITE_RETURN_INV("Check src alignment failed.");
261
262 /* Set src_vgbuf structure. */
263 lv_vglite_set_src_buf(src_buf, src_area, src_stride);
264
265 /* Set scissor */
266 lv_vglite_set_scissor(clip_area);
267
268 /* Set vgmatrix. */
269 lv_vglite_set_transformation_matrix(dest_area, dsc);
270
271 /* Start blit. */
272 rv = lv_vglite_blit(src_area, dsc->opa);
273
274 /* Disable scissor. */
275 lv_vglite_disable_scissor();
276
277 return rv;
278 }
279 #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/
280
lv_gpu_nxp_vglite_buffer_copy(lv_color_t * dest_buf,const lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,const lv_area_t * src_area,lv_coord_t src_stride)281 lv_res_t lv_gpu_nxp_vglite_buffer_copy(lv_color_t * dest_buf, const lv_area_t * dest_area, lv_coord_t dest_stride,
282 const lv_color_t * src_buf, const lv_area_t * src_area, lv_coord_t src_stride)
283 {
284 vg_lite_error_t err = VG_LITE_SUCCESS;
285
286 if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
287 VG_LITE_RETURN_INV("Check src alignment failed.");
288
289 vg_lite_buffer_t src_vgbuf;
290 /* Set src_vgbuf structure. */
291 lv_vglite_set_buf(&src_vgbuf, src_buf, src_area, src_stride);
292
293 vg_lite_buffer_t dest_vgbuf;
294 /* Set dest_vgbuf structure. */
295 lv_vglite_set_buf(&dest_vgbuf, dest_buf, dest_area, dest_stride);
296
297 uint32_t rect[] = {
298 (uint32_t)src_area->x1, /* start x */
299 (uint32_t)src_area->y1, /* start y */
300 (uint32_t)lv_area_get_width(src_area), /* width */
301 (uint32_t)lv_area_get_height(src_area) /* height */
302 };
303
304 /* Set scissor. */
305 lv_vglite_set_scissor(dest_area);
306
307 /* Set vgmatrix. */
308 lv_vglite_set_translation_matrix(dest_area);
309
310 err = vg_lite_blit_rect(&dest_vgbuf, &src_vgbuf, rect, &vgmatrix,
311 VG_LITE_BLEND_NONE, 0xFFFFFFFFU, VG_LITE_FILTER_POINT);
312 if(err != VG_LITE_SUCCESS) {
313 LV_LOG_ERROR("Blit rectangle failed.");
314 /* Disable scissor. */
315 lv_vglite_disable_scissor();
316
317 return LV_RES_INV;
318 }
319
320 if(lv_vglite_run() != LV_RES_OK) {
321 LV_LOG_ERROR("Run failed.");
322 /* Disable scissor. */
323 lv_vglite_disable_scissor();
324
325 return LV_RES_INV;
326 }
327
328 /* Disable scissor. */
329 lv_vglite_disable_scissor();
330
331 return LV_RES_OK;
332 }
333
334 /**********************
335 * STATIC FUNCTIONS
336 **********************/
337
338 #if VG_LITE_BLIT_SPLIT_ENABLED
lv_vglite_blit_split(lv_color_t * dest_buf,lv_area_t * dest_area,lv_coord_t dest_stride,const lv_color_t * src_buf,lv_area_t * src_area,lv_coord_t src_stride,lv_opa_t opa)339 static lv_res_t lv_vglite_blit_split(lv_color_t * dest_buf, lv_area_t * dest_area, lv_coord_t dest_stride,
340 const lv_color_t * src_buf, lv_area_t * src_area, lv_coord_t src_stride,
341 lv_opa_t opa)
342 {
343 lv_res_t rv = LV_RES_INV;
344
345 VG_LITE_LOG_TRACE("Blit "
346 "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
347 "Size: ([%dx%d] -> [%dx%d]) | "
348 "Addr: (0x%x -> 0x%x)",
349 src_area->x1, src_area->y1, src_area->x2, src_area->y2,
350 dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
351 lv_area_get_width(src_area), lv_area_get_height(src_area),
352 lv_area_get_width(dest_area), lv_area_get_height(dest_area),
353 (uintptr_t)src_buf, (uintptr_t)dest_buf);
354
355 /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */
356 align_x(src_area, (lv_color_t **)&src_buf);
357 align_y(src_area, (lv_color_t **)&src_buf, src_stride);
358 align_x(dest_area, (lv_color_t **)&dest_buf);
359 align_y(dest_area, (lv_color_t **)&dest_buf, dest_stride);
360
361 /* Stage 2: If we're in limit, do a single BLIT */
362 if((src_area->x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) &&
363 (src_area->y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) {
364 if(check_src_alignment(src_buf, src_stride) != LV_RES_OK)
365 VG_LITE_RETURN_INV("Check src alignment failed.");
366
367 /* Set new dest_vgbuf and src_vgbuf memory addresses. */
368 lv_vglite_set_dest_buf_ptr(dest_buf);
369 lv_vglite_set_src_buf_ptr(src_buf);
370
371 /* Set scissor */
372 lv_vglite_set_scissor(dest_area);
373
374 /* Set vgmatrix. */
375 lv_vglite_set_translation_matrix(dest_area);
376
377 /* Start blit. */
378 rv = lv_vglite_blit(src_area, opa);
379
380 /* Disable scissor. */
381 lv_vglite_disable_scissor();
382
383 VG_LITE_LOG_TRACE("Single "
384 "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
385 "Size: ([%dx%d] -> [%dx%d]) | "
386 "Addr: (0x%x -> 0x%x) %s",
387 src_area->x1, src_area->y1, src_area->x2, src_area->y2,
388 dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
389 lv_area_get_width(src_area), lv_area_get_height(src_area),
390 lv_area_get_width(dest_area), lv_area_get_height(dest_area),
391 (uintptr_t)src_buf, (uintptr_t)dest_buf,
392 rv == LV_RES_OK ? "OK!" : "FAILED!");
393
394 return rv;
395 };
396
397 /* Stage 3: Split the BLIT into multiple tiles */
398 VG_LITE_LOG_TRACE("Split "
399 "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
400 "Size: ([%dx%d] -> [%dx%d]) | "
401 "Addr: (0x%x -> 0x%x)",
402 src_area->x1, src_area->y1, src_area->x2, src_area->y2,
403 dest_area->x1, dest_area->y1, dest_area->x2, dest_area->y2,
404 lv_area_get_width(src_area), lv_area_get_height(src_area),
405 lv_area_get_width(dest_area), lv_area_get_height(dest_area),
406 (uintptr_t)src_buf, (uintptr_t)dest_buf);
407
408
409 lv_coord_t width = lv_area_get_width(src_area);
410 lv_coord_t height = lv_area_get_height(src_area);
411
412 /* Number of tiles needed */
413 int total_tiles_x = (src_area->x1 + width + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) /
414 LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
415 int total_tiles_y = (src_area->y1 + height + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) /
416 LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
417
418 /* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as
419 * the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be
420 * different */
421 int shift_src_x = (src_area->x1 > dest_area->x1) ? (src_area->x1 - dest_area->x1) : 0;
422 int shift_dest_x = (src_area->x1 < dest_area->x1) ? (dest_area->x1 - src_area->x1) : 0;
423
424 VG_LITE_LOG_TRACE("X shift: src: %d, dst: %d", shift_src_x, shift_dest_x);
425
426 lv_color_t * tile_dest_buf;
427 lv_area_t tile_dest_area;
428 const lv_color_t * tile_src_buf;
429 lv_area_t tile_src_area;
430
431 for(int y = 0; y < total_tiles_y; y++) {
432
433 tile_src_area.y1 = 0; /* no vertical alignment, always start from 0 */
434 tile_src_area.y2 = height - y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
435 if(tile_src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
436 tile_src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */
437 }
438 tile_src_buf = src_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * src_stride;
439
440 tile_dest_area.y1 = tile_src_area.y1; /* y has no alignment, always in sync with src */
441 tile_dest_area.y2 = tile_src_area.y2;
442
443 tile_dest_buf = dest_buf + y * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * dest_stride;
444
445 for(int x = 0; x < total_tiles_x; x++) {
446
447 if(x == 0) {
448 /* 1st tile is special - there may be a gap between buffer start pointer
449 * and area.x1 value, as the pointer has to be aligned.
450 * tile_src_buf pointer - keep init value from Y-loop.
451 * Also, 1st tile start is not shifted! shift is applied from 2nd tile */
452 tile_src_area.x1 = src_area->x1;
453 tile_dest_area.x1 = dest_area->x1;
454 }
455 else {
456 /* subsequent tiles always starts from 0, but shifted*/
457 tile_src_area.x1 = 0 + shift_src_x;
458 tile_dest_area.x1 = 0 + shift_dest_x;
459 /* and advance start pointer + 1 tile size */
460 tile_src_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
461 tile_dest_buf += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
462 }
463
464 /* Clip tile end coordinates */
465 tile_src_area.x2 = width + src_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
466 if(tile_src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
467 tile_src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
468 }
469
470 tile_dest_area.x2 = width + dest_area->x1 - x * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
471 if(tile_dest_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
472 tile_dest_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
473 }
474
475 if(x < (total_tiles_x - 1)) {
476 /* And adjust end coords if shifted, but not for last tile! */
477 tile_src_area.x2 += shift_src_x;
478 tile_dest_area.x2 += shift_dest_x;
479 }
480
481 if(check_src_alignment(tile_src_buf, src_stride) != LV_RES_OK)
482 VG_LITE_RETURN_INV("Check src alignment failed.");
483
484 /* Set new dest_vgbuf and src_vgbuf memory addresses. */
485 lv_vglite_set_dest_buf_ptr(tile_dest_buf);
486 lv_vglite_set_src_buf_ptr(tile_src_buf);
487
488 /* Set scissor */
489 lv_vglite_set_scissor(&tile_dest_area);
490
491 /* Set vgmatrix. */
492 lv_vglite_set_translation_matrix(&tile_dest_area);
493
494 /* Start blit. */
495 rv = lv_vglite_blit(&tile_src_area, opa);
496
497 /* Disable scissor. */
498 lv_vglite_disable_scissor();
499
500 VG_LITE_LOG_TRACE("Tile [%d, %d] "
501 "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | "
502 "Size: ([%dx%d] -> [%dx%d]) | "
503 "Addr: (0x%x -> 0x%x) %s",
504 x, y,
505 tile_src_area.x1, tile_src_area.y1, tile_src_area.x2, tile_src_area.y2,
506 tile_dest_area.x1, tile_dest_area.y1, tile_dest_area.x2, tile_dest_area.y2,
507 lv_area_get_width(&tile_src_area), lv_area_get_height(&tile_src_area),
508 lv_area_get_width(&tile_dest_area), lv_area_get_height(&tile_dest_area),
509 (uintptr_t)tile_src_buf, (uintptr_t)tile_dest_buf,
510 rv == LV_RES_OK ? "OK!" : "FAILED!");
511
512 if(rv != LV_RES_OK) {
513 return rv;
514 }
515 }
516 }
517
518 return rv;
519 }
520 #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/
521
lv_vglite_blit(const lv_area_t * src_area,lv_opa_t opa)522 static lv_res_t lv_vglite_blit(const lv_area_t * src_area, lv_opa_t opa)
523 {
524 vg_lite_error_t err = VG_LITE_SUCCESS;
525 vg_lite_buffer_t * dst_vgbuf = lv_vglite_get_dest_buf();
526 vg_lite_buffer_t * src_vgbuf = lv_vglite_get_src_buf();
527
528 uint32_t rect[] = {
529 (uint32_t)src_area->x1, /* start x */
530 (uint32_t)src_area->y1, /* start y */
531 (uint32_t)lv_area_get_width(src_area), /* width */
532 (uint32_t)lv_area_get_height(src_area) /* height */
533 };
534
535 uint32_t color;
536 vg_lite_blend_t blend;
537 if(opa >= (lv_opa_t)LV_OPA_MAX) {
538 color = 0xFFFFFFFFU;
539 blend = VG_LITE_BLEND_SRC_OVER;
540 src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
541 }
542 else {
543 if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) {
544 color = (opa << 24) | 0x00FFFFFFU;
545 }
546 else {
547 color = (opa << 24) | (opa << 16) | (opa << 8) | opa;
548 }
549 blend = VG_LITE_BLEND_SRC_OVER;
550 src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
551 src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT;
552 }
553
554 err = vg_lite_blit_rect(dst_vgbuf, src_vgbuf, rect, &vgmatrix, blend, color, VG_LITE_FILTER_POINT);
555 VG_LITE_ERR_RETURN_INV(err, "Blit rectangle failed.");
556
557 if(lv_vglite_run() != LV_RES_OK)
558 VG_LITE_RETURN_INV("Run failed.");
559
560 return LV_RES_OK;
561 }
562
check_src_alignment(const lv_color_t * src_buf,lv_coord_t src_stride)563 static lv_res_t check_src_alignment(const lv_color_t * src_buf, lv_coord_t src_stride)
564 {
565 /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */
566
567 /* Test for pointer alignment */
568 if((((uintptr_t)src_buf) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != (uintptr_t)0x0U)
569 VG_LITE_RETURN_INV("Src buffer ptr (0x%x) not aligned to 0x%x bytes.",
570 (size_t)src_buf, LV_ATTRIBUTE_MEM_ALIGN_SIZE);
571
572 /* Test for stride alignment */
573 if((src_stride % (lv_coord_t)LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0x0U)
574 VG_LITE_RETURN_INV("Src buffer stride (%d px) not aligned to %d px.",
575 src_stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
576 return LV_RES_OK;
577 }
578
lv_vglite_set_translation_matrix(const lv_area_t * dest_area)579 static inline void lv_vglite_set_translation_matrix(const lv_area_t * dest_area)
580 {
581 vg_lite_identity(&vgmatrix);
582 vg_lite_translate((vg_lite_float_t)dest_area->x1, (vg_lite_float_t)dest_area->y1, &vgmatrix);
583 }
584
lv_vglite_set_transformation_matrix(const lv_area_t * dest_area,const lv_draw_img_dsc_t * dsc)585 static inline void lv_vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw_img_dsc_t * dsc)
586 {
587 lv_vglite_set_translation_matrix(dest_area);
588
589 bool has_scale = (dsc->zoom != LV_IMG_ZOOM_NONE);
590 bool has_rotation = (dsc->angle != 0);
591
592 vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &vgmatrix);
593 if(has_rotation)
594 vg_lite_rotate(dsc->angle / 10.0f, &vgmatrix); /* angle is 1/10 degree */
595 if(has_scale) {
596 vg_lite_float_t scale = 1.0f * dsc->zoom / LV_IMG_ZOOM_NONE;
597 vg_lite_scale(scale, scale, &vgmatrix);
598 }
599 vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &vgmatrix);
600 }
601
602 #if VG_LITE_BLIT_SPLIT_ENABLED
align_x(lv_area_t * area,lv_color_t ** buf)603 static void align_x(lv_area_t * area, lv_color_t ** buf)
604 {
605 int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE / sizeof(lv_color_t)));
606 VG_LITE_COND_STOP(alignedAreaStartPx < 0, "Negative X alignment.");
607
608 area->x1 -= alignedAreaStartPx;
609 area->x2 -= alignedAreaStartPx;
610 *buf += alignedAreaStartPx;
611 }
612
align_y(lv_area_t * area,lv_color_t ** buf,lv_coord_t stride)613 static void align_y(lv_area_t * area, lv_color_t ** buf, lv_coord_t stride)
614 {
615 int LineToAlignMem;
616 int alignedAreaStartPy;
617 /* find how many lines of pixels will respect memory alignment requirement */
618 if((stride % (lv_coord_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) == 0x0U) {
619 alignedAreaStartPy = area->y1;
620 }
621 else {
622 LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t));
623 VG_LITE_COND_STOP(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)),
624 "Complex case: need gcd function.");
625 alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem);
626 VG_LITE_COND_STOP(alignedAreaStartPy < 0, "Negative Y alignment.");
627 }
628
629 area->y1 -= alignedAreaStartPy;
630 area->y2 -= alignedAreaStartPy;
631 *buf += (uint32_t)(alignedAreaStartPy * stride);
632 }
633 #endif /*VG_LITE_BLIT_SPLIT_ENABLED*/
634
635 #endif /*LV_USE_GPU_NXP_VG_LITE*/
636