add builtin STM32 DMA2D support

This commit is contained in:
Gabor Kiss-Vamosi
2020-04-16 11:12:20 +02:00
parent ca03ef2b1f
commit 54019d4934
11 changed files with 376 additions and 173 deletions

View File

@@ -177,6 +177,8 @@ typedef void * lv_group_user_data_t;
/* 1: Enable GPU interface*/ /* 1: Enable GPU interface*/
#define LV_USE_GPU 1 #define LV_USE_GPU 1
#define LV_GPU_INCLUDE <stdint.h> /*E.g. "stm32f7xx_hal.h"*/
#define LV_USE_GPU_STM32_DMA2D 1
/* 1: Enable file system (might be required for images */ /* 1: Enable file system (might be required for images */
#define LV_USE_FILESYSTEM 1 #define LV_USE_FILESYSTEM 1

View File

@@ -263,6 +263,12 @@
#ifndef LV_USE_GPU #ifndef LV_USE_GPU
#define LV_USE_GPU 1 #define LV_USE_GPU 1
#endif #endif
#ifndef LV_GPU_INCLUDE
#define LV_GPU_INCLUDE <stdint.h> /*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 */ /* 1: Enable file system (might be required for images */
#ifndef LV_USE_FILESYSTEM #ifndef LV_USE_FILESYSTEM

View File

@@ -11,14 +11,30 @@
#include "../lv_misc/lv_math.h" #include "../lv_misc/lv_math.h"
#include "../lv_hal/lv_hal_disp.h" #include "../lv_hal/lv_hal_disp.h"
#include "../lv_core/lv_refr.h" #include "../lv_core/lv_refr.h"
#include LV_GPU_INCLUDE
static DMA2D_HandleTypeDef hdma2d;
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
#define FILL_DIRECT_LEN 32
#define FILL_DIRECT_MASK 0x1F
#define GPU_SIZE_LIMIT 240 #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 * 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) \ #define FILL_NORMAL_MASK_PX(out_x, color) \
if(*mask_tmp_x) { \ if(*mask_tmp_x) { \
if(*mask_tmp_x == LV_OPA_COVER) disp_buf_tmp[out_x] = color; \ if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[out_x] = color; \
else disp_buf_tmp[out_x] = lv_color_mix(color, disp_buf_tmp[out_x], *mask_tmp_x); \ else disp_buf_first[out_x] = lv_color_mix(color, disp_buf_first[out_x], *mask_tmp_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) \ #define MAP_NORMAL_MASK_PX(x) \
if(*mask_tmp_x) { \ if(*mask_tmp_x) { \
if(*mask_tmp_x == LV_OPA_COVER) disp_buf_tmp[x] = map_buf_tmp[x]; \ if(*mask_tmp_x == LV_OPA_COVER) disp_buf_first[x] = map_buf_first[x]; \
else disp_buf_tmp[x] = lv_color_mix(map_buf_tmp[x], disp_buf_tmp[x], *mask_tmp_x); \ else disp_buf_first[x] = lv_color_mix(map_buf_first[x], disp_buf_first[x], *mask_tmp_x); \
} \ } \
mask_tmp_x++; mask_tmp_x++;
@@ -103,17 +119,17 @@ mask_tmp_x++;
/** /**
* * Fill and area in the display buffer.
* @param disp_area * @param clip_area clip the fill to this area (absolute coordinates)
* @param clip_area already truncated to disp_arae * @param fill_area fill this area (absolute coordinates) (should be clipped)
* @param fill_area * @param color fill color
* @param disp_buf * @param mask a mask to apply on the fill (uint8_t array with 0x00..0xff values).
* @param cf * Relative to fill area but its width is truncated to clip area.
* @param color * @param mask_res LV_MASK_RES_COVER: the mask has only 0xff values (no mask),
* @param mask * LV_MASK_RES_TRANSP: the mask has only 0x00 values (full transparent),
* @param mask_res * LV_MASK_RES_CHANGED: the mask has mixed values
* @param opa * @param opa overall opacity in 0x00..0xff range
* @param mode * @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, 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, 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*/ /*Do not draw transparent things*/
if(opa < LV_OPA_MIN) return; 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_t * disp = lv_refr_get_disp_refreshing();
lv_disp_buf_t * vdb = lv_disp_get_buf(disp); 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, 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 * mask, lv_draw_mask_res_t mask_res,
lv_opa_t opa, lv_blend_mode_t mode) lv_opa_t opa, lv_blend_mode_t mode)
{ {
/*Do not draw transparent things*/ /*Do not draw transparent things*/
if(opa < LV_OPA_MIN) return; 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. /* Get clipped fill area which is the real draw area.
* It is always the same or inside `fill_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, 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, lv_color_t color, lv_opa_t opa,
const lv_opa_t * mask, lv_draw_mask_res_t mask_res) 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*/ /*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); 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_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*/ /*Create a temp. disp_buf which always point to the first pixel of the destination area*/
lv_color_t * disp_buf_tmp = disp_buf + disp_w * draw_area->y1; lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area->y1 + draw_area->x1;
int32_t x; int32_t x;
int32_t y; 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*/ /*Simple fill (maybe with opacity), no masking*/
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) { if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) {
if(opa > LV_OPA_MAX) { if(opa > LV_OPA_MAX) {
lv_color_t * disp_buf_tmp_ori = disp_buf_tmp;
#if LV_USE_GPU #if LV_USE_GPU
if(disp->driver.gpu_fill_cb && lv_area_get_size(draw_area) > GPU_SIZE_LIMIT) { 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); disp->driver.gpu_fill_cb(&disp->driver, disp_buf, disp_w, draw_area, color);
return; return;
} }
#if LV_USE_GPU_STM32_CHROM_ART
if(lv_area_get_size(draw_area) >= 240) {
#if __DCACHE_PRESENT
SCB_CleanInvalidateDCache();
#endif #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*/ /* DMA2D Initialization */
/*Set the first pixels manually*/ if (HAL_DMA2D_Init(&hdma2d) == HAL_OK) {
int32_t fill_end = draw_area->x1 + FILL_DIRECT_LEN + (draw_area_w & FILL_DIRECT_MASK) - 1; if (HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) {
int32_t direct_fill_end = LV_MATH_MIN(draw_area->x2, HAL_DMA2D_Start(&hdma2d, (uint32_t)lv_color_to32(color), (uint32_t)disp_buf_first, draw_area_w, draw_area_h);
fill_end); HAL_DMA2D_PollForTransfer(&hdma2d, HAL_MAX_DELAY);
for(x = draw_area->x1; x <= direct_fill_end ; x++) { }
disp_buf_tmp[x].full = color.full; }
return;
} }
#endif
for(; x <= draw_area->x2; x += FILL_DIRECT_LEN) { #endif
lv_memcpy(&disp_buf_tmp[x], &disp_buf_tmp[draw_area->x1], FILL_DIRECT_LEN * sizeof(lv_color_t)); /*Software rendering*/
} for(y = 0; y < draw_area_h; y++) {
lv_color_fill(disp_buf_first, color, draw_area_w);
disp_buf_tmp += disp_w; disp_buf_first += 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;
} }
} }
/*No mask with opacity*/ /*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(x = 0; x < draw_area_w ; x++) blend_buf[x].full = color.full;
for(y = draw_area->y1; y <= draw_area->y2; y++) { 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->driver.gpu_blend_cb(&disp->driver, disp_buf_first, blend_buf, draw_area_w, opa);
disp_buf_tmp += disp_w; disp_buf_first += disp_w;
} }
return; 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_color_premult(color, opa, color_premult);
lv_opa_t opa_inv = 255 - opa; lv_opa_t opa_inv = 255 - opa;
for(y = draw_area->y1; y <= draw_area->y2; y++) { for(y = 0; y < draw_area_h; y++) {
for(x = draw_area->x1; x <= draw_area->x2; x++) { for(x = 0; x < draw_area_w; x++) {
if(last_dest_color.full != disp_buf_tmp[x].full) { if(last_dest_color.full != disp_buf_first[x].full) {
last_dest_color = disp_buf_tmp[x]; last_dest_color = disp_buf_first[x];
#if LV_COLOR_SCREEN_TRANSP #if LV_COLOR_SCREEN_TRANSP
if(disp->driver.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); &last_res_color.ch.alpha);
} }
else else
#endif #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*/ /*Masked*/
else { else {
/* The mask is relative to the clipped area.
* In the cycles below mask will be indexed from `draw_area.x1` /*DMA2D could be used here but it's much slower than software rendering*/
* but it corresponds to zero index. So prepare `mask_tmp` accordingly. */ #if LV_USE_GPU_STM32_CHROM_ART && 0
const lv_opa_t * mask_tmp = mask - draw_area->x1; 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*/ /*Buffer the result color to avoid recalculating the same color*/
lv_color_t last_dest_color; lv_color_t last_dest_color;
lv_color_t last_res_color; lv_color_t last_res_color;
lv_opa_t last_mask = LV_OPA_TRANSP; lv_opa_t last_mask = LV_OPA_TRANSP;
last_dest_color.full = disp_buf_tmp[0].full; last_dest_color.full = disp_buf_first[0].full;
last_res_color.full = disp_buf_tmp[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*/ /*Only the mask matters*/
if(opa > LV_OPA_MAX) { if(opa > LV_OPA_MAX) {
for(y = draw_area->y1; y <= draw_area->y2; y++) { for(y = 0; y < draw_area_h; y++) {
const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; const lv_opa_t * mask_tmp_x = mask;
#if 0 #if 0
for(x = draw_area->x1; x <= draw_area->x2; x++) { for(x = draw_area->x1; x <= draw_area->x2; x++) {
#if LV_COLOR_SCREEN_TRANSP #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 #endif
} }
#else #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 #if LV_COLOR_SCREEN_TRANSP
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color) FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
#else #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) { for(; x <= x_end4; x += 4) {
if(*mask32) { if(*mask32) {
if((*mask32) == 0xFFFFFFFF) { if((*mask32) == 0xFFFFFFFF) {
disp_buf_tmp[x] = color; disp_buf_first[x] = color;
disp_buf_tmp[x + 1] = color; disp_buf_first[x + 1] = color;
disp_buf_tmp[x + 2] = color; disp_buf_first[x + 2] = color;
disp_buf_tmp[x + 3] = color; disp_buf_first[x + 3] = color;
} }
else { else {
mask_tmp_x = (const lv_opa_t *)mask32; 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; 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 #if LV_COLOR_SCREEN_TRANSP
FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color) FILL_NORMAL_MASK_PX_SCR_TRANSP(x, color)
#else #else
@@ -429,46 +509,60 @@ static void fill_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, con
#endif #endif
} }
#endif #endif
disp_buf_tmp += disp_w; disp_buf_first += disp_w;
mask_tmp += draw_area_w; mask += draw_area_w;
} }
} }
/*Handle opa and mask values too*/ /*Handle opa and mask values too*/
else { else {
lv_opa_t opa_tmp = LV_OPA_TRANSP; lv_opa_t opa_tmp = LV_OPA_TRANSP;
for(y = draw_area->y1; y <= draw_area->y2; y++) { for(y = draw_area->y1; y <= draw_area->y2; y++) {
const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; const lv_opa_t * mask_tmp_x = mask;
for(x = draw_area->x1; x <= draw_area->x2; x++) { for(x = 0; x < draw_area_w; x++) {
if(*mask_tmp_x) { if(*mask_tmp_x) {
if(*mask_tmp_x != last_mask) opa_tmp = *mask_tmp_x == LV_OPA_COVER ? opa : (uint32_t)((uint32_t)( if(*mask_tmp_x != last_mask) opa_tmp = *mask_tmp_x == LV_OPA_COVER ? opa : (uint32_t)((uint32_t)(
*mask_tmp_x) * opa) >> 8; *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 LV_COLOR_SCREEN_TRANSP
if(disp->driver.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); &last_res_color.ch.alpha);
} }
else else
#endif #endif
{ {
if(opa_tmp == LV_OPA_COVER) last_res_color = color; 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_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++; mask_tmp_x++;
} }
disp_buf_tmp += disp_w; disp_buf_first += disp_w;
mask_tmp += draw_area_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, 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, 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) 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, 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_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) 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*/ /*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); 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_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*/ /*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); int32_t map_w = lv_area_get_width(map_area);
/*Create a temp. disp_buf which always point to current line to draw*/ /*Create a temp. disp_buf which always point to first pixel to draw*/
lv_color_t * disp_buf_tmp = disp_buf + disp_w * draw_area->y1; 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 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. 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 #if LV_COLOR_SCREEN_TRANSP
lv_opa_t opa_composed; 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*/ /*Simple fill (maybe with opacity), no masking*/
if(mask_res == LV_DRAW_MASK_RES_FULL_COVER) { 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 LV_USE_GPU
if(disp->driver.gpu_blend_cb && (lv_area_get_size(draw_area) > GPU_SIZE_LIMIT)) { 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++) { 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->driver.gpu_blend_cb(&disp->driver, disp_buf_first, map_buf_first, draw_area_w, opa);
disp_buf_tmp += disp_w; disp_buf_first += disp_w;
map_buf_tmp += map_w; map_buf_first += map_w;
} }
return; return;
} }
#endif #endif
if(opa > LV_OPA_MAX) { if(opa > LV_OPA_MAX) {
for(y = draw_area->y1; y <= draw_area->y2; y++) { #if LV_USE_GPU_STM32_CHROM_ART
lv_memcpy(&disp_buf_tmp[draw_area->x1], map_buf_tmp, draw_area_w * sizeof(lv_color_t)); if(lv_area_get_size(draw_area) >= 240) {
disp_buf_tmp += disp_w; #if __DCACHE_PRESENT
map_buf_tmp += map_w; 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 { else {
/*The map will be indexed from `draw_area->x1` so compensate it.*/ #if LV_USE_GPU_STM32_CHROM_ART
map_buf_tmp -= draw_area->x1; if(lv_area_get_size(draw_area) >= 256) {
for(y = draw_area->y1; y <= draw_area->y2; y++) { #if __DCACHE_PRESENT
for(x = draw_area->x1; x <= draw_area->x2; x++) { 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 LV_COLOR_SCREEN_TRANSP
if(disp->driver.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], 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_tmp[x].ch.alpha); &disp_buf_first[x].ch.alpha);
} }
else else
#endif #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; disp_buf_first += disp_w;
map_buf_tmp += map_w; map_buf_first += map_w;
} }
} }
} }
/*Masked*/ /*Masked*/
else { 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*/ /*Only the mask matters*/
if(opa > LV_OPA_MAX) { if(opa > LV_OPA_MAX) {
/*Go to the first pixel of the row */ /*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++) { for(y = 0; y < draw_area_h; y++) {
const lv_opa_t * mask_tmp_x = &mask_tmp[draw_area->x1]; const lv_opa_t * mask_tmp_x = mask;
#if 0 #if 0
for(x = draw_area->x1; x <= draw_area->x2; x++) { for(x = draw_area->x1; x <= draw_area->x2; x++) {
MAP_NORMAL_MASK_PX(x); MAP_NORMAL_MASK_PX(x);
} }
#else #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 #if LV_COLOR_SCREEN_TRANSP
MAP_NORMAL_MASK_PX_SCR_TRANSP(x) MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
#else #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; uint32_t * mask32 = (uint32_t *) mask_tmp_x;
for(; x <= x_end4; x += 4) { for(; x < x_end4; x += 4) {
if(*mask32) { if(*mask32) {
if((*mask32) == 0xFFFFFFFF) { if((*mask32) == 0xFFFFFFFF) {
disp_buf_tmp[x] = map_buf_tmp[x]; disp_buf_first[x] = map_buf_first[x];
disp_buf_tmp[x + 1] = map_buf_tmp[x + 1]; disp_buf_first[x + 1] = map_buf_first[x + 1];
disp_buf_tmp[x + 2] = map_buf_tmp[x + 2]; disp_buf_first[x + 2] = map_buf_first[x + 2];
disp_buf_tmp[x + 3] = map_buf_tmp[x + 3]; disp_buf_first[x + 3] = map_buf_first[x + 3];
} }
else { else {
mask_tmp_x = (const lv_opa_t *)mask32; 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; 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 #if LV_COLOR_SCREEN_TRANSP
MAP_NORMAL_MASK_PX_SCR_TRANSP(x) MAP_NORMAL_MASK_PX_SCR_TRANSP(x)
#else #else
@@ -736,33 +898,32 @@ static void map_normal(const lv_area_t * disp_area, lv_color_t * disp_buf, cons
#endif #endif
} }
#endif #endif
disp_buf_tmp += disp_w; disp_buf_first += disp_w;
mask_tmp += draw_area_w; mask += draw_area_w;
map_buf_tmp += map_w; map_buf_first += map_w;
} }
} }
/*Handle opa and mask values too*/ /*Handle opa and mask values too*/
else { else {
map_buf_tmp -= draw_area->x1; for(y = 0; y < draw_area_h; y++) {
for(y = draw_area->y1; y <= draw_area->y2; y++) { for(x = 0; x < draw_area_w; x++) {
for(x = draw_area->x1; x <= draw_area->x2; x++) { if(mask[x]) {
if(mask_tmp[x]) { lv_opa_t opa_tmp = mask[x] >= LV_OPA_MAX ? opa : ((opa * mask[x]) >> 8);
lv_opa_t opa_tmp = mask_tmp[x] >= LV_OPA_MAX ? opa : ((opa * mask_tmp[x]) >> 8);
#if LV_COLOR_SCREEN_TRANSP #if LV_COLOR_SCREEN_TRANSP
if(disp->driver.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], 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_tmp[x].ch.alpha); &disp_buf_first[x].ch.alpha);
} }
else else
#endif #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; disp_buf_first += disp_w;
mask_tmp += draw_area_w; mask += draw_area_w;
map_buf_tmp += map_w; map_buf_first += map_w;
} }
} }
} }

View File

@@ -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; 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, 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)); 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)); lv_memset_00(mask_buf + px_i_start, lv_area_get_width(&draw_area));
mask_res = LV_DRAW_MASK_RES_CHANGED; mask_res = LV_DRAW_MASK_RES_CHANGED;
} }

View File

@@ -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) { 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_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)); 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)); 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) { 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_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)); 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)); lv_memset_00(mask_buf + mask_p_start, lv_area_get_width(&map_area));
} }
} }

View File

@@ -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); 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(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; lv_style_int_t dash_cnt = dash_start;
uint32_t i; uint32_t i;
for(i = 0; i < draw_area_w; i++, dash_cnt++) { 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); 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(dashed) {
if(mask_res != LV_DRAW_MASK_RES_FULL_TRANSP) { if(mask_res != LV_DRAW_MASK_RES_TRANSP) {
if(dash_cnt > dsc->dash_width) { 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) { 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++) { 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); 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); lv_memset_00(&mask_buf[mask_p], draw_area_w);
} }

View File

@@ -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; dsc = m->param;
lv_draw_mask_res_t res = LV_DRAW_MASK_RES_FULL_COVER; 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); 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; else if(res == LV_DRAW_MASK_RES_CHANGED) changed = true;
m++; 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_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 if(p->cfg.side == LV_DRAW_MASK_LINE_SIDE_BOTTOM && abs_y > 0) return LV_DRAW_MASK_RES_FULL_COVER;
else { else {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
} }
/*Vertical*/ /*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; if(abs_x + len < 0) return LV_DRAW_MASK_RES_FULL_COVER;
else { else {
int32_t k = - abs_x; 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); if(k >= 0 && k < len) lv_memset_00(&mask_buf[k], len - k);
return LV_DRAW_MASK_RES_CHANGED; return LV_DRAW_MASK_RES_CHANGED;
} }
} }
else { 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 { else {
int32_t k = - abs_x; int32_t k = - abs_x;
if(k < 0) k = 0; 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); else if(k >= 0 && k < len) lv_memset_00(&mask_buf[0], k);
return LV_DRAW_MASK_RES_CHANGED; 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; return LV_DRAW_MASK_RES_FULL_COVER;
} }
else { 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; return LV_DRAW_MASK_RES_FULL_COVER;
} }
else { 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(p->yx_steep > 0) {
if(y_at_x < abs_y) { if(y_at_x < abs_y) {
if(p->inv) { if(p->inv) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
else { else {
return LV_DRAW_MASK_RES_FULL_COVER; 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 { else {
if(y_at_x > abs_y) { if(y_at_x > abs_y) {
if(p->inv) { if(p->inv) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
else { else {
return LV_DRAW_MASK_RES_FULL_COVER; 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) { if(p->inv) {
k = xei - abs_x; k = xei - abs_x;
if(k > len) { if(k > len) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
if(k >= 0) { if(k >= 0) {
lv_memset_00(&mask_buf[0], k); 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 { else {
k++; k++;
if(k < 0) { if(k < 0) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
if(k <= len) { if(k <= len) {
lv_memset_00(&mask_buf[k], len - k); 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; return LV_DRAW_MASK_RES_FULL_COVER;
} }
else { 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; x_at_y = (int32_t)((int32_t)p->xy_steep * (abs_y)) >> 10;
if(x_at_y > abs_x + len) { if(x_at_y > abs_x + len) {
if(p->inv) { if(p->inv) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
else { else {
return LV_DRAW_MASK_RES_FULL_COVER; 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) { if(p->inv) {
k = xsi - abs_x; k = xsi - abs_x;
if(k >= len) { 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); if(k >= 0) lv_memset_00(&mask_buf[0], k);
} }
else { else {
if(k > len) k = len; 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); 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) { if(p->inv) {
k = xsi - abs_x; 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); if(k >= 0) lv_memset_00(&mask_buf[0], k);
} }
else { else {
if(k > len) k = len; 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); 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 > len) tmp = len;
if(tmp > 0) { if(tmp > 0) {
res1 = lv_draw_mask_line(&mask_buf[0], abs_x, abs_y, tmp, &p->start_line); 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); 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 > len) tmp = len;
if(tmp < 0) tmp = 0; if(tmp < 0) tmp = 0;
res2 = lv_draw_mask_line(&mask_buf[tmp], abs_x + tmp, abs_y, len - tmp, &p->end_line); 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); lv_memset_00(&mask_buf[tmp], len - tmp);
} }
if(res1 == res2) return res1; 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 > len) tmp = len;
if(tmp > 0) { 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); 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); 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 > len) tmp = len;
if(tmp < 0) tmp = 0; 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); 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); lv_memset_00(&mask_buf[tmp], len - tmp);
} }
if(res1 == res2) return res1; 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); 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; 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_FULL_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 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; 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(outer == false) {
if(abs_y < rect.y1 || abs_y >rect.y2) { if(abs_y < rect.y1 || abs_y >rect.y2) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
} }
else { 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) { if(outer == false) {
/*Remove the edges*/ /*Remove the edges*/
int32_t last = rect.x1 - abs_x; 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) { if(last >= 0) {
lv_memset_00(&mask_buf[0], last); lv_memset_00(&mask_buf[0], last);
} }
int32_t first = rect.x2 - abs_x + 1; 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) { else if(first < len) {
lv_memset_00(&mask_buf[first], len - first); 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) { if(outer == false) {
kr++; kr++;
if(kl > len) { if(kl > len) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
if(kl >= 0) { if(kl >= 0) {
lv_memset_00(&mask_buf[0], kl); lv_memset_00(&mask_buf[0], kl);
} }
if(kr < 0) { if(kr < 0) {
return LV_DRAW_MASK_RES_FULL_TRANSP; return LV_DRAW_MASK_RES_TRANSP;
} }
if(kr <= len) { if(kr <= len) {
lv_memset_00(&mask_buf[kr], len - kr); 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) { if(outer == 0) {
kl++; kl++;
if(kl > len) { 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(kl >= 0) lv_memset_00(&mask_buf[0], kl);
if(kr < 0) { 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); if(kr < len) lv_memset_00(&mask_buf[kr], len - kr);
} }

View File

@@ -27,7 +27,7 @@ extern "C" {
**********************/ **********************/
enum { enum {
LV_DRAW_MASK_RES_FULL_TRANSP, LV_DRAW_MASK_RES_TRANSP,
LV_DRAW_MASK_RES_FULL_COVER, LV_DRAW_MASK_RES_FULL_COVER,
LV_DRAW_MASK_RES_CHANGED, LV_DRAW_MASK_RES_CHANGED,
LV_DRAW_MASK_RES_UNKNOWN LV_DRAW_MASK_RES_UNKNOWN

View File

@@ -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++) { for(y = 0; y < size; y++) {
lv_memset_ff(mask_line, size); lv_memset_ff(mask_line, size);
lv_draw_mask_res_t mask_res = mask_param.dsc.cb(mask_line, 0, y, size, &mask_param); 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])); lv_memset_00(sh_ups_tmp_buf, size * sizeof(sh_ups_tmp_buf[0]));
} }
else { else {

View File

@@ -37,6 +37,38 @@
* STATIC FUNCTIONS * 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) lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl)
{ {
return lv_color_mix(LV_COLOR_WHITE, c, lvl); return lv_color_mix(LV_COLOR_WHITE, c, lvl);

View File

@@ -597,6 +597,8 @@ static inline lv_color_t lv_color_hex3(uint32_t c)
(uint8_t)((c & 0xF) | ((c & 0xF) << 4))); (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_lighten(lv_color_t c, lv_opa_t lvl);
lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl); lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl);