diff --git a/Kconfig b/Kconfig index f509d9654..f0e629532 100644 --- a/Kconfig +++ b/Kconfig @@ -166,7 +166,7 @@ menu "LVGL configuration" 1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) and call lv_gpu_nxp_pxp_init() automatically during lv_init(). - Note that symbol FSL_RTOS_FREE_RTOS has to be defined in order + Note that symbol SDK_OS_FREE_RTOS has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. 0: lv_gpu_nxp_pxp_init() has to be called manually before diff --git a/lv_conf_template.h b/lv_conf_template.h index e2828efa3..43bef7707 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -122,7 +122,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ #define LV_USE_GPU_NXP_PXP 0 #if LV_USE_GPU_NXP_PXP /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) - * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol FSL_RTOS_FREE_RTOS + * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() */ diff --git a/src/core/lv_obj.c b/src/core/lv_obj.c index 31f1afd72..f265b81a1 100644 --- a/src/core/lv_obj.c +++ b/src/core/lv_obj.c @@ -30,6 +30,11 @@ #include "../gpu/lv_gpu_stm32_dma2d.h" #endif +#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT + #include "../gpu/lv_gpu_nxp_pxp.h" + #include "../gpu/lv_gpu_nxp_pxp_osa.h" +#endif + /********************* * DEFINES *********************/ @@ -105,6 +110,13 @@ void lv_init(void) lv_gpu_stm32_dma2d_init(); #endif +#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT + if(lv_gpu_nxp_pxp_init(&pxp_default_cfg) != LV_RES_OK) { + LV_LOG_ERROR("PXP init error. STOP.\n"); + for(; ;) ; + } +#endif + _lv_obj_style_init(); _lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t)); _lv_ll_init(&LV_GC_ROOT(_lv_indev_ll), sizeof(lv_indev_t)); diff --git a/src/draw/lv_draw_blend.c b/src/draw/lv_draw_blend.c index 1d10d86e3..336f13c23 100644 --- a/src/draw/lv_draw_blend.c +++ b/src/draw/lv_draw_blend.c @@ -701,8 +701,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col blit.src_stride = lv_area_get_width(map_area) * sizeof(lv_color_t); blit.src_area.x1 = (draw_area->x1 - (map_area->x1 - disp_area->x1)); blit.src_area.y1 = (draw_area->y1 - (map_area->y1 - disp_area->y1)); - blit.src_area.x2 = blit.src_area.x1 + draw_area_w; - blit.src_area.y2 = blit.src_area.y1 + draw_area_h; + blit.src_area.x2 = blit.src_area.x1 + draw_area_w - 1; + blit.src_area.y2 = blit.src_area.y1 + draw_area_h - 1; blit.dst = disp_buf; blit.dst_width = lv_area_get_width(disp_area); @@ -710,8 +710,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col blit.dst_stride = lv_area_get_width(disp_area) * sizeof(lv_color_t); blit.dst_area.x1 = draw_area->x1; blit.dst_area.y1 = draw_area->y1; - blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w; - blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h; + blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w - 1; + blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h - 1; blit.opa = opa; @@ -751,8 +751,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col blit.src_stride = lv_area_get_width(map_area) * sizeof(lv_color_t); blit.src_area.x1 = (draw_area->x1 - (map_area->x1 - disp_area->x1)); blit.src_area.y1 = (draw_area->y1 - (map_area->y1 - disp_area->y1)); - blit.src_area.x2 = blit.src_area.x1 + draw_area_w; - blit.src_area.y2 = blit.src_area.y1 + draw_area_h; + blit.src_area.x2 = blit.src_area.x1 + draw_area_w - 1; + blit.src_area.y2 = blit.src_area.y1 + draw_area_h - 1; blit.dst = disp_buf; blit.dst_width = lv_area_get_width(disp_area); @@ -760,8 +760,8 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col blit.dst_stride = lv_area_get_width(disp_area) * sizeof(lv_color_t); blit.dst_area.x1 = draw_area->x1; blit.dst_area.y1 = draw_area->y1; - blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w; - blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h; + blit.dst_area.x2 = blit.dst_area.x1 + draw_area_w - 1; + blit.dst_area.y2 = blit.dst_area.y1 + draw_area_h - 1; blit.opa = opa; diff --git a/src/gpu/lv_gpu_nxp_pxp.c b/src/gpu/lv_gpu_nxp_pxp.c index 97753e822..1b669d861 100644 --- a/src/gpu/lv_gpu_nxp_pxp.c +++ b/src/gpu/lv_gpu_nxp_pxp.c @@ -71,8 +71,6 @@ static void lv_gpu_nxp_pxp_run(void); static void lv_gpu_nxp_pxp_blit_recolor(lv_color_t * dest, lv_coord_t dest_width, const lv_color_t * src, lv_coord_t src_width, lv_coord_t copy_width, lv_coord_t copy_height, lv_opa_t opa, lv_color_t recolor, lv_opa_t recolorOpa); -static void lv_gpu_nxp_invalidate_cache(uint32_t address, uint32_t width, uint32_t height, uint32_t stride, - uint32_t pxSize); /********************** * STATIC VARIABLES @@ -160,8 +158,7 @@ void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_width, const lv_ .width = fill_area->x2 - fill_area->x1 + 1, .height = fill_area->y2 - fill_area->y1 + 1, }; - lv_gpu_nxp_invalidate_cache(outputConfig.buffer0Addr, outputConfig.width, outputConfig.height, outputConfig.pitchBytes, - sizeof(lv_color_t)); + PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputConfig); if(opa > LV_OPA_MAX) { @@ -272,9 +269,6 @@ void lv_gpu_nxp_pxp_blit(lv_color_t * dest, lv_coord_t dest_width, const lv_colo PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, copy_width - 1U, copy_height - 1U); PXP_SetAlphaSurfaceBlendConfig(LV_GPU_NXP_PXP_ID, &asBlendConfig); - lv_gpu_nxp_invalidate_cache(asBufferConfig.bufferAddr, copy_width, copy_height, asBufferConfig.pitchBytes, - sizeof(lv_color_t)); - if(colorKeyEnabled) { PXP_SetAlphaSurfaceOverlayColorKey(LV_GPU_NXP_PXP_ID, colorKey, colorKey); } @@ -290,10 +284,7 @@ void lv_gpu_nxp_pxp_blit(lv_color_t * dest, lv_coord_t dest_width, const lv_colo outputBufferConfig.height = copy_height; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - lv_gpu_nxp_invalidate_cache(outputBufferConfig.buffer0Addr, outputBufferConfig.width, outputBufferConfig.height, - outputBufferConfig.pitchBytes, sizeof(lv_color_t)); - - lv_gpu_nxp_pxp_run(); /*Start PXP task*/ + lv_gpu_nxp_pxp_run(); /* Start PXP task */ } /** @@ -349,6 +340,12 @@ void lv_gpu_nxp_pxp_disable_recolor(void) */ static void lv_gpu_nxp_pxp_run(void) { + lv_disp_t * disp = _lv_refr_get_disp_refreshing(); + + if(disp && disp->driver->clean_dcache_cb) { /* Clean & invalidate cache */ + disp->driver->clean_dcache_cb(disp->driver); + } + pxp_cfg.pxp_run(); } @@ -396,9 +393,6 @@ static void lv_gpu_nxp_pxp_blit_recolor(lv_color_t * dest, lv_coord_t dest_width PXP_SetAlphaSurfaceBufferConfig(LV_GPU_NXP_PXP_ID, &asBufferConfig); PXP_SetAlphaSurfacePosition(LV_GPU_NXP_PXP_ID, 0U, 0U, copy_width - 1U, copy_height - 1U); - lv_gpu_nxp_invalidate_cache(asBufferConfig.bufferAddr, copy_width, copy_height, asBufferConfig.pitchBytes, - sizeof(lv_color_t)); - /*Disable PS buffer, use as color generator*/ PXP_SetProcessSurfacePosition(LV_GPU_NXP_PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); PXP_SetProcessSurfaceBackGroundColor(LV_GPU_NXP_PXP_ID, lv_color_to32(recolor)); @@ -413,9 +407,6 @@ static void lv_gpu_nxp_pxp_blit_recolor(lv_color_t * dest, lv_coord_t dest_width outputBufferConfig.height = copy_height; PXP_SetOutputBufferConfig(LV_GPU_NXP_PXP_ID, &outputBufferConfig); - lv_gpu_nxp_invalidate_cache(outputBufferConfig.buffer0Addr, outputBufferConfig.width, outputBufferConfig.height, - outputBufferConfig.pitchBytes, sizeof(lv_color_t)); - pxp_porter_duff_config_t pdConfig; /*Configure Porter-Duff blending - For RGB 565 only!*/ @@ -454,23 +445,4 @@ static void lv_gpu_nxp_pxp_blit_recolor(lv_color_t * dest, lv_coord_t dest_width } } -/** - * @brief Invalidate cache for rectangular area of memory - * - * @param[in] address starting address of area - * @param[in] width width of area in pixels - * @param[in] height height of area in pixels - * @param[in] stride stride in bytes - * @param[in] pxSize pixel size in bytes - */ -static void lv_gpu_nxp_invalidate_cache(uint32_t address, uint32_t width, uint32_t height, uint32_t stride, - uint32_t pxSize) -{ - int y; - - for(y = 0; y < height; y++) { - DCACHE_CleanInvalidateByRange(address, width * pxSize); - address += stride; - } -} -#endif /*LV_USE_GPU && LV_USE_GPU_NXP_PXP*/ +#endif /* LV_USE_GPU_NXP_PXP */ diff --git a/src/gpu/lv_gpu_nxp_pxp.h b/src/gpu/lv_gpu_nxp_pxp.h index 9d3957246..9aba7c27d 100644 --- a/src/gpu/lv_gpu_nxp_pxp.h +++ b/src/gpu/lv_gpu_nxp_pxp.h @@ -61,6 +61,11 @@ extern "C" { #define LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT 16 #endif +#ifndef LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT +/** Minimum invalidated area (in pixels) to be synchronized by PXP during buffer sync */ +#define LV_GPU_NXP_PXP_BUFF_SYNC_BLIT_SIZE_LIMIT 32 +#endif + #ifndef LV_GPU_NXP_PXP_FILL_SIZE_LIMIT /** Minimum area (in pixels) to be filled by PXP with 100% opacity*/ #define LV_GPU_NXP_PXP_FILL_SIZE_LIMIT 64 diff --git a/src/gpu/lv_gpu_nxp_pxp_osa.c b/src/gpu/lv_gpu_nxp_pxp_osa.c index 8e56efbf5..d247f2b74 100644 --- a/src/gpu/lv_gpu_nxp_pxp_osa.c +++ b/src/gpu/lv_gpu_nxp_pxp_osa.c @@ -32,13 +32,14 @@ *********************/ #include "../lv_conf_internal.h" +#include "../misc/lv_log.h" #if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT #include "lv_gpu_nxp_pxp.h" #include "fsl_pxp.h" -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) #include "FreeRTOS.h" #include "semphr.h" #endif @@ -62,7 +63,7 @@ static void _lv_gpu_nxp_pxp_run(void); * STATIC VARIABLES **********************/ -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) static SemaphoreHandle_t s_pxpIdle; #else static volatile bool s_pxpIdle; @@ -81,13 +82,13 @@ static void _lv_gpu_nxp_pxp_run(void); */ void PXP_IRQHandler(void) { -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) BaseType_t taskAwake = pdFALSE; #endif if(kPXP_CompleteFlag & PXP_GetStatusFlags(LV_GPU_NXP_PXP_ID)) { PXP_ClearStatusFlags(LV_GPU_NXP_PXP_ID, kPXP_CompleteFlag); -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) xSemaphoreGiveFromISR(s_pxpIdle, &taskAwake); portYIELD_FROM_ISR(taskAwake); #else @@ -106,7 +107,7 @@ void PXP_IRQHandler(void) */ static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void) { -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) s_pxpIdle = xSemaphoreCreateBinary(); if(s_pxpIdle == NULL) { return LV_RES_INV; @@ -128,7 +129,7 @@ static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void) static void _lv_gpu_nxp_pxp_interrupt_deinit(void) { NVIC_DisableIRQ(LV_GPU_NXP_PXP_IRQ_ID); -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) vSemaphoreDelete(s_pxpIdle); #endif } @@ -138,14 +139,14 @@ static void _lv_gpu_nxp_pxp_interrupt_deinit(void) */ static void _lv_gpu_nxp_pxp_run(void) { -#if !defined(FSL_RTOS_FREE_RTOS) +#if !defined(SDK_OS_FREE_RTOS) s_pxpIdle = false; #endif PXP_EnableInterrupts(LV_GPU_NXP_PXP_ID, kPXP_CompleteInterruptEnable); PXP_Start(LV_GPU_NXP_PXP_ID); -#if defined(FSL_RTOS_FREE_RTOS) +#if defined(SDK_OS_FREE_RTOS) if(xSemaphoreTake(s_pxpIdle, portMAX_DELAY) != pdTRUE) { LV_LOG_ERROR("xSemaphoreTake error. Task halted."); for(; ;) ; diff --git a/src/gpu/lv_gpu_nxp_vglite.c b/src/gpu/lv_gpu_nxp_vglite.c index 94ab5ca9a..6021300e7 100644 --- a/src/gpu/lv_gpu_nxp_vglite.c +++ b/src/gpu/lv_gpu_nxp_vglite.c @@ -40,27 +40,78 @@ #include "../misc/lv_log.h" #include "fsl_cache.h" #include "vg_lite.h" +#include "fsl_debug_console.h" /********************* * DEFINES *********************/ -/********************** - * TYPEDEFS - **********************/ - #if LV_COLOR_DEPTH==16 #define VGLITE_PX_FMT VG_LITE_RGB565 #else #error Only 16bit color depth is supported. Set LV_COLOR_DEPTH to 16. #endif +/* Enable BLIT quality degradation workaround for RT595 */ +#define RT595_BLIT_WRKRND_ENABLED 1 + +/* If LV_HOR_RES_MAX/LV_VER_RES_MAX is higher than this value, workaround will be enabled */ +#define RT595_BLIT_WRKRND_THR 352 + +/* Print detailed info to SDK console (NOT to LVGL log system) */ +#define BLIT_DBG_VERBOSE 0 + +/* Draw rectangles around BLIT tiles */ +#define BLIT_DBG_AREAS 0 + +/* Redirect PRINT to SDK PRINTF */ +#define PRINT PRINTF + +/* Verbose debug print */ +#if BLIT_DBG_VERBOSE + #define PRINT_BLT PRINTF +#else + #define PRINT_BLT(...) +#endif + +/* Internal compound symbol */ +#if (defined(CPU_MIMXRT595SFFOB) || defined(CPU_MIMXRT595SFFOB_cm33) || \ + defined(CPU_MIMXRT595SFFOC) || defined(CPU_MIMXRT595SFFOC_cm33)) && \ + ((LV_HOR_RES_MAX > RT595_BLIT_WRKRND_THR) || (LV_VER_RES_MAX > RT595_BLIT_WRKRND_THR)) && \ + RT595_BLIT_WRKRND_ENABLED + #define _BLIT_SPLIT_ENABLED 1 +#else + #define _BLIT_SPLIT_ENABLED 0 +#endif + +/* BLIT split threshold - BLITs with width or height higher than this value will be done + * in multiple steps. Value must be 16-aligned. Don't change. + * */ +#define LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR 352 + + +/********************** + * TYPEDEFS + **********************/ + /********************** * STATIC PROTOTYPES **********************/ -static lv_res_t init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t height, uint32_t stride, - const lv_color_t * ptr); +static lv_res_t _init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t height, uint32_t stride, + const lv_color_t * ptr, bool source); + +static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit); +#if _BLIT_SPLIT_ENABLED +static void _align_x(lv_area_t * area, lv_color_t ** buf); +static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx); +static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit); +#if BLIT_DBG_AREAS +static void _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); +#endif +static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit); +#endif /********************** * STATIC VARIABLES @@ -70,6 +121,14 @@ static lv_res_t init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t hei * MACROS **********************/ +#define CHECK(cond, txt) \ + do { \ + if (cond) { \ + PRINT("%s. STOP!\n", txt); \ + for ( ; ; ); \ + } \ + } while(0) + /********************** * GLOBAL FUNCTIONS **********************/ @@ -94,25 +153,37 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv lv_color32_t col32 = {.full = lv_color_to32(color)}; /*Convert color to RGBA8888*/ lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(init_vg_buf(&rt, dest_width, dest_height, dest_width * sizeof(lv_color_t), dest_buf) != LV_RES_OK) { + if(_init_vg_buf(&rt, (uint32_t) dest_width, (uint32_t) dest_height, (uint32_t) dest_width * sizeof(lv_color_t), (const lv_color_t *) dest_buf, false) != LV_RES_OK) { #if LV_GPU_NXP_VG_LITE_LOG_ERRORS LV_LOG_ERROR("init_vg_buf reported error. Fill failed."); #endif return LV_RES_INV; } - if(opa >= LV_OPA_MAX) { /*Opaque fill*/ + if(opa >= (lv_opa_t) LV_OPA_MAX) { /*Opaque fill*/ rect.x = fill_area->x1; rect.y = fill_area->y1; - rect.width = (fill_area->x2 - fill_area->x1) + 1; - rect.height = (fill_area->y2 - fill_area->y1) + 1; + rect.width = (int32_t) fill_area->x2 - (int32_t) fill_area->x1 + 1; + rect.height = (int32_t) fill_area->y2 - (int32_t) fill_area->y1 + 1; - if(disp && disp->driver->clean_dcache_cb) { /*Clean & invalidate cache*/ + if(disp != NULL && disp->driver->clean_dcache_cb != NULL) { /*Clean & invalidate cache*/ disp->driver->clean_dcache_cb(disp->driver); } - err |= vg_lite_clear(&rt, &rect, col32.full); - err |= vg_lite_finish(); + err = vg_lite_clear(&rt, &rect, col32.full); + if (err != VG_LITE_SUCCESS) { + #if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("vg_lite_clear reported error. Fill failed."); + #endif + return LV_RES_INV; + } + err = vg_lite_finish(); + if (err != VG_LITE_SUCCESS) { + #if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("vg_lite_finish reported error. Fill failed."); + #endif + return LV_RES_INV; + } } else { /*fill with transparency*/ @@ -127,8 +198,8 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv VLC_OP_END }; - err |= vg_lite_init_path(&path, VG_LITE_S16, VG_LITE_LOW, sizeof(path_data), path_data, - fill_area->x1, fill_area->y1, fill_area->x2 + 1, fill_area->y2 + 1); + err = vg_lite_init_path(&path, VG_LITE_S16, VG_LITE_LOW, sizeof(path_data), path_data, + (vg_lite_float_t) fill_area->x1, (vg_lite_float_t) fill_area->y1, ((vg_lite_float_t) fill_area->x2) + 1.0f, ((vg_lite_float_t) fill_area->y2) + 1.0f); if(err != VG_LITE_SUCCESS) { #if LV_GPU_NXP_VG_LITE_LOG_ERRORS LV_LOG_ERROR("vg_lite_init_path() failed."); @@ -136,12 +207,12 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv return LV_RES_INV; } - colMix.ch.red = ((uint16_t)col32.ch.red * opa) >> 8; /*Pre-multiply color*/ - colMix.ch.green = ((uint16_t)col32.ch.green * opa) >> 8; - colMix.ch.blue = ((uint16_t)col32.ch.blue * opa) >> 8; + colMix.ch.red = (uint8_t)(((uint16_t)col32.ch.red * opa) >> 8); /*Pre-multiply color*/ + colMix.ch.green = (uint8_t)(((uint16_t)col32.ch.green * opa) >> 8); + colMix.ch.blue = (uint8_t)(((uint16_t)col32.ch.blue * opa) >> 8); colMix.ch.alpha = opa; - if(disp && disp->driver->clean_dcache_cb) { /*Clean & invalidate cache*/ + if((disp != NULL) && (disp->driver->clean_dcache_cb != NULL)) { /*Clean & invalidate cache*/ disp->driver->clean_dcache_cb(disp->driver); } @@ -149,8 +220,8 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv vg_lite_identity(&matrix); /*Draw rectangle*/ - err |= vg_lite_draw(&rt, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, colMix.full); - if(err) { + err = vg_lite_draw(&rt, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, colMix.full); + if(err != VG_LITE_SUCCESS) { #if LV_GPU_NXP_VG_LITE_LOG_ERRORS LV_LOG_ERROR("vg_lite_draw() failed."); #endif @@ -158,8 +229,21 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv return LV_RES_INV; } - err |= vg_lite_finish(); - err |= vg_lite_clear_path(&path); + err = vg_lite_finish(); + if(err != VG_LITE_SUCCESS) { +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("vg_lite_finish() failed."); +#endif + return LV_RES_INV; + } + + err = vg_lite_clear_path(&path); + if(err != VG_LITE_SUCCESS) { +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("vg_lite_clear_path() failed."); +#endif + return LV_RES_INV; + } } if(err == VG_LITE_SUCCESS) { @@ -180,63 +264,255 @@ lv_res_t lv_gpu_nxp_vglite_fill(lv_color_t * dest_buf, lv_coord_t dest_width, lv * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) */ lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +{ +#if _BLIT_SPLIT_ENABLED + + lv_res_t rv = LV_RES_INV; + + if(_lv_gpu_nxp_vglite_check_blit(blit) != LV_RES_OK) { + PRINT_BLT("Blit check failed\n"); + return LV_RES_INV; + } + + PRINT_BLT("BLIT from: " + "Area: %03d,%03d - %03d,%03d " + "Addr: %d\n\n", + blit->src_area.x1, blit->src_area.y1, + blit->src_area.x2, blit->src_area.y2, + (uintptr_t) blit->src); + + PRINT_BLT("BLIT to: " + "Area: %03d,%03d - %03d,%03d " + "Addr: %d\n\n", + blit->dst_area.x1, blit->dst_area.y1, + blit->dst_area.x2, blit->dst_area.y2, + (uintptr_t) blit->src); + + /* Stage 1: Move starting pointers as close as possible to [x1, y1], so coordinates are as small as possible. */ + _align_x(&blit->src_area, (lv_color_t **)&blit->src); + _align_y(&blit->src_area, (lv_color_t **)&blit->src, blit->src_stride / sizeof(lv_color_t)); + _align_x(&blit->dst_area, (lv_color_t **)&blit->dst); + _align_y(&blit->dst_area, (lv_color_t **)&blit->dst, blit->dst_stride / sizeof(lv_color_t)); + + /* Stage 2: If we're in limit, do a single BLIT */ + if((blit->src_area.x2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) && + (blit->src_area.y2 < LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR)) { + PRINT_BLT("Simple blit!\n"); + return _lv_gpu_nxp_vglite_blit_single(blit); + }; + + /* Stage 3: Split the BLIT into multiple tiles */ + PRINT_BLT("Split blit!\n"); + + PRINT_BLT("Blit " + "([%03d,%03d], [%03d,%03d]) -> " + "([%03d,%03d], [%03d,%03d]) | " + "([%03dx%03d] -> [%03dx%03d]) | " + "A:(%d -> %d)\n", + blit->src_area.x1, blit->src_area.y1, blit->src_area.x2, blit->src_area.y2, + blit->dst_area.x1, blit->dst_area.y1, blit->dst_area.x2, blit->dst_area.y2, + lv_area_get_width(&blit->src_area), lv_area_get_height(&blit->src_area), + lv_area_get_width(&blit->dst_area), lv_area_get_height(&blit->dst_area), + (uintptr_t) blit->src, (uintptr_t) blit->dst); + + + uint32_t totalWidth = lv_area_get_width(&blit->src_area); + uint32_t totalHeight = lv_area_get_height(&blit->src_area); + + lv_gpu_nxp_vglite_blit_info_t tileBlit; + + /* Number of tiles needed */ + int totalTilesX = (blit->src_area.x1 + totalWidth + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + int totalTilesY = (blit->src_area.y1 + totalHeight + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1) / + LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + + /* src and dst buffer shift against each other. Src buffer real data [0,0] may start actually at [3,0] in buffer, as + * the buffer pointer has to be aligned, while dst buffer real data [0,0] may start at [1,0] in buffer. alignment may be + * different */ + int shiftSrcX = (blit->src_area.x1 > blit->dst_area.x1) ? (blit->src_area.x1 - blit->dst_area.x1) : 0; + int shiftDstX = (blit->src_area.x1 < blit->dst_area.x1) ? (blit->dst_area.x1 - blit->src_area.x1) : 0; + + PRINT_BLT("\n"); + PRINT_BLT("Align shift: src: %d, dst: %d\n", shiftSrcX, shiftDstX); + + tileBlit = *blit; + + for(int tileY = 0; tileY < totalTilesY; tileY++) { + + tileBlit.src_area.y1 = 0; /* no vertical alignment, always start from 0 */ + tileBlit.src_area.y2 = totalHeight - tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tileBlit.src_area.y2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tileBlit.src_area.y2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; /* Should never happen */ + } + tileBlit.src = blit->src + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->src_stride / sizeof( + lv_color_t); /* stride in px! */ + + tileBlit.dst_area.y1 = tileBlit.src_area.y1; /* y has no alignment, always in sync with src */ + tileBlit.dst_area.y2 = tileBlit.src_area.y2; + + tileBlit.dst = blit->dst + tileY * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR * blit->dst_stride / sizeof( + lv_color_t); /* stride in px! */ + + for(int tileX = 0; tileX < totalTilesX; tileX++) { + + if(tileX == 0) { + /* 1st tile is special - there may be a gap between buffer start pointer + * and area.x1 value, as the pointer has to be aligned. + * tileBlit.src pointer - keep init value from Y-loop. + * Also, 1st tile start is not shifted! shift is applied from 2nd tile */ + tileBlit.src_area.x1 = blit->src_area.x1; + tileBlit.dst_area.x1 = blit->dst_area.x1; + } + else { + /* subsequent tiles always starts from 0, but shifted*/ + tileBlit.src_area.x1 = 0 + shiftSrcX; + tileBlit.dst_area.x1 = 0 + shiftDstX; + /* and advance start pointer + 1 tile size */ + tileBlit.src += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + tileBlit.dst += LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR; + } + + /* Clip tile end coordinates */ + tileBlit.src_area.x2 = totalWidth + blit->src_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tileBlit.src_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tileBlit.src_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + } + + tileBlit.dst_area.x2 = totalWidth + blit->dst_area.x1 - tileX * LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + if(tileBlit.dst_area.x2 >= LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR) { + tileBlit.dst_area.x2 = LV_GPU_NXP_VG_LITE_BLIT_SPLIT_THR - 1; + } + + if(tileX < (totalTilesX - 1)) { + /* And adjust end coords if shifted, but not for last tile! */ + tileBlit.src_area.x2 += shiftSrcX; + tileBlit.dst_area.x2 += shiftDstX; + } + + rv = _lv_gpu_nxp_vglite_blit_single(&tileBlit); + +#if BLIT_DBG_AREAS + _draw_rectangle((lv_color_t *) tileBlit.dst, tileBlit.dst_width, tileBlit.dst_height, &tileBlit.dst_area, LV_COLOR_RED); + _draw_rectangle((lv_color_t *) tileBlit.src, tileBlit.src_width, tileBlit.src_height, &tileBlit.src_area, + LV_COLOR_GREEN); +#endif + + PRINT_BLT("Tile [%d, %d]: " + "([%d,%d], [%d,%d]) -> " + "([%d,%d], [%d,%d]) | " + "([%dx%d] -> [%dx%d]) | " + "A:(0x%8X -> 0x%8X) %s\n", + tileX, tileY, + tileBlit.src_area.x1, tileBlit.src_area.y1, tileBlit.src_area.x2, tileBlit.src_area.y2, + tileBlit.dst_area.x1, tileBlit.dst_area.y1, tileBlit.dst_area.x2, tileBlit.dst_area.y2, + lv_area_get_width(&tileBlit.src_area), lv_area_get_height(&tileBlit.src_area), + lv_area_get_width(&tileBlit.dst_area), lv_area_get_height(&tileBlit.dst_area), + (uintptr_t) tileBlit.src, (uintptr_t) tileBlit.dst, + rv == LV_RES_OK ? "OK!" : "!!! FAILED !!!"); + + if(rv != LV_RES_OK) { /* if anything goes wrong... */ +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("Split BLIT failed. Trying SW BLIT instead."); +#endif + _sw_blit(&tileBlit); + rv = LV_RES_OK; /* Don't report error, as SW BLIT was performed */ + } + + } + PRINT_BLT(" \n"); + } + + return rv; /* should never fail */ + +#else /* non RT595 */ + /* Just pass down */ + return _lv_gpu_nxp_vglite_blit_single(blit); +#endif +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/*** + * BLock Image Transfer - single direct BLIT. + * @param[in] blit Description of the transfer + * @retval LV_RES_OK Transfer complete + * @retval LV_RES_INV Error occurred (\see LV_GPU_NXP_VG_LITE_LOG_ERRORS) + */ +static lv_res_t _lv_gpu_nxp_vglite_blit_single(lv_gpu_nxp_vglite_blit_info_t * blit) { vg_lite_buffer_t src_vgbuf, dst_vgbuf; vg_lite_error_t err = VG_LITE_SUCCESS; uint32_t rect[4]; lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - if(blit->opa < LV_OPA_MIN) { + if(blit == NULL) { + /*Wrong parameter*/ + return LV_RES_INV; + } + + if(blit->opa < (lv_opa_t) LV_OPA_MIN) { return LV_RES_OK; /*Nothing to BLIT*/ } - if(!blit) { - /*Wrong parameter*/ - return LV_RES_INV; - } - /*Wrap src/dst buffer into VG-Lite buffer*/ - if(init_vg_buf(&src_vgbuf, blit->src_width, blit->src_height, blit->src_stride, blit->src) != LV_RES_OK) { + if(_init_vg_buf(&src_vgbuf, (uint32_t) blit->src_width, (uint32_t) blit->src_height, (uint32_t) blit->src_stride, blit->src, true) != LV_RES_OK) { #if LV_GPU_NXP_VG_LITE_LOG_ERRORS LV_LOG_ERROR("init_vg_buf reported error. BLIT failed."); #endif return LV_RES_INV; } - if(init_vg_buf(&dst_vgbuf, blit->dst_width, blit->dst_height, blit->dst_stride, blit->dst) != LV_RES_OK) { + if(_init_vg_buf(&dst_vgbuf, (uint32_t) blit->dst_width, (uint32_t) blit->dst_height, (uint32_t) blit->dst_stride, blit->dst, false) != LV_RES_OK) { #if LV_GPU_NXP_VG_LITE_LOG_ERRORS LV_LOG_ERROR("init_vg_buf reported error. BLIT failed."); #endif return LV_RES_INV; } - rect[0] = 0; /*Crop*/ - rect[1] = 0; - rect[2] = blit->src_width; - rect[3] = blit->src_height; + rect[0] = (uint32_t) blit->src_area.x1; /* start x */ + rect[1] = (uint32_t) blit->src_area.y1; /* start y */ + rect[2] = (uint32_t) blit->src_area.x2 - (uint32_t) blit->src_area.x1 + 1U; /* width */ + rect[3] = (uint32_t) blit->src_area.y2 - (uint32_t) blit->src_area.y1 + 1U; /* height */ vg_lite_matrix_t matrix; vg_lite_identity(&matrix); - vg_lite_translate(blit->dst_area.x1, blit->dst_area.y1, &matrix); + vg_lite_translate((vg_lite_float_t)blit->dst_area.x1, (vg_lite_float_t)blit->dst_area.y1, &matrix); - if(disp && disp->driver->clean_dcache_cb) { /*Clean & invalidate cache*/ + if((disp != NULL) && (disp->driver->clean_dcache_cb != NULL)) { /*Clean & invalidate cache*/ disp->driver->clean_dcache_cb(disp->driver); } uint32_t color; vg_lite_blend_t blend; - if(blit->opa >= LV_OPA_MAX) { + if(blit->opa >= (uint8_t) LV_OPA_MAX) { color = 0x0; blend = VG_LITE_BLEND_NONE; } else { - color = ((blit->opa) << 24) | ((blit->opa) << 16) | ((blit->opa) << 8) | (blit->opa); + uint32_t opa = (uint32_t) blit->opa; + color = (opa << 24) | (opa << 16) | (opa << 8) | opa; blend = VG_LITE_BLEND_SRC_OVER; src_vgbuf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; } - err |= vg_lite_blit_rect(&dst_vgbuf, &src_vgbuf, rect, &matrix, blend, color, VG_LITE_FILTER_POINT); - err |= vg_lite_finish(); + err = vg_lite_blit_rect(&dst_vgbuf, &src_vgbuf, rect, &matrix, blend, color, VG_LITE_FILTER_POINT); + if(err != VG_LITE_SUCCESS) { +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("vg_lite_blit_rect() failed."); +#endif + return LV_RES_INV; + } + + err = vg_lite_finish(); + if(err != VG_LITE_SUCCESS) { +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("vg_lite_finish() failed."); +#endif + return LV_RES_INV; + } if(err == VG_LITE_SUCCESS) { return LV_RES_OK; @@ -249,10 +525,6 @@ lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit) } } -/********************** - * STATIC FUNCTIONS - **********************/ - /*** * Fills vg_lite_buffer_t structure according given parameters. * @param[out] dst Buffer structure to be filled @@ -261,19 +533,19 @@ lv_res_t lv_gpu_nxp_vglite_blit(lv_gpu_nxp_vglite_blit_info_t * blit) * @param[in] stride Stride of the buffer in bytes * @param[in] ptr Pointer to the buffer (must be aligned according VG-Lite requirements) */ -static lv_res_t init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t height, uint32_t stride, - const lv_color_t * ptr) +static lv_res_t _init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t height, uint32_t stride, + const lv_color_t * ptr, bool source) { - if((((uintptr_t)ptr) % LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0) { /*Test for alignment*/ + if((((uintptr_t)ptr) % (uintptr_t)LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0U) { /*Test for alignment*/ #if LV_GPU_NXP_VG_LITE_LOG_ERRORS LV_LOG_ERROR("ptr (0x%X) not aligned to %d.", (size_t) ptr, LV_ATTRIBUTE_MEM_ALIGN_SIZE); #endif return LV_RES_INV; } - if((stride % LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0x0) { /*Test for stride alignment*/ + if(source && (stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t))) != 0x0U) { /*Test for stride alignment*/ #if LV_GPU_NXP_VG_LITE_LOG_ERRORS - LV_LOG_ERROR("Buffer stride (%d px) not aligned to %d px.", stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); + LV_LOG_ERROR("Buffer stride (%d px) not aligned to %d bytes.", stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * sizeof(lv_color_t)); #endif return LV_RES_INV; } @@ -283,17 +555,205 @@ static lv_res_t init_vg_buf(vg_lite_buffer_t * dst, uint32_t width, uint32_t hei dst->image_mode = VG_LITE_NORMAL_IMAGE_MODE; dst->transparency_mode = VG_LITE_IMAGE_OPAQUE; - dst->width = width; - dst->height = height; - dst->stride = stride; + dst->width = (int32_t) width; + dst->height = (int32_t) height; + dst->stride = (int32_t) stride; - memset(&dst->yuv, 0, sizeof(dst->yuv)); + void *r_ptr = memset(&dst->yuv, 0, sizeof(dst->yuv)); + if (r_ptr == NULL) { + return LV_RES_INV; + } dst->memory = (void *)ptr; dst->address = (uint32_t) dst->memory; - dst->handle = 0x0; + dst->handle = NULL; return LV_RES_OK; } +#if _BLIT_SPLIT_ENABLED + +/** + * Software BLIT as a fall-back scenario + * @param[in] blit BLIT configuration + */ +static void _sw_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +{ + int x, y; + + lv_coord_t w = lv_area_get_width(&blit->src_area); + lv_coord_t h = lv_area_get_height(&blit->src_area); + + uint32_t srcStridePx = blit->src_stride / sizeof(lv_color_t); + uint32_t dstStridePx = blit->dst_stride / sizeof(lv_color_t); + + lv_color_t * src = (lv_color_t *)blit->src + blit->src_area.y1 * srcStridePx + blit->src_area.x1; + lv_color_t * dst = (lv_color_t *)blit->dst + blit->dst_area.y1 * dstStridePx + blit->dst_area.x1; + + if(blit->opa >= LV_OPA_MAX) { + /* simple copy */ + for(y = 0; y < h; y++) { + _lv_memcpy(dst, src, w * sizeof(lv_color_t)); + src += srcStridePx; + dst += dstStridePx; + } + } + else if(blit->opa >= LV_OPA_MIN) { + /* alpha blending */ + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + dst[x] = lv_color_mix(src[x], dst[x], blit->opa); + } + src += srcStridePx; + dst += dstStridePx; + } + } +} + +/** + * Verify BLIT structure - widths, stride, pointer alignment + * @param[in] blit + * @return + */ +static lv_res_t _lv_gpu_nxp_vglite_check_blit(lv_gpu_nxp_vglite_blit_info_t * blit) +{ + + if(lv_area_get_width(&blit->src_area) < LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) { /* Test for minimal width */ +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("source area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->src_area), + LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); +#endif + return LV_RES_INV; + } + + if(lv_area_get_width(&blit->dst_area) < LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) { /* Test for minimal width */ +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("destination area width (%d) is smaller than required (%d).", lv_area_get_width(&blit->dst_area), + LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); +#endif + return LV_RES_INV; + } + + if((((uintptr_t) blit->src) % LV_ATTRIBUTE_MEM_ALIGN_SIZE) != 0x0) { /* Test for pointer alignment */ +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("source buffer ptr (0x%X) not aligned to %d.", (size_t) blit->src, LV_ATTRIBUTE_MEM_ALIGN_SIZE); +#endif + return LV_RES_INV; + } + /* No alignment requirement for destination pixel buffer when using mode VG_LITE_LINEAR */ + + if((blit->src_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0) { /* Test for stride alignment */ +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("source buffer stride (%d px) not aligned to %d px.", blit->src_stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); +#endif + return LV_RES_INV; + } + + if((blit->dst_stride % (LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX * LV_COLOR_DEPTH / 8)) != 0x0) { /* Test for stride alignment */ +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("destination buffer stride (%d px) not aligned to %d px.", blit->dst_stride, LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); +#endif + return LV_RES_INV; + } + + if((lv_area_get_width(&blit->src_area) != lv_area_get_width(&blit->dst_area)) || + (lv_area_get_height(&blit->src_area) != lv_area_get_height(&blit->dst_area))) { +#if LV_GPU_NXP_VG_LITE_LOG_ERRORS + LV_LOG_ERROR("source and destination buffer areas are not equal."); +#endif + return LV_RES_INV; + } + + return LV_RES_OK; +} + +/*** + * Move buffer pointer as close as possible to area, but with respect to alignment requirements. X-axis only. + * @param[in,out] area Area to be updated + * @param[in,out] buf Pointer to be updated + */ +static void _align_x(lv_area_t * area, lv_color_t ** buf) +{ + + int alignedAreaStartPx = area->x1 - (area->x1 % (LV_ATTRIBUTE_MEM_ALIGN_SIZE * 8 / LV_COLOR_DEPTH) ); + CHECK(alignedAreaStartPx < 0, "Should never happen."); + + area->x1 -= alignedAreaStartPx; + area->x2 -= alignedAreaStartPx; + *buf += alignedAreaStartPx; +} + +/*** + * Move buffer pointer to the area start and update variables, Y-axis only. + * @param[in,out] area Area to be updated + * @param[in,out] buf Pointer to be updated + * @param[in] stridePx Buffer stride in pixels + */ +static void _align_y(lv_area_t * area, lv_color_t ** buf, uint32_t stridePx) +{ + int LineToAlignMem; + int alignedAreaStartPy; + /* find how many lines of pixels will respect memory alignment requirement */ + if(stridePx % LV_ATTRIBUTE_MEM_ALIGN_SIZE == 0) { + alignedAreaStartPy = area->y1; + } else { + LineToAlignMem = LV_ATTRIBUTE_MEM_ALIGN_SIZE / (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX); + CHECK(LV_ATTRIBUTE_MEM_ALIGN_SIZE % (sizeof(lv_color_t) * LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX) != 0, "Complex case: need gcd function."); + alignedAreaStartPy = area->y1 - (area->y1 % LineToAlignMem); + CHECK(alignedAreaStartPy < 0, "Should never happen."); + } + + area->y1 -= alignedAreaStartPy; + area->y2 -= alignedAreaStartPy; + *buf += alignedAreaStartPy * stridePx; +} + +#if BLIT_DBG_AREAS +/*** + * Draws a simple rectangle, 1 px line width. + * @param dest_buf Destination buffer + * @param dest_width Destination buffer width (must be aligned on 16px) + * @param dest_height Destination buffer height + * @param fill_area Rectangle coordinates + * @param color Rectangle color + */ +static void _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) +{ + + lv_area_t a; + + /* top line */ + a.x1 = fill_area->x1; + a.x2 = fill_area->x2; + a.y1 = fill_area->y1; + a.y2 = fill_area->y1; + lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); + + + /* bottom line */ + a.x1 = fill_area->x1; + a.x2 = fill_area->x2; + a.y1 = fill_area->y2; + a.y2 = fill_area->y2; + lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); + + /* left line */ + a.x1 = fill_area->x1; + a.x2 = fill_area->x1; + a.y1 = fill_area->y1; + a.y2 = fill_area->y2; + lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); + + /* right line */ + a.x1 = fill_area->x2; + a.x2 = fill_area->x2; + a.y1 = fill_area->y1; + a.y2 = fill_area->y2; + lv_gpu_nxp_vglite_fill(dest_buf, dest_width, dest_height, &a, color, LV_OPA_COVER); +} +#endif /* BLIT_DBG_AREAS */ + +#endif /* _BLIT_SPLIT_ENABLED */ + #endif /*LV_USE_GPU_NXP_VG_LITE*/ diff --git a/src/gpu/lv_gpu_nxp_vglite.h b/src/gpu/lv_gpu_nxp_vglite.h index 3f8b71734..31416598e 100644 --- a/src/gpu/lv_gpu_nxp_vglite.h +++ b/src/gpu/lv_gpu_nxp_vglite.h @@ -43,8 +43,11 @@ extern "C" { * DEFINES *********************/ -/** Stride in px required by VG-Lite HW. Don't change this.*/ -#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16 +/** Use this symbol as limit to disable feature (value has to be larger than supported resolution) */ +#define LV_GPU_NXP_VG_LITE_FEATURE_DISABLED (1920*1080+1) + +/** Stride in px required by VG-Lite HW. Don't change this. */ +#define LV_GPU_NXP_VG_LITE_STRIDE_ALIGN_PX 16U #ifndef LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT /** Minimum area (in pixels) to be filled by VG-Lite with 100% opacity*/ @@ -61,6 +64,11 @@ extern "C" { #define LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT 32 #endif +#ifndef LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT +/** Minimum invalidated area (in pixels) to be synchronized by VG-Lite during buffer sync */ +#define LV_GPU_NXP_VG_LITE_BUFF_SYNC_BLIT_SIZE_LIMIT 32 +#endif + #ifndef LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT /** Minimum area (in pixels) for image copy with transparency to be handled by VG-Lite*/ #define LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT 32 diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 8f8a58691..6abd8bdc6 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -307,7 +307,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/ #endif #if LV_USE_GPU_NXP_PXP /*1: Add default bare metal and FreeRTOS interrupt handling routines for PXP (lv_gpu_nxp_pxp_osa.c) - * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol FSL_RTOS_FREE_RTOS + * and call lv_gpu_nxp_pxp_init() automatically during lv_init(). Note that symbol SDK_OS_FREE_RTOS * has to be defined in order to use FreeRTOS OSA, otherwise bare-metal implementation is selected. *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() */