diff --git a/CHANGELOG.md b/CHANGELOG.md index 602710fe2..342e5e3d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # Changelog -## v7.7.0 (22.09.2020) +## v7.7.0 (06.10.2020) ### New features +- Add PXP GPU support (for NXP MCUs) +- Allow max. 16 cell types for table +- Add `lv_table_set_text_fmt()` + ### Bugfixes @@ -14,6 +18,8 @@ ### Bugfixes - Fix selection of options with non-ASCII letters in dropdown list - Fix font loader to support LV_FONT_FMT_TXT_LARGE +- Fix BIDI support in dropdown list +- Fix copying base dir in lv_obj_craete ## v7.5.0 (15.09.2020) diff --git a/README.md b/README.md index af3a4cde5..7972392d1 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ For more examples see the [lv_examples](https://github.com/lvgl/lv_examples) rep ### Button with label ```c -lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); /*Add a button the current screen*/ +lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL); /*Add a button to the current screen*/ lv_obj_set_pos(btn, 10, 10); /*Set its position*/ lv_obj_set_size(btn, 100, 50); /*Set its size*/ lv_obj_set_event_cb(btn, btn_event_cb); /*Assign a callback to the button*/ diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index eb63f9fe0..cbae70459 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -22,7 +22,6 @@ Planned to September/October 2020 - Simplified File system interface ([feat/new_fs_api](https://github.com/lvgl/lvgl/tree/feat/new-fs-api) branch) to make porting easier - Work in progress - Remove the align parameter from `lv_canvas_draw_text` -- RGB888 support [#1722](https://github.com/lvgl/lvgl/issues/1722) ## v8.1 - Add radio button widget @@ -32,8 +31,11 @@ Planned to September/October 2020 - Unit testing (gtest?). See [#1658](https://github.com/lvgl/lvgl/issues/1658) - Benchmarking (gem5?). See [#1660](https://github.com/lvgl/lvgl/issues/1660) - Consider direct binary font format support +- Remove the copy paramter from create functions ## Ideas +- Text node. See [#1701](https://github.com/lvgl/lvgl/issues/1701#issuecomment-699479408) +- RGB888 support [#1722](https://github.com/lvgl/lvgl/issues/1722) - CPP binding. See [Forum](https://forum.lvgl.io/t/is-it-possible-to-officially-support-optional-cpp-api/2736) - Optmize font decompression - Switch to RGBA colors in styles diff --git a/lv_conf_template.h b/lv_conf_template.h index 8997a9985..112688290 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -195,6 +195,17 @@ typedef void * lv_group_user_data_t; e.g. "stm32f769xx.h" or "stm32f429xx.h" */ #define LV_GPU_DMA2D_CMSIS_INCLUDE +/*1: Use PXP for CPU off-load on NXP RTxxx platforms */ +#define LV_USE_GPU_NXP_PXP 0 + +/*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 to use FreeRTOS OSA, otherwise bare-metal implementation is selected. + *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() + * */ +#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 + + /* 1: Enable file system (might be required for images */ #define LV_USE_FILESYSTEM 1 #if LV_USE_FILESYSTEM diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 6c3fca221..487cecdb7 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -476,6 +476,20 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ # endif #endif +/*1: Use PXP for CPU off-load on NXP RTxxx platforms */ +#ifndef LV_USE_GPU_NXP_PXP +#define LV_USE_GPU_NXP_PXP 0 +#endif + +/*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 to use FreeRTOS OSA, otherwise bare-metal implementation is selected. + *0: lv_gpu_nxp_pxp_init() has to be called manually before lv_init() + * */ +#ifndef LV_USE_GPU_NXP_PXP_AUTO_INIT +#define LV_USE_GPU_NXP_PXP_AUTO_INIT 0 +#endif + /* 1: Enable file system (might be required for images */ #ifndef LV_USE_FILESYSTEM # ifdef CONFIG_LV_USE_FILESYSTEM @@ -1251,7 +1265,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h" */ /* Support bidirectional texts. * Allows mixing Left-to-Right and Right-to-Left texts. - * The direction will be processed according to the Unicode Bidirectioanl Algorithm: + * The direction will be processed according to the Unicode Bidirectional Algorithm: * https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/ #ifndef LV_USE_BIDI # ifdef CONFIG_LV_USE_BIDI diff --git a/src/lv_core/lv_disp.c b/src/lv_core/lv_disp.c index 89ff8b6e5..10536d176 100644 --- a/src/lv_core/lv_disp.c +++ b/src/lv_core/lv_disp.c @@ -120,7 +120,6 @@ lv_obj_t * lv_disp_get_layer_sys(lv_disp_t * disp) return disp->sys_layer; } - /** * Assign a screen to a display. * @param disp pointer to a display where to assign the screen diff --git a/src/lv_core/lv_disp.h b/src/lv_core/lv_disp.h index 3083c46d2..00a9de8db 100644 --- a/src/lv_core/lv_disp.h +++ b/src/lv_core/lv_disp.h @@ -184,7 +184,6 @@ static inline void lv_scr_load(lv_obj_t * scr) lv_disp_load_scr(scr); } - /********************** * MACROS **********************/ diff --git a/src/lv_core/lv_obj.h b/src/lv_core/lv_obj.h index a6ed06d50..7e57432af 100644 --- a/src/lv_core/lv_obj.h +++ b/src/lv_core/lv_obj.h @@ -806,11 +806,11 @@ bool _lv_debug_check_obj_valid(const lv_obj_t * obj); # if LV_USE_ASSERT_NULL /*Use at least LV_ASSERT_NULL if enabled*/ # define LV_ASSERT_OBJ(obj_p, obj_type) LV_ASSERT_NULL(obj_p) # else -# define LV_ASSERT_OBJ(obj_p, obj_type) true +# define LV_ASSERT_OBJ(obj_p, obj_type) # endif # endif #else -# define LV_ASSERT_OBJ(obj, obj_type) true +# define LV_ASSERT_OBJ(obj, obj_type) #endif diff --git a/src/lv_core/lv_style.h b/src/lv_core/lv_style.h index c72cf906f..96c87bb0e 100644 --- a/src/lv_core/lv_style.h +++ b/src/lv_core/lv_style.h @@ -641,13 +641,13 @@ bool lv_debug_check_style_list(const lv_style_list_t * list); # define LV_ASSERT_STYLE_LIST(list_p) LV_DEBUG_ASSERT(LV_DEBUG_IS_STYLE_LIST(list_p), "Invalid style list", list_p); # endif # else -# define LV_ASSERT_STYLE(style_p) true -# define LV_ASSERT_STYLE_LIST(list_p) true +# define LV_ASSERT_STYLE(style_p) +# define LV_ASSERT_STYLE_LIST(list_p) # endif #else -# define LV_ASSERT_STYLE(p) true -# define LV_ASSERT_STYLE_LIST(p) true +# define LV_ASSERT_STYLE(p) +# define LV_ASSERT_STYLE_LIST(p) #endif #ifdef __cplusplus diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index 109246556..618431a3d 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -12,13 +12,18 @@ #include "../lv_hal/lv_hal_disp.h" #include "../lv_core/lv_refr.h" +#if LV_USE_GPU_NXP_PXP +#include "../lv_gpu/lv_gpu_nxp_pxp.h" +#elif LV_USE_GPU_STM32_DMA2D #include "../lv_gpu/lv_gpu_stm32_dma2d.h" +#endif /********************* * DEFINES *********************/ #define GPU_SIZE_LIMIT 240 + /********************** * TYPEDEFS **********************/ @@ -335,9 +340,12 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co disp->driver.gpu_fill_cb(&disp->driver, disp_buf, disp_w, draw_area, color); return; } -#endif - -#if LV_USE_GPU_STM32_DMA2D +#elif LV_USE_GPU_NXP_PXP + if(lv_area_get_size(draw_area) >= GPU_NXP_PXP_FILL_SIZE_LIMIT) { + lv_gpu_nxp_pxp_fill(disp_buf, disp_w, draw_area, color, opa); + return; + } +#elif LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { lv_gpu_stm32_dma2d_fill(disp_buf_first, disp_w, color, draw_area_w, draw_area_h); return; @@ -351,7 +359,13 @@ LV_ATTRIBUTE_FAST_MEM static void fill_normal(const lv_area_t * disp_area, lv_co } /*No mask with opacity*/ else { -#if LV_USE_GPU + +#if LV_USE_GPU_NXP_PXP + if(lv_area_get_size(draw_area) >= GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT) { + lv_gpu_nxp_pxp_fill(disp_buf, disp_w, draw_area, color, opa); + return; + } +#elif LV_USE_GPU if(disp->driver.gpu_blend_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) { for(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full; @@ -726,11 +740,16 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col #endif if(opa > LV_OPA_MAX) { -#if LV_USE_GPU_STM32_DMA2D - if(lv_area_get_size(draw_area) >= 240) { - lv_gpu_stm32_dma2d_copy(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h); - return; - } +#if LV_USE_GPU_NXP_PXP + if (lv_area_get_size(draw_area) >= GPU_NXP_PXP_BLIT_SIZE_LIMIT) { + lv_gpu_nxp_pxp_blit(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h, opa); + return; + } +#elif LV_USE_GPU_STM32_DMA2D + if(lv_area_get_size(draw_area) >= 240) { + lv_gpu_stm32_dma2d_copy(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h); + return; + } #endif /*Software rendering*/ @@ -741,7 +760,12 @@ LV_ATTRIBUTE_FAST_MEM static void map_normal(const lv_area_t * disp_area, lv_col } } else { -#if LV_USE_GPU_STM32_DMA2D +#if LV_USE_GPU_NXP_PXP + if (lv_area_get_size(draw_area) >= GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT) { + lv_gpu_nxp_pxp_blit(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h, opa); + return; + } +#elif LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { lv_gpu_stm32_dma2d_blend(disp_buf_first, disp_w, map_buf_first, opa, map_w, draw_area_w, draw_area_h); return; diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 47615724a..421cab9b8 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -13,8 +13,11 @@ #include "../lv_core/lv_refr.h" #include "../lv_misc/lv_mem.h" #include "../lv_misc/lv_math.h" +#if LV_USE_GPU_STM32_DMA2D #include "../lv_gpu/lv_gpu_stm32_dma2d.h" - +#elif LV_USE_GPU_NXP_PXP +#include "../lv_gpu/lv_gpu_nxp_pxp.h" +#endif /********************* * DEFINES @@ -355,6 +358,22 @@ LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const _lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa, draw_dsc->blend_mode); } +#if LV_USE_GPU_NXP_PXP + /* Simple case without masking and transformations */ + else if (other_mask_cnt == 0 && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE && alpha_byte == false && + chroma_key == true && draw_dsc->recolor_opa == LV_OPA_TRANSP) { /* copy with color keying (+ alpha) */ + lv_gpu_nxp_pxp_enable_color_key(); + _lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa, + draw_dsc->blend_mode); + lv_gpu_nxp_pxp_disable_color_key(); + } else if (other_mask_cnt == 0 && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE && alpha_byte == false && + chroma_key == false && draw_dsc->recolor_opa != LV_OPA_TRANSP) { /* copy with recolor (+ alpha) */ + lv_gpu_nxp_pxp_enable_recolor(draw_dsc->recolor, draw_dsc->recolor_opa); + _lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa, + draw_dsc->blend_mode); + lv_gpu_nxp_pxp_disable_recolor(); + } +#endif /*In the other cases every pixel need to be checked one-by-one*/ else { /*The pixel size in byte is different if an alpha byte is added too*/ diff --git a/src/lv_draw/lv_draw_mask.c b/src/lv_draw/lv_draw_mask.c index dcd1d4a9f..f7b8bc1ff 100644 --- a/src/lv_draw/lv_draw_mask.c +++ b/src/lv_draw/lv_draw_mask.c @@ -1,7 +1,3 @@ - - - - /** * @file lv_mask.c * diff --git a/src/lv_gpu/lv_gpu_nxp_pxp.c b/src/lv_gpu/lv_gpu_nxp_pxp.c new file mode 100644 index 000000000..7efa6341f --- /dev/null +++ b/src/lv_gpu/lv_gpu_nxp_pxp.c @@ -0,0 +1,474 @@ +/** + * @file lv_gpu_nxp_pxp.c + * + */ + +/** + * MIT License + * + * Copyright (c) 2020 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + + +/********************* + * INCLUDES + *********************/ + +#include "lv_conf.h" + +#if LV_USE_GPU_NXP_PXP + +#include "lvgl.h" +#include "lv_gpu_nxp_pxp.h" +#include "../lv_misc/lv_mem.h" +#include "../lv_misc/lv_log.h" + +#include "fsl_pxp.h" +#include "fsl_cache.h" + +/********************* + * DEFINES + *********************/ + +/* PXP instance ID */ +#define PXP_ID PXP + +#if LV_COLOR_16_SWAP + #error Color swap not implemented. Disable LV_COLOR_16_SWAP feature. +#endif + +#if LV_COLOR_DEPTH==16 + #define PXP_OUT_PIXEL_FORMAT kPXP_OutputPixelFormatRGB565 + #define PXP_AS_PIXEL_FORMAT kPXP_AsPixelFormatRGB565 + #define PXP_PS_PIXEL_FORMAT kPXP_PsPixelFormatRGB565 +#elif + #error Only 16bit color depth is supported. Set LV_COLOR_DEPTH to 16. +#endif + + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +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 + **********************/ + +static bool colorKeyEnabled = false; +static uint32_t colorKey = 0x0; + +static bool recolorEnabled = false; +static lv_color_t recolor = {.full = 0x0}; +static lv_opa_t recolorOpa = 0x0; + +static lv_nxp_pxp_cfg_t pxp_cfg; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Reset and initialize PXP device. This function should be called as a part + * of display init sequence. + * + * @return LV_RES_OK: PXP init ok; LV_RES_INV: init error. See error log for more information. + */ +lv_res_t lv_gpu_nxp_pxp_init(lv_nxp_pxp_cfg_t * cfg) +{ + if(!cfg || !cfg->pxp_interrupt_deinit || !cfg->pxp_interrupt_init || !cfg->pxp_run) { + LV_LOG_ERROR("PXP configuration error. Check callback pointers."); + return LV_RES_INV; + } + + PXP_Init(PXP); + PXP_EnableCsc1(PXP, false); /* Disable CSC1, it is enabled by default. */ + PXP_EnableInterrupts(PXP, kPXP_CompleteInterruptEnable); + + pxp_cfg = *cfg; + if(pxp_cfg.pxp_interrupt_init() != LV_RES_OK) { + PXP_Deinit(PXP); + LV_LOG_ERROR("PXP interrupt init error. Check pxp_interrupt_init callback."); + return LV_RES_INV; + } + + colorKey = lv_color_to32(LV_COLOR_TRANSP); + + return LV_RES_OK; +} + +/** + * Disable PXP device. Should be called during display deinit sequence. + */ +void lv_gpu_nxp_pxp_deinit(void) +{ + pxp_cfg.pxp_interrupt_deinit(); + PXP_DisableInterrupts(PXP, kPXP_CompleteInterruptEnable); + PXP_Deinit(PXP_ID); +} + + +/** + * Fill area, with optional opacity. + * + * @param[in/out] dest_buf destination buffer + * @param[in] dest_width width (stride) of destination buffer in pixels + * @param[in] fill_area area to fill + * @param[in] color color + * @param[in] opa transparency of the color + */ +void lv_gpu_nxp_pxp_fill(lv_color_t * dest_buf, lv_coord_t dest_width, const lv_area_t * fill_area, lv_color_t color, + lv_opa_t opa) +{ + PXP_Init(PXP_ID); + PXP_EnableCsc1(PXP_ID, false); /* Disable CSC1, it is enabled by default. */ + PXP_SetProcessBlockSize(PXP, kPXP_BlockSize16); /* Block size 16x16 for higher performance */ + + /* OUT buffer configure */ + pxp_output_buffer_config_t outputConfig = { + .pixelFormat = PXP_OUT_PIXEL_FORMAT, + .interlacedMode = kPXP_OutputProgressive, + .buffer0Addr = (uint32_t)(dest_buf + dest_width * fill_area->y1 + fill_area->x1), + .buffer1Addr = (uint32_t)NULL, + .pitchBytes = dest_width * sizeof(lv_color_t), + .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(PXP_ID, &outputConfig); + + if(opa > LV_OPA_MAX) { + /* Simple color fill without opacity - AS disabled, PS as color generator */ + PXP_SetAlphaSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); /* Disable AS. */ + PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); /* Disable PS. */ + PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to32(color)); + } + else { + /* Fill with opacity - AS used as source (same as OUT), PS used as color generator, blended together */ + pxp_as_buffer_config_t asBufferConfig; + pxp_porter_duff_config_t pdConfig; + + /* Set AS to OUT */ + asBufferConfig.pixelFormat = PXP_AS_PIXEL_FORMAT; + asBufferConfig.bufferAddr = (uint32_t)outputConfig.buffer0Addr; + asBufferConfig.pitchBytes = outputConfig.pitchBytes; + + PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig); + PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, fill_area->x2 - fill_area->x1 + 1, fill_area->y2 - fill_area->y1 + 1); + + /* Disable PS, use as color generator */ + PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); + PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to32(color)); + + /* Configure Porter-Duff blending - For RGB 565 only! */ + pdConfig.enable = 1; + pdConfig.dstColorMode = kPXP_PorterDuffColorStraight; + pdConfig.srcColorMode = kPXP_PorterDuffColorStraight; + pdConfig.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha; + pdConfig.srcGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha; + pdConfig.srcFactorMode = kPXP_PorterDuffFactorStraight; + pdConfig.dstFactorMode = kPXP_PorterDuffFactorStraight; + pdConfig.srcGlobalAlpha = opa; + pdConfig.dstGlobalAlpha = 255 - opa; + pdConfig.srcAlphaMode = kPXP_PorterDuffAlphaStraight; /* don't care */ + pdConfig.dstAlphaMode = kPXP_PorterDuffAlphaStraight; /* don't care */ + PXP_SetPorterDuffConfig(PXP_ID, &pdConfig); + } + + lv_gpu_nxp_pxp_run(); /* Start PXP task */ +} + +/** + * @brief BLock Image Transfer - copy rectangular image from src buffer to dst buffer with effects. + * + * By default, image is copied directly, with optional opacity configured by \p opa. + * Color keying can be enabled by calling lv_gpu_nxp_pxp_enable_color_key() before calling this function. + * Recoloring can be enabled by calling lv_gpu_nxp_pxp_enable_recolor() before calling this function. + * Note that color keying and recoloring at the same time is not supported and black rectangle is rendered. + * + * @param[in/out] dest destination buffer + * @param[in] dest_width width (stride) of destination buffer in pixels + * @param[in] src source buffer + * @param[in] src_with width (stride) of source buffer in pixels + * @param[in] copy_w width of area to be copied from src to dest + * @param[in] copy_h height of area to be copied from src to dest + * @param[in] opa opacity of the result + */ +void lv_gpu_nxp_pxp_blit(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) +{ + + if(recolorEnabled) { /* switch to recolor version of blit */ + lv_gpu_nxp_pxp_blit_recolor(dest, dest_width, src, src_width, copy_width, copy_height, opa, recolor, recolorOpa); + return; + }; + + PXP_Init(PXP); + PXP_EnableCsc1(PXP, false); /* Disable CSC1, it is enabled by default. */ + PXP_SetProcessBlockSize(PXP, kPXP_BlockSize16); /* block size 16x16 for higher performance */ + + pxp_output_buffer_config_t outputBufferConfig; + pxp_as_buffer_config_t asBufferConfig; + pxp_as_blend_config_t asBlendConfig; + + asBlendConfig.alpha = opa; + asBlendConfig.invertAlpha = false; + asBlendConfig.alphaMode = kPXP_AlphaRop; + asBlendConfig.ropMode = kPXP_RopMergeAs; + + if(opa >= LV_OPA_MAX && !colorKeyEnabled) { + /* Simple blit, no effect - Disable PS buffer */ + PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); + } + else { + /* Alpha blending or color keying enabled - PS must be enabled to fetch background pixels + PS and OUT buffers are the same, blend will be done in-place */ + pxp_ps_buffer_config_t psBufferConfig = { + .pixelFormat = PXP_PS_PIXEL_FORMAT, + .swapByte = false, + .bufferAddr = (uint32_t)dest, + .bufferAddrU = 0U, + .bufferAddrV = 0U, + .pitchBytes = dest_width * sizeof(lv_color_t) + }; + asBlendConfig.alphaMode = kPXP_AlphaOverride; + PXP_SetProcessSurfaceBufferConfig(PXP_ID, &psBufferConfig); + PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, copy_width - 1, copy_height - 1); + } + + /* AS buffer - source image */ + asBufferConfig.pixelFormat = PXP_AS_PIXEL_FORMAT; + asBufferConfig.bufferAddr = (uint32_t)src; + asBufferConfig.pitchBytes = src_width * sizeof(lv_color_t); + PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig); + PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, copy_width - 1U, copy_height - 1U); + PXP_SetAlphaSurfaceBlendConfig(PXP_ID, &asBlendConfig); + + lv_gpu_nxp_invalidate_cache(asBufferConfig.bufferAddr, copy_width, copy_height, asBufferConfig.pitchBytes, sizeof(lv_color_t)); + + if(colorKeyEnabled) { + PXP_SetAlphaSurfaceOverlayColorKey(PXP_ID, colorKey, colorKey); + } + PXP_EnableAlphaSurfaceOverlayColorKey(PXP_ID, colorKeyEnabled); + + + /* Output buffer. */ + outputBufferConfig.pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT; + outputBufferConfig.interlacedMode = kPXP_OutputProgressive; + outputBufferConfig.buffer0Addr = (uint32_t)dest; + outputBufferConfig.buffer1Addr = (uint32_t)0U; + outputBufferConfig.pitchBytes = dest_width * sizeof(lv_color_t); + outputBufferConfig.width = copy_width; + outputBufferConfig.height = copy_height; + PXP_SetOutputBufferConfig(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 */ +} + +/** + * @brief Enable color keying for subsequent calls to lv_gpu_nxp_pxp_blit() + * + * Color key is defined by LV_COLOR_TRANSP symbol in lv_conf.h + */ +void lv_gpu_nxp_pxp_enable_color_key(void) +{ + colorKeyEnabled = true; +} + +/** + * @brief Disable color keying for subsequent calls to lv_gpu_nxp_pxp_blit() + * + */ +void lv_gpu_nxp_pxp_disable_color_key(void) +{ + colorKeyEnabled = false; +} + +/** + * @brief Enable recolor feature for subsequent calls to lv_gpu_nxp_pxp_blit() + * + * @param[in] color recolor value + * @param[in] opa effect opacity + */ +void lv_gpu_nxp_pxp_enable_recolor(lv_color_t color, lv_opa_t opa) +{ + recolorEnabled = true; + recolor = color; + recolorOpa = opa; + +} + +/** + * @brief Disable recolor feature for subsequent calls to lv_gpu_nxp_pxp_blit() + */ +void lv_gpu_nxp_pxp_disable_recolor(void) +{ + recolorEnabled = false; +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * @brief Start PXP job and wait for results + * + * Function used internally to start PXP task according current device + * configuration. + */ +static void lv_gpu_nxp_pxp_run(void) +{ + pxp_cfg.pxp_run(); +} + +/** + * @brief BLock Image Transfer - copy rectangular image from src buffer to dst buffer with recoloring. + * + * Note that color keying and recoloring at the same time is not supported and black rectangle is rendered. + * + * @param[in/out] dest destination buffer + * @param[in] dest_width width (stride) of destination buffer in pixels + * @param[in] src source buffer + * @param[in] src_with width (stride) of source buffer in pixels + * @param[in] copy_w width of area to be copied from src to dest + * @param[in] copy_h height of area to be copied from src to dest + * @param[in] opa opacity of the result + * @param[in] recolor recolor value + * @param[in] recolorOpa effect opacity + */ +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) +{ + pxp_output_buffer_config_t outputBufferConfig; + pxp_as_buffer_config_t asBufferConfig; + + if(colorKeyEnabled) { + /* should never get here, recolor & color keying not supported. Draw black box instead. */ + const lv_area_t fill_area = {.x1 = 0, .y1 = 0, .x2 = copy_width - 1, .y2 = copy_height - 1}; + lv_gpu_nxp_pxp_fill(dest, dest_width, &fill_area, LV_COLOR_BLACK, LV_OPA_MAX); + LV_LOG_WARN("Recoloring and color keying is not supported. Black rectangle rendered."); + return ; + } + else { + /* Recoloring without color keying */ + if(opa > LV_OPA_MAX) { + /* Recolor with full opacity - AS source image, PS color generator, OUT destination */ + PXP_Init(PXP); + PXP_EnableCsc1(PXP, false); /* Disable CSC1, it is enabled by default. */ + PXP_SetProcessBlockSize(PXP, kPXP_BlockSize16); /* block size 16x16 for higher performance */ + + /* AS buffer - source image */ + asBufferConfig.pixelFormat = PXP_AS_PIXEL_FORMAT; + asBufferConfig.bufferAddr = (uint32_t)src; + asBufferConfig.pitchBytes = src_width * sizeof(lv_color_t); + PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig); + PXP_SetAlphaSurfacePosition(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(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); + PXP_SetProcessSurfaceBackGroundColor(PXP_ID, lv_color_to32(recolor)); + + /* Output buffer */ + outputBufferConfig.pixelFormat = (pxp_output_pixel_format_t)PXP_OUT_PIXEL_FORMAT; + outputBufferConfig.interlacedMode = kPXP_OutputProgressive; + outputBufferConfig.buffer0Addr = (uint32_t)dest; + outputBufferConfig.buffer1Addr = (uint32_t)0U; + outputBufferConfig.pitchBytes = dest_width * sizeof(lv_color_t); + outputBufferConfig.width = copy_width; + outputBufferConfig.height = copy_height; + PXP_SetOutputBufferConfig(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! */ + pdConfig.enable = 1; + pdConfig.dstColorMode = kPXP_PorterDuffColorStraight; + pdConfig.srcColorMode = kPXP_PorterDuffColorStraight; + pdConfig.dstGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha; + pdConfig.srcGlobalAlphaMode = kPXP_PorterDuffGlobalAlpha; + pdConfig.srcFactorMode = kPXP_PorterDuffFactorStraight; + pdConfig.dstFactorMode = kPXP_PorterDuffFactorStraight; + pdConfig.srcGlobalAlpha = recolorOpa; + pdConfig.dstGlobalAlpha = 255 - recolorOpa; + pdConfig.srcAlphaMode = kPXP_PorterDuffAlphaStraight; /* don't care */ + pdConfig.dstAlphaMode = kPXP_PorterDuffAlphaStraight; /* don't care */ + PXP_SetPorterDuffConfig(PXP_ID, &pdConfig); + + lv_gpu_nxp_pxp_run(); /* Start PXP task */ + + } + else { + /* Recolor with transparency */ + + /* Step 1: Recolor with full opacity to temporary buffer */ + lv_color_t * tmpBuf = (lv_color_t *) _lv_mem_buf_get(copy_width * copy_height * sizeof(lv_color_t)); + lv_gpu_nxp_pxp_blit_recolor(tmpBuf, copy_width, src, src_width, copy_width, copy_height, LV_OPA_COVER, recolor, + recolorOpa); + + /* Step 2: BLIT temporary results with required opacity to output */ + lv_gpu_nxp_pxp_disable_recolor(); /* make sure to take BLIT path, not the recolor */ + lv_gpu_nxp_pxp_blit(dest, dest_width, tmpBuf, copy_width, copy_width, copy_height, opa); + lv_gpu_nxp_pxp_enable_recolor(recolor, recolorOpa); /* restore state */ + + /* Step 3: Clean-up memory */ + _lv_mem_buf_release(tmpBuf); + } + } +} + +/** + * @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 */ diff --git a/src/lv_gpu/lv_gpu_nxp_pxp.h b/src/lv_gpu/lv_gpu_nxp_pxp.h new file mode 100644 index 000000000..10207dd30 --- /dev/null +++ b/src/lv_gpu/lv_gpu_nxp_pxp.h @@ -0,0 +1,184 @@ +/** + * @file lv_gpu_nxp_pxp.h + * + */ + +/** + * MIT License + * + * Copyright (c) 2020 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_SRC_LV_GPU_LV_GPU_NXP_PXP_H_ +#define LV_SRC_LV_GPU_LV_GPU_NXP_PXP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_color.h" + +/********************* + * DEFINES + *********************/ + +/* PXP module instance to use */ +#define PXP_ID PXP + +/* PXP interrupt line ID */ +#define PXP_IRQ_ID PXP_IRQn + +/* Minimum area for image copy with 100% opacity to be handled by PXP */ +#ifndef GPU_NXP_PXP_BLIT_SIZE_LIMIT +#define GPU_NXP_PXP_BLIT_SIZE_LIMIT 1 +#endif + +/* Minimum area for image copy with transparency to be handled by PXP */ +#ifndef GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT +#define GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT 16 +#endif + +/* Minimum area to be filled by PXP with 100% opacity */ +#ifndef GPU_NXP_PXP_FILL_SIZE_LIMIT +#define GPU_NXP_PXP_FILL_SIZE_LIMIT 64 +#endif + +/* Minimum area to be filled by PXP with transparency */ +#ifndef GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT +#define GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT 32 +#endif + +/********************** + * TYPEDEFS + **********************/ +/** + * NXP PXP device configuration - call-backs used for + * interrupt init/wait/deinit. + */ +typedef struct { + /** Callback for PXP interrupt initialization */ + lv_res_t (*pxp_interrupt_init)(void); + + /** Callback for PXP interrupt de-initialization */ + void (*pxp_interrupt_deinit)(void); + + /** Callback that should start PXP and wait for operation complete */ + void (*pxp_run)(void); +} lv_nxp_pxp_cfg_t; + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * Reset and initialize PXP device. This function should be called as a part + * of display init sequence. + * + * @return LV_RES_OK: PXP init ok; LV_RES_INV: init error. See error log for more information. + */ +lv_res_t lv_gpu_nxp_pxp_init(lv_nxp_pxp_cfg_t *cfg); + +/** + * Disable PXP device. Should be called during display deinit sequence. + */ +void lv_gpu_nxp_pxp_deinit(void); + +/** + * Fill area, with optional opacity. + * + * @param[in/out] dest_buf destination buffer + * @param[in] dest_width width (stride) of destination buffer in pixels + * @param[in] fill_area area to fill + * @param[in] color color + * @param[in] opa transparency of the color + */ +void lv_gpu_nxp_pxp_fill(lv_color_t *dest_buf, lv_coord_t dest_width, const lv_area_t *fill_area, lv_color_t color, lv_opa_t opa); + + + +/** + * @brief BLock Image Transfer - copy rectangular image from src buffer to dst buffer with effects. + * + * By default, image is copied directly, with optional opacity configured by \p opa. + * Color keying can be enabled by calling lv_gpu_nxp_pxp_enable_color_key() before calling this function. + * Recoloring can be enabled by calling lv_gpu_nxp_pxp_enable_recolor() before calling this function. + * Note that color keying and recoloring at the same time is not supported and black rectangle is rendered. + * + * @param[in/out] dest destination buffer + * @param[in] dest_width width (stride) of destination buffer in pixels + * @param[in] src source buffer + * @param[in] src_with width (stride) of source buffer in pixels + * @param[in] copy_w width of area to be copied from src to dest + * @param[in] copy_h height of area to be copied from src to dest + * @param[in] opa opacity of the result + */ +void lv_gpu_nxp_pxp_blit(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); + + +/** + * @brief Enable color keying for subsequent calls to lv_gpu_nxp_pxp_blit() + * + * Color key is defined by LV_COLOR_TRANSP symbol in lv_conf.h + */ +void lv_gpu_nxp_pxp_enable_color_key(void); + +/** + * @brief Disable color keying for subsequent calls to lv_gpu_nxp_pxp_blit() + * + */ +void lv_gpu_nxp_pxp_disable_color_key(void); + + +/** + * @brief Enable recolor feature for subsequent calls to lv_gpu_nxp_pxp_blit() + * + * @param[in] color recolor value + * @param[in] opa effect opacity + */ +void lv_gpu_nxp_pxp_enable_recolor(lv_color_t color, lv_opa_t opa); + +/** + * @brief Disable recolor feature for subsequent calls to lv_gpu_nxp_pxp_blit() + */ +void lv_gpu_nxp_pxp_disable_recolor(void); + +/********************** + * STATIC FUNCTIONS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_SRC_LV_GPU_LV_GPU_NXP_PXP_H_ */ diff --git a/src/lv_gpu/lv_gpu_nxp_pxp_osa.c b/src/lv_gpu/lv_gpu_nxp_pxp_osa.c new file mode 100644 index 000000000..eb23fbbe3 --- /dev/null +++ b/src/lv_gpu/lv_gpu_nxp_pxp_osa.c @@ -0,0 +1,166 @@ +/** + * @file lv_gpu_nxp_pxp_osa.c + * + */ + +/** + * MIT License + * + * Copyright (c) 2020 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_conf.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) + #include "FreeRTOS.h" + #include "semphr.h" +#endif + + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ +static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void); +static void _lv_gpu_nxp_pxp_interrupt_deinit(void); +static void _lv_gpu_nxp_pxp_run(void); + +/********************** + * STATIC VARIABLES + **********************/ + +#if defined(FSL_RTOS_FREE_RTOS) + static SemaphoreHandle_t s_pxpIdle; +#else + static volatile bool s_pxpIdle; +#endif + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +/** + * PXP device interrupt handler. Used to check PXP task completion status. + */ +void PXP_IRQHandler(void) +{ +#if defined(FSL_RTOS_FREE_RTOS) + BaseType_t taskAwake = pdFALSE; +#endif + + if(kPXP_CompleteFlag & PXP_GetStatusFlags(PXP_ID)) { + PXP_ClearStatusFlags(PXP_ID, kPXP_CompleteFlag); +#if defined(FSL_RTOS_FREE_RTOS) + xSemaphoreGiveFromISR(s_pxpIdle, &taskAwake); + portYIELD_FROM_ISR(taskAwake); +#else + s_pxpIdle = true; +#endif + + } +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/** + * PXP interrupt initialization. + */ +static lv_res_t _lv_gpu_nxp_pxp_interrupt_init(void) +{ +#if defined(FSL_RTOS_FREE_RTOS) + s_pxpIdle = xSemaphoreCreateBinary(); + if(s_pxpIdle == NULL) { + return LV_RES_INV; + } + + NVIC_SetPriority(PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1); +#else + s_pxpIdle = true; +#endif + + NVIC_EnableIRQ(PXP_IRQ_ID); + + return LV_RES_OK; +} + +/** + * PXP interrupt de-initialization. + */ +static void _lv_gpu_nxp_pxp_interrupt_deinit(void) +{ + NVIC_DisableIRQ(PXP_IRQ_ID); +#if defined(FSL_RTOS_FREE_RTOS) + vSemaphoreDelete(s_pxpIdle); +#endif +} + +/** + * Function to start PXP job. This function must wait for task complete. + */ +static void _lv_gpu_nxp_pxp_run(void) +{ +#if !defined(FSL_RTOS_FREE_RTOS) + s_pxpIdle = false; +#endif + + PXP_EnableInterrupts(PXP_ID, kPXP_CompleteInterruptEnable); + PXP_Start(PXP_ID); + +#if defined(FSL_RTOS_FREE_RTOS) + if(xSemaphoreTake(s_pxpIdle, portMAX_DELAY) != pdTRUE) { + LV_LOG_ERROR("xSemaphoreTake error. Task halted."); + for(; ;) ; + } +#else + while(s_pxpIdle == false) { + } +#endif +} + +lv_nxp_pxp_cfg_t pxp_default_cfg = { + .pxp_interrupt_init = _lv_gpu_nxp_pxp_interrupt_init, + .pxp_interrupt_deinit = _lv_gpu_nxp_pxp_interrupt_deinit, + .pxp_run = _lv_gpu_nxp_pxp_run +}; + +#endif /* LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT */ diff --git a/src/lv_gpu/lv_gpu_nxp_pxp_osa.h b/src/lv_gpu/lv_gpu_nxp_pxp_osa.h new file mode 100644 index 000000000..9a10df9e2 --- /dev/null +++ b/src/lv_gpu/lv_gpu_nxp_pxp_osa.h @@ -0,0 +1,47 @@ +/** + * @file lv_gpu_nxp_pxp_osa.h + * + */ + +/** + * MIT License + * + * Copyright (c) 2020 NXP + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next paragraph) + * shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef LV_SRC_LV_GPU_LV_GPU_NXP_PXP_OSA_H_ +#define LV_SRC_LV_GPU_LV_GPU_NXP_PXP_OSA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lv_conf.h" + +#if LV_USE_GPU_NXP_PXP && LV_USE_GPU_NXP_PXP_AUTO_INIT +extern lv_nxp_pxp_cfg_t pxp_default_cfg; +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_SRC_LV_GPU_LV_GPU_NXP_PXP_OSA_H_ */ diff --git a/src/lv_misc/lv_debug.h b/src/lv_misc/lv_debug.h index 2fa0fb95a..9160ceee8 100644 --- a/src/lv_misc/lv_debug.h +++ b/src/lv_misc/lv_debug.h @@ -81,7 +81,7 @@ void lv_debug_log_error(const char * msg, uint64_t value); # define LV_ASSERT_NULL(p) LV_DEBUG_ASSERT(LV_DEBUG_IS_NULL(p), "NULL pointer", p); # endif #else -# define LV_ASSERT_NULL(p) true +# define LV_ASSERT_NULL(p) #endif #if LV_USE_ASSERT_MEM @@ -89,7 +89,7 @@ void lv_debug_log_error(const char * msg, uint64_t value); # define LV_ASSERT_MEM(p) LV_DEBUG_ASSERT(LV_DEBUG_IS_NULL(p), "Out of memory", p); # endif #else -# define LV_ASSERT_MEM(p) true +# define LV_ASSERT_MEM(p) #endif #if LV_USE_ASSERT_MEM_INTEGRITY @@ -97,7 +97,7 @@ void lv_debug_log_error(const char * msg, uint64_t value); # define LV_ASSERT_MEM_INTEGRITY() LV_DEBUG_ASSERT(LV_DEBUG_CHECK_MEM_INTEGRITY(), "Memory integrity error", 0); # endif #else -# define LV_ASSERT_MEM_INTEGRITY() true +# define LV_ASSERT_MEM_INTEGRITY() #endif #if LV_USE_ASSERT_STR @@ -108,7 +108,7 @@ void lv_debug_log_error(const char * msg, uint64_t value); # if LV_USE_ASSERT_NULL /*Use at least LV_ASSERT_NULL if enabled*/ # define LV_ASSERT_STR(str) LV_ASSERT_NULL(str) # else -# define LV_ASSERT_STR(str) true +# define LV_ASSERT_STR(str) # endif #endif @@ -117,11 +117,11 @@ void lv_debug_log_error(const char * msg, uint64_t value); #define LV_DEBUG_ASSERT(expr, msg, value) do{}while(0) -#define LV_ASSERT_NULL(p) true -#define LV_ASSERT_MEM(p) true -#define LV_ASSERT_MEM_INTEGRITY() true -#define LV_ASSERT_STR(p) true -#define LV_ASSERT_OBJ(obj, obj_type) true +#define LV_ASSERT_NULL(p) +#define LV_ASSERT_MEM(p) +#define LV_ASSERT_MEM_INTEGRITY() +#define LV_ASSERT_STR(p) +#define LV_ASSERT_OBJ(obj, obj_type) #endif /* LV_USE_DEBUG */ /*clang-format on*/ diff --git a/src/lv_misc/lv_log.h b/src/lv_misc/lv_log.h index 7e07712eb..a85427e78 100644 --- a/src/lv_misc/lv_log.h +++ b/src/lv_misc/lv_log.h @@ -79,75 +79,42 @@ void _lv_log_add(lv_log_level_t level, const char * file, int line, const char * #if LV_LOG_LEVEL <= LV_LOG_LEVEL_TRACE #define LV_LOG_TRACE(...) _lv_log_add(LV_LOG_LEVEL_TRACE, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_TRACE(...) \ - { \ - ; \ - } +#define LV_LOG_TRACE(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_INFO #define LV_LOG_INFO(...) _lv_log_add(LV_LOG_LEVEL_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_INFO(...) \ - { \ - ; \ - } +#define LV_LOG_INFO(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_WARN #define LV_LOG_WARN(...) _lv_log_add(LV_LOG_LEVEL_WARN, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_WARN(...) \ - { \ - ; \ - } +#define LV_LOG_WARN(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_ERROR #define LV_LOG_ERROR(...) _lv_log_add(LV_LOG_LEVEL_ERROR, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_ERROR(...) \ - { \ - ; \ - } +#define LV_LOG_ERROR(...) #endif #if LV_LOG_LEVEL <= LV_LOG_LEVEL_USER #define LV_LOG_USER(...) _lv_log_add(LV_LOG_LEVEL_USER, __FILE__, __LINE__, __func__, __VA_ARGS__); #else -#define LV_LOG_USER(...) \ - { \ - ; \ - } +#define LV_LOG_USER(...) #endif #else /*LV_USE_LOG*/ /*Do nothing if `LV_USE_LOG 0`*/ -#define _lv_log_add(level, file, line, ...) \ - { \ - ; \ - } -#define LV_LOG_TRACE(...) \ - { \ - ; \ - } -#define LV_LOG_INFO(...) \ - { \ - ; \ - } -#define LV_LOG_WARN(...) \ - { \ - ; \ - } -#define LV_LOG_ERROR(...) \ - { \ - ; \ - } -#define LV_LOG_USER(...) \ - { \ - ; \ - } +#define _lv_log_add(level, file, line, ...) +#define LV_LOG_TRACE(...) +#define LV_LOG_INFO(...) +#define LV_LOG_WARN(...) +#define LV_LOG_ERROR(...) +#define LV_LOG_USER(...) #endif /*LV_USE_LOG*/ #ifdef __cplusplus diff --git a/src/lv_misc/lv_math.h b/src/lv_misc/lv_math.h index d4d626ef9..3c5600d2b 100644 --- a/src/lv_misc/lv_math.h +++ b/src/lv_misc/lv_math.h @@ -42,8 +42,6 @@ extern "C" { #define LV_BEZIER_VAL_MAX 1024 /**< Max time in Bezier functions (not [0..1] to use integers) */ #define LV_BEZIER_VAL_SHIFT 10 /**< log2(LV_BEZIER_VAL_MAX): used to normalize up scaled values*/ - - /********************** * TYPEDEFS **********************/ diff --git a/src/lv_widgets/lv_bar.c b/src/lv_widgets/lv_bar.c index 4db6d3499..6b3daba42 100644 --- a/src/lv_widgets/lv_bar.c +++ b/src/lv_widgets/lv_bar.c @@ -705,6 +705,7 @@ static void lv_bar_set_value_with_anim(lv_obj_t * bar, int16_t new_value, int16_ anim_info->anim_start = anim_info->anim_end; anim_info->anim_end = new_value; } + *value_ptr = new_value; /* Stop the previous animation if it exists */ lv_anim_del(anim_info, NULL); diff --git a/src/lv_widgets/lv_dropdown.c b/src/lv_widgets/lv_dropdown.c index ea3751f1c..90b2877b5 100644 --- a/src/lv_widgets/lv_dropdown.c +++ b/src/lv_widgets/lv_dropdown.c @@ -621,6 +621,10 @@ void lv_dropdown_open(lv_obj_t * ddlist) lv_obj_set_y(ext->list, lv_obj_get_y(ext->list) - (ext->list->coords.y2 - LV_VER_RES)); } } + + if(lv_label_get_align(label) == LV_LABEL_ALIGN_RIGHT) { + lv_obj_set_x(label, lv_obj_get_width_fit(ext->list) - lv_obj_get_width(label)); + } } /** @@ -685,7 +689,11 @@ static lv_design_res_t lv_dropdown_design(lv_obj_t * ddlist, const lv_area_t * c const char * txt; - txt = ext->dir != LV_DIR_LEFT ? opt_txt : ext->symbol; + bool rev = false; + if(ext->dir == LV_DIR_LEFT) rev = true; + if(lv_obj_get_base_dir(ddlist) == LV_BIDI_DIR_RTL) rev = true; + + txt = rev ? ext->symbol : opt_txt; if(txt) { _lv_txt_get_size(&txt_size, txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX, label_dsc.flag); @@ -705,7 +713,7 @@ static lv_design_res_t lv_dropdown_design(lv_obj_t * ddlist, const lv_area_t * c lv_draw_label(&txt_area, clip_area, &label_dsc, txt, NULL); } - txt = ext->dir != LV_DIR_LEFT ? ext->symbol : opt_txt; + txt = rev ? opt_txt : ext->symbol; if(txt) { _lv_txt_get_size(&txt_size, txt, label_dsc.font, label_dsc.letter_space, label_dsc.line_space, LV_COORD_MAX, label_dsc.flag); diff --git a/src/lv_widgets/lv_roller.c b/src/lv_widgets/lv_roller.c index 8fc8eb575..7afea7900 100644 --- a/src/lv_widgets/lv_roller.c +++ b/src/lv_widgets/lv_roller.c @@ -1,4 +1,3 @@ - /** * @file lv_roller.c * diff --git a/src/lv_widgets/lv_switch.c b/src/lv_widgets/lv_switch.c index ec38c0ea6..effcdfd5a 100644 --- a/src/lv_widgets/lv_switch.c +++ b/src/lv_widgets/lv_switch.c @@ -123,8 +123,8 @@ void lv_switch_on(lv_obj_t * sw, lv_anim_enable_t anim) #if LV_USE_ANIMATION == 0 anim = LV_ANIM_OFF; #endif - lv_switch_ext_t * ext = lv_obj_get_ext_attr(sw); - ext->state = 1; + if(lv_bar_get_value(sw) == 1) + return; lv_bar_set_value(sw, 1, anim); lv_obj_add_state(sw, LV_STATE_CHECKED); } @@ -141,8 +141,8 @@ void lv_switch_off(lv_obj_t * sw, lv_anim_enable_t anim) #if LV_USE_ANIMATION == 0 anim = LV_ANIM_OFF; #endif - lv_switch_ext_t * ext = lv_obj_get_ext_attr(sw); - ext->state = 0; + if(lv_bar_get_value(sw) == 0) + return; lv_bar_set_value(sw, 0, anim); lv_obj_clear_state(sw, LV_STATE_CHECKED); } diff --git a/src/lv_widgets/lv_switch.h b/src/lv_widgets/lv_switch.h index 8079b0fc3..90d60883d 100644 --- a/src/lv_widgets/lv_switch.h +++ b/src/lv_widgets/lv_switch.h @@ -36,7 +36,6 @@ typedef struct { lv_bar_ext_t bar; /*Ext. of ancestor*/ /*New data for this type */ lv_style_list_t style_knob; /*Style of the knob*/ - uint8_t state : 1; /*The current state*/ } lv_switch_ext_t; /** @@ -112,8 +111,7 @@ static inline void lv_switch_set_anim_time(lv_obj_t * sw, uint16_t anim_time) */ static inline bool lv_switch_get_state(const lv_obj_t * sw) { - lv_switch_ext_t * ext = (lv_switch_ext_t *)lv_obj_get_ext_attr(sw); - return ext->state ? true : false; + return lv_bar_get_value(sw) == 1 ? true : false; } /** diff --git a/src/lv_widgets/lv_table.c b/src/lv_widgets/lv_table.c index 04e47a028..316d40b85 100644 --- a/src/lv_widgets/lv_table.c +++ b/src/lv_widgets/lv_table.c @@ -14,6 +14,7 @@ #include "../lv_misc/lv_txt.h" #include "../lv_misc/lv_math.h" #include "../lv_draw/lv_draw_label.h" +#include "../lv_misc/lv_printf.h" #include "../lv_themes/lv_theme.h" /********************* @@ -172,11 +173,117 @@ void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const format.s.crop = 0; } - ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ +#if LV_USE_ARABIC_PERSIAN_CHARS + /*Get the size of the Arabic text and process it*/ + size_t len_ap = _lv_txt_ap_calc_bytes_cnt(txt); + ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], len_ap + 1); LV_ASSERT_MEM(ext->cell_data[cell]); if(ext->cell_data[cell] == NULL) return; - strcpy(ext->cell_data[cell] + 1, txt); /*+1 to skip the format byte*/ + _lv_txt_ap_proc(txt, &ext->cell_data[cell][1]); +#else + ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ + LV_ASSERT_MEM(ext->cell_data[cell]); + if(ext->cell_data[cell] == NULL) return; + + strcpy(ext->cell_data[cell] + 1, txt); /*+1 to skip the format byte*/ +#endif + + ext->cell_data[cell][0] = format.format_byte; + refr_size(table); +} + + +/** + * Set the value of a cell. Memory will be allocated to store the text by the table. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param fmt `printf`-like format + */ +void lv_table_set_cell_value_fmt(lv_obj_t * table, uint16_t row, uint16_t col, const char * fmt, ...) +{ + LV_ASSERT_OBJ(table, LV_OBJX_NAME); + LV_ASSERT_STR(fmt); + + lv_table_ext_t * ext = lv_obj_get_ext_attr(table); + if(col >= ext->col_cnt) { + LV_LOG_WARN("lv_table_set_cell_value: invalid column"); + return; + } + + /*Auto expand*/ + if(row >= ext->row_cnt) { + lv_table_set_row_cnt(table, row + 1); + } + + uint32_t cell = row * ext->col_cnt + col; + lv_table_cell_format_t format; + + /*Save the format byte*/ + if(ext->cell_data[cell]) { + format.format_byte = ext->cell_data[cell][0]; + } + /*Initialize the format byte*/ + else { + lv_bidi_dir_t base_dir = lv_obj_get_base_dir(table); + if(base_dir == LV_BIDI_DIR_LTR) format.s.align = LV_LABEL_ALIGN_LEFT; + else if(base_dir == LV_BIDI_DIR_RTL) format.s.align = LV_LABEL_ALIGN_RIGHT; + else if(base_dir == LV_BIDI_DIR_AUTO) +#if LV_USE_BIDI + format.s.align = _lv_bidi_detect_base_dir(fmt); +#else + format.s.align = LV_LABEL_ALIGN_LEFT; +#endif + format.s.right_merge = 0; + format.s.type = 0; + format.s.crop = 0; + } + + va_list ap, ap2; + va_start(ap, fmt); + va_copy(ap2, ap); + + /*Allocate space for the new text by using trick from C99 standard section 7.19.6.12 */ + uint32_t len = lv_vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + +#if LV_USE_ARABIC_PERSIAN_CHARS + /*Put together the text according to the format string*/ + char * raw_txt = _lv_mem_buf_get(len + 1); + LV_ASSERT_MEM(raw_txt); + if(raw_txt == NULL) { + va_end(ap2); + return; + } + + lv_vsnprintf(raw_txt, len + 1, fmt, ap2); + + /*Get the size of the Arabic text and process it*/ + size_t len_ap = _lv_txt_ap_calc_bytes_cnt(raw_txt); + ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], len_ap + 1); + LV_ASSERT_MEM(ext->cell_data[cell]); + if(ext->cell_data[cell] == NULL) { + va_end(ap2); + return; + } + _lv_txt_ap_proc(raw_txt, &ext->cell_data[cell][1]); + + _lv_mem_buf_release(raw_txt); +#else + ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], len + 2); /*+1: trailing '\0; +1: format byte*/ + LV_ASSERT_MEM(ext->cell_data[cell]); + if(ext->cell_data[cell] == NULL) { + va_end(ap2); + return; + } + + ext->cell_data[cell][len + 1] = 0; /* Ensure NULL termination */ + + lv_vsnprintf(&ext->cell_data[cell][1], len + 1, fmt, ap2); +#endif + + va_end(ap2); ext->cell_data[cell][0] = format.format_byte; refr_size(table); diff --git a/src/lv_widgets/lv_table.h b/src/lv_widgets/lv_table.h index f1c2131b7..d7dddeec9 100644 --- a/src/lv_widgets/lv_table.h +++ b/src/lv_widgets/lv_table.h @@ -111,6 +111,15 @@ lv_obj_t * lv_table_create(lv_obj_t * par, const lv_obj_t * copy); */ void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const char * txt); +/** + * Set the value of a cell. Memory will be allocated to store the text by the table. + * @param table pointer to a Table object + * @param row id of the row [0 .. row_cnt -1] + * @param col id of the column [0 .. col_cnt -1] + * @param fmt `printf`-like format + */ +void lv_table_set_cell_value_fmt(lv_obj_t * table, uint16_t row, uint16_t col, const char * fmt, ...); + /** * Set the number of rows * @param table table pointer to a Table object diff --git a/src/lv_widgets/lv_textarea.c b/src/lv_widgets/lv_textarea.c index 2a53d123e..39e638846 100644 --- a/src/lv_widgets/lv_textarea.c +++ b/src/lv_widgets/lv_textarea.c @@ -247,7 +247,6 @@ void lv_textarea_add_char(lv_obj_t * ta, uint32_t c) return; } - if(ext->pwd_mode != 0) pwd_char_hider(ta); /*Make sure all the current text contains only '*'*/ /*If the textarea is empty, invalidate it to hide the placeholder*/