feat(draw/sw): allow custom handlers (#7531)

This commit is contained in:
Fabian Blatz
2025-02-28 23:24:11 +01:00
committed by GitHub
parent d689dd6951
commit b201713604
8 changed files with 264 additions and 81 deletions

View File

@@ -215,6 +215,7 @@
/** Enable drawing complex gradients in software: linear at an angle, radial or conical */
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 0
#endif
/*Use TSi's aka (Think Silicon) NemaGFX */

View File

@@ -126,6 +126,7 @@ typedef struct _lv_global_t {
lv_cache_t * img_header_cache;
lv_draw_global_info_t draw_info;
lv_ll_t draw_sw_blend_handler_ll;
#if defined(LV_DRAW_SW_SHADOW_CACHE_SIZE) && LV_DRAW_SW_SHADOW_CACHE_SIZE > 0
lv_draw_sw_shadow_cache_t sw_shadow_cache;
#endif

View File

@@ -41,6 +41,14 @@
/**********************
* STATIC PROTOTYPES
**********************/
static inline void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_sw_blend_color(lv_color_format_t layer_cf,
lv_draw_sw_blend_fill_dsc_t * fill_dsc);
static inline void /* LV_ATTRIBUTE_FAST_MEM */ lv_draw_sw_blend_image(lv_color_format_t layer_cf,
lv_draw_sw_blend_image_dsc_t * image_dsc);
/**********************
* STATIC VARIABLES
**********************/
@@ -66,6 +74,13 @@ void lv_draw_sw_blend(lv_draw_task_t * t, const lv_draw_sw_blend_dsc_t * blend_d
lv_layer_t * layer = t->target_layer;
uint32_t layer_stride_byte = layer->draw_buf->header.stride;
lv_draw_sw_blend_handler_t handler = lv_draw_sw_get_blend_handler(layer->color_format);
if(handler) {
handler(t, blend_dsc);
LV_PROFILER_DRAW_END;
return;
}
if(blend_dsc->src_buf == NULL) {
lv_draw_sw_blend_fill_dsc_t fill_dsc;
fill_dsc.dest_w = lv_area_get_width(&blend_area);
@@ -90,45 +105,7 @@ void lv_draw_sw_blend(lv_draw_task_t * t, const lv_draw_sw_blend_dsc_t * blend_d
(blend_area.x1 - blend_dsc->mask_area->x1);
}
switch(layer->color_format) {
#if LV_DRAW_SW_SUPPORT_RGB565
case LV_COLOR_FORMAT_RGB565:
lv_draw_sw_blend_color_to_rgb565(&fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_ARGB8888
case LV_COLOR_FORMAT_ARGB8888:
lv_draw_sw_blend_color_to_argb8888(&fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_RGB888
case LV_COLOR_FORMAT_RGB888:
lv_draw_sw_blend_color_to_rgb888(&fill_dsc, 3);
break;
#endif
#if LV_DRAW_SW_SUPPORT_XRGB8888
case LV_COLOR_FORMAT_XRGB8888:
lv_draw_sw_blend_color_to_rgb888(&fill_dsc, 4);
break;
#endif
#if LV_DRAW_SW_SUPPORT_L8
case LV_COLOR_FORMAT_L8:
lv_draw_sw_blend_color_to_l8(&fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_AL88
case LV_COLOR_FORMAT_AL88:
lv_draw_sw_blend_color_to_al88(&fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_I1
case LV_COLOR_FORMAT_I1:
lv_draw_sw_blend_color_to_i1(&fill_dsc);
break;
#endif
default:
break;
}
lv_draw_sw_blend_color(layer->color_format, &fill_dsc);
}
else {
if(!lv_area_intersect(&blend_area, &blend_area, blend_dsc->src_area)) {
@@ -179,46 +156,7 @@ void lv_draw_sw_blend(lv_draw_task_t * t, const lv_draw_sw_blend_dsc_t * blend_d
image_dsc.dest_buf = lv_draw_layer_go_to_xy(layer, blend_area.x1 - layer->buf_area.x1,
blend_area.y1 - layer->buf_area.y1);
switch(layer->color_format) {
#if LV_DRAW_SW_SUPPORT_RGB565
case LV_COLOR_FORMAT_RGB565:
case LV_COLOR_FORMAT_RGB565A8:
lv_draw_sw_blend_image_to_rgb565(&image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_ARGB8888
case LV_COLOR_FORMAT_ARGB8888:
lv_draw_sw_blend_image_to_argb8888(&image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_RGB888
case LV_COLOR_FORMAT_RGB888:
lv_draw_sw_blend_image_to_rgb888(&image_dsc, 3);
break;
#endif
#if LV_DRAW_SW_SUPPORT_XRGB8888
case LV_COLOR_FORMAT_XRGB8888:
lv_draw_sw_blend_image_to_rgb888(&image_dsc, 4);
break;
#endif
#if LV_DRAW_SW_SUPPORT_L8
case LV_COLOR_FORMAT_L8:
lv_draw_sw_blend_image_to_l8(&image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_AL88
case LV_COLOR_FORMAT_AL88:
lv_draw_sw_blend_image_to_al88(&image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_I1
case LV_COLOR_FORMAT_I1:
lv_draw_sw_blend_image_to_i1(&image_dsc);
break;
#endif
default:
break;
}
lv_draw_sw_blend_image(layer->color_format, &image_dsc);
}
LV_PROFILER_DRAW_END;
}
@@ -227,4 +165,93 @@ void lv_draw_sw_blend(lv_draw_task_t * t, const lv_draw_sw_blend_dsc_t * blend_d
* STATIC FUNCTIONS
**********************/
static inline void LV_ATTRIBUTE_FAST_MEM lv_draw_sw_blend_color(lv_color_format_t layer_cf,
lv_draw_sw_blend_fill_dsc_t * fill_dsc)
{
switch(layer_cf) {
#if LV_DRAW_SW_SUPPORT_RGB565
case LV_COLOR_FORMAT_RGB565:
lv_draw_sw_blend_color_to_rgb565(fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_ARGB8888
case LV_COLOR_FORMAT_ARGB8888:
lv_draw_sw_blend_color_to_argb8888(fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_RGB888
case LV_COLOR_FORMAT_RGB888:
lv_draw_sw_blend_color_to_rgb888(fill_dsc, 3);
break;
#endif
#if LV_DRAW_SW_SUPPORT_XRGB8888
case LV_COLOR_FORMAT_XRGB8888:
lv_draw_sw_blend_color_to_rgb888(fill_dsc, 4);
break;
#endif
#if LV_DRAW_SW_SUPPORT_L8
case LV_COLOR_FORMAT_L8:
lv_draw_sw_blend_color_to_l8(fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_AL88
case LV_COLOR_FORMAT_AL88:
lv_draw_sw_blend_color_to_al88(fill_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_I1
case LV_COLOR_FORMAT_I1:
lv_draw_sw_blend_color_to_i1(fill_dsc);
break;
#endif
default:
break;
}
}
static inline void LV_ATTRIBUTE_FAST_MEM lv_draw_sw_blend_image(lv_color_format_t layer_cf,
lv_draw_sw_blend_image_dsc_t * image_dsc)
{
switch(layer_cf) {
#if LV_DRAW_SW_SUPPORT_RGB565
case LV_COLOR_FORMAT_RGB565:
case LV_COLOR_FORMAT_RGB565A8:
lv_draw_sw_blend_image_to_rgb565(image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_ARGB8888
case LV_COLOR_FORMAT_ARGB8888:
lv_draw_sw_blend_image_to_argb8888(image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_RGB888
case LV_COLOR_FORMAT_RGB888:
lv_draw_sw_blend_image_to_rgb888(image_dsc, 3);
break;
#endif
#if LV_DRAW_SW_SUPPORT_XRGB8888
case LV_COLOR_FORMAT_XRGB8888:
lv_draw_sw_blend_image_to_rgb888(image_dsc, 4);
break;
#endif
#if LV_DRAW_SW_SUPPORT_L8
case LV_COLOR_FORMAT_L8:
lv_draw_sw_blend_image_to_l8(image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_AL88
case LV_COLOR_FORMAT_AL88:
lv_draw_sw_blend_image_to_al88(image_dsc);
break;
#endif
#if LV_DRAW_SW_SUPPORT_I1
case LV_COLOR_FORMAT_I1:
lv_draw_sw_blend_image_to_i1(image_dsc);
break;
#endif
default:
break;
}
}
#endif

View File

@@ -32,6 +32,18 @@ extern "C" {
* GLOBAL PROTOTYPES
**********************/
/**
* Custom draw function for SW rendering.
* @param t pointer to a draw task
* @param dsc pointer to an initialized blend descriptor
*/
typedef void (*lv_draw_sw_blend_handler_t)(lv_draw_task_t * t, const lv_draw_sw_blend_dsc_t * dsc);
typedef struct {
lv_color_format_t dest_cf;
lv_draw_sw_blend_handler_t handler;
} lv_draw_sw_custom_blend_handler_t;
/**
* Call the blend function of the `layer`.
* @param draw_unit pointer to a draw unit

View File

@@ -92,6 +92,8 @@ void lv_draw_sw_init(void)
#if LV_USE_VECTOR_GRAPHIC && LV_USE_THORVG
tvg_engine_init(TVG_ENGINE_SW, 0);
#endif
lv_ll_init(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll, sizeof(lv_draw_sw_custom_blend_handler_t));
}
void lv_draw_sw_deinit(void)
@@ -340,4 +342,57 @@ static void execute_drawing(lv_draw_sw_unit_t * u)
LV_PROFILER_DRAW_END;
}
bool lv_draw_sw_register_blend_handler(lv_draw_sw_custom_blend_handler_t * handler)
{
lv_draw_sw_custom_blend_handler_t * existing_handler = NULL;
lv_draw_sw_custom_blend_handler_t * new_handler = NULL;
// Check if a handler is already registered for the color format
LV_LL_READ(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll, existing_handler) {
if(existing_handler->dest_cf == handler->dest_cf) {
new_handler = existing_handler;
break;
}
}
if(new_handler == NULL) {
new_handler = lv_ll_ins_head(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll);
if(new_handler == NULL) {
LV_ASSERT_MALLOC(new_handler);
return false;
}
}
lv_memcpy(new_handler, handler, sizeof(lv_draw_sw_custom_blend_handler_t));
return true;
}
bool lv_draw_sw_unregister_blend_handler(lv_color_format_t dest_cf)
{
lv_draw_sw_custom_blend_handler_t * handler;
LV_LL_READ(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll, handler) {
if(handler->dest_cf == dest_cf) {
lv_ll_remove(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll, handler);
lv_free(handler);
return true;
}
}
return false;
}
lv_draw_sw_blend_handler_t lv_draw_sw_get_blend_handler(lv_color_format_t dest_cf)
{
lv_draw_sw_custom_blend_handler_t * handler;
LV_LL_READ(&LV_GLOBAL_DEFAULT()->draw_sw_blend_handler_ll, handler) {
if(handler->dest_cf == dest_cf) {
return handler->handler;
}
}
return NULL;
}
#endif /*LV_USE_DRAW_SW*/

View File

@@ -28,6 +28,7 @@ extern "C" {
#include "../lv_draw_line.h"
#include "../lv_draw_arc.h"
#include "lv_draw_sw_utils.h"
#include "blend/lv_draw_sw_blend.h"
/*********************
* DEFINES
@@ -154,6 +155,32 @@ void lv_draw_sw_transform(const lv_area_t * dest_area, const void * src_buf,
void lv_draw_sw_vector(lv_draw_task_t * t, const lv_draw_vector_task_dsc_t * dsc);
#endif
/**
* Register a custom blend handler for a color format.
* Handler will be called when blending a color or an
* image to a buffer with the given color format.
* At most one handler can be registered for a color format.
* Subsequent registrations will overwrite the previous handler.
*
* @param handler pointer to a blend handler
* @return true if the handler was registered, false if the handler could not be registered
*/
bool lv_draw_sw_register_blend_handler(lv_draw_sw_custom_blend_handler_t * handler);
/**
* Unregister a custom blend handler for a color format.
* @param dest_cf color format
* @return true if a handler was unregistered, false if no handler was registered
*/
bool lv_draw_sw_unregister_blend_handler(lv_color_format_t dest_cf);
/**
* Get the blend handler for a color format.
* @param dest_cf color format
* @return pointer to the blend handler or NULL if no handler is registered
*/
lv_draw_sw_blend_handler_t lv_draw_sw_get_blend_handler(lv_color_format_t dest_cf);
/***********************
* GLOBAL VARIABLES
***********************/
@@ -162,8 +189,6 @@ void lv_draw_sw_vector(lv_draw_task_t * t, const lv_draw_vector_task_dsc_t * dsc
* MACROS
**********************/
#include "blend/lv_draw_sw_blend.h"
#endif /*LV_USE_DRAW_SW*/
#ifdef __cplusplus

View File

@@ -604,6 +604,7 @@
#define LV_USE_DRAW_SW_COMPLEX_GRADIENTS 0
#endif
#endif
#endif
/*Use TSi's aka (Think Silicon) NemaGFX */

View File

@@ -0,0 +1,61 @@
#if LV_BUILD_TEST
#include "../lvgl.h"
#include "../../lvgl_private.h"
#include "unity/unity.h"
void setUp(void)
{
}
void tearDown(void)
{
}
void test_register_custom_handlers(void)
{
lv_draw_sw_custom_blend_handler_t handler = {
.dest_cf = LV_COLOR_FORMAT_I2,
.handler = NULL,
};
TEST_ASSERT_TRUE(lv_draw_sw_register_blend_handler(&handler));
}
void test_overwrite_custom_handler(void)
{
lv_draw_sw_custom_blend_handler_t handler = {
.dest_cf = LV_COLOR_FORMAT_I2,
.handler = (lv_draw_sw_blend_handler_t)0xDEADBEEF,
};
TEST_ASSERT_TRUE(lv_draw_sw_register_blend_handler(&handler));
lv_draw_sw_custom_blend_handler_t handler2 = {
.dest_cf = LV_COLOR_FORMAT_I2,
.handler = (lv_draw_sw_blend_handler_t)0xCAFEBABE,
};
TEST_ASSERT_TRUE(lv_draw_sw_register_blend_handler(&handler2));
lv_draw_sw_blend_handler_t handler3 = lv_draw_sw_get_blend_handler(LV_COLOR_FORMAT_I2);
TEST_ASSERT_NOT_NULL(handler3);
TEST_ASSERT_EQUAL_PTR(handler3, (lv_draw_sw_blend_handler_t)0xCAFEBABE);
}
void test_unregister_custom_handler(void)
{
lv_draw_sw_custom_blend_handler_t handler = {
.dest_cf = LV_COLOR_FORMAT_I2,
.handler = NULL,
};
TEST_ASSERT_TRUE(lv_draw_sw_register_blend_handler(&handler));
TEST_ASSERT_TRUE(lv_draw_sw_unregister_blend_handler(LV_COLOR_FORMAT_I2));
lv_draw_sw_blend_handler_t handler2 = lv_draw_sw_get_blend_handler(LV_COLOR_FORMAT_I2);
TEST_ASSERT_NULL(handler2);
}
#endif