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*/