1 /**
2 * @file lv_gpu_nxp_vglite.c
3 *
4 */
5
6 /**
7 * MIT License
8 *
9 * Copyright (c) 2020 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_gpu_nxp_vglite.h"
35
36 #if LV_USE_GPU_NXP_VG_LITE
37
38 #include "lvgl.h"
39 #include "../misc/lv_log.h"
40 #include "fsl_cache.h"
41 #include "vg_lite.h"
42 #include "fsl_debug_console.h"
43
44 /*********************
45 * DEFINES
46 *********************/
47
48 #if LV_COLOR_DEPTH==16
49 #define VGLITE_PX_FMT VG_LITE_RGB565
50 #else
51 #error Only 16bit color depth is supported. Set LV_COLOR_DEPTH to 16.
52 #endif
53
54 /* Enable BLIT quality degradation workaround for RT595 */
55 #define RT595_BLIT_WRKRND_ENABLED 1
56
57 /* If LV_HOR_RES_MAX/LV_VER_RES_MAX is higher than this value, workaround will be enabled */
58 #define RT595_BLIT_WRKRND_THR 352
59
60 /* Print detailed info to SDK console (NOT to LVGL log system) */
61 #define BLIT_DBG_VERBOSE 0
62
63 /* Draw rectangles around BLIT tiles */
64 #define BLIT_DBG_AREAS 0
65
66 /* Redirect PRINT to SDK PRINTF */
67 #define PRINT PRINTF
68
69 /* Verbose debug print */
70 #if BLIT_DBG_VERBOSE
71 #define PRINT_BLT PRINTF
72 #else
73 #define PRINT_BLT(...)
74 #endif
75
76 /* Internal compound symbol */
77 #if (defined(CPU_MIMXRT595SFFOB) || defined(CPU_MIMXRT595SFFOB_cm33) || \
78 defined(CPU_MIMXRT595SFFOC) || defined(CPU_MIMXRT595SFFOC_cm33)) && \
79 ((LV_HOR_RES_MAX > RT595_BLIT_WRKRND_THR) || (LV_VER_RES_MAX > RT595_BLIT_WRKRND_THR)) && \
80 RT595_BLIT_WRKRND_ENABLED
81 #define _BLIT_SPLIT_ENABLED 1
82 #else
83 #define _BLIT_SPLIT_ENABLED 0
84 #endif
85
86 /* BLIT split threshold - BLITs with width or height higher than this value will be done
87 * in multiple steps. Value must be 16-aligned. Don't change.
88 * */
89 #define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352
90
91
92 /**********************
93 * TYPEDEFS
94 **********************/
95
96 /**********************
97 * STATIC PROTOTYPES
98 **********************/
99
100 static lv_res_t _init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t height, uint32_t stride,
101 const lv_color_t * ptr, bool source);
102
103 static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit);
104 #if _BLIT_SPLIT_ENABLED
105 static void _align_x(lv_area_t * area, lv_color_t ** buf);
106 static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx);
107 static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit);
108 #if BLIT_DBG_AREAS
109 static void _draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height,
110 lv_area_t * fill_area, lv_color_t color);
111 #endif
112 static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit);
113 #endif
114
115 /**********************
116 * STATIC VARIABLES
117 **********************/
118
119 /**********************
120 * MACROS
121 **********************/
122
123 #define CHECK(cond, txt) \
124 do { \
125 if (cond) { \
126 PRINT("%s. STOP!\n", txt); \
127 for ( ; ; ); \
128 } \
129 } while(0)
130
131 /**********************
132 * GLOBAL FUNCTIONS
133 **********************/
134
135 /***
136 * Fills rectangular area in buffer.
137 * @param[in] dest_buf Destination buffer pointer (must be aligned on 32 bytes)
138 * @param[in] dest_width Destination buffer width in pixels (must be aligned on 16 px)
139 * @param[in] dest_height Destination buffer height in pixels
140 * @param[in] fill_area Area to be filled
141 * @param[in] color Fill color
142 * @param[in] opa Opacity (255 = full, 128 = 50% background/50% color, 0 = no fill)
143 * @retval LV_RES_OK Fill completed
144 * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
145 */
lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf,lv_coord_t dest_width,lv_coord_t dest_height,const lv_area_t * fill_area,lv_color_t color,lv_opa_t opa)146 lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height,
147 const lv_area_t * fill_area, lv_color_t color, lv_opa_t opa)
148 {
149 vg_lite_buffer_t rt;
150 vg_lite_rectangle_t rect;
151 vg_lite_error_t err = VG_LITE_SUCCESS;
152 lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/
153 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
154
155 if(_init_vg_buf(&rt, (uint32_t) dest_width, (uint32_t) dest_height, (uint32_t) dest_width * sizeof(lv_color_t),
156 (const lv_color_t *) dest_buf, false) != LV_RES_OK) {
157 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
158 LV_LOG_ERROR("init_vg_buf reported error. Fill failed.");
159 #endif
160 return LV_RES_INV;
161 }
162
163 if(opa >= (lv_opa_t) LV_OPA_MAX) { /*Opaque fill*/
164 rect.x = fill_area->x1;
165 rect.y = fill_area->y1;
166 rect.width = (int32_t) fill_area->x2 - (int32_t) fill_area->x1 + 1;
167 rect.height = (int32_t) fill_area->y2 - (int32_t) fill_area->y1 + 1;
168
169 if(disp != NULL && disp->driver->clean_dcache_cb != NULL) { /*Clean & invalidate cache*/
170 disp->driver->clean_dcache_cb(disp->driver);
171 }
172
173 err = vg_lite_clear(&rt, &rect, col32.full);
174 if(err != VG_LITE_SUCCESS) {
175 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
176 LV_LOG_ERROR("vg_lite_clear reported error. Fill failed.");
177 #endif
178 return LV_RES_INV;
179 }
180 err = vg_lite_finish();
181 if(err != VG_LITE_SUCCESS) {
182 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
183 LV_LOG_ERROR("vg_lite_finish reported error. Fill failed.");
184 #endif
185 return LV_RES_INV;
186 }
187 }
188 else { /*fill with transparency*/
189
190 vg_lite_path_t path;
191 lv_color32_t colMix;
192 int16_t path_data[] = { /*VG rectangular path*/
193 VLC_OP_MOVE, fill_area->x1, fill_area->y1,
194 VLC_OP_LINE, fill_area->x2 + 1, fill_area->y1,
195 VLC_OP_LINE, fill_area->x2 + 1, fill_area->y2 + 1,
196 VLC_OP_LINE, fill_area->x1, fill_area->y2 + 1,
197 VLC_OP_LINE, fill_area->x1, fill_area->y1,
198 VLC_OP_END
199 };
200
201 err = vg_lite_init_path(&path, VG_LITE_S16, VG_LITE_LOW, sizeof(path_data), path_data,
202 (vg_lite_float_t) fill_area->x1, (vg_lite_float_t) fill_area->y1, ((vg_lite_float_t) fill_area->x2) + 1.0f,
203 ((vg_lite_float_t) fill_area->y2) + 1.0f);
204 if(err != VG_LITE_SUCCESS) {
205 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
206 LV_LOG_ERROR("vg_lite_init_path() failed.");
207 #endif
208 return LV_RES_INV;
209 }
210
211 colMix.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8); /*Pre-multiply color*/
212 colMix.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8);
213 colMix.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8);
214 colMix.ch.alpha = opa;
215
216 if((disp != NULL) && (disp->driver->clean_dcache_cb != NULL)) { /*Clean & invalidate cache*/
217 disp->driver->clean_dcache_cb(disp->driver);
218 }
219
220 vg_lite_matrix_t matrix;
221 vg_lite_identity(&matrix);
222
223 /*Draw rectangle*/
224 err = vg_lite_draw(&rt, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, colMix.full);
225 if(err != VG_LITE_SUCCESS) {
226 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
227 LV_LOG_ERROR("vg_lite_draw() failed.");
228 #endif
229 vg_lite_clear_path(&path);
230 return LV_RES_INV;
231 }
232
233 err = vg_lite_finish();
234 if(err != VG_LITE_SUCCESS) {
235 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
236 LV_LOG_ERROR("vg_lite_finish() failed.");
237 #endif
238 return LV_RES_INV;
239 }
240
241 err = vg_lite_clear_path(&path);
242 if(err != VG_LITE_SUCCESS) {
243 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
244 LV_LOG_ERROR("vg_lite_clear_path() failed.");
245 #endif
246 return LV_RES_INV;
247 }
248 }
249
250 if(err == VG_LITE_SUCCESS) {
251 return LV_RES_OK;
252 }
253 else {
254 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
255 LV_LOG_ERROR("VG Lite Fill failed.");
256 #endif
257 return LV_RES_INV;
258 }
259 }
260
261 /***
262 * BLock Image Transfer.
263 * @param[in] blit Description of the transfer
264 * @retval LV_RES_OK Transfer complete
265 * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
266 */
lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit)267 lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit)
268 {
269 #if _BLIT_SPLIT_ENABLED
270
271 lv_res_t rv = LV_RES_INV;
272
273 if(_lv_gpu_nxp_vglite_check_blit(blit) != LV_RES_OK) {
274 PRINT_BLT("Blit check failed\n");
275 return LV_RES_INV;
276 }
277
278 PRINT_BLT("BLIT from: "
279 "Area: %03d,%03d - %03d,%03d "
280 "Addr: %d\n\n",
281 blit->src_area.x1, blit->src_area.y1,
282 blit->src_area.x2, blit->src_area.y2,
283 (uintptr_t) blit->src);
284
285 PRINT_BLT("BLIT to: "
286 "Area: %03d,%03d - %03d,%03d "
287 "Addr: %d\n\n",
288 blit->dst_area.x1, blit->dst_area.y1,
289 blit->dst_area.x2, blit->dst_area.y2,
290 (uintptr_t) blit->src);
291
292 /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */
293 _align_x(&blit->src_area, (lv_color_t **)&blit->src);
294 _align_y(&blit->src_area, (lv_color_t **)&blit->src, blit->src_stride / sizeof(lv_color_t));
295 _align_x(&blit->dst_area, (lv_color_t **)&blit->dst);
296 _align_y(&blit->dst_area, (lv_color_t **)&blit->dst, blit->dst_stride / sizeof(lv_color_t));
297
298 /* Stage 2: If we're in limit, do a single BLIT */
299 if((blit->src_area.x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) &&
300 (blit->src_area.y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) {
301 PRINT_BLT("Simple blit!\n");
302 return _lv_gpu_nxp_vglite_blit_single(blit);
303 };
304
305 /* Stage 3: Split the BLIT into multiple tiles */
306 PRINT_BLT("Split blit!\n");
307
308 PRINT_BLT("Blit "
309 "([%03d,%03d], [%03d,%03d]) -> "
310 "([%03d,%03d], [%03d,%03d]) | "
311 "([%03dx%03d] -> [%03dx%03d]) | "
312 "A:(%d -> %d)\n",
313 blit->src_area.x1, blit->src_area.y1, blit->src_area.x2, blit->src_area.y2,
314 blit->dst_area.x1, blit->dst_area.y1, blit->dst_area.x2, blit->dst_area.y2,
315 lv_area_get_width(&blit->src_area), lv_area_get_height(&blit->src_area),
316 lv_area_get_width(&blit->dst_area), lv_area_get_height(&blit->dst_area),
317 (uintptr_t) blit->src, (uintptr_t) blit->dst);
318
319
320 uint32_t totalWidth = lv_area_get_width(&blit->src_area);
321 uint32_t totalHeight = lv_area_get_height(&blit->src_area);
322
323 lv_gpu_nxp_vglite_blit_info_t tileBlit;
324
325 /* Number of tiles needed */
326 int totalTilesX = (blit->src_area.x1 + totalWidth + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) /
327 LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
328 int totalTilesY = (blit->src_area.y1 + totalHeight + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) /
329 LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
330
331 /* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as
332 * the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be
333 * different */
334 int shiftSrcX = (blit->src_area.x1 > blit->dst_area.x1) ? (blit->src_area.x1 - blit->dst_area.x1) : 0;
335 int shiftDstX = (blit->src_area.x1 < blit->dst_area.x1) ? (blit->dst_area.x1 - blit->src_area.x1) : 0;
336
337 PRINT_BLT("\n");
338 PRINT_BLT("Align shift: src: %d, dst: %d\n", shiftSrcX, shiftDstX);
339
340 tileBlit = *blit;
341
342 for(int tileY = 0; tileY < totalTilesY; tileY++) {
343
344 tileBlit.src_area.y1 = 0; /* no vertical alignment, always start from 0 */
345 tileBlit.src_area.y2 = totalHeight - tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
346 if(tileBlit.src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
347 tileBlit.src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */
348 }
349 tileBlit.src = blit->src + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->src_stride / sizeof(
350 lv_color_t); /* stride in px! */
351
352 tileBlit.dst_area.y1 = tileBlit.src_area.y1; /* y has no alignment, always in sync with src */
353 tileBlit.dst_area.y2 = tileBlit.src_area.y2;
354
355 tileBlit.dst = blit->dst + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->dst_stride / sizeof(
356 lv_color_t); /* stride in px! */
357
358 for(int tileX = 0; tileX < totalTilesX; tileX++) {
359
360 if(tileX == 0) {
361 /* 1st tile is special - there may be a gap between buffer start pointer
362 * and area.x1 value, as the pointer has to be aligned.
363 * tileBlit.src pointer - keep init value from Y-loop.
364 * Also, 1st tile start is not shifted! shift is applied from 2nd tile */
365 tileBlit.src_area.x1 = blit->src_area.x1;
366 tileBlit.dst_area.x1 = blit->dst_area.x1;
367 }
368 else {
369 /* subsequent tiles always starts from 0, but shifted*/
370 tileBlit.src_area.x1 = 0 + shiftSrcX;
371 tileBlit.dst_area.x1 = 0 + shiftDstX;
372 /* and advance start pointer + 1 tile size */
373 tileBlit.src += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
374 tileBlit.dst += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR;
375 }
376
377 /* Clip tile end coordinates */
378 tileBlit.src_area.x2 = totalWidth + blit->src_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
379 if(tileBlit.src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
380 tileBlit.src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
381 }
382
383 tileBlit.dst_area.x2 = totalWidth + blit->dst_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
384 if(tileBlit.dst_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) {
385 tileBlit.dst_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1;
386 }
387
388 if(tileX < (totalTilesX - 1)) {
389 /* And adjust end coords if shifted, but not for last tile! */
390 tileBlit.src_area.x2 += shiftSrcX;
391 tileBlit.dst_area.x2 += shiftDstX;
392 }
393
394 rv = _lv_gpu_nxp_vglite_blit_single(&tileBlit);
395
396 #if BLIT_DBG_AREAS
397 _draw_rectangle((lv_color_t *) tileBlit.dst, tileBlit.dst_width, tileBlit.dst_height, &tileBlit.dst_area, LV_COLOR_RED);
398 _draw_rectangle((lv_color_t *) tileBlit.src, tileBlit.src_width, tileBlit.src_height, &tileBlit.src_area,
399 LV_COLOR_GREEN);
400 #endif
401
402 PRINT_BLT("Tile [%d, %d]: "
403 "([%d,%d], [%d,%d]) -> "
404 "([%d,%d], [%d,%d]) | "
405 "([%dx%d] -> [%dx%d]) | "
406 "A:(0x%8X -> 0x%8X) %s\n",
407 tileX, tileY,
408 tileBlit.src_area.x1, tileBlit.src_area.y1, tileBlit.src_area.x2, tileBlit.src_area.y2,
409 tileBlit.dst_area.x1, tileBlit.dst_area.y1, tileBlit.dst_area.x2, tileBlit.dst_area.y2,
410 lv_area_get_width(&tileBlit.src_area), lv_area_get_height(&tileBlit.src_area),
411 lv_area_get_width(&tileBlit.dst_area), lv_area_get_height(&tileBlit.dst_area),
412 (uintptr_t) tileBlit.src, (uintptr_t) tileBlit.dst,
413 rv == LV_RES_OK ? "OK!" : "!!! FAILED !!!");
414
415 if(rv != LV_RES_OK) { /* if anything goes wrong... */
416 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
417 LV_LOG_ERROR("Split BLIT failed. Trying SW BLIT instead.");
418 #endif
419 _sw_blit(&tileBlit);
420 rv = LV_RES_OK; /* Don't report error, as SW BLIT was performed */
421 }
422
423 }
424 PRINT_BLT(" \n");
425 }
426
427 return rv; /* should never fail */
428
429 #else /* non RT595 */
430 /* Just pass down */
431 return _lv_gpu_nxp_vglite_blit_single(blit);
432 #endif
433 }
434
435 /**********************
436 * STATIC FUNCTIONS
437 **********************/
438
439 /***
440 * BLock Image Transfer - single direct BLIT.
441 * @param[in] blit Description of the transfer
442 * @retval LV_RES_OK Transfer complete
443 * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS)
444 */
_lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit)445 static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit)
446 {
447 vg_lite_buffer_t src_vgbuf, dst_vgbuf;
448 vg_lite_error_t err = VG_LITE_SUCCESS;
449 uint32_t rect[4];
450 lv_disp_t * disp = _lv_refr_get_disp_refreshing();
451
452 if(blit == NULL) {
453 /*Wrong parameter*/
454 return LV_RES_INV;
455 }
456
457 if(blit->opa < (lv_opa_t) LV_OPA_MIN) {
458 return LV_RES_OK; /*Nothing to BLIT*/
459 }
460
461 /*Wrap src/dst buffer into VG-Lite buffer*/
462 if(_init_vg_buf(&src_vgbuf, (uint32_t) blit->src_width, (uint32_t) blit->src_height, (uint32_t) blit->src_stride,
463 blit->src, true) != LV_RES_OK) {
464 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
465 LV_LOG_ERROR("init_vg_buf reported error. BLIT failed.");
466 #endif
467 return LV_RES_INV;
468 }
469
470 if(_init_vg_buf(&dst_vgbuf, (uint32_t) blit->dst_width, (uint32_t) blit->dst_height, (uint32_t) blit->dst_stride,
471 blit->dst, false) != LV_RES_OK) {
472 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
473 LV_LOG_ERROR("init_vg_buf reported error. BLIT failed.");
474 #endif
475 return LV_RES_INV;
476 }
477
478 rect[0] = (uint32_t) blit->src_area.x1; /* start x */
479 rect[1] = (uint32_t) blit->src_area.y1; /* start y */
480 rect[2] = (uint32_t) blit->src_area.x2 - (uint32_t) blit->src_area.x1 + 1U; /* width */
481 rect[3] = (uint32_t) blit->src_area.y2 - (uint32_t) blit->src_area.y1 + 1U; /* height */
482
483 vg_lite_matrix_t matrix;
484 vg_lite_identity(&matrix);
485 vg_lite_translate((vg_lite_float_t)blit->dst_area.x1, (vg_lite_float_t)blit->dst_area.y1, &matrix);
486
487 if((disp != NULL) && (disp->driver->clean_dcache_cb != NULL)) { /*Clean & invalidate cache*/
488 disp->driver->clean_dcache_cb(disp->driver);
489 }
490
491 uint32_t color;
492 vg_lite_blend_t blend;
493 if(blit->opa >= (uint8_t) LV_OPA_MAX) {
494 color = 0x0;
495 blend = VG_LITE_BLEND_NONE;
496 }
497 else {
498 uint32_t opa = (uint32_t) blit->opa;
499 color = (opa << 24) | (opa << 16) | (opa << 8) | opa;
500 blend = VG_LITE_BLEND_SRC_OVER;
501 src_vgbuf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE;
502 }
503
504 err = vg_lite_blit_rect(&dst_vgbuf, &src_vgbuf, rect, &matrix, blend, color, VG_LITE_FILTER_POINT);
505 if(err != VG_LITE_SUCCESS) {
506 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
507 LV_LOG_ERROR("vg_lite_blit_rect() failed.");
508 #endif
509 return LV_RES_INV;
510 }
511
512 err = vg_lite_finish();
513 if(err != VG_LITE_SUCCESS) {
514 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
515 LV_LOG_ERROR("vg_lite_finish() failed.");
516 #endif
517 return LV_RES_INV;
518 }
519
520 if(err == VG_LITE_SUCCESS) {
521 return LV_RES_OK;
522 }
523 else {
524 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
525 LV_LOG_ERROR("vg_lite_blit_rect or vg_lite_finish reported error. BLIT failed.");
526 #endif
527 return LV_RES_INV;
528 }
529 }
530
531 /***
532 * Fills vg_lite_buffer_t structure according given parameters.
533 * @param[out] dst Buffer structure to be filled
534 * @param[in] width Width of buffer in pixels
535 * @param[in] height Height of buffer in pixels
536 * @param[in] stride Stride of the buffer in bytes
537 * @param[in] ptr Pointer to the buffer (must be aligned according VG-Lite requirements)
538 */
_init_vg_buf(vg_lite_buffer_t * dst,uint32_t width,uint32_t height,uint32_t stride,const lv_color_t * ptr,bool source)539 static lv_res_t _init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t height, uint32_t stride,
540 const lv_color_t * ptr, bool source)
541 {
542 if((((uintptr_t)ptr) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0U) { /*Test for alignment*/
543 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
544 LV_LOG_ERROR("ptr (0x%X) not aligned to %d.", (size_t) ptr, LV_ATTRIBUTE_MEM_ALIGN_SIZE);
545 #endif
546 return LV_RES_INV;
547 }
548
549 if(source &&
550 (stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t))) != 0x0U) { /*Test for stride alignment*/
551 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
552 LV_LOG_ERROR("Buffer stride (%d px) not aligned to %d bytes.", stride,
553 LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t));
554 #endif
555 return LV_RES_INV;
556 }
557
558 dst->format = VGLITE_PX_FMT;
559 dst->tiled = VG_LITE_LINEAR;
560 dst->image_mode = VG_LITE_NORMAL_IMAGE_MODE;
561 dst->transparency_mode = VG_LITE_IMAGE_OPAQUE;
562
563 dst->width = (int32_t) width;
564 dst->height = (int32_t) height;
565 dst->stride = (int32_t) stride;
566
567 void * r_ptr = memset(&dst->yuv, 0, sizeof(dst->yuv));
568 if(r_ptr == NULL) {
569 return LV_RES_INV;
570 }
571
572 dst->memory = (void *)ptr;
573 dst->address = (uint32_t) dst->memory;
574 dst->handle = NULL;
575
576 return LV_RES_OK;
577 }
578
579 #if _BLIT_SPLIT_ENABLED
580
581 /**
582 * Software BLIT as a fall-back scenario
583 * @param[in] blit BLIT configuration
584 */
_sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit)585 static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit)
586 {
587 int x, y;
588
589 lv_coord_t w = lv_area_get_width(&blit->src_area);
590 lv_coord_t h = lv_area_get_height(&blit->src_area);
591
592 uint32_t srcStridePx = blit->src_stride / sizeof(lv_color_t);
593 uint32_t dstStridePx = blit->dst_stride / sizeof(lv_color_t);
594
595 lv_color_t * src = (lv_color_t *)blit->src + blit->src_area.y1 * srcStridePx + blit->src_area.x1;
596 lv_color_t * dst = (lv_color_t *)blit->dst + blit->dst_area.y1 * dstStridePx + blit->dst_area.x1;
597
598 if(blit->opa >= LV_OPA_MAX) {
599 /* simple copy */
600 for(y = 0; y < h; y++) {
601 _lv_memcpy(dst, src, w * sizeof(lv_color_t));
602 src += srcStridePx;
603 dst += dstStridePx;
604 }
605 }
606 else if(blit->opa >= LV_OPA_MIN) {
607 /* alpha blending */
608 for(y = 0; y < h; y++) {
609 for(x = 0; x < w; x++) {
610 dst[x] = lv_color_mix(src[x], dst[x], blit->opa);
611 }
612 src += srcStridePx;
613 dst += dstStridePx;
614 }
615 }
616 }
617
618 /**
619 * Verify BLIT structure - widths, stride, pointer alignment
620 * @param[in] blit
621 * @return
622 */
_lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit)623 static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit)
624 {
625
626 if(lv_area_get_width(&blit->src_area) < LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) { /* Test for minimal width */
627 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
628 LV_LOG_ERROR("source area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->src_area),
629 LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
630 #endif
631 return LV_RES_INV;
632 }
633
634 if(lv_area_get_width(&blit->dst_area) < LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) { /* Test for minimal width */
635 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
636 LV_LOG_ERROR("destination area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->dst_area),
637 LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
638 #endif
639 return LV_RES_INV;
640 }
641
642 if((((uintptr_t) blit->src) % LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0) { /* Test for pointer alignment */
643 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
644 LV_LOG_ERROR("source buffer ptr (0x%X) not aligned to %d.", (size_t) blit->src, LV_ATTRIBUTE_MEM_ALIGN_SIZE);
645 #endif
646 return LV_RES_INV;
647 }
648 /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */
649
650 if((blit->src_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) !=
651 0x0) { /* Test for stride alignment */
652 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
653 LV_LOG_ERROR("source buffer stride (%d px) not aligned to %d px.", blit->src_stride,
654 LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
655 #endif
656 return LV_RES_INV;
657 }
658
659 if((blit->dst_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) !=
660 0x0) { /* Test for stride alignment */
661 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
662 LV_LOG_ERROR("destination buffer stride (%d px) not aligned to %d px.", blit->dst_stride,
663 LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
664 #endif
665 return LV_RES_INV;
666 }
667
668 if((lv_area_get_width(&blit->src_area) != lv_area_get_width(&blit->dst_area)) ||
669 (lv_area_get_height(&blit->src_area) != lv_area_get_height(&blit->dst_area))) {
670 #if LV_GPU_NXP_VG_LITE_LOG_ERRORS
671 LV_LOG_ERROR("source and destination buffer areas are not equal.");
672 #endif
673 return LV_RES_INV;
674 }
675
676 return LV_RES_OK;
677 }
678
679 /***
680 * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only.
681 * @param[in,out] area Area to be updated
682 * @param[in,out] buf Pointer to be updated
683 */
_align_x(lv_area_t * area,lv_color_t ** buf)684 static void _align_x(lv_area_t * area, lv_color_t ** buf)
685 {
686
687 int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE * 8 / LV_COLOR_DEPTH));
688 CHECK(alignedAreaStartPx < 0, "Should never happen.");
689
690 area->x1 -= alignedAreaStartPx;
691 area->x2 -= alignedAreaStartPx;
692 *buf += alignedAreaStartPx;
693 }
694
695 /***
696 * Move buffer pointer to the area start and update variables, Y-axis only.
697 * @param[in,out] area Area to be updated
698 * @param[in,out] buf Pointer to be updated
699 * @param[in] stridePx Buffer stride in pixels
700 */
_align_y(lv_area_t * area,lv_color_t ** buf,uint32_t stridePx)701 static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx)
702 {
703 int LineToAlignMem;
704 int alignedAreaStartPy;
705 /* find how many lines of pixels will respect memory alignment requirement */
706 if(stridePx % LV_ATTRIBUTE_MEM_ALIGN_SIZE == 0) {
707 alignedAreaStartPy = area->y1;
708 }
709 else {
710 LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX);
711 CHECK(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0,
712 "Complex case: need gcd function.");
713 alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem);
714 CHECK(alignedAreaStartPy < 0, "Should never happen.");
715 }
716
717 area->y1 -= alignedAreaStartPy;
718 area->y2 -= alignedAreaStartPy;
719 *buf += alignedAreaStartPy * stridePx;
720 }
721
722 #if BLIT_DBG_AREAS
723 /***
724 * Draws a simple rectangle, 1 px line width.
725 * @param dest_buf Destination buffer
726 * @param dest_width Destination buffer width (must be aligned on 16px)
727 * @param dest_height Destination buffer height
728 * @param fill_area Rectangle coordinates
729 * @param color Rectangle color
730 */
_draw_rectangle(lv_color_t * dest_buf,lv_coord_t dest_width,lv_coord_t dest_height,lv_area_t * fill_area,lv_color_t color)731 static void _draw_rectangle(lv_color_t * dest_buf, lv_coord_t dest_width, lv_coord_t dest_height,
732 lv_area_t * fill_area, lv_color_t color)
733 {
734
735 lv_area_t a;
736
737 /* top line */
738 a.x1 = fill_area->x1;
739 a.x2 = fill_area->x2;
740 a.y1 = fill_area->y1;
741 a.y2 = fill_area->y1;
742 lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
743
744
745 /* bottom line */
746 a.x1 = fill_area->x1;
747 a.x2 = fill_area->x2;
748 a.y1 = fill_area->y2;
749 a.y2 = fill_area->y2;
750 lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
751
752 /* left line */
753 a.x1 = fill_area->x1;
754 a.x2 = fill_area->x1;
755 a.y1 = fill_area->y1;
756 a.y2 = fill_area->y2;
757 lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
758
759 /* right line */
760 a.x1 = fill_area->x2;
761 a.x2 = fill_area->x2;
762 a.y1 = fill_area->y1;
763 a.y2 = fill_area->y2;
764 lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER);
765 }
766 #endif /* BLIT_DBG_AREAS */
767
768 #endif /* _BLIT_SPLIT_ENABLED */
769
770 #endif /*LV_USE_GPU_NXP_VG_LITE*/
771