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 Sep 5, 2024
1 parent 7e2be83 commit 85906eb
Show file tree
Hide file tree
Showing 35 changed files with 4,219 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
21 changes: 21 additions & 0 deletions components/esp_lvgl_port/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,27 @@ if("usb_host_hid" IN_LIST build_components)
list(APPEND ADD_LIBS idf::usb_host_hid)
endif()

# Include SIMD assembly source code for rendering, only for LVGL 9.x and only for esp32 and esp32s3
if(lvgl_ver VERSION_GREATER_EQUAL "9.0.0")
if(CONFIG_IDF_TARGET_ESP32 OR CONFIG_IDF_TARGET_ESP32S3)
message(VERBOSE "Compiling SIMD")
if(CONFIG_IDF_TARGET_ESP32S3)
file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32s3.S) # Select only esp32s3 related files
else()
file(GLOB_RECURSE ASM_SRCS ${PORT_PATH}/simd/*_esp32.S) # Select only esp32 related files
endif()
list(APPEND ADD_SRCS ${ASM_SRCS})

# Include component libraries, so lvgl component would see lvgl_port includes
idf_component_get_property(lvgl_lib ${lvgl_name} COMPONENT_LIB)
target_include_directories(${lvgl_lib} PRIVATE "include")

# Force link .S files
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_argb8888_esp")
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u lv_color_blend_to_rgb565_esp")
endif()
endif()

# Here we create the real lvgl_port_lib
add_library(lvgl_port_lib STATIC
${PORT_PATH}/esp_lvgl_port.c
Expand Down
92 changes: 92 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,92 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#ifdef __cplusplus
extern "C" {
#endif

#include "lvgl.h"

/*********************
* INCLUDES
*********************/

#if !CONFIG_LV_DRAW_SW_ASM_CUSTOM
#warning "esp_lvgl_port_lv_blend.h included, but CONFIG_LV_DRAW_SW_ASM_CUSTOM not set. Assembly rendering not used"
#else

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

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

#ifndef LV_DRAW_SW_COLOR_BLEND_TO_RGB565
#define LV_DRAW_SW_COLOR_BLEND_TO_RGB565(dsc) \
_lv_color_blend_to_rgb565_esp(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;

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

extern int lv_color_blend_to_argb8888_esp(asm_dsc_t *asm_dsc);

static inline lv_result_t _lv_color_blend_to_argb8888_esp(lv_draw_sw_blend_fill_dsc_t *dsc)
{
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,
};

return lv_color_blend_to_argb8888_esp(&asm_dsc);
}

extern int lv_color_blend_to_rgb565_esp(asm_dsc_t *asm_dsc);

static inline lv_result_t _lv_color_blend_to_rgb565_esp(lv_draw_sw_blend_fill_dsc_t *dsc)
{
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,
};

return lv_color_blend_to_rgb565_esp(&asm_dsc);
}

#endif // CONFIG_LV_DRAW_SW_ASM_CUSTOM

#ifdef __cplusplus
} /*extern "C"*/
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

// This is LVGL ARGB8888 simple fill for ESP32 processor

.section .text
.align 4
.global lv_color_blend_to_argb8888_esp
.type lv_color_blend_to_argb8888_esp,@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_esp:

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

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 85906eb

Please sign in to comment.