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