mirror of
https://github.com/lvgl/lvgl.git
synced 2024-11-23 09:43:41 +08:00
feat(drawing) hardware accelerated rendering by SDL2 (#2484)
* Hardware accelerated SDL render WIP * Rect drawing code cleanup * Fixed arc drawing angle Fixed compact rect drawing * Refactoring Fixed cache deinit order * Image recolor Drawing left and right border * Math problems * Improving draw cache * Improving line drawing logic * Improving arc drawing quality * Added round function * Attempts to render properly on Pi * Updated lruc function names * Updated symbol names * Saved ram by reusing part of background rect * Added outline drawing Removed arc texture caching * rect drawing cache rendering * high efficiency rect shadow texture caching * fixed simple borders drawing * fixed generic borders drawing * Simplified text atlas caching logic Supports chroma keyed image * Color palette WIP * Improved draw cache * Updated defines for better build * renaming files for better consistency * fix includes * Updated lv_conf_internal with generator * Fixing build issues * fixed img rotation pivot * better font atlas caching WIP * fix includes * full font atlas support improved gpu caching for rect * update conf header * fix palette creation * Fixed font atlas key matching * fixed chroma key image background * added 3bpp mask palette (WIP) * fixed caching key initialization * disabled gpu arc drawing for now updated naming convention * updated naming convention * fix makefile and include path * improved rect drawing when having masks * improved rect drawing when having masks * reduced texture allocation while drawing with mask * accurate clipping for rects and texts * fixed build error * fixed build error * line drawing WIP * updated imports * fixed freezes if LRU has smaller new item * fixed clipping rect color * fixed build error * using built-in free function for LRU key * Added custom background drawing function * fixing imports * fixed shadow bitmap on old SDL libs * improved draw_img compatibility * fixing font baking * fixed font rendering * fixed lv_draw_line check * configurable SDL include path * disabled SDL line drawing implementation * supports screen resize * sdl: Remove duplicated object Observed issue: /usr/bin/ld: lv_gpu_sdl_texture_cache.o: \ in function `_lv_gpu_sdl_texture_cache_init': lv_gpu_sdl_texture_cache.c:(.text+0x30): \ multiple definition of `_lv_gpu_sdl_texture_cache_init'; \ lv_gpu_sdl_texture_cache.o:lv_gpu_sdl_texture_cache.c:(.text+0x30): \ first defined here Forwarded: https://github.com/mariotaku/lvgl/pull/1 Relate-to: https://github.com/lvgl/lvgl/pull/2484 Signed-off-by: Philippe Coval <philippe.coval@huawei.com> * Reduced opening of image * Closes image resource properly * improved draw image logic * Moved driver related code to lv_drivers * fixed lv_deinit implicit sdl code invocation * improved shadow clipping * fixed outline area invalidation * updated comments * formatted code using astyle * Updated README * formatted code * fixed typo * fixed static declaration Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com> Co-authored-by: Philippe Coval <philippe.coval@huawei.com>
This commit is contained in:
parent
71e6f65d51
commit
efc5bb40d9
@ -149,6 +149,25 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
/*Use NXP's VG-Lite GPU iMX RTxxx platforms*/
|
||||
#define LV_USE_GPU_NXP_VG_LITE 0
|
||||
|
||||
/*Use SDL renderer API*/
|
||||
#ifndef LV_USE_GPU_SDL
|
||||
# ifdef CONFIG_LV_USE_GPU_SDL
|
||||
# define LV_USE_GPU_SDL CONFIG_LV_USE_GPU_SDL
|
||||
# else
|
||||
# define LV_USE_GPU_SDL 0
|
||||
# endif
|
||||
#endif
|
||||
#if LV_USE_GPU_SDL
|
||||
# define LV_USE_EXTERNAL_RENDERER 1
|
||||
# ifndef LV_GPU_SDL_INCLUDE
|
||||
# define LV_GPU_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_EXTERNAL_RENDERER
|
||||
# define LV_USE_EXTERNAL_RENDERER 0
|
||||
#endif
|
||||
|
||||
/*-------------
|
||||
* Logging
|
||||
*-----------*/
|
||||
@ -225,7 +244,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
#define LV_USE_USER_DATA 1
|
||||
|
||||
/*Garbage Collector settings
|
||||
*Used if lvgl is binded to higher level language and the memory is managed by that language*/
|
||||
*Used if lvgl is bound to higher level language and the memory is managed by that language*/
|
||||
#define LV_ENABLE_GC 0
|
||||
#if LV_ENABLE_GC != 0
|
||||
# define LV_GC_INCLUDE "gc.h" /*Include Garbage Collector related things*/
|
||||
|
@ -35,6 +35,10 @@
|
||||
#include "../gpu/lv_gpu_nxp_pxp_osa.h"
|
||||
#endif
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
#include "../gpu/lv_gpu_sdl.h"
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@ -121,6 +125,9 @@ void lv_init(void)
|
||||
for(; ;) ;
|
||||
}
|
||||
#endif
|
||||
#if LV_USE_GPU_SDL
|
||||
lv_gpu_sdl_init();
|
||||
#endif
|
||||
|
||||
_lv_obj_style_init();
|
||||
_lv_ll_init(&LV_GC_ROOT(_lv_disp_ll), sizeof(lv_disp_t));
|
||||
@ -177,10 +184,13 @@ void lv_init(void)
|
||||
LV_LOG_TRACE("finished");
|
||||
}
|
||||
|
||||
#if LV_ENABLE_GC || !LV_MEM_CUSTOM
|
||||
#if LV_ENABLE_GC || !LV_MEM_CUSTOM || LV_USE_GPU_SDL
|
||||
|
||||
void lv_deinit(void)
|
||||
{
|
||||
#if LV_USE_GPU_SDL
|
||||
lv_gpu_sdl_deinit();
|
||||
#endif
|
||||
_lv_gc_clear_roots();
|
||||
|
||||
lv_disp_set_default(NULL);
|
||||
|
@ -517,7 +517,9 @@ static void lv_refr_area_part(const lv_area_t * area_p)
|
||||
|
||||
/*Draw a display background if there is no top object*/
|
||||
if(top_act_scr == NULL && top_prev_scr == NULL) {
|
||||
if(disp_refr->bg_img) {
|
||||
if(disp_refr->bg_fn) {
|
||||
disp_refr->bg_fn(&start_mask);
|
||||
} else if(disp_refr->bg_img) {
|
||||
lv_draw_img_dsc_t dsc;
|
||||
lv_draw_img_dsc_init(&dsc);
|
||||
dsc.opa = disp_refr->bg_opa;
|
||||
|
@ -33,6 +33,7 @@
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
static void fill_set_px(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area,
|
||||
lv_color_t color, lv_opa_t opa,
|
||||
const lv_opa_t * mask, lv_draw_mask_res_t mask_res);
|
||||
@ -65,6 +66,7 @@ static void map_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, con
|
||||
static inline lv_color_t color_blend_true_color_additive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
|
||||
static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_color_t bg, lv_opa_t opa);
|
||||
#endif
|
||||
#endif //LV_USE_GPU_SDL_RENDER
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -109,6 +111,7 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
/**
|
||||
* Fill and area in the display buffer.
|
||||
* @param clip_area clip the fill to this area (absolute coordinates)
|
||||
@ -273,6 +276,7 @@ static void fill_set_px(const lv_area_t * disp_area, lv_color_t * disp_buf, con
|
||||
}
|
||||
}
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
/**
|
||||
* Fill an area with a color
|
||||
* @param disp_area the current display area (destination area)
|
||||
@ -572,6 +576,7 @@ static void fill_blended(const lv_area_t * disp_area, lv_color_t * disp_buf, co
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // LV_USE_GPU_SDL_RENDER
|
||||
|
||||
static void map_set_px(const lv_area_t * disp_area, lv_color_t * disp_buf, const lv_area_t * draw_area,
|
||||
const lv_area_t * map_area, const lv_color_t * map_buf, lv_opa_t opa,
|
||||
@ -1022,3 +1027,5 @@ static inline lv_color_t color_blend_true_color_subtractive(lv_color_t fg, lv_co
|
||||
return lv_color_mix(fg, bg, opa);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // LV_USE_GPU_SDL_RENDER
|
@ -30,6 +30,7 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
|
||||
const void * src,
|
||||
const lv_draw_img_dsc_t * draw_dsc);
|
||||
@ -41,6 +42,7 @@ LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const
|
||||
|
||||
static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg);
|
||||
static void draw_cleanup(_lv_img_cache_entry_t * cache);
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -63,6 +65,7 @@ void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc)
|
||||
dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
|
||||
}
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
/**
|
||||
* Draw an image
|
||||
* @param coords the coordinates of the image
|
||||
@ -89,6 +92,7 @@ void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void *
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif //LV_USE_GPU_SDL_RENDER
|
||||
|
||||
/**
|
||||
* Get the pixel size of a color format in bits
|
||||
@ -229,6 +233,7 @@ lv_img_src_t lv_img_src_get_type(const void * src)
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
|
||||
const void * src,
|
||||
const lv_draw_img_dsc_t * draw_dsc)
|
||||
@ -659,3 +664,5 @@ static void draw_cleanup(_lv_img_cache_entry_t * cache)
|
||||
LV_UNUSED(cache);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif //LV_USE_GPU_SDL_RENDER
|
@ -13,6 +13,9 @@
|
||||
#include "../misc/lv_bidi.h"
|
||||
#include "../misc/lv_assert.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
#include "../gpu/lv_gpu_sdl.h"
|
||||
#endif
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
@ -32,9 +35,13 @@ typedef uint8_t cmd_state_t;
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g,
|
||||
const lv_area_t * clip_area,
|
||||
const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode);
|
||||
#endif
|
||||
|
||||
#if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX
|
||||
static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area,
|
||||
const uint8_t * map_p, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode);
|
||||
@ -387,6 +394,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_label(const lv_area_t * coords, const lv_area
|
||||
LV_ASSERT_MEM_INTEGRITY();
|
||||
}
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
@ -616,6 +624,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_letter_normal(lv_coord_t pos_x, lv_coord_
|
||||
|
||||
lv_mem_buf_release(mask_buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LV_DRAW_COMPLEX && LV_USE_FONT_SUBPX
|
||||
static void draw_letter_subpx(lv_coord_t pos_x, lv_coord_t pos_y, lv_font_glyph_dsc_t * g, const lv_area_t * clip_area,
|
||||
|
@ -34,7 +34,6 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_ver(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
@ -117,6 +116,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_line(const lv_point_t * point1, const lv_poin
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_line_hor(const lv_point_t * point1, const lv_point_t * point2,
|
||||
const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc)
|
||||
|
@ -126,6 +126,39 @@ LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply(lv_opa_t * mask_buf,
|
||||
return changed ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified buffers on a line. Used internally by the library's drawing routines.
|
||||
* @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`.
|
||||
* @param abs_x absolute X coordinate where the line to calculate start
|
||||
* @param abs_y absolute Y coordinate where the line to calculate start
|
||||
* @param len length of the line to calculate (in pixel count)
|
||||
* @param ids ID array of added buffers
|
||||
* @param ids_count number of ID array
|
||||
* @return One of these values:
|
||||
* - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero
|
||||
* - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged
|
||||
* - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply_ids(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
|
||||
lv_coord_t len, const int16_t *ids, int16_t ids_count)
|
||||
{
|
||||
bool changed = false;
|
||||
_lv_draw_mask_common_dsc_t * dsc;
|
||||
|
||||
for (int i = 0; i < ids_count; i++) {
|
||||
int16_t id = ids[i];
|
||||
if (id == LV_MASK_ID_INV) continue;
|
||||
dsc = LV_GC_ROOT(_lv_draw_mask_list[id]).param;
|
||||
if (!dsc) continue;
|
||||
lv_draw_mask_res_t res = LV_DRAW_MASK_RES_FULL_COVER;
|
||||
res = dsc->cb(mask_buf, abs_x, abs_y, len, dsc);
|
||||
if(res == LV_DRAW_MASK_RES_TRANSP) return LV_DRAW_MASK_RES_TRANSP;
|
||||
else if(res == LV_DRAW_MASK_RES_CHANGED) changed = true;
|
||||
}
|
||||
|
||||
return changed ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a mask with a given ID
|
||||
* @param id the ID of the mask. Returned by `lv_draw_mask_add`
|
||||
|
@ -236,6 +236,22 @@ int16_t lv_draw_mask_add(void * param, void * custom_id);
|
||||
LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
|
||||
lv_coord_t len);
|
||||
|
||||
/**
|
||||
* Apply the specified buffers on a line. Used internally by the library's drawing routines.
|
||||
* @param mask_buf store the result mask here. Has to be `len` byte long. Should be initialized with `0xFF`.
|
||||
* @param abs_x absolute X coordinate where the line to calculate start
|
||||
* @param abs_y absolute Y coordinate where the line to calculate start
|
||||
* @param len length of the line to calculate (in pixel count)
|
||||
* @param ids ID array of added buffers
|
||||
* @param ids_count number of ID array
|
||||
* @return One of these values:
|
||||
* - `LV_DRAW_MASK_RES_FULL_TRANSP`: the whole line is transparent. `mask_buf` is not set to zero
|
||||
* - `LV_DRAW_MASK_RES_FULL_COVER`: the whole line is fully visible. `mask_buf` is unchanged
|
||||
* - `LV_DRAW_MASK_RES_CHANGED`: `mask_buf` has changed, it shows the desired opacity of each pixel in the given line
|
||||
*/
|
||||
LV_ATTRIBUTE_FAST_MEM lv_draw_mask_res_t lv_draw_mask_apply_ids(lv_opa_t * mask_buf, lv_coord_t abs_x, lv_coord_t abs_y,
|
||||
lv_coord_t len, const int16_t *ids, int16_t ids_count);
|
||||
|
||||
//! @endcond
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,7 @@
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_bg(const lv_area_t * coords, const lv_area_t * clip_area,
|
||||
const lv_draw_rect_dsc_t * dsc);
|
||||
LV_ATTRIBUTE_FAST_MEM static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip,
|
||||
@ -54,6 +55,7 @@ static void draw_border_simple(const lv_area_t * clip, const lv_area_t * outer_a
|
||||
#if LV_DRAW_COMPLEX
|
||||
LV_ATTRIBUTE_FAST_MEM static inline lv_color_t grad_get(const lv_draw_rect_dsc_t * dsc, lv_coord_t s, lv_coord_t i);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
@ -89,6 +91,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc)
|
||||
dsc->border_side = LV_BORDER_SIDE_FULL;
|
||||
}
|
||||
|
||||
#if LV_USE_EXTERNAL_RENDERER == 0
|
||||
/**
|
||||
* Draw a rectangle
|
||||
* @param coords the coordinates of the rectangle
|
||||
@ -1331,3 +1334,5 @@ static void draw_border_simple(const lv_area_t * clip, const lv_area_t * outer_a
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -80,10 +80,10 @@ LV_ATTRIBUTE_FAST_MEM void lv_draw_rect_dsc_init(lv_draw_rect_dsc_t * dsc);
|
||||
/**
|
||||
* Draw a rectangle
|
||||
* @param coords the coordinates of the rectangle
|
||||
* @param mask the rectangle will be drawn only in this mask
|
||||
* @param clip the rectangle will be drawn only in this area
|
||||
* @param dsc pointer to an initialized `lv_draw_rect_dsc_t` variable
|
||||
*/
|
||||
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * mask, const lv_draw_rect_dsc_t * dsc);
|
||||
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
/**
|
||||
* Draw a pixel
|
||||
|
@ -2,8 +2,11 @@ CSRCS += lv_gpu_nxp_pxp.c
|
||||
CSRCS += lv_gpu_nxp_pxp_osa.c
|
||||
CSRCS += lv_gpu_nxp_vglite.c
|
||||
CSRCS += lv_gpu_stm32_dma2d.c
|
||||
CSRCS += lv_gpu_sdl.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu
|
||||
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu"
|
||||
|
||||
include $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu/sdl/lv_gpu_sdl.mk
|
59
src/gpu/lv_gpu_sdl.c
Normal file
59
src/gpu/lv_gpu_sdl.c
Normal file
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "lv_gpu_sdl.h"
|
||||
#include "sdl/lv_gpu_sdl_utils.h"
|
||||
#include "sdl/lv_gpu_sdl_texture_cache.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_gpu_sdl_init()
|
||||
{
|
||||
_lv_gpu_sdl_utils_init();
|
||||
_lv_gpu_sdl_texture_cache_init();
|
||||
}
|
||||
|
||||
void lv_gpu_sdl_deinit()
|
||||
{
|
||||
_lv_gpu_sdl_texture_cache_deinit();
|
||||
_lv_gpu_sdl_utils_deinit();
|
||||
}
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
69
src/gpu/lv_gpu_sdl.h
Normal file
69
src/gpu/lv_gpu_sdl.h
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GPU_SDL_H
|
||||
#define LV_GPU_SDL_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_gpu_sdl_init();
|
||||
|
||||
/**
|
||||
* @brief Free caches
|
||||
*
|
||||
*/
|
||||
void lv_gpu_sdl_deinit();
|
||||
|
||||
/*======================
|
||||
* Add/remove functions
|
||||
*=====================*/
|
||||
|
||||
/*=====================
|
||||
* Setter functions
|
||||
*====================*/
|
||||
|
||||
/*=====================
|
||||
* Getter functions
|
||||
*====================*/
|
||||
|
||||
/*=====================
|
||||
* Other functions
|
||||
*====================*/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GPU_SDL_H*/
|
28
src/gpu/sdl/README.md
Normal file
28
src/gpu/sdl/README.md
Normal file
@ -0,0 +1,28 @@
|
||||
# SDL_Renderer Based Drawing Functions
|
||||
|
||||
In LVGL, drawing was performed by CPU. To improve drawing performance on platforms with GPU,
|
||||
we should perform drawing operations on GPU if possible.
|
||||
|
||||
This implementation has moved most bitmap blending and drawing procedures to utilize SDL_Renderer,
|
||||
which takes advantages of hardware acceleration APIs like DirectX or OpenGL.
|
||||
|
||||
This implementation can be also considered as a reference implementation, for contributors wants to
|
||||
develop accelerated drawing functions with other APIs such as OpenGL/OpenGL ES.
|
||||
|
||||
## Caveats
|
||||
`lv_draw_arc`, `lv_draw_line` is not enabled, due to incomplete implementation. So lines and arcs will
|
||||
have significant impact to drawing performances.
|
||||
|
||||
Performance of this implementation still has room to improve. Or we should use more powerful APIs
|
||||
such as OpenGL.
|
||||
|
||||
## Notices for files
|
||||
|
||||
### `lv_gpu_sdl_stack_blur.c`
|
||||
|
||||
Contains modified code from [android-stackblur](https://github.com/kikoso/android-stackblur) project.
|
||||
Apache License 2.0
|
||||
|
||||
### `lv_gpu_sdl_lru.c`/`lv_gpu_sdl_lru.h`
|
||||
|
||||
Contains modified code from [C-LRU-Cache](https://github.com/willcannings/C-LRU-Cache) project. No license defined.
|
16
src/gpu/sdl/lv_gpu_sdl.mk
Normal file
16
src/gpu/sdl/lv_gpu_sdl.mk
Normal file
@ -0,0 +1,16 @@
|
||||
CSRCS += lv_gpu_sdl_draw_arc.c
|
||||
CSRCS += lv_gpu_sdl_draw_blend.c
|
||||
CSRCS += lv_gpu_sdl_draw_img.c
|
||||
CSRCS += lv_gpu_sdl_draw_label.c
|
||||
CSRCS += lv_gpu_sdl_draw_line.c
|
||||
CSRCS += lv_gpu_sdl_draw_rect.c
|
||||
CSRCS += lv_gpu_sdl_lru.c
|
||||
CSRCS += lv_gpu_sdl_mask.c
|
||||
CSRCS += lv_gpu_sdl_stack_blur.c
|
||||
CSRCS += lv_gpu_sdl_texture_cache.c
|
||||
CSRCS += lv_gpu_sdl_utils.c
|
||||
|
||||
DEPPATH += --dep-path $(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu/sdl
|
||||
VPATH += :$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu/sdl
|
||||
|
||||
CFLAGS += "-I$(LVGL_DIR)/$(LVGL_DIR_NAME)/src/gpu/sdl"
|
163
src/gpu/sdl/lv_gpu_sdl_draw_arc.c
Normal file
163
src/gpu/sdl/lv_gpu_sdl_draw_arc.c
Normal file
@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_draw_arc.c
|
||||
*
|
||||
* This implementation does not functioning properly so it's not enabled
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "../../hal/lv_hal_disp.h"
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "../../draw/lv_draw_arc.h"
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
#include "lv_gpu_sdl_lru.h"
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
#include "lv_gpu_sdl_mask.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
uint16_t radius;
|
||||
uint16_t angle;
|
||||
lv_coord_t width;
|
||||
uint8_t rounded;
|
||||
} lv_draw_arc_key_t;
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_arc2(lv_coord_t center_x, lv_coord_t center_y, uint16_t radius, uint16_t start_angle, uint16_t end_angle,
|
||||
const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc)
|
||||
{
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
lv_disp_drv_t * driver = disp->driver;
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) driver->user_data;
|
||||
|
||||
lv_area_t area_out;
|
||||
area_out.x1 = center_x - radius;
|
||||
area_out.y1 = center_y - radius;
|
||||
area_out.x2 = center_x + radius - 1; /*-1 because the center already belongs to the left/bottom part*/
|
||||
area_out.y2 = center_y + radius - 1;
|
||||
|
||||
lv_area_t area_in;
|
||||
lv_area_copy(&area_in, &area_out);
|
||||
area_in.x1 += dsc->width;
|
||||
area_in.y1 += dsc->width;
|
||||
area_in.x2 -= dsc->width;
|
||||
area_in.y2 -= dsc->width;
|
||||
|
||||
/*Increase 1 px each side to texture, to have better rotation result*/
|
||||
lv_area_t texture_area_out;
|
||||
lv_area_copy(&texture_area_out, &area_out);
|
||||
lv_area_increase(&texture_area_out, 1, 1);
|
||||
|
||||
SDL_Rect area_out_rect, clip_rect;
|
||||
lv_area_to_sdl_rect(&texture_area_out, &area_out_rect);
|
||||
lv_area_to_sdl_rect(clip_area, &clip_rect);
|
||||
|
||||
lv_draw_arc_key_t key = {
|
||||
.magic = LV_GPU_CACHE_KEY_MAGIC_ARC,
|
||||
.radius = radius,
|
||||
.angle = ((end_angle - start_angle) % 360 + 360) % 360,
|
||||
.width = dsc->width,
|
||||
.rounded = dsc->rounded,
|
||||
};
|
||||
// SDL_Texture *texture = lv_gpu_draw_cache_get(&key, sizeof(key));
|
||||
SDL_Texture * texture = NULL;
|
||||
if(texture == NULL) {
|
||||
/*Create inner the mask*/
|
||||
lv_draw_mask_radius_param_t mask_in_param;
|
||||
lv_draw_mask_radius_init(&mask_in_param, &area_in, LV_RADIUS_CIRCLE, true);
|
||||
int16_t mask_in_id = lv_draw_mask_add(&mask_in_param, NULL);
|
||||
|
||||
lv_draw_mask_radius_param_t mask_out_param;
|
||||
lv_draw_mask_radius_init(&mask_out_param, &area_out, LV_RADIUS_CIRCLE, false);
|
||||
int16_t mask_out_id = lv_draw_mask_add(&mask_out_param, NULL);
|
||||
|
||||
SDL_Surface * ark_mask;
|
||||
if(key.angle < 360) {
|
||||
while(start_angle >= 360) start_angle -= 360;
|
||||
while(end_angle >= 360) end_angle -= 360;
|
||||
lv_draw_mask_angle_param_t mask_angle_param;
|
||||
lv_draw_mask_angle_init(&mask_angle_param, center_x, center_y, 0, key.angle);
|
||||
int16_t mask_angle_id = lv_draw_mask_add(&mask_angle_param, NULL);
|
||||
ark_mask = lv_sdl_apply_mask_surface(&texture_area_out, NULL, 0);
|
||||
lv_draw_mask_remove_id(mask_angle_id);
|
||||
}
|
||||
else {
|
||||
ark_mask = lv_sdl_apply_mask_surface(&texture_area_out, NULL, 0);
|
||||
}
|
||||
lv_draw_mask_remove_id(mask_out_id);
|
||||
lv_draw_mask_remove_id(mask_in_id);
|
||||
|
||||
if(dsc->rounded) {
|
||||
SDL_Renderer * mask_renderer = SDL_CreateSoftwareRenderer(ark_mask);
|
||||
lv_area_t cap_area = {.x1 = 0, .y1 = 0};
|
||||
lv_area_set_width(&cap_area, dsc->width);
|
||||
lv_area_set_height(&cap_area, dsc->width);
|
||||
|
||||
lv_draw_mask_radius_param_t mask_rout_param;
|
||||
lv_draw_mask_radius_init(&mask_rout_param, &cap_area, LV_RADIUS_CIRCLE, false);
|
||||
int16_t mask_rout_id = lv_draw_mask_add(&mask_rout_param, NULL);
|
||||
SDL_Texture * round_texture = lv_sdl_gen_mask_texture(mask_renderer, &cap_area, &mask_rout_id, 1);
|
||||
lv_draw_mask_remove_id(mask_rout_id);
|
||||
|
||||
SDL_SetTextureBlendMode(round_texture, SDL_BLENDMODE_BLEND);
|
||||
float mid_point = radius - key.width / 2.0f;
|
||||
SDL_Rect cap_dst;
|
||||
cap_dst.w = lv_area_get_width(&cap_area);
|
||||
cap_dst.h = lv_area_get_height(&cap_area);
|
||||
cap_dst.x = mid_point + lv_sdl_round(SDL_cos(0) * mid_point);
|
||||
cap_dst.y = mid_point + lv_sdl_round(SDL_sin(0) * mid_point);
|
||||
SDL_RenderCopy(mask_renderer, round_texture, NULL, &cap_dst);
|
||||
cap_dst.x = mid_point + lv_sdl_round(SDL_cos(key.angle * M_PI / 180.0f) * mid_point);
|
||||
cap_dst.y = mid_point + lv_sdl_round(SDL_sin(key.angle * M_PI / 180.0f) * mid_point);
|
||||
SDL_RenderCopy(mask_renderer, round_texture, NULL, &cap_dst);
|
||||
SDL_DestroyTexture(round_texture);
|
||||
SDL_DestroyRenderer(mask_renderer);
|
||||
}
|
||||
texture = SDL_CreateTextureFromSurface(renderer, ark_mask);
|
||||
SDL_FreeSurface(ark_mask);
|
||||
|
||||
SDL_assert(texture);
|
||||
// lv_gpu_draw_cache_put(&key, sizeof(key), texture);
|
||||
}
|
||||
|
||||
SDL_Color arc_color;
|
||||
lv_color_to_sdl_color(&dsc->color, &arc_color);
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, dsc->opa);
|
||||
SDL_SetTextureColorMod(texture, arc_color.r, arc_color.g, arc_color.b);
|
||||
SDL_RenderSetClipRect(renderer, &clip_rect);
|
||||
SDL_RenderCopyEx(renderer, texture, NULL, &area_out_rect, start_angle, NULL, SDL_FLIP_NONE);
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
95
src/gpu/sdl/lv_gpu_sdl_draw_blend.c
Normal file
95
src/gpu/sdl/lv_gpu_sdl_draw_blend.c
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_draw_blend.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "../../draw/lv_draw_blend.h"
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
#include "lv_gpu_sdl_mask.h"
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void _lv_blend_fill(const lv_area_t * clip_area, const lv_area_t * fill_area, lv_color_t color,
|
||||
lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa, lv_blend_mode_t mode)
|
||||
{
|
||||
/*Do not draw transparent things*/
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(mask_res == LV_DRAW_MASK_RES_TRANSP) return;
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
/*Get clipped fill area which is the real draw area.
|
||||
*It is always the same or inside `fill_area`*/
|
||||
lv_area_t draw_area;
|
||||
if(!_lv_area_intersect(&draw_area, clip_area, fill_area)) return;
|
||||
|
||||
SDL_Rect draw_area_rect;
|
||||
lv_area_to_sdl_rect(&draw_area, &draw_area_rect);
|
||||
if(mask) {
|
||||
SDL_Surface * mask_surface = lv_sdl_create_mask_surface(mask, lv_area_get_width(&draw_area),
|
||||
lv_area_get_height(&draw_area),
|
||||
lv_area_get_width(&draw_area));
|
||||
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, mask_surface);
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, opa);
|
||||
SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue);
|
||||
SDL_RenderSetClipRect(renderer, &draw_area_rect);
|
||||
SDL_RenderCopy(renderer, texture, NULL, &draw_area_rect);
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(mask_surface);
|
||||
}
|
||||
else {
|
||||
SDL_SetRenderDrawColor(renderer, color.ch.red, color.ch.green, color.ch.blue, opa);
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_RenderSetClipRect(renderer, &draw_area_rect);
|
||||
SDL_RenderFillRect(renderer, &draw_area_rect);
|
||||
}
|
||||
}
|
||||
|
||||
void _lv_blend_map(const lv_area_t * clip_area, const lv_area_t * map_area,
|
||||
const lv_color_t * map_buf, lv_opa_t * mask, lv_draw_mask_res_t mask_res, lv_opa_t opa,
|
||||
lv_blend_mode_t mode)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
171
src/gpu/sdl/lv_gpu_sdl_draw_img.c
Normal file
171
src/gpu/sdl/lv_gpu_sdl_draw_img.c
Normal file
@ -0,0 +1,171 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_draw_img.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
#include "lv_gpu_sdl_lru.h"
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src,
|
||||
const lv_draw_img_dsc_t * draw_dsc)
|
||||
{
|
||||
if(draw_dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
size_t key_size;
|
||||
lv_gpu_sdl_cache_key_head_img_t * key = lv_gpu_sdl_img_cache_key_create(src, draw_dsc->frame_id, &key_size);
|
||||
bool texture_found = false;
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get(key, key_size, &texture_found);
|
||||
if(!texture_found) {
|
||||
_lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id);
|
||||
lv_gpu_sdl_cache_flag_t tex_flags = 0;
|
||||
if(cdsc) {
|
||||
lv_img_decoder_dsc_t * dsc = &cdsc->dec_dsc;
|
||||
if(dsc->user_data && SDL_memcmp(dsc->user_data, LV_GPU_SDL_DEC_DSC_TEXTURE_HEAD, 8) == 0) {
|
||||
texture = ((lv_gpu_sdl_dec_dsc_userdata_t *) dsc->user_data)->texture;
|
||||
tex_flags |= LV_GPU_SDL_CACHE_FLAG_MANAGED;
|
||||
}
|
||||
else {
|
||||
texture = upload_img_texture(renderer, dsc);
|
||||
}
|
||||
#if LV_IMG_CACHE_DEF_SIZE == 0
|
||||
lv_img_decoder_close(dsc);
|
||||
#endif
|
||||
}
|
||||
if(texture && cdsc) {
|
||||
lv_img_header_t * header = SDL_malloc(sizeof(lv_img_header_t));
|
||||
SDL_memcpy(header, &cdsc->dec_dsc.header, sizeof(lv_img_header_t));
|
||||
lv_gpu_draw_cache_put_advanced(key, key_size, texture, header, SDL_free, tex_flags);
|
||||
}
|
||||
else {
|
||||
lv_gpu_draw_cache_put(key, key_size, NULL);
|
||||
}
|
||||
}
|
||||
SDL_free(key);
|
||||
if(!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_Rect mask_rect, coords_rect;
|
||||
lv_area_to_sdl_rect(mask, &mask_rect);
|
||||
lv_area_to_sdl_rect(coords, &coords_rect);
|
||||
lv_area_zoom_to_sdl_rect(coords, &coords_rect, draw_dsc->zoom, &draw_dsc->pivot);
|
||||
|
||||
SDL_Point pivot = {.x = draw_dsc->pivot.x, .y = draw_dsc->pivot.y};
|
||||
SDL_SetTextureAlphaMod(texture, draw_dsc->opa);
|
||||
SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_RenderSetClipRect(renderer, &mask_rect);
|
||||
|
||||
SDL_Color recolor;
|
||||
lv_color_to_sdl_color(&draw_dsc->recolor, &recolor);
|
||||
/*Draw original image if not fully recolored*/
|
||||
/*TODO: what if the image is translucent as well?*/
|
||||
if(draw_dsc->recolor_opa < LV_OPA_MAX) {
|
||||
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
|
||||
}
|
||||
|
||||
SDL_SetTextureColorMod(texture, recolor.r, recolor.g, recolor.b);
|
||||
if(draw_dsc->recolor_opa >= LV_OPA_MAX) {
|
||||
/*Draw fully colored image*/
|
||||
SDL_SetTextureAlphaMod(texture, draw_dsc->opa);
|
||||
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
|
||||
}
|
||||
else if(draw_dsc->recolor_opa >= LV_OPA_MIN) {
|
||||
SDL_SetTextureAlphaMod(texture, draw_dsc->recolor_opa);
|
||||
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, draw_dsc->angle, &pivot, SDL_FLIP_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static SDL_Texture * upload_img_texture(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
if(!dsc->img_data) {
|
||||
return upload_img_texture_fallback(renderer, dsc);
|
||||
}
|
||||
bool chroma_keyed = dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
|
||||
uint32_t h = dsc->header.h;
|
||||
uint32_t w = dsc->header.w;
|
||||
void * data = (void *) dsc->img_data;
|
||||
Uint32 rmask = 0x00FF0000;
|
||||
Uint32 gmask = 0x0000FF00;
|
||||
Uint32 bmask = 0x000000FF;
|
||||
Uint32 amask = 0xFF000000;
|
||||
if(chroma_keyed) {
|
||||
amask = 0x00;
|
||||
}
|
||||
SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(data, w, h, LV_COLOR_DEPTH, w * LV_COLOR_DEPTH / 8,
|
||||
rmask, gmask, bmask, amask);
|
||||
SDL_SetColorKey(surface, chroma_keyed, lv_color_to32(LV_COLOR_CHROMA_KEY));
|
||||
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
return texture;
|
||||
}
|
||||
|
||||
static SDL_Texture * upload_img_texture_fallback(SDL_Renderer * renderer, lv_img_decoder_dsc_t * dsc)
|
||||
{
|
||||
lv_coord_t h = dsc->header.h;
|
||||
lv_coord_t w = dsc->header.w;
|
||||
uint8_t * data = lv_mem_buf_get(w * h * sizeof(lv_color_t));
|
||||
for(lv_coord_t y = 0; y < h; y++) {
|
||||
lv_img_decoder_read_line(dsc, 0, y, w, &data[y * w * sizeof(lv_color_t)]);
|
||||
}
|
||||
Uint32 rmask = 0x00FF0000;
|
||||
Uint32 gmask = 0x0000FF00;
|
||||
Uint32 bmask = 0x000000FF;
|
||||
Uint32 amask = 0xFF000000;
|
||||
SDL_Surface * surface = SDL_CreateRGBSurfaceFrom(data, w, h, LV_COLOR_DEPTH, w * LV_COLOR_DEPTH / 8,
|
||||
rmask, gmask, bmask, amask);
|
||||
SDL_SetColorKey(surface, SDL_TRUE, lv_color_to32(LV_COLOR_CHROMA_KEY));
|
||||
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
lv_mem_buf_release(data);
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
332
src/gpu/sdl/lv_gpu_sdl_draw_label.c
Normal file
332
src/gpu/sdl/lv_gpu_sdl_draw_label.c
Normal file
@ -0,0 +1,332 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_draw_label.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "../../draw/lv_draw_label.h"
|
||||
#include "../../font/lv_font_fmt_txt.h"
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "../../misc/lv_utils.h"
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
#include "lv_gpu_sdl_mask.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct lv_sdl_font_atlas_t {
|
||||
SDL_Rect * pos;
|
||||
} lv_sdl_font_atlas_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
const lv_font_t * font_p;
|
||||
uint32_t cmap_index;
|
||||
} lv_font_key_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void draw_letter_masked(SDL_Renderer * renderer, SDL_Texture * atlas, SDL_Rect * src, SDL_Rect * dst,
|
||||
SDL_Rect * clip, lv_color_t color, lv_opa_t opa);
|
||||
|
||||
static void font_atlas_free(lv_sdl_font_atlas_t * atlas);
|
||||
|
||||
static SDL_Texture * font_atlas_bake(SDL_Renderer * renderer, const lv_font_t * font_p, uint32_t cmap_idx,
|
||||
lv_sdl_font_atlas_t * atlas);
|
||||
|
||||
static int32_t unicode_list_compare(const void * ref, const void * element);
|
||||
|
||||
static bool font_cmap_find_index(const lv_font_fmt_txt_dsc_t * dsc, uint32_t letter, uint32_t * cmap_index,
|
||||
uint32_t * char_index);
|
||||
|
||||
static lv_font_key_t font_key_create(const lv_font_t * font_p, uint32_t cmap_index);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_letter(const lv_point_t * pos_p, const lv_area_t * clip_area,
|
||||
const lv_font_t * font_p, uint32_t letter, lv_color_t color, lv_opa_t opa,
|
||||
lv_blend_mode_t blend_mode)
|
||||
{
|
||||
if(opa < LV_OPA_MIN) return;
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
if(font_p == NULL) {
|
||||
LV_LOG_WARN("lv_draw_letter: font is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_font_glyph_dsc_t g;
|
||||
bool g_ret = lv_font_get_glyph_dsc(font_p, &g, letter, '\0');
|
||||
if(g_ret == false) {
|
||||
/*Add warning if the dsc is not found
|
||||
*but do not print warning for non printable ASCII chars (e.g. '\n')*/
|
||||
if(letter >= 0x20 &&
|
||||
letter != 0xf8ff && /*LV_SYMBOL_DUMMY*/
|
||||
letter != 0x200c) { /*ZERO WIDTH NON-JOINER*/
|
||||
LV_LOG_WARN("lv_draw_letter: glyph dsc. not found for U+%X", letter);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*Don't draw anything if the character is empty. E.g. space*/
|
||||
if((g.box_h == 0) || (g.box_w == 0)) return;
|
||||
|
||||
int32_t pos_x = pos_p->x + g.ofs_x;
|
||||
int32_t pos_y = pos_p->y + (font_p->line_height - font_p->base_line) - g.box_h - g.ofs_y;
|
||||
|
||||
/*If the letter is completely out of mask don't draw it*/
|
||||
if(pos_x + g.box_w < clip_area->x1 ||
|
||||
pos_x > clip_area->x2 ||
|
||||
pos_y + g.box_h < clip_area->y1 ||
|
||||
pos_y > clip_area->y2) {
|
||||
return;
|
||||
}
|
||||
lv_area_t dst = {pos_x, pos_y, pos_x + g.box_w - 1, pos_y + g.box_h - 1};
|
||||
uint32_t atlas_index;
|
||||
uint32_t cmap_index;
|
||||
if(!font_cmap_find_index(font_p->dsc, letter, &cmap_index, &atlas_index)) {
|
||||
return;
|
||||
}
|
||||
lv_font_key_t key = font_key_create(font_p, cmap_index);
|
||||
lv_sdl_font_atlas_t * atlas = NULL;
|
||||
bool found = false;
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get_with_userdata(&key, sizeof(key), &found, (void **) &atlas);
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
if(!found) {
|
||||
atlas = SDL_malloc(sizeof(lv_sdl_font_atlas_t));
|
||||
texture = font_atlas_bake(renderer, font_p, cmap_index, atlas);
|
||||
lv_gpu_draw_cache_put_advanced(&key, sizeof(key), texture, atlas, (lv_lru_free_t *) font_atlas_free, 0);
|
||||
}
|
||||
if(texture == NULL) return;
|
||||
SDL_Rect dstrect = {.x = pos_x, .y = pos_y, .w = g.box_w, .h = g.box_h};
|
||||
|
||||
SDL_Rect clip_area_rect;
|
||||
lv_area_to_sdl_rect(clip_area, &clip_area_rect);
|
||||
|
||||
if(lv_draw_mask_is_any(&dst)) {
|
||||
draw_letter_masked(renderer, texture, &atlas->pos[atlas_index], &dstrect, &clip_area_rect, color, opa);
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, opa);
|
||||
SDL_SetTextureColorMod(texture, color.ch.red, color.ch.green, color.ch.blue);
|
||||
SDL_RenderSetClipRect(renderer, &clip_area_rect);
|
||||
SDL_RenderCopy(renderer, texture, &atlas->pos[atlas_index], &dstrect);
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void draw_letter_masked(SDL_Renderer * renderer, SDL_Texture * atlas, SDL_Rect * src, SDL_Rect * dst,
|
||||
SDL_Rect * clip, lv_color_t color, lv_opa_t opa)
|
||||
{
|
||||
SDL_Texture * screen = SDL_GetRenderTarget(renderer);
|
||||
|
||||
lv_area_t mask_area = {.x1 = dst->x, .x2 = dst->x + dst->w - 1, .y1 = dst->y, .y2 = dst->y + dst->h - 1};
|
||||
SDL_Texture * content = lv_gpu_temp_texture_obtain(renderer, dst->w, dst->h);
|
||||
SDL_SetTextureBlendMode(content, SDL_BLENDMODE_NONE);
|
||||
SDL_SetRenderTarget(renderer, content);
|
||||
SDL_RenderSetClipRect(renderer, NULL);
|
||||
|
||||
/* Replace texture with clip mask */
|
||||
SDL_Rect mask_rect = {.w = dst->w, .h = dst->h, .x = 0, .y = 0};
|
||||
SDL_Texture * mask = lv_sdl_gen_mask_texture(renderer, &mask_area, NULL, 0);
|
||||
SDL_SetTextureBlendMode(mask, SDL_BLENDMODE_NONE);
|
||||
SDL_RenderCopy(renderer, mask, NULL, &mask_rect);
|
||||
|
||||
/* Multiply with font atlas */
|
||||
SDL_SetTextureAlphaMod(atlas, 0xFF);
|
||||
SDL_SetTextureColorMod(atlas, 0xFF, 0xFF, 0xFF);
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||
SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO,
|
||||
SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO,
|
||||
SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
||||
SDL_SetTextureBlendMode(atlas, mode);
|
||||
#else
|
||||
SDL_SetTextureBlendMode(atlas, SDL_BLENDMODE_BLEND);
|
||||
#endif
|
||||
SDL_RenderCopy(renderer, atlas, src, &mask_rect);
|
||||
|
||||
/* Draw composited part on screen */
|
||||
SDL_SetTextureBlendMode(content, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(content, opa);
|
||||
SDL_SetTextureColorMod(content, color.ch.red, color.ch.green, color.ch.blue);
|
||||
|
||||
SDL_SetRenderTarget(renderer, screen);
|
||||
SDL_RenderSetClipRect(renderer, clip);
|
||||
SDL_RenderCopy(renderer, content, &mask_rect, dst);
|
||||
SDL_DestroyTexture(mask);
|
||||
}
|
||||
|
||||
SDL_Texture * font_atlas_bake(SDL_Renderer * renderer, const lv_font_t * font_p, uint32_t cmap_idx,
|
||||
lv_sdl_font_atlas_t * atlas)
|
||||
{
|
||||
/* Clear atlas struct */
|
||||
SDL_memset(atlas, 0, sizeof(lv_sdl_font_atlas_t));
|
||||
const lv_font_fmt_txt_dsc_t * dsc = (lv_font_fmt_txt_dsc_t *) font_p->dsc;
|
||||
if(dsc->bitmap_format != LV_FONT_FMT_TXT_PLAIN) {
|
||||
/* we don't support compressed font at this moment */
|
||||
return NULL;
|
||||
}
|
||||
const lv_font_fmt_txt_cmap_t * cmap = &dsc->cmaps[cmap_idx];
|
||||
int glyph_count = cmap->type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY ? cmap->range_length : cmap->list_length;
|
||||
int atlas_size = 0;
|
||||
while(atlas_size * atlas_size < glyph_count) {
|
||||
atlas_size++;
|
||||
}
|
||||
int atlas_w = font_p->line_height * atlas_size;
|
||||
int atlas_h = font_p->line_height * (glyph_count / atlas_size + 1);
|
||||
if(atlas_w > 2048 || atlas_h > 2048) {
|
||||
/*This atlas texture will be too large to load*/
|
||||
return NULL;
|
||||
}
|
||||
lv_opa_t * s1 = lv_mem_buf_get(atlas_w * atlas_h * sizeof(lv_opa_t));
|
||||
atlas->pos = SDL_malloc(sizeof(SDL_Rect) * glyph_count);
|
||||
int atlas_y = 0;
|
||||
int atlas_x = 0;
|
||||
for(int i = 0; i < glyph_count; i++) {
|
||||
int glyph_idx = cmap->glyph_id_start + i;
|
||||
switch(cmap->type) {
|
||||
case LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL: {
|
||||
const uint8_t * gid_ofs_8 = cmap->glyph_id_ofs_list;
|
||||
glyph_idx = gid_ofs_8[i];
|
||||
break;
|
||||
}
|
||||
case LV_FONT_FMT_TXT_CMAP_SPARSE_FULL: {
|
||||
const uint16_t * gid_ofs_16 = cmap->glyph_id_ofs_list;
|
||||
glyph_idx = gid_ofs_16[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
const lv_font_fmt_txt_glyph_dsc_t * gd = &dsc->glyph_dsc[glyph_idx];
|
||||
if(atlas_x + gd->box_w >= atlas_w) {
|
||||
atlas_x = 0;
|
||||
atlas_y += font_p->line_height;
|
||||
}
|
||||
SDL_Rect * rect = &atlas->pos[i];
|
||||
rect->x = atlas_x;
|
||||
rect->y = atlas_y;
|
||||
rect->w = gd->box_w;
|
||||
rect->h = gd->box_h;
|
||||
if(gd->box_w <= 0 || gd->box_h <= 0) {
|
||||
continue;
|
||||
}
|
||||
lv_sdl_to_8bpp(&s1[rect->y * atlas_w + rect->x], &dsc->glyph_bitmap[gd->bitmap_index], rect->w,
|
||||
rect->h, atlas_w, dsc->bpp);
|
||||
atlas_x += gd->box_w;
|
||||
}
|
||||
SDL_Surface * mask = lv_sdl_create_mask_surface(s1, atlas_w, atlas_h, atlas_w);
|
||||
SDL_Texture * result = SDL_CreateTextureFromSurface(renderer, mask);
|
||||
SDL_FreeSurface(mask);
|
||||
lv_mem_buf_release(s1);
|
||||
|
||||
if(!result) {
|
||||
if(atlas->pos) {
|
||||
SDL_free(atlas->pos);
|
||||
}
|
||||
SDL_memset(atlas, 0, sizeof(lv_sdl_font_atlas_t));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void font_atlas_free(lv_sdl_font_atlas_t * atlas)
|
||||
{
|
||||
if(atlas->pos) {
|
||||
SDL_free(atlas->pos);
|
||||
}
|
||||
SDL_free(atlas);
|
||||
}
|
||||
|
||||
static bool font_cmap_find_index(const lv_font_fmt_txt_dsc_t * dsc, uint32_t letter, uint32_t * cmap_index,
|
||||
uint32_t * char_index)
|
||||
{
|
||||
for(int i = 0; i < dsc->cmap_num; i++) {
|
||||
const lv_font_fmt_txt_cmap_t * cmap = &dsc->cmaps[i];
|
||||
/*Relative code point*/
|
||||
uint32_t rcp = letter - cmap->range_start;
|
||||
if(rcp > cmap->range_length) continue;
|
||||
if(cmap->type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY) {
|
||||
*cmap_index = i;
|
||||
*char_index = rcp;
|
||||
return true;
|
||||
}
|
||||
else if(cmap->type == LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL) {
|
||||
*cmap_index = i;
|
||||
*char_index = rcp;
|
||||
return true;
|
||||
}
|
||||
else if(cmap->type == LV_FONT_FMT_TXT_CMAP_SPARSE_TINY) {
|
||||
uint16_t key = rcp;
|
||||
uint16_t * p = _lv_utils_bsearch(&key, cmap->unicode_list, cmap->list_length,
|
||||
sizeof(cmap->unicode_list[0]), unicode_list_compare);
|
||||
if(!p) continue;
|
||||
|
||||
*cmap_index = i;
|
||||
*char_index = p - cmap->unicode_list;
|
||||
return true;
|
||||
}
|
||||
else if(cmap->type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL) {
|
||||
uint16_t key = rcp;
|
||||
uint16_t * p = _lv_utils_bsearch(&key, cmap->unicode_list, cmap->list_length,
|
||||
sizeof(cmap->unicode_list[0]), unicode_list_compare);
|
||||
if(!p) continue;
|
||||
|
||||
*cmap_index = i;
|
||||
*char_index = p - cmap->unicode_list;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t unicode_list_compare(const void * ref, const void * element)
|
||||
{
|
||||
return ((int32_t)(*(uint16_t *) ref)) - ((int32_t)(*(uint16_t *) element));
|
||||
}
|
||||
|
||||
static lv_font_key_t font_key_create(const lv_font_t * font_p, uint32_t cmap_index)
|
||||
{
|
||||
lv_font_key_t key;
|
||||
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
|
||||
SDL_memset(&key, 0, sizeof(key));
|
||||
key.magic = LV_GPU_CACHE_KEY_MAGIC_FONT;
|
||||
key.font_p = font_p;
|
||||
key.cmap_index = cmap_index;
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
158
src/gpu/sdl/lv_gpu_sdl_draw_line.c
Normal file
158
src/gpu/sdl/lv_gpu_sdl_draw_line.c
Normal file
@ -0,0 +1,158 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_draw_line.c
|
||||
*
|
||||
* This implementation does not functioning properly so it's not enabled
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
#include "lv_gpu_sdl_lru.h"
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
#include "lv_gpu_sdl_mask.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
lv_coord_t length;
|
||||
lv_coord_t thickness;
|
||||
} lv_draw_line_key_t;
|
||||
|
||||
static lv_draw_line_key_t line_key_create(lv_coord_t length, lv_coord_t thickness);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_line2(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip,
|
||||
const lv_draw_line_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->width == 0) return;
|
||||
if(dsc->opa <= LV_OPA_MIN) return;
|
||||
|
||||
if(point1->x == point2->x && point1->y == point2->y) return;
|
||||
|
||||
lv_area_t clip_line;
|
||||
clip_line.x1 = LV_MIN(point1->x, point2->x) - dsc->width / 2;
|
||||
clip_line.x2 = LV_MAX(point1->x, point2->x) + dsc->width / 2;
|
||||
clip_line.y1 = LV_MIN(point1->y, point2->y) - dsc->width / 2;
|
||||
clip_line.y2 = LV_MAX(point1->y, point2->y) + dsc->width / 2;
|
||||
|
||||
if(!_lv_area_intersect(&clip_line, &clip_line, clip)) return;
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
SDL_Color line_color;
|
||||
lv_color_to_sdl_color(&dsc->color, &line_color);
|
||||
|
||||
int length = lv_sdl_round(SDL_sqrt(SDL_pow(point2->y - point1->y + 1, 2) + SDL_pow(point2->x - point1->x + 1, 2)));
|
||||
lv_coord_t thickness = dsc->width;
|
||||
lv_draw_line_key_t key = line_key_create(length, thickness);
|
||||
lv_area_t coords = {1, 1, length, dsc->width};
|
||||
lv_area_t tex_coords;
|
||||
lv_area_copy(&tex_coords, &coords);
|
||||
lv_area_increase(&tex_coords, 1, 1);
|
||||
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get(&key, sizeof(key), NULL);
|
||||
|
||||
if(texture == NULL) {
|
||||
lv_draw_mask_radius_param_t mask_rout_param;
|
||||
lv_draw_mask_radius_init(&mask_rout_param, &coords, 0, false);
|
||||
int16_t mask_rout_id = lv_draw_mask_add(&mask_rout_param, NULL);
|
||||
texture = lv_sdl_gen_mask_texture(renderer, &tex_coords, &mask_rout_id, 1);
|
||||
lv_draw_mask_remove_id(mask_rout_id);
|
||||
SDL_assert(texture);
|
||||
lv_gpu_draw_cache_put(&key, sizeof(key), texture);
|
||||
}
|
||||
double angle = SDL_atan2(point2->y - point1->y, point2->x - point1->x) * 180 / M_PI;
|
||||
|
||||
SDL_Rect clip_rect;
|
||||
lv_area_to_sdl_rect(&clip_line, &clip_rect);
|
||||
|
||||
|
||||
SDL_Texture * screen = SDL_GetRenderTarget(renderer);
|
||||
|
||||
SDL_Texture * content = lv_gpu_temp_texture_obtain(renderer, clip_rect.w, clip_rect.h);
|
||||
SDL_SetTextureBlendMode(content, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderTarget(renderer, content);
|
||||
SDL_RenderSetClipRect(renderer, NULL);
|
||||
|
||||
// /* Replace texture with clip mask */
|
||||
SDL_Rect mask_rect = {.w = clip_rect.w, .h = clip_rect.h, .x = 0, .y = 0};
|
||||
// SDL_Texture *mask = lv_sdl_gen_mask_texture(renderer, &clip_line, NULL, 0);
|
||||
// SDL_SetTextureBlendMode(mask, SDL_BLENDMODE_NONE);
|
||||
//// SDL_RenderCopy(renderer, mask, NULL, &mask_rect);
|
||||
//
|
||||
// SDL_SetTextureAlphaMod(texture, 0xFF);
|
||||
// SDL_SetTextureColorMod(texture, 0xFF, 0xFF, 0xFF);
|
||||
//#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||
// SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO,
|
||||
// SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO,
|
||||
// SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
||||
// SDL_SetTextureBlendMode(texture, mode);
|
||||
// SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
|
||||
//#else
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_NONE);
|
||||
//#endif
|
||||
|
||||
SDL_Rect coords_rect;
|
||||
lv_area_to_sdl_rect(&tex_coords, &coords_rect);
|
||||
coords_rect.x = 0 - coords_rect.h / 2;
|
||||
coords_rect.y = 0 - coords_rect.h / 2;
|
||||
SDL_Point center = {coords_rect.h / 2, coords_rect.h / 2};
|
||||
SDL_RenderCopyEx(renderer, texture, NULL, &coords_rect, angle, ¢er, SDL_FLIP_NONE);
|
||||
//
|
||||
// /* Draw composited part on screen */
|
||||
SDL_SetTextureBlendMode(content, SDL_BLENDMODE_NONE);
|
||||
SDL_SetTextureAlphaMod(content, dsc->opa);
|
||||
SDL_SetTextureColorMod(content, line_color.r, line_color.g, line_color.b);
|
||||
//
|
||||
SDL_SetRenderTarget(renderer, screen);
|
||||
// SDL_RenderSetClipRect(renderer, &clip_rect);
|
||||
SDL_RenderSetClipRect(renderer, NULL);
|
||||
SDL_RenderCopy(renderer, content, &mask_rect, &clip_rect);
|
||||
// SDL_DestroyTexture(mask);
|
||||
}
|
||||
|
||||
static lv_draw_line_key_t line_key_create(lv_coord_t length, lv_coord_t thickness)
|
||||
{
|
||||
lv_draw_line_key_t key;
|
||||
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
|
||||
SDL_memset(&key, 0, sizeof(key));
|
||||
key.magic = LV_GPU_CACHE_KEY_MAGIC_LINE;
|
||||
key.length = length;
|
||||
key.thickness = thickness;
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
733
src/gpu/sdl/lv_gpu_sdl_draw_rect.c
Normal file
733
src/gpu/sdl/lv_gpu_sdl_draw_rect.c
Normal file
@ -0,0 +1,733 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_draw_rect.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "../../draw/lv_draw_rect.h"
|
||||
#include "../../hal/lv_hal_disp.h"
|
||||
#include "../../core/lv_refr.h"
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
#include "lv_gpu_sdl_lru.h"
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
#include "lv_gpu_sdl_mask.h"
|
||||
#include "lv_gpu_sdl_stack_blur.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
lv_coord_t radius;
|
||||
lv_coord_t size;
|
||||
} lv_draw_rect_bg_key_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
lv_coord_t radius;
|
||||
lv_coord_t size;
|
||||
lv_coord_t blur;
|
||||
} lv_draw_rect_shadow_key_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
lv_coord_t rout, rin;
|
||||
lv_coord_t thickness;
|
||||
lv_coord_t size;
|
||||
lv_border_side_t side;
|
||||
} lv_draw_rect_border_key_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void draw_bg_color(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip,
|
||||
const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void draw_border(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void draw_shadow(SDL_Renderer * renderer, const lv_area_t * coords, const lv_area_t * clip,
|
||||
const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void draw_border_generic(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_coord_t rout,
|
||||
lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode);
|
||||
|
||||
static void draw_border_simple(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color,
|
||||
lv_opa_t opa);
|
||||
|
||||
static void draw_rect_masked(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void draw_rect_masked_simple(const lv_area_t * coords, const lv_area_t * mask, const lv_draw_rect_dsc_t * dsc);
|
||||
|
||||
static void frag_render_corners(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
|
||||
const lv_area_t * coords);
|
||||
|
||||
static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
|
||||
const lv_area_t * coords);
|
||||
|
||||
static void frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
|
||||
const lv_area_t * coords);
|
||||
|
||||
static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size);
|
||||
|
||||
static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur);
|
||||
|
||||
static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, lv_coord_t thickness,
|
||||
lv_coord_t size, lv_border_side_t side);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#define SKIP_BORDER(dsc) ((dsc)->border_opa <= LV_OPA_MIN || (dsc)->border_width == 0 || (dsc)->border_side == LV_BORDER_SIDE_NONE || (dsc)->border_post)
|
||||
#define SKIP_SHADOW(dsc) ((dsc)->shadow_width == 0 || (dsc)->shadow_opa <= LV_OPA_MIN || ((dsc)->shadow_width == 1 && (dsc)->shadow_spread <= 0 && (dsc)->shadow_ofs_x == 0 && (dsc)->shadow_ofs_y == 0))
|
||||
#define SKIP_IMAGE(dsc) ((dsc)->bg_img_src == NULL || (dsc)->bg_img_opa <= LV_OPA_MIN)
|
||||
#define SKIP_OUTLINE(dsc) ((dsc)->outline_opa <= LV_OPA_MIN || (dsc)->outline_width == 0)
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_draw_rect(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
lv_area_t draw_area;
|
||||
bool has_draw_content = _lv_area_intersect(&draw_area, coords, clip);
|
||||
|
||||
if(lv_draw_mask_is_any(&draw_area)) {
|
||||
draw_rect_masked(coords, clip, dsc);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
|
||||
SDL_Rect clip_rect;
|
||||
lv_area_to_sdl_rect(clip, &clip_rect);
|
||||
SDL_RenderSetClipRect(renderer, &clip_rect);
|
||||
draw_shadow(renderer, coords, clip, dsc);
|
||||
/* Shadows and outlines will also draw in extended area */
|
||||
if(has_draw_content) {
|
||||
draw_bg_color(renderer, coords, dsc);
|
||||
draw_bg_img(coords, clip, dsc);
|
||||
draw_border(renderer, coords, dsc);
|
||||
}
|
||||
draw_outline(coords, clip, dsc);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void draw_bg_color(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
SDL_Color bg_color;
|
||||
lv_color_to_sdl_color(&dsc->bg_color, &bg_color);
|
||||
lv_coord_t radius = dsc->radius;
|
||||
if(radius > 0) {
|
||||
/*A small texture with a quarter of the rect is enough*/
|
||||
lv_coord_t bg_w = lv_area_get_width(coords), bg_h = lv_area_get_height(coords), bg_min = LV_MIN(bg_w, bg_h);
|
||||
/* If size isn't times of 2, increase 1 px */
|
||||
lv_coord_t min_half = bg_min % 2 == 0 ? bg_min / 2 : bg_min / 2 + 1;
|
||||
lv_coord_t frag_size = radius == LV_RADIUS_CIRCLE ? min_half : LV_MIN(radius + 1, min_half);
|
||||
lv_draw_rect_bg_key_t key = rect_bg_key_create(radius, frag_size);
|
||||
lv_area_t coords_frag;
|
||||
lv_area_copy(&coords_frag, coords);
|
||||
lv_area_set_width(&coords_frag, frag_size);
|
||||
lv_area_set_height(&coords_frag, frag_size);
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get(&key, sizeof(key), NULL);
|
||||
if(texture == NULL) {
|
||||
lv_draw_mask_radius_param_t mask_rout_param;
|
||||
lv_draw_mask_radius_init(&mask_rout_param, coords, radius, false);
|
||||
int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
|
||||
texture = lv_sdl_gen_mask_texture(renderer, &coords_frag, &mask_id, 1);
|
||||
lv_draw_mask_remove_id(mask_id);
|
||||
SDL_assert(texture);
|
||||
lv_gpu_draw_cache_put(&key, sizeof(key), texture);
|
||||
}
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, dsc->bg_opa);
|
||||
SDL_SetTextureColorMod(texture, bg_color.r, bg_color.g, bg_color.b);
|
||||
frag_render_corners(renderer, texture, frag_size, coords);
|
||||
frag_render_borders(renderer, texture, frag_size, coords);
|
||||
frag_render_center(renderer, texture, frag_size, coords);
|
||||
}
|
||||
else {
|
||||
SDL_Rect coords_rect;
|
||||
lv_area_to_sdl_rect(coords, &coords_rect);
|
||||
SDL_SetRenderDrawColor(renderer, bg_color.r, bg_color.g, bg_color.b, dsc->bg_opa);
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_RenderFillRect(renderer, &coords_rect);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_bg_img(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
if(SKIP_IMAGE(dsc)) return;
|
||||
|
||||
lv_img_src_t src_type = lv_img_src_get_type(dsc->bg_img_src);
|
||||
if(src_type == LV_IMG_SRC_SYMBOL) {
|
||||
lv_point_t size;
|
||||
lv_txt_get_size(&size, dsc->bg_img_src, dsc->bg_img_symbol_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE);
|
||||
lv_area_t a;
|
||||
a.x1 = coords->x1 + lv_area_get_width(coords) / 2 - size.x / 2;
|
||||
a.x2 = a.x1 + size.x - 1;
|
||||
a.y1 = coords->y1 + lv_area_get_height(coords) / 2 - size.y / 2;
|
||||
a.y2 = a.y1 + size.y - 1;
|
||||
|
||||
lv_draw_label_dsc_t label_draw_dsc;
|
||||
lv_draw_label_dsc_init(&label_draw_dsc);
|
||||
label_draw_dsc.font = dsc->bg_img_symbol_font;
|
||||
label_draw_dsc.color = dsc->bg_img_recolor;
|
||||
label_draw_dsc.opa = dsc->bg_img_opa;
|
||||
lv_draw_label(&a, clip, &label_draw_dsc, dsc->bg_img_src, NULL);
|
||||
}
|
||||
else {
|
||||
lv_img_header_t header;
|
||||
size_t key_size;
|
||||
lv_gpu_sdl_cache_key_head_img_t * key = lv_gpu_sdl_img_cache_key_create(dsc->bg_img_src, 0, &key_size);
|
||||
bool key_found;
|
||||
lv_img_header_t * cache_header = NULL;
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get_with_userdata(key, key_size, &key_found, (void **) &cache_header);
|
||||
SDL_free(key);
|
||||
if(texture) {
|
||||
header = *cache_header;
|
||||
}
|
||||
else if(key_found || lv_img_decoder_get_info(dsc->bg_img_src, &header) != LV_RES_OK) {
|
||||
/* When cache hit but with negative result, use default decoder. If still fail, return.*/
|
||||
LV_LOG_WARN("Couldn't read the background image");
|
||||
return;
|
||||
}
|
||||
|
||||
lv_draw_img_dsc_t img_dsc;
|
||||
lv_draw_img_dsc_init(&img_dsc);
|
||||
img_dsc.blend_mode = dsc->blend_mode;
|
||||
img_dsc.recolor = dsc->bg_img_recolor;
|
||||
img_dsc.recolor_opa = dsc->bg_img_recolor_opa;
|
||||
img_dsc.opa = dsc->bg_img_opa;
|
||||
|
||||
/*Center align*/
|
||||
if(dsc->bg_img_tiled == false) {
|
||||
lv_area_t area;
|
||||
area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - header.w / 2;
|
||||
area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - header.h / 2;
|
||||
area.x2 = area.x1 + header.w - 1;
|
||||
area.y2 = area.y1 + header.h - 1;
|
||||
|
||||
lv_draw_img(&area, clip, dsc->bg_img_src, &img_dsc);
|
||||
}
|
||||
else {
|
||||
lv_area_t area;
|
||||
area.y1 = coords->y1;
|
||||
area.y2 = area.y1 + header.h - 1;
|
||||
|
||||
for(; area.y1 <= coords->y2; area.y1 += header.h, area.y2 += header.h) {
|
||||
|
||||
area.x1 = coords->x1;
|
||||
area.x2 = area.x1 + header.w - 1;
|
||||
for(; area.x1 <= coords->x2; area.x1 += header.w, area.x2 += header.w) {
|
||||
lv_draw_img(&area, clip, dsc->bg_img_src, &img_dsc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_shadow(SDL_Renderer * renderer, const lv_area_t * coords, const lv_area_t * clip,
|
||||
const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
/*Check whether the shadow is visible*/
|
||||
if(SKIP_SHADOW(dsc)) return;
|
||||
|
||||
lv_coord_t sw = dsc->shadow_width;
|
||||
|
||||
lv_area_t core_area;
|
||||
core_area.x1 = coords->x1 + dsc->shadow_ofs_x - dsc->shadow_spread;
|
||||
core_area.x2 = coords->x2 + dsc->shadow_ofs_x + dsc->shadow_spread;
|
||||
core_area.y1 = coords->y1 + dsc->shadow_ofs_y - dsc->shadow_spread;
|
||||
core_area.y2 = coords->y2 + dsc->shadow_ofs_y + dsc->shadow_spread;
|
||||
|
||||
lv_area_t shadow_area;
|
||||
shadow_area.x1 = core_area.x1 - sw / 2 - 1;
|
||||
shadow_area.x2 = core_area.x2 + sw / 2 + 1;
|
||||
shadow_area.y1 = core_area.y1 - sw / 2 - 1;
|
||||
shadow_area.y2 = core_area.y2 + sw / 2 + 1;
|
||||
|
||||
lv_opa_t opa = dsc->shadow_opa;
|
||||
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
/*Get clipped draw area which is the real draw area.
|
||||
*It is always the same or inside `shadow_area`*/
|
||||
lv_area_t draw_area;
|
||||
if(!_lv_area_intersect(&draw_area, &shadow_area, clip)) return;
|
||||
|
||||
SDL_Rect core_area_rect;
|
||||
lv_area_to_sdl_rect(&shadow_area, &core_area_rect);
|
||||
|
||||
lv_coord_t radius = dsc->radius;
|
||||
lv_coord_t sh_width = lv_area_get_width(&core_area);
|
||||
lv_coord_t sh_height = lv_area_get_height(&core_area);
|
||||
lv_coord_t sh_min = LV_MIN(sh_width, sh_height);
|
||||
/* If size isn't times of 2, increase 1 px */
|
||||
lv_coord_t min_half = sh_min % 2 == 0 ? sh_min / 2 : sh_min / 2 + 1;
|
||||
/* No matter how big the shadow is, what we need is just a corner */
|
||||
lv_coord_t frag_size = radius == LV_RADIUS_CIRCLE ? min_half : LV_MIN(radius + 1, min_half);
|
||||
/* This is how big the corner is after blurring */
|
||||
lv_coord_t blur_frag_size = frag_size + sw + 2;
|
||||
|
||||
lv_draw_rect_shadow_key_t key = rect_shadow_key_create(radius, frag_size, sw);
|
||||
|
||||
lv_area_t blur_frag;
|
||||
lv_area_copy(&blur_frag, &shadow_area);
|
||||
lv_area_set_width(&blur_frag, blur_frag_size * 2);
|
||||
lv_area_set_height(&blur_frag, blur_frag_size * 2);
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get(&key, sizeof(key), NULL);
|
||||
if(texture == NULL) {
|
||||
lv_draw_mask_radius_param_t mask_rout_param;
|
||||
lv_draw_mask_radius_init(&mask_rout_param, &core_area, radius, false);
|
||||
int16_t mask_id = lv_draw_mask_add(&mask_rout_param, NULL);
|
||||
lv_opa_t * mask_buf = lv_draw_mask_dump(&blur_frag, &mask_id, 1);
|
||||
lv_stack_blur_grayscale(mask_buf, lv_area_get_width(&blur_frag), lv_area_get_height(&blur_frag), sw / 2 + 1);
|
||||
texture = lv_sdl_create_mask_texture(renderer, mask_buf, blur_frag_size, blur_frag_size,
|
||||
lv_area_get_width(&blur_frag));
|
||||
lv_mem_buf_release(mask_buf);
|
||||
lv_draw_mask_remove_id(mask_id);
|
||||
SDL_assert(texture);
|
||||
lv_gpu_draw_cache_put(&key, sizeof(key), texture);
|
||||
}
|
||||
|
||||
SDL_Color shadow_color;
|
||||
lv_color_to_sdl_color(&dsc->shadow_color, &shadow_color);
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, opa);
|
||||
SDL_SetTextureColorMod(texture, shadow_color.r, shadow_color.g, shadow_color.b);
|
||||
|
||||
frag_render_corners(renderer, texture, blur_frag_size, &shadow_area);
|
||||
frag_render_borders(renderer, texture, blur_frag_size, &shadow_area);
|
||||
frag_render_center(renderer, texture, blur_frag_size, &shadow_area);
|
||||
}
|
||||
|
||||
|
||||
static void draw_border(SDL_Renderer * renderer, const lv_area_t * coords, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
if(SKIP_BORDER(dsc)) return;
|
||||
|
||||
SDL_Color border_color;
|
||||
lv_color_to_sdl_color(&dsc->border_color, &border_color);
|
||||
|
||||
|
||||
if(dsc->border_side != LV_BORDER_SIDE_FULL) {
|
||||
SDL_SetRenderDrawColor(renderer, border_color.r, border_color.g, border_color.b, dsc->border_opa);
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
for(int w = 0; w <= dsc->border_width; w++) {
|
||||
if(dsc->border_side & LV_BORDER_SIDE_TOP) {
|
||||
SDL_RenderDrawLine(renderer, coords->x1, coords->y1 + w, coords->x2, coords->y1 + w);
|
||||
}
|
||||
if(dsc->border_side & LV_BORDER_SIDE_BOTTOM) {
|
||||
SDL_RenderDrawLine(renderer, coords->x1, coords->y2 - w, coords->x2, coords->y2 - w);
|
||||
}
|
||||
if(dsc->border_side & LV_BORDER_SIDE_LEFT) {
|
||||
SDL_RenderDrawLine(renderer, coords->x1 + w, coords->y1, coords->x1 + w, coords->y2);
|
||||
}
|
||||
if(dsc->border_side & LV_BORDER_SIDE_RIGHT) {
|
||||
SDL_RenderDrawLine(renderer, coords->x2 - w, coords->y1, coords->x2 - w, coords->y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
int32_t coords_w = lv_area_get_width(coords);
|
||||
int32_t coords_h = lv_area_get_height(coords);
|
||||
int32_t rout = dsc->radius;
|
||||
int32_t short_side = LV_MIN(coords_w, coords_h);
|
||||
if(rout > short_side >> 1) rout = short_side >> 1;
|
||||
|
||||
/*Get the inner area*/
|
||||
lv_area_t area_inner;
|
||||
lv_area_copy(&area_inner, coords);
|
||||
area_inner.x1 += ((dsc->border_side & LV_BORDER_SIDE_LEFT) ? dsc->border_width : -(dsc->border_width + rout));
|
||||
area_inner.x2 -= ((dsc->border_side & LV_BORDER_SIDE_RIGHT) ? dsc->border_width : -(dsc->border_width + rout));
|
||||
area_inner.y1 += ((dsc->border_side & LV_BORDER_SIDE_TOP) ? dsc->border_width : -(dsc->border_width + rout));
|
||||
area_inner.y2 -= ((dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? dsc->border_width : -(dsc->border_width + rout));
|
||||
|
||||
lv_coord_t rin = rout - dsc->border_width;
|
||||
if(rin < 0) rin = 0;
|
||||
draw_border_generic(coords, &area_inner, rout, rin, dsc->border_color, dsc->border_opa,
|
||||
dsc->blend_mode);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_outline(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
if(SKIP_OUTLINE(dsc)) return;
|
||||
|
||||
lv_opa_t opa = dsc->outline_opa;
|
||||
|
||||
if(opa > LV_OPA_MAX) opa = LV_OPA_COVER;
|
||||
|
||||
/*Get the inner radius*/
|
||||
lv_area_t area_inner;
|
||||
lv_area_copy(&area_inner, coords);
|
||||
|
||||
/*Extend the outline into the background area if it's overlapping the edge*/
|
||||
lv_coord_t pad = (dsc->outline_pad == 0 ? (dsc->outline_pad - 1) : dsc->outline_pad);
|
||||
area_inner.x1 -= pad;
|
||||
area_inner.y1 -= pad;
|
||||
area_inner.x2 += pad;
|
||||
area_inner.y2 += pad;
|
||||
|
||||
lv_area_t area_outer;
|
||||
lv_area_copy(&area_outer, &area_inner);
|
||||
|
||||
area_outer.x1 -= dsc->outline_width;
|
||||
area_outer.x2 += dsc->outline_width;
|
||||
area_outer.y1 -= dsc->outline_width;
|
||||
area_outer.y2 += dsc->outline_width;
|
||||
|
||||
lv_area_t draw_area;
|
||||
if(!_lv_area_intersect(&draw_area, &area_outer, clip)) return;
|
||||
|
||||
int32_t inner_w = lv_area_get_width(&area_inner);
|
||||
int32_t inner_h = lv_area_get_height(&area_inner);
|
||||
int32_t rin = dsc->radius;
|
||||
int32_t short_side = LV_MIN(inner_w, inner_h);
|
||||
if(rin > short_side >> 1) rin = short_side >> 1;
|
||||
|
||||
lv_coord_t rout = rin + dsc->outline_width;
|
||||
|
||||
draw_border_generic(&area_outer, &area_inner, rout, rin, dsc->outline_color, dsc->outline_opa,
|
||||
dsc->blend_mode);
|
||||
}
|
||||
|
||||
static void draw_border_generic(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_coord_t rout,
|
||||
lv_coord_t rin, lv_color_t color, lv_opa_t opa, lv_blend_mode_t blend_mode)
|
||||
{
|
||||
opa = opa >= LV_OPA_COVER ? LV_OPA_COVER : opa;
|
||||
|
||||
if(rout == 0 || rin == 0) {
|
||||
draw_border_simple(outer_area, inner_area, color, opa);
|
||||
return;
|
||||
}
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
lv_coord_t border_width = lv_area_get_width(outer_area);
|
||||
lv_coord_t border_height = lv_area_get_height(outer_area);
|
||||
lv_coord_t border_min = LV_MIN(border_width, border_height);
|
||||
lv_coord_t min_half = border_min % 2 == 0 ? border_min / 2 : border_min / 2 + 1;
|
||||
lv_coord_t frag_size = rout == LV_RADIUS_CIRCLE ? min_half : LV_MIN(rout + 1, min_half);
|
||||
lv_draw_rect_border_key_t key = rect_border_key_create(rout, rin, inner_area->x1 - outer_area->x1 + 1,
|
||||
frag_size, LV_BORDER_SIDE_FULL);
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get(&key, sizeof(key), NULL);
|
||||
if(texture == NULL) {
|
||||
/*Create mask for the outer area*/
|
||||
int16_t mask_ids[2] = {LV_MASK_ID_INV, LV_MASK_ID_INV};
|
||||
lv_draw_mask_radius_param_t mask_rout_param;
|
||||
if(rout > 0) {
|
||||
lv_draw_mask_radius_init(&mask_rout_param, outer_area, rout, false);
|
||||
mask_ids[0] = lv_draw_mask_add(&mask_rout_param, NULL);
|
||||
}
|
||||
|
||||
/*Create mask for the inner mask*/
|
||||
if(rin < 0) rin = 0;
|
||||
lv_draw_mask_radius_param_t mask_rin_param;
|
||||
lv_draw_mask_radius_init(&mask_rin_param, inner_area, rin, true);
|
||||
mask_ids[1] = lv_draw_mask_add(&mask_rin_param, NULL);
|
||||
|
||||
lv_area_t frag_area;
|
||||
lv_area_copy(&frag_area, outer_area);
|
||||
lv_area_set_width(&frag_area, frag_size);
|
||||
lv_area_set_height(&frag_area, frag_size);
|
||||
|
||||
texture = lv_sdl_gen_mask_texture(renderer, &frag_area, mask_ids, 2);
|
||||
|
||||
lv_draw_mask_remove_id(mask_ids[1]);
|
||||
lv_draw_mask_remove_id(mask_ids[0]);
|
||||
SDL_assert(texture);
|
||||
lv_gpu_draw_cache_put(&key, sizeof(key), texture);
|
||||
}
|
||||
|
||||
SDL_Rect outer_rect;
|
||||
lv_area_to_sdl_rect(outer_area, &outer_rect);
|
||||
SDL_Color color_sdl;
|
||||
lv_color_to_sdl_color(&color, &color_sdl);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, opa);
|
||||
SDL_SetTextureColorMod(texture, color_sdl.r, color_sdl.g, color_sdl.b);
|
||||
|
||||
frag_render_corners(renderer, texture, frag_size, outer_area);
|
||||
frag_render_borders(renderer, texture, frag_size, outer_area);
|
||||
}
|
||||
|
||||
static void draw_border_simple(const lv_area_t * outer_area, const lv_area_t * inner_area, lv_color_t color,
|
||||
lv_opa_t opa)
|
||||
{
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
SDL_Color color_sdl;
|
||||
lv_color_to_sdl_color(&color, &color_sdl);
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, color_sdl.r, color_sdl.g, color_sdl.b, opa);
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_Rect simple_rect;
|
||||
simple_rect.w = inner_area->x2 - outer_area->x1 + 1;
|
||||
simple_rect.h = inner_area->y1 - outer_area->y1 + 1;
|
||||
/*Top border*/
|
||||
simple_rect.x = outer_area->x1;
|
||||
simple_rect.y = outer_area->y1;
|
||||
SDL_RenderFillRect(renderer, &simple_rect);
|
||||
/*Bottom border*/
|
||||
simple_rect.x = inner_area->x1;
|
||||
simple_rect.y = inner_area->y2;
|
||||
SDL_RenderFillRect(renderer, &simple_rect);
|
||||
|
||||
simple_rect.w = inner_area->x1 - outer_area->x1 + 1;
|
||||
simple_rect.h = inner_area->y2 - outer_area->y1 + 1;
|
||||
/*Left border*/
|
||||
simple_rect.x = outer_area->x1;
|
||||
simple_rect.y = inner_area->y1;
|
||||
SDL_RenderFillRect(renderer, &simple_rect);
|
||||
/*Right border*/
|
||||
simple_rect.x = inner_area->x2;
|
||||
simple_rect.y = outer_area->y1;
|
||||
SDL_RenderFillRect(renderer, &simple_rect);
|
||||
|
||||
}
|
||||
|
||||
static void frag_render_corners(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
lv_coord_t bg_w = lv_area_get_width(coords);
|
||||
lv_coord_t bg_h = lv_area_get_height(coords);
|
||||
SDL_Rect srcrect = {0, 0, frag_size, frag_size};
|
||||
SDL_Rect dstrect = {.x = coords->x1, .y = coords->y1, .w = frag_size, .h = frag_size};
|
||||
/* Upper left */
|
||||
SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_NONE);
|
||||
/* Upper right, clip right edge if too big */
|
||||
srcrect.w = dstrect.w = LV_MIN(frag_size, bg_w - frag_size);
|
||||
dstrect.x = coords->x2 - srcrect.w + 1;
|
||||
SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_HORIZONTAL);
|
||||
/* Lower right, clip bottom edge if too big */
|
||||
srcrect.h = dstrect.h = LV_MIN(frag_size, bg_h - frag_size);
|
||||
dstrect.y = coords->y2 - srcrect.h + 1;
|
||||
SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_HORIZONTAL | SDL_FLIP_VERTICAL);
|
||||
/* Lower left, right edge should not be clipped */
|
||||
srcrect.w = dstrect.w = frag_size;
|
||||
dstrect.x = coords->x1;
|
||||
SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_VERTICAL);
|
||||
}
|
||||
|
||||
static void frag_render_borders(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size,
|
||||
const lv_area_t * coords)
|
||||
{
|
||||
lv_coord_t bg_w = lv_area_get_width(coords);
|
||||
lv_coord_t bg_h = lv_area_get_height(coords);
|
||||
SDL_Rect srcrect;
|
||||
SDL_Rect dstrect;
|
||||
/* For top/bottom edges, stretch pixels on the right */
|
||||
srcrect.h = dstrect.h = frag_size;
|
||||
dstrect.w = bg_w - frag_size * 2;
|
||||
/* Has space to fill */
|
||||
if(dstrect.w > 0 && dstrect.h > 0) {
|
||||
srcrect.w = 1;
|
||||
srcrect.y = 0;
|
||||
srcrect.x = frag_size - 1;
|
||||
dstrect.x = coords->x1 + frag_size;
|
||||
/* Top edge */
|
||||
dstrect.y = coords->y1;
|
||||
SDL_RenderCopy(renderer, frag, &srcrect, &dstrect);
|
||||
/* Bottom edge */
|
||||
dstrect.y = coords->y2 - frag_size + 1;
|
||||
if(bg_h < frag_size * 2) {
|
||||
/* Bottom edge will overlap with top, so decrease it by 1 px */
|
||||
srcrect.h = dstrect.h = frag_size - 1;
|
||||
dstrect.y += 1;
|
||||
}
|
||||
if(srcrect.h > 0) {
|
||||
SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_VERTICAL);
|
||||
}
|
||||
}
|
||||
/* For left/right edges, stretch pixels on the bottom */
|
||||
srcrect.w = dstrect.w = frag_size;
|
||||
dstrect.h = bg_h - frag_size * 2;
|
||||
if(dstrect.w > 0 && dstrect.h > 0) {
|
||||
srcrect.h = 1;
|
||||
srcrect.x = 0;
|
||||
srcrect.y = frag_size - 1;
|
||||
dstrect.y = coords->y1 + frag_size;
|
||||
/* Left edge */
|
||||
dstrect.x = coords->x1;
|
||||
SDL_RenderCopy(renderer, frag, &srcrect, &dstrect);
|
||||
/* Right edge */
|
||||
dstrect.x = coords->x2 - frag_size + 1;
|
||||
if(bg_w < frag_size * 2) {
|
||||
/* Right edge will overlap with left, so decrease it by 1 px */
|
||||
srcrect.w = dstrect.w = frag_size - 1;
|
||||
dstrect.x += 1;
|
||||
}
|
||||
if(srcrect.w > 0) {
|
||||
SDL_RenderCopyEx(renderer, frag, &srcrect, &dstrect, 0, NULL, SDL_FLIP_HORIZONTAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
frag_render_center(SDL_Renderer * renderer, SDL_Texture * frag, lv_coord_t frag_size, const lv_area_t * coords)
|
||||
{
|
||||
lv_coord_t bg_w = lv_area_get_width(coords);
|
||||
lv_coord_t bg_h = lv_area_get_height(coords);
|
||||
SDL_Rect dstrect = {coords->x1 + frag_size, coords->y1 + frag_size, bg_w - frag_size * 2, bg_h - frag_size * 2};
|
||||
if(dstrect.w > 0 && dstrect.h > 0) {
|
||||
SDL_Rect srcrect = {frag_size - 1, frag_size - 1, 1, 1};
|
||||
SDL_RenderCopy(renderer, frag, &srcrect, &dstrect);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_rect_masked(const lv_area_t * coords, const lv_area_t * clip, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
if(dsc->radius <= 0 && SKIP_BORDER(dsc) && SKIP_SHADOW(dsc) && SKIP_IMAGE(dsc) && SKIP_OUTLINE(dsc)) {
|
||||
draw_rect_masked_simple(coords, clip, dsc);
|
||||
return;
|
||||
}
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
SDL_Texture * screen = SDL_GetRenderTarget(renderer);
|
||||
|
||||
lv_coord_t sw = dsc->shadow_width;
|
||||
|
||||
lv_area_t sh_area = *coords;
|
||||
lv_area_increase(&sh_area, dsc->shadow_spread + sw / 2 + 1, dsc->shadow_spread + sw / 2 + 1);
|
||||
lv_area_move(&sh_area, dsc->shadow_ofs_x, dsc->shadow_ofs_y);
|
||||
|
||||
lv_coord_t draw_w = lv_area_get_width(&sh_area);
|
||||
lv_coord_t draw_h = lv_area_get_height(&sh_area);
|
||||
/* Render drawing area to an offscreen texture */
|
||||
SDL_Texture * content = lv_gpu_temp_texture_obtain(renderer, draw_w, draw_h);
|
||||
SDL_assert(content);
|
||||
SDL_SetTextureColorMod(content, 0xFF, 0xFF, 0xFF);
|
||||
SDL_SetTextureAlphaMod(content, 0xFF);
|
||||
SDL_SetTextureBlendMode(content, SDL_BLENDMODE_BLEND);
|
||||
|
||||
SDL_SetRenderTarget(renderer, content);
|
||||
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0x00);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderSetClipRect(renderer, NULL);
|
||||
lv_area_t content_coords;
|
||||
lv_area_copy(&content_coords, coords);
|
||||
lv_area_move(&content_coords, -sh_area.x1, -sh_area.y1);
|
||||
|
||||
draw_shadow(renderer, &content_coords, clip, dsc);
|
||||
draw_bg_color(renderer, &content_coords, dsc);
|
||||
draw_bg_img(&content_coords, clip, dsc);
|
||||
draw_border(renderer, &content_coords, dsc);
|
||||
draw_outline(&content_coords, clip, dsc);
|
||||
|
||||
SDL_Texture * clip_mask = lv_sdl_gen_mask_texture(renderer, &sh_area, NULL, 0);
|
||||
SDL_Rect src_rect = {.w = draw_w, .h = draw_h, .x = 0, .y = 0};
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 6)
|
||||
SDL_BlendMode mode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE,
|
||||
SDL_BLENDOPERATION_ADD, SDL_BLENDFACTOR_ZERO,
|
||||
SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDOPERATION_ADD);
|
||||
SDL_SetTextureBlendMode(clip_mask, mode);
|
||||
SDL_RenderCopy(renderer, clip_mask, NULL, &src_rect);
|
||||
#endif
|
||||
|
||||
SDL_Rect mask_rect;
|
||||
SDL_Rect draw_rect;
|
||||
lv_area_to_sdl_rect(&sh_area, &draw_rect);
|
||||
lv_area_to_sdl_rect(clip, &mask_rect);
|
||||
|
||||
SDL_SetRenderTarget(renderer, screen);
|
||||
SDL_RenderSetClipRect(renderer, &mask_rect);
|
||||
SDL_RenderCopy(renderer, content, &src_rect, &draw_rect);
|
||||
SDL_DestroyTexture(clip_mask);
|
||||
}
|
||||
|
||||
static void draw_rect_masked_simple(const lv_area_t * coords, const lv_area_t * mask, const lv_draw_rect_dsc_t * dsc)
|
||||
{
|
||||
SDL_Color bg_color;
|
||||
lv_color_to_sdl_color(&dsc->bg_color, &bg_color);
|
||||
|
||||
lv_disp_t * disp = _lv_refr_get_disp_refreshing();
|
||||
SDL_Renderer * renderer = (SDL_Renderer *) disp->driver->user_data;
|
||||
|
||||
SDL_Surface * indexed = lv_sdl_apply_mask_surface(coords, NULL, 0);
|
||||
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed);
|
||||
|
||||
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureAlphaMod(texture, dsc->bg_opa);
|
||||
SDL_SetTextureColorMod(texture, bg_color.r, bg_color.g, bg_color.b);
|
||||
|
||||
SDL_Rect coords_rect, mask_rect;
|
||||
lv_area_to_sdl_rect(coords, &coords_rect);
|
||||
lv_area_to_sdl_rect(mask, &mask_rect);
|
||||
|
||||
SDL_RenderSetClipRect(renderer, &mask_rect);
|
||||
SDL_RenderCopy(renderer, texture, NULL, &coords_rect);
|
||||
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_FreeSurface(indexed);
|
||||
}
|
||||
|
||||
static lv_draw_rect_bg_key_t rect_bg_key_create(lv_coord_t radius, lv_coord_t size)
|
||||
{
|
||||
lv_draw_rect_bg_key_t key;
|
||||
SDL_memset(&key, 0, sizeof(key));
|
||||
key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BG;
|
||||
key.radius = radius;
|
||||
key.size = size;
|
||||
return key;
|
||||
}
|
||||
|
||||
static lv_draw_rect_shadow_key_t rect_shadow_key_create(lv_coord_t radius, lv_coord_t size, lv_coord_t blur)
|
||||
{
|
||||
lv_draw_rect_shadow_key_t key;
|
||||
SDL_memset(&key, 0, sizeof(key));
|
||||
key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW;
|
||||
key.radius = radius;
|
||||
key.size = size;
|
||||
key.blur = blur;
|
||||
return key;
|
||||
}
|
||||
|
||||
static lv_draw_rect_border_key_t rect_border_key_create(lv_coord_t rout, lv_coord_t rin, lv_coord_t thickness,
|
||||
lv_coord_t size, lv_border_side_t side)
|
||||
{
|
||||
lv_draw_rect_border_key_t key;
|
||||
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
|
||||
SDL_memset(&key, 0, sizeof(key));
|
||||
key.magic = LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER;
|
||||
key.rout = rout;
|
||||
key.rin = rin;
|
||||
key.thickness = thickness;
|
||||
key.size = size;
|
||||
key.side = side;
|
||||
return key;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
375
src/gpu/sdl/lv_gpu_sdl_lru.c
Normal file
375
src/gpu/sdl/lv_gpu_sdl_lru.c
Normal file
@ -0,0 +1,375 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_lru.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "lv_gpu_sdl_lru.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* MurmurHash2
|
||||
* @author Austin Appleby
|
||||
* @see http://sites.google.com/site/murmurhash/
|
||||
*/
|
||||
static uint32_t lv_lru_hash(lv_lru_t * cache, const void * key, uint32_t key_length);
|
||||
|
||||
/** compare a key against an existing item's key */
|
||||
static int lv_lru_cmp_keys(lruc_item * item, const void * key, uint32_t key_length);
|
||||
|
||||
/** remove an item and push it to the free items queue */
|
||||
static void lv_lru_remove_item(lv_lru_t * cache, lruc_item * prev, lruc_item * item, uint32_t hash_index);
|
||||
|
||||
/**
|
||||
* remove the least recently used item
|
||||
*
|
||||
* @todo we can optimise this by finding the n lru items, where n = required_space / average_length
|
||||
*/
|
||||
static void lv_lru_remove_lru_item(lv_lru_t * cache);
|
||||
|
||||
/** pop an existing item off the free queue, or create a new one */
|
||||
static lruc_item * lv_lru_pop_or_create_item(lv_lru_t * cache);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/* error helpers */
|
||||
#define error_for(conditions, error) if(conditions) {return error;}
|
||||
#define test_for_missing_cache() error_for(!cache, LV_LRU_MISSING_CACHE)
|
||||
#define test_for_missing_key() error_for(!key, LV_LRU_MISSING_KEY)
|
||||
#define test_for_missing_value() error_for(!value || value_length == 0, LV_LRU_MISSING_VALUE)
|
||||
#define test_for_value_too_large() error_for(value_length > cache->total_memory, LV_LRU_VALUE_TOO_LARGE)
|
||||
|
||||
/* lock helpers */
|
||||
#define lock_cache() if(SDL_LockMutex(cache->mutex)) {\
|
||||
perror("LRU Cache unable to obtain mutex lock");\
|
||||
return LV_LRU_LOCK_ERROR;\
|
||||
}
|
||||
|
||||
#define unlock_cache() if(SDL_UnlockMutex(cache->mutex)) {\
|
||||
perror("LRU Cache unable to release mutex lock");\
|
||||
return LV_LRU_LOCK_ERROR;\
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_lru_t * lv_lru_new(uint64_t cache_size, uint32_t average_length, lv_lru_free_t * value_free,
|
||||
lv_lru_free_t * key_free)
|
||||
{
|
||||
// create the cache
|
||||
lv_lru_t * cache = (lv_lru_t *) calloc(sizeof(lv_lru_t), 1);
|
||||
if(!cache) {
|
||||
perror("LRU Cache unable to create cache object");
|
||||
return NULL;
|
||||
}
|
||||
cache->hash_table_size = cache_size / average_length;
|
||||
cache->average_item_length = average_length;
|
||||
cache->free_memory = cache_size;
|
||||
cache->total_memory = cache_size;
|
||||
cache->seed = time(NULL);
|
||||
cache->value_free = value_free ? value_free : free;
|
||||
cache->key_free = key_free ? key_free : free;
|
||||
|
||||
// size the hash table to a guestimate of the number of slots required (assuming a perfect hash)
|
||||
cache->items = (lruc_item **) calloc(sizeof(lruc_item *), cache->hash_table_size);
|
||||
if(!cache->items) {
|
||||
perror("LRU Cache unable to create cache hash table");
|
||||
free(cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// all cache calls are guarded by a mutex
|
||||
cache->mutex = SDL_CreateMutex();
|
||||
if(!cache->mutex) {
|
||||
perror("LRU Cache unable to initialise mutex");
|
||||
free(cache->items);
|
||||
free(cache);
|
||||
return NULL;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
lruc_error lv_lru_free(lv_lru_t * cache)
|
||||
{
|
||||
test_for_missing_cache();
|
||||
|
||||
// free each of the cached items, and the hash table
|
||||
lruc_item * item = NULL, *next = NULL;
|
||||
uint32_t i = 0;
|
||||
if(cache->items) {
|
||||
for(; i < cache->hash_table_size; i++) {
|
||||
item = cache->items[i];
|
||||
while(item) {
|
||||
next = (lruc_item *) item->next;
|
||||
cache->value_free(item->value);
|
||||
cache->key_free(item->key);
|
||||
cache->free_memory += item->value_length;
|
||||
free(item);
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
free(cache->items);
|
||||
}
|
||||
|
||||
if(cache->free_items) {
|
||||
item = cache->free_items;
|
||||
while(item) {
|
||||
next = (lruc_item *) item->next;
|
||||
free(item);
|
||||
item = next;
|
||||
}
|
||||
}
|
||||
|
||||
// free the cache
|
||||
if(cache->mutex) {
|
||||
SDL_DestroyMutex(cache->mutex);
|
||||
}
|
||||
free(cache);
|
||||
|
||||
return LV_LRU_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
lruc_error lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, void * value, size_t value_length)
|
||||
{
|
||||
test_for_missing_cache();
|
||||
test_for_missing_key();
|
||||
test_for_missing_value();
|
||||
test_for_value_too_large();
|
||||
lock_cache();
|
||||
|
||||
// see if the key already exists
|
||||
uint32_t hash_index = lv_lru_hash(cache, key, key_length);
|
||||
int64_t required = 0;
|
||||
lruc_item * item = NULL, *prev = NULL;
|
||||
item = cache->items[hash_index];
|
||||
|
||||
while(item && lv_lru_cmp_keys(item, key, key_length)) {
|
||||
prev = item;
|
||||
item = (lruc_item *) item->next;
|
||||
}
|
||||
|
||||
if(item) {
|
||||
// update the value and value_lengths
|
||||
required = (int)(value_length - item->value_length);
|
||||
cache->value_free(item->value);
|
||||
item->value = value;
|
||||
item->value_length = value_length;
|
||||
|
||||
}
|
||||
else {
|
||||
// insert a new item
|
||||
item = lv_lru_pop_or_create_item(cache);
|
||||
item->value = value;
|
||||
item->key = malloc(key_length);
|
||||
memcpy(item->key, key, key_length);
|
||||
item->value_length = value_length;
|
||||
item->key_length = key_length;
|
||||
required = value_length;
|
||||
|
||||
if(prev)
|
||||
prev->next = item;
|
||||
else
|
||||
cache->items[hash_index] = item;
|
||||
}
|
||||
item->access_count = ++cache->access_count;
|
||||
|
||||
// remove as many items as necessary to free enough space
|
||||
if(required > 0 && required > cache->free_memory) {
|
||||
while(cache->free_memory < required)
|
||||
lv_lru_remove_lru_item(cache);
|
||||
}
|
||||
cache->free_memory -= required;
|
||||
unlock_cache();
|
||||
return LV_LRU_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
lruc_error lv_lru_get(lv_lru_t * cache, const void * key, size_t key_size, void ** value)
|
||||
{
|
||||
test_for_missing_cache();
|
||||
test_for_missing_key();
|
||||
lock_cache();
|
||||
|
||||
// loop until we find the item, or hit the end of a chain
|
||||
uint32_t hash_index = lv_lru_hash(cache, key, key_size);
|
||||
lruc_item * item = cache->items[hash_index];
|
||||
|
||||
while(item && lv_lru_cmp_keys(item, key, key_size))
|
||||
item = (lruc_item *) item->next;
|
||||
|
||||
if(item) {
|
||||
*value = item->value;
|
||||
item->access_count = ++cache->access_count;
|
||||
}
|
||||
else {
|
||||
*value = NULL;
|
||||
}
|
||||
|
||||
unlock_cache();
|
||||
return LV_LRU_NO_ERROR;
|
||||
}
|
||||
|
||||
lruc_error lv_lru_delete(lv_lru_t * cache, const void * key, size_t key_size)
|
||||
{
|
||||
test_for_missing_cache();
|
||||
test_for_missing_key();
|
||||
lock_cache();
|
||||
|
||||
// loop until we find the item, or hit the end of a chain
|
||||
lruc_item * item = NULL, *prev = NULL;
|
||||
uint32_t hash_index = lv_lru_hash(cache, key, key_size);
|
||||
item = cache->items[hash_index];
|
||||
|
||||
while(item && lv_lru_cmp_keys(item, key, key_size)) {
|
||||
prev = item;
|
||||
item = (lruc_item *) item->next;
|
||||
}
|
||||
|
||||
if(item) {
|
||||
lv_lru_remove_item(cache, prev, item, hash_index);
|
||||
}
|
||||
|
||||
unlock_cache();
|
||||
return LV_LRU_NO_ERROR;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static uint32_t lv_lru_hash(lv_lru_t * cache, const void * key, uint32_t key_length)
|
||||
{
|
||||
uint32_t m = 0x5bd1e995;
|
||||
uint32_t r = 24;
|
||||
uint32_t h = cache->seed ^ key_length;
|
||||
char * data = (char *) key;
|
||||
|
||||
while(key_length >= 4) {
|
||||
uint32_t k = *(uint32_t *) data;
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
h *= m;
|
||||
h ^= k;
|
||||
data += 4;
|
||||
key_length -= 4;
|
||||
}
|
||||
|
||||
switch(key_length) {
|
||||
case 3:
|
||||
h ^= data[2] << 16;
|
||||
case 2:
|
||||
h ^= data[1] << 8;
|
||||
case 1:
|
||||
h ^= data[0];
|
||||
h *= m;
|
||||
};
|
||||
|
||||
h ^= h >> 13;
|
||||
h *= m;
|
||||
h ^= h >> 15;
|
||||
return h % cache->hash_table_size;
|
||||
}
|
||||
|
||||
static int lv_lru_cmp_keys(lruc_item * item, const void * key, uint32_t key_length)
|
||||
{
|
||||
if(key_length != item->key_length)
|
||||
return 1;
|
||||
else
|
||||
return memcmp(key, item->key, key_length);
|
||||
}
|
||||
|
||||
static void lv_lru_remove_item(lv_lru_t * cache, lruc_item * prev, lruc_item * item, uint32_t hash_index)
|
||||
{
|
||||
if(prev)
|
||||
prev->next = item->next;
|
||||
else
|
||||
cache->items[hash_index] = (lruc_item *) item->next;
|
||||
|
||||
// free memory and update the free memory counter
|
||||
cache->free_memory += item->value_length;
|
||||
cache->value_free(item->value);
|
||||
cache->key_free(item->key);
|
||||
|
||||
// push the item to the free items queue
|
||||
memset(item, 0, sizeof(lruc_item));
|
||||
item->next = cache->free_items;
|
||||
cache->free_items = item;
|
||||
}
|
||||
|
||||
static void lv_lru_remove_lru_item(lv_lru_t * cache)
|
||||
{
|
||||
lruc_item * min_item = NULL, *min_prev = NULL;
|
||||
lruc_item * item = NULL, *prev = NULL;
|
||||
uint32_t i = 0, min_index = -1;
|
||||
uint64_t min_access_count = -1;
|
||||
|
||||
for(; i < cache->hash_table_size; i++) {
|
||||
item = cache->items[i];
|
||||
prev = NULL;
|
||||
|
||||
while(item) {
|
||||
if(item->access_count < min_access_count || min_access_count == -1) {
|
||||
min_access_count = item->access_count;
|
||||
min_item = item;
|
||||
min_prev = prev;
|
||||
min_index = i;
|
||||
}
|
||||
prev = item;
|
||||
item = item->next;
|
||||
}
|
||||
}
|
||||
|
||||
if(min_item)
|
||||
lv_lru_remove_item(cache, min_prev, min_item, min_index);
|
||||
}
|
||||
|
||||
static lruc_item * lv_lru_pop_or_create_item(lv_lru_t * cache)
|
||||
{
|
||||
lruc_item * item = NULL;
|
||||
|
||||
if(cache->free_items) {
|
||||
item = cache->free_items;
|
||||
cache->free_items = item->next;
|
||||
memset(item, 0, sizeof(lruc_item));
|
||||
}
|
||||
else {
|
||||
item = (lruc_item *) calloc(sizeof(lruc_item), 1);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
90
src/gpu/sdl/lv_gpu_sdl_lru.h
Normal file
90
src/gpu/sdl/lv_gpu_sdl_lru.h
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_lru.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_LRU_H
|
||||
#define LV_LRU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef enum {
|
||||
LV_LRU_NO_ERROR = 0,
|
||||
LV_LRU_MISSING_CACHE,
|
||||
LV_LRU_MISSING_KEY,
|
||||
LV_LRU_MISSING_VALUE,
|
||||
LV_LRU_LOCK_ERROR,
|
||||
LV_LRU_VALUE_TOO_LARGE
|
||||
} lruc_error;
|
||||
|
||||
typedef void (lv_lru_free_t)(void * v);
|
||||
|
||||
typedef struct lruc_item {
|
||||
void * value;
|
||||
void * key;
|
||||
size_t value_length;
|
||||
size_t key_length;
|
||||
uint64_t access_count;
|
||||
struct lruc_item * next;
|
||||
} lruc_item;
|
||||
|
||||
typedef struct {
|
||||
lruc_item ** items;
|
||||
uint64_t access_count;
|
||||
uint64_t free_memory;
|
||||
uint64_t total_memory;
|
||||
uint64_t average_item_length;
|
||||
uint32_t hash_table_size;
|
||||
time_t seed;
|
||||
lv_lru_free_t * value_free;
|
||||
lv_lru_free_t * key_free;
|
||||
lruc_item * free_items;
|
||||
SDL_mutex * mutex;
|
||||
} lv_lru_t;
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
lv_lru_t * lv_lru_new(uint64_t cache_size, uint32_t average_length, lv_lru_free_t * value_free,
|
||||
lv_lru_free_t * key_free);
|
||||
|
||||
lruc_error lv_lru_free(lv_lru_t * cache);
|
||||
|
||||
lruc_error lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, void * value, size_t value_length);
|
||||
|
||||
lruc_error lv_lru_get(lv_lru_t * cache, const void * key, size_t key_size, void ** value);
|
||||
|
||||
lruc_error lv_lru_delete(lv_lru_t * cache, const void * key, size_t key_size);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_LRU_H*/
|
110
src/gpu/sdl/lv_gpu_sdl_mask.c
Normal file
110
src/gpu/sdl/lv_gpu_sdl_mask.c
Normal file
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_mask.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "../../draw/lv_draw_mask.h"
|
||||
#include "../../misc/lv_mem.h"
|
||||
#include "lv_gpu_sdl_mask.h"
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
SDL_Surface * lv_sdl_create_mask_surface(lv_opa_t * pixels, lv_coord_t width, lv_coord_t height, lv_coord_t stride)
|
||||
{
|
||||
SDL_Surface * indexed = SDL_CreateRGBSurfaceFrom(pixels, width, height, 8, stride, 0, 0, 0, 0);
|
||||
SDL_SetSurfacePalette(indexed, lv_sdl_get_grayscale_palette(8));
|
||||
SDL_Surface * converted = SDL_ConvertSurfaceFormat(indexed, SDL_PIXELFORMAT_ARGB8888, 0);
|
||||
SDL_FreeSurface(indexed);
|
||||
return converted;
|
||||
}
|
||||
|
||||
SDL_Texture * lv_sdl_create_mask_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width,
|
||||
lv_coord_t height, lv_coord_t stride)
|
||||
{
|
||||
SDL_Surface * indexed = lv_sdl_create_mask_surface(pixels, width, height, stride);
|
||||
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed);
|
||||
SDL_FreeSurface(indexed);
|
||||
return texture;
|
||||
}
|
||||
|
||||
lv_opa_t * lv_draw_mask_dump(const lv_area_t * coords, const int16_t * ids, int16_t ids_count)
|
||||
{
|
||||
SDL_assert(coords->x2 >= coords->x1);
|
||||
SDL_assert(coords->y2 >= coords->y1);
|
||||
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
|
||||
lv_opa_t * mask_buf = lv_mem_buf_get(w * h);
|
||||
for(lv_coord_t y = 0; y < h; y++) {
|
||||
lv_opa_t * line_buf = &mask_buf[y * w];
|
||||
lv_memset_ff(line_buf, w);
|
||||
lv_coord_t abs_x = (lv_coord_t) coords->x1, abs_y = (lv_coord_t)(y + coords->y1), len = (lv_coord_t) w;
|
||||
lv_draw_mask_res_t res;
|
||||
if(ids) {
|
||||
res = lv_draw_mask_apply_ids(line_buf, abs_x, abs_y, len, ids, ids_count);
|
||||
}
|
||||
else {
|
||||
res = lv_draw_mask_apply(line_buf, abs_x, abs_y, len);
|
||||
}
|
||||
if(res == LV_DRAW_MASK_RES_TRANSP) {
|
||||
lv_memset_00(line_buf, w);
|
||||
}
|
||||
}
|
||||
return mask_buf;
|
||||
}
|
||||
|
||||
SDL_Surface * lv_sdl_apply_mask_surface(const lv_area_t * coords, const int16_t * ids, int16_t ids_count)
|
||||
{
|
||||
lv_coord_t w = lv_area_get_width(coords), h = lv_area_get_height(coords);
|
||||
|
||||
lv_opa_t * mask_buf = lv_draw_mask_dump(coords, ids, ids_count);
|
||||
lv_mem_buf_release(mask_buf);
|
||||
return lv_sdl_create_mask_surface(mask_buf, w, h, w);
|
||||
}
|
||||
|
||||
SDL_Texture * lv_sdl_gen_mask_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids,
|
||||
int16_t ids_count)
|
||||
{
|
||||
SDL_Surface * indexed = lv_sdl_apply_mask_surface(coords, ids, ids_count);
|
||||
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, indexed);
|
||||
SDL_FreeSurface(indexed);
|
||||
return texture;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
57
src/gpu/sdl/lv_gpu_sdl_mask.h
Normal file
57
src/gpu/sdl/lv_gpu_sdl_mask.h
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_mask.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GPU_SDL_MASK_H
|
||||
#define LV_GPU_SDL_MASK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
|
||||
#include "../../misc/lv_area.h"
|
||||
#include "../../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
|
||||
lv_opa_t * lv_draw_mask_dump(const lv_area_t * coords, const int16_t * ids, int16_t ids_count);
|
||||
|
||||
SDL_Surface * lv_sdl_create_mask_surface(lv_opa_t * pixels, lv_coord_t width, lv_coord_t height, lv_coord_t stride);
|
||||
|
||||
SDL_Texture * lv_sdl_create_mask_texture(SDL_Renderer * renderer, lv_opa_t * pixels, lv_coord_t width,
|
||||
lv_coord_t height, lv_coord_t stride);
|
||||
|
||||
SDL_Surface * lv_sdl_apply_mask_surface(const lv_area_t * coords, const int16_t * ids, int16_t ids_count);
|
||||
|
||||
SDL_Texture *
|
||||
lv_sdl_gen_mask_texture(SDL_Renderer * renderer, const lv_area_t * coords, const int16_t * ids, int16_t ids_count);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GPU_SDL_MASK_H*/
|
247
src/gpu/sdl/lv_gpu_sdl_stack_blur.c
Normal file
247
src/gpu/sdl/lv_gpu_sdl_stack_blur.c
Normal file
@ -0,0 +1,247 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_stack_blur.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_gpu_sdl_stack_blur.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void
|
||||
stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core, int step);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
// Based heavily on http://vitiy.info/Code/stackblur.cpp
|
||||
// See http://vitiy.info/stackblur-algorithm-multi-threaded-blur-for-cpp/
|
||||
// Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
|
||||
|
||||
static unsigned short const stackblur_mul[255] = {
|
||||
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
|
||||
454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
|
||||
482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
|
||||
437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
|
||||
497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
|
||||
320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
|
||||
446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
|
||||
329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
|
||||
505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
|
||||
399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
|
||||
324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
|
||||
268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
|
||||
451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
|
||||
385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
|
||||
332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
|
||||
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259
|
||||
};
|
||||
|
||||
static unsigned char const stackblur_shr[255] = {
|
||||
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
|
||||
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
|
||||
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
|
||||
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
|
||||
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
|
||||
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
|
||||
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r)
|
||||
{
|
||||
stack_blur_job(buf, w, h, r, 1, 0, 1);
|
||||
stack_blur_job(buf, w, h, r, 1, 0, 2);
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void stack_blur_job(lv_opa_t * src, unsigned int w, unsigned int h, unsigned int radius, int cores, int core,
|
||||
int step)
|
||||
{
|
||||
if(radius < 2 || radius > 254) {
|
||||
/* Silently ignore bad radius */
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int x, y, xp, yp, i;
|
||||
unsigned int sp;
|
||||
unsigned int stack_start;
|
||||
unsigned char * stack_ptr;
|
||||
|
||||
lv_opa_t * src_ptr;
|
||||
lv_opa_t * dst_ptr;
|
||||
|
||||
unsigned long sum_r;
|
||||
unsigned long sum_in_r;
|
||||
unsigned long sum_out_r;
|
||||
|
||||
unsigned int wm = w - 1;
|
||||
unsigned int hm = h - 1;
|
||||
unsigned int stride = w;
|
||||
unsigned int div = (radius * 2) + 1;
|
||||
unsigned int mul_sum = stackblur_mul[radius];
|
||||
unsigned char shr_sum = stackblur_shr[radius];
|
||||
unsigned char stack[254 * 2 + 1];
|
||||
|
||||
if(step == 1) {
|
||||
unsigned int minY = core * h / cores;
|
||||
unsigned int maxY = (core + 1) * h / cores;
|
||||
|
||||
for(y = minY; y < maxY; y++) {
|
||||
sum_r =
|
||||
sum_in_r =
|
||||
sum_out_r = 0;
|
||||
|
||||
src_ptr = src + stride * y; // start of line (0,y)
|
||||
|
||||
for(i = 0; i <= radius; i++) {
|
||||
stack_ptr = &stack[i];
|
||||
stack_ptr[0] = src_ptr[0];
|
||||
sum_r += src_ptr[0] * (i + 1);
|
||||
sum_out_r += src_ptr[0];
|
||||
}
|
||||
|
||||
|
||||
for(i = 1; i <= radius; i++) {
|
||||
if(i <= wm) src_ptr += 1;
|
||||
stack_ptr = &stack[i + radius];
|
||||
stack_ptr[0] = src_ptr[0];
|
||||
sum_r += src_ptr[0] * (radius + 1 - i);
|
||||
sum_in_r += src_ptr[0];
|
||||
}
|
||||
|
||||
|
||||
sp = radius;
|
||||
xp = radius;
|
||||
if(xp > wm) xp = wm;
|
||||
src_ptr = src + (xp + y * w); // img.pix_ptr(xp, y);
|
||||
dst_ptr = src + y * stride; // img.pix_ptr(0, y);
|
||||
for(x = 0; x < w; x++) {
|
||||
dst_ptr[0] = LV_CLAMP((sum_r * mul_sum) >> shr_sum, 0, 255);
|
||||
dst_ptr += 1;
|
||||
|
||||
sum_r -= sum_out_r;
|
||||
|
||||
stack_start = sp + div - radius;
|
||||
if(stack_start >= div) stack_start -= div;
|
||||
stack_ptr = &stack[stack_start];
|
||||
|
||||
sum_out_r -= stack_ptr[0];
|
||||
|
||||
if(xp < wm) {
|
||||
src_ptr += 1;
|
||||
++xp;
|
||||
}
|
||||
|
||||
stack_ptr[0] = src_ptr[0];
|
||||
|
||||
sum_in_r += src_ptr[0];
|
||||
sum_r += sum_in_r;
|
||||
|
||||
++sp;
|
||||
if(sp >= div) sp = 0;
|
||||
stack_ptr = &stack[sp];
|
||||
|
||||
sum_out_r += stack_ptr[0];
|
||||
sum_in_r -= stack_ptr[0];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// step 2
|
||||
if(step == 2) {
|
||||
unsigned int minX = core * w / cores;
|
||||
unsigned int maxX = (core + 1) * w / cores;
|
||||
|
||||
for(x = minX; x < maxX; x++) {
|
||||
sum_r =
|
||||
sum_in_r =
|
||||
sum_out_r = 0;
|
||||
|
||||
src_ptr = src + x; // x,0
|
||||
for(i = 0; i <= radius; i++) {
|
||||
stack_ptr = &stack[i];
|
||||
stack_ptr[0] = src_ptr[0];
|
||||
sum_r += src_ptr[0] * (i + 1);
|
||||
sum_out_r += src_ptr[0];
|
||||
}
|
||||
for(i = 1; i <= radius; i++) {
|
||||
if(i <= hm) src_ptr += stride; // +stride
|
||||
|
||||
stack_ptr = &stack[i + radius];
|
||||
stack_ptr[0] = src_ptr[0];
|
||||
sum_r += src_ptr[0] * (radius + 1 - i);
|
||||
sum_in_r += src_ptr[0];
|
||||
}
|
||||
|
||||
sp = radius;
|
||||
yp = radius;
|
||||
if(yp > hm) yp = hm;
|
||||
src_ptr = src + (x + yp * w); // img.pix_ptr(x, yp);
|
||||
dst_ptr = src + x; // img.pix_ptr(x, 0);
|
||||
for(y = 0; y < h; y++) {
|
||||
dst_ptr[0] = LV_CLAMP((sum_r * mul_sum) >> shr_sum, 0, 255);
|
||||
dst_ptr += stride;
|
||||
|
||||
sum_r -= sum_out_r;
|
||||
|
||||
stack_start = sp + div - radius;
|
||||
if(stack_start >= div) stack_start -= div;
|
||||
stack_ptr = &stack[stack_start];
|
||||
|
||||
sum_out_r -= stack_ptr[0];
|
||||
|
||||
if(yp < hm) {
|
||||
src_ptr += stride; // stride
|
||||
++yp;
|
||||
}
|
||||
|
||||
stack_ptr[0] = src_ptr[0];
|
||||
|
||||
sum_in_r += src_ptr[0];
|
||||
sum_r += sum_in_r;
|
||||
|
||||
++sp;
|
||||
if(sp >= div) sp = 0;
|
||||
stack_ptr = &stack[sp];
|
||||
|
||||
sum_out_r += stack_ptr[0];
|
||||
sum_in_r -= stack_ptr[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
42
src/gpu/sdl/lv_gpu_sdl_stack_blur.h
Normal file
42
src/gpu/sdl/lv_gpu_sdl_stack_blur.h
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_stack_blur.h
|
||||
*
|
||||
*/
|
||||
#ifndef LV_GPU_SDL_STACK_BLUR_H
|
||||
#define LV_GPU_SDL_STACK_BLUR_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#include "../../misc/lv_color.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void lv_stack_blur_grayscale(lv_opa_t * buf, uint16_t w, uint16_t h, uint16_t r);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GPU_SDL_STACK_BLUR_H*/
|
197
src/gpu/sdl/lv_gpu_sdl_texture_cache.c
Normal file
197
src/gpu/sdl/lv_gpu_sdl_texture_cache.c
Normal file
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_texture_cache.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "lv_gpu_sdl_texture_cache.h"
|
||||
|
||||
#include "../../misc/lv_log.h"
|
||||
#include "../../draw/lv_draw_label.h"
|
||||
#include "../../draw/lv_draw_img.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
SDL_Texture * texture;
|
||||
void * userdata;
|
||||
lv_lru_free_t * userdata_free;
|
||||
lv_gpu_sdl_cache_flag_t flags;
|
||||
} draw_cache_value_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
} temp_texture_key_t;
|
||||
|
||||
typedef struct {
|
||||
lv_coord_t width, height;
|
||||
} temp_texture_userdata_t;
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
static void draw_cache_free_value(draw_cache_value_t *);
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static lv_lru_t * lv_sdl_texture_cache;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void _lv_gpu_sdl_texture_cache_init()
|
||||
{
|
||||
lv_sdl_texture_cache = lv_lru_new(1024 * 1024 * 8, 65536, (lv_lru_free_t *) draw_cache_free_value,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void _lv_gpu_sdl_texture_cache_deinit()
|
||||
{
|
||||
lv_lru_free(lv_sdl_texture_cache);
|
||||
}
|
||||
|
||||
SDL_Texture * lv_gpu_draw_cache_get(const void * key, size_t key_length, bool * found)
|
||||
{
|
||||
return lv_gpu_draw_cache_get_with_userdata(key, key_length, found, NULL);
|
||||
}
|
||||
|
||||
SDL_Texture * lv_gpu_draw_cache_get_with_userdata(const void * key, size_t key_length, bool * found, void ** userdata)
|
||||
{
|
||||
draw_cache_value_t * value = NULL;
|
||||
lv_lru_get(lv_sdl_texture_cache, key, key_length, (void **) &value);
|
||||
if(!value) {
|
||||
if(found) {
|
||||
*found = false;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
if(userdata) {
|
||||
*userdata = value->userdata;
|
||||
}
|
||||
}
|
||||
if(found) {
|
||||
*found = true;
|
||||
}
|
||||
return value->texture;
|
||||
}
|
||||
|
||||
void lv_gpu_draw_cache_put(const void * key, size_t key_length, SDL_Texture * texture)
|
||||
{
|
||||
lv_gpu_draw_cache_put_advanced(key, key_length, texture, NULL, NULL, 0);
|
||||
}
|
||||
|
||||
void lv_gpu_draw_cache_put_advanced(const void * key, size_t key_length, SDL_Texture * texture, void * userdata,
|
||||
lv_lru_free_t userdata_free, lv_gpu_sdl_cache_flag_t flags)
|
||||
{
|
||||
draw_cache_value_t * value = SDL_malloc(sizeof(draw_cache_value_t));
|
||||
value->texture = texture;
|
||||
value->userdata = userdata;
|
||||
value->userdata_free = userdata_free;
|
||||
value->flags = flags;
|
||||
if(!texture) {
|
||||
lv_lru_set(lv_sdl_texture_cache, key, key_length, value, 1);
|
||||
return;
|
||||
}
|
||||
if(flags & LV_GPU_SDL_CACHE_FLAG_MANAGED) {
|
||||
/* Managed texture doesn't count into cache size */
|
||||
LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format));
|
||||
lv_lru_set(lv_sdl_texture_cache, key, key_length, value, 1);
|
||||
return;
|
||||
}
|
||||
Uint32 format;
|
||||
int access, width, height;
|
||||
if(SDL_QueryTexture(texture, &format, &access, &width, &height) != 0) {
|
||||
return;
|
||||
}
|
||||
LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format));
|
||||
lv_lru_set(lv_sdl_texture_cache, key, key_length, value, width * height * SDL_BITSPERPIXEL(format) / 8);
|
||||
}
|
||||
|
||||
SDL_Texture * lv_gpu_temp_texture_obtain(SDL_Renderer * renderer, lv_coord_t width, lv_coord_t height)
|
||||
{
|
||||
temp_texture_key_t key;
|
||||
SDL_memset(&key, 0, sizeof(key));
|
||||
key.magic = LV_GPU_CACHE_KEY_TEMP;
|
||||
temp_texture_userdata_t * userdata = NULL;
|
||||
SDL_Texture * texture = lv_gpu_draw_cache_get_with_userdata(&key, sizeof(key), NULL, (void **) &userdata);
|
||||
if(texture && userdata->width >= width && userdata->height >= height) {
|
||||
return texture;
|
||||
}
|
||||
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, width, height);
|
||||
userdata = SDL_malloc(sizeof(temp_texture_userdata_t));
|
||||
userdata->width = width;
|
||||
userdata->height = height;
|
||||
lv_gpu_draw_cache_put_advanced(&key, sizeof(key), texture, userdata, SDL_free, 0);
|
||||
return texture;
|
||||
}
|
||||
|
||||
lv_gpu_sdl_cache_key_head_img_t * lv_gpu_sdl_img_cache_key_create(const void * src, int32_t frame_id, size_t * size)
|
||||
{
|
||||
lv_gpu_sdl_cache_key_head_img_t header;
|
||||
/* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
|
||||
SDL_memset(&header, 0, sizeof(header));
|
||||
header.magic = LV_GPU_CACHE_KEY_MAGIC_IMG;
|
||||
header.type = lv_img_src_get_type(src);
|
||||
header.frame_id = frame_id;
|
||||
void * key;
|
||||
size_t key_size;
|
||||
if(header.type == LV_IMG_SRC_FILE || header.type == LV_IMG_SRC_SYMBOL) {
|
||||
size_t srclen = SDL_strlen(src);
|
||||
key_size = sizeof(header) + srclen;
|
||||
key = SDL_malloc(key_size);
|
||||
SDL_memcpy(key, &header, sizeof(header));
|
||||
/*Copy string content as key value*/
|
||||
SDL_memcpy(key + sizeof(header), src, srclen);
|
||||
}
|
||||
else {
|
||||
key_size = sizeof(header) + sizeof(void *);
|
||||
key = SDL_malloc(key_size);
|
||||
SDL_memcpy(key, &header, sizeof(header));
|
||||
/*Copy address number as key value*/
|
||||
SDL_memcpy(key + sizeof(header), &src, sizeof(void *));
|
||||
}
|
||||
*size = key_size;
|
||||
return (lv_gpu_sdl_cache_key_head_img_t *) key;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void draw_cache_free_value(draw_cache_value_t * value)
|
||||
{
|
||||
if(value->texture && !(value->flags & LV_GPU_SDL_CACHE_FLAG_MANAGED)) {
|
||||
LV_LOG_INFO("destroy texture %p", value->texture);
|
||||
SDL_DestroyTexture(value->texture);
|
||||
}
|
||||
if(value->userdata_free) {
|
||||
value->userdata_free(value->userdata);
|
||||
}
|
||||
SDL_free(value);
|
||||
}
|
||||
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
||||
|
90
src/gpu/sdl/lv_gpu_sdl_texture_cache.h
Normal file
90
src/gpu/sdl/lv_gpu_sdl_texture_cache.h
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_texture_cache.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GPU_SDL_TEXTURE_CACHE_H
|
||||
#define LV_GPU_SDL_TEXTURE_CACHE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
#include "../../draw/lv_img_decoder.h"
|
||||
#include "../../misc/lv_area.h"
|
||||
#include "lv_gpu_sdl_lru.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#define LV_GPU_SDL_DEC_DSC_TEXTURE_HEAD "@LVSDLTex"
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
typedef struct {
|
||||
char head[8];
|
||||
SDL_Texture * texture;
|
||||
} lv_gpu_sdl_dec_dsc_userdata_t;
|
||||
|
||||
typedef enum {
|
||||
LV_GPU_CACHE_KEY_MAGIC_ARC = 0x01,
|
||||
LV_GPU_CACHE_KEY_MAGIC_IMG = 0x11,
|
||||
LV_GPU_CACHE_KEY_MAGIC_LINE = 0x21,
|
||||
LV_GPU_CACHE_KEY_MAGIC_RECT_BG = 0x31,
|
||||
LV_GPU_CACHE_KEY_MAGIC_RECT_SHADOW = 0x32,
|
||||
LV_GPU_CACHE_KEY_MAGIC_RECT_BORDER = 0x33,
|
||||
LV_GPU_CACHE_KEY_MAGIC_FONT = 0x41,
|
||||
LV_GPU_CACHE_KEY_TEMP = 0xFF,
|
||||
} lv_gpu_cache_key_magic_t;
|
||||
|
||||
typedef enum {
|
||||
LV_GPU_SDL_CACHE_FLAG_NONE = 0,
|
||||
LV_GPU_SDL_CACHE_FLAG_MANAGED = 1,
|
||||
} lv_gpu_sdl_cache_flag_t;
|
||||
|
||||
typedef struct {
|
||||
lv_gpu_cache_key_magic_t magic;
|
||||
lv_img_src_t type;
|
||||
int32_t frame_id;
|
||||
} lv_gpu_sdl_cache_key_head_img_t;
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void _lv_gpu_sdl_texture_cache_init();
|
||||
|
||||
void _lv_gpu_sdl_texture_cache_deinit();
|
||||
|
||||
SDL_Texture * lv_gpu_draw_cache_get(const void * key, size_t key_length, bool * found);
|
||||
|
||||
SDL_Texture * lv_gpu_draw_cache_get_with_userdata(const void * key, size_t key_length, bool * found, void ** userdata);
|
||||
|
||||
void lv_gpu_draw_cache_put(const void * key, size_t key_length, SDL_Texture * texture);
|
||||
|
||||
void lv_gpu_draw_cache_put_advanced(const void * key, size_t key_length, SDL_Texture * texture, void * userdata,
|
||||
lv_lru_free_t userdata_free, lv_gpu_sdl_cache_flag_t flags);
|
||||
|
||||
SDL_Texture * lv_gpu_temp_texture_obtain(SDL_Renderer * renderer, lv_coord_t width, lv_coord_t height);
|
||||
|
||||
lv_gpu_sdl_cache_key_head_img_t * lv_gpu_sdl_img_cache_key_create(const void * src, int32_t frame_id, size_t * size);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GPU_SDL_TEXTURE_CACHE_H*/
|
179
src/gpu/sdl/lv_gpu_sdl_utils.c
Normal file
179
src/gpu/sdl/lv_gpu_sdl_utils.c
Normal file
@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_utils.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#if LV_USE_GPU_SDL
|
||||
|
||||
#include "lv_gpu_sdl_utils.h"
|
||||
|
||||
#include "../../draw/lv_draw_label.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
static SDL_Palette * lv_sdl_palette_grayscale1 = NULL;
|
||||
static SDL_Palette * lv_sdl_palette_grayscale2 = NULL;
|
||||
static SDL_Palette * lv_sdl_palette_grayscale3 = NULL;
|
||||
static SDL_Palette * lv_sdl_palette_grayscale4 = NULL;
|
||||
static SDL_Palette * lv_sdl_palette_grayscale8 = NULL;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void _lv_gpu_sdl_utils_init()
|
||||
{
|
||||
lv_sdl_palette_grayscale1 = lv_sdl_alloc_palette_for_bpp(_lv_bpp1_opa_table, 1);
|
||||
lv_sdl_palette_grayscale2 = lv_sdl_alloc_palette_for_bpp(_lv_bpp2_opa_table, 2);
|
||||
lv_sdl_palette_grayscale3 = lv_sdl_alloc_palette_for_bpp(_lv_bpp3_opa_table, 3);
|
||||
lv_sdl_palette_grayscale4 = lv_sdl_alloc_palette_for_bpp(_lv_bpp4_opa_table, 4);
|
||||
lv_sdl_palette_grayscale8 = lv_sdl_alloc_palette_for_bpp(_lv_bpp8_opa_table, 8);
|
||||
}
|
||||
|
||||
void _lv_gpu_sdl_utils_deinit()
|
||||
{
|
||||
SDL_FreePalette(lv_sdl_palette_grayscale1);
|
||||
SDL_FreePalette(lv_sdl_palette_grayscale2);
|
||||
SDL_FreePalette(lv_sdl_palette_grayscale3);
|
||||
SDL_FreePalette(lv_sdl_palette_grayscale4);
|
||||
SDL_FreePalette(lv_sdl_palette_grayscale8);
|
||||
}
|
||||
|
||||
void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out)
|
||||
{
|
||||
out->x = in->x1;
|
||||
out->y = in->y1;
|
||||
out->w = in->x2 - in->x1 + 1;
|
||||
out->h = in->y2 - in->y1 + 1;
|
||||
}
|
||||
|
||||
void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out)
|
||||
{
|
||||
uint32_t color32 = lv_color_to32(*in);
|
||||
lv_color32_t * color32_t = (lv_color32_t *) &color32;
|
||||
out->a = color32_t->ch.alpha;
|
||||
out->r = color32_t->ch.red;
|
||||
out->g = color32_t->ch.green;
|
||||
out->b = color32_t->ch.blue;
|
||||
}
|
||||
|
||||
void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot)
|
||||
{
|
||||
if(zoom == LV_IMG_ZOOM_NONE) {
|
||||
lv_area_to_sdl_rect(in, out);
|
||||
return;
|
||||
}
|
||||
int h = in->y2 - in->y1 + 1;
|
||||
int w = in->x2 - in->x1 + 1;
|
||||
int sh = h * zoom >> 8;
|
||||
int sw = w * zoom >> 8;
|
||||
out->x = in->x1 - (sw / 2 - pivot->x);
|
||||
out->y = in->y1 - (sh / 2 - pivot->y);
|
||||
out->w = sw;
|
||||
out->h = sh;
|
||||
}
|
||||
|
||||
double lv_sdl_round(double d)
|
||||
{
|
||||
return (d - (long) d) < 0.5 ? SDL_floor(d) : SDL_ceil(d);
|
||||
}
|
||||
|
||||
SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp)
|
||||
{
|
||||
SDL_assert(bpp >= 1 && bpp <= 8);
|
||||
int color_cnt = 1 << bpp;
|
||||
SDL_Palette * result = SDL_AllocPalette(color_cnt);
|
||||
SDL_Color palette[256];
|
||||
for(int i = 0; i < color_cnt; i++) {
|
||||
palette[i].r = palette[i].g = palette[i].b = 0xFF;
|
||||
palette[i].a = mapping ? mapping[i] : i;
|
||||
}
|
||||
SDL_SetPaletteColors(result, palette, 0, color_cnt);
|
||||
return result;
|
||||
}
|
||||
|
||||
SDL_Palette * lv_sdl_get_grayscale_palette(uint8_t bpp)
|
||||
{
|
||||
switch(bpp) {
|
||||
case 1:
|
||||
return lv_sdl_palette_grayscale1;
|
||||
case 2:
|
||||
return lv_sdl_palette_grayscale2;
|
||||
case 3:
|
||||
return lv_sdl_palette_grayscale3;
|
||||
case 4:
|
||||
return lv_sdl_palette_grayscale4;
|
||||
case 8:
|
||||
return lv_sdl_palette_grayscale8;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp)
|
||||
{
|
||||
int src_len = width * height;
|
||||
int cur = 0;
|
||||
int curbit;
|
||||
uint8_t opa_mask;
|
||||
const uint8_t * opa_table;
|
||||
switch(bpp) {
|
||||
case 1:
|
||||
opa_mask = 0x1;
|
||||
opa_table = _lv_bpp1_opa_table;
|
||||
break;
|
||||
case 2:
|
||||
opa_mask = 0x4;
|
||||
opa_table = _lv_bpp2_opa_table;
|
||||
break;
|
||||
case 4:
|
||||
opa_mask = 0xF;
|
||||
opa_table = _lv_bpp4_opa_table;
|
||||
break;
|
||||
case 8:
|
||||
opa_mask = 0xFF;
|
||||
opa_table = _lv_bpp8_opa_table;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
/* Does this work well on big endian systems? */
|
||||
while(cur < src_len) {
|
||||
curbit = 8 - bpp;
|
||||
uint8_t src_byte = src[cur * bpp / 8];
|
||||
while(curbit >= 0) {
|
||||
uint8_t src_bits = opa_mask & (src_byte >> curbit);
|
||||
dest[(cur / width * stride) + (cur % width)] = opa_table[src_bits];
|
||||
curbit -= bpp;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
#endif /*LV_USE_GPU_SDL*/
|
61
src/gpu/sdl/lv_gpu_sdl_utils.h
Normal file
61
src/gpu/sdl/lv_gpu_sdl_utils.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @file lv_gpu_sdl_utils.h
|
||||
*
|
||||
*/
|
||||
#ifndef LV_GPU_SDL_UTILS_H
|
||||
#define LV_GPU_SDL_UTILS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../lv_conf_internal.h"
|
||||
|
||||
#include "../../misc/lv_color.h"
|
||||
#include "../../misc/lv_area.h"
|
||||
|
||||
#include LV_GPU_SDL_INCLUDE_PATH
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
void _lv_gpu_sdl_utils_init();
|
||||
|
||||
void _lv_gpu_sdl_utils_deinit();
|
||||
|
||||
void lv_area_to_sdl_rect(const lv_area_t * in, SDL_Rect * out);
|
||||
|
||||
void lv_color_to_sdl_color(const lv_color_t * in, SDL_Color * out);
|
||||
|
||||
void lv_area_zoom_to_sdl_rect(const lv_area_t * in, SDL_Rect * out, uint16_t zoom, const lv_point_t * pivot);
|
||||
|
||||
double lv_sdl_round(double d);
|
||||
|
||||
SDL_Palette * lv_sdl_alloc_palette_for_bpp(const uint8_t * mapping, uint8_t bpp);
|
||||
|
||||
SDL_Palette * lv_sdl_get_grayscale_palette(uint8_t bpp);
|
||||
|
||||
void lv_sdl_to_8bpp(uint8_t * dest, const uint8_t * src, int width, int height, int stride, uint8_t bpp);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /*extern "C"*/
|
||||
#endif
|
||||
|
||||
#endif /*LV_GPU_SDL_UTILS_H*/
|
@ -167,6 +167,7 @@ uint8_t del_prev :
|
||||
lv_opa_t bg_opa; /**<Opacity of the background color or wallpaper*/
|
||||
lv_color_t bg_color; /**< Default display color when screens are transparent*/
|
||||
const void * bg_img; /**< An image source to display as wallpaper*/
|
||||
void (*bg_fn)(lv_area_t*);/**< A function to handle drawing*/
|
||||
|
||||
/** Invalidated (marked to redraw) areas*/
|
||||
lv_area_t inv_areas[LV_INV_BUF_SIZE];
|
||||
|
@ -46,11 +46,9 @@
|
||||
/*----------------------------------
|
||||
* Start parsing lv_conf_template.h
|
||||
-----------------------------------*/
|
||||
/* clang-format off */
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/*====================
|
||||
COLOR SETTINGS
|
||||
*====================*/
|
||||
@ -60,7 +58,7 @@
|
||||
# ifdef CONFIG_LV_COLOR_DEPTH
|
||||
# define LV_COLOR_DEPTH CONFIG_LV_COLOR_DEPTH
|
||||
# else
|
||||
# define LV_COLOR_DEPTH 32
|
||||
# define LV_COLOR_DEPTH 16
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@ -123,6 +121,12 @@
|
||||
# define LV_MEM_ADR 0 /*0: unused*/
|
||||
# endif
|
||||
#endif
|
||||
/*Instead of an address give a memory allocator that will be called to get a memory pool for LVGL. E.g. my_malloc*/
|
||||
#if LV_MEM_ADR == 0
|
||||
//#define LV_MEM_POOL_INCLUDE your_alloc_library /* Uncomment if using an external allocator*/
|
||||
//#define LV_MEM_POOL_ALLOC your_alloc /* Uncomment if using an external allocator*/
|
||||
#endif
|
||||
|
||||
#else /*LV_MEM_CUSTOM*/
|
||||
#ifndef LV_MEM_CUSTOM_INCLUDE
|
||||
# ifdef CONFIG_LV_MEM_CUSTOM_INCLUDE
|
||||
@ -286,6 +290,7 @@
|
||||
# define LV_DISP_ROT_MAX_BUF (10*1024)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*-------------
|
||||
* GPU
|
||||
*-----------*/
|
||||
@ -342,6 +347,49 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*Use SDL renderer API*/
|
||||
#ifndef LV_USE_GPU_SDL
|
||||
# ifdef CONFIG_LV_USE_GPU_SDL
|
||||
#ifndef LV_USE_GPU_SDL
|
||||
# ifdef CONFIG_LV_USE_GPU_SDL
|
||||
# define LV_USE_GPU_SDL CONFIG_LV_USE_GPU_SDL
|
||||
# else
|
||||
# define LV_USE_GPU_SDL CONFIG_LV_USE_GPU_SDL
|
||||
# endif
|
||||
#endif
|
||||
# else
|
||||
# define LV_USE_GPU_SDL 0
|
||||
# endif
|
||||
#endif
|
||||
#if LV_USE_GPU_SDL
|
||||
#ifndef LV_USE_EXTERNAL_RENDERER
|
||||
# ifdef CONFIG_LV_USE_EXTERNAL_RENDERER
|
||||
# define LV_USE_EXTERNAL_RENDERER CONFIG_LV_USE_EXTERNAL_RENDERER
|
||||
# else
|
||||
# define LV_USE_EXTERNAL_RENDERER 1
|
||||
# endif
|
||||
#endif
|
||||
# ifndef LV_GPU_SDL_INCLUDE
|
||||
#ifndef LV_GPU_SDL_INCLUDE_PATH
|
||||
# ifdef CONFIG_LV_GPU_SDL_INCLUDE_PATH
|
||||
# define LV_GPU_SDL_INCLUDE_PATH CONFIG_LV_GPU_SDL_INCLUDE_PATH
|
||||
# else
|
||||
# define LV_GPU_SDL_INCLUDE_PATH <SDL2/SDL.h>
|
||||
# endif
|
||||
#endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef LV_USE_EXTERNAL_RENDERER
|
||||
#ifndef LV_USE_EXTERNAL_RENDERER
|
||||
# ifdef CONFIG_LV_USE_EXTERNAL_RENDERER
|
||||
# define LV_USE_EXTERNAL_RENDERER CONFIG_LV_USE_EXTERNAL_RENDERER
|
||||
# else
|
||||
# define LV_USE_EXTERNAL_RENDERER 0
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*-------------
|
||||
* Logging
|
||||
*-----------*/
|
||||
@ -675,7 +723,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*Compiler prefix for a big array declaration in RAM*/
|
||||
/*Complier prefix for a big array declaration in RAM*/
|
||||
#ifndef LV_ATTRIBUTE_LARGE_RAM_ARRAY
|
||||
# ifdef CONFIG_LV_ATTRIBUTE_LARGE_RAM_ARRAY
|
||||
# define LV_ATTRIBUTE_LARGE_RAM_ARRAY CONFIG_LV_ATTRIBUTE_LARGE_RAM_ARRAY
|
||||
@ -894,7 +942,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
# ifdef CONFIG_LV_FONT_DEJAVU_16_PERSIAN_HEBREW
|
||||
# define LV_FONT_DEJAVU_16_PERSIAN_HEBREW CONFIG_LV_FONT_DEJAVU_16_PERSIAN_HEBREW
|
||||
# else
|
||||
# define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Persian letters and all their forms*/
|
||||
# define LV_FONT_DEJAVU_16_PERSIAN_HEBREW 0 /*Hebrew, Arabic, Perisan letters and all their forms*/
|
||||
# endif
|
||||
#endif
|
||||
#ifndef LV_FONT_SIMSUN_16_CJK
|
||||
@ -1142,7 +1190,6 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef LV_USE_DROPDOWN
|
||||
# ifdef CONFIG_LV_USE_DROPDOWN
|
||||
# define LV_USE_DROPDOWN CONFIG_LV_USE_DROPDOWN
|
||||
@ -1437,6 +1484,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
/*-----------
|
||||
* Themes
|
||||
*----------*/
|
||||
|
||||
/*A simple, impressive and very complete theme*/
|
||||
#ifndef LV_USE_THEME_DEFAULT
|
||||
# ifdef CONFIG_LV_USE_THEME_DEFAULT
|
||||
@ -1536,7 +1584,7 @@ e.g. "stm32f769xx.h" or "stm32f429xx.h"*/
|
||||
|
||||
LV_EXPORT_CONST_INT(LV_DPI_DEF);
|
||||
|
||||
/*If running without lv_conf.h add typedefs with default value*/
|
||||
/*If running without lv_conf.h add typdesf with default value*/
|
||||
#if defined(LV_CONF_SKIP)
|
||||
|
||||
# if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) /*Disable warnings for Visual Studio*/
|
||||
|
Loading…
Reference in New Issue
Block a user