Skip to content

Commit

Permalink
feature(lvgl_port): Initial support for SIMD rendering in LVGL
Browse files Browse the repository at this point in the history
    - Assembly source files for LVGL blend API integrated into lvgl_port
    - Initial assembly assembly implementation of:
        - ARGB8888 simple fill for esp32s3 and esp32
        - RGB565 simple fill for esp32
    - Functionality and benchmark test app
  • Loading branch information
peter-marcisovsky committed Jul 31, 2024
1 parent 7f12e73 commit 61b3433
Show file tree
Hide file tree
Showing 20 changed files with 1,697 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ dependencies.lock
doxygen_output/**
dist
__pycache__
gdbinit
13 changes: 11 additions & 2 deletions components/esp_lvgl_port/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,21 @@ endif()

set(PORT_PATH "src/${PORT_FOLDER}")

# Include SIMD assembly source code for rendering
if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3)
if (lvgl_ver VERSION_GREATER_EQUAL "9.0.0")
message(VERBOSE "Compiling SIMD")
file(GLOB_RECURSE ASM_SOURCES ${PORT_PATH}/simd/*.S)
endif()
endif()

idf_component_register(
SRCS "${PORT_PATH}/esp_lvgl_port.c" "${PORT_PATH}/esp_lvgl_port_disp.c"
SRCS "${PORT_PATH}/esp_lvgl_port.c" "${PORT_PATH}/esp_lvgl_port_disp.c" ${ASM_SOURCES}
INCLUDE_DIRS "include"
PRIV_INCLUDE_DIRS "priv_include"
REQUIRES "esp_lcd"
PRIV_REQUIRES "esp_timer")
PRIV_REQUIRES "esp_timer"
WHOLE_ARCHIVE)

set(ADD_SRCS "")
set(ADD_LIBS "")
Expand Down
131 changes: 131 additions & 0 deletions components/esp_lvgl_port/include/esp_lvgl_port_lv_blend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

/*********************
* INCLUDES
*********************/
#include "esp_log.h"
#include <sdkconfig.h>
#include "lvgl.h"
#include "lv_conf_internal.h"

#if CONFIG_LV_DRAW_SW_ASM_CUSTOM

/*********************
* DEFINES
*********************/

#ifndef LV_DRAW_SW_COLOR_BLEND_TO_ARGB8888
#define LV_DRAW_SW_COLOR_BLEND_TO_ARGB8888(dsc) \
_lv_color_blend_to_argb8888_esp32(dsc)
#endif

#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB565
#define LV_DRAW_SW_COLOR_BLEND_TO_RGB565(dsc) \
_lv_color_blend_to_rgb565_esp32(dsc)
#endif


/**********************
* TYPEDEFS
**********************/

typedef struct {
uint32_t opa;
void *dst_buf;
uint32_t dst_w;
uint32_t dst_h;
uint32_t dst_stride;
const void *src_buf;
uint32_t src_stride;
const lv_opa_t *mask_buf;
uint32_t mask_stride;
} asm_dsc_t;

/**********************
* STATIC VARIABLES
**********************/

static const char *TAG_LV_BLEND = "LVGL_PORT_LV_BLEND";

/**********************
* GLOBAL PROTOTYPES
**********************/

// Extern variable to control switching between Assembly or C implementation, for testing purposes only
extern bool LV_BLEND_USE_ASM;

extern int lv_color_blend_to_argb8888_esp32_aes3(asm_dsc_t *asm_dsc); // ESP32S3 assembly implementation
extern int lv_color_blend_to_argb8888_esp32_ae32(asm_dsc_t *asm_dsc); // ESP32 assembly implementation

static inline lv_result_t _lv_color_blend_to_argb8888_esp32(_lv_draw_sw_blend_fill_dsc_t *dsc)
{
// Check if asm variant should be used (Only for testing)
if (!LV_BLEND_USE_ASM) {
ESP_LOGD(TAG_LV_BLEND, "Calling ANSI impl. of: Simple fill ARGB8888");
return LV_RESULT_INVALID;
}

asm_dsc_t asm_dsc = {
.dst_buf = dsc->dest_buf,
.dst_w = dsc->dest_w,
.dst_h = dsc->dest_h,
.dst_stride = dsc->dest_stride,
.src_buf = &dsc->color,
};

ESP_LOGD(TAG_LV_BLEND, "Calling ASM impl. of: Simple fill ARGB8888");
#if CONFIG_IDF_TARGET_ESP32S3
return lv_color_blend_to_argb8888_esp32_aes3(&asm_dsc);
#elif (CONFIG_IDF_TARGET_ESP32)
return lv_color_blend_to_argb8888_esp32_ae32(&asm_dsc);
#else
return LV_RESULT_INVALID;
#endif
}

extern int lv_color_blend_to_rgb565_esp32_aes3(asm_dsc_t *asm_dsc); // ESP32S3 assembly implementation
extern int lv_color_blend_to_rgb565_esp32_ae32(asm_dsc_t *asm_dsc); // ESP32 assembly implementation

static inline lv_result_t _lv_color_blend_to_rgb565_esp32(_lv_draw_sw_blend_fill_dsc_t *dsc)
{
// Check if asm variant should be used (Only for testing)
if (!LV_BLEND_USE_ASM) {
ESP_LOGD(TAG_LV_BLEND, "Calling ANSI impl. of: Simple fill RGB565");
return LV_RESULT_INVALID;
}

asm_dsc_t asm_dsc = {
.dst_buf = dsc->dest_buf,
.dst_w = dsc->dest_w,
.dst_h = dsc->dest_h,
.dst_stride = dsc->dest_stride,
.src_buf = &dsc->color,
};

ESP_LOGD(TAG_LV_BLEND, "Calling ASM impl. of: Simple fill RGB565");
#if CONFIG_IDF_TARGET_ESP32S3
//return lv_color_blend_to_rgb565_esp32_aes3(&asm_dsc);
return lv_color_blend_to_rgb565_esp32_ae32(&asm_dsc); // TODO ESP32S3 assembly not yet implemented, calling esp32 version for now
// TODO asm version is slower than ANSI
#elif (CONFIG_IDF_TARGET_ESP32)
return lv_color_blend_to_rgb565_esp32_ae32(&asm_dsc);
#else
return LV_RESULT_INVALID;
#endif
}

#ifdef __cplusplus
} /*extern "C"*/
#endif

#endif // CONFIG_LV_DRAW_SW_ASM_CUSTOM
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

// This is LVGL ARGB8888 simple fill for ESP32 processor.
.text
.align 4
.global lv_color_blend_to_argb8888_esp32_ae32
.global .lv_color_blend_to_argb8888_esp32_ae32_body
.type lv_color_blend_to_argb8888_esp32_ae32,@function
// The function implements the following C code:
// void lv_color_blend_to_argb8888(_lv_draw_sw_blend_fill_dsc_t * dsc);

// Input params
//
// dsc - a2

// typedef struct {
// uint32_t opa; l32i 0
// void * dst_buf; l32i 4
// uint32_t dst_w; l32i 8
// uint32_t dst_h; l32i 12
// uint32_t dst_stride; l32i 16
// const void * src_buf; l32i 20
// uint32_t src_stride; l32i 24
// const lv_opa_t * mask_buf; l32i 28
// uint32_t mask_stride; l32i 32
// } asm_dsc_t;

lv_color_blend_to_argb8888_esp32_ae32:

entry a1, 32

l32i.n a3, a2, 4 // a3 - dest_buff
l32i.n a4, a2, 8 // a4 - dest_w in uint32_t
l32i.n a5, a2, 12 // a5 - dest_h in uint32_t
l32i.n a6, a2, 16 // a6 - dest_stride in bytes
l32i.n a7, a2, 20 // a7 - src_buff (color)
l32i.n a8, a7, 0 // a8 - color as value
slli a11, a4, 2 // a11 - dest_w_bytes = sizeof(uint32_t) * dest_w

movi a7, 0xff000000 // oppactiy mask
or a10, a7, a8 // apply oppacity

.lv_color_blend_to_argb8888_esp32_ae32_body:

srli a9, a4, 2 // a9 - loop_len = dest_w / 4
sub a6, a6, a11 // dest_stride = dest_stride - dest_w_bytes

.outer_loop:

// Run main loop which sets 16 bytes in one loop run
loopnez a9, ._main_loop
s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3
s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3
s32i.n a10, a3, 8 // save 32 bits from a10 to dest_buff a3
s32i.n a10, a3, 12 // save 32 bits from a10 to dest_buff a3
addi.n a3, a3, 16 // increment dest_buff pointer by 16 bytes
._main_loop:

// Finish the remaining bytes out of the loop
// Check modulo 8 of the dest_w_bytes, if - then set 8 bytes
bbci a11, 3, _mod_8_check // branch if 2-nd bit of dest_w_bytes is clear
s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes
s32i.n a10, a3, 4 // save 32 bits from a10 to dest_buff a3, offset 0 bytes
addi.n a3, a3, 8 // increment dest_buff pointer by 8 bytes
_mod_8_check:

// Check modulo 4 of the dest_w_bytes, if - then set 4 bytes
bbci a11, 2, _mod_4_check // branch if 2-nd bit of dest_w_bytes is clear
s32i.n a10, a3, 0 // save 32 bits from a10 to dest_buff a3, offset 0 bytes
addi.n a3, a3, 4 // increment dest_buff pointer by 4 bytes
_mod_4_check:

add a3, a3, a6 // dest_buff + dest_stride
addi.n a5, a5, -1 // decrease the outer loop
bnez a5, .outer_loop

movi.n a2, 1 // return LV_RESULT_OK = 1
retw.n // return
Loading

0 comments on commit 61b3433

Please sign in to comment.