acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
lv_gpu_nxp_vglite.c (28167B)
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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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*/