From 54019d493405096a7fcfddbbaeb06eede99cce41 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 16 Apr 2020 11:12:20 +0200 Subject: [PATCH 1/9] add builtin STM32 DMA2D support --- lv_conf_template.h | 2 + src/lv_conf_internal.h | 6 + src/lv_draw/lv_draw_blend.c | 429 +++++++++++++++++++++++++----------- src/lv_draw/lv_draw_img.c | 2 +- src/lv_draw/lv_draw_label.c | 4 +- src/lv_draw/lv_draw_line.c | 8 +- src/lv_draw/lv_draw_mask.c | 60 ++--- src/lv_draw/lv_draw_mask.h | 2 +- src/lv_draw/lv_draw_rect.c | 2 +- src/lv_misc/lv_color.c | 32 +++ src/lv_misc/lv_color.h | 2 + 11 files changed, 376 insertions(+), 173 deletions(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index 6c51b867a..b87dddf2b 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -177,6 +177,8 @@ typedef void * lv_group_user_data_t; /* 1: Enable GPU interface*/ #define LV_USE_GPU 1 +#define LV_GPU_INCLUDE /*E.g. "stm32f7xx_hal.h"*/ +#define LV_USE_GPU_STM32_DMA2D 1 /* 1: Enable file system (might be required for images */ #define LV_USE_FILESYSTEM 1 diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 74a6fc55e..338afd0a7 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -263,6 +263,12 @@ #ifndef LV_USE_GPU #define LV_USE_GPU 1 #endif +#ifndef LV_GPU_INCLUDE +#define LV_GPU_INCLUDE /*E.g. "stm32f7xx_hal.h"*/ +#endif +#ifndef LV_USE_GPU_STM32_DMA2D +#define LV_USE_GPU_STM32_DMA2D 1 +#endif /* 1: Enable file system (might be required for images */ #ifndef LV_USE_FILESYSTEM diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index 0128eb3e6..13e6c8552 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -11,14 +11,30 @@ #include "../lv_misc/lv_math.h" #include "../lv_hal/lv_hal_disp.h" #include "../lv_core/lv_refr.h" +#include LV_GPU_INCLUDE + +static DMA2D_HandleTypeDef hdma2d; /********************* * DEFINES *********************/ -#define FILL_DIRECT_LEN 32 -#define FILL_DIRECT_MASK 0x1F #define GPU_SIZE_LIMIT 240 +#if LV_USE_GPU_STM32_CHROM_ART +#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP +#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565 +#define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565 +#elif LV_COLOR_DEPTH == 32 +#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_ARGB8888 +#define DMA2D_INPUT_FORMAT DMA2D_INPUT_ARGB8888 +#else +/*Can't use GPU with other formats*/ +#undef LV_USE_GPU_STM32_DMA2D +#endif +#endif + +//#undef LV_USE_GPU_STM32_CHROM_ART + /********************** * TYPEDEFS **********************/ @@ -65,8 +81,8 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co #define FILL_NORMAL_MASK_PX(out_x, color) \ if(*mask_tmp_x) { \ - if(*mask_tmp_x == LV_OPA_COVER) disp_buf_tmp[out_x] = color; \ - else disp_buf_tmp[out_x] = lv_color_mix(color, disp_buf_tmp[out_x], *mask_tmp_x); \ + if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[out_x] = color; \ + else disp_buf_first[out_x] = lv_color_mix(color, disp_buf_first[out_x], *mask_tmp_x); \ } \ mask_tmp_x++; @@ -83,8 +99,8 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co #define MAP_NORMAL_MASK_PX(x) \ if(*mask_tmp_x) { \ - if(*mask_tmp_x == LV_OPA_COVER) disp_buf_tmp[x] = map_buf_tmp[x]; \ - else disp_buf_tmp[x] = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], *mask_tmp_x); \ + if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[x] = map_buf_first[x]; \ + else disp_buf_first[x] = lv_color_mix(map_buf_first[x], disp_buf_first[x], *mask_tmp_x); \ } \ mask_tmp_x++; @@ -103,17 +119,17 @@ mask_tmp_x++; /** - * - * @param disp_area - * @param clip_area already truncated to disp_arae - * @param fill_area - * @param disp_buf - * @param cf - * @param color - * @param mask - * @param mask_res - * @param opa - * @param mode + * Fill and area in the display buffer. + * @param clip_area clip the fill to this area (absolute coordinates) + * @param fill_area fill this area (absolute coordinates) (should be clipped) + * @param color fill color + * @param mask a mask to apply on the fill (uint8_t array with 0x00..0xff values). + * Relative to fill area but its width is truncated to clip area. + * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), + * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), + * LV_MASK_RES_CHANGED: the mask has mixed values + * @param opa overall opacity in 0x00..0xff range + * @param mode blend mode from `lv_blend_mode_t` */ void lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, lv_color_t color, lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, @@ -121,7 +137,7 @@ void lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, { /*Do not draw transparent things*/ if(opa < LV_OPA_MIN) return; - if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) return; + if(mask_res == LV_DRAW_MASK_RES_TRANSP) return; lv_disp_t * disp = lv_refr_get_disp_refreshing(); lv_disp_buf_t * vdb = lv_disp_get_buf(disp); @@ -166,14 +182,26 @@ void lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, } } - +/** + * Copy a map (image) to a display buffer. + * @param clip_area clip the map to this area (absolute coordinates) + * @param map_area area of the image (absolute coordinates) + * @param map_buf a pixels of the map (image) + * @param mask a mask to apply on every pixel (uint8_t array with 0x00..0xff values). + * Relative to map area but its width is truncated to clip area. + * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), + * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), + * LV_MASK_RES_CHANGED: the mask has mixed values + * @param opa overall opacity in 0x00..0xff range + * @param mode blend mode from `lv_blend_mode_t` + */ void lv_blend_map(const lv_area_t * clip_area, const lv_area_t * map_area, const lv_color_t * map_buf, lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode) { /*Do not draw transparent things*/ if(opa < LV_OPA_MIN) return; - if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) return; + if(mask_res == LV_DRAW_MASK_RES_TRANSP) return; /* Get clipped fill area which is the real draw area. * It is always the same or inside `fill_area` */ @@ -260,6 +288,19 @@ static void fill_set_px(const lv_area_t * disp_area, lv_color_t * disp_buf, con } } +/** + * Fill an area with a color + * @param disp_area the current display area (destination area) + * @param disp_buf destination buffer + * @param draw_area fill this area (relative to `disp_area`) + * @param color fill color + * @param opa overall opacity in 0x00..0xff range + * @param mask a mask to apply on every pixel (uint8_t array with 0x00..0xff values). + * It fits into draw_area. + * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), + * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), + * LV_MASK_RES_CHANGED: the mask has mixed values + */ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_draw_mask_res_t mask_res) @@ -272,11 +313,11 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con /*Get the width of the `disp_area` it will be used to go to the next line*/ int32_t disp_w = lv_area_get_width(disp_area); - /*Get the width of the `draw_area` it will be used to go to the next line of the mask*/ int32_t draw_area_w = lv_area_get_width(draw_area); + int32_t draw_area_h = lv_area_get_height(draw_area); - /*Create a temp. disp_buf which always point to current line to draw*/ - lv_color_t * disp_buf_tmp = disp_buf + disp_w * draw_area->y1; + /*Create a temp. disp_buf which always point to the first pixel of the destination area*/ + lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area->y1 + draw_area->x1; int32_t x; int32_t y; @@ -284,33 +325,39 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con /*Simple fill (maybe with opacity), no masking*/ if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) { if(opa > LV_OPA_MAX) { - lv_color_t * disp_buf_tmp_ori = disp_buf_tmp; - #if LV_USE_GPU if(disp->driver.gpu_fill_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) { disp->driver.gpu_fill_cb(&disp->driver, disp_buf, disp_w, draw_area, color); return; } +#if LV_USE_GPU_STM32_CHROM_ART + if(lv_area_get_size(draw_area) >= 240) { +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); #endif + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_R2M; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = disp_w - draw_area_w; + hdma2d.LayerCfg[1].InputAlpha = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[1].InputOffset = 0; - /*Fill the first line. Use `memcpy` because it's faster then simple value assignment*/ - /*Set the first pixels manually*/ - int32_t fill_end = draw_area->x1 + FILL_DIRECT_LEN + (draw_area_w & FILL_DIRECT_MASK) - 1; - int32_t direct_fill_end = LV_MATH_MIN(draw_area->x2, - fill_end); - for(x = draw_area->x1; x <= direct_fill_end ; x++) { - disp_buf_tmp[x].full = color.full; + /* DMA2D Initialization */ + if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { + HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)disp_buf_first, draw_area_w, draw_area_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + } + } + return; } - - for(; x <= draw_area->x2; x += FILL_DIRECT_LEN) { - lv_memcpy(&disp_buf_tmp[x], &disp_buf_tmp[draw_area->x1], FILL_DIRECT_LEN * sizeof(lv_color_t)); - } - - disp_buf_tmp += disp_w; - - for(y = draw_area->y1 + 1; y <= draw_area->y2; y++) { - lv_memcpy(&disp_buf_tmp[draw_area->x1], &disp_buf_tmp_ori[draw_area->x1], draw_area_w * sizeof(lv_color_t)); - disp_buf_tmp += disp_w; +#endif +#endif + /*Software rendering*/ + for(y = 0; y < draw_area_h; y++) { + lv_color_fill(disp_buf_first, color, draw_area_w); + disp_buf_first += disp_w; } } /*No mask with opacity*/ @@ -321,8 +368,8 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con for(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full; for(y = draw_area->y1; y <= draw_area->y2; y++) { - disp->driver.gpu_blend_cb(&disp->driver, &disp_buf_tmp[draw_area->x1], blend_buf, draw_area_w, opa); - disp_buf_tmp += disp_w; + disp->driver.gpu_blend_cb(&disp->driver, disp_buf_first, blend_buf, draw_area_w, opa); + disp_buf_first += disp_w; } return; } @@ -334,48 +381,81 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con lv_color_premult(color, opa, color_premult); lv_opa_t opa_inv = 255 - opa; - for(y = draw_area->y1; y <= draw_area->y2; y++) { - for(x = draw_area->x1; x <= draw_area->x2; x++) { - if(last_dest_color.full != disp_buf_tmp[x].full) { - last_dest_color = disp_buf_tmp[x]; + for(y = 0; y < draw_area_h; y++) { + for(x = 0; x < draw_area_w; x++) { + if(last_dest_color.full != disp_buf_first[x].full) { + last_dest_color = disp_buf_first[x]; #if LV_COLOR_SCREEN_TRANSP if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, color, opa, &last_res_color, + lv_color_mix_with_alpha(disp_buf_first[x], disp_buf_first[x].ch.alpha, color, opa, &last_res_color, &last_res_color.ch.alpha); } else #endif { - last_res_color = lv_color_mix_premult(color_premult, disp_buf_tmp[x], opa_inv); + last_res_color = lv_color_mix_premult(color_premult, disp_buf_first[x], opa_inv); } } - disp_buf_tmp[x] = last_res_color; + disp_buf_first[x] = last_res_color; } - disp_buf_tmp += disp_w; + disp_buf_first += disp_w; } } } /*Masked*/ else { - /* The mask is relative to the clipped area. - * In the cycles below mask will be indexed from `draw_area.x1` - * but it corresponds to zero index. So prepare `mask_tmp` accordingly. */ - const lv_opa_t * mask_tmp = mask - draw_area->x1; + + /*DMA2D could be used here but it's much slower than software rendering*/ +#if LV_USE_GPU_STM32_CHROM_ART && 0 + if(lv_area_get_size(draw_area) > 240) { +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + /* Configure the DMA2D Mode, Color Mode and line output offset */ + hdma2d.Init.Mode = DMA2D_M2M_BLEND; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = disp_w - draw_area_w; + + /* Configure the foreground -> The character */ + lv_color32_t c32; + c32.full = lv_color_to32(color); + c32.ch.alpha = opa; + hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = c32.full; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_A8; + hdma2d.LayerCfg[1].InputOffset = 0; + + /* Configure the background -> Display buffer */ + hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[0].InputAlpha = 0x00; + hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[0].InputOffset = disp_w - draw_area_w; + + /* DMA2D Initialization */ + HAL_DMA2D_Init(&hdma2d); + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + HAL_DMA2D_ConfigLayer(&hdma2d, 1); + HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) disp_buf_first, (uint32_t)disp_buf_first, draw_area_w, draw_area_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + return; + } +#endif + /*Buffer the result color to avoid recalculating the same color*/ lv_color_t last_dest_color; lv_color_t last_res_color; lv_opa_t last_mask = LV_OPA_TRANSP; - last_dest_color.full = disp_buf_tmp[0].full; - last_res_color.full = disp_buf_tmp[0].full; + last_dest_color.full = disp_buf_first[0].full; + last_res_color.full = disp_buf_first[0].full; - int32_t x_end4 = draw_area->x2 - 4; + int32_t x_end4 = draw_area_w - 4; /*Only the mask matters*/ if(opa > LV_OPA_MAX) { - for(y = draw_area->y1; y <= draw_area->y2; y++) { - const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; + for(y = 0; y < draw_area_h; y++) { + const lv_opa_t * mask_tmp_x = mask; #if 0 for(x = draw_area->x1; x <= draw_area->x2; x++) { #if LV_COLOR_SCREEN_TRANSP @@ -385,7 +465,7 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con #endif } #else - for(x = draw_area->x1; x <= draw_area->x2 && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) { + for(x = 0; x < draw_area_w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) { #if LV_COLOR_SCREEN_TRANSP FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color) #else @@ -397,10 +477,10 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con for(; x <= x_end4; x += 4) { if(*mask32) { if((*mask32) == 0xFFFFFFFF) { - disp_buf_tmp[x] = color; - disp_buf_tmp[x + 1] = color; - disp_buf_tmp[x + 2] = color; - disp_buf_tmp[x + 3] = color; + disp_buf_first[x] = color; + disp_buf_first[x + 1] = color; + disp_buf_first[x + 2] = color; + disp_buf_first[x + 3] = color; } else { mask_tmp_x = (const lv_opa_t *)mask32; @@ -421,7 +501,7 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con } mask_tmp_x = (const lv_opa_t *)mask32; - for(; x <= draw_area->x2 ; x++) { + for(; x < draw_area_w ; x++) { #if LV_COLOR_SCREEN_TRANSP FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color) #else @@ -429,46 +509,60 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con #endif } #endif - disp_buf_tmp += disp_w; - mask_tmp += draw_area_w; + disp_buf_first += disp_w; + mask += draw_area_w; } } /*Handle opa and mask values too*/ else { lv_opa_t opa_tmp = LV_OPA_TRANSP; for(y = draw_area->y1; y <= draw_area->y2; y++) { - const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; - for(x = draw_area->x1; x <= draw_area->x2; x++) { + const lv_opa_t * mask_tmp_x = mask; + for(x = 0; x < draw_area_w; x++) { if(*mask_tmp_x) { if(*mask_tmp_x != last_mask) opa_tmp = *mask_tmp_x == LV_OPA_COVER ? opa : (uint32_t)((uint32_t)( *mask_tmp_x) * opa) >> 8; - if(*mask_tmp_x != last_mask || last_dest_color.full != disp_buf_tmp[x].full) { + if(*mask_tmp_x != last_mask || last_dest_color.full != disp_buf_first[x].full) { #if LV_COLOR_SCREEN_TRANSP if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, color, opa_tmp, &last_res_color, + lv_color_mix_with_alpha(disp_buf_first[x], disp_buf_first[x].ch.alpha, color, opa_tmp, &last_res_color, &last_res_color.ch.alpha); } else #endif { if(opa_tmp == LV_OPA_COVER) last_res_color = color; - else last_res_color = lv_color_mix(color, disp_buf_tmp[x], opa_tmp); + else last_res_color = lv_color_mix(color, disp_buf_first[x], opa_tmp); } last_mask = *mask_tmp_x; - last_dest_color.full = disp_buf_tmp[x].full; + last_dest_color.full = disp_buf_first[x].full; } - disp_buf_tmp[x] = last_res_color; + disp_buf_first[x] = last_res_color; } mask_tmp_x++; } - disp_buf_tmp += disp_w; - mask_tmp += draw_area_w; + disp_buf_first += disp_w; + mask += draw_area_w; } } } } +/** + * Fill an area with a color but apply blending algorithms + * @param disp_area the current display area (destination area) + * @param disp_buf destination buffer + * @param draw_area fill this area (relative to `disp_area`) + * @param color fill color + * @param opa overall opacity in 0x00..0xff range + * @param mask a mask to apply on every pixel (uint8_t array with 0x00..0xff values). + * It fits into draw_area. + * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), + * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), + * LV_MASK_RES_CHANGED: the mask has mixed values + * @param mode blend mode from `lv_blend_mode_t` + */ static void fill_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area, lv_color_t color, lv_opa_t opa, const lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_blend_mode_t mode) @@ -595,7 +689,19 @@ static void map_set_px(const lv_area_t * disp_area, lv_color_t * disp_buf, cons } } - +/** + * Copy an image to an area + * @param disp_area the current display area (destination area) + * @param disp_buf destination buffer + * @param map_area coordinates of the map (image) to copy. (absolute coordinates) + * @param map_buf the pixel of the image + * @param opa overall opacity in 0x00..0xff range + * @param mask a mask to apply on every pixel (uint8_t array with 0x00..0xff values). + * It fits into draw_area. + * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask), + * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent), + * LV_MASK_RES_CHANGED: the mask has mixed values + */ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area, const lv_area_t * map_area, const lv_color_t * map_buf, lv_opa_t opa, const lv_opa_t * mask, lv_draw_mask_res_t mask_res) @@ -604,18 +710,18 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons /*Get the width of the `disp_area` it will be used to go to the next line*/ int32_t disp_w = lv_area_get_width(disp_area); - /*Get the width of the `draw_area` it will be used to go to the next line of the mask*/ int32_t draw_area_w = lv_area_get_width(draw_area); + int32_t draw_area_h = lv_area_get_height(draw_area); /*Get the width of the `mask_area` it will be used to go to the next line*/ int32_t map_w = lv_area_get_width(map_area); - /*Create a temp. disp_buf which always point to current line to draw*/ - lv_color_t * disp_buf_tmp = disp_buf + disp_w * draw_area->y1; - - /*Create a temp. map_buf which always point to current line to draw*/ - const lv_color_t * map_buf_tmp = map_buf + map_w * (draw_area->y1 - (map_area->y1 - disp_area->y1)); + /*Create a temp. disp_buf which always point to first pixel to draw*/ + lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area->y1 + draw_area->x1;; + /*Create a temp. map_buf which always point to first pixel to draw from the map*/ + const lv_color_t * map_buf_first = map_buf + map_w * (draw_area->y1 - (map_area->y1 - disp_area->y1)); + map_buf_first += (draw_area->x1 - (map_area->x1 - disp_area->x1)); #if LV_COLOR_SCREEN_TRANSP lv_opa_t opa_composed; @@ -629,70 +735,126 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons /*Simple fill (maybe with opacity), no masking*/ if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) { - /*Go to the first px of the row*/ - map_buf_tmp += (draw_area->x1 - (map_area->x1 - disp_area->x1)); #if LV_USE_GPU if(disp->driver.gpu_blend_cb && (lv_area_get_size(draw_area) > GPU_SIZE_LIMIT)) { for(y = draw_area->y1; y <= draw_area->y2; y++) { - disp->driver.gpu_blend_cb(&disp->driver, &disp_buf_tmp[draw_area->x1], map_buf_tmp, draw_area_w, opa); - disp_buf_tmp += disp_w; - map_buf_tmp += map_w; + disp->driver.gpu_blend_cb(&disp->driver, disp_buf_first, map_buf_first, draw_area_w, opa); + disp_buf_first += disp_w; + map_buf_first += map_w; } return; } #endif if(opa > LV_OPA_MAX) { - for(y = draw_area->y1; y <= draw_area->y2; y++) { - lv_memcpy(&disp_buf_tmp[draw_area->x1], map_buf_tmp, draw_area_w * sizeof(lv_color_t)); - disp_buf_tmp += disp_w; - map_buf_tmp += map_w; +#if LV_USE_GPU_STM32_CHROM_ART + if(lv_area_get_size(draw_area) >= 240) { +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_M2M; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = disp_w - draw_area_w; + + /* Foreground layer */ + hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = opa; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[1].InputOffset = map_w - draw_area_w; + hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; + + /* DMA2D Initialization */ + if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { + HAL_DMA2D_Start(&hdma2d, (uint32_t)map_buf_first, (uint32_t)disp_buf_first, draw_area_w, draw_area_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + } + } + return; + } +#endif + + /*Software rendering*/ + for(y = 0; y < draw_area_h; y++) { + lv_memcpy(disp_buf_first, map_buf_first, draw_area_w * sizeof(lv_color_t)); + disp_buf_first += disp_w; + map_buf_first += map_w; } } else { - /*The map will be indexed from `draw_area->x1` so compensate it.*/ - map_buf_tmp -= draw_area->x1; - for(y = draw_area->y1; y <= draw_area->y2; y++) { - for(x = draw_area->x1; x <= draw_area->x2; x++) { +#if LV_USE_GPU_STM32_CHROM_ART + if(lv_area_get_size(draw_area) >= 256) { +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_M2M_BLEND; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = disp_w - draw_area_w; + + /* Background layer */ + hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[0].InputOffset = disp_w - draw_area_w; + hdma2d.LayerCfg[0].AlphaInverted = DMA2D_REGULAR_ALPHA; + + /* Foreground layer */ + hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = opa; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[1].InputOffset = map_w - draw_area_w; + hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; + + /* DMA2D Initialization */ + if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { + HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map_buf_first, (uint32_t)disp_buf_first, (uint32_t)disp_buf_first, draw_area_w, draw_area_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + } + } + return; + } +#endif + + /*Software rendering*/ + + for(y = 0; y < draw_area_h; y++) { + for(x = 0; x < draw_area_w; x++) { #if LV_COLOR_SCREEN_TRANSP if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, map_buf_tmp[x], opa, &disp_buf_tmp[x], - &disp_buf_tmp[x].ch.alpha); + lv_color_mix_with_alpha(disp_buf_first[x], disp_buf_first[x].ch.alpha, map_buf_first[x], opa, &disp_buf_first[x], + &disp_buf_first[x].ch.alpha); } else #endif { - disp_buf_tmp[x] = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], opa); + disp_buf_first[x] = lv_color_mix(map_buf_first[x], disp_buf_first[x], opa); } } - disp_buf_tmp += disp_w; - map_buf_tmp += map_w; + disp_buf_first += disp_w; + map_buf_first += map_w; } } } /*Masked*/ else { - /* The mask is relative to the clipped area. - * In the cycles below mask will be indexed from `draw_area.x1` - * but it corresponds to zero index. So prepare `mask_tmp` accordingly. */ - const lv_opa_t * mask_tmp = mask - draw_area->x1; - /*Only the mask matters*/ if(opa > LV_OPA_MAX) { /*Go to the first pixel of the row */ - map_buf_tmp += (draw_area->x1 - (map_area->x1 - disp_area->x1)); - map_buf_tmp -= draw_area->x1; - int32_t x_end4 = draw_area->x2 - 4; + int32_t x_end4 = draw_area_w - 4; - for(y = draw_area->y1; y <= draw_area->y2; y++) { - const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; + for(y = 0; y < draw_area_h; y++) { + const lv_opa_t * mask_tmp_x = mask; #if 0 for(x = draw_area->x1; x <= draw_area->x2; x++) { MAP_NORMAL_MASK_PX(x); } #else - for(x = draw_area->x1; x <= draw_area->x2 && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) { + for(x = 0; x < draw_area_w && ((lv_uintptr_t)mask_tmp_x & 0x3); x++) { #if LV_COLOR_SCREEN_TRANSP MAP_NORMAL_MASK_PX_SCR_TRANSP(x) #else @@ -701,13 +863,13 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons } uint32_t * mask32 = (uint32_t *) mask_tmp_x; - for(; x <= x_end4; x += 4) { + for(; x < x_end4; x += 4) { if(*mask32) { if((*mask32) == 0xFFFFFFFF) { - disp_buf_tmp[x] = map_buf_tmp[x]; - disp_buf_tmp[x + 1] = map_buf_tmp[x + 1]; - disp_buf_tmp[x + 2] = map_buf_tmp[x + 2]; - disp_buf_tmp[x + 3] = map_buf_tmp[x + 3]; + disp_buf_first[x] = map_buf_first[x]; + disp_buf_first[x + 1] = map_buf_first[x + 1]; + disp_buf_first[x + 2] = map_buf_first[x + 2]; + disp_buf_first[x + 3] = map_buf_first[x + 3]; } else { mask_tmp_x = (const lv_opa_t *)mask32; @@ -728,7 +890,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons } mask_tmp_x = (const lv_opa_t *)mask32; - for(; x <= draw_area->x2 ; x++) { + for(; x < draw_area_w ; x++) { #if LV_COLOR_SCREEN_TRANSP MAP_NORMAL_MASK_PX_SCR_TRANSP(x) #else @@ -736,33 +898,32 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons #endif } #endif - disp_buf_tmp += disp_w; - mask_tmp += draw_area_w; - map_buf_tmp += map_w; + disp_buf_first += disp_w; + mask += draw_area_w; + map_buf_first += map_w; } } /*Handle opa and mask values too*/ else { - map_buf_tmp -= draw_area->x1; - for(y = draw_area->y1; y <= draw_area->y2; y++) { - for(x = draw_area->x1; x <= draw_area->x2; x++) { - if(mask_tmp[x]) { - lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : ((opa * mask_tmp[x]) >> 8); + for(y = 0; y < draw_area_h; y++) { + for(x = 0; x < draw_area_w; x++) { + if(mask[x]) { + lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8); #if LV_COLOR_SCREEN_TRANSP if(disp->driver.screen_transp) { - lv_color_mix_with_alpha(disp_buf_tmp[x], disp_buf_tmp[x].ch.alpha, map_buf_tmp[x], opa_tmp, &disp_buf_tmp[x], - &disp_buf_tmp[x].ch.alpha); + lv_color_mix_with_alpha(disp_buf_first[x], disp_buf_first[x].ch.alpha, map_buf_first[x], opa_tmp, &disp_buf_first[x], + &disp_buf_first[x].ch.alpha); } else #endif { - disp_buf_tmp[x] = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], opa_tmp); + disp_buf_first[x] = lv_color_mix(map_buf_first[x], disp_buf_first[x], opa_tmp); } } } - disp_buf_tmp += disp_w; - mask_tmp += draw_area_w; - map_buf_tmp += map_w; + disp_buf_first += disp_w; + mask += draw_area_w; + map_buf_first += map_w; } } } diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 294e33f97..a4ee0386f 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -537,7 +537,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, lv_draw_mask_res_t mask_res_sub; mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, draw_area.x1 + vdb->area.x1, y + draw_area.y1 + vdb->area.y1, lv_area_get_width(&draw_area)); - if(mask_res_sub == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(mask_buf + px_i_start, lv_area_get_width(&draw_area)); mask_res = LV_DRAW_MASK_RES_CHANGED; } diff --git a/src/lv_draw/lv_draw_label.c b/src/lv_draw/lv_draw_label.c index 42eeb95ee..598ddbc94 100644 --- a/src/lv_draw/lv_draw_label.c +++ b/src/lv_draw/lv_draw_label.c @@ -556,7 +556,7 @@ static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph if(other_mask_cnt) { lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, fill_area.x1, fill_area.y2, lv_area_get_width(&fill_area)); - if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&fill_area)); } } @@ -756,7 +756,7 @@ static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_ if(other_mask_cnt) { lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf + mask_p_start, map_area.x1, map_area.y2, lv_area_get_width(&map_area)); - if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&map_area)); } } diff --git a/src/lv_draw/lv_draw_line.c b/src/lv_draw/lv_draw_line.c index 85ca52320..020273e21 100644 --- a/src/lv_draw/lv_draw_line.c +++ b/src/lv_draw/lv_draw_line.c @@ -182,7 +182,7 @@ static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2, lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w); if(dashed) { - if(mask_res != LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res != LV_DRAW_MASK_RES_TRANSP) { lv_style_int_t dash_cnt = dash_start; uint32_t i; for(i = 0; i < draw_area_w; i++, dash_cnt++) { @@ -285,9 +285,9 @@ static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2, lv_draw_mask_res_t mask_res = lv_draw_mask_apply(mask_buf, vdb->area.x1 + draw_area.x1, vdb->area.y1 + h, draw_area_w); if(dashed) { - if(mask_res != LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res != LV_DRAW_MASK_RES_TRANSP) { if(dash_cnt > dsc->dash_width) { - mask_res = LV_DRAW_MASK_RES_FULL_TRANSP; + mask_res = LV_DRAW_MASK_RES_TRANSP; } if(dash_cnt >= dsc->dash_gap + dsc->dash_width) { @@ -437,7 +437,7 @@ static void draw_line_skew(const lv_point_t * point1, const lv_point_t * point2, for(h = draw_area.y1 + disp_area->y1; h <= draw_area.y2 + disp_area->y1; h++) { lv_draw_mask_res_t mask_res = lv_draw_mask_apply(&mask_buf[mask_p], x, h, draw_area_w); - if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(&mask_buf[mask_p], draw_area_w); } diff --git a/src/lv_draw/lv_draw_mask.c b/src/lv_draw/lv_draw_mask.c index fbc77cab2..c9c1537e8 100644 --- a/src/lv_draw/lv_draw_mask.c +++ b/src/lv_draw/lv_draw_mask.c @@ -110,7 +110,7 @@ lv_draw_mask_res_t lv_draw_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_ dsc = m->param; lv_draw_mask_res_t res = LV_DRAW_MASK_RES_FULL_COVER; res = dsc->cb(mask_buf, abs_x, abs_y, len, (void *)m->param); - if(res == LV_DRAW_MASK_RES_FULL_TRANSP) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(res == LV_DRAW_MASK_RES_TRANSP) return LV_DRAW_MASK_RES_TRANSP; else if(res == LV_DRAW_MASK_RES_CHANGED) changed = true; m++; @@ -442,7 +442,7 @@ static lv_draw_mask_res_t lv_draw_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_ else if(p->cfg.side == LV_DRAW_MASK_LINE_SIDE_TOP && abs_y + 1 < 0) return LV_DRAW_MASK_RES_FULL_COVER; else if(p->cfg.side == LV_DRAW_MASK_LINE_SIDE_BOTTOM && abs_y > 0) return LV_DRAW_MASK_RES_FULL_COVER; else { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } } /*Vertical*/ @@ -455,17 +455,17 @@ static lv_draw_mask_res_t lv_draw_mask_line(lv_opa_t * mask_buf, lv_coord_t abs_ if(abs_x + len < 0) return LV_DRAW_MASK_RES_FULL_COVER; else { int32_t k = - abs_x; - if(k < 0) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(k < 0) return LV_DRAW_MASK_RES_TRANSP; if(k >= 0 && k < len) lv_memset_00(&mask_buf[k], len - k); return LV_DRAW_MASK_RES_CHANGED; } } else { - if(abs_x + len < 0) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(abs_x + len < 0) return LV_DRAW_MASK_RES_TRANSP; else { int32_t k = - abs_x; if(k < 0) k = 0; - if(k >= len) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(k >= len) return LV_DRAW_MASK_RES_TRANSP; else if(k >= 0 && k < len) lv_memset_00(&mask_buf[0], k); return LV_DRAW_MASK_RES_CHANGED; } @@ -496,7 +496,7 @@ static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, return LV_DRAW_MASK_RES_FULL_COVER; } else { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } } } @@ -506,7 +506,7 @@ static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, return LV_DRAW_MASK_RES_FULL_COVER; } else { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } } } @@ -517,7 +517,7 @@ static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, if(p->yx_steep > 0) { if(y_at_x < abs_y) { if(p->inv) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } else { return LV_DRAW_MASK_RES_FULL_COVER; @@ -527,7 +527,7 @@ static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, else { if(y_at_x > abs_y) { if(p->inv) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } else { return LV_DRAW_MASK_RES_FULL_COVER; @@ -581,7 +581,7 @@ static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, if(p->inv) { k = xei - abs_x; if(k > len) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(k >= 0) { lv_memset_00(&mask_buf[0], k); @@ -590,7 +590,7 @@ static lv_draw_mask_res_t line_mask_flat(lv_opa_t * mask_buf, lv_coord_t abs_x, else { k++; if(k < 0) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(k <= len) { lv_memset_00(&mask_buf[k], len - k); @@ -614,7 +614,7 @@ static lv_draw_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, return LV_DRAW_MASK_RES_FULL_COVER; } else { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } } @@ -623,7 +623,7 @@ static lv_draw_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, x_at_y = (int32_t)((int32_t)p->xy_steep * (abs_y)) >> 10; if(x_at_y > abs_x + len) { if(p->inv) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } else { return LV_DRAW_MASK_RES_FULL_COVER; @@ -660,14 +660,14 @@ static lv_draw_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, if(p->inv) { k = xsi - abs_x; if(k >= len) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(k >= 0) lv_memset_00(&mask_buf[0], k); } else { if(k > len) k = len; - if(k == 0) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(k == 0) return LV_DRAW_MASK_RES_TRANSP; else if(k > 0) lv_memset_00(&mask_buf[k], len - k); } @@ -726,13 +726,13 @@ static lv_draw_mask_res_t line_mask_steep(lv_opa_t * mask_buf, lv_coord_t abs_x, if(p->inv) { k = xsi - abs_x; - if(k > len) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(k > len) return LV_DRAW_MASK_RES_TRANSP; if(k >= 0) lv_memset_00(&mask_buf[0], k); } else { if(k > len) k = len; - if(k == 0) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(k == 0) return LV_DRAW_MASK_RES_TRANSP; else if(k > 0) lv_memset_00(&mask_buf[k], len - k); } } @@ -781,7 +781,7 @@ static lv_draw_mask_res_t lv_draw_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs if(tmp > len) tmp = len; if(tmp > 0) { res1 = lv_draw_mask_line(&mask_buf[0], abs_x, abs_y, tmp, &p->start_line); - if(res1 == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(res1 == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(&mask_buf[0], tmp); } } @@ -789,7 +789,7 @@ static lv_draw_mask_res_t lv_draw_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs if(tmp > len) tmp = len; if(tmp < 0) tmp = 0; res2 = lv_draw_mask_line(&mask_buf[tmp], abs_x + tmp, abs_y, len - tmp, &p->end_line); - if(res2 == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(res2 == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(&mask_buf[tmp], len - tmp); } if(res1 == res2) return res1; @@ -823,7 +823,7 @@ static lv_draw_mask_res_t lv_draw_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs if(tmp > len) tmp = len; if(tmp > 0) { res1 = lv_draw_mask_line(&mask_buf[0], abs_x, abs_y, tmp, (lv_draw_mask_line_param_t *)&p->end_line); - if(res1 == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(res1 == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(&mask_buf[0], tmp); } } @@ -831,7 +831,7 @@ static lv_draw_mask_res_t lv_draw_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs if(tmp > len) tmp = len; if(tmp < 0) tmp = 0; res2 = lv_draw_mask_line(&mask_buf[tmp], abs_x + tmp, abs_y, len - tmp, (lv_draw_mask_line_param_t *)&p->start_line); - if(res2 == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(res2 == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(&mask_buf[tmp], len - tmp); } if(res1 == res2) return res1; @@ -874,8 +874,8 @@ static lv_draw_mask_res_t lv_draw_mask_angle(lv_opa_t * mask_buf, lv_coord_t abs res2 = lv_draw_mask_line(mask_buf, abs_x, abs_y, len, &p->end_line); } - if(res1 == LV_DRAW_MASK_RES_FULL_TRANSP || res2 == LV_DRAW_MASK_RES_FULL_TRANSP) return LV_DRAW_MASK_RES_FULL_TRANSP; - else if(res1 == LV_DRAW_MASK_RES_UNKNOWN && res2 == LV_DRAW_MASK_RES_UNKNOWN) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(res1 == LV_DRAW_MASK_RES_TRANSP || res2 == LV_DRAW_MASK_RES_TRANSP) return LV_DRAW_MASK_RES_TRANSP; + else if(res1 == LV_DRAW_MASK_RES_UNKNOWN && res2 == LV_DRAW_MASK_RES_UNKNOWN) return LV_DRAW_MASK_RES_TRANSP; else if(res1 == LV_DRAW_MASK_RES_FULL_COVER && res2 == LV_DRAW_MASK_RES_FULL_COVER) return LV_DRAW_MASK_RES_FULL_COVER; else return LV_DRAW_MASK_RES_CHANGED; } @@ -891,7 +891,7 @@ static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * mask_buf, lv_coord_t ab if(outer == false) { if(abs_y < rect.y1 || abs_y >rect.y2) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } } else { @@ -905,13 +905,13 @@ static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * mask_buf, lv_coord_t ab if(outer == false) { /*Remove the edges*/ int32_t last = rect.x1 - abs_x; - if(last > len) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(last > len) return LV_DRAW_MASK_RES_TRANSP; if(last >= 0) { lv_memset_00(&mask_buf[0], last); } int32_t first = rect.x2 - abs_x + 1; - if(first <= 0) return LV_DRAW_MASK_RES_FULL_TRANSP; + if(first <= 0) return LV_DRAW_MASK_RES_TRANSP; else if(first < len) { lv_memset_00(&mask_buf[first], len - first); } @@ -1018,13 +1018,13 @@ static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * mask_buf, lv_coord_t ab if(outer == false) { kr++; if(kl > len) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(kl >= 0) { lv_memset_00(&mask_buf[0], kl); } if(kr < 0) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(kr <= len) { lv_memset_00(&mask_buf[kr], len - kr); @@ -1114,12 +1114,12 @@ static lv_draw_mask_res_t lv_draw_mask_radius(lv_opa_t * mask_buf, lv_coord_t ab if(outer == 0) { kl++; if(kl > len) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(kl >= 0) lv_memset_00(&mask_buf[0], kl); if(kr < 0) { - return LV_DRAW_MASK_RES_FULL_TRANSP; + return LV_DRAW_MASK_RES_TRANSP; } if(kr < len) lv_memset_00(&mask_buf[kr], len - kr); } diff --git a/src/lv_draw/lv_draw_mask.h b/src/lv_draw/lv_draw_mask.h index b2321748a..b8270609a 100644 --- a/src/lv_draw/lv_draw_mask.h +++ b/src/lv_draw/lv_draw_mask.h @@ -27,7 +27,7 @@ extern "C" { **********************/ enum { - LV_DRAW_MASK_RES_FULL_TRANSP, + LV_DRAW_MASK_RES_TRANSP, LV_DRAW_MASK_RES_FULL_COVER, LV_DRAW_MASK_RES_CHANGED, LV_DRAW_MASK_RES_UNKNOWN diff --git a/src/lv_draw/lv_draw_rect.c b/src/lv_draw/lv_draw_rect.c index ba1bbd0ab..11be7ddd2 100644 --- a/src/lv_draw/lv_draw_rect.c +++ b/src/lv_draw/lv_draw_rect.c @@ -1060,7 +1060,7 @@ static void shadow_draw_corner_buf(const lv_area_t * coords, uint16_t * sh_buf, for(y = 0; y < size; y++) { lv_memset_ff(mask_line, size); lv_draw_mask_res_t mask_res = mask_param.dsc.cb(mask_line, 0, y, size, &mask_param); - if(mask_res == LV_DRAW_MASK_RES_FULL_TRANSP) { + if(mask_res == LV_DRAW_MASK_RES_TRANSP) { lv_memset_00(sh_ups_tmp_buf, size * sizeof(sh_ups_tmp_buf[0])); } else { diff --git a/src/lv_misc/lv_color.c b/src/lv_misc/lv_color.c index a1f647370..f27a730b6 100644 --- a/src/lv_misc/lv_color.c +++ b/src/lv_misc/lv_color.c @@ -37,6 +37,38 @@ * STATIC FUNCTIONS **********************/ +void lv_color_fill(lv_color_t * buf, lv_color_t color, uint32_t px_num) +{ + while(px_num > 16) { + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + *buf = color; buf++; + + px_num -= 16; + } + while(px_num ) { + *buf = color; buf++; + px_num --; + } +} + + lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl) { return lv_color_mix(LV_COLOR_WHITE, c, lvl); diff --git a/src/lv_misc/lv_color.h b/src/lv_misc/lv_color.h index f8bcf57ac..58f62f9c1 100644 --- a/src/lv_misc/lv_color.h +++ b/src/lv_misc/lv_color.h @@ -597,6 +597,8 @@ static inline lv_color_t lv_color_hex3(uint32_t c) (uint8_t)((c & 0xF) | ((c & 0xF) << 4))); } +void lv_color_fill(lv_color_t * buf, lv_color_t color, uint32_t px_num); + lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl); lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl); From f6ae49d29c4ee1efb9f1fbfd512a845970b28b64 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 16 Apr 2020 11:13:59 +0200 Subject: [PATCH 2/9] minor fixes --- src/lv_draw/lv_draw_blend.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index 13e6c8552..e754a1ba5 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -20,7 +20,7 @@ static DMA2D_HandleTypeDef hdma2d; *********************/ #define GPU_SIZE_LIMIT 240 -#if LV_USE_GPU_STM32_CHROM_ART +#if LV_USE_GPU_STM32_DMA2D #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP #define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565 #define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565 @@ -330,7 +330,7 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con disp->driver.gpu_fill_cb(&disp->driver, disp_buf, disp_w, draw_area, color); return; } -#if LV_USE_GPU_STM32_CHROM_ART +#if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { #if __DCACHE_PRESENT SCB_CleanInvalidateDCache(); @@ -407,7 +407,7 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con else { /*DMA2D could be used here but it's much slower than software rendering*/ -#if LV_USE_GPU_STM32_CHROM_ART && 0 +#if LV_USE_GPU_STM32_DMA2D && 0 if(lv_area_get_size(draw_area) > 240) { #if __DCACHE_PRESENT SCB_CleanInvalidateDCache(); @@ -747,7 +747,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons #endif if(opa > LV_OPA_MAX) { -#if LV_USE_GPU_STM32_CHROM_ART +#if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { #if __DCACHE_PRESENT SCB_CleanInvalidateDCache(); @@ -784,7 +784,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons } } else { -#if LV_USE_GPU_STM32_CHROM_ART +#if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 256) { #if __DCACHE_PRESENT SCB_CleanInvalidateDCache(); From 6f87d29ac7ecaaf8a619adeb696d2bba946bb4e8 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 16 Apr 2020 16:12:35 +0200 Subject: [PATCH 3/9] more dma2d to a separate file --- lvgl.mk | 1 + src/lv_draw/lv_draw_blend.c | 124 ++--------------------- src/lv_gpu/lv_draw.mk | 6 ++ src/lv_gpu/lv_gpu_stm32_dma2d.c | 168 ++++++++++++++++++++++++++++++++ src/lv_gpu/lv_gpu_stm32_dma2d.h | 43 ++++++++ 5 files changed, 224 insertions(+), 118 deletions(-) create mode 100644 src/lv_gpu/lv_draw.mk create mode 100644 src/lv_gpu/lv_gpu_stm32_dma2d.c create mode 100644 src/lv_gpu/lv_gpu_stm32_dma2d.h diff --git a/lvgl.mk b/lvgl.mk index 0c578a810..bbea98d35 100644 --- a/lvgl.mk +++ b/lvgl.mk @@ -5,5 +5,6 @@ include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_font/lv_font.mk include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_misc/lv_misc.mk include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_themes/lv_themes.mk include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_draw/lv_draw.mk +include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_gpu/lv_gpu.mk diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index e754a1ba5..8b1c781f3 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -11,30 +11,14 @@ #include "../lv_misc/lv_math.h" #include "../lv_hal/lv_hal_disp.h" #include "../lv_core/lv_refr.h" -#include LV_GPU_INCLUDE -static DMA2D_HandleTypeDef hdma2d; +#include "../lv_gpu/lv_gpu_stm32_dma2d.h" /********************* * DEFINES *********************/ #define GPU_SIZE_LIMIT 240 -#if LV_USE_GPU_STM32_DMA2D -#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP -#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565 -#define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565 -#elif LV_COLOR_DEPTH == 32 -#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_ARGB8888 -#define DMA2D_INPUT_FORMAT DMA2D_INPUT_ARGB8888 -#else -/*Can't use GPU with other formats*/ -#undef LV_USE_GPU_STM32_DMA2D -#endif -#endif - -//#undef LV_USE_GPU_STM32_CHROM_ART - /********************** * TYPEDEFS **********************/ @@ -332,24 +316,7 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con } #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_R2M; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = disp_w - draw_area_w; - hdma2d.LayerCfg[1].InputAlpha = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[1].InputOffset = 0; - - /* DMA2D Initialization */ - if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { - HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)disp_buf_first, draw_area_w, draw_area_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); - } - } + lv_gpu_stm32_dma2d_fill(disp_buf_first, disp_w, color, draw_area_w, draw_area_h); return; } #endif @@ -405,39 +372,10 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con } /*Masked*/ else { - /*DMA2D could be used here but it's much slower than software rendering*/ #if LV_USE_GPU_STM32_DMA2D && 0 if(lv_area_get_size(draw_area) > 240) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif - /* Configure the DMA2D Mode, Color Mode and line output offset */ - hdma2d.Init.Mode = DMA2D_M2M_BLEND; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = disp_w - draw_area_w; - - /* Configure the foreground -> The character */ - lv_color32_t c32; - c32.full = lv_color_to32(color); - c32.ch.alpha = opa; - hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = c32.full; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_A8; - hdma2d.LayerCfg[1].InputOffset = 0; - - /* Configure the background -> Display buffer */ - hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[0].InputAlpha = 0x00; - hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[0].InputOffset = disp_w - draw_area_w; - - /* DMA2D Initialization */ - HAL_DMA2D_Init(&hdma2d); - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - HAL_DMA2D_ConfigLayer(&hdma2d, 1); - HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) disp_buf_first, (uint32_t)disp_buf_first, draw_area_w, draw_area_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + lv_gpu_stm32_dma2d_fill_mask(disp_buf_first, disp_w, color, mask, opa, draw_area_w, draw_area_h); return; } #endif @@ -749,29 +687,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons if(opa > LV_OPA_MAX) { #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_M2M; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = disp_w - draw_area_w; - - /* Foreground layer */ - hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = opa; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[1].InputOffset = map_w - draw_area_w; - hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; - - /* DMA2D Initialization */ - if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { - HAL_DMA2D_Start(&hdma2d, (uint32_t)map_buf_first, (uint32_t)disp_buf_first, draw_area_w, draw_area_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); - } - } + lv_gpu_stm32_dma2d_blend_normal_cover(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h); return; } #endif @@ -785,36 +701,8 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons } else { #if LV_USE_GPU_STM32_DMA2D - if(lv_area_get_size(draw_area) >= 256) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif - hdma2d.Instance = DMA2D; - hdma2d.Init.Mode = DMA2D_M2M_BLEND; - hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; - hdma2d.Init.OutputOffset = disp_w - draw_area_w; - - /* Background layer */ - hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; - hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[0].InputOffset = disp_w - draw_area_w; - hdma2d.LayerCfg[0].AlphaInverted = DMA2D_REGULAR_ALPHA; - - /* Foreground layer */ - hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; - hdma2d.LayerCfg[1].InputAlpha = opa; - hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; - hdma2d.LayerCfg[1].InputOffset = map_w - draw_area_w; - hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; - - /* DMA2D Initialization */ - if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { - HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map_buf_first, (uint32_t)disp_buf_first, (uint32_t)disp_buf_first, draw_area_w, draw_area_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); - } - } + if(lv_area_get_size(draw_area) >= 240) { + lv_gpu_stm32_dma2d_blend_normal_opa(disp_buf_first, disp_w, map_buf_first, opa, map_w, draw_area_w, draw_area_h); return; } #endif diff --git a/src/lv_gpu/lv_draw.mk b/src/lv_gpu/lv_draw.mk new file mode 100644 index 000000000..cff89c686 --- /dev/null +++ b/src/lv_gpu/lv_draw.mk @@ -0,0 +1,6 @@ +CSRCS += lv_gpu_stm32_dma2d.c + +DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_gpu +VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_gpu + +CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/lv_gpu" diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c new file mode 100644 index 000000000..77cda0b5b --- /dev/null +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -0,0 +1,168 @@ +/** + * @file lv_gpu_stm32_dma2d.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_gpu_stm32_dma2d.h" + +#if LV_USE_GPU_STM32_DMA2D +#include "stm32f7xx_hal.h" + +/********************* + * DEFINES + *********************/ + +#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP +#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565 +#define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565 +#elif LV_COLOR_DEPTH == 32 +#define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_ARGB8888 +#define DMA2D_INPUT_FORMAT DMA2D_INPUT_ARGB8888 +#else +/*Can't use GPU with other formats*/ +#undef LV_USE_GPU_STM32_DMA2D +#endif + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC VARIABLES + **********************/ +static DMA2D_HandleTypeDef hdma2d; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ +void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h) +{ +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_R2M; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = buf_w - fill_w; + hdma2d.LayerCfg[1].InputAlpha = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[1].InputOffset = 0; + + /* DMA2D Initialization */ + if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { + HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)buf, fill_w, fill_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + } + } +} + +void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h) +{ +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + /* Configure the DMA2D Mode, Color Mode and line output offset */ + hdma2d.Init.Mode = DMA2D_M2M_BLEND; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = buf_w - fill_w; + + /* Configure the foreground -> The character */ + lv_color32_t c32; + c32.full = lv_color_to32(color); + c32.ch.alpha = opa; + hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = c32.full; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_A8; + hdma2d.LayerCfg[1].InputOffset = 0; + + /* Configure the background -> Display buffer */ + hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[0].InputAlpha = 0x00; + hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[0].InputOffset = buf_w - fill_w; + + /* DMA2D Initialization */ + HAL_DMA2D_Init(&hdma2d); + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + HAL_DMA2D_ConfigLayer(&hdma2d, 1); + HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); +} + +void lv_gpu_stm32_dma2d_blend_normal_cover(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) +{ +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_M2M; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = buf_w - copy_w; + + /* Foreground layer */ + hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = 0xFF; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[1].InputOffset = map_w - copy_w; + hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; + + /* DMA2D Initialization */ + if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { + HAL_DMA2D_Start(&hdma2d, (uint32_t)map, (uint32_t)buf, copy_w, copy_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + } + } +} + +void lv_gpu_stm32_dma2d_blend_normal_opa(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) +{ +#if __DCACHE_PRESENT + SCB_CleanInvalidateDCache(); +#endif + hdma2d.Instance = DMA2D; + hdma2d.Init.Mode = DMA2D_M2M_BLEND; + hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; + hdma2d.Init.OutputOffset = buf_w - copy_w; + + /* Background layer */ + hdma2d.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; + hdma2d.LayerCfg[0].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[0].InputOffset = buf_w - copy_w; + hdma2d.LayerCfg[0].AlphaInverted = DMA2D_REGULAR_ALPHA; + + /* Foreground layer */ + hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; + hdma2d.LayerCfg[1].InputAlpha = opa; + hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; + hdma2d.LayerCfg[1].InputOffset = map_w - copy_w; + hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; + + /* DMA2D Initialization */ + if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { + HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map, (uint32_t)buf, (uint32_t)buf, copy_w, copy_h); + HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + } + } +} +/********************** + * STATIC FUNCTIONS + **********************/ + + +#endif diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.h b/src/lv_gpu/lv_gpu_stm32_dma2d.h new file mode 100644 index 000000000..5a6985af7 --- /dev/null +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.h @@ -0,0 +1,43 @@ +/** + * @file lv_gpu_stm32_dma2d.h + * + */ + +#ifndef LV_GPU_STM32_DMA2D_H +#define LV_GPU_STM32_DMA2D_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "../lv_misc/lv_area.h" +#include "../lv_misc/lv_color.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h); +void lv_gpu_stm32_dma2d_blend_normal_cover(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); +void lv_gpu_stm32_dma2d_blend_normal_opa(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); +void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /*LV_GPU_STM32_DMA2D_H*/ From 23368fa704768ead82be33e2267810169b9744aa Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Thu, 16 Apr 2020 16:37:02 +0200 Subject: [PATCH 4/9] draw_img: blend argb images directly with DMA2D in trivial cases --- src/lv_draw/lv_draw_blend.c | 6 +++--- src/lv_draw/lv_draw_img.c | 12 ++++++++++++ src/lv_gpu/lv_gpu_stm32_dma2d.c | 7 ++++--- src/lv_gpu/lv_gpu_stm32_dma2d.h | 4 ++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/lv_draw/lv_draw_blend.c b/src/lv_draw/lv_draw_blend.c index 8b1c781f3..0f24e2e90 100644 --- a/src/lv_draw/lv_draw_blend.c +++ b/src/lv_draw/lv_draw_blend.c @@ -655,7 +655,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons int32_t map_w = lv_area_get_width(map_area); /*Create a temp. disp_buf which always point to first pixel to draw*/ - lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area->y1 + draw_area->x1;; + lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area->y1 + draw_area->x1; /*Create a temp. map_buf which always point to first pixel to draw from the map*/ const lv_color_t * map_buf_first = map_buf + map_w * (draw_area->y1 - (map_area->y1 - disp_area->y1)); @@ -687,7 +687,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons if(opa > LV_OPA_MAX) { #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { - lv_gpu_stm32_dma2d_blend_normal_cover(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h); + lv_gpu_stm32_dma2d_copy(disp_buf_first, disp_w, map_buf_first, map_w, draw_area_w, draw_area_h); return; } #endif @@ -702,7 +702,7 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons else { #if LV_USE_GPU_STM32_DMA2D if(lv_area_get_size(draw_area) >= 240) { - lv_gpu_stm32_dma2d_blend_normal_opa(disp_buf_first, disp_w, map_buf_first, opa, map_w, draw_area_w, draw_area_h); + lv_gpu_stm32_dma2d_blend(disp_buf_first, disp_w, map_buf_first, opa, map_w, draw_area_w, draw_area_h); return; } #endif diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index a4ee0386f..4fa2196f2 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -13,6 +13,8 @@ #include "../lv_core/lv_refr.h" #include "../lv_misc/lv_mem.h" #include "../lv_misc/lv_math.h" +#include "../lv_gpu/lv_gpu_stm32_dma2d.h" + /********************* * DEFINES @@ -395,6 +397,16 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, /*Simple ARGB image. Handle it as special case because it's very common*/ if(other_mask_cnt == 0 && !transform && !chroma_key && draw_dsc->recolor_opa == LV_OPA_TRANSP && alpha_byte) { +#if LV_USE_GPU_STM32_DMA2D && LV_COLOR_DEPTH == 32 + /*Blend ARGB images directly*/ + if(lv_area_get_size(draw_area) > 240) { + int32_t disp_w = lv_area_get_width(disp_area); + lv_color_t * disp_buf = vdb->buf_act; + lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area.y1 + draw_area.x1; + lv_gpu_stm32_dma2d_blend(disp_buf_first, disp_w, (const lv_color_t *)map_buf_tmp, draw_dsc->opa, map_w, draw_area_w, draw_area_h); + return; + } +#endif int32_t x; int32_t y; for(y = 0; y < draw_area_h; y++) { diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 77cda0b5b..4ecee6e7f 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -101,7 +101,7 @@ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); } -void lv_gpu_stm32_dma2d_blend_normal_cover(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) +void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { #if __DCACHE_PRESENT SCB_CleanInvalidateDCache(); @@ -128,7 +128,7 @@ void lv_gpu_stm32_dma2d_blend_normal_cover(lv_color_t * buf, lv_coord_t buf_w, c } } -void lv_gpu_stm32_dma2d_blend_normal_opa(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) +void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { #if __DCACHE_PRESENT SCB_CleanInvalidateDCache(); @@ -145,7 +145,7 @@ void lv_gpu_stm32_dma2d_blend_normal_opa(lv_color_t * buf, lv_coord_t buf_w, con hdma2d.LayerCfg[0].AlphaInverted = DMA2D_REGULAR_ALPHA; /* Foreground layer */ - hdma2d.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; + hdma2d.LayerCfg[1].AlphaMode = DMA2D_COMBINE_ALPHA; hdma2d.LayerCfg[1].InputAlpha = opa; hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_FORMAT; hdma2d.LayerCfg[1].InputOffset = map_w - copy_w; @@ -160,6 +160,7 @@ void lv_gpu_stm32_dma2d_blend_normal_opa(lv_color_t * buf, lv_coord_t buf_w, con } } } + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.h b/src/lv_gpu/lv_gpu_stm32_dma2d.h index 5a6985af7..c6c21107c 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.h +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.h @@ -28,8 +28,8 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h); -void lv_gpu_stm32_dma2d_blend_normal_cover(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); -void lv_gpu_stm32_dma2d_blend_normal_opa(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); +void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); +void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h); /********************** From 44f2ca17fd850b690f8a94fce4e6d3e1e91ca15f Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 20 Apr 2020 14:36:35 +0200 Subject: [PATCH 5/9] add comments to GPU DMA2D functions --- lv_conf_template.h | 3 +- src/lv_conf_internal.h | 5 +--- src/lv_gpu/lv_gpu_stm32_dma2d.c | 42 ++++++++++++++++++++++++++ src/lv_gpu/lv_gpu_stm32_dma2d.h | 52 ++++++++++++++++++++++++++++++--- 4 files changed, 92 insertions(+), 10 deletions(-) diff --git a/lv_conf_template.h b/lv_conf_template.h index b87dddf2b..d1f0ed96e 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -177,8 +177,7 @@ typedef void * lv_group_user_data_t; /* 1: Enable GPU interface*/ #define LV_USE_GPU 1 -#define LV_GPU_INCLUDE /*E.g. "stm32f7xx_hal.h"*/ -#define LV_USE_GPU_STM32_DMA2D 1 +#define LV_USE_GPU_STM32_DMA2D 0 /* 1: Enable file system (might be required for images */ #define LV_USE_FILESYSTEM 1 diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 338afd0a7..325501ddc 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -263,11 +263,8 @@ #ifndef LV_USE_GPU #define LV_USE_GPU 1 #endif -#ifndef LV_GPU_INCLUDE -#define LV_GPU_INCLUDE /*E.g. "stm32f7xx_hal.h"*/ -#endif #ifndef LV_USE_GPU_STM32_DMA2D -#define LV_USE_GPU_STM32_DMA2D 1 +#define LV_USE_GPU_STM32_DMA2D 0 #endif /* 1: Enable file system (might be required for images */ diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 4ecee6e7f..38c682558 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -46,6 +46,16 @@ static DMA2D_HandleTypeDef hdma2d; /********************** * GLOBAL FUNCTIONS **********************/ + +/** + * Fill an area in the buffer with a color + * @param buf a buffer which should be filled + * @param buf_w width of the buffer in pixels + * @param color fill color + * @param fill_w width to fill in pixels (<= buf_w) + * @param fill_h height to fill in pixels + * @note `buf_w - fill_w` is offset to the next line after fill + */ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h) { #if __DCACHE_PRESENT @@ -68,6 +78,17 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo } } +/** + * Fill an area in the buffer with a color but take into account a mask which describes the opacity of each pixel + * @param buf a buffer which should be filled using a mask + * @param buf_w width of the buffer in pixels + * @param color fill color + * @param mask 0..255 values describing the opacity of the corresponding pixel. It's width is `fill_w` + * @param opa overall opacity. 255 in `mask` should mean this opacity. + * @param fill_w width to fill in pixels (<= buf_w) + * @param fill_h height to fill in pixels + * @note `buf_w - fill_w` is offset to the next line after fill + */ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h) { #if __DCACHE_PRESENT @@ -101,6 +122,16 @@ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); } +/** + * Copy a map (typically RGB image) to a buffer + * @param buf a buffer where map should be copied + * @param buf_w width of the buffer in pixels + * @param map an "image" to copy + * @param map_w width of teh map in pixels + * @param copy_w width of the area to copy in pixels (<= buf_w) + * @param copy_h height of the area to copy in pixels + * @note `map_w - fill_w` is offset to the next line after copy + */ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { #if __DCACHE_PRESENT @@ -128,6 +159,17 @@ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_ } } +/** + * Blend a map (e.g. ARGB image or RGB image with opacity) to a buffer + * @param buf a buffer where `map` should be copied + * @param buf_w width of the buffer in pixels + * @param map an "image" to copy + * @param opa opacity of `map` + * @param map_w width of teh map in pixels + * @param copy_w width of the area to copy in pixels (<= buf_w) + * @param copy_h height of the area to copy in pixels + * @note `map_w - fill_w` is offset to the next line after copy + */ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { #if __DCACHE_PRESENT diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.h b/src/lv_gpu/lv_gpu_stm32_dma2d.h index c6c21107c..65db95bda 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.h +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.h @@ -27,11 +27,55 @@ extern "C" { /********************** * GLOBAL PROTOTYPES **********************/ -void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h); -void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); -void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); -void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h); +/** + * Fill an area in the buffer with a color + * @param buf a buffer which should be filled + * @param buf_w width of the buffer in pixels + * @param color fill color + * @param fill_w width to fill in pixels (<= buf_w) + * @param fill_h height to fill in pixels + * @note `buf_w - fill_w` is offset to the next line after fill + */ +void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h); + + +/** + * Fill an area in the buffer with a color but take into account a mask which describes the opacity of each pixel + * @param buf a buffer which should be filled using a mask + * @param buf_w width of the buffer in pixels + * @param color fill color + * @param mask 0..255 values describing the opacity of the corresponding pixel. It's width is `fill_w` + * @param opa overall opacity. 255 in `mask` should mean this opacity. + * @param fill_w width to fill in pixels (<= buf_w) + * @param fill_h height to fill in pixels + * @note `buf_w - fill_w` is offset to the next line after fill + */ +void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h); + +/** + * Copy a map (typically RGB image) to a buffer + * @param buf a buffer where map should be copied + * @param buf_w width of the buffer in pixels + * @param map an "image" to copy + * @param map_w width of teh map in pixels + * @param copy_w width of the area to copy in pixels (<= buf_w) + * @param copy_h height of the area to copy in pixels + * @note `map_w - fill_w` is offset to the next line after copy + */ +void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); +/** + * Blend a map (e.g. ARGB image or RGB image with opacity) to a buffer + * @param buf a buffer where `map` should be copied + * @param buf_w width of the buffer in pixels + * @param map an "image" to copy + * @param opa opacity of `map` + * @param map_w width of teh map in pixels + * @param copy_w width of the area to copy in pixels (<= buf_w) + * @param copy_h height of the area to copy in pixels + * @note `map_w - fill_w` is offset to the next line after copy + */ +void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h); /********************** * MACROS **********************/ From d98362a60d80b1bb80aa33e9975f5acfd1d91b73 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 24 Apr 2020 11:52:31 +0200 Subject: [PATCH 6/9] add disp_drv->wait_cb --- src/lv_core/lv_refr.c | 8 ++++-- src/lv_gpu/lv_gpu_stm32_dma2d.c | 44 +++++++++++++++++---------------- src/lv_hal/lv_hal_disp.h | 5 ++++ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/lv_core/lv_refr.c b/src/lv_core/lv_refr.c index addfff02e..9e4795e01 100644 --- a/src/lv_core/lv_refr.c +++ b/src/lv_core/lv_refr.c @@ -458,7 +458,9 @@ static void lv_refr_area_part(const lv_area_t * area_p) /*In non double buffered mode, before rendering the next part wait until the previous image is * flushed*/ if(lv_disp_is_double_buf(disp_refr) == false) { - while(vdb->flushing) ; + while(vdb->flushing) { + if(disp_refr->driver.wait_cb) disp_refr->driver.wait_cb(&disp_refr->driver); + } } lv_obj_t * top_p; @@ -654,7 +656,9 @@ static void lv_refr_vdb_flush(void) /*In double buffered mode wait until the other buffer is flushed before flushing the current * one*/ if(lv_disp_is_double_buf(disp_refr)) { - while(vdb->flushing); + while(vdb->flushing) { + if(disp_refr->driver.wait_cb) disp_refr->driver.wait_cb(&disp_refr->driver); + } } vdb->flushing = 1; diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 38c682558..169a24eaa 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -33,6 +33,7 @@ /********************** * STATIC PROTOTYPES **********************/ +static void dma2d_wait(void); /********************** * STATIC VARIABLES @@ -70,12 +71,10 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo hdma2d.LayerCfg[1].InputOffset = 0; /* DMA2D Initialization */ - if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { - HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)buf, fill_w, fill_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); - } - } + HAL_DMA2D_Init(&hdma2d) { + HAL_DMA2D_ConfigLayer(&hdma2d, 1) + HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)buf, fill_w, fill_h); + dma2d_wait(); } /** @@ -119,7 +118,7 @@ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t HAL_DMA2D_ConfigLayer(&hdma2d, 0); HAL_DMA2D_ConfigLayer(&hdma2d, 1); HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t) mask, (uint32_t) buf, (uint32_t)buf, fill_w, fill_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); + dma2d_wait(); } /** @@ -150,13 +149,11 @@ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_ hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* DMA2D Initialization */ - if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { - HAL_DMA2D_Start(&hdma2d, (uint32_t)map, (uint32_t)buf, copy_w, copy_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); - } - } + HAL_DMA2D_Init(&hdma2d); + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + HAL_DMA2D_ConfigLayer(&hdma2d, 1); + HAL_DMA2D_Start(&hdma2d, (uint32_t)map, (uint32_t)buf, copy_w, copy_h); + dma2d_wait(); } /** @@ -194,18 +191,23 @@ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* DMA2D Initialization */ - if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) { - HAL_DMA2D_ConfigLayer(&hdma2d, 0); - if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { - HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map, (uint32_t)buf, (uint32_t)buf, copy_w, copy_h); - HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY); - } - } + HAL_DMA2D_Init(&hdma2d); { + HAL_DMA2D_ConfigLayer(&hdma2d, 0); + HAL_DMA2D_ConfigLayer(&hdma2d, 1); + HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map, (uint32_t)buf, (uint32_t)buf, copy_w, copy_h); + dma2d_wait(); } /********************** * STATIC FUNCTIONS **********************/ +static void dma2d_wait(void) +{ + lv_disp_t * disp = lv_refr_get_disp_refreshing(); + while(HAL_DMA2D_PollForTransfer(&hdma2d, 0) == HAL_BUSY) { + if(disp->driver.wait_cb) disp->driver.wait_cb(&disp->driver); + } +} #endif diff --git a/src/lv_hal/lv_hal_disp.h b/src/lv_hal/lv_hal_disp.h index da664f6ac..2e1ad41a5 100644 --- a/src/lv_hal/lv_hal_disp.h +++ b/src/lv_hal/lv_hal_disp.h @@ -104,6 +104,11 @@ typedef struct _disp_drv_t { * number of flushed pixels */ void (*monitor_cb)(struct _disp_drv_t * disp_drv, uint32_t time, uint32_t px); + /** OPTIONAL: Called periodically while lvgl waits for operation to be completed. + * For example flushing or GPU + * User can execute very simple tasks here or yield the task */ + void (*wait_cb)(struct _disp_drv_t * disp_drv); + #if LV_USE_GPU /** OPTIONAL: Blend two memories using opacity (GPU only)*/ void (*gpu_blend_cb)(struct _disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, From 5f528d53f1b16afe16a612f408cb9ced73491e78 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Fri, 24 Apr 2020 12:08:33 +0200 Subject: [PATCH 7/9] dma2d fixes --- src/lv_draw/lv_draw_img.c | 2 +- src/lv_gpu/lv_gpu_stm32_dma2d.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lv_draw/lv_draw_img.c b/src/lv_draw/lv_draw_img.c index 4fa2196f2..31cdbf786 100644 --- a/src/lv_draw/lv_draw_img.c +++ b/src/lv_draw/lv_draw_img.c @@ -399,7 +399,7 @@ static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area, if(other_mask_cnt == 0 && !transform && !chroma_key && draw_dsc->recolor_opa == LV_OPA_TRANSP && alpha_byte) { #if LV_USE_GPU_STM32_DMA2D && LV_COLOR_DEPTH == 32 /*Blend ARGB images directly*/ - if(lv_area_get_size(draw_area) > 240) { + if(lv_area_get_size(&draw_area) > 240) { int32_t disp_w = lv_area_get_width(disp_area); lv_color_t * disp_buf = vdb->buf_act; lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area.y1 + draw_area.x1; diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 169a24eaa..7791d82b5 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -7,6 +7,7 @@ * INCLUDES *********************/ #include "lv_gpu_stm32_dma2d.h" +#include "../lv_core/lv_refr.h" #if LV_USE_GPU_STM32_DMA2D #include "stm32f7xx_hal.h" @@ -71,8 +72,8 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo hdma2d.LayerCfg[1].InputOffset = 0; /* DMA2D Initialization */ - HAL_DMA2D_Init(&hdma2d) { - HAL_DMA2D_ConfigLayer(&hdma2d, 1) + HAL_DMA2D_Init(&hdma2d); + HAL_DMA2D_ConfigLayer(&hdma2d, 1); HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)buf, fill_w, fill_h); dma2d_wait(); } @@ -191,7 +192,7 @@ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color hdma2d.LayerCfg[1].AlphaInverted = DMA2D_REGULAR_ALPHA; /* DMA2D Initialization */ - HAL_DMA2D_Init(&hdma2d); { + HAL_DMA2D_Init(&hdma2d); HAL_DMA2D_ConfigLayer(&hdma2d, 0); HAL_DMA2D_ConfigLayer(&hdma2d, 1); HAL_DMA2D_BlendingStart(&hdma2d, (uint32_t)map, (uint32_t)buf, (uint32_t)buf, copy_w, copy_h); @@ -205,7 +206,7 @@ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color static void dma2d_wait(void) { lv_disp_t * disp = lv_refr_get_disp_refreshing(); - while(HAL_DMA2D_PollForTransfer(&hdma2d, 0) == HAL_BUSY) { + while(HAL_DMA2D_PollForTransfer(&hdma2d, 0) == HAL_TIMEOUT) { if(disp->driver.wait_cb) disp->driver.wait_cb(&disp->driver); } } From 843fa5e30479d0e04eb62c452b74a54a1c863f9a Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Mon, 27 Apr 2020 21:07:15 +0200 Subject: [PATCH 8/9] DMA2D fix with 16 bit color depth --- src/lv_gpu/lv_gpu_stm32_dma2d.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 7791d82b5..84248fb6a 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -16,7 +16,15 @@ * DEFINES *********************/ -#if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP +#if LV_COLOR_16_SWAP +#error "Can't use DMA2D with LV_COLOR_16_SWAP 1" +#endif + +#if LV_COLOR_DEPTH == 8 +#error "Can't use DMA2D with LV_COLOR_DEPTH == 8" +#endif + +#if LV_COLOR_DEPTH == 16 #define DMA2D_OUTPUT_FORMAT DMA2D_OUTPUT_RGB565 #define DMA2D_INPUT_FORMAT DMA2D_INPUT_RGB565 #elif LV_COLOR_DEPTH == 32 @@ -24,7 +32,6 @@ #define DMA2D_INPUT_FORMAT DMA2D_INPUT_ARGB8888 #else /*Can't use GPU with other formats*/ -#undef LV_USE_GPU_STM32_DMA2D #endif /********************** From a54d6a175258381571569c03b895d5d916430da2 Mon Sep 17 00:00:00 2001 From: Gabor Kiss-Vamosi Date: Tue, 28 Apr 2020 14:39:02 +0200 Subject: [PATCH 9/9] DMA2D: invalidate cache only if enabled --- src/lv_gpu/lv_gpu_stm32_dma2d.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/lv_gpu/lv_gpu_stm32_dma2d.c b/src/lv_gpu/lv_gpu_stm32_dma2d.c index 84248fb6a..b4b7fd493 100644 --- a/src/lv_gpu/lv_gpu_stm32_dma2d.c +++ b/src/lv_gpu/lv_gpu_stm32_dma2d.c @@ -41,6 +41,7 @@ /********************** * STATIC PROTOTYPES **********************/ +static void invalidate_cache(void); static void dma2d_wait(void); /********************** @@ -67,9 +68,8 @@ static DMA2D_HandleTypeDef hdma2d; */ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, lv_coord_t fill_w, lv_coord_t fill_h) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif + invalidate_cache(); + hdma2d.Instance = DMA2D; hdma2d.Init.Mode = DMA2D_R2M; hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; @@ -98,9 +98,8 @@ void lv_gpu_stm32_dma2d_fill(lv_color_t * buf, lv_coord_t buf_w, lv_color_t colo */ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t color, const lv_opa_t * mask, lv_opa_t opa, lv_coord_t fill_w, lv_coord_t fill_h) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif + invalidate_cache(); + /* Configure the DMA2D Mode, Color Mode and line output offset */ hdma2d.Init.Mode = DMA2D_M2M_BLEND; hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; @@ -141,9 +140,8 @@ void lv_gpu_stm32_dma2d_fill_mask(lv_color_t * buf, lv_coord_t buf_w, lv_color_t */ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif + invalidate_cache(); + hdma2d.Instance = DMA2D; hdma2d.Init.Mode = DMA2D_M2M; hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; @@ -177,9 +175,8 @@ void lv_gpu_stm32_dma2d_copy(lv_color_t * buf, lv_coord_t buf_w, const lv_color_ */ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color_t * map, lv_opa_t opa, lv_coord_t map_w, lv_coord_t copy_w, lv_coord_t copy_h) { -#if __DCACHE_PRESENT - SCB_CleanInvalidateDCache(); -#endif + invalidate_cache(); + hdma2d.Instance = DMA2D; hdma2d.Init.Mode = DMA2D_M2M_BLEND; hdma2d.Init.ColorMode = DMA2D_OUTPUT_FORMAT; @@ -210,6 +207,15 @@ void lv_gpu_stm32_dma2d_blend(lv_color_t * buf, lv_coord_t buf_w, const lv_color * STATIC FUNCTIONS **********************/ +static void invalidate_cache(void) +{ +#if __DCACHE_PRESENT + if(SCB->CCR & (uint32_t)SCB_CCR_DC_Msk) { + SCB_CleanInvalidateDCache(); + } +#endif +} + static void dma2d_wait(void) { lv_disp_t * disp = lv_refr_get_disp_refreshing();