diff --git a/src/draw/convert/helium/lv_draw_buf_convert_helium.c b/src/draw/convert/helium/lv_draw_buf_convert_helium.c new file mode 100644 index 0000000000..ff5b8cd686 --- /dev/null +++ b/src/draw/convert/helium/lv_draw_buf_convert_helium.c @@ -0,0 +1,100 @@ +/** + * @file lv_draw_buf_convert_helium.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../../../lv_conf_internal.h" + +#if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_HELIUM +#include "lv_draw_buf_convert_helium.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_result_t _lv_draw_buf_convert_premultiply_indexed_helium(lv_draw_buf_t * buf) +{ + lv_draw_buf_t palette_draw_buf; + + LV_ASSERT_NULL(buf); + + if(!LV_COLOR_FORMAT_IS_INDEXED(buf->header.cf)) { + LV_LOG_WARN("Unsupported color format : %d", buf->header.cf); + return LV_RESULT_INVALID; + } + + lv_memcpy(&palette_draw_buf, buf, sizeof(lv_draw_buf_t)); + + palette_draw_buf.header.w = LV_COLOR_INDEXED_PALETTE_SIZE(buf->header.cf); + palette_draw_buf.header.h = 1; + palette_draw_buf.header.cf = LV_COLOR_FORMAT_ARGB8888; + palette_draw_buf.header.stride = 4 * palette_draw_buf.header.w; + + return _lv_draw_buf_convert_premultiply_argb8888_helium(&palette_draw_buf); +} + +lv_result_t _lv_draw_buf_convert_premultiply_argb8888_helium(lv_draw_buf_t * buf) +{ + LV_ASSERT_NULL(buf); + + uint32_t h = buf->header.h; + uint32_t w = buf->header.w; + uint32_t stride = buf->header.stride; + uint8_t * data = (uint8_t *)buf->data; + + if(buf->header.cf != LV_COLOR_FORMAT_ARGB8888) { + LV_LOG_WARN("Unsupported color format : %d", buf->header.cf); + return LV_RESULT_INVALID; + } + + __asm volatile( + " .p2align 2 \n" + " 1: \n" + " mov r0, %[pSource] \n" + " mov r1, %[pTarget] \n" + " wlstp.8 lr, %[w], 3f \n" + " 2: \n" + " vld40.u8 {q0, q1, q2, q3}, [r0] \n" + " vld41.u8 {q0, q1, q2, q3}, [r0] \n" + " vld42.u8 {q0, q1, q2, q3}, [r0] \n" + " vld43.u8 {q0, q1, q2, q3}, [r0]! \n" + " vrmulh.u8 q0, q0, q3 \n" + " vrmulh.u8 q1, q1, q3 \n" + " vrmulh.u8 q2, q2, q3 \n" + " vst40.u8 {q0, q1, q2, q3}, [r1] \n" + " vst41.u8 {q0, q1, q2, q3}, [r1] \n" + " vst42.u8 {q0, q1, q2, q3}, [r1] \n" + " vst43.u8 {q0, q1, q2, q3}, [r1]! \n" + " letp lr, 2b \n" + " 3: \n" + " adds %[pSource], %[src_stride] \n" + " adds %[pTarget], %[dst_stride] \n" + " subs %[h], #1 \n" + " bne 1b \n" + : [pSource] "+r"(data), [pTarget] "+r"(data), [h] "+r"(h) + : [w] "r"(w), [src_stride] "r"(stride), [dst_stride] "r"(stride) + : "q0", "q1", "q2", "q3", "r0", "r1", "lr", "memory"); + + return LV_RESULT_OK; +} + +#endif /* LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_HELIUM */ diff --git a/src/draw/convert/helium/lv_draw_buf_convert_helium.h b/src/draw/convert/helium/lv_draw_buf_convert_helium.h new file mode 100644 index 0000000000..1d2c6d4bbb --- /dev/null +++ b/src/draw/convert/helium/lv_draw_buf_convert_helium.h @@ -0,0 +1,54 @@ +/** + * @file lv_draw_buf_convert_helium.h + * + */ + +#ifndef LV_DRAW_BUF_CONVERT_HELIUM_H +#define LV_DRAW_BUF_CONVERT_HELIUM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../../misc/lv_color.h" +#include "../../lv_draw_buf.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_INDEXED +#define LV_DRAW_CONVERT_PREMULTIPLY_INDEXED(buf) \ + _lv_draw_buf_convert_premultiply_indexed_helium(buf) +#endif + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888 +#define LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888(buf) \ + _lv_draw_buf_convert_premultiply_argb8888_helium(buf) +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Convert indexed draw_buf to premultiplied format with helium specific optimizations + * @param buf pointer to a draw buf + */ +lv_result_t _lv_draw_buf_convert_premultiply_indexed_helium(lv_draw_buf_t * buf); + +/** + * Convert argb8888 draw_buf to premultiplied format with helium specific optimizations + * @param buf pointer to a draw buf + */ +lv_result_t _lv_draw_buf_convert_premultiply_argb8888_helium(lv_draw_buf_t * buf); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_DRAW_BUF_CONVERT_HELIUM_H */ \ No newline at end of file diff --git a/src/draw/convert/lv_draw_buf_convert.c b/src/draw/convert/lv_draw_buf_convert.c new file mode 100644 index 0000000000..7e01b4eb33 --- /dev/null +++ b/src/draw/convert/lv_draw_buf_convert.c @@ -0,0 +1,130 @@ +/** + * @file lv_draw_buf_convert.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "lv_draw_buf_convert.h" + +#if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_NEON + #include "neon/lv_draw_buf_convert_neon.h" +#elif LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_HELIUM + #include "helium/lv_draw_buf_convert_helium.h" +#elif LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_CUSTOM + #include LV_DRAW_SW_ASM_CUSTOM_INCLUDE +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/********************** + * MACROS + **********************/ + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_INDEXED + #define LV_DRAW_CONVERT_PREMULTIPLY_INDEXED(...) LV_RESULT_INVALID +#endif + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888 + #define LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888(...) LV_RESULT_INVALID +#endif + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_RGB565A8 + #define LV_DRAW_CONVERT_PREMULTIPLY_RGB565A8(...) LV_RESULT_INVALID +#endif + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_ARGB8565 + #define LV_DRAW_CONVERT_PREMULTIPLY_ARGB8565(...) LV_RESULT_INVALID +#endif + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_result_t lv_draw_buf_convert_premultiply(lv_draw_buf_t * draw_buf) +{ + LV_ASSERT_NULL(draw_buf); + + /*Premultiply color with alpha, do case by case by judging color format*/ + lv_color_format_t cf = draw_buf->header.cf; + if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { + if(LV_RESULT_INVALID == LV_DRAW_CONVERT_PREMULTIPLY_INDEXED(draw_buf)) { + int size = LV_COLOR_INDEXED_PALETTE_SIZE(cf); + lv_color32_t * palette = (lv_color32_t *)draw_buf->data; + for(int i = 0; i < size; i++) { + lv_color_premultiply(&palette[i]); + } + } + } + else if(cf == LV_COLOR_FORMAT_ARGB8888) { + if(LV_RESULT_INVALID == LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888(draw_buf)) { + uint32_t h = draw_buf->header.h; + uint32_t w = draw_buf->header.w; + uint32_t stride = draw_buf->header.stride; + uint8_t * line = (uint8_t *)draw_buf->data; + for(uint32_t y = 0; y < h; y++) { + lv_color32_t * pixel = (lv_color32_t *)line; + for(uint32_t x = 0; x < w; x++) { + lv_color_premultiply(pixel); + pixel++; + } + line += stride; + } + } + } + else if(cf == LV_COLOR_FORMAT_RGB565A8) { + if(LV_RESULT_INVALID == LV_DRAW_CONVERT_PREMULTIPLY_RGB565A8(draw_buf)) { + uint32_t h = draw_buf->header.h; + uint32_t w = draw_buf->header.w; + uint32_t stride = draw_buf->header.stride; + uint32_t alpha_stride = stride / 2; + uint8_t * line = (uint8_t *)draw_buf->data; + lv_opa_t * alpha = (lv_opa_t *)(line + stride * h); + for(uint32_t y = 0; y < h; y++) { + lv_color16_t * pixel = (lv_color16_t *)line; + for(uint32_t x = 0; x < w; x++) { + lv_color16_premultiply(pixel, alpha[x]); + pixel++; + } + line += stride; + alpha += alpha_stride; + } + } + } + else if(cf == LV_COLOR_FORMAT_ARGB8565) { + if(LV_RESULT_INVALID == LV_DRAW_CONVERT_PREMULTIPLY_ARGB8565(draw_buf)) { + uint32_t h = draw_buf->header.h; + uint32_t w = draw_buf->header.w; + uint32_t stride = draw_buf->header.stride; + uint8_t * line = (uint8_t *)draw_buf->data; + for(uint32_t y = 0; y < h; y++) { + uint8_t * pixel = line; + for(uint32_t x = 0; x < w; x++) { + uint8_t alpha = pixel[2]; + lv_color16_premultiply((lv_color16_t *)pixel, alpha); + pixel += 3; + } + line += stride; + } + } + } + else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { + /*Pass*/ + } + else { + LV_LOG_WARN("draw buf has no alpha, cf: %d", cf); + } + + return LV_RESULT_OK; +} \ No newline at end of file diff --git a/src/draw/convert/lv_draw_buf_convert.h b/src/draw/convert/lv_draw_buf_convert.h new file mode 100644 index 0000000000..6c2d79e91a --- /dev/null +++ b/src/draw/convert/lv_draw_buf_convert.h @@ -0,0 +1,39 @@ +/** + * @file lv_draw_buf_convert.h + * + */ + +#ifndef LV_DRAW_BUF_CONVERT_H +#define LV_DRAW_BUF_CONVERT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../misc/lv_color.h" +#include "../lv_draw_buf.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Convert draw_buf to premultiplied format + * @param buf pointer to a draw buf + */ +lv_result_t lv_draw_buf_convert_premultiply(lv_draw_buf_t * buf); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_DRAW_BUF_CONVERT_H */ \ No newline at end of file diff --git a/src/draw/convert/neon/lv_draw_buf_convert_neon.c b/src/draw/convert/neon/lv_draw_buf_convert_neon.c new file mode 100644 index 0000000000..991f55fb29 --- /dev/null +++ b/src/draw/convert/neon/lv_draw_buf_convert_neon.c @@ -0,0 +1,132 @@ +/** + * @file lv_draw_buf_convert_neon.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../../../lv_conf_internal.h" + +#if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_NEON + +#include +#include "lv_draw_buf_convert_neon.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/********************** + * STATIC FUNCTIONS + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +lv_result_t _lv_draw_buf_convert_premultiply_indexed_neon(lv_draw_buf_t * buf) +{ + lv_draw_buf_t palette_draw_buf; + + LV_ASSERT_NULL(buf); + + if(!LV_COLOR_FORMAT_IS_INDEXED(buf->header.cf)) { + LV_LOG_WARN("Unsupported color format : %d", buf->header.cf); + return LV_RESULT_INVALID; + } + + lv_memcpy(&palette_draw_buf, buf, sizeof(lv_draw_buf_t)); + + palette_draw_buf.header.w = LV_COLOR_INDEXED_PALETTE_SIZE(buf->header.cf); + palette_draw_buf.header.h = 1; + palette_draw_buf.header.cf = LV_COLOR_FORMAT_ARGB8888; + palette_draw_buf.header.stride = 4 * palette_draw_buf.header.w; + + return _lv_draw_buf_convert_premultiply_argb8888_neon(&palette_draw_buf); + +} + +lv_result_t _lv_draw_buf_convert_premultiply_argb8888_neon(lv_draw_buf_t * buf) +{ + LV_ASSERT_NULL(buf); + + uint32_t h = buf->header.h; + uint32_t w = buf->header.w; + uint32_t stride = buf->header.stride; + uint8_t * data = (uint8_t *)buf->data; + + if(buf->header.cf != LV_COLOR_FORMAT_ARGB8888) { + LV_LOG_WARN("Unsupported color format : %d", buf->header.cf); + return LV_RESULT_INVALID; + } + + for(uint32_t y = 0; y < h; y++) { + uint8_t * p = (uint8_t *)data; + uint32_t remaining_pixels = w; + + while(remaining_pixels >= 8) { + uint8x8x4_t rgba = vld4_u8(p); + + uint16x8_t r16 = vmovl_u8(rgba.val[0]); + uint16x8_t g16 = vmovl_u8(rgba.val[1]); + uint16x8_t b16 = vmovl_u8(rgba.val[2]); + uint16x8_t a16 = vmovl_u8(rgba.val[3]); + + rgba.val[0] = vshrn_n_u16(vmulq_u16(r16, a16), 8); + rgba.val[1] = vshrn_n_u16(vmulq_u16(g16, a16), 8); + rgba.val[2] = vshrn_n_u16(vmulq_u16(b16, a16), 8); + + vst4_u8(p, rgba); + + p += 8 * 4; + remaining_pixels -= 8; + } + + if(remaining_pixels >= 4) { + uint8x8x4_t rgba; + rgba = vld4_lane_u8(p, rgba, 0); + rgba = vld4_lane_u8(p + 4, rgba, 1); + rgba = vld4_lane_u8(p + 8, rgba, 2); + rgba = vld4_lane_u8(p + 12, rgba, 3); + + uint16x8_t r16 = vmovl_u8(rgba.val[0]); + uint16x8_t g16 = vmovl_u8(rgba.val[1]); + uint16x8_t b16 = vmovl_u8(rgba.val[2]); + uint16x8_t a16 = vmovl_u8(rgba.val[3]); + + rgba.val[0] = vshrn_n_u16(vmulq_u16(r16, a16), 8); + rgba.val[1] = vshrn_n_u16(vmulq_u16(g16, a16), 8); + rgba.val[2] = vshrn_n_u16(vmulq_u16(b16, a16), 8); + + vst4_lane_u8(p, rgba, 0); + vst4_lane_u8(p + 4, rgba, 1); + vst4_lane_u8(p + 8, rgba, 2); + vst4_lane_u8(p + 12, rgba, 3); + + p += 4 * 4; + remaining_pixels -= 4; + } + + while(remaining_pixels--) { + uint8_t a = p[3]; + p[0] = ((uint16_t)(p[0]) * a) >> 8; + p[1] = ((uint16_t)(p[1]) * a) >> 8; + p[2] = ((uint16_t)(p[2]) * a) >> 8; + p += 4; + } + + data += stride; + } + + return LV_RESULT_OK; +} +#endif /* LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_NEON */ diff --git a/src/draw/convert/neon/lv_draw_buf_convert_neon.h b/src/draw/convert/neon/lv_draw_buf_convert_neon.h new file mode 100644 index 0000000000..6a3934d67a --- /dev/null +++ b/src/draw/convert/neon/lv_draw_buf_convert_neon.h @@ -0,0 +1,56 @@ +/** + * @file lv_draw_buf_convert_neon.h + * + */ + +#ifndef LV_DRAW_BUF_CONVERT_NEON_H +#define LV_DRAW_BUF_CONVERT_NEON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../../misc/lv_color.h" +#include "../../lv_draw_buf.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_INDEXED +#define LV_DRAW_CONVERT_PREMULTIPLY_INDEXED(buf) \ + _lv_draw_buf_convert_premultiply_indexed_neon(buf) +#endif + +#ifndef LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888 +#define LV_DRAW_CONVERT_PREMULTIPLY_ARGB8888(buf) \ + _lv_draw_buf_convert_premultiply_argb8888_neon(buf) +#endif + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +/** + * Convert indexed draw_buf to premultiplied format with neon specific optimizations + * @param buf pointer to a draw buf + */ + +lv_result_t _lv_draw_buf_convert_premultiply_indexed_neon(lv_draw_buf_t * buf); + +/** + * Convert argb8888 draw_buf to premultiplied format with neon specific optimizations + * @param buf pointer to a draw buf + */ +lv_result_t _lv_draw_buf_convert_premultiply_argb8888_neon(lv_draw_buf_t * buf); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LV_DRAW_BUF_CONVERT_NEON_H */ \ No newline at end of file diff --git a/src/draw/lv_draw_buf.c b/src/draw/lv_draw_buf.c index db39bef82a..e2cc643c19 100644 --- a/src/draw/lv_draw_buf.c +++ b/src/draw/lv_draw_buf.c @@ -12,6 +12,7 @@ #include "../core/lv_global.h" #include "../misc/lv_math.h" #include "../misc/lv_area_private.h" +#include "convert/lv_draw_buf_convert.h" /********************* * DEFINES @@ -472,67 +473,7 @@ lv_result_t lv_draw_buf_premultiply(lv_draw_buf_t * draw_buf) } LV_PROFILER_DRAW_BEGIN; - /*Premultiply color with alpha, do case by case by judging color format*/ - lv_color_format_t cf = draw_buf->header.cf; - if(LV_COLOR_FORMAT_IS_INDEXED(cf)) { - int size = LV_COLOR_INDEXED_PALETTE_SIZE(cf); - lv_color32_t * palette = (lv_color32_t *)draw_buf->data; - for(int i = 0; i < size; i++) { - lv_color_premultiply(&palette[i]); - } - } - else if(cf == LV_COLOR_FORMAT_ARGB8888) { - uint32_t h = draw_buf->header.h; - uint32_t w = draw_buf->header.w; - uint32_t stride = draw_buf->header.stride; - uint8_t * line = (uint8_t *)draw_buf->data; - for(uint32_t y = 0; y < h; y++) { - lv_color32_t * pixel = (lv_color32_t *)line; - for(uint32_t x = 0; x < w; x++) { - lv_color_premultiply(pixel); - pixel++; - } - line += stride; - } - } - else if(cf == LV_COLOR_FORMAT_RGB565A8) { - uint32_t h = draw_buf->header.h; - uint32_t w = draw_buf->header.w; - uint32_t stride = draw_buf->header.stride; - uint32_t alpha_stride = stride / 2; - uint8_t * line = (uint8_t *)draw_buf->data; - lv_opa_t * alpha = (lv_opa_t *)(line + stride * h); - for(uint32_t y = 0; y < h; y++) { - lv_color16_t * pixel = (lv_color16_t *)line; - for(uint32_t x = 0; x < w; x++) { - lv_color16_premultiply(pixel, alpha[x]); - pixel++; - } - line += stride; - alpha += alpha_stride; - } - } - else if(cf == LV_COLOR_FORMAT_ARGB8565) { - uint32_t h = draw_buf->header.h; - uint32_t w = draw_buf->header.w; - uint32_t stride = draw_buf->header.stride; - uint8_t * line = (uint8_t *)draw_buf->data; - for(uint32_t y = 0; y < h; y++) { - uint8_t * pixel = line; - for(uint32_t x = 0; x < w; x++) { - uint8_t alpha = pixel[2]; - lv_color16_premultiply((lv_color16_t *)pixel, alpha); - pixel += 3; - } - line += stride; - } - } - else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) { - /*Pass*/ - } - else { - LV_LOG_WARN("draw buf has no alpha, cf: %d", cf); - } + lv_draw_buf_convert_premultiply(draw_buf); draw_buf->header.flags |= LV_IMAGE_FLAGS_PREMULTIPLIED;