Update esp_lvgl_port (#230)
Updated to espressif/esp-bsp@531ad57 https://github.com/espressif/esp-bsp/commit/531ad57f6abe178d6b43d898fac495c59747803f
This commit is contained in:
committed by
GitHub
parent
ee88a563dc
commit
44b366b557
@@ -4,7 +4,7 @@ Test app accommodates two types of tests: [`functionality test`](#Functionality-
|
||||
|
||||
Assembly source files could be found in the [`lvgl_port`](../../src/lvgl9/simd/) component. Header file with the assembly function prototypes is provided into the LVGL using Kconfig option `LV_DRAW_SW_ASM_CUSTOM_INCLUDE` and can be found in the [`lvgl_port/include`](../../include/esp_lvgl_port_lv_blend.h)
|
||||
|
||||
## Benchmark results
|
||||
## Benchmark results for LV Fill functions (memset)
|
||||
|
||||
| Color format | Matrix size | Memory alignment | ASM version | ANSI C version |
|
||||
| :----------- | :---------- | :--------------- | :------------- | :------------- |
|
||||
@@ -12,9 +12,20 @@ Assembly source files could be found in the [`lvgl_port`](../../src/lvgl9/simd/)
|
||||
| | 127x127 | 1 byte | 0.488 | 1.597 |
|
||||
| RGB565 | 128x128 | 16 byte | 0.196 | 1.146 |
|
||||
| | 127x127 | 1 byte | 0.497 | 1.124 |
|
||||
| RGB888 | 128x128 | 16 byte | 0.608 | 4.062 |
|
||||
| | 127x127 | 1 byte | 0.818 | 3.969 |
|
||||
* this data was obtained by running [benchmark tests](#benchmark-test) on 128x128 16 byte aligned matrix (ideal case) and 127x127 1 byte aligned matrix (worst case)
|
||||
* the values represent cycles per sample to perform simple fill of the matrix on esp32s3
|
||||
|
||||
## Benchmark results for LV Image functions (memcpy)
|
||||
|
||||
| Color format | Matrix size | Memory alignment | ASM version | ANSI C version |
|
||||
| :----------- | :---------- | :--------------- | :------------- | :------------- |
|
||||
| RGB565 | 128x128 | 16 byte | 0.352 | 3.437 |
|
||||
| | 127x128 | 1 byte | 0.866 | 5.978 |
|
||||
* this data was obtained by running [benchmark tests](#benchmark-test) on 128x128 16 byte aligned matrix (ideal case) and 127x128 1 byte aligned matrix (worst case)
|
||||
* the values represent cycles per sample to perform memory copy between two matrices on esp32s3
|
||||
|
||||
## Functionality test
|
||||
* Tests, whether the HW accelerated assembly version of an LVGL function provides the same results as the ANSI version
|
||||
* A top-level flow of the functionality test:
|
||||
@@ -62,6 +73,8 @@ Here's the test menu, pick your combo:
|
||||
(2) "Test fill functionality RGB565" [fill][functionality][RGB565]
|
||||
(3) "LV Fill benchmark ARGB8888" [fill][benchmark][ARGB8888]
|
||||
(4) "LV Fill benchmark RGB565" [fill][benchmark][RGB565]
|
||||
(5) "LV Image functionality RGB565 blend to RGB565" [image][functionality][RGB565]
|
||||
(6) "LV Image benchmark RGB565 blend to RGB565" [image][benchmark][RGB565]
|
||||
|
||||
Enter test for running.
|
||||
```
|
||||
|
||||
@@ -8,6 +8,9 @@ if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3)
|
||||
else()
|
||||
file(GLOB_RECURSE ASM_SOURCES ${PORT_PATH}/simd/*_esp32.S) # Select only esp32 related files
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE ASM_MACROS ${PORT_PATH}/simd/lv_macro_*.S) # Explicitly add all assembler macro files
|
||||
|
||||
else()
|
||||
message(WARNING "This test app is intended only for esp32 and esp32s3")
|
||||
endif()
|
||||
@@ -15,7 +18,14 @@ endif()
|
||||
# Hard copy of LV files
|
||||
file(GLOB_RECURSE BLEND_SRCS lv_blend/src/*.c)
|
||||
|
||||
idf_component_register(SRCS "test_app_main.c" "test_lv_fill_functionality.c" "test_lv_fill_benchmark.c" ${BLEND_SRCS} ${ASM_SOURCES}
|
||||
idf_component_register(SRCS "test_app_main.c"
|
||||
"test_lv_fill_functionality.c" # memset tests
|
||||
"test_lv_fill_benchmark.c"
|
||||
"test_lv_image_functionality.c" # memcpy tests
|
||||
"test_lv_image_benchmark.c"
|
||||
${BLEND_SRCS} # Hard copy of LVGL's blend API, to simplify testing
|
||||
${ASM_SOURCES} # Assembly src files
|
||||
${ASM_MACROS} # Assembly macro files
|
||||
INCLUDE_DIRS "lv_blend/include" "../../../include"
|
||||
REQUIRES unity
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
@@ -57,6 +57,7 @@ typedef struct {
|
||||
lv_color_format_t src_color_format;
|
||||
lv_opa_t opa;
|
||||
lv_blend_mode_t blend_mode;
|
||||
bool use_asm;
|
||||
} _lv_draw_sw_blend_image_dsc_t;
|
||||
|
||||
/**********************
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* This file is derived from the LVGL project.
|
||||
* See https://github.com/lvgl/lvgl for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_sw_blend_rgb888.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_DRAW_SW_BLEND_RGB888_H
|
||||
#define LV_DRAW_SW_BLEND_RGB888_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_sw_blend.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_sw_blend_color_to_rgb888(_lv_draw_sw_blend_fill_dsc_t *dsc,
|
||||
uint32_t dest_px_size);
|
||||
|
||||
void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_sw_blend_image_to_rgb888(_lv_draw_sw_blend_image_dsc_t *dsc,
|
||||
uint32_t dest_px_size);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_DRAW_SW_BLEND_RGB888_H*/
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* This file is derived from the LVGL project.
|
||||
* See https://github.com/lvgl/lvgl for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_string.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_STRING_H
|
||||
#define LV_STRING_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
//#include "../lv_conf_internal.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "lv_types.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* @brief Copies a block of memory from a source address to a destination address.
|
||||
* @param dst Pointer to the destination array where the content is to be copied.
|
||||
* @param src Pointer to the source of data to be copied.
|
||||
* @param len Number of bytes to copy.
|
||||
* @return Pointer to the destination array.
|
||||
* @note The function does not check for any overlapping of the source and destination memory blocks.
|
||||
*/
|
||||
void *lv_memcpy(void *dst, const void *src, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Fills a block of memory with a specified value.
|
||||
* @param dst Pointer to the destination array to fill with the specified value.
|
||||
* @param v Value to be set. The value is passed as an int, but the function fills
|
||||
* the block of memory using the unsigned char conversion of this value.
|
||||
* @param len Number of bytes to be set to the value.
|
||||
*/
|
||||
void lv_memset(void *dst, uint8_t v, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Move a block of memory from source to destination
|
||||
* @param dst Pointer to the destination array where the content is to be copied.
|
||||
* @param src Pointer to the source of data to be copied.
|
||||
* @param len Number of bytes to copy
|
||||
* @return Pointer to the destination array.
|
||||
*/
|
||||
void *lv_memmove(void *dst, const void *src, size_t len);
|
||||
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_STRING_H*/
|
||||
@@ -19,6 +19,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
+5
-5
@@ -23,7 +23,7 @@
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_math.h"
|
||||
#include "lv_color.h"
|
||||
#include "string.h"
|
||||
#include "lv_string.h"
|
||||
|
||||
#include "esp_lvgl_port_lv_blend.h"
|
||||
|
||||
@@ -628,7 +628,7 @@ static void LV_ATTRIBUTE_FAST_MEM rgb888_image_blend(_lv_draw_sw_blend_image_dsc
|
||||
if (src_px_size == 4) {
|
||||
uint32_t line_in_bytes = w * 4;
|
||||
for (y = 0; y < h; y++) {
|
||||
memcpy(dest_buf_c32, src_buf, line_in_bytes); // lv_memcpy
|
||||
lv_memcpy(dest_buf_c32, src_buf, line_in_bytes);
|
||||
dest_buf_c32 = drawbuf_next_row(dest_buf_c32, dest_stride);
|
||||
src_buf = drawbuf_next_row(src_buf, src_stride);
|
||||
}
|
||||
@@ -870,9 +870,9 @@ static inline lv_color32_t LV_ATTRIBUTE_FAST_MEM lv_color_32_32_mix(lv_color32_t
|
||||
|
||||
void lv_color_mix_with_alpha_cache_init(lv_color_mix_alpha_cache_t *cache)
|
||||
{
|
||||
memset(&cache->fg_saved, 0x00, sizeof(lv_color32_t)); //lv_memzero
|
||||
memset(&cache->bg_saved, 0x00, sizeof(lv_color32_t)); //lv_memzero
|
||||
memset(&cache->res_saved, 0x00, sizeof(lv_color32_t)); //lv_memzero
|
||||
lv_memset(&cache->fg_saved, 0x00, sizeof(lv_color32_t)); //lv_memzero
|
||||
lv_memset(&cache->bg_saved, 0x00, sizeof(lv_color32_t)); //lv_memzero
|
||||
lv_memset(&cache->res_saved, 0x00, sizeof(lv_color32_t)); //lv_memzero
|
||||
cache->res_alpha_saved = 255;
|
||||
cache->ratio_saved = 255;
|
||||
}
|
||||
|
||||
+5
-3
@@ -23,7 +23,7 @@
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_math.h"
|
||||
#include "lv_color.h"
|
||||
#include "string.h"
|
||||
#include "lv_string.h"
|
||||
|
||||
#include "esp_lvgl_port_lv_blend.h"
|
||||
|
||||
@@ -601,10 +601,12 @@ static void LV_ATTRIBUTE_FAST_MEM rgb565_image_blend(_lv_draw_sw_blend_image_dsc
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB565(dsc)) {
|
||||
if (dsc->use_asm) {
|
||||
LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB565(dsc);
|
||||
} else {
|
||||
uint32_t line_in_bytes = w * 2;
|
||||
for (y = 0; y < h; y++) {
|
||||
memcpy(dest_buf_u16, src_buf_u16, line_in_bytes); // lv_memcpy
|
||||
lv_memcpy(dest_buf_u16, src_buf_u16, line_in_bytes);
|
||||
dest_buf_u16 = drawbuf_next_row(dest_buf_u16, dest_stride);
|
||||
src_buf_u16 = drawbuf_next_row(src_buf_u16, src_stride);
|
||||
}
|
||||
|
||||
+952
@@ -0,0 +1,952 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* This file is derived from the LVGL project.
|
||||
* See https://github.com/lvgl/lvgl for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_draw_sw_blend_to_rgb888.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_draw_sw_blend_to_rgb888.h"
|
||||
|
||||
#include "lv_assert.h"
|
||||
#include "lv_types.h"
|
||||
#include "lv_log.h"
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_math.h"
|
||||
#include "lv_color.h"
|
||||
#include "lv_string.h"
|
||||
|
||||
#include "esp_lvgl_port_lv_blend.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_ATTRIBUTE_FAST_MEM
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void /* LV_ATTRIBUTE_FAST_MEM */ al88_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size);
|
||||
|
||||
static void /* LV_ATTRIBUTE_FAST_MEM */ i1_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size);
|
||||
|
||||
static inline uint8_t /* LV_ATTRIBUTE_FAST_MEM */ get_bit(const uint8_t *buf, int32_t bit_idx);
|
||||
|
||||
static void /* LV_ATTRIBUTE_FAST_MEM */ l8_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size);
|
||||
|
||||
static void /* LV_ATTRIBUTE_FAST_MEM */ rgb565_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size);
|
||||
|
||||
static void /* LV_ATTRIBUTE_FAST_MEM */ rgb888_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc,
|
||||
const uint8_t dest_px_size,
|
||||
uint32_t src_px_size);
|
||||
|
||||
static void /* LV_ATTRIBUTE_FAST_MEM */ argb8888_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc,
|
||||
uint32_t dest_px_size);
|
||||
|
||||
static inline void /* LV_ATTRIBUTE_FAST_MEM */ lv_color_8_24_mix(const uint8_t src, uint8_t *dest, uint8_t mix);
|
||||
|
||||
static inline void /* LV_ATTRIBUTE_FAST_MEM */ lv_color_24_24_mix(const uint8_t *src, uint8_t *dest, uint8_t mix);
|
||||
|
||||
static inline void /* LV_ATTRIBUTE_FAST_MEM */ blend_non_normal_pixel(uint8_t *dest, lv_color32_t src,
|
||||
lv_blend_mode_t mode);
|
||||
static inline void * /* LV_ATTRIBUTE_FAST_MEM */ drawbuf_next_row(const void *buf, uint32_t stride);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB888
|
||||
#define LV_DRAW_SW_COLOR_BLEND_TO_RGB888(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB888_WITH_OPA
|
||||
#define LV_DRAW_SW_COLOR_BLEND_TO_RGB888_WITH_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB888_WITH_MASK
|
||||
#define LV_DRAW_SW_COLOR_BLEND_TO_RGB888_WITH_MASK(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB888_MIX_MASK_OPA
|
||||
#define LV_DRAW_SW_COLOR_BLEND_TO_RGB888_MIX_MASK_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888
|
||||
#define LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_OPA
|
||||
#define LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_MASK
|
||||
#define LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_MASK(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA
|
||||
#define LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888
|
||||
#define LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_WITH_OPA
|
||||
#define LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_WITH_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_WITH_MASK
|
||||
#define LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_WITH_MASK(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA
|
||||
#define LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888
|
||||
#define LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_WITH_OPA
|
||||
#define LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_WITH_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_WITH_MASK
|
||||
#define LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_WITH_MASK(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA
|
||||
#define LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888
|
||||
#define LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_WITH_OPA
|
||||
#define LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_WITH_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_WITH_MASK
|
||||
#define LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_WITH_MASK(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA
|
||||
#define LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_I1_BLEND_NORMAL_TO_888
|
||||
#define LV_DRAW_SW_I1_BLEND_NORMAL_TO_888(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_WITH_OPA
|
||||
#define LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_WITH_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_WITH_MASK
|
||||
#define LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_WITH_MASK(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
#ifndef LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_MIX_MASK_OPA
|
||||
#define LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_MIX_MASK_OPA(...) LV_RESULT_INVALID
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_sw_blend_color_to_rgb888(_lv_draw_sw_blend_fill_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
const lv_opa_t *mask = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
|
||||
LV_UNUSED(w);
|
||||
LV_UNUSED(h);
|
||||
LV_UNUSED(x);
|
||||
LV_UNUSED(y);
|
||||
LV_UNUSED(opa);
|
||||
LV_UNUSED(mask);
|
||||
LV_UNUSED(mask_stride);
|
||||
LV_UNUSED(dest_stride);
|
||||
|
||||
/*Simple fill*/
|
||||
if (mask == NULL && opa >= LV_OPA_MAX) {
|
||||
if (dsc->use_asm && dest_px_size == 3) {
|
||||
LV_DRAW_SW_COLOR_BLEND_TO_RGB888(dsc, dest_px_size);
|
||||
} else {
|
||||
if (dest_px_size == 3) {
|
||||
uint8_t *dest_buf_u8 = dsc->dest_buf;
|
||||
uint8_t *dest_buf_ori = dsc->dest_buf;
|
||||
w *= dest_px_size;
|
||||
|
||||
for (x = 0; x < w; x += 3) {
|
||||
dest_buf_u8[x + 0] = dsc->color.blue;
|
||||
dest_buf_u8[x + 1] = dsc->color.green;
|
||||
dest_buf_u8[x + 2] = dsc->color.red;
|
||||
}
|
||||
|
||||
dest_buf_u8 += dest_stride;
|
||||
|
||||
for (y = 1; y < h; y++) {
|
||||
lv_memcpy(dest_buf_u8, dest_buf_ori, w);
|
||||
dest_buf_u8 += dest_stride;
|
||||
}
|
||||
}
|
||||
if (dest_px_size == 4) {
|
||||
uint32_t color32 = lv_color_to_u32(dsc->color);
|
||||
uint32_t *dest_buf_u32 = dsc->dest_buf;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x <= w - 16; x += 16) {
|
||||
dest_buf_u32[x + 0] = color32;
|
||||
dest_buf_u32[x + 1] = color32;
|
||||
dest_buf_u32[x + 2] = color32;
|
||||
dest_buf_u32[x + 3] = color32;
|
||||
|
||||
dest_buf_u32[x + 4] = color32;
|
||||
dest_buf_u32[x + 5] = color32;
|
||||
dest_buf_u32[x + 6] = color32;
|
||||
dest_buf_u32[x + 7] = color32;
|
||||
|
||||
dest_buf_u32[x + 8] = color32;
|
||||
dest_buf_u32[x + 9] = color32;
|
||||
dest_buf_u32[x + 10] = color32;
|
||||
dest_buf_u32[x + 11] = color32;
|
||||
|
||||
dest_buf_u32[x + 12] = color32;
|
||||
dest_buf_u32[x + 13] = color32;
|
||||
dest_buf_u32[x + 14] = color32;
|
||||
dest_buf_u32[x + 15] = color32;
|
||||
}
|
||||
for (; x < w; x ++) {
|
||||
dest_buf_u32[x] = color32;
|
||||
}
|
||||
|
||||
dest_buf_u32 = drawbuf_next_row(dest_buf_u32, dest_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Opacity only*/
|
||||
else if (mask == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_COLOR_BLEND_TO_RGB888_WITH_OPA(dsc, dest_px_size)) {
|
||||
uint32_t color32 = lv_color_to_u32(dsc->color);
|
||||
uint8_t *dest_buf = dsc->dest_buf;
|
||||
w *= dest_px_size;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x += dest_px_size) {
|
||||
lv_color_24_24_mix((const uint8_t *)&color32, &dest_buf[x], opa);
|
||||
}
|
||||
|
||||
dest_buf = drawbuf_next_row(dest_buf, dest_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Masked with full opacity*/
|
||||
else if (mask && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_COLOR_BLEND_TO_RGB888_WITH_MASK(dsc, dest_px_size)) {
|
||||
uint32_t color32 = lv_color_to_u32(dsc->color);
|
||||
uint8_t *dest_buf = dsc->dest_buf;
|
||||
w *= dest_px_size;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
uint32_t mask_x;
|
||||
for (x = 0, mask_x = 0; x < w; x += dest_px_size, mask_x++) {
|
||||
lv_color_24_24_mix((const uint8_t *)&color32, &dest_buf[x], mask[mask_x]);
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
mask += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*Masked with opacity*/
|
||||
else {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_COLOR_BLEND_TO_RGB888_MIX_MASK_OPA(dsc, dest_px_size)) {
|
||||
uint32_t color32 = lv_color_to_u32(dsc->color);
|
||||
uint8_t *dest_buf = dsc->dest_buf;
|
||||
w *= dest_px_size;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
uint32_t mask_x;
|
||||
for (x = 0, mask_x = 0; x < w; x += dest_px_size, mask_x++) {
|
||||
lv_color_24_24_mix((const uint8_t *) &color32, &dest_buf[x], LV_OPA_MIX2(opa, mask[mask_x]));
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
mask += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_draw_sw_blend_image_to_rgb888(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
|
||||
switch (dsc->src_color_format) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
rgb565_image_blend(dsc, dest_px_size);
|
||||
break;
|
||||
case LV_COLOR_FORMAT_RGB888:
|
||||
rgb888_image_blend(dsc, dest_px_size, 3);
|
||||
break;
|
||||
case LV_COLOR_FORMAT_XRGB8888:
|
||||
rgb888_image_blend(dsc, dest_px_size, 4);
|
||||
break;
|
||||
case LV_COLOR_FORMAT_ARGB8888:
|
||||
argb8888_image_blend(dsc, dest_px_size);
|
||||
break;
|
||||
case LV_COLOR_FORMAT_L8:
|
||||
l8_image_blend(dsc, dest_px_size);
|
||||
break;
|
||||
case LV_COLOR_FORMAT_AL88:
|
||||
al88_image_blend(dsc, dest_px_size);
|
||||
break;
|
||||
case LV_COLOR_FORMAT_I1:
|
||||
i1_image_blend(dsc, dest_px_size);
|
||||
break;
|
||||
default:
|
||||
LV_LOG_WARN("Not supported source color format");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void LV_ATTRIBUTE_FAST_MEM i1_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
uint8_t *dest_buf_u8 = dsc->dest_buf;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
const uint8_t *src_buf_i1 = dsc->src_buf;
|
||||
int32_t src_stride = dsc->src_stride;
|
||||
const lv_opa_t *mask_buf = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
|
||||
int32_t dest_x;
|
||||
int32_t src_x;
|
||||
int32_t y;
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_I1_BLEND_NORMAL_TO_888(dsc)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
uint8_t chan_val = get_bit(src_buf_i1, src_x) * 255;
|
||||
dest_buf_u8[dest_x + 2] = chan_val;
|
||||
dest_buf_u8[dest_x + 1] = chan_val;
|
||||
dest_buf_u8[dest_x + 0] = chan_val;
|
||||
}
|
||||
dest_buf_u8 = drawbuf_next_row(dest_buf_u8, dest_stride);
|
||||
src_buf_i1 = drawbuf_next_row(src_buf_i1, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_WITH_OPA(dsc)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
uint8_t chan_val = get_bit(src_buf_i1, src_x) * 255;
|
||||
lv_color_8_24_mix(chan_val, &dest_buf_u8[dest_x], opa);
|
||||
}
|
||||
dest_buf_u8 = drawbuf_next_row(dest_buf_u8, dest_stride);
|
||||
src_buf_i1 = drawbuf_next_row(src_buf_i1, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_WITH_MASK(dsc)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
uint8_t chan_val = get_bit(src_buf_i1, src_x) * 255;
|
||||
lv_color_8_24_mix(chan_val, &dest_buf_u8[dest_x], mask_buf[src_x]);
|
||||
}
|
||||
dest_buf_u8 = drawbuf_next_row(dest_buf_u8, dest_stride);
|
||||
src_buf_i1 = drawbuf_next_row(src_buf_i1, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_I1_BLEND_NORMAL_TO_888_MIX_MASK_OPA(dsc)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
uint8_t chan_val = get_bit(src_buf_i1, src_x) * 255;
|
||||
lv_color_8_24_mix(chan_val, &dest_buf_u8[dest_x], LV_OPA_MIX2(opa, mask_buf[src_x]));
|
||||
}
|
||||
dest_buf_u8 = drawbuf_next_row(dest_buf_u8, dest_stride);
|
||||
src_buf_i1 = drawbuf_next_row(src_buf_i1, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color32_t src_argb;
|
||||
src_argb.red = get_bit(src_buf_i1, src_x) * 255;
|
||||
src_argb.green = src_argb.red;
|
||||
src_argb.blue = src_argb.red;
|
||||
if (mask_buf == NULL) {
|
||||
src_argb.alpha = opa;
|
||||
} else {
|
||||
src_argb.alpha = LV_OPA_MIX2(mask_buf[src_x], opa);
|
||||
}
|
||||
blend_non_normal_pixel(&dest_buf_u8[dest_x], src_argb, dsc->blend_mode);
|
||||
}
|
||||
if (mask_buf) {
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
dest_buf_u8 = drawbuf_next_row(dest_buf_u8, dest_stride);
|
||||
src_buf_i1 = drawbuf_next_row(src_buf_i1, src_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LV_ATTRIBUTE_FAST_MEM al88_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
uint8_t *dest_buf_u8 = dsc->dest_buf;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
const lv_color16a_t *src_buf_al88 = dsc->src_buf;
|
||||
int32_t src_stride = dsc->src_stride;
|
||||
const lv_opa_t *mask_buf = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
|
||||
int32_t dest_x;
|
||||
int32_t src_x;
|
||||
int32_t y;
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_al88[src_x].lumi, &dest_buf_u8[dest_x], src_buf_al88[src_x].alpha);
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_al88 = drawbuf_next_row(src_buf_al88, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_OPA(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_al88[src_x].lumi, &dest_buf_u8[dest_x], LV_OPA_MIX2(src_buf_al88[src_x].alpha, opa));
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_al88 = drawbuf_next_row(src_buf_al88, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_MASK(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_al88[src_x].lumi, &dest_buf_u8[dest_x], LV_OPA_MIX2(src_buf_al88[src_x].alpha,
|
||||
mask_buf[src_x]));
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_al88 = drawbuf_next_row(src_buf_al88, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_al88[src_x].lumi, &dest_buf_u8[dest_x], LV_OPA_MIX3(src_buf_al88[src_x].alpha,
|
||||
mask_buf[src_x], opa));
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_al88 = drawbuf_next_row(src_buf_al88, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color32_t src_argb;
|
||||
src_argb.red = src_argb.green = src_argb.blue = src_buf_al88[src_x].lumi;
|
||||
if (mask_buf == NULL) {
|
||||
src_argb.alpha = LV_OPA_MIX2(src_buf_al88[src_x].alpha, opa);
|
||||
} else {
|
||||
src_argb.alpha = LV_OPA_MIX3(src_buf_al88[src_x].alpha, mask_buf[dest_x], opa);
|
||||
}
|
||||
blend_non_normal_pixel(&dest_buf_u8[dest_x], src_argb, dsc->blend_mode);
|
||||
}
|
||||
if (mask_buf) {
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_al88 = drawbuf_next_row(src_buf_al88, src_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LV_ATTRIBUTE_FAST_MEM l8_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
uint8_t *dest_buf_u8 = dsc->dest_buf;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
const uint8_t *src_buf_l8 = dsc->src_buf;
|
||||
int32_t src_stride = dsc->src_stride;
|
||||
const lv_opa_t *mask_buf = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
|
||||
int32_t dest_x;
|
||||
int32_t src_x;
|
||||
int32_t y;
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
dest_buf_u8[dest_x + 2] = src_buf_l8[src_x];
|
||||
dest_buf_u8[dest_x + 1] = src_buf_l8[src_x];
|
||||
dest_buf_u8[dest_x + 0] = src_buf_l8[src_x];
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_l8 = drawbuf_next_row(src_buf_l8, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_OPA(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_l8[src_x], &dest_buf_u8[dest_x], opa);
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_l8 = drawbuf_next_row(src_buf_l8, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_WITH_MASK(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_l8[src_x], &dest_buf_u8[dest_x], mask_buf[src_x]);
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_l8 = drawbuf_next_row(src_buf_l8, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_L8_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_8_24_mix(src_buf_l8[src_x], &dest_buf_u8[dest_x], LV_OPA_MIX2(opa, mask_buf[src_x]));
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_l8 = drawbuf_next_row(src_buf_l8, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lv_color32_t src_argb;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
src_argb.red = src_buf_l8[src_x];
|
||||
src_argb.green = src_buf_l8[src_x];
|
||||
src_argb.blue = src_buf_l8[src_x];
|
||||
if (mask_buf == NULL) {
|
||||
src_argb.alpha = opa;
|
||||
} else {
|
||||
src_argb.alpha = LV_OPA_MIX2(mask_buf[dest_x], opa);
|
||||
}
|
||||
blend_non_normal_pixel(&dest_buf_u8[dest_x], src_argb, dsc->blend_mode);
|
||||
}
|
||||
if (mask_buf) {
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_l8 = drawbuf_next_row(src_buf_l8, src_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LV_ATTRIBUTE_FAST_MEM rgb565_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
uint8_t *dest_buf_u8 = dsc->dest_buf;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
const lv_color16_t *src_buf_c16 = (const lv_color16_t *) dsc->src_buf;
|
||||
int32_t src_stride = dsc->src_stride;
|
||||
const lv_opa_t *mask_buf = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
|
||||
int32_t src_x;
|
||||
int32_t dest_x;
|
||||
int32_t y;
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (src_x = 0, dest_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
dest_buf_u8[dest_x + 2] = (src_buf_c16[src_x].red * 2106) >> 8; /*To make it rounded*/
|
||||
dest_buf_u8[dest_x + 1] = (src_buf_c16[src_x].green * 1037) >> 8;
|
||||
dest_buf_u8[dest_x + 0] = (src_buf_c16[src_x].blue * 2106) >> 8;
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_c16 = drawbuf_next_row(src_buf_c16, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_WITH_OPA(dsc, dest_px_size)) {
|
||||
uint8_t res[3];
|
||||
for (y = 0; y < h; y++) {
|
||||
for (src_x = 0, dest_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
res[2] = (src_buf_c16[src_x].red * 2106) >> 8; /*To make it rounded*/
|
||||
res[1] = (src_buf_c16[src_x].green * 1037) >> 8;
|
||||
res[0] = (src_buf_c16[src_x].blue * 2106) >> 8;
|
||||
lv_color_24_24_mix(res, &dest_buf_u8[dest_x], opa);
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_c16 = drawbuf_next_row(src_buf_c16, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_WITH_MASK(dsc, dest_px_size)) {
|
||||
uint8_t res[3];
|
||||
for (y = 0; y < h; y++) {
|
||||
for (src_x = 0, dest_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
res[2] = (src_buf_c16[src_x].red * 2106) >> 8; /*To make it rounded*/
|
||||
res[1] = (src_buf_c16[src_x].green * 1037) >> 8;
|
||||
res[0] = (src_buf_c16[src_x].blue * 2106) >> 8;
|
||||
lv_color_24_24_mix(res, &dest_buf_u8[dest_x], mask_buf[src_x]);
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_c16 = drawbuf_next_row(src_buf_c16, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB565_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(dsc, dest_px_size)) {
|
||||
uint8_t res[3];
|
||||
for (y = 0; y < h; y++) {
|
||||
for (src_x = 0, dest_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
res[2] = (src_buf_c16[src_x].red * 2106) >> 8; /*To make it rounded*/
|
||||
res[1] = (src_buf_c16[src_x].green * 1037) >> 8;
|
||||
res[0] = (src_buf_c16[src_x].blue * 2106) >> 8;
|
||||
lv_color_24_24_mix(res, &dest_buf_u8[dest_x], LV_OPA_MIX2(opa, mask_buf[src_x]));
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_c16 = drawbuf_next_row(src_buf_c16, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lv_color32_t src_argb;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (src_x = 0, dest_x = 0; src_x < w; src_x++, dest_x += dest_px_size) {
|
||||
src_argb.red = (src_buf_c16[src_x].red * 2106) >> 8;
|
||||
src_argb.green = (src_buf_c16[src_x].green * 1037) >> 8;
|
||||
src_argb.blue = (src_buf_c16[src_x].blue * 2106) >> 8;
|
||||
if (mask_buf == NULL) {
|
||||
src_argb.alpha = opa;
|
||||
} else {
|
||||
src_argb.alpha = LV_OPA_MIX2(mask_buf[src_x], opa);
|
||||
}
|
||||
blend_non_normal_pixel(&dest_buf_u8[dest_x], src_argb, dsc->blend_mode);
|
||||
}
|
||||
if (mask_buf) {
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
dest_buf_u8 += dest_stride;
|
||||
src_buf_c16 = drawbuf_next_row(src_buf_c16, src_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LV_ATTRIBUTE_FAST_MEM rgb888_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, const uint8_t dest_px_size,
|
||||
uint32_t src_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w * dest_px_size;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
uint8_t *dest_buf = dsc->dest_buf;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
const uint8_t *src_buf = dsc->src_buf;
|
||||
int32_t src_stride = dsc->src_stride;
|
||||
const lv_opa_t *mask_buf = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
|
||||
int32_t dest_x;
|
||||
int32_t src_x;
|
||||
int32_t y;
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
/*Special case*/
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888(dsc, dest_px_size, src_px_size)) {
|
||||
if (src_px_size == dest_px_size) {
|
||||
for (y = 0; y < h; y++) {
|
||||
lv_memcpy(dest_buf, src_buf, w);
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; dest_x < w; dest_x += dest_px_size, src_x += src_px_size) {
|
||||
dest_buf[dest_x + 0] = src_buf[src_x + 0];
|
||||
dest_buf[dest_x + 1] = src_buf[src_x + 1];
|
||||
dest_buf[dest_x + 2] = src_buf[src_x + 2];
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mask_buf == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_WITH_OPA(dsc, dest_px_size, src_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; dest_x < w; dest_x += dest_px_size, src_x += src_px_size) {
|
||||
lv_color_24_24_mix(&src_buf[src_x], &dest_buf[dest_x], opa);
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mask_buf && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_WITH_MASK(dsc, dest_px_size, src_px_size)) {
|
||||
uint32_t mask_x;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (mask_x = 0, dest_x = 0, src_x = 0; dest_x < w; mask_x++, dest_x += dest_px_size, src_x += src_px_size) {
|
||||
lv_color_24_24_mix(&src_buf[src_x], &dest_buf[dest_x], mask_buf[mask_x]);
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mask_buf && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_RGB888_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(dsc, dest_px_size, src_px_size)) {
|
||||
uint32_t mask_x;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (mask_x = 0, dest_x = 0, src_x = 0; dest_x < w; mask_x++, dest_x += dest_px_size, src_x += src_px_size) {
|
||||
lv_color_24_24_mix(&src_buf[src_x], &dest_buf[dest_x], LV_OPA_MIX2(opa, mask_buf[mask_x]));
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lv_color32_t src_argb;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; dest_x < w; dest_x += dest_px_size, src_x += src_px_size) {
|
||||
src_argb.red = src_buf[src_x + 2];
|
||||
src_argb.green = src_buf[src_x + 1];
|
||||
src_argb.blue = src_buf[src_x + 0];
|
||||
if (mask_buf == NULL) {
|
||||
src_argb.alpha = opa;
|
||||
} else {
|
||||
src_argb.alpha = LV_OPA_MIX2(mask_buf[dest_x], opa);
|
||||
}
|
||||
|
||||
blend_non_normal_pixel(&dest_buf[dest_x], src_argb, dsc->blend_mode);
|
||||
}
|
||||
if (mask_buf) {
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf += src_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LV_ATTRIBUTE_FAST_MEM argb8888_image_blend(_lv_draw_sw_blend_image_dsc_t *dsc, uint32_t dest_px_size)
|
||||
{
|
||||
int32_t w = dsc->dest_w;
|
||||
int32_t h = dsc->dest_h;
|
||||
lv_opa_t opa = dsc->opa;
|
||||
uint8_t *dest_buf = dsc->dest_buf;
|
||||
int32_t dest_stride = dsc->dest_stride;
|
||||
const lv_color32_t *src_buf_c32 = dsc->src_buf;
|
||||
int32_t src_stride = dsc->src_stride;
|
||||
const lv_opa_t *mask_buf = dsc->mask_buf;
|
||||
int32_t mask_stride = dsc->mask_stride;
|
||||
|
||||
int32_t dest_x;
|
||||
int32_t src_x;
|
||||
int32_t y;
|
||||
|
||||
if (dsc->blend_mode == LV_BLEND_MODE_NORMAL) {
|
||||
if (mask_buf == NULL && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_24_24_mix((const uint8_t *)&src_buf_c32[src_x], &dest_buf[dest_x], src_buf_c32[src_x].alpha);
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf_c32 = drawbuf_next_row(src_buf_c32, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf == NULL && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_WITH_OPA(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_24_24_mix((const uint8_t *)&src_buf_c32[src_x], &dest_buf[dest_x], LV_OPA_MIX2(src_buf_c32[src_x].alpha, opa));
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf_c32 = drawbuf_next_row(src_buf_c32, src_stride);
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa >= LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_WITH_MASK(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_24_24_mix((const uint8_t *)&src_buf_c32[src_x], &dest_buf[dest_x],
|
||||
LV_OPA_MIX2(src_buf_c32[src_x].alpha, mask_buf[src_x]));
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf_c32 = drawbuf_next_row(src_buf_c32, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
} else if (mask_buf && opa < LV_OPA_MAX) {
|
||||
if (LV_RESULT_INVALID == LV_DRAW_SW_ARGB8888_BLEND_NORMAL_TO_RGB888_MIX_MASK_OPA(dsc, dest_px_size)) {
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x++) {
|
||||
lv_color_24_24_mix((const uint8_t *)&src_buf_c32[src_x], &dest_buf[dest_x],
|
||||
LV_OPA_MIX3(src_buf_c32[src_x].alpha, mask_buf[src_x], opa));
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf_c32 = drawbuf_next_row(src_buf_c32, src_stride);
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lv_color32_t src_argb;
|
||||
for (y = 0; y < h; y++) {
|
||||
for (dest_x = 0, src_x = 0; src_x < w; dest_x += dest_px_size, src_x ++) {
|
||||
src_argb = src_buf_c32[src_x];
|
||||
if (mask_buf == NULL) {
|
||||
src_argb.alpha = LV_OPA_MIX2(src_argb.alpha, opa);
|
||||
} else {
|
||||
src_argb.alpha = LV_OPA_MIX3(src_argb.alpha, mask_buf[dest_x], opa);
|
||||
}
|
||||
|
||||
blend_non_normal_pixel(&dest_buf[dest_x], src_argb, dsc->blend_mode);
|
||||
}
|
||||
if (mask_buf) {
|
||||
mask_buf += mask_stride;
|
||||
}
|
||||
dest_buf += dest_stride;
|
||||
src_buf_c32 = drawbuf_next_row(src_buf_c32, src_stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void LV_ATTRIBUTE_FAST_MEM blend_non_normal_pixel(uint8_t *dest, lv_color32_t src, lv_blend_mode_t mode)
|
||||
{
|
||||
uint8_t res[3] = {0, 0, 0};
|
||||
switch (mode) {
|
||||
case LV_BLEND_MODE_ADDITIVE:
|
||||
res[0] = LV_MIN(dest[0] + src.blue, 255);
|
||||
res[1] = LV_MIN(dest[1] + src.green, 255);
|
||||
res[2] = LV_MIN(dest[2] + src.red, 255);
|
||||
break;
|
||||
case LV_BLEND_MODE_SUBTRACTIVE:
|
||||
res[0] = LV_MAX(dest[0] - src.blue, 0);
|
||||
res[1] = LV_MAX(dest[1] - src.green, 0);
|
||||
res[2] = LV_MAX(dest[2] - src.red, 0);
|
||||
break;
|
||||
case LV_BLEND_MODE_MULTIPLY:
|
||||
res[0] = (dest[0] * src.blue) >> 8;
|
||||
res[1] = (dest[1] * src.green) >> 8;
|
||||
res[2] = (dest[2] * src.red) >> 8;
|
||||
break;
|
||||
default:
|
||||
LV_LOG_WARN("Not supported blend mode: %d", mode);
|
||||
return;
|
||||
}
|
||||
lv_color_24_24_mix(res, dest, src.alpha);
|
||||
}
|
||||
|
||||
static inline void LV_ATTRIBUTE_FAST_MEM lv_color_8_24_mix(const uint8_t src, uint8_t *dest, uint8_t mix)
|
||||
{
|
||||
|
||||
if (mix == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mix >= LV_OPA_MAX) {
|
||||
dest[0] = src;
|
||||
dest[1] = src;
|
||||
dest[2] = src;
|
||||
} else {
|
||||
lv_opa_t mix_inv = 255 - mix;
|
||||
dest[0] = (uint32_t)((uint32_t)src * mix + dest[0] * mix_inv) >> 8;
|
||||
dest[1] = (uint32_t)((uint32_t)src * mix + dest[1] * mix_inv) >> 8;
|
||||
dest[2] = (uint32_t)((uint32_t)src * mix + dest[2] * mix_inv) >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void LV_ATTRIBUTE_FAST_MEM lv_color_24_24_mix(const uint8_t *src, uint8_t *dest, uint8_t mix)
|
||||
{
|
||||
|
||||
if (mix == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mix >= LV_OPA_MAX) {
|
||||
dest[0] = src[0];
|
||||
dest[1] = src[1];
|
||||
dest[2] = src[2];
|
||||
} else {
|
||||
lv_opa_t mix_inv = 255 - mix;
|
||||
dest[0] = (uint32_t)((uint32_t)src[0] * mix + dest[0] * mix_inv) >> 8;
|
||||
dest[1] = (uint32_t)((uint32_t)src[1] * mix + dest[1] * mix_inv) >> 8;
|
||||
dest[2] = (uint32_t)((uint32_t)src[2] * mix + dest[2] * mix_inv) >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t LV_ATTRIBUTE_FAST_MEM get_bit(const uint8_t *buf, int32_t bit_idx)
|
||||
{
|
||||
return (buf[bit_idx / 8] >> (7 - (bit_idx % 8))) & 1;
|
||||
}
|
||||
|
||||
static inline void *LV_ATTRIBUTE_FAST_MEM drawbuf_next_row(const void *buf, uint32_t stride)
|
||||
{
|
||||
return (void *)((uint8_t *)buf + stride);
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* This file is derived from the LVGL project.
|
||||
* See https://github.com/lvgl/lvgl for details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file lv_string.c
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
//#include "../../lv_conf_internal.h"
|
||||
#if LV_USE_STDLIB_STRING == LV_STDLIB_BUILTIN
|
||||
#include "lv_assert.h"
|
||||
#include "lv_log.h"
|
||||
#include "lv_math.h"
|
||||
#include "lv_string.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#ifdef LV_ARCH_64
|
||||
#define MEM_UNIT uint64_t
|
||||
#define ALIGN_MASK 0x7
|
||||
#else
|
||||
#define MEM_UNIT uint32_t
|
||||
#define ALIGN_MASK 0x3
|
||||
#endif
|
||||
|
||||
#define LV_ATTRIBUTE_FAST_MEM
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#if LV_USE_LOG && LV_LOG_TRACE_MEM
|
||||
#define LV_TRACE_MEM(...) LV_LOG_TRACE(__VA_ARGS__)
|
||||
#else
|
||||
#define LV_TRACE_MEM(...)
|
||||
#endif
|
||||
|
||||
#define _COPY(d, s) *d = *s; d++; s++;
|
||||
#define _SET(d, v) *d = v; d++;
|
||||
#define _REPEAT8(expr) expr expr expr expr expr expr expr expr
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void *LV_ATTRIBUTE_FAST_MEM lv_memcpy(void *dst, const void *src, size_t len)
|
||||
{
|
||||
uint8_t *d8 = dst;
|
||||
const uint8_t *s8 = src;
|
||||
|
||||
/*Simplify for small memories*/
|
||||
if (len < 16) {
|
||||
while (len) {
|
||||
*d8 = *s8;
|
||||
d8++;
|
||||
s8++;
|
||||
len--;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
lv_uintptr_t d_align = (lv_uintptr_t)d8 & ALIGN_MASK;
|
||||
lv_uintptr_t s_align = (lv_uintptr_t)s8 & ALIGN_MASK;
|
||||
|
||||
/*Byte copy for unaligned memories*/
|
||||
if (s_align != d_align) {
|
||||
while (len > 32) {
|
||||
_REPEAT8(_COPY(d8, s8));
|
||||
_REPEAT8(_COPY(d8, s8));
|
||||
_REPEAT8(_COPY(d8, s8));
|
||||
_REPEAT8(_COPY(d8, s8));
|
||||
len -= 32;
|
||||
}
|
||||
while (len) {
|
||||
_COPY(d8, s8)
|
||||
len--;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/*Make the memories aligned*/
|
||||
if (d_align) {
|
||||
d_align = ALIGN_MASK + 1 - d_align;
|
||||
while (d_align && len) {
|
||||
_COPY(d8, s8);
|
||||
d_align--;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t *d32 = (uint32_t *)d8;
|
||||
const uint32_t *s32 = (uint32_t *)s8;
|
||||
while (len > 32) {
|
||||
_REPEAT8(_COPY(d32, s32))
|
||||
len -= 32;
|
||||
}
|
||||
|
||||
d8 = (uint8_t *)d32;
|
||||
s8 = (const uint8_t *)s32;
|
||||
while (len) {
|
||||
_COPY(d8, s8)
|
||||
len--;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void LV_ATTRIBUTE_FAST_MEM lv_memset(void *dst, uint8_t v, size_t len)
|
||||
{
|
||||
uint8_t *d8 = (uint8_t *)dst;
|
||||
uintptr_t d_align = (lv_uintptr_t) d8 & ALIGN_MASK;
|
||||
|
||||
/*Make the address aligned*/
|
||||
if (d_align) {
|
||||
d_align = ALIGN_MASK + 1 - d_align;
|
||||
while (d_align && len) {
|
||||
_SET(d8, v);
|
||||
len--;
|
||||
d_align--;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t v32 = (uint32_t)v + ((uint32_t)v << 8) + ((uint32_t)v << 16) + ((uint32_t)v << 24);
|
||||
uint32_t *d32 = (uint32_t *)d8;
|
||||
|
||||
while (len > 32) {
|
||||
_REPEAT8(_SET(d32, v32));
|
||||
len -= 32;
|
||||
}
|
||||
|
||||
d8 = (uint8_t *)d32;
|
||||
while (len) {
|
||||
_SET(d8, v);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
void *LV_ATTRIBUTE_FAST_MEM lv_memmove(void *dst, const void *src, size_t len)
|
||||
{
|
||||
if (dst < src || (char *)dst > ((char *)src + len)) {
|
||||
return lv_memcpy(dst, src, len);
|
||||
}
|
||||
|
||||
if (dst > src) {
|
||||
char *tmp = (char *)dst + len - 1;
|
||||
char *s = (char *)src + len - 1;
|
||||
|
||||
while (len--) {
|
||||
*tmp-- = *s--;
|
||||
}
|
||||
} else {
|
||||
char *tmp = (char *)dst;
|
||||
char *s = (char *)src;
|
||||
|
||||
while (len--) {
|
||||
*tmp++ = *s++;
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_STDLIB_BUILTIN*/
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -42,7 +42,8 @@ typedef struct {
|
||||
void *p_asm_alloc; // pointer to the beginning of the memory allocated for ASM test buf, used in free()
|
||||
void *p_ansi_alloc; // pointer to the beginning of the memory allocated for ANSI test buf, used in free()
|
||||
} buf;
|
||||
void (*blend_api_func)(_lv_draw_sw_blend_fill_dsc_t *); // pointer to LVGL API function
|
||||
void (*blend_api_func)(_lv_draw_sw_blend_fill_dsc_t *); // pointer to LVGL API function
|
||||
void (*blend_api_px_func)(_lv_draw_sw_blend_fill_dsc_t *, uint32_t); // pointer to LVGL API function with dest_px_size argument
|
||||
lv_color_format_t color_format; // LV color format
|
||||
size_t data_type_size; // Used data type size, eg sizeof()
|
||||
size_t active_buf_len; // Length of buffer, where the actual data are stored (not including Canary bytes)
|
||||
@@ -64,8 +65,9 @@ typedef struct {
|
||||
unsigned int cc_width; // Corner case test array width
|
||||
unsigned int benchmark_cycles; // Count of benchmark cycles
|
||||
void *array_align16; // test array with 16 byte alignment - testing most ideal case
|
||||
void *array_align1; // test array with 1 byte alignment - testing wort case
|
||||
void (*blend_api_func)(_lv_draw_sw_blend_fill_dsc_t *); // pointer to LVGL API function
|
||||
void *array_align1; // test array with 1 byte alignment - testing worst case
|
||||
void (*blend_api_func)(_lv_draw_sw_blend_fill_dsc_t *); // pointer to LVGL API function
|
||||
void (*blend_api_px_func)(_lv_draw_sw_blend_fill_dsc_t *, uint32_t); // pointer to LVGL API function with dest_px_size argument
|
||||
} bench_test_case_params_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_err.h"
|
||||
#include <stdint.h>
|
||||
#include "lv_color.h"
|
||||
#include "lv_draw_sw_blend.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------- Macros and Types --------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Type of blend DUT function
|
||||
*/
|
||||
typedef enum {
|
||||
OPERATION_FILL,
|
||||
OPERATION_FILL_WITH_OPA,
|
||||
} blend_operation_t;
|
||||
|
||||
/**
|
||||
* @brief Canary pixels amount depending on data type
|
||||
* @note
|
||||
* - We should use at least 16 bytes of memory for canary pixels because of esp32s3 TIE 16-bytes wide Q registers
|
||||
* - Canary pixels are multiplied by sizeof(used_data_type) to get the memory length occupied by the canary pixels
|
||||
* - The memory occupied by canary pixels should be in 16-byte multiples, to achieve 16-byte memory alignment in functionality test
|
||||
* - For example, ideally, for RGB565 we would need 8 canary pixels -> 8 * sizeof(uint16_t) = 16
|
||||
*/
|
||||
typedef enum {
|
||||
CANARY_PIXELS_ARGB8888 = 4, /*!< Canary pixels: 4 * sizeof(uint32_t) = 16 */
|
||||
CANARY_PIXELS_RGB565 = 8, /*!< Canary pixels: 8 * sizeof(uint16_t) = 16 */
|
||||
} canary_pixels_t;
|
||||
|
||||
/**
|
||||
* @brief Functionality test combinations for LV Image
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int min_w; /*!< Minimum width of the test array */
|
||||
unsigned int min_h; /*!< Minimum height of the test array */
|
||||
unsigned int max_w; /*!< Maximum width of the test array */
|
||||
unsigned int max_h; /*!< Maximum height of the test array */
|
||||
unsigned int src_min_unalign_byte; /*!< Minimum amount of unaligned bytes of the source test array */
|
||||
unsigned int dest_min_unalign_byte; /*!< Minimum amount of unaligned bytes of the destination test array */
|
||||
unsigned int src_max_unalign_byte; /*!< Maximum amount of unaligned bytes of the source test array */
|
||||
unsigned int dest_max_unalign_byte; /*!< Maximum amount of unaligned bytes of the destination test array */
|
||||
unsigned int src_unalign_step; /*!< Increment step in bytes unalignment of the source test array */
|
||||
unsigned int dest_unalign_step; /*!< Increment step in bytes unalignment of the destination test array */
|
||||
unsigned int src_stride_step; /*!< Increment step in destination stride of the source test array */
|
||||
unsigned int dest_stride_step; /*!< Increment step in destination stride of the destination test array */
|
||||
unsigned int test_combinations_count; /*!< Count of fest combinations */
|
||||
} test_matrix_lv_image_params_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Functionality test case parameters for LV Image
|
||||
*/
|
||||
typedef struct {
|
||||
struct {
|
||||
void *p_src; /*!< pointer to the source test buff (common src buffer for both the ANSI and ASM) */
|
||||
void *p_src_alloc; /*!< pointer to the beginning of the memory allocated for the source ASM test buf, used in free() */
|
||||
void *p_dest_asm; /*!< pointer to the destination ASM test buf */
|
||||
void *p_dest_ansi; /*!< pointer to the destination ANSI test buf */
|
||||
void *p_dest_asm_alloc; /*!< pointer to the beginning of the memory allocated for the destination ASM test buf, used in free() */
|
||||
void *p_dest_ansi_alloc; /*!< pointer to the beginning of the memory allocated for the destination ANSI test buf, used in free() */
|
||||
} buf;
|
||||
void (*blend_api_func)(_lv_draw_sw_blend_image_dsc_t *); /*!< pointer to LVGL API function */
|
||||
lv_color_format_t color_format; /*!< LV color format */
|
||||
size_t src_data_type_size; /*!< Used data type size in the source buffer, eg sizeof(src_buff[0]) */
|
||||
size_t dest_data_type_size; /*!< Used data type size in the destination buffer, eg sizeof(dest_buff[0]) */
|
||||
size_t src_buf_len; /*!< Length of the source buffer, including matrix padding (no Canary pixels are used for source buffer) */
|
||||
size_t active_dest_buf_len; /*!< Length of the destination buffer, where the actual data are stored, including matrix padding, not including Canary pixels */
|
||||
size_t total_dest_buf_len; /*!< Total length of the destination buffer (including Canary pixels and matrix padding) */
|
||||
size_t canary_pixels; /*!< Canary pixels must be adjusted according to the used color type, to achieve aligned memory effect */
|
||||
unsigned int dest_w; /*!< Destination buffer width */
|
||||
unsigned int dest_h; /*!< Destination buffer height */
|
||||
unsigned int src_stride; /*!< Source buffer stride */
|
||||
unsigned int dest_stride; /*!< Destination buffer stride */
|
||||
unsigned int src_unalign_byte; /*!< Source buffer memory unalignment */
|
||||
unsigned int dest_unalign_byte; /*!< Destination buffer memory unalignment */
|
||||
blend_operation_t operation_type; /*!< Type of fundamental blend operation */
|
||||
} func_test_case_lv_image_params_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Benchmark test case parameters for LV Image
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int height; /*!< Test array height */
|
||||
unsigned int width; /*!< Test array width */
|
||||
unsigned int dest_stride; /*!< Destination test array stride */
|
||||
unsigned int src_stride; /*!< Source test array stride */
|
||||
unsigned int cc_height; /*!< Corner case test array height */
|
||||
unsigned int cc_width; /*!< Corner case test array width */
|
||||
unsigned int benchmark_cycles; /*!< Count of benchmark cycles */
|
||||
void *src_array_align16; /*!< Source test array with 16 byte alignment - testing most ideal case */
|
||||
void *src_array_align1; /*!< Source test array with 1 byte alignment - testing worst case */
|
||||
void *dest_array_align16; /*!< Destination test array with 16 byte alignment - testing most ideal case */
|
||||
void *dest_array_align1; /*!< Destination test array with 1 byte alignment - testing worst case */
|
||||
void (*blend_api_func)(_lv_draw_sw_blend_image_dsc_t *); /*!< pointer to LVGL API function */
|
||||
} bench_test_case_lv_image_params_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_draw_sw_blend_to_argb8888.h"
|
||||
#include "lv_draw_sw_blend_to_rgb565.h"
|
||||
#include "lv_draw_sw_blend_to_rgb888.h"
|
||||
|
||||
#define WIDTH 128
|
||||
#define HEIGHT 128
|
||||
@@ -115,6 +116,31 @@ TEST_CASE("LV Fill benchmark RGB565", "[fill][benchmark][RGB565]")
|
||||
lv_fill_benchmark_init(&test_params);
|
||||
free(dest_array_align16);
|
||||
}
|
||||
|
||||
TEST_CASE("LV Fill benchmark RGB888", "[fill][benchmark][RGB888]")
|
||||
{
|
||||
uint8_t *dest_array_align16 = (uint8_t *)memalign(16, STRIDE * HEIGHT * sizeof(uint8_t) * 3 + UNALIGN_BYTES);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, dest_array_align16);
|
||||
|
||||
// Apply byte unalignment for the worst-case test scenario
|
||||
uint8_t *dest_array_align1 = dest_array_align16 + UNALIGN_BYTES;
|
||||
|
||||
bench_test_case_params_t test_params = {
|
||||
.height = HEIGHT,
|
||||
.width = WIDTH,
|
||||
.stride = STRIDE * 3,
|
||||
.cc_height = HEIGHT - 1,
|
||||
.cc_width = WIDTH - 1,
|
||||
.benchmark_cycles = BENCHMARK_CYCLES,
|
||||
.array_align16 = (void *)dest_array_align16,
|
||||
.array_align1 = (void *)dest_array_align1,
|
||||
.blend_api_px_func = &lv_draw_sw_blend_color_to_rgb888,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG_LV_FILL_BENCH, "running test for RGB888 color format");
|
||||
lv_fill_benchmark_init(&test_params);
|
||||
free(dest_array_align16);
|
||||
}
|
||||
// ------------------------------------------------ Static test functions ----------------------------------------------
|
||||
|
||||
static void lv_fill_benchmark_init(bench_test_case_params_t *test_params)
|
||||
@@ -162,11 +188,21 @@ static void lv_fill_benchmark_init(bench_test_case_params_t *test_params)
|
||||
static float lv_fill_benchmark_run(bench_test_case_params_t *test_params, _lv_draw_sw_blend_fill_dsc_t *dsc)
|
||||
{
|
||||
// Call the DUT function for the first time to init the benchmark test
|
||||
test_params->blend_api_func(dsc);
|
||||
if (test_params->blend_api_func != NULL) {
|
||||
test_params->blend_api_func(dsc);
|
||||
} else if (test_params->blend_api_px_func != NULL) {
|
||||
test_params->blend_api_px_func(dsc, 3);
|
||||
}
|
||||
|
||||
const unsigned int start_b = xthal_get_ccount();
|
||||
for (int i = 0; i < test_params->benchmark_cycles; i++) {
|
||||
test_params->blend_api_func(dsc);
|
||||
if (test_params->blend_api_func != NULL) {
|
||||
for (int i = 0; i < test_params->benchmark_cycles; i++) {
|
||||
test_params->blend_api_func(dsc);
|
||||
}
|
||||
} else if (test_params->blend_api_px_func != NULL) {
|
||||
for (int i = 0; i < test_params->benchmark_cycles; i++) {
|
||||
test_params->blend_api_px_func(dsc, 3);
|
||||
}
|
||||
}
|
||||
const unsigned int end_b = xthal_get_ccount();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_draw_sw_blend_to_argb8888.h"
|
||||
#include "lv_draw_sw_blend_to_rgb565.h"
|
||||
#include "lv_draw_sw_blend_to_rgb888.h"
|
||||
|
||||
// ------------------------------------------------- Defines -----------------------------------------------------------
|
||||
|
||||
@@ -47,14 +48,14 @@ static lv_color_t test_color = {
|
||||
* - generate functionality test combinations, based on the provided test_matrix struct
|
||||
*
|
||||
* @param[in] test_matrix Pointer to structure defining test matrix - all the test combinations
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
* @param[in] test_case Pointer to structure defining functionality test case
|
||||
*/
|
||||
static void functionality_test_matrix(test_matrix_params_t *test_matrix, func_test_case_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief Fill test buffers for functionality test
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
* @param[in] test_case Pointer to structure defining functionality test case
|
||||
*/
|
||||
static void fill_test_bufs(func_test_case_params_t *test_case);
|
||||
|
||||
@@ -63,24 +64,31 @@ static void fill_test_bufs(func_test_case_params_t *test_case);
|
||||
*
|
||||
* - function prepares structures for functionality testing and runs the LVGL API
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
* @param[in] test_case Pointer to structure defining functionality test case
|
||||
*/
|
||||
static void lv_fill_functionality(func_test_case_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief Evaluate results for 32bit data length
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
* @param[in] test_case Pointer to structure defining functionality test case
|
||||
*/
|
||||
static void test_eval_32bit_data(func_test_case_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief Evaluate results for 16bit data length
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
* @param[in] test_case Pointer to structure defining functionality test case
|
||||
*/
|
||||
static void test_eval_16bit_data(func_test_case_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief Evaluate results for 24bit data length
|
||||
*
|
||||
* @param[in] test_case Pointer to structure defining functionality test case
|
||||
*/
|
||||
static void test_eval_24bit_data(func_test_case_params_t *test_case);
|
||||
|
||||
// ------------------------------------------------ Test cases ---------------------------------------------------------
|
||||
|
||||
/*
|
||||
@@ -147,6 +155,29 @@ TEST_CASE("Test fill functionality RGB565", "[fill][functionality][RGB565]")
|
||||
functionality_test_matrix(&test_matrix, &test_case);
|
||||
}
|
||||
|
||||
TEST_CASE("Test fill functionality RGB888", "[fill][functionality][RGB888]")
|
||||
{
|
||||
test_matrix_params_t test_matrix = {
|
||||
.min_w = 12, // 12 is the lower limit for the esp32s3 asm implementation, otherwise esp32 is executed
|
||||
.min_h = 1,
|
||||
.max_w = 32,
|
||||
.max_h = 3,
|
||||
.min_unalign_byte = 0,
|
||||
.max_unalign_byte = 16,
|
||||
.unalign_step = 1,
|
||||
.dest_stride_step = 1,
|
||||
.test_combinations_count = 0,
|
||||
};
|
||||
|
||||
func_test_case_params_t test_case = {
|
||||
.blend_api_px_func = &lv_draw_sw_blend_color_to_rgb888,
|
||||
.color_format = LV_COLOR_FORMAT_RGB888,
|
||||
.data_type_size = sizeof(uint8_t) * 3, // 24-bit data length
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG_LV_FILL_FUNC, "running test for RGB888 color format");
|
||||
functionality_test_matrix(&test_matrix, &test_case);
|
||||
}
|
||||
// ------------------------------------------------ Static test functions ----------------------------------------------
|
||||
|
||||
static void functionality_test_matrix(test_matrix_params_t *test_matrix, func_test_case_params_t *test_case)
|
||||
@@ -195,8 +226,13 @@ static void lv_fill_functionality(func_test_case_params_t *test_case)
|
||||
dsc_ansi.dest_buf = test_case->buf.p_ansi;
|
||||
dsc_ansi.use_asm = false;
|
||||
|
||||
test_case->blend_api_func(&dsc_asm); // Call the LVGL API with Assembly code
|
||||
test_case->blend_api_func(&dsc_ansi); // Call the LVGL API with ANSI code
|
||||
if (test_case->blend_api_func != NULL) {
|
||||
test_case->blend_api_func(&dsc_asm); // Call the LVGL API with Assembly code
|
||||
test_case->blend_api_func(&dsc_ansi); // Call the LVGL API with ANSI code
|
||||
} else if (test_case->blend_api_px_func != NULL) {
|
||||
test_case->blend_api_px_func(&dsc_asm, 3); // Call the LVGL API with Assembly code with set pixel size
|
||||
test_case->blend_api_px_func(&dsc_ansi, 3); // Call the LVGL API with ANSI code with set pixel size
|
||||
}
|
||||
|
||||
// Shift array pointers by Canary Bytes amount back
|
||||
test_case->buf.p_asm -= CANARY_BYTES * test_case->data_type_size;
|
||||
@@ -216,6 +252,11 @@ static void lv_fill_functionality(func_test_case_params_t *test_case)
|
||||
break;
|
||||
}
|
||||
|
||||
case LV_COLOR_FORMAT_RGB888: {
|
||||
test_eval_24bit_data(test_case);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
TEST_ASSERT_MESSAGE(false, "LV Color format not found");
|
||||
}
|
||||
@@ -309,3 +350,34 @@ static void test_eval_16bit_data(func_test_case_params_t *test_case)
|
||||
TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(0, (uint16_t *)test_case->buf.p_ansi + (test_case->total_buf_len - CANARY_BYTES), CANARY_BYTES, test_msg_buf);
|
||||
TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(0, (uint16_t *)test_case->buf.p_asm + (test_case->total_buf_len - CANARY_BYTES), CANARY_BYTES, test_msg_buf);
|
||||
}
|
||||
|
||||
static void test_eval_24bit_data(func_test_case_params_t *test_case)
|
||||
{
|
||||
// Print results, 24bit data
|
||||
#if DBG_PRINT_OUTPUT
|
||||
size_t data_type_size = test_case->data_type_size;
|
||||
for (uint32_t i = 0; i < test_case->total_buf_len; i++) {
|
||||
uint32_t ansi_value = ((uint8_t *)test_case->buf.p_ansi)[i * data_type_size]
|
||||
| (((uint8_t *)test_case->buf.p_ansi)[i * data_type_size + 1] << 8)
|
||||
| (((uint8_t *)test_case->buf.p_ansi)[i * data_type_size + 2] << 16);
|
||||
uint32_t asm_value = ((uint8_t *)test_case->buf.p_asm)[i * data_type_size]
|
||||
| (((uint8_t *)test_case->buf.p_asm)[i * data_type_size + 1] << 8)
|
||||
| (((uint8_t *)test_case->buf.p_asm)[i * data_type_size + 2] << 16);
|
||||
printf("dest_buf[%"PRIi32"] %s ansi = %8"PRIx32" \t asm = %8"PRIx32" \n", i, ((i < 10) ? (" ") : ("")), ansi_value, asm_value);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
const int canary_bytes_area = CANARY_BYTES * test_case->data_type_size;
|
||||
|
||||
// Canary bytes area must stay 0
|
||||
TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(0, (uint8_t *)test_case->buf.p_ansi, canary_bytes_area, test_msg_buf);
|
||||
TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(0, (uint8_t *)test_case->buf.p_asm, canary_bytes_area, test_msg_buf);
|
||||
|
||||
// dest_buf_asm and dest_buf_ansi must be equal
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY_MESSAGE((uint8_t *)test_case->buf.p_asm + canary_bytes_area, (uint8_t *)test_case->buf.p_ansi + canary_bytes_area, test_case->active_buf_len * test_case->data_type_size, test_msg_buf);
|
||||
|
||||
// Canary bytes area must stay 0
|
||||
TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(0, (uint8_t *)test_case->buf.p_ansi + (test_case->total_buf_len - CANARY_BYTES) * test_case->data_type_size, canary_bytes_area, test_msg_buf);
|
||||
TEST_ASSERT_EACH_EQUAL_UINT8_MESSAGE(0, (uint8_t *)test_case->buf.p_asm + (test_case->total_buf_len - CANARY_BYTES) * test_case->data_type_size, canary_bytes_area, test_msg_buf);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <sdkconfig.h>
|
||||
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h" // for xthal_get_ccount()
|
||||
#include "lv_image_common.h"
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_draw_sw_blend_to_rgb565.h"
|
||||
|
||||
#define COMMON_DIM 128 // Common matrix dimension 128x128 pixels
|
||||
#define WIDTH COMMON_DIM
|
||||
#define HEIGHT COMMON_DIM
|
||||
#define STRIDE WIDTH
|
||||
#define UNALIGN_BYTES 3
|
||||
#define BENCHMARK_CYCLES 1000
|
||||
|
||||
// ------------------------------------------------ Static variables ---------------------------------------------------
|
||||
|
||||
static const char *TAG_LV_IMAGE_BENCH = "LV Image Benchmark";
|
||||
static const char *asm_ansi_func[] = {"ASM", "ANSI"};
|
||||
|
||||
// ------------------------------------------------ Static function headers --------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Initialize the benchmark test
|
||||
*/
|
||||
static void lv_image_benchmark_init(bench_test_case_lv_image_params_t *test_params);
|
||||
|
||||
/**
|
||||
* @brief Run the benchmark test
|
||||
*/
|
||||
static float lv_image_benchmark_run(bench_test_case_lv_image_params_t *test_params, _lv_draw_sw_blend_image_dsc_t *dsc);
|
||||
|
||||
// ------------------------------------------------ Test cases ---------------------------------------------------------
|
||||
|
||||
/*
|
||||
Benchmark tests
|
||||
|
||||
Requires:
|
||||
- To pass functionality tests first
|
||||
|
||||
Purpose:
|
||||
- Test that an acceleration is achieved by an assembly implementation of LVGL blending API
|
||||
|
||||
Procedure:
|
||||
- Initialize input parameters (test array length, width, allocate array...) of the benchmark test
|
||||
- Run assembly version of LVGL blending API multiple times (1000-times or so)
|
||||
- Firstly use an input test parameters for the most ideal case (16-byte aligned arrays, arrays widths divisible by 2 for RGB565 color format)
|
||||
- Then use worst-case input test parameters (1-byte aligned arrays, arrays width NOT divisible by 2 for RGB565 color format)
|
||||
- Count how many CPU cycles does it take to run a function from the LVGL blending API for each case (ideal and worst case)
|
||||
- Run ansi version of LVGL blending API multiple times (1000-times or so) and repeat the 2 above steps for the ansi version
|
||||
- Compare the results
|
||||
- Free test arrays and structures needed for LVGL blending API
|
||||
|
||||
Inducing Most ideal and worst case scenarios:
|
||||
- Most ideal:
|
||||
- Both, the source and the destination buffers should be aligned by 16-byte (Xtensa PIE), or 4-byte (Xtensa base) boundaries
|
||||
- Matrix width (in pixels) should be equal to the main loop length in the assembly src code
|
||||
typically multiples of 16 bytes (for RGB565 it's either 32 bytes - 16 pixels or 48 bytes - 24 pixels)
|
||||
- Matrix height does not have any effect on benchmark unit tests, unit the matrix is too large that cache limitations start to affect the performance
|
||||
- Matrix strides, should be equal to the matrix widths (0 matrix padding), or their multiples (matrix width = matrix padding)
|
||||
- Worst case:
|
||||
- Both, hte source and the destination buffers should NOT be aligned by 16-byte (Xtensa PIE), or 4-byte (Xtensa base) boundaries,
|
||||
Source buffer unalignment should be different from the destination unalignment, with one unalignment being even, the other being odd
|
||||
The unalignments shall be small numbers (preferably 1 or 2 bytes)
|
||||
- Matrix width should be one pixels smaller, than the matrix width for the most ideal case
|
||||
- Matrix height does not have any effect on benchmark unit tests, unit the matrix is too large that cache limitations start to affect the performance
|
||||
- Matrix strides, should NOT be equal to the matrix widths (non 0 matrix padding)
|
||||
*/
|
||||
// ------------------------------------------------ Test cases stages --------------------------------------------------
|
||||
|
||||
TEST_CASE("LV Image benchmark RGB565 blend to RGB565", "[image][benchmark][RGB565]")
|
||||
{
|
||||
uint16_t *dest_array_align16 = (uint16_t *)memalign(16, STRIDE * HEIGHT * sizeof(uint16_t) + UNALIGN_BYTES);
|
||||
uint16_t *src_array_align16 = (uint16_t *)memalign(16, STRIDE * HEIGHT * sizeof(uint16_t) + UNALIGN_BYTES);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, dest_array_align16);
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, src_array_align16);
|
||||
|
||||
// Apply byte unalignment (different for each array) for the worst-case test scenario
|
||||
uint16_t *dest_array_align1 = (uint16_t *)((uint8_t *)dest_array_align16 + UNALIGN_BYTES - 1);
|
||||
uint16_t *src_array_align1 = (uint16_t *)((uint8_t *)src_array_align16 + UNALIGN_BYTES);
|
||||
|
||||
bench_test_case_lv_image_params_t test_params = {
|
||||
.height = HEIGHT,
|
||||
.width = WIDTH,
|
||||
.dest_stride = STRIDE * sizeof(uint16_t),
|
||||
.src_stride = STRIDE * sizeof(uint16_t),
|
||||
.cc_height = HEIGHT,
|
||||
.cc_width = WIDTH - 1,
|
||||
.benchmark_cycles = BENCHMARK_CYCLES,
|
||||
.src_array_align16 = (void *)src_array_align16,
|
||||
.src_array_align1 = (void *)src_array_align1,
|
||||
.dest_array_align16 = (void *)dest_array_align16,
|
||||
.dest_array_align1 = (void *)dest_array_align1,
|
||||
.blend_api_func = &lv_draw_sw_blend_image_to_rgb565,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG_LV_IMAGE_BENCH, "running test for RGB565 color format");
|
||||
lv_image_benchmark_init(&test_params);
|
||||
free(dest_array_align16);
|
||||
free(src_array_align16);
|
||||
}
|
||||
// ------------------------------------------------ Static test functions ----------------------------------------------
|
||||
|
||||
static void lv_image_benchmark_init(bench_test_case_lv_image_params_t *test_params)
|
||||
{
|
||||
// Init structure for LVGL blend API, to call the Assembly API
|
||||
_lv_draw_sw_blend_image_dsc_t dsc = {
|
||||
.dest_buf = test_params->dest_array_align16,
|
||||
.dest_w = test_params->width,
|
||||
.dest_h = test_params->height,
|
||||
.dest_stride = test_params->dest_stride, // stride * sizeof()
|
||||
.mask_buf = NULL,
|
||||
.src_buf = test_params->src_array_align16,
|
||||
.src_stride = test_params->src_stride,
|
||||
.src_color_format = LV_COLOR_FORMAT_RGB565,
|
||||
.opa = LV_OPA_MAX,
|
||||
.blend_mode = LV_BLEND_MODE_NORMAL,
|
||||
.use_asm = true,
|
||||
};
|
||||
|
||||
// Init structure for LVGL blend API, to call the ANSI API
|
||||
_lv_draw_sw_blend_image_dsc_t dsc_cc = dsc;
|
||||
dsc_cc.dest_buf = test_params->dest_array_align1;
|
||||
dsc_cc.dest_w = test_params->cc_width;
|
||||
dsc_cc.dest_h = test_params->cc_height;
|
||||
dsc_cc.src_buf = test_params->src_array_align1;
|
||||
|
||||
// Run benchmark 2 times:
|
||||
// First run using assembly, second run using ANSI
|
||||
for (int i = 0; i < 2; i++) {
|
||||
|
||||
// Run benchmark with the most ideal input parameters
|
||||
float cycles = lv_image_benchmark_run(test_params, &dsc); // Call Benchmark cycle
|
||||
float per_sample = cycles / ((float)(dsc.dest_w * dsc.dest_h));
|
||||
ESP_LOGI(TAG_LV_IMAGE_BENCH, " %s ideal case: %.3f cycles for %"PRIi32"x%"PRIi32" matrix, %.3f cycles per sample", asm_ansi_func[i], cycles, dsc.dest_w, dsc.dest_h, per_sample);
|
||||
|
||||
// Run benchmark with the corner case input parameters
|
||||
cycles = lv_image_benchmark_run(test_params, &dsc_cc); // Call Benchmark cycle
|
||||
per_sample = cycles / ((float)(dsc_cc.dest_w * dsc_cc.dest_h));
|
||||
ESP_LOGI(TAG_LV_IMAGE_BENCH, " %s corner case: %.3f cycles for %"PRIi32"x%"PRIi32" matrix, %.3f cycles per sample\n", asm_ansi_func[i], cycles, dsc_cc.dest_w, dsc_cc.dest_h, per_sample);
|
||||
|
||||
// change to ANSI
|
||||
dsc.use_asm = false;
|
||||
dsc_cc.use_asm = false;
|
||||
}
|
||||
}
|
||||
|
||||
static float lv_image_benchmark_run(bench_test_case_lv_image_params_t *test_params, _lv_draw_sw_blend_image_dsc_t *dsc)
|
||||
{
|
||||
// Call the DUT function for the first time to init the benchmark test
|
||||
test_params->blend_api_func(dsc);
|
||||
|
||||
const unsigned int start_b = xthal_get_ccount();
|
||||
for (int i = 0; i < test_params->benchmark_cycles; i++) {
|
||||
test_params->blend_api_func(dsc);
|
||||
}
|
||||
const unsigned int end_b = xthal_get_ccount();
|
||||
|
||||
const float total_b = end_b - start_b;
|
||||
const float cycles = total_b / (test_params->benchmark_cycles);
|
||||
return cycles;
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "lv_image_common.h"
|
||||
#include "lv_draw_sw_blend.h"
|
||||
#include "lv_draw_sw_blend_to_rgb565.h"
|
||||
|
||||
// ------------------------------------------------- Defines -----------------------------------------------------------
|
||||
|
||||
#define DBG_PRINT_OUTPUT false
|
||||
|
||||
// ------------------------------------------------- Macros and Types --------------------------------------------------
|
||||
|
||||
#define UPDATE_TEST_CASE(test_case_ptr, dest_w, dest_h, src_stride, dest_stride, src_unalign_byte, dest_unalign_byte) ({ \
|
||||
(test_case_ptr)->src_buf_len = (size_t)(dest_h * src_stride); \
|
||||
(test_case_ptr)->active_dest_buf_len = (size_t)(dest_h * dest_stride); \
|
||||
(test_case_ptr)->total_dest_buf_len = (size_t)((dest_h * dest_stride) + (test_case_ptr->canary_pixels * 2)); \
|
||||
(test_case_ptr)->dest_w = (dest_w); \
|
||||
(test_case_ptr)->dest_h = (dest_h); \
|
||||
(test_case_ptr)->src_stride = (src_stride); \
|
||||
(test_case_ptr)->dest_stride = (dest_stride); \
|
||||
(test_case_ptr)->src_unalign_byte = (src_unalign_byte); \
|
||||
(test_case_ptr)->dest_unalign_byte = (dest_unalign_byte); \
|
||||
})
|
||||
|
||||
// ------------------------------------------------ Static variables ---------------------------------------------------
|
||||
|
||||
static const char *TAG_LV_IMAGE_FUNC = "LV Image Functionality";
|
||||
static char test_msg_buf[200];
|
||||
|
||||
static const test_matrix_lv_image_params_t default_test_matrix_image_rgb565_blend_rgb565 = {
|
||||
#if CONFIG_IDF_TARGET_ESP32S3
|
||||
.min_w = 8, // 8 is the lower limit for the esp32s3 asm implementation, otherwise esp32 is executed
|
||||
.min_h = 1,
|
||||
.max_w = 24,
|
||||
.max_h = 2,
|
||||
.src_max_unalign_byte = 16, // Use 16-byte boundary check for Xtensa PIE
|
||||
.dest_max_unalign_byte = 16,
|
||||
.dest_unalign_step = 1, // Step 1 as the destination array is being aligned in the assembly code all the time
|
||||
.src_unalign_step = 3, // Step 3 (more relaxed) as source array is used unaligned in the assembly code
|
||||
.src_stride_step = 3,
|
||||
.dest_stride_step = 3,
|
||||
#else
|
||||
.min_w = 1,
|
||||
.min_h = 1,
|
||||
.max_w = 16,
|
||||
.max_h = 2,
|
||||
.src_max_unalign_byte = 4, // Use 4-byte boundary check for Xtensa base
|
||||
.dest_max_unalign_byte = 4,
|
||||
.dest_unalign_step = 1,
|
||||
.src_unalign_step = 1,
|
||||
.src_stride_step = 1,
|
||||
.dest_stride_step = 1,
|
||||
#endif
|
||||
.src_min_unalign_byte = 0,
|
||||
.dest_min_unalign_byte = 0,
|
||||
.test_combinations_count = 0,
|
||||
};
|
||||
|
||||
// ------------------------------------------------ Static function headers --------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Generate all the functionality test combinations
|
||||
*
|
||||
* - generate functionality test combinations, based on the provided test_matrix struct
|
||||
*
|
||||
* @param[in] test_matrix Pointer to structure defining test matrix - all the test combinations
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
*/
|
||||
static void functionality_test_matrix(test_matrix_lv_image_params_t *test_matrix, func_test_case_lv_image_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief Fill test buffers for image functionality test
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
*/
|
||||
static void fill_test_bufs(func_test_case_lv_image_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief The actual functionality test
|
||||
*
|
||||
* - function prepares structures for functionality testing and runs the LVGL API
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
*/
|
||||
static void lv_image_functionality(func_test_case_lv_image_params_t *test_case);
|
||||
|
||||
/**
|
||||
* @brief Evaluate results of LV Image functionality for 16bit data length
|
||||
*
|
||||
* @param[in] test_case Pointer ot structure defining functionality test case
|
||||
*/
|
||||
static void test_eval_image_16bit_data(func_test_case_lv_image_params_t *test_case);
|
||||
|
||||
// ------------------------------------------------ Test cases ---------------------------------------------------------
|
||||
|
||||
/*
|
||||
Functionality tests
|
||||
|
||||
Purpose:
|
||||
- Test that an assembly version of LVGL blending API achieves the same results as the ANSI version
|
||||
|
||||
Procedure:
|
||||
- Prepare testing matrix, to cover all the possible combinations of destination and source arrays widths,
|
||||
lengths, strides and memory alignments
|
||||
- Run assembly version of the LVGL blending API
|
||||
- Run ANSI C version of the LVGL blending API
|
||||
- Compare the results
|
||||
- Repeat above 3 steps for each test matrix setup
|
||||
*/
|
||||
|
||||
// ------------------------------------------------ Test cases stages --------------------------------------------------
|
||||
|
||||
TEST_CASE("LV Image functionality RGB565 blend to RGB565", "[image][functionality][RGB565]")
|
||||
{
|
||||
test_matrix_lv_image_params_t test_matrix = default_test_matrix_image_rgb565_blend_rgb565;
|
||||
|
||||
func_test_case_lv_image_params_t test_case = {
|
||||
.blend_api_func = &lv_draw_sw_blend_image_to_rgb565,
|
||||
.color_format = LV_COLOR_FORMAT_RGB565,
|
||||
.canary_pixels = CANARY_PIXELS_RGB565,
|
||||
.src_data_type_size = sizeof(uint16_t),
|
||||
.dest_data_type_size = sizeof(uint16_t),
|
||||
.operation_type = OPERATION_FILL,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG_LV_IMAGE_FUNC, "running test for RGB565 color format");
|
||||
functionality_test_matrix(&test_matrix, &test_case);
|
||||
}
|
||||
|
||||
// ------------------------------------------------ Static test functions ----------------------------------------------
|
||||
|
||||
static void functionality_test_matrix(test_matrix_lv_image_params_t *test_matrix, func_test_case_lv_image_params_t *test_case)
|
||||
{
|
||||
// Step destination array width
|
||||
for (int dest_w = test_matrix->min_w; dest_w <= test_matrix->max_w; dest_w++) {
|
||||
|
||||
// Step destination array height
|
||||
for (int dest_h = test_matrix->min_h; dest_h <= test_matrix->max_h; dest_h++) {
|
||||
|
||||
// Step source array stride
|
||||
for (int src_stride = dest_w; src_stride <= dest_w * 2; src_stride += test_matrix->src_stride_step) {
|
||||
|
||||
// Step destination array stride
|
||||
for (int dest_stride = dest_w; dest_stride <= dest_w * 2; dest_stride += test_matrix->dest_stride_step) {
|
||||
|
||||
// Step source array unalignment
|
||||
for (int src_unalign_byte = test_matrix->src_min_unalign_byte; src_unalign_byte <= test_matrix->src_max_unalign_byte; src_unalign_byte += test_matrix->src_unalign_step) {
|
||||
|
||||
// Step destination array unalignment
|
||||
for (int dest_unalign_byte = test_matrix->dest_min_unalign_byte; dest_unalign_byte <= test_matrix->dest_max_unalign_byte; dest_unalign_byte += test_matrix->dest_unalign_step) {
|
||||
|
||||
// Call functionality test
|
||||
UPDATE_TEST_CASE(test_case, dest_w, dest_h, src_stride, dest_stride, src_unalign_byte, dest_unalign_byte);
|
||||
lv_image_functionality(test_case);
|
||||
test_matrix->test_combinations_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG_LV_IMAGE_FUNC, "test combinations: %d\n", test_matrix->test_combinations_count);
|
||||
}
|
||||
|
||||
static void lv_image_functionality(func_test_case_lv_image_params_t *test_case)
|
||||
{
|
||||
fill_test_bufs(test_case);
|
||||
|
||||
_lv_draw_sw_blend_image_dsc_t dsc_asm = {
|
||||
.dest_buf = test_case->buf.p_dest_asm,
|
||||
.dest_w = test_case->dest_w,
|
||||
.dest_h = test_case->dest_h,
|
||||
.dest_stride = test_case->dest_stride * test_case->dest_data_type_size, // dest_stride * sizeof(data_type)
|
||||
.mask_buf = NULL,
|
||||
.mask_stride = 0,
|
||||
.src_buf = test_case->buf.p_src,
|
||||
.src_stride = test_case->src_stride * test_case->src_data_type_size, // src_stride * sizeof(data_type)
|
||||
.src_color_format = test_case->color_format,
|
||||
.opa = LV_OPA_MAX,
|
||||
.blend_mode = LV_BLEND_MODE_NORMAL,
|
||||
.use_asm = true,
|
||||
};
|
||||
|
||||
// Init structure for LVGL blend API, to call the ANSI API
|
||||
_lv_draw_sw_blend_image_dsc_t dsc_ansi = dsc_asm;
|
||||
dsc_ansi.dest_buf = test_case->buf.p_dest_ansi;
|
||||
dsc_ansi.use_asm = false;
|
||||
|
||||
test_case->blend_api_func(&dsc_asm); // Call the LVGL API with Assembly code
|
||||
test_case->blend_api_func(&dsc_ansi); // Call the LVGL API with ANSI code
|
||||
|
||||
// Shift array pointers by (Canary pixels amount * data type length) back
|
||||
test_case->buf.p_dest_asm -= test_case->canary_pixels * test_case->dest_data_type_size;
|
||||
test_case->buf.p_dest_ansi -= test_case->canary_pixels * test_case->dest_data_type_size;
|
||||
|
||||
// Evaluate the results
|
||||
sprintf(test_msg_buf, "Test case: dest_w = %d, dest_h = %d, dest_stride = %d, src_stride = %d, dest_unalign_byte = %d, src_unalign_byte = %d\n",
|
||||
test_case->dest_w, test_case->dest_h, test_case->dest_stride, test_case->src_stride, test_case->dest_unalign_byte, test_case->src_unalign_byte);
|
||||
#if DBG_PRINT_OUTPUT
|
||||
printf("%s\n", test_msg_buf);
|
||||
#endif
|
||||
switch (test_case->color_format) {
|
||||
case LV_COLOR_FORMAT_RGB565:
|
||||
test_eval_image_16bit_data(test_case);
|
||||
break;
|
||||
default:
|
||||
TEST_ASSERT_MESSAGE(false, "LV Color format not found");
|
||||
break;
|
||||
}
|
||||
|
||||
// Free memory allocated for test buffers
|
||||
free(test_case->buf.p_dest_asm_alloc);
|
||||
free(test_case->buf.p_dest_ansi_alloc);
|
||||
free(test_case->buf.p_src_alloc);
|
||||
}
|
||||
|
||||
static void fill_test_bufs(func_test_case_lv_image_params_t *test_case)
|
||||
{
|
||||
const size_t src_data_type_size = test_case->src_data_type_size; // sizeof() of used data type in the source buffer
|
||||
const size_t dest_data_type_size = test_case->dest_data_type_size; // sizeof() of used data type in the destination buffer
|
||||
const size_t src_buf_len = test_case->src_buf_len; // Total source buffer length, data part of the source buffer including matrix padding (no Canary pixels are used for source buffer)
|
||||
const size_t total_dest_buf_len = test_case->total_dest_buf_len; // Total destination buffer length, data part of the destination buffer including the Canary pixels and matrix padding
|
||||
const size_t active_dest_buf_len = test_case->active_dest_buf_len; // Length of the data part of the destination buffer including matrix padding
|
||||
const size_t canary_pixels = test_case->canary_pixels; // Canary pixels, according to the data type
|
||||
const unsigned int src_unalign_byte = test_case->src_unalign_byte; // Unalignment bytes for source buffer
|
||||
const unsigned int dest_unalign_byte = test_case->dest_unalign_byte; // Unalignment bytes for destination buffer
|
||||
|
||||
// Allocate destination arrays and source array for Assembly and ANSI LVGL Blend API
|
||||
void *src_mem_common = memalign(16, (src_buf_len * src_data_type_size) + src_unalign_byte);
|
||||
void *dest_mem_asm = memalign(16, (total_dest_buf_len * dest_data_type_size) + dest_unalign_byte);
|
||||
void *dest_mem_ansi = memalign(16, (total_dest_buf_len * dest_data_type_size) + dest_unalign_byte);
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(src_mem_common, "Lack of memory");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(dest_mem_asm, "Lack of memory");
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(dest_mem_ansi, "Lack of memory");
|
||||
|
||||
// Save a pointer to the beginning of the allocated memory which will be used to free()
|
||||
test_case->buf.p_src_alloc = src_mem_common;
|
||||
test_case->buf.p_dest_asm_alloc = dest_mem_asm;
|
||||
test_case->buf.p_dest_ansi_alloc = dest_mem_ansi;
|
||||
|
||||
// Apply destination and source array unalignment
|
||||
uint8_t *src_buf_common = (uint8_t *)src_mem_common + src_unalign_byte;
|
||||
uint8_t *dest_buf_asm = (uint8_t *)dest_mem_asm + dest_unalign_byte;
|
||||
uint8_t *dest_buf_ansi = (uint8_t *)dest_mem_ansi + dest_unalign_byte;
|
||||
|
||||
// Set the whole buffer to 0, including the Canary pixels part
|
||||
memset(src_buf_common, 0, src_buf_len * src_data_type_size);
|
||||
memset(dest_buf_asm, 0, total_dest_buf_len * src_data_type_size);
|
||||
memset(dest_buf_ansi, 0, total_dest_buf_len * src_data_type_size);
|
||||
|
||||
switch (test_case->operation_type) {
|
||||
case OPERATION_FILL:
|
||||
// Fill the actual part of the destination buffers with known values,
|
||||
// Values must be same, because of the stride
|
||||
|
||||
if (test_case->color_format == LV_COLOR_FORMAT_RGB565) {
|
||||
uint16_t *dest_buf_asm_uint16 = (uint16_t *)dest_buf_asm;
|
||||
uint16_t *dest_buf_ansi_uint16 = (uint16_t *)dest_buf_ansi;
|
||||
uint16_t *src_buf_uint16 = (uint16_t *)src_buf_common;
|
||||
|
||||
// Fill destination buffers
|
||||
for (int i = 0; i < active_dest_buf_len; i++) {
|
||||
dest_buf_asm_uint16[canary_pixels + i] = i + ((i & 1) ? 0x6699 : 0x9966);
|
||||
dest_buf_ansi_uint16[canary_pixels + i] = dest_buf_asm_uint16[canary_pixels + i];
|
||||
}
|
||||
|
||||
// Fill source buffer
|
||||
for (int i = 0; i < src_buf_len; i++) {
|
||||
src_buf_uint16[i] = i + ((i & 1) ? 0x55AA : 0xAA55);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
TEST_ASSERT_MESSAGE(false, "LV Operation not found");
|
||||
break;
|
||||
}
|
||||
|
||||
// Shift array pointers by (Canary pixels amount * data type length) forward
|
||||
dest_buf_asm += canary_pixels * dest_data_type_size;
|
||||
dest_buf_ansi += canary_pixels * dest_data_type_size;
|
||||
|
||||
// Save a pointer to the working part of the memory, where the test data are stored
|
||||
test_case->buf.p_src = (void *)src_buf_common;
|
||||
test_case->buf.p_dest_asm = (void *)dest_buf_asm;
|
||||
test_case->buf.p_dest_ansi = (void *)dest_buf_ansi;
|
||||
|
||||
#if DBG_PRINT_OUTPUT
|
||||
printf("Destination buffers fill:\n");
|
||||
for (uint32_t i = 0; i < test_case->active_dest_buf_len; i++) {
|
||||
printf("dest_buf[%"PRIi32"] %s ansi = %8"PRIx16" \t asm = %8"PRIx16" \n", i, ((i < 10) ? (" ") : ("")), ((uint16_t *)test_case->buf.p_dest_ansi)[i], ((uint16_t *)test_case->buf.p_dest_asm)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Source buffer fill:\n");
|
||||
for (uint32_t i = 0; i < test_case->src_buf_len; i++) {
|
||||
printf("src_buf[%"PRIi32"] %s = %8"PRIx16" \n", i, ((i < 10) ? (" ") : ("")), ((uint16_t *)test_case->buf.p_src)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static void test_eval_image_16bit_data(func_test_case_lv_image_params_t *test_case)
|
||||
{
|
||||
// Print results, 16bit data
|
||||
#if DBG_PRINT_OUTPUT
|
||||
printf("\nEval\nDestination buffers fill:\n");
|
||||
for (uint32_t i = 0; i < test_case->total_dest_buf_len; i++) {
|
||||
printf("dest_buf[%"PRIi32"] %s ansi = %8"PRIx16" \t asm = %8"PRIx16" %s \n", i, ((i < 10) ? (" ") : ("")), ((uint16_t *)test_case->buf.p_dest_ansi)[i], ((uint16_t *)test_case->buf.p_dest_asm)[i], (((uint16_t *)test_case->buf.p_dest_ansi)[i] == ((uint16_t *)test_case->buf.p_dest_asm)[i]) ? ("OK") : ("FAIL"));
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Source buffer fill:\n");
|
||||
for (uint32_t i = 0; i < test_case->src_buf_len; i++) {
|
||||
printf("src_buf[%"PRIi32"] %s = %8"PRIx16" \n", i, ((i < 10) ? (" ") : ("")), ((uint16_t *)test_case->buf.p_src)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
// Canary pixels area must stay 0
|
||||
const size_t canary_pixels = test_case->canary_pixels;
|
||||
TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(0, (uint16_t *)test_case->buf.p_dest_ansi, canary_pixels, test_msg_buf);
|
||||
TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(0, (uint16_t *)test_case->buf.p_dest_asm, canary_pixels, test_msg_buf);
|
||||
|
||||
// dest_buf_asm and dest_buf_ansi must be equal
|
||||
TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE((uint16_t *)test_case->buf.p_dest_ansi + canary_pixels, (uint16_t *)test_case->buf.p_dest_asm + canary_pixels, test_case->active_dest_buf_len, test_msg_buf);
|
||||
|
||||
// Data part of the destination buffer and source buffer (not considering matrix padding) must be equal
|
||||
uint16_t *dest_row_begin = (uint16_t *)test_case->buf.p_dest_asm + canary_pixels;
|
||||
uint16_t *src_row_begin = (uint16_t *)test_case->buf.p_src;
|
||||
for (int row = 0; row < test_case->dest_h; row++) {
|
||||
TEST_ASSERT_EQUAL_UINT16_ARRAY_MESSAGE(dest_row_begin, src_row_begin, test_case->dest_w, test_msg_buf);
|
||||
dest_row_begin += test_case->dest_stride; // Move pointer of the destination buffer to the next row
|
||||
src_row_begin += test_case->src_stride; // Move pointer of the source buffer to the next row
|
||||
}
|
||||
|
||||
// Canary pixels area must stay 0
|
||||
TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(0, (uint16_t *)test_case->buf.p_dest_ansi + (test_case->total_dest_buf_len - canary_pixels), canary_pixels, test_msg_buf);
|
||||
TEST_ASSERT_EACH_EQUAL_UINT16_MESSAGE(0, (uint16_t *)test_case->buf.p_dest_asm + (test_case->total_dest_buf_len - canary_pixels), canary_pixels, test_msg_buf);
|
||||
}
|
||||
Reference in New Issue
Block a user