From 20b00ef65d703af5012e65da517f13acb7661d89 Mon Sep 17 00:00:00 2001 From: Attila Kiss Date: Tue, 3 Dec 2024 11:37:55 +0100 Subject: [PATCH] feat(sdl): add I1 color format render support (#7036) Co-authored-by: liamHowatt Co-authored-by: Neo Xu --- src/draw/sw/lv_draw_sw_utils.c | 20 ++++++++++++++ src/draw/sw/lv_draw_sw_utils.h | 15 ++++++++++ src/drivers/sdl/lv_sdl_window.c | 49 +++++++++++++++++++++++++++------ 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/draw/sw/lv_draw_sw_utils.c b/src/draw/sw/lv_draw_sw_utils.c index 9933f178a..df3e54866 100644 --- a/src/draw/sw/lv_draw_sw_utils.c +++ b/src/draw/sw/lv_draw_sw_utils.c @@ -126,6 +126,26 @@ static void rotate270_l8(const uint8_t * src, uint8_t * dst, int32_t src_width, * GLOBAL FUNCTIONS **********************/ +void lv_draw_sw_i1_to_argb8888(const void * buf_i1, void * buf_argb8888, uint32_t width, uint32_t height, + uint32_t buf_i1_stride, uint32_t buf_argb8888_stride, uint32_t index0_color, uint32_t index1_color) +{ + /*Extract the bits of I1 px_map and convert them to ARGB8888*/ + const uint8_t * src = buf_i1; + uint32_t * dst = buf_argb8888; + uint32_t i1_row_byte_count = width / 8; + for(uint32_t row = 0; row < height; row++) { + uint32_t * dst_p = dst; + for(uint32_t i = 0; i < i1_row_byte_count; i++) { + /*From MSB to LSB (pixel 0 to pixel 7 in a byte)*/ + for(int32_t bit = 7; bit >= 0; bit--) { + *dst_p++ = ((src[i] >> bit) & 1) ? index1_color : index0_color; + } + } + src += buf_i1_stride; + dst += buf_argb8888_stride / 4; + } +} + void lv_draw_sw_rgb565_swap(void * buf, uint32_t buf_size_px) { if(LV_DRAW_SW_RGB565_SWAP(buf, buf_size_px) == LV_RESULT_OK) return; diff --git a/src/draw/sw/lv_draw_sw_utils.h b/src/draw/sw/lv_draw_sw_utils.h index 293155efb..cf4789223 100644 --- a/src/draw/sw/lv_draw_sw_utils.h +++ b/src/draw/sw/lv_draw_sw_utils.h @@ -29,6 +29,21 @@ extern "C" { * GLOBAL PROTOTYPES **********************/ +/** + * Converts an I1 buffer to ARGB8888 format. + * @param buf_i1 pointer to buffer with I1 formatted render + * @param buf_argb8888 pointer to buffer for ARGB8888 render + * @param width width in pixels of the area. + * must be a multiple of 8. + * @param height height in pixels of the area + * @param buf_i1_stride stride of i1 buffer in bytes + * @param buf_argb8888_stride stride of argb8888 buffer in bytes + * @param index0_color color of the 0 bits of i1 buf + * @param index1_color color of the 1 bits of i1 buf + */ +void lv_draw_sw_i1_to_argb8888(const void * buf_i1, void * buf_argb8888, uint32_t width, uint32_t height, + uint32_t buf_i1_stride, uint32_t buf_argb8888_stride, uint32_t index0_color, uint32_t index1_color); + /** * Swap the upper and lower byte of an RGB565 buffer. * Might be required if a 8bit parallel port or an SPI port send the bytes in the wrong order. diff --git a/src/drivers/sdl/lv_sdl_window.c b/src/drivers/sdl/lv_sdl_window.c index 30b84f495..1e2289a8e 100644 --- a/src/drivers/sdl/lv_sdl_window.c +++ b/src/drivers/sdl/lv_sdl_window.c @@ -109,12 +109,13 @@ lv_display_t * lv_sdl_window_create(int32_t hor_res, int32_t ver_res) #if LV_USE_DRAW_SDL == 0 if(sdl_render_mode() == LV_DISPLAY_RENDER_MODE_PARTIAL) { - dsc->buf1 = sdl_draw_buf_realloc_aligned(NULL, 32 * 1024); + uint32_t palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(lv_display_get_color_format(disp)) * 4; + uint32_t buffer_size_bytes = 32 * 1024 + palette_size; + dsc->buf1 = sdl_draw_buf_realloc_aligned(NULL, buffer_size_bytes); #if LV_SDL_BUF_COUNT == 2 - dsc->buf2 = sdl_draw_buf_realloc_aligned(NULL, 32 * 1024); + dsc->buf2 = sdl_draw_buf_realloc_aligned(NULL, buffer_size_bytes); #endif - lv_display_set_buffers(disp, dsc->buf1, dsc->buf2, - 32 * 1024, LV_DISPLAY_RENDER_MODE_PARTIAL); + lv_display_set_buffers(disp, dsc->buf1, dsc->buf2, buffer_size_bytes, LV_DISPLAY_RENDER_MODE_PARTIAL); } /*LV_DISPLAY_RENDER_MODE_DIRECT or FULL */ else { @@ -210,8 +211,29 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m #if LV_USE_DRAW_SDL == 0 lv_sdl_window_t * dsc = lv_display_get_driver_data(disp); lv_color_format_t cf = lv_display_get_color_format(disp); + uint32_t * argb_px_map = NULL; if(sdl_render_mode() == LV_DISPLAY_RENDER_MODE_PARTIAL) { + /*Update values in a special OLED I1 --> ARGB8888 case + We render everything in I1, but display it in ARGB8888*/ + if(cf == LV_COLOR_FORMAT_I1) { + /*I1 uses 1 bit wide pixels, ARGB8888 uses 4 byte wide pixels*/ + cf = LV_COLOR_FORMAT_ARGB8888; + uint32_t width = lv_area_get_width(area); + uint32_t height = lv_area_get_height(area); + uint32_t argb_px_map_size = width * height * 4; + argb_px_map = malloc(argb_px_map_size); + if(argb_px_map == NULL) { + LV_LOG_ERROR("malloc failed"); + lv_display_flush_ready(disp); + return; + } + /* skip the palette */ + px_map += LV_COLOR_INDEXED_PALETTE_SIZE(LV_COLOR_FORMAT_I1) * 4; + lv_draw_sw_i1_to_argb8888(px_map, argb_px_map, width, height, width / 8, width * 4, 0xFF000000u, 0xFFFFFFFFu); + px_map = (uint8_t *)argb_px_map; + } + lv_area_t rotated_area = *area; lv_display_rotate_area(disp, &rotated_area); @@ -247,6 +269,7 @@ static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_m window_update(disp); } + free(argb_px_map); #else LV_UNUSED(area); LV_UNUSED(px_map); @@ -352,7 +375,11 @@ static void window_update(lv_display_t * disp) lv_sdl_window_t * dsc = lv_display_get_driver_data(disp); #if LV_USE_DRAW_SDL == 0 int32_t hor_res = disp->hor_res; - uint32_t stride = lv_draw_buf_width_to_stride(hor_res, lv_display_get_color_format(disp)); + lv_color_format_t cf = lv_display_get_color_format(disp); + if(cf == LV_COLOR_FORMAT_I1) { + cf = LV_COLOR_FORMAT_ARGB8888; + } + uint32_t stride = lv_draw_buf_width_to_stride(hor_res, cf); SDL_UpdateTexture(dsc->texture, NULL, dsc->fb_act, stride); SDL_RenderClear(dsc->renderer); @@ -366,7 +393,14 @@ static void window_update(lv_display_t * disp) #if LV_USE_DRAW_SDL == 0 static void texture_resize(lv_display_t * disp) { - uint32_t stride = lv_draw_buf_width_to_stride(disp->hor_res, lv_display_get_color_format(disp)); + lv_color_format_t cf = lv_display_get_color_format(disp); + /*In some cases SDL stride might be different than LVGL render stride, like in I1 format. + SDL still uses ARGB8888 as the color format, but LVGL renders in I1, thus causing a mismatch + This ensures correct stride for SDL buffers in this case.*/ + if(cf == LV_COLOR_FORMAT_I1) { + cf = LV_COLOR_FORMAT_ARGB8888; + } + uint32_t stride = lv_draw_buf_width_to_stride(disp->hor_res, cf); lv_sdl_window_t * dsc = lv_display_get_driver_data(disp); dsc->fb1 = sdl_draw_buf_realloc_aligned(dsc->fb1, stride * disp->ver_res); @@ -384,7 +418,7 @@ static void texture_resize(lv_display_t * disp) } if(dsc->texture) SDL_DestroyTexture(dsc->texture); -#if LV_COLOR_DEPTH == 32 +#if LV_COLOR_DEPTH == 32 || LV_COLOR_DEPTH == 1 SDL_PixelFormatEnum px_format = SDL_PIXELFORMAT_RGB888; /*same as SDL_PIXELFORMAT_RGB888, but it's not supported in older versions*/ #elif LV_COLOR_DEPTH == 24 @@ -394,7 +428,6 @@ static void texture_resize(lv_display_t * disp) #else #error("Unsupported color format") #endif - // px_format = SDL_PIXELFORMAT_BGR24; dsc->texture = SDL_CreateTexture(dsc->renderer, px_format, SDL_TEXTUREACCESS_STATIC, disp->hor_res, disp->ver_res);