feat(draw_buf): add MVE & NEON support of alpha premultiply (#8712)

Signed-off-by: rongyichang <rongyichang@xiaomi.com>
This commit is contained in:
terry.rong
2025-09-05 16:40:16 +02:00
committed by GitHub
parent 690dd40a33
commit 62b879d12b
7 changed files with 513 additions and 61 deletions
@@ -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 */
@@ -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 */
+130
View File
@@ -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;
}
+39
View File
@@ -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 */
@@ -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 <arm_neon.h>
#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 */
@@ -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 */
+2 -61
View File
@@ -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;