1 /**
2  * @file lv_draw_sdl_texture_cache.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 
10 #include "../../lv_conf_internal.h"
11 
12 #if LV_USE_GPU_SDL
13 
14 #include "lv_draw_sdl_texture_cache.h"
15 
16 #include "lv_draw_sdl_utils.h"
17 
18 /*********************
19  *      DEFINES
20  *********************/
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 typedef struct {
27     SDL_Texture * texture;
28     void * userdata;
29     lv_lru_free_t * userdata_free;
30     lv_draw_sdl_cache_flag_t flags;
31 } draw_cache_value_t;
32 
33 typedef struct {
34     lv_sdl_cache_key_magic_t magic;
35 } temp_texture_key_t;
36 
37 typedef struct {
38     lv_coord_t width, height;
39 } temp_texture_userdata_t;
40 
41 static void draw_cache_free_value(draw_cache_value_t *);
42 
43 static draw_cache_value_t * draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
44                                                  bool * found);
45 /**********************
46  *  STATIC VARIABLES
47  **********************/
48 
49 /**********************
50  *      MACROS
51  **********************/
52 
53 /**********************
54  *   GLOBAL FUNCTIONS
55  **********************/
56 
lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx)57 void lv_draw_sdl_texture_cache_init(lv_draw_sdl_ctx_t * ctx)
58 {
59     ctx->internals->texture_cache = lv_lru_create(LV_GPU_SDL_LRU_SIZE, 65536,
60                                                   (lv_lru_free_t *) draw_cache_free_value, NULL);
61 }
62 
lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx)63 void lv_draw_sdl_texture_cache_deinit(lv_draw_sdl_ctx_t * ctx)
64 {
65     lv_lru_del(ctx->internals->texture_cache);
66 }
67 
lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx,const void * key,size_t key_length,bool * found)68 SDL_Texture * lv_draw_sdl_texture_cache_get(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, bool * found)
69 {
70     return lv_draw_sdl_texture_cache_get_with_userdata(ctx, key, key_length, found, NULL);
71 }
72 
lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx,const void * key,size_t key_length,bool * found,void ** userdata)73 SDL_Texture * lv_draw_sdl_texture_cache_get_with_userdata(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
74                                                           bool * found, void ** userdata)
75 {
76     draw_cache_value_t * value = draw_cache_get_entry(ctx, key, key_length, found);
77     if(!value) return NULL;
78     if(userdata) {
79         *userdata = value->userdata;
80     }
81     return value->texture;
82 }
83 
lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx,const void * key,size_t key_length,SDL_Texture * texture)84 void lv_draw_sdl_texture_cache_put(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length, SDL_Texture * texture)
85 {
86     lv_draw_sdl_texture_cache_put_advanced(ctx, key, key_length, texture, NULL, NULL, 0);
87 }
88 
lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx,const void * key,size_t key_length,SDL_Texture * texture,void * userdata,void userdata_free (void *),lv_draw_sdl_cache_flag_t flags)89 void lv_draw_sdl_texture_cache_put_advanced(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
90                                             SDL_Texture * texture, void * userdata, void userdata_free(void *),
91                                             lv_draw_sdl_cache_flag_t flags)
92 {
93     lv_lru_t * lru = ctx->internals->texture_cache;
94     draw_cache_value_t * value = SDL_malloc(sizeof(draw_cache_value_t));
95     value->texture = texture;
96     value->userdata = userdata;
97     value->userdata_free = userdata_free;
98     value->flags = flags;
99     if(!texture) {
100         lv_lru_set(lru, key, key_length, value, 1);
101         return;
102     }
103     if(flags & LV_DRAW_SDL_CACHE_FLAG_MANAGED) {
104         /* Managed texture doesn't count into cache size */
105         LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format));
106         lv_lru_set(lru, key, key_length, value, 1);
107         return;
108     }
109     Uint32 format;
110     int access, width, height;
111     if(SDL_QueryTexture(texture, &format, &access, &width, &height) != 0) {
112         return;
113     }
114     LV_LOG_INFO("cache texture %p, %d*%d@%dbpp", texture, width, height, SDL_BITSPERPIXEL(format));
115     lv_lru_set(lru, key, key_length, value, width * height * SDL_BITSPERPIXEL(format) / 8);
116 }
117 
lv_draw_sdl_texture_img_key_create(const void * src,int32_t frame_id,size_t * size)118 lv_draw_sdl_cache_key_head_img_t * lv_draw_sdl_texture_img_key_create(const void * src, int32_t frame_id, size_t * size)
119 {
120     lv_draw_sdl_cache_key_head_img_t header;
121     /* VERY IMPORTANT! Padding between members is uninitialized, so we have to wipe them manually */
122     SDL_memset(&header, 0, sizeof(header));
123     header.magic = LV_GPU_CACHE_KEY_MAGIC_IMG;
124     header.type = lv_img_src_get_type(src);
125     header.frame_id = frame_id;
126     void * key;
127     size_t key_size;
128     if(header.type == LV_IMG_SRC_FILE || header.type == LV_IMG_SRC_SYMBOL) {
129         size_t srclen = SDL_strlen(src);
130         key_size = sizeof(header) + srclen;
131         key = SDL_malloc(key_size);
132         SDL_memcpy(key, &header, sizeof(header));
133         /*Copy string content as key value*/
134         SDL_memcpy(key + sizeof(header), src, srclen);
135     }
136     else {
137         key_size = sizeof(header) + sizeof(void *);
138         key = SDL_malloc(key_size);
139         SDL_memcpy(key, &header, sizeof(header));
140         /*Copy address number as key value*/
141         SDL_memcpy(key + sizeof(header), &src, sizeof(void *));
142     }
143     *size = key_size;
144     return (lv_draw_sdl_cache_key_head_img_t *) key;
145 }
146 
draw_cache_free_value(draw_cache_value_t * value)147 static void draw_cache_free_value(draw_cache_value_t * value)
148 {
149     if(value->texture && !(value->flags & LV_DRAW_SDL_CACHE_FLAG_MANAGED)) {
150         LV_LOG_INFO("destroy texture %p", value->texture);
151         SDL_DestroyTexture(value->texture);
152     }
153     if(value->userdata_free) {
154         value->userdata_free(value->userdata);
155     }
156     SDL_free(value);
157 }
158 
draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx,const void * key,size_t key_length,bool * found)159 static draw_cache_value_t * draw_cache_get_entry(lv_draw_sdl_ctx_t * ctx, const void * key, size_t key_length,
160                                                  bool * found)
161 {
162     lv_lru_t * lru = ctx->internals->texture_cache;
163     draw_cache_value_t * value = NULL;
164     lv_lru_get(lru, key, key_length, (void **) &value);
165     if(!value) {
166         if(found) {
167             *found = false;
168         }
169         return NULL;
170     }
171     if(found) {
172         *found = true;
173     }
174     return value;
175 }
176 
177 #endif /*LV_USE_GPU_SDL*/
178 
179