summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Makefile_Evas.am13
-rw-r--r--src/bin/evas/evas_cserve2.h140
-rw-r--r--src/bin/evas/evas_cserve2_cache.c2508
-rw-r--r--src/bin/evas/evas_cserve2_debug.c185
-rw-r--r--src/bin/evas/evas_cserve2_fonts.c157
-rw-r--r--src/bin/evas/evas_cserve2_index.c1084
-rw-r--r--src/bin/evas/evas_cserve2_main.c111
-rw-r--r--src/bin/evas/evas_cserve2_main_loop_linux.c12
-rw-r--r--src/bin/evas/evas_cserve2_messages.c3
-rw-r--r--src/bin/evas/evas_cserve2_requests.c32
-rw-r--r--src/bin/evas/evas_cserve2_scale.c6
-rw-r--r--src/bin/evas/evas_cserve2_shm.c118
-rw-r--r--src/bin/evas/evas_cserve2_shm_debug.c811
-rw-r--r--src/bin/evas/evas_cserve2_slave.c49
-rw-r--r--src/bin/evas/evas_cserve2_slaves.c3
-rw-r--r--src/bin/evas/evas_cserve2_usage.c85
-rw-r--r--src/lib/evas/cache2/evas_cache2.c179
-rw-r--r--src/lib/evas/cache2/evas_cache2.h2
-rw-r--r--src/lib/evas/canvas/evas_main.c11
-rw-r--r--src/lib/evas/canvas/evas_object_image.c56
-rw-r--r--src/lib/evas/canvas/evas_object_inform.c2
-rw-r--r--src/lib/evas/canvas/evas_render.c2
-rw-r--r--src/lib/evas/common/evas_font_draw.c53
-rw-r--r--src/lib/evas/common/evas_font_main.c13
-rw-r--r--src/lib/evas/common/evas_image_load.c35
-rw-r--r--src/lib/evas/common/evas_image_scalecache.c22
-rw-r--r--src/lib/evas/cserve2/evas_cs2.h158
-rw-r--r--src/lib/evas/cserve2/evas_cs2_client.c2048
-rw-r--r--src/lib/evas/cserve2/evas_cs2_image_data.c9
-rw-r--r--src/lib/evas/cserve2/evas_cs2_private.h59
-rw-r--r--src/lib/evas/cserve2/evas_cs2_utils.c2
-rw-r--r--src/modules/evas/engines/gl_common/evas_gl_image.c147
-rw-r--r--src/modules/evas/engines/software_generic/evas_engine.c92
33 files changed, 6433 insertions, 1774 deletions
diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am
index 29bea4b603..7a52016126 100644
--- a/src/Makefile_Evas.am
+++ b/src/Makefile_Evas.am
@@ -999,7 +999,8 @@ bin/evas/dummy_slave
999bin_PROGRAMS += \ 999bin_PROGRAMS += \
1000bin/evas/evas_cserve2_client \ 1000bin/evas/evas_cserve2_client \
1001bin/evas/evas_cserve2_usage \ 1001bin/evas/evas_cserve2_usage \
1002bin/evas/evas_cserve2_debug 1002bin/evas/evas_cserve2_debug \
1003bin/evas/evas_cserve2_shm_debug
1003 1004
1004bin_evas_evas_cserve2_SOURCES = \ 1005bin_evas_evas_cserve2_SOURCES = \
1005bin/evas/evas_cserve2.h \ 1006bin/evas/evas_cserve2.h \
@@ -1013,6 +1014,7 @@ bin/evas/evas_cserve2_requests.c \
1013bin/evas/evas_cserve2_fonts.c \ 1014bin/evas/evas_cserve2_fonts.c \
1014bin/evas/evas_cserve2_scale.c \ 1015bin/evas/evas_cserve2_scale.c \
1015bin/evas/evas_cserve2_main_loop_linux.c \ 1016bin/evas/evas_cserve2_main_loop_linux.c \
1017bin/evas/evas_cserve2_index.c \
1016lib/evas/cserve2/evas_cs2_utils.h \ 1018lib/evas/cserve2/evas_cs2_utils.h \
1017lib/evas/cserve2/evas_cs2_utils.c 1019lib/evas/cserve2/evas_cs2_utils.c
1018 1020
@@ -1055,6 +1057,15 @@ bin_evas_evas_cserve2_debug_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
1055bin_evas_evas_cserve2_debug_LDADD = @USE_EINA_LIBS@ 1057bin_evas_evas_cserve2_debug_LDADD = @USE_EINA_LIBS@
1056bin_evas_evas_cserve2_debug_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ 1058bin_evas_evas_cserve2_debug_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@
1057 1059
1060bin_evas_evas_cserve2_shm_debug_SOURCES = \
1061bin/evas/evas_cserve2_shm_debug.c
1062bin_evas_evas_cserve2_shm_debug_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
1063-I$(top_srcdir)/src/lib/evas \
1064-I$(top_srcdir)/src/lib/evas/cserve2 \
1065@EINA_CFLAGS@
1066bin_evas_evas_cserve2_shm_debug_LDADD = @USE_EINA_LIBS@
1067bin_evas_evas_cserve2_shm_debug_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@
1068
1058bin_evas_evas_cserve2_slave_SOURCES = \ 1069bin_evas_evas_cserve2_slave_SOURCES = \
1059bin/evas/evas_cserve2_slave.c \ 1070bin/evas/evas_cserve2_slave.c \
1060bin/evas/evas_cserve2_utils.c \ 1071bin/evas/evas_cserve2_utils.c \
diff --git a/src/bin/evas/evas_cserve2.h b/src/bin/evas/evas_cserve2.h
index cc1a748970..e49bfc451d 100644
--- a/src/bin/evas/evas_cserve2.h
+++ b/src/bin/evas/evas_cserve2.h
@@ -4,22 +4,54 @@
4#include <Eina.h> 4#include <Eina.h>
5#include "evas_cs2.h" 5#include "evas_cs2.h"
6 6
7#ifndef CSERVE2_LOG_LEVEL
8#define CSERVE2_LOG_LEVEL 4
9#endif
10
11#ifdef CRIT
12#undef CRIT
13#endif
14#if CSERVE2_LOG_LEVEL >= 0
15#define CRIT(...) EINA_LOG_DOM_CRIT(_evas_cserve2_bin_log_dom, __VA_ARGS__)
16#else
17#define CRIT(...) do {} while(0)
18#endif
19
7#ifdef ERR 20#ifdef ERR
8#undef ERR 21#undef ERR
9#endif 22#endif
23#if CSERVE2_LOG_LEVEL >= 1
10#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_bin_log_dom, __VA_ARGS__) 24#define ERR(...) EINA_LOG_DOM_ERR(_evas_cserve2_bin_log_dom, __VA_ARGS__)
11#ifdef DBG 25#else
12#undef DBG 26#define ERR(...) do {} while(0)
13#endif 27#endif
14#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_bin_log_dom, __VA_ARGS__) 28
15#ifdef WRN 29#ifdef WRN
16#undef WRN 30#undef WRN
17#endif 31#endif
32#if CSERVE2_LOG_LEVEL >= 2
18#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_bin_log_dom, __VA_ARGS__) 33#define WRN(...) EINA_LOG_DOM_WARN(_evas_cserve2_bin_log_dom, __VA_ARGS__)
34#else
35#define WRN(...) do {} while(0)
36#endif
37
19#ifdef INF 38#ifdef INF
20#undef INF 39#undef INF
21#endif 40#endif
41#if CSERVE2_LOG_LEVEL >= 3
22#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__) 42#define INF(...) EINA_LOG_DOM_INFO(_evas_cserve2_bin_log_dom, __VA_ARGS__)
43#else
44#define INF(...) do {} while(0)
45#endif
46
47#ifdef DBG
48#undef DBG
49#endif
50#if CSERVE2_LOG_LEVEL >= 4
51#define DBG(...) EINA_LOG_DOM_DBG(_evas_cserve2_bin_log_dom, __VA_ARGS__)
52#else
53#define DBG(...) do {} while(0)
54#endif
23 55
24#define DEBUG_LOAD_TIME 1 56#define DEBUG_LOAD_TIME 1
25 57
@@ -30,6 +62,8 @@ extern Eina_Prefix *_evas_cserve2_pfx;
30typedef struct _Slave Slave; 62typedef struct _Slave Slave;
31typedef struct _Slave_Thread_Data Slave_Thread_Data; 63typedef struct _Slave_Thread_Data Slave_Thread_Data;
32typedef struct _Shm_Handle Shm_Handle; 64typedef struct _Shm_Handle Shm_Handle;
65typedef struct _Shared_Array Shared_Array;
66typedef struct _Shared_Mempool Shared_Mempool;
33 67
34typedef enum { 68typedef enum {
35 FD_READ = 1, 69 FD_READ = 1,
@@ -69,8 +103,17 @@ typedef enum {
69} Slave_Command; 103} Slave_Command;
70 104
71struct _Slave_Msg_Image_Open { 105struct _Slave_Msg_Image_Open {
72 Eina_Bool has_loader_data : 1; 106 struct {
73 // Optionally followed by: 107 struct {
108 unsigned int x, y, w, h;
109 } region;
110 double dpi;
111 unsigned int w, h;
112 int scale_down_by;
113 Eina_Bool orientation;
114 } lo;
115 // const char path[];
116 // const char key[];
74 // const char loader[]; 117 // const char loader[];
75}; 118};
76 119
@@ -103,6 +146,7 @@ struct _Slave_Msg_Image_Load {
103 146
104struct _Slave_Msg_Image_Loaded { 147struct _Slave_Msg_Image_Loaded {
105 int w, h; 148 int w, h;
149 Eina_Bool alpha : 1;
106 Eina_Bool alpha_sparse : 1; 150 Eina_Bool alpha_sparse : 1;
107}; 151};
108 152
@@ -140,14 +184,13 @@ struct _Slave_Msg_Font_Glyphs_Load {
140 unsigned int *glyphs; 184 unsigned int *glyphs;
141 } glyphs; 185 } glyphs;
142 struct { 186 struct {
143 Shm_Handle *shm; 187 Shared_Mempool *mempool;
144 unsigned int usage;
145 unsigned int nglyphs;
146 } cache; 188 } cache;
147}; 189};
148 190
149struct _Slave_Msg_Glyph { 191struct _Slave_Msg_Glyph {
150 unsigned int index; 192 unsigned int index;
193 unsigned int buffer_id;
151 unsigned int offset; 194 unsigned int offset;
152 unsigned int size; 195 unsigned int size;
153 unsigned int rows; 196 unsigned int rows;
@@ -159,21 +202,13 @@ struct _Slave_Msg_Glyph {
159 202
160typedef struct _Slave_Msg_Glyph Slave_Msg_Glyph; 203typedef struct _Slave_Msg_Glyph Slave_Msg_Glyph;
161 204
162struct _Slave_Msg_Font_Cache {
163 unsigned int nglyphs;
164 Slave_Msg_Glyph *glyphs;
165 Shm_Handle *shm;
166 unsigned int usage;
167};
168
169typedef struct _Slave_Msg_Font_Cache Slave_Msg_Font_Cache;
170
171struct _Slave_Msg_Font_Glyphs_Loaded { 205struct _Slave_Msg_Font_Glyphs_Loaded {
172 unsigned int ncaches; 206 Shared_Mempool *mempool;
173 unsigned int gl_load_time; 207 unsigned int gl_load_time;
174 unsigned int gl_render_time; 208 unsigned int gl_render_time;
175 unsigned int gl_slave_time; 209 unsigned int gl_slave_time;
176 Slave_Msg_Font_Cache **caches; 210 Slave_Msg_Glyph *glyphs;
211 unsigned int nglyphs;
177}; 212};
178 213
179typedef struct _Slave_Msg_Font_Load Slave_Msg_Font_Load; 214typedef struct _Slave_Msg_Font_Load Slave_Msg_Font_Load;
@@ -229,6 +264,7 @@ void cserve2_client_del(Client *client);
229void cserve2_client_deliver(Client *client); 264void cserve2_client_deliver(Client *client);
230void cserve2_client_error_send(Client *client, unsigned int rid, int error_code); 265void cserve2_client_error_send(Client *client, unsigned int rid, int error_code);
231ssize_t cserve2_client_send(Client *client, const void *data, size_t size); 266ssize_t cserve2_client_send(Client *client, const void *data, size_t size);
267void cserve2_index_list_send(int generation_id, const char *strings_index_path, const char *strings_entries_path, const char *files_index_path, const char *images_index_path, const char *fonts_index_path, Client *client);
232 268
233Eina_Bool cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data); 269Eina_Bool cserve2_fd_watch_add(int fd, Fd_Flags flags, Fd_Watch_Cb cb, const void *data);
234Eina_Bool cserve2_fd_watch_del(int fd); 270Eina_Bool cserve2_fd_watch_del(int fd);
@@ -260,15 +296,18 @@ void cserve2_message_handler(int fd, Fd_Flags flags, void *data);
260void cserve2_shm_init(); 296void cserve2_shm_init();
261void cserve2_shm_shutdown(); 297void cserve2_shm_shutdown();
262Shm_Handle *cserve2_shm_request(const char *infix, size_t size); 298Shm_Handle *cserve2_shm_request(const char *infix, size_t size);
299Shm_Handle *cserve2_shm_segment_request(Shm_Handle *shm, size_t size);
300Shm_Handle *cserve2_shm_resize(Shm_Handle *shm, size_t newsize);
263void cserve2_shm_unref(Shm_Handle *shm); 301void cserve2_shm_unref(Shm_Handle *shm);
264const char *cserve2_shm_name_get(const Shm_Handle *shm); 302const char *cserve2_shm_name_get(const Shm_Handle *shm);
303int cserve2_shm_id_get(const Shm_Handle *shm);
265off_t cserve2_shm_map_offset_get(const Shm_Handle *shm); 304off_t cserve2_shm_map_offset_get(const Shm_Handle *shm);
266off_t cserve2_shm_offset_get(const Shm_Handle *shm); 305off_t cserve2_shm_offset_get(const Shm_Handle *shm);
267size_t cserve2_shm_map_size_get(const Shm_Handle *shm); 306size_t cserve2_shm_map_size_get(const Shm_Handle *shm);
268size_t cserve2_shm_size_get(const Shm_Handle *shm); 307size_t cserve2_shm_size_get(const Shm_Handle *shm);
269void *cserve2_shm_map(Shm_Handle *shm); 308void *cserve2_shm_map(Shm_Handle *shm);
270void cserve2_shm_unmap(Shm_Handle *shm); 309void cserve2_shm_unmap(Shm_Handle *shm);
271size_t cserve2_shm_size_normalize(size_t size); 310size_t cserve2_shm_size_normalize(size_t size, size_t align);
272 311
273void cserve2_command_run(Client *client, Message_Type type); 312void cserve2_command_run(Client *client, Message_Type type);
274 313
@@ -279,10 +318,10 @@ void cserve2_cache_init(void);
279void cserve2_cache_shutdown(void); 318void cserve2_cache_shutdown(void);
280void cserve2_cache_client_new(Client *client); 319void cserve2_cache_client_new(Client *client);
281void cserve2_cache_client_del(Client *client); 320void cserve2_cache_client_del(Client *client);
282int cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid); 321int cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid, Evas_Image_Load_Opts *lo);
283void cserve2_cache_file_close(Client *client, unsigned int client_file_id); 322void cserve2_cache_file_close(Client *client, unsigned int client_file_id);
284int cserve2_cache_image_entry_create(Client *client, int rid, unsigned int file_id, unsigned int image_id, Evas_Image_Load_Opts *opts); 323int cserve2_cache_image_entry_create(Client *client, int rid, unsigned int client_file_id, unsigned int image_id, const Evas_Image_Load_Opts *opts);
285void cserve2_rgba_image_scale_do(void *src_data, void *dst_data, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int alpha, int smooth); 324void cserve2_rgba_image_scale_do(void *src_data, int src_full_w, int src_full_h, void *dst_data, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h, int alpha, int smooth);
286void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid); 325void cserve2_cache_image_load(Client *client, unsigned int client_image_id, unsigned int rid);
287void cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid); 326void cserve2_cache_image_preload(Client *client, unsigned int client_image_id, unsigned int rid);
288void cserve2_cache_image_unload(Client *client, unsigned int client_image_id); 327void cserve2_cache_image_unload(Client *client, unsigned int client_image_id);
@@ -302,6 +341,8 @@ void cserve2_request_cancel(Slave_Request *req, Client *client, Error_Type err);
302void cserve2_request_cancel_all(Slave_Request *req, Error_Type err); 341void cserve2_request_cancel_all(Slave_Request *req, Error_Type err);
303void cserve2_requests_init(void); 342void cserve2_requests_init(void);
304void cserve2_requests_shutdown(void); 343void cserve2_requests_shutdown(void);
344void cserve2_request_dependents_drop(Slave_Request *req, Slave_Request_Type type);
345void cserve2_entry_request_drop(void *data, Slave_Request_Type type);
305 346
306void cserve2_font_init(void); 347void cserve2_font_init(void);
307void cserve2_font_shutdown(void); 348void cserve2_font_shutdown(void);
@@ -309,4 +350,57 @@ void *cserve2_font_slave_cb(Slave_Thread_Data *sd, Slave_Command *cmd, const voi
309void cserve2_font_source_ft_free(void *fontsource); 350void cserve2_font_source_ft_free(void *fontsource);
310void cserve2_font_ft_free(void *fontinfo); 351void cserve2_font_ft_free(void *fontinfo);
311 352
353// Shared buffers & indexes
354void cserve2_shared_index_init(void);
355void cserve2_shared_index_shutdown(void);
356
357typedef Eina_Bool (* Shared_Array_Repack_Skip_Cb) (Shared_Array *sa,
358 const void *elem,
359 void *user_data);
360
361// Shared arrays (arrays of fixed size object)
362Shared_Array *cserve2_shared_array_new(int tag, int generation_id, int elemsize, int initcount);
363const char *cserve2_shared_array_name_get(Shared_Array *sa);
364void cserve2_shared_array_del(Shared_Array *sa);
365int cserve2_shared_array_size_get(Shared_Array *sa);
366int cserve2_shared_array_count_get(Shared_Array *sa);
367int cserve2_shared_array_map_size_get(Shared_Array *sa);
368int cserve2_shared_array_item_size_get(Shared_Array *sa);
369int cserve2_shared_array_generation_id_get(Shared_Array *sa);
370int cserve2_shared_array_generation_id_set(Shared_Array *sa, int generation_id);
371int cserve2_shared_array_size_set(Shared_Array *sa, int newcount);
372int cserve2_shared_array_item_new(Shared_Array *sa);
373void *cserve2_shared_array_item_data_get(Shared_Array *sa, int elemid);
374Shared_Array *cserve2_shared_array_repack(Shared_Array *sa, int generation_id,
375 Shared_Array_Repack_Skip_Cb skip,
376 Eina_Compare_Cb cmp, void *user_data);
377int cserve2_shared_array_item_find(Shared_Array *sa, void *data,
378 Eina_Compare_Cb cmp);
379void *cserve2_shared_array_item_data_find(Shared_Array *sa, void *data,
380 Eina_Compare_Cb cmp);
381int cserve2_shared_array_foreach(Shared_Array *sa, Eina_Each_Cb cb, void *data);
382
383// Shared buffers and memory pools
384Shared_Mempool *cserve2_shared_mempool_new(int indextag, int index_elemsize, int generation_id, int initsize);
385void cserve2_shared_mempool_del(Shared_Mempool *sm);
386int cserve2_shared_mempool_buffer_new(Shared_Mempool *sm, int size);
387int cserve2_shared_mempool_buffer_ref(Shared_Mempool *sm, int bufferid);
388void cserve2_shared_mempool_buffer_del(Shared_Mempool *sm, int bufferid);
389void *cserve2_shared_mempool_buffer_get(Shared_Mempool *sm, int bufferid);
390int cserve2_shared_mempool_buffer_offset_get(Shared_Mempool *sm, int bufferid);
391size_t cserve2_shared_mempool_size_get(Shared_Mempool *sm);
392const char *cserve2_shared_mempool_name_get(Shared_Mempool *sm);
393int cserve2_shared_mempool_generation_id_get(Shared_Mempool *sm);
394int cserve2_shared_mempool_generation_id_set(Shared_Mempool *sm, int generation_id);
395Shared_Array *cserve2_shared_mempool_index_get(Shared_Mempool *sm);
396
397// Shared strings
398const char *cserve2_shared_strings_table_name_get();
399const char *cserve2_shared_strings_index_name_get();
400int cserve2_shared_string_add(const char *str);
401int cserve2_shared_string_ref(int id);
402void cserve2_shared_string_del(int id);
403const char *cserve2_shared_string_get(int id);
404int cserve2_shared_strings_repack(Shared_Array_Repack_Skip_Cb skip, Eina_Compare_Cb cmp);
405
312#endif /* _EVAS_CSERVE2_H */ 406#endif /* _EVAS_CSERVE2_H */
diff --git a/src/bin/evas/evas_cserve2_cache.c b/src/bin/evas/evas_cserve2_cache.c
index b9283dac3a..9f92543919 100644
--- a/src/bin/evas/evas_cserve2_cache.c
+++ b/src/bin/evas/evas_cserve2_cache.c
@@ -14,15 +14,34 @@
14 14
15#include <Evas_Loader.h> 15#include <Evas_Loader.h>
16 16
17#define ENTRY Entry base
18#define ASENTRY(a) (&(a->base))
19#define ENTRYID(a) ((a)->base.id)
20
17typedef struct _Entry Entry; 21typedef struct _Entry Entry;
18typedef struct _Reference Reference; 22typedef struct _Reference Reference;
19typedef struct _File_Data File_Data; 23typedef struct _File_Entry File_Entry;
20typedef struct _Image_Data Image_Data; 24typedef struct _Image_Entry Image_Entry;
21typedef struct _File_Watch File_Watch; 25typedef struct _File_Watch File_Watch;
22 26
23typedef struct _Font_Source Font_Source; 27typedef struct _Font_Source Font_Source;
24typedef struct _Font_Entry Font_Entry; 28typedef struct _Font_Entry Font_Entry;
25typedef struct _Font_Cache Font_Cache; 29
30static const Evas_Image_Load_Opts empty_lo = {
31 { 0, 0, 0, 0 },
32 {
33 0, 0, 0, 0,
34 0, 0,
35 0,
36 0
37 },
38 0.0,
39 0, 0,
40 0,
41 0,
42
43 EINA_FALSE
44};
26 45
27typedef enum { 46typedef enum {
28 CSERVE2_IMAGE_FILE, 47 CSERVE2_IMAGE_FILE,
@@ -43,53 +62,37 @@ struct _Entry {
43#endif 62#endif
44}; 63};
45 64
46struct _File_Data { 65struct _File_Entry {
47 Entry base; 66 ENTRY;
48 char *path;
49 char *key;
50 int w, h;
51 int frame_count;
52 int loop_count;
53 int loop_hint;
54 const char *loader_data;
55 File_Watch *watcher; 67 File_Watch *watcher;
56 Eina_List *images; 68 Eina_List *images;
57 Eina_Bool alpha : 1;
58 Eina_Bool invalid : 1;
59}; 69};
60 70
61// Default values for load options commented below 71struct _Image_Entry {
62struct _Image_Data { 72 ENTRY;
63 Entry base;
64 unsigned int file_id;
65 File_Data *file;
66 Evas_Image_Load_Opts opts;
67 Shm_Handle *shm; 73 Shm_Handle *shm;
68 Eina_Bool alpha_sparse : 1;
69 Eina_Bool unused : 1;
70 Eina_Bool doload : 1;
71}; 74};
72 75
73struct _Font_Source { 76struct _Font_Source {
74 const char *key; 77 string_t key;
75 const char *name; 78 string_t name;
76 const char *file; 79 string_t file;
77 int references; 80 int refcount;
78 void *ft; 81 void *ft; // Font_Source_Info
79}; 82};
80 83
81struct _Font_Entry { 84struct _Font_Entry {
82 Entry base; 85 ENTRY;
83 unsigned int rend_flags; 86 unsigned int rend_flags;
84 unsigned int size; 87 unsigned int size;
85 unsigned int dpi; 88 unsigned int dpi;
89 unsigned int font_data_id;
86 Font_Source *src; 90 Font_Source *src;
87 void *ft; 91 void *ft; // Font_Info
88 Fash_Glyph2 *glyphs; 92 Fash_Glyph2 *glyph_entries[3]; // Fast access to the Glyph_Entry objects
89 unsigned int nglyphs; 93 unsigned int nglyphs;
90 Eina_Inlist *caches;
91 Font_Cache *last_cache;
92 Eina_Bool unused : 1; 94 Eina_Bool unused : 1;
95 Shared_Mempool *mempool; // Contains the rendered glyphs
93#ifdef DEBUG_LOAD_TIME 96#ifdef DEBUG_LOAD_TIME
94 struct timeval rstart; // start of the glyphs load request 97 struct timeval rstart; // start of the glyphs load request
95 struct timeval rfinish; // finish of the glyphs load request 98 struct timeval rfinish; // finish of the glyphs load request
@@ -101,28 +104,9 @@ struct _Font_Entry {
101#endif 104#endif
102}; 105};
103 106
104struct _Font_Cache {
105 EINA_INLIST;
106 Font_Entry *fe;
107 Shm_Handle *shm;
108 unsigned int usage;
109 int inuse;
110 Eina_Inlist *glyphs;
111 unsigned int nglyphs;
112};
113
114struct _Glyph_Entry { 107struct _Glyph_Entry {
115 EINA_INLIST; 108 unsigned int gldata_id;
116 Font_Entry *fe; 109 Font_Entry *fe;
117 Font_Cache *fc;
118 unsigned int index;
119 unsigned int offset;
120 unsigned int size;
121 unsigned int rows;
122 unsigned int width;
123 unsigned int pitch;
124 unsigned int num_grays;
125 unsigned int pixel_mode;
126}; 110};
127 111
128struct _Glyphs_Request { 112struct _Glyphs_Request {
@@ -140,13 +124,6 @@ struct _Glyphs_Request {
140 124
141typedef struct _Glyphs_Request Glyphs_Request; 125typedef struct _Glyphs_Request Glyphs_Request;
142 126
143struct _Glyphs_Group {
144 Font_Cache *fc;
145 Eina_List *glyphs;
146};
147
148typedef struct _Glyphs_Group Glyphs_Group;
149
150struct _Reference { 127struct _Reference {
151 Client *client; 128 Client *client;
152 Entry *entry; 129 Entry *entry;
@@ -159,8 +136,18 @@ struct _File_Watch {
159 Eina_List *entries; 136 Eina_List *entries;
160}; 137};
161 138
162static unsigned int _file_id = 0; // id unique number 139static unsigned int _generation_id = 0;
163static unsigned int _image_id = 0; // id unique number 140static unsigned int _entry_id = 0;
141static unsigned int _font_data_id = 0;
142static unsigned int _freed_file_entry_count = 0;
143static unsigned int _freed_image_entry_count = 0;
144static unsigned int _freed_font_entry_count = 0;
145static Eina_Bool _shutdown = EINA_FALSE;
146
147static Shared_Array *_file_data_array = NULL;
148static Shared_Array *_image_data_array = NULL;
149static Shared_Array *_font_data_array = NULL;
150
164static Eina_Hash *file_ids = NULL; // maps path + key --> file_id 151static Eina_Hash *file_ids = NULL; // maps path + key --> file_id
165static Eina_Hash *file_entries = NULL; // maps file_id --> entry 152static Eina_Hash *file_entries = NULL; // maps file_id --> entry
166 153
@@ -181,6 +168,9 @@ static int unused_mem_usage = 0;
181static int max_font_usage = 10 * 4 * 1024; /* in kbytes */ 168static int max_font_usage = 10 * 4 * 1024; /* in kbytes */
182static int font_mem_usage = 0; 169static int font_mem_usage = 0;
183 170
171#define MAX_PREEMPTIVE_LOAD_SIZE (320*320*4)
172#define ARRAY_REPACK_TRIGGER_PERCENT 25 // repack when array conains 25% holes
173
184#ifdef DEBUG_LOAD_TIME 174#ifdef DEBUG_LOAD_TIME
185static int 175static int
186_timeval_sub(const struct timeval *tv2, const struct timeval *tv1) 176_timeval_sub(const struct timeval *tv2, const struct timeval *tv1)
@@ -224,19 +214,256 @@ _entry_load_reused(Entry *e)
224#endif 214#endif
225} 215}
226 216
217static int
218_shm_object_id_cmp_cb(const void *data1, const void *data2)
219{
220 const Shm_Object *obj;
221 unsigned int key;
222
223 if (data1 == data2) return 0;
224 if (!data1) return 1;
225 if (!data2) return -1;
226
227 obj = data1;
228 key = *((unsigned int *) data2);
229 if (obj->id == key) return 0;
230 if (obj->id < key)
231 return -1;
232 else
233 return +1;
234}
235
236static File_Data *
237_file_data_find(unsigned int file_id)
238{
239 File_Data *fd;
240
241 fd = cserve2_shared_array_item_data_find(_file_data_array, &file_id,
242 _shm_object_id_cmp_cb);
243 if (fd && !fd->refcount)
244 {
245 ERR("Can not access object %u with refcount 0", file_id);
246 return NULL;
247 }
248 else if (!fd)
249 ERR("Could not find file %u", file_id);
250
251 return fd;
252}
253
254static File_Entry *
255_file_entry_find(unsigned int entry_id)
256{
257 Entry *e;
258
259 e = (Entry *) eina_hash_find(file_entries, &entry_id);
260 if (!e || e->type != CSERVE2_IMAGE_FILE)
261 {
262 ERR("Could not find file entry %u", entry_id);
263 return NULL;
264 }
265
266 return (File_Entry *) e;
267}
268
269static Image_Data *
270_image_data_find(unsigned int image_id)
271{
272 Image_Data *idata;
273
274 idata = cserve2_shared_array_item_data_find(_image_data_array, &image_id,
275 _shm_object_id_cmp_cb);
276 if (idata && !idata->refcount)
277 {
278 ERR("Can not access object %u with refcount 0", image_id);
279 return NULL;
280 }
281 else if (!idata)
282 ERR("Could not find image %u", image_id);
283
284 return idata;
285}
286
287static Image_Entry *
288_image_entry_find(unsigned int entry_id)
289{
290 Entry *e;
291
292 e = (Entry *) eina_hash_find(image_entries, &entry_id);
293 if (!e || e->type != CSERVE2_IMAGE_DATA)
294 {
295 ERR("Could not find image entry %u", entry_id);
296 return NULL;
297 }
298
299 return (Image_Entry *) e;
300}
301
302static Font_Data *
303_font_data_find(unsigned int fs_id)
304{
305 Font_Data *fdata;
306
307 fdata = cserve2_shared_array_item_data_find(_font_data_array,
308 &fs_id, _shm_object_id_cmp_cb);
309 if (!fdata)
310 {
311 ERR("Could not find font data %u", fs_id);
312 return NULL;
313 }
314
315 return fdata;
316}
317
318static Glyph_Data *
319_glyph_data_find(Shared_Mempool *sm, unsigned int glyph_id)
320{
321 Glyph_Data *gldata;
322 Shared_Array *sa;
323
324 sa = cserve2_shared_mempool_index_get(sm);
325 gldata = cserve2_shared_array_item_data_find(sa, &glyph_id,
326 _shm_object_id_cmp_cb);
327 if (!gldata)
328 {
329 ERR("Could not find glyph %u", glyph_id);
330 return NULL;
331 }
332
333 return gldata;
334}
335
336static Eina_Bool
337_repack_skip_cb(Shared_Array *sa EINA_UNUSED, const void *elem,
338 void *user_data EINA_UNUSED)
339{
340 const Shm_Object *obj = elem;
341 return (!obj->refcount);
342}
343
344static void
345_repack()
346{
347 Shared_Array *sa;
348 int count;
349 Eina_Bool updated = EINA_FALSE;
350
351 if (_shutdown)
352 return;
353
354 // Repack when we have 10% fragmentation over the whole shm buffer
355
356 count = cserve2_shared_array_size_get(_file_data_array);
357 if ((count > 0) && (_freed_file_entry_count > 100 ||
358 ((_freed_file_entry_count * 100) / count >= ARRAY_REPACK_TRIGGER_PERCENT)))
359 {
360 DBG("Repacking file data array: %s",
361 cserve2_shared_array_name_get(_file_data_array));
362
363 _generation_id++;
364
365 sa = cserve2_shared_array_repack(_file_data_array, _generation_id,
366 _repack_skip_cb,
367 _shm_object_id_cmp_cb, NULL);
368 if (!sa)
369 {
370 ERR("Failed to repack files array. Keeping previous references!");
371 goto skip_files;
372 }
373
374 cserve2_shared_array_del(_file_data_array);
375 _freed_file_entry_count = 0;
376 _file_data_array = sa;
377 updated = EINA_TRUE;
378 }
379skip_files:
380
381 count = cserve2_shared_array_size_get(_image_data_array);
382 if ((count > 0) && (_freed_image_entry_count > 100 ||
383 ((_freed_image_entry_count * 100) / count >= ARRAY_REPACK_TRIGGER_PERCENT)))
384 {
385 DBG("Repacking image data array: %s",
386 cserve2_shared_array_name_get(_image_data_array));
387
388 if (!updated)
389 _generation_id++;
390
391 sa = cserve2_shared_array_repack(_image_data_array, _generation_id,
392 _repack_skip_cb,
393 _shm_object_id_cmp_cb, NULL);
394 if (!sa)
395 {
396 ERR("Failed to repack images array. Keeping previous references!");
397 goto skip_images;
398 }
399
400 cserve2_shared_array_del(_image_data_array);
401 _freed_image_entry_count = 0;
402 _image_data_array = sa;
403 updated = EINA_TRUE;
404 }
405skip_images:
406
407 count = cserve2_shared_array_size_get(_font_data_array);
408 if ((count > 0) && (_freed_font_entry_count > 100 ||
409 ((_freed_font_entry_count * 100) / count >= ARRAY_REPACK_TRIGGER_PERCENT)))
410 {
411 DBG("Repacking font data array: %s",
412 cserve2_shared_array_name_get(_font_data_array));
413
414 if (!updated)
415 _generation_id++;
416
417 sa = cserve2_shared_array_repack(_font_data_array, _generation_id,
418 _repack_skip_cb,
419 _shm_object_id_cmp_cb, NULL);
420 if (!sa)
421 {
422 ERR("Failed to repack fonts array. Keeping previous references!");
423 goto skip_fonts;
424 }
425
426 cserve2_shared_array_del(_font_data_array);
427 _freed_font_entry_count = 0;
428 _font_data_array = sa;
429 updated = EINA_TRUE;
430 }
431skip_fonts:
432
433 if (cserve2_shared_strings_repack(_repack_skip_cb, _shm_object_id_cmp_cb) == 1)
434 updated = EINA_TRUE;
435
436 if (updated)
437 {
438 // TODO: Update strings table generation_id?
439 cserve2_shared_array_generation_id_set(_font_data_array, _generation_id);
440 cserve2_shared_array_generation_id_set(_image_data_array, _generation_id);
441 cserve2_shared_array_generation_id_set(_file_data_array, _generation_id);
442 cserve2_index_list_send(_generation_id,
443 cserve2_shared_strings_index_name_get(),
444 cserve2_shared_strings_table_name_get(),
445 cserve2_shared_array_name_get(_file_data_array),
446 cserve2_shared_array_name_get(_image_data_array),
447 cserve2_shared_array_name_get(_font_data_array),
448 NULL);
449 }
450}
451
452
227static Msg_Opened * 453static Msg_Opened *
228_image_opened_msg_create(File_Data *entry, int *size) 454_image_opened_msg_create(File_Data *fd, int *size)
229{ 455{
230 Msg_Opened *msg; 456 Msg_Opened *msg;
231 457
232 msg = calloc(1, sizeof(*msg)); 458 msg = calloc(1, sizeof(*msg));
233 msg->base.type = CSERVE2_OPENED; 459 msg->base.type = CSERVE2_OPENED;
234 msg->image.w = entry->w; 460 msg->image.w = fd->w;
235 msg->image.h = entry->h; 461 msg->image.h = fd->h;
236 msg->image.frame_count = entry->frame_count; 462 msg->image.frame_count = fd->frame_count;
237 msg->image.loop_count = entry->loop_count; 463 msg->image.loop_count = fd->loop_count;
238 msg->image.loop_hint = entry->loop_hint; 464 msg->image.loop_hint = fd->loop_hint;
239 msg->image.alpha = entry->alpha; 465 msg->image.alpha = fd->alpha;
466 msg->image.animated = fd->animated;
240 467
241 *size = sizeof(*msg); 468 *size = sizeof(*msg);
242 469
@@ -244,15 +471,15 @@ _image_opened_msg_create(File_Data *entry, int *size)
244} 471}
245 472
246static void 473static void
247_image_opened_send(Client *client, File_Data *entry, unsigned int rid) 474_image_opened_send(Client *client, File_Data *fd, unsigned int rid)
248{ 475{
249 int size; 476 int size;
250 Msg_Opened *msg; 477 Msg_Opened *msg;
251 478
252 DBG("Sending OPENED reply for entry: %d and RID: %d.", entry->base.id, rid); 479 DBG("Sending OPENED reply for entry: %d and RID: %d.", fd->id, rid);
253 // clear the struct with possible paddings, since it is not aligned. 480 // clear the struct with possible paddings, since it is not aligned.
254 481
255 msg = _image_opened_msg_create(entry, &size); 482 msg = _image_opened_msg_create(fd, &size);
256 msg->base.rid = rid; 483 msg->base.rid = rid;
257 484
258 cserve2_client_send(client, &size, sizeof(size)); 485 cserve2_client_send(client, &size, sizeof(size));
@@ -262,10 +489,10 @@ _image_opened_send(Client *client, File_Data *entry, unsigned int rid)
262} 489}
263 490
264static Msg_Loaded * 491static Msg_Loaded *
265_image_loaded_msg_create(Image_Data *entry, int *size) 492_image_loaded_msg_create(Image_Entry *ientry, Image_Data *idata, int *size)
266{ 493{
267 Msg_Loaded *msg; 494 Msg_Loaded *msg;
268 const char *shmpath = cserve2_shm_name_get(entry->shm); 495 const char *shmpath = cserve2_shm_name_get(ientry->shm);
269 int path_len; 496 int path_len;
270 char *buf; 497 char *buf;
271 498
@@ -275,11 +502,28 @@ _image_loaded_msg_create(Image_Data *entry, int *size)
275 msg = calloc(1, *size); 502 msg = calloc(1, *size);
276 msg->base.type = CSERVE2_LOADED; 503 msg->base.type = CSERVE2_LOADED;
277 504
278 msg->shm.mmap_offset = cserve2_shm_map_offset_get(entry->shm); 505 msg->shm.mmap_offset = cserve2_shm_map_offset_get(ientry->shm);
279 msg->shm.use_offset = cserve2_shm_offset_get(entry->shm); 506 msg->shm.use_offset = cserve2_shm_offset_get(ientry->shm);
280 msg->shm.mmap_size = cserve2_shm_map_size_get(entry->shm); 507 msg->shm.mmap_size = cserve2_shm_map_size_get(ientry->shm);
281 msg->shm.image_size = cserve2_shm_size_get(entry->shm); 508 msg->shm.image_size = cserve2_shm_size_get(ientry->shm);
282 msg->alpha_sparse = entry->alpha_sparse; 509 msg->alpha_sparse = idata->alpha_sparse;
510 msg->image.w = idata->w;
511 msg->image.h = idata->h;
512 msg->alpha = idata->alpha;
513
514 if (idata->shm_id)
515 {
516 const char *old = cserve2_shared_string_get(idata->shm_id);
517 if (strcmp(old, shmpath))
518 {
519 cserve2_shared_string_del(idata->shm_id);
520 idata->shm_id = cserve2_shared_string_add(shmpath);
521 }
522 }
523 else
524 idata->shm_id = cserve2_shared_string_add(shmpath);
525
526 idata->valid = EINA_TRUE;
283 527
284 buf = (char *)msg + sizeof(*msg); 528 buf = (char *)msg + sizeof(*msg);
285 memcpy(buf, shmpath, path_len); 529 memcpy(buf, shmpath, path_len);
@@ -288,14 +532,15 @@ _image_loaded_msg_create(Image_Data *entry, int *size)
288} 532}
289 533
290static void 534static void
291_image_loaded_send(Client *client, Image_Data *entry, unsigned int rid) 535_image_loaded_send(Client *client, Image_Entry *ientry, Image_Data *idata,
536 unsigned int rid)
292{ 537{
293 int size; 538 int size;
294 Msg_Loaded *msg; 539 Msg_Loaded *msg;
295 540
296 DBG("Sending LOADED reply for entry %d and RID: %d.", entry->base.id, rid); 541 DBG("Sending LOADED reply for entry %d and RID: %d.", idata->id, rid);
297 542
298 msg = _image_loaded_msg_create(entry, &size); 543 msg = _image_loaded_msg_create(ientry, idata, &size);
299 msg->base.rid = rid; 544 msg->base.rid = rid;
300 545
301 cserve2_client_send(client, &size, sizeof(size)); 546 cserve2_client_send(client, &size, sizeof(size));
@@ -323,33 +568,54 @@ _font_loaded_send(Client *client, unsigned int rid)
323} 568}
324 569
325static void * 570static void *
326_open_request_build(File_Data *f, int *bufsize) 571_open_request_build(Entry *entry, int *bufsize)
327{ 572{
328 char *buf; 573 Slave_Msg_Image_Open msg = { { { 0,0,0,0}, 0,0,0,0,0, } };
329 int size, pathlen, keylen, loaderlen; 574 const char *loader_data, *key, *path;
330 Slave_Msg_Image_Open msg; 575 void *buf;
331 576 size_t pathlen, keylen, loaderlen;
332 pathlen = strlen(f->path) + 1; 577 File_Data *fd;
333 keylen = strlen(f->key) + 1; 578 Eina_Binbuf *bb;
334
335 memset(&msg, 0, sizeof(msg));
336 msg.has_loader_data = !!f->loader_data;
337 loaderlen = msg.has_loader_data ? (strlen(f->loader_data) + 1) : 0;
338
339 size = sizeof(msg) + pathlen + keylen + loaderlen;
340 buf = malloc(size);
341 if (!buf) return NULL;
342 579
343 memcpy(buf, &msg, sizeof(msg)); 580 if (!entry || entry->type != CSERVE2_IMAGE_FILE)
344 memcpy(buf + sizeof(msg), f->path, pathlen); 581 return NULL;
345 memcpy(buf + sizeof(msg) + pathlen, f->key, keylen);
346 if (msg.has_loader_data)
347 memcpy(buf + sizeof(msg) + pathlen + keylen, f->loader_data, loaderlen);
348
349 *bufsize = size;
350 582
351 _entry_load_start(&f->base); 583 fd = _file_data_find(entry->id);
584 if (!fd)
585 {
586 ERR("Could not find file data for entry %u", entry->id);
587 return NULL;
588 }
352 589
590 path = cserve2_shared_string_get(fd->path);
591 key = cserve2_shared_string_get(fd->key);
592 loader_data = cserve2_shared_string_get(fd->loader_data);
593 if (!path) path = "";
594 if (!key) key = "";
595 if (!loader_data) loader_data = "";
596 pathlen = strlen(path) + 1;
597 keylen = strlen(key) + 1;
598 loaderlen = strlen(loader_data) + 1;
599
600 msg.lo.region.x = fd->lo.region.x;
601 msg.lo.region.y = fd->lo.region.y;
602 msg.lo.region.w = fd->lo.region.w;
603 msg.lo.region.h = fd->lo.region.h;
604 msg.lo.dpi = fd->lo.dpi;
605 msg.lo.w = fd->lo.w;
606 msg.lo.h = fd->lo.h;
607 msg.lo.scale_down_by = fd->lo.scale_down_by;
608 msg.lo.orientation = fd->lo.orientation;
609
610 bb = eina_binbuf_new();
611 eina_binbuf_append_length(bb, (unsigned char *) &msg, sizeof(msg));
612 eina_binbuf_append_length(bb, (unsigned char *) path, pathlen);
613 eina_binbuf_append_length(bb, (unsigned char *) key, keylen);
614 eina_binbuf_append_length(bb, (unsigned char *) loader_data, loaderlen);
615
616 *bufsize = eina_binbuf_length_get(bb);
617 buf = eina_binbuf_string_steal(bb);
618 eina_binbuf_free(bb);
353 return buf; 619 return buf;
354} 620}
355 621
@@ -360,26 +626,55 @@ _request_free(void *msg, void *data EINA_UNUSED)
360} 626}
361 627
362static Msg_Opened * 628static Msg_Opened *
363_open_request_response(File_Data *e, Slave_Msg_Image_Opened *resp, int *size) 629_open_request_response(Entry *entry, Slave_Msg_Image_Opened *resp, int *size)
364{ 630{
365 _entry_load_finish(&e->base); 631 File_Data *fd;
632 Slave_Request *req;
366 633
367 e->base.request = NULL; 634 _entry_load_finish(entry);
635 req = entry->request;
636 entry->request = NULL;
368 637
369 e->w = resp->w; 638 fd = _file_data_find(entry->id);
370 e->h = resp->h; 639 if (!fd)
371 e->frame_count = resp->frame_count; 640 {
372 e->loop_count = resp->loop_count; 641 ERR("Could not find file data for entry %u", entry->id);
373 e->loop_hint = resp->loop_hint; 642 return NULL;
374 e->alpha = resp->alpha; 643 }
644
645 fd->w = resp->w;
646 fd->h = resp->h;
647 fd->animated = resp->animated;
648 fd->frame_count = resp->frame_count;
649 fd->loop_count = resp->loop_count;
650 fd->loop_hint = resp->loop_hint;
651 fd->alpha = resp->alpha;
375 if (resp->has_loader_data) 652 if (resp->has_loader_data)
376 { 653 {
377 const char *ldata = (const char *)resp + 654 const char *ldata =
378 sizeof(Slave_Msg_Image_Opened); 655 (const char *)resp + sizeof(Slave_Msg_Image_Opened);
379 e->loader_data = eina_stringshare_add(ldata); 656 fd->loader_data = cserve2_shared_string_add(ldata);
657 }
658
659 fd->valid = EINA_TRUE;
660
661 // If the image is too large, cancel pre-emptive load.
662 if (fd->w * fd->h * 4 >= MAX_PREEMPTIVE_LOAD_SIZE)
663 {
664 DBG("Not pre-loading this image ");
665 cserve2_request_dependents_drop(req, CSERVE2_REQ_IMAGE_SPEC_LOAD);
380 } 666 }
381 667
382 return _image_opened_msg_create(e, size); 668 return _image_opened_msg_create(fd, size);
669}
670
671void
672cserve2_entry_request_drop(void *data, Slave_Request_Type type EINA_UNUSED)
673{
674 Entry *e = data;
675
676 if (!e) return;
677 e->request = NULL;
383} 678}
384 679
385static void 680static void
@@ -416,26 +711,43 @@ static Slave_Request_Funcs _open_funcs = {
416}; 711};
417 712
418static void * 713static void *
419_load_request_build(Image_Data *i, int *bufsize) 714_load_request_build(Image_Entry *ientry, int *bufsize)
420{ 715{
421 char *buf, *ptr; 716 char *buf, *ptr;
422 const char *shmpath; 717 const char *shmpath, *loader_data, *path, *key;
423 int size; 718 int size;
424 int shmlen, filelen, keylen, loaderlen; 719 int shmlen, filelen, keylen, loaderlen;
425 Slave_Msg_Image_Load msg; 720 Slave_Msg_Image_Load msg;
721 File_Data *fd;
722 Image_Data *idata;
723
724 idata = _image_data_find(ENTRYID(ientry));
725 if (!idata) return NULL;
726
727 fd = _file_data_find(idata->file_id);
728 if (!fd)
729 {
730 ERR("Could not find file data %u for image %u",
731 idata->file_id, idata->id);
732 return NULL;
733 }
426 734
427 // opening shm for this file 735 // opening shm for this file
428 i->shm = cserve2_shm_request("img", i->file->w * i->file->h * 4); 736 ientry->shm = cserve2_shm_request("img", fd->w * fd->h * 4);
429 if (!i->shm) 737 if (!ientry->shm)
430 return NULL; 738 return NULL;
431 739
432 shmpath = cserve2_shm_name_get(i->shm); 740 shmpath = cserve2_shm_name_get(ientry->shm);
433
434 shmlen = strlen(shmpath) + 1; 741 shmlen = strlen(shmpath) + 1;
435 filelen = strlen(i->file->path) + 1; 742 path = cserve2_shared_string_get(fd->path);
436 keylen = strlen(i->file->key) + 1; 743 key = cserve2_shared_string_get(fd->key);
437 if (i->file->loader_data) 744 if (!path) path = "";
438 loaderlen = strlen(i->file->loader_data) + 1; 745 if (!key) key = "";
746 filelen = strlen(path) + 1;
747 keylen = strlen(key) + 1;
748 loader_data = cserve2_shared_string_get(fd->loader_data);
749 if (loader_data)
750 loaderlen = strlen(loader_data) + 1;
439 else 751 else
440 loaderlen = 0; 752 loaderlen = 0;
441 753
@@ -444,23 +756,23 @@ _load_request_build(Image_Data *i, int *bufsize)
444 if (!buf) return NULL; 756 if (!buf) return NULL;
445 757
446 memset(&msg, 0, sizeof(msg)); 758 memset(&msg, 0, sizeof(msg));
447 msg.w = i->file->w; 759 msg.w = fd->w;
448 msg.h = i->file->h; 760 msg.h = fd->h;
449 msg.alpha = i->file->alpha; 761 msg.alpha = fd->alpha;
450 762
451 // NOTE: Not passing scale_load options 763 // NOTE: Not passing scale_load options
452 msg.opts.w = i->opts.w; 764 msg.opts.w = idata->opts.w;
453 msg.opts.h = i->opts.h; 765 msg.opts.h = idata->opts.h;
454 msg.opts.region = i->opts.region; 766 msg.opts.region = idata->opts.region;
455 msg.opts.scale_down_by = i->opts.scale_down_by; 767 msg.opts.scale_down_by = idata->opts.scale_down_by;
456 msg.opts.dpi = i->opts.dpi; 768 msg.opts.dpi = idata->opts.dpi;
457 msg.opts.degree = i->opts.degree; 769 msg.opts.degree = idata->opts.degree;
458 msg.opts.orientation = i->opts.orientation; 770 msg.opts.orientation = idata->opts.orientation;
459 771
460 msg.shm.mmap_offset = cserve2_shm_map_offset_get(i->shm); 772 msg.shm.mmap_offset = cserve2_shm_map_offset_get(ientry->shm);
461 msg.shm.image_offset = cserve2_shm_offset_get(i->shm); 773 msg.shm.image_offset = cserve2_shm_offset_get(ientry->shm);
462 msg.shm.mmap_size = cserve2_shm_map_size_get(i->shm); 774 msg.shm.mmap_size = cserve2_shm_map_size_get(ientry->shm);
463 msg.shm.image_size = cserve2_shm_size_get(i->shm); 775 msg.shm.image_size = cserve2_shm_size_get(ientry->shm);
464 776
465 msg.has_loader_data = !!loaderlen; 777 msg.has_loader_data = !!loaderlen;
466 778
@@ -469,32 +781,41 @@ _load_request_build(Image_Data *i, int *bufsize)
469 781
470 memcpy(ptr, shmpath, shmlen); 782 memcpy(ptr, shmpath, shmlen);
471 ptr += shmlen; 783 ptr += shmlen;
472 memcpy(ptr, i->file->path, filelen); 784 memcpy(ptr, path, filelen);
473 ptr += filelen; 785 ptr += filelen;
474 memcpy(ptr, i->file->key, keylen); 786 memcpy(ptr, key, keylen);
475 ptr += keylen; 787 ptr += keylen;
476 if (loaderlen > 0) memcpy(ptr, i->file->loader_data, loaderlen); 788 if (loaderlen > 0)
789 memcpy(ptr, loader_data, loaderlen);
477 790
478 *bufsize = size; 791 *bufsize = size;
479 792
480 _entry_load_start(&i->base); 793 _entry_load_start(&ientry->base);
481 794
482 return buf; 795 return buf;
483} 796}
484 797
485static inline Eina_Bool 798static inline Eina_Bool
486_scaling_needed(Image_Data *entry, Slave_Msg_Image_Loaded *resp) 799_scaling_needed(Image_Data *idata, Slave_Msg_Image_Loaded *resp)
487{ 800{
488 return (((entry->opts.scale_load.dst_w) && (entry->opts.scale_load.dst_h)) && 801 return (((idata->opts.scale_load.dst_w) && (idata->opts.scale_load.dst_h)) &&
489 ((entry->opts.scale_load.dst_w != resp->w) || 802 ((idata->opts.scale_load.dst_w != resp->w) ||
490 (entry->opts.scale_load.dst_h != resp->h))); 803 (idata->opts.scale_load.dst_h != resp->h)));
491} 804}
492 805
493static int 806static int
494_scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original) 807_scaling_do(Shm_Handle *scale_shm, Image_Data *idata, Image_Entry *original)
495{ 808{
496 char *scale_map, *orig_map; 809 char *scale_map, *orig_map;
497 void *src_data, *dst_data; 810 void *src_data, *dst_data;
811 Image_Data *orig_idata;
812
813 orig_idata = _image_data_find(original->base.id);
814 if (!orig_idata)
815 {
816 ERR("Could not find image %u", original->base.id);
817 return -1;
818 }
498 819
499 scale_map = cserve2_shm_map(scale_shm); 820 scale_map = cserve2_shm_map(scale_shm);
500 if (scale_map == MAP_FAILED) 821 if (scale_map == MAP_FAILED)
@@ -515,18 +836,22 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
515 src_data = orig_map + cserve2_shm_map_offset_get(original->shm); 836 src_data = orig_map + cserve2_shm_map_offset_get(original->shm);
516 dst_data = scale_map + cserve2_shm_map_offset_get(scale_shm); 837 dst_data = scale_map + cserve2_shm_map_offset_get(scale_shm);
517 838
518 DBG("Scaling image ([%d,%d:%dx%d] --> [%d,%d:%dx%d])", 839 DBG("Scaling image ([%dx%d]:[%d,%d:%dx%d] --> [%d,%d:%dx%d])",
519 entry->opts.scale_load.src_x, entry->opts.scale_load.src_y, 840 orig_idata->w, orig_idata->h,
520 entry->opts.scale_load.src_w, entry->opts.scale_load.src_h, 841 idata->opts.scale_load.src_x, idata->opts.scale_load.src_y,
842 idata->opts.scale_load.src_w, idata->opts.scale_load.src_h,
521 0, 0, 843 0, 0,
522 entry->opts.scale_load.dst_w, entry->opts.scale_load.dst_h); 844 idata->opts.scale_load.dst_w, idata->opts.scale_load.dst_h);
523 845
524 cserve2_rgba_image_scale_do(src_data, dst_data, 846 idata->alpha = orig_idata->alpha;
525 entry->opts.scale_load.src_x, entry->opts.scale_load.src_y, 847 cserve2_rgba_image_scale_do(
526 entry->opts.scale_load.src_w, entry->opts.scale_load.src_h, 848 src_data, orig_idata->w, orig_idata->h,
527 0, 0, 849 dst_data,
528 entry->opts.scale_load.dst_w, entry->opts.scale_load.dst_h, 850 idata->opts.scale_load.src_x, idata->opts.scale_load.src_y,
529 entry->file->alpha, entry->opts.scale_load.smooth); 851 idata->opts.scale_load.src_w, idata->opts.scale_load.src_h,
852 0, 0,
853 idata->opts.scale_load.dst_w, idata->opts.scale_load.dst_h,
854 idata->alpha, idata->opts.scale_load.smooth);
530 855
531 cserve2_shm_unmap(original->shm); 856 cserve2_shm_unmap(original->shm);
532 cserve2_shm_unmap(scale_shm); 857 cserve2_shm_unmap(scale_shm);
@@ -535,52 +860,66 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
535} 860}
536 861
537static int 862static int
538_scaling_prepare_and_do(Image_Data *orig) 863_scaling_prepare_and_do(Image_Entry *ientry, Image_Data *idata)
539{ 864{
540 Shm_Handle *scale_shm; 865 Shm_Handle *scale_shm;
541 866
542 DBG("Original image's shm path %s", cserve2_shm_name_get(orig->shm)); 867 scale_shm = cserve2_shm_request("img", idata->opts.scale_load.dst_w
868 * idata->opts.scale_load.dst_h * 4);
543 869
544 scale_shm = cserve2_shm_request( 870 if (!scale_shm)
545 "img", 871 return -1;
546 orig->opts.scale_load.dst_w * orig->opts.scale_load.dst_h * 4);
547 872
548 DBG("Scale image's shm path %s", cserve2_shm_name_get(scale_shm)); 873 DBG("Scaling image from shm %s to shm %s",
874 cserve2_shm_name_get(ientry->shm), cserve2_shm_name_get(scale_shm));
549 875
550 if (_scaling_do(scale_shm, orig, orig)) return -1; 876 if (_scaling_do(scale_shm, idata, ientry) != 0)
877 return -1;
551 878
552 cserve2_shm_unref(orig->shm); /* unreference old shm */ 879 // Switch shm in original image
553 orig->shm = scale_shm; /* update shm */ 880 cserve2_shm_unref(ientry->shm);
881 cserve2_shared_string_del(idata->shm_id);
882 ientry->shm = scale_shm;
883 idata->shm_id = 0;
884 idata->w = idata->opts.scale_load.dst_w;
885 idata->h = idata->opts.scale_load.dst_h;
554 886
555 return 0; 887 return 0;
556} 888}
557 889
558static Msg_Loaded * 890static Msg_Loaded *
559_load_request_response(Image_Data *e, Slave_Msg_Image_Loaded *resp, int *size) 891_load_request_response(Image_Entry *ientry,
892 Slave_Msg_Image_Loaded *resp, int *size)
560{ 893{
561 _entry_load_finish(&e->base); 894 Image_Data *idata;
562 895
563 e->base.request = NULL; 896 idata = _image_data_find(ENTRYID(ientry));
897 if (!idata) return NULL;
564 898
565 e->alpha_sparse = resp->alpha_sparse; 899 _entry_load_finish(ASENTRY(ientry));
566 if (!e->doload) 900 ASENTRY(ientry)->request = NULL;
567 DBG("Entry %d loaded by speculative preload.", e->base.id);
568 901
569 if (_scaling_needed(e, resp)) 902 idata->alpha = resp->alpha;
903 idata->alpha_sparse = resp->alpha_sparse;
904 if (!idata->doload)
905 DBG("Entry %d loaded by speculative preload.", idata->id);
906
907 idata->w = resp->w;
908 idata->h = resp->h;
909
910 if (_scaling_needed(idata, resp))
570 { 911 {
571 DBG("About to scale down image '%s%s'", e->file->path, e->file->key); 912 DBG("About to scale image %u", idata->id);
572 913
573 if (!_scaling_prepare_and_do(e)) 914 if (!_scaling_prepare_and_do(ientry, idata))
574 DBG("Image '%s:%s' has been scaled down.", 915 DBG("Image %u has been scaled.", idata->id);
575 e->file->path, e->file->key);
576 else 916 else
577 ERR("Failed to scale down image '%s%s'", 917 ERR("Failed to scale image %u", idata->id);
578 e->file->path, e->file->key);
579 } 918 }
580 else 919 else
581 DBG("No scaling needed for image '%s%s'", e->file->path, e->file->key); 920 DBG("No scaling needed for image %u", idata->id);
582 921
583 return _image_loaded_msg_create(e, size); 922 return _image_loaded_msg_create(ientry, idata, size);
584} 923}
585 924
586static Slave_Request_Funcs _load_funcs = { 925static Slave_Request_Funcs _load_funcs = {
@@ -590,11 +929,12 @@ static Slave_Request_Funcs _load_funcs = {
590 .error = (Slave_Request_Error)_request_failed 929 .error = (Slave_Request_Error)_request_failed
591}; 930};
592 931
593static unsigned int 932static void
594_img_opts_id_get(unsigned int file_id, Evas_Image_Load_Opts *opts, 933_image_key_set(unsigned int file_id, const Evas_Image_Load_Opts *opts,
595 char *buf, int size) 934 char *buf, int size)
596{ 935{
597 uintptr_t image_id; 936 if (!opts)
937 opts = &empty_lo;
598 938
599 snprintf(buf, size, 939 snprintf(buf, size,
600 "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:!([%d,%d:%dx%d]-[%dx%d:%d]):%d:%d", 940 "%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:!([%d,%d:%dx%d]-[%dx%d:%d]):%d:%d",
@@ -606,123 +946,224 @@ _img_opts_id_get(unsigned int file_id, Evas_Image_Load_Opts *opts,
606 opts->scale_load.dst_w, opts->scale_load.dst_h, 946 opts->scale_load.dst_w, opts->scale_load.dst_h,
607 opts->scale_load.smooth, opts->degree, 947 opts->scale_load.smooth, opts->degree,
608 opts->orientation); 948 opts->orientation);
609
610 image_id = (uintptr_t)eina_hash_find(image_ids, buf);
611
612 return image_id;
613} 949}
614 950
615static unsigned int 951static unsigned int
616_image_data_opts_id_get(Image_Data *im, char *buf, int size) 952_image_opts_id_get(unsigned int file_id, const Evas_Image_Load_Opts *opts,
953 char *buf, int size)
617{ 954{
618 return _img_opts_id_get(im->file_id, &im->opts, buf, size); 955 uintptr_t image_id;
956
957 _image_key_set(file_id, opts, buf, size);
958 image_id = (uintptr_t) eina_hash_find(image_ids, buf);
959
960 return (unsigned int) image_id;
619} 961}
620 962
621static int 963static int
622_image_entry_size_get(Image_Data *e) 964_image_entry_size_get(Image_Entry *ientry)
623{ 965{
624 int size = sizeof(Image_Data); 966 int size = sizeof(Image_Data);
625 /* XXX: get the overhead of the shm handler too */ 967 /* XXX: get the overhead of the shm handler too */
626 if (e->shm) 968 if (ientry->shm)
627 size += cserve2_shm_size_get(e->shm); 969 size += cserve2_shm_size_get(ientry->shm);
628 return size / 1024; 970 return size / 1024;
629} 971}
630 972
973static Eina_Bool
974_evas_image_load_opts_empty(Evas_Image_Load_Opts *lo)
975{
976 if (!lo) return EINA_TRUE;
977
978 return ((lo->scale_down_by == 0)
979 && (lo->dpi == 0.0)
980 && (lo->w == 0) && (lo->h == 0)
981 && (lo->region.x == 0) && (lo->region.y == 0)
982 && (lo->region.w == 0) && (lo->region.h == 0)
983 && (lo->orientation == 0));
984}
985
986static void
987_file_hkey_get(char *buf, size_t sz, const char *path, const char *key,
988 Evas_Image_Load_Opts *lo)
989{
990 // Same as _evas_cache_image_loadopts_append() but not optimized :)
991 if (lo && _evas_image_load_opts_empty(lo))
992 lo = NULL;
993
994 if (!lo)
995 snprintf(buf, sz, "%s:%s", path, key);
996 else
997 {
998 if (lo->orientation)
999 {
1000 snprintf(buf, sz, "%s:%s//@/%d/%f/%dx%d/%d+%d.%dx%d",
1001 path, key, lo->scale_down_by, lo->dpi, lo->w, lo->h,
1002 lo->region.x, lo->region.y, lo->region.w, lo->region.h);
1003 }
1004 else
1005 {
1006 snprintf(buf, sz, "%s:%s//@/%d/%f/%dx%d/%d+%d.%dx%d/o",
1007 path, key, lo->scale_down_by, lo->dpi, lo->w, lo->h,
1008 lo->region.x, lo->region.y, lo->region.w, lo->region.h);
1009 }
1010 }
1011}
1012
631static void 1013static void
632_file_id_free(File_Data *entry) 1014_file_id_free(File_Data *fd)
633{ 1015{
1016 Evas_Image_Load_Opts lo = empty_lo;
634 char buf[4096]; 1017 char buf[4096];
635 1018
636 DBG("Removing entry file id: %d, file: \"%s:%s\"", 1019 lo.region.x = fd->lo.region.x;
637 entry->base.id, entry->path, entry->key); 1020 lo.region.y = fd->lo.region.y;
638 snprintf(buf, sizeof(buf), "%s:%s", entry->path, entry->key); 1021 lo.region.w = fd->lo.region.w;
1022 lo.region.h = fd->lo.region.h;
1023 lo.dpi = fd->lo.dpi;
1024 lo.w = fd->lo.w;
1025 lo.h = fd->lo.h;
1026 lo.scale_down_by = fd->lo.scale_down_by;
1027 lo.orientation = fd->lo.orientation;
1028
1029 _file_hkey_get(buf, sizeof(buf), cserve2_shared_string_get(fd->path),
1030 cserve2_shared_string_get(fd->key), &lo);
1031
1032 DBG("Removing entry file id: %u, file: \"%s\"", fd->id, buf);
639 eina_hash_del_by_key(file_ids, buf); 1033 eina_hash_del_by_key(file_ids, buf);
640} 1034}
641 1035
642static void 1036static void
643_image_id_free(Image_Data *entry) 1037_image_id_free(Image_Data *idata)
644{ 1038{
645 char buf[4096]; 1039 char buf[4096];
646 1040
647 DBG("Removing entry image id: %d", entry->base.id); 1041 DBG("Removing entry image id: %d", idata->id);
648 1042
649 _image_data_opts_id_get(entry, buf, sizeof(buf)); 1043 _image_opts_id_get(idata->file_id, &idata->opts, buf, sizeof(buf));
650 eina_hash_del_by_key(image_ids, buf); 1044 eina_hash_del_by_key(image_ids, buf);
651} 1045}
652 1046
653static void 1047static void
654_image_entry_free(Image_Data *entry) 1048_image_entry_free(Image_Entry *ientry)
655{ 1049{
656 File_Data *fentry = entry->file; 1050 File_Data *fd;
1051 File_Entry *fentry;
1052 Image_Data *idata;
1053
1054 idata = _image_data_find(ENTRYID(ientry));
1055 if (!idata || !idata->refcount)
1056 {
1057 CRIT("Trying to free already freed object: %u", ENTRYID(ientry));
1058 return;
1059 }
1060
1061 if (--idata->refcount > 0)
1062 return;
657 1063
658 if (entry->base.request) 1064 if (ientry->base.request)
659 cserve2_request_cancel_all(entry->base.request, CSERVE2_REQUEST_CANCEL); 1065 cserve2_request_cancel_all(ientry->base.request,
1066 CSERVE2_REQUEST_CANCEL);
660 1067
661 if (entry->unused) 1068 if (idata->unused)
662 { 1069 {
663 image_entries_lru = eina_list_remove(image_entries_lru, entry); 1070 image_entries_lru = eina_list_remove(image_entries_lru, ientry);
664 unused_mem_usage -= _image_entry_size_get(entry); 1071 unused_mem_usage -= _image_entry_size_get(ientry);
665 } 1072 }
666 1073
667 if (fentry) 1074 fd = _file_data_find(idata->file_id);
1075 if (fd)
668 { 1076 {
669 fentry->images = eina_list_remove(fentry->images, entry); 1077 fentry = _file_entry_find(fd->id);
670 if (!fentry->images && !fentry->base.references) 1078 fentry->images = eina_list_remove(fentry->images, ientry);
671 eina_hash_del_by_key(file_entries, &fentry->base.id); 1079 if (fentry && !fentry->images && !ASENTRY(fentry)->references)
1080 eina_hash_del_by_key(file_entries, &fd->id);
672 } 1081 }
673 if (entry->shm) 1082 else
674 cserve2_shm_unref(entry->shm); 1083 ERR("Could not find file data %u for image %u",
675 free(entry); 1084 idata->file_id, idata->id);
1085
1086 if (ientry->shm)
1087 cserve2_shm_unref(ientry->shm);
1088 cserve2_shared_string_del(idata->shm_id);
1089 idata->shm_id = 0;
1090 free(ientry);
676} 1091}
677 1092
678static void 1093static void
679_hash_image_entry_free(void *data) 1094_hash_image_entry_free(void *data)
680{ 1095{
681 Image_Data *entry = data; 1096 Image_Entry *ientry = data;
1097 Image_Data *idata;
682 1098
683 _image_id_free(entry); 1099 idata = _image_data_find(ENTRYID(ientry));
684 _image_entry_free(entry); 1100 if (idata && idata->refcount > 0)
1101 {
1102 _image_id_free(idata);
1103 _image_entry_free(ientry);
1104 _freed_image_entry_count++;
1105 _repack();
1106 }
1107 else ERR("Could not find image entry %u", ENTRYID(ientry));
685} 1108}
686 1109
687static void 1110static void
688_file_entry_free(File_Data *entry) 1111_file_entry_free(File_Entry *fentry)
689{ 1112{
690 File_Watch *fw; 1113 File_Watch *fw;
691 1114
1115 if (!fentry) return;
1116
692 // Should we call free for each of the images too? 1117 // Should we call free for each of the images too?
693 // If everything goes fine, it's not necessary. 1118 // If everything goes fine, it's not necessary.
694 if (entry->images) 1119
1120 if (fentry->images)
695 { 1121 {
696 ERR("Freeing file %d (\"%s:%s\") image data still referenced.", 1122 ERR("Freeing file %u image data still referenced.", ENTRYID(fentry));
697 entry->base.id, entry->path, entry->key); 1123 eina_list_free(fentry->images);
698 eina_list_free(entry->images);
699 } 1124 }
1125 if (ASENTRY(fentry)->request)
1126 cserve2_request_cancel_all(ASENTRY(fentry)->request,
1127 CSERVE2_REQUEST_CANCEL);
700 1128
701 if (entry->base.request) 1129 if ((fw = fentry->watcher))
702 cserve2_request_cancel_all(entry->base.request, CSERVE2_REQUEST_CANCEL);
703
704 if ((fw = entry->watcher))
705 { 1130 {
706 fw->entries = eina_list_remove(fw->entries, entry); 1131 fw->entries = eina_list_remove(fw->entries, fentry);
707 if (!fw->entries) 1132 if (!fw->entries)
708 eina_hash_del_by_key(file_watch, fw->path); 1133 eina_hash_del_by_key(file_watch, fw->path);
709 } 1134 }
710 1135
711 free(entry->key); 1136 free(fentry);
712 free(entry->path); 1137}
713 eina_stringshare_del(entry->loader_data); 1138
714 free(entry); 1139static void
1140_file_data_free(File_Data *fd)
1141{
1142 if (!fd) return;
1143 if (!fd->refcount) return;
1144 if (--fd->refcount == 0)
1145 {
1146 cserve2_shared_string_del(fd->key);
1147 cserve2_shared_string_del(fd->path);
1148 cserve2_shared_string_del(fd->loader_data);
1149 }
715} 1150}
716 1151
717static void 1152static void
718_hash_file_entry_free(void *data) 1153_hash_file_entry_free(void *data)
719{ 1154{
720 File_Data *entry = data; 1155 File_Entry *fentry = data;
1156 File_Data *fd;
721 // TODO: Add some checks to make sure that we are freeing an 1157 // TODO: Add some checks to make sure that we are freeing an
722 // unused entry. 1158 // unused entry.
723 1159
724 _file_id_free(entry); 1160 fd = _file_data_find(ENTRYID(fentry));
725 _file_entry_free(entry); 1161 _file_id_free(fd);
1162 _file_data_free(fd);
1163 _file_entry_free(fentry);
1164
1165 _freed_file_entry_count++;
1166 _repack();
726} 1167}
727 1168
728static void 1169static void
@@ -736,8 +1177,10 @@ _file_watch_free(void *data)
736} 1177}
737 1178
738static int 1179static int
739_font_entry_cmp(const Font_Entry *k1, int k1_length EINA_UNUSED, const Font_Entry *k2, int k2_length EINA_UNUSED) 1180_font_entry_cmp(const Font_Entry *k1, int k1_length EINA_UNUSED,
1181 const Font_Entry *k2, int k2_length EINA_UNUSED)
740{ 1182{
1183 const char *key1, *key2;
741 if (k1->src->key == k2->src->key) 1184 if (k1->src->key == k2->src->key)
742 { 1185 {
743 if (k1->size == k2->size) 1186 if (k1->size == k2->size)
@@ -748,14 +1191,19 @@ _font_entry_cmp(const Font_Entry *k1, int k1_length EINA_UNUSED, const Font_Entr
748 } 1191 }
749 return k1->size - k2->size; 1192 return k1->size - k2->size;
750 } 1193 }
751 return strcmp(k1->src->key, k2->src->key); 1194 key1 = cserve2_shared_string_get(k1->src->key);
1195 key2 = cserve2_shared_string_get(k2->src->key);
1196 return strcmp(key1, key2);
752} 1197}
753 1198
754static int 1199static int
755_font_entry_key_hash(const Font_Entry *key, int key_length EINA_UNUSED) 1200_font_entry_key_hash(const Font_Entry *key, int key_length EINA_UNUSED)
756{ 1201{
757 int hash; 1202 const char *keystr;
758 hash = eina_hash_djb2(key->src->key, eina_stringshare_strlen(key->src->key) + 1); 1203 int hash;
1204
1205 keystr = cserve2_shared_string_get(key->src->key);
1206 hash = eina_hash_djb2(keystr, strlen(keystr));
759 hash ^= eina_hash_int32(&key->rend_flags, sizeof(int)); 1207 hash ^= eina_hash_int32(&key->rend_flags, sizeof(int));
760 hash ^= eina_hash_int32(&key->size, sizeof(int)); 1208 hash ^= eina_hash_int32(&key->size, sizeof(int));
761 hash ^= eina_hash_int32(&key->dpi, sizeof(int)); 1209 hash ^= eina_hash_int32(&key->dpi, sizeof(int));
@@ -763,101 +1211,131 @@ _font_entry_key_hash(const Font_Entry *key, int key_length EINA_UNUSED)
763 return hash; 1211 return hash;
764} 1212}
765 1213
1214static int
1215_font_entry_memory_usage_get(Font_Entry *fe)
1216{
1217 int size = sizeof(Font_Entry);
1218
1219 if (!fe) return 0;
1220 if (!fe->mempool)
1221 return size;
1222
1223 size += cserve2_shared_mempool_size_get(fe->mempool);
1224 size += fe->nglyphs * sizeof(Glyph_Entry);
1225
1226 return size;
1227}
1228
766static void 1229static void
767_font_entry_free(Font_Entry *fe) 1230_font_entry_free(Font_Entry *fe)
768{ 1231{
769 fash_gl_free(fe->glyphs); 1232 Font_Data *fd;
770 fe->src->references--; 1233 int size, k;
771 if (fe->ft) cserve2_font_ft_free(fe->ft); 1234
772 if (fe->src->references <= 0) 1235 if (!fe) return;
773 eina_hash_del_by_key(font_sources, fe->src->key); 1236 size = _font_entry_memory_usage_get(fe);
1237
1238 DBG("Font memory usage down: %d -> %d / %d", font_mem_usage,
1239 font_mem_usage - size, max_font_usage);
1240 font_mem_usage -= size;
1241
1242 fd = _font_data_find(fe->font_data_id);
1243 if (fd)
1244 {
1245 fd->refcount = 0;
1246 cserve2_shared_string_del(fd->glyph_index_shm);
1247 cserve2_shared_string_del(fd->file);
1248 cserve2_shared_string_del(fd->name);
1249 }
1250
1251 for (k = 0; k < 3; k++)
1252 fash_gl_free(fe->glyph_entries[k]);
1253 cserve2_shared_mempool_del(fe->mempool);
1254 cserve2_font_ft_free(fe->ft);
1255 fe->src->refcount--;
1256 if (fe->src->refcount <= 0)
1257 {
1258 const char *key = cserve2_shared_string_get(fe->src->key);
1259 eina_hash_del_by_key(font_sources, key);
1260 }
774 free(fe); 1261 free(fe);
1262
1263 _freed_font_entry_count++;
1264 _repack();
775} 1265}
776 1266
777static void 1267static void
778_glyph_free_cb(void *data) 1268_glyph_free_cb(void *data)
779{ 1269{
780 Glyph_Entry *gl = data; 1270 Glyph_Entry *gl = data;
1271 Glyph_Data *gldata;
1272
1273 if (!gl || !gl->fe) return;
1274
1275 gldata = _glyph_data_find(gl->fe->mempool, gl->gldata_id);
1276 if (gldata)
1277 {
1278 cserve2_shared_string_del(gldata->mempool_id);
1279 gldata->refcount--;
1280 }
781 free(gl); 1281 free(gl);
782} 1282}
783 1283
784static void 1284static void
785_font_source_free(Font_Source *fs) 1285_font_source_free(Font_Source *fs)
786{ 1286{
787 eina_stringshare_del(fs->key); 1287 if (!fs) return;
788 eina_stringshare_del(fs->name); 1288
789 eina_stringshare_del(fs->file); 1289 cserve2_shared_string_del(fs->key);
790 if (fs->ft) cserve2_font_source_ft_free(fs->ft); 1290 cserve2_shared_string_del(fs->name);
1291 cserve2_shared_string_del(fs->file);
1292 cserve2_font_source_ft_free(fs->ft);
791 1293
792 free(fs); 1294 free(fs);
793} 1295}
794 1296
795static void 1297static void
796_font_shm_promote(Font_Cache *fc) 1298_font_lru_update(Font_Entry *fe)
797{ 1299{
798 Eina_List *l; 1300 Eina_List *l;
799 l = eina_list_data_find_list(font_shm_lru, fc); 1301 l = eina_list_data_find_list(font_shm_lru, fe);
800 font_shm_lru = eina_list_demote_list(font_shm_lru, l); 1302 if (l)
801}
802
803static int
804_font_shm_size_get(Font_Cache *fc)
805{
806 int size;
807
808 size = sizeof(*fc) + cserve2_shm_size_get(fc->shm);
809
810 return size;
811}
812
813static void
814_font_shm_free(Font_Cache *fc)
815{
816 Font_Entry *fe = fc->fe;
817 fe->caches = eina_inlist_remove(fe->caches, EINA_INLIST_GET(fc));
818 if (fc == fe->last_cache)
819 fe->last_cache = NULL;
820
821 while (fc->glyphs)
822 { 1303 {
823 Glyph_Entry *gl = EINA_INLIST_CONTAINER_GET(fc->glyphs, Glyph_Entry); 1304 if (fe->unused)
824 fc->glyphs = eina_inlist_remove(fc->glyphs, fc->glyphs); 1305 font_shm_lru = eina_list_promote_list(font_shm_lru, l);
825 fash_gl_del(fe->glyphs, gl->index); 1306 else
1307 font_shm_lru = eina_list_demote_list(font_shm_lru, l);
826 } 1308 }
827 1309 else
828 cserve2_shm_unref(fc->shm); 1310 font_shm_lru = eina_list_append(font_shm_lru, fe);
829 free(fc);
830
831 if (!fe->caches)
832 eina_hash_del_by_key(font_entries, fe);
833} 1311}
834 1312
835static void 1313static void
836_font_shm_lru_flush(void) 1314_font_lru_flush(void)
837{ 1315{
838 Eina_List *l, *l_next; 1316 Eina_List *l, *l_next;
839 1317
840 l = font_shm_lru; 1318 l = font_shm_lru;
841 l_next = eina_list_next(l); 1319 l_next = eina_list_next(l);
842 1320
1321 DBG("Font memory usage [begin]: %d / %d", font_mem_usage, max_font_usage);
1322
843 while (l && font_mem_usage > max_font_usage) 1323 while (l && font_mem_usage > max_font_usage)
844 { 1324 {
845 int size; 1325 Font_Entry *fe;
846 Font_Cache *fc;
847 1326
848 fc = eina_list_data_get(l); 1327 fe = eina_list_data_get(l);
849 if (fc->fe->unused && fc->inuse == 0) 1328 if (fe->unused)
850 { 1329 {
851 font_shm_lru = eina_list_remove_list(font_shm_lru, l); 1330 font_shm_lru = eina_list_remove_list(font_shm_lru, l);
852 size = _font_shm_size_get(fc); 1331 eina_hash_del_by_key(font_entries, fe);
853 size += fc->nglyphs * sizeof(Glyph_Entry);
854 _font_shm_free(fc);
855 font_mem_usage -= size;
856 } 1332 }
857 1333
858 l = l_next; 1334 l = l_next;
859 l_next = eina_list_next(l); 1335 l_next = eina_list_next(l);
860 } 1336 }
1337
1338 DBG("Font memory usage [end]: %d / %d", font_mem_usage, max_font_usage);
861} 1339}
862 1340
863void 1341void
@@ -866,7 +1344,7 @@ cserve2_cache_init(void)
866 file_ids = eina_hash_string_superfast_new(NULL); 1344 file_ids = eina_hash_string_superfast_new(NULL);
867 file_entries = eina_hash_int32_new(_hash_file_entry_free); 1345 file_entries = eina_hash_int32_new(_hash_file_entry_free);
868 image_ids = eina_hash_string_superfast_new(NULL); 1346 image_ids = eina_hash_string_superfast_new(NULL);
869 image_entries = eina_hash_string_superfast_new(_hash_image_entry_free); 1347 image_entries = eina_hash_int32_new(_hash_image_entry_free);
870 file_watch = eina_hash_string_superfast_new(_file_watch_free); 1348 file_watch = eina_hash_string_superfast_new(_file_watch_free);
871 1349
872 font_sources = eina_hash_string_small_new(EINA_FREE_CB(_font_source_free)); 1350 font_sources = eina_hash_string_small_new(EINA_FREE_CB(_font_source_free));
@@ -875,15 +1353,23 @@ cserve2_cache_init(void)
875 EINA_KEY_HASH(_font_entry_key_hash), 1353 EINA_KEY_HASH(_font_entry_key_hash),
876 EINA_FREE_CB(_font_entry_free), 1354 EINA_FREE_CB(_font_entry_free),
877 5); 1355 5);
1356
1357 _generation_id++;
1358 _file_data_array = cserve2_shared_array_new(FILE_DATA_ARRAY_TAG,
1359 _generation_id,
1360 sizeof(File_Data), 0);
1361 _image_data_array = cserve2_shared_array_new(IMAGE_DATA_ARRAY_TAG,
1362 _generation_id,
1363 sizeof(Image_Data), 0);
1364 _font_data_array = cserve2_shared_array_new(FONT_DATA_ARRAY_TAG,
1365 _generation_id,
1366 sizeof(Font_Data), 0);
878} 1367}
879 1368
880void 1369void
881cserve2_cache_shutdown(void) 1370cserve2_cache_shutdown(void)
882{ 1371{
883 Font_Cache *fc; 1372 _shutdown = EINA_TRUE;
884
885 EINA_LIST_FREE(font_shm_lru, fc)
886 _font_shm_free(fc);
887 1373
888 eina_hash_free(image_entries); 1374 eina_hash_free(image_entries);
889 eina_hash_free(image_ids); 1375 eina_hash_free(image_ids);
@@ -893,6 +1379,10 @@ cserve2_cache_shutdown(void)
893 1379
894 eina_hash_free(font_entries); 1380 eina_hash_free(font_entries);
895 eina_hash_free(font_sources); 1381 eina_hash_free(font_sources);
1382
1383 cserve2_shared_array_del(_file_data_array);
1384 cserve2_shared_array_del(_image_data_array);
1385 cserve2_shared_array_del(_font_data_array);
896} 1386}
897 1387
898static Reference * 1388static Reference *
@@ -912,25 +1402,31 @@ _entry_reference_add(Entry *entry, Client *client, unsigned int client_entry_id)
912} 1402}
913 1403
914static void 1404static void
915_entry_unused_push(Image_Data *e) 1405_entry_unused_push(Image_Entry *ientry)
916{ 1406{
917 int size = _image_entry_size_get(e); 1407 Image_Data *idata;
1408 int size;
918 1409
919 if ((size > max_unused_mem_usage) || !(e->doload)) 1410 idata = _image_data_find(ENTRYID(ientry));
1411 if (!idata) return;
1412 idata->unused = EINA_TRUE;
1413
1414 size = _image_entry_size_get(ientry);
1415 if ((size > max_unused_mem_usage) || !(idata->doload))
920 { 1416 {
921 eina_hash_del_by_key(image_entries, &e->base.id); 1417 eina_hash_del_by_key(image_entries, &idata->id);
922 return; 1418 return;
923 } 1419 }
924 while (image_entries_lru && 1420 while (image_entries_lru &&
925 (size > (max_unused_mem_usage - unused_mem_usage))) 1421 (size > (max_unused_mem_usage - unused_mem_usage)))
926 { 1422 {
927 Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru)); 1423 Image_Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
928 Eina_Bool ok = eina_hash_del_by_key(image_entries, &ie->id); 1424 Eina_Bool ok = eina_hash_del_by_key(image_entries, &(ENTRYID(ie)));
929 if (!ok) 1425 if (!ok)
930 { 1426 {
931 DBG("Image %d was not found in the hash table!", ie->id); 1427 DBG("Image %d was not found in the hash table!", ENTRYID(ie));
932 image_entries_lru = eina_list_remove(image_entries_lru, ie); 1428 image_entries_lru = eina_list_remove(image_entries_lru, ie);
933 _image_entry_free((Image_Data*) ie); 1429 _image_entry_free(ie);
934 } 1430 }
935 } 1431 }
936 if (!image_entries_lru && (unused_mem_usage != 0)) 1432 if (!image_entries_lru && (unused_mem_usage != 0))
@@ -939,8 +1435,7 @@ _entry_unused_push(Image_Data *e)
939 unused_mem_usage); 1435 unused_mem_usage);
940 unused_mem_usage = 0; 1436 unused_mem_usage = 0;
941 } 1437 }
942 image_entries_lru = eina_list_append(image_entries_lru, e); 1438 image_entries_lru = eina_list_append(image_entries_lru, ientry);
943 e->unused = EINA_TRUE;
944 unused_mem_usage += size; 1439 unused_mem_usage += size;
945} 1440}
946 1441
@@ -954,32 +1449,43 @@ _entry_reference_del(Entry *entry, Reference *ref)
954 1449
955 if (entry->type == CSERVE2_IMAGE_FILE) 1450 if (entry->type == CSERVE2_IMAGE_FILE)
956 { 1451 {
957 File_Data *fentry = (File_Data *)entry; 1452 File_Entry *fentry = (File_Entry *) entry;
1453 File_Data *fd = _file_data_find(entry->id);
958 1454
959 if (fentry->invalid) 1455 if (fd)
960 _file_entry_free(fentry); 1456 {
961 else if (!fentry->images) 1457 // FIXME: Check difference with master (2 cases vs. only one)
962 eina_hash_del_by_key(file_entries, &entry->id); 1458 if (fd->invalid || !fentry->images)
1459 eina_hash_del_by_key(file_entries, &entry->id);
1460 }
1461 else
1462 ERR("File data not found for id %u", entry->id);
963 /* don't free file entries that have images attached to it, they will 1463 /* don't free file entries that have images attached to it, they will
964 * be freed when the last unused image is freed */ 1464 * be freed when the last unused image is freed */
965 } 1465 }
966 else if (entry->type == CSERVE2_IMAGE_DATA) 1466 else if (entry->type == CSERVE2_IMAGE_DATA)
967 { 1467 {
968 Image_Data *ientry = (Image_Data *)entry; 1468 Image_Entry *ientry = (Image_Entry *) entry;
1469 Image_Data *idata = _image_data_find(entry->id);
969 1470
970 if (!ientry->file) 1471 if (!idata || !idata->file_id)
971 eina_hash_del_by_key(image_entries, &entry->id); 1472 eina_hash_del_by_key(image_entries, &entry->id);
972 else if (ientry->file->invalid)
973 _image_entry_free(ientry);
974 else 1473 else
975 _entry_unused_push(ientry); 1474 {
1475 File_Data *fdata = _file_data_find(idata->file_id);
1476
1477 if (fdata->invalid)
1478 _image_entry_free(ientry);
1479 else
1480 _entry_unused_push(ientry);
1481 }
976 } 1482 }
977 else if (entry->type == CSERVE2_FONT_ENTRY) 1483 else if (entry->type == CSERVE2_FONT_ENTRY)
978 { 1484 {
979 Font_Entry *fe = (Font_Entry *)entry; 1485 Font_Entry *fe = (Font_Entry *) entry;
980 fe->unused = EINA_TRUE; 1486 fe->unused = EINA_TRUE;
981 if (!fe->caches) 1487 _font_lru_update(fe);
982 eina_hash_del_by_key(font_entries, fe); 1488 _font_lru_flush();
983 } 1489 }
984 else 1490 else
985 ERR("Wrong type of entry."); 1491 ERR("Wrong type of entry.");
@@ -1041,6 +1547,14 @@ cserve2_cache_client_new(Client *client)
1041 client->files.referencing = eina_hash_int32_new(_entry_free_cb); 1547 client->files.referencing = eina_hash_int32_new(_entry_free_cb);
1042 client->images.referencing = eina_hash_int32_new(_entry_free_cb); 1548 client->images.referencing = eina_hash_int32_new(_entry_free_cb);
1043 client->fonts.referencing = NULL; 1549 client->fonts.referencing = NULL;
1550
1551 cserve2_index_list_send(_generation_id,
1552 cserve2_shared_strings_index_name_get(),
1553 cserve2_shared_strings_table_name_get(),
1554 cserve2_shared_array_name_get(_file_data_array),
1555 cserve2_shared_array_name_get(_image_data_array),
1556 cserve2_shared_array_name_get(_font_data_array),
1557 client);
1044} 1558}
1045 1559
1046void 1560void
@@ -1059,93 +1573,147 @@ cserve2_cache_client_del(Client *client)
1059 } 1573 }
1060} 1574}
1061 1575
1062static Image_Data * 1576static Image_Entry *
1063_image_entry_new(Client *client, int rid, 1577_image_entry_new(Client *client, int rid,
1064 unsigned int file_id, unsigned int image_id, 1578 unsigned int client_file_id, unsigned int client_image_id,
1065 Evas_Image_Load_Opts *opts) 1579 const Evas_Image_Load_Opts *opts, char *buf, size_t buf_size)
1066{ 1580{
1067 Reference *ref; 1581 Reference *ref, *oldref;
1068 Image_Data *im_entry; 1582 Image_Entry *ientry;
1583 Image_Data *idata;
1584 File_Data *fd;
1585 int idata_id;
1586 unsigned int image_id;
1069 1587
1070 ref = eina_hash_find(client->files.referencing, &file_id); 1588 ref = eina_hash_find(client->files.referencing, &client_file_id);
1071 if (!ref) 1589 if (!ref)
1072 { 1590 {
1073 ERR("Couldn't find file id: %d, for image id: %d", 1591 ERR("Couldn't find file id: %d, for image id: %d",
1074 file_id, image_id); 1592 client_file_id, image_id);
1075 cserve2_client_error_send(client, rid, 1593 cserve2_client_error_send(client, rid,
1076 CSERVE2_INVALID_CACHE); 1594 CSERVE2_INVALID_CACHE);
1077 return NULL; 1595 return NULL;
1078 } 1596 }
1079 if (((File_Data *)ref->entry)->invalid) 1597 fd = _file_data_find(ref->entry->id);
1598 if (!fd || fd->invalid)
1080 { 1599 {
1081 cserve2_client_error_send(client, rid, 1600 cserve2_client_error_send(client, rid,
1082 CSERVE2_FILE_CHANGED); 1601 CSERVE2_FILE_CHANGED);
1083 return NULL; 1602 return NULL;
1084 } 1603 }
1085 1604
1086 im_entry = calloc(1, sizeof(*im_entry)); 1605 idata_id = cserve2_shared_array_item_new(_image_data_array);
1087 im_entry->base.type = CSERVE2_IMAGE_DATA; 1606 idata = cserve2_shared_array_item_data_get(_image_data_array, idata_id);
1088 im_entry->file_id = ref->entry->id; 1607 if (idata_id < 0 || !idata)
1089 im_entry->file = (File_Data *)ref->entry; 1608 {
1609 ERR("Could not create new image entry in shared array");
1610 cserve2_client_error_send(client, rid,
1611 CSERVE2_RESOURCE_ALLOCATION_FAILED);
1612 return NULL;
1613 }
1614
1615 image_id = ++_entry_id;
1616 while (eina_hash_find(image_entries, &image_id))
1617 image_id = ++_entry_id;
1618
1619 DBG("Creating new image entry: %u at index %d in shm %s",
1620 image_id, idata_id, cserve2_shared_array_name_get(_image_data_array));
1621
1622 ientry = calloc(1, sizeof(*ientry));
1623 ientry->base.id = image_id;
1624 ientry->base.type = CSERVE2_IMAGE_DATA;
1090 if (opts) 1625 if (opts)
1091 { 1626 {
1092 im_entry->opts.dpi = opts->dpi; 1627 idata->opts.dpi = opts->dpi;
1093 im_entry->opts.w = opts->w; 1628 idata->opts.w = opts->w;
1094 im_entry->opts.h = opts->h; 1629 idata->opts.h = opts->h;
1095 im_entry->opts.scale_down_by = opts->scale_down_by; 1630 idata->opts.scale_down_by = opts->scale_down_by;
1096 im_entry->opts.region.x = opts->region.x; 1631 idata->opts.region.x = opts->region.x;
1097 im_entry->opts.region.y = opts->region.y; 1632 idata->opts.region.y = opts->region.y;
1098 im_entry->opts.region.w = opts->region.w; 1633 idata->opts.region.w = opts->region.w;
1099 im_entry->opts.region.h = opts->region.h; 1634 idata->opts.region.h = opts->region.h;
1100 im_entry->opts.scale_load.src_x = opts->scale_load.src_x; 1635 idata->opts.scale_load.src_x = opts->scale_load.src_x;
1101 im_entry->opts.scale_load.src_y = opts->scale_load.src_y; 1636 idata->opts.scale_load.src_y = opts->scale_load.src_y;
1102 im_entry->opts.scale_load.src_w = opts->scale_load.src_w; 1637 idata->opts.scale_load.src_w = opts->scale_load.src_w;
1103 im_entry->opts.scale_load.src_h = opts->scale_load.src_h; 1638 idata->opts.scale_load.src_h = opts->scale_load.src_h;
1104 im_entry->opts.scale_load.dst_w = opts->scale_load.dst_w; 1639 idata->opts.scale_load.dst_w = opts->scale_load.dst_w;
1105 im_entry->opts.scale_load.dst_h = opts->scale_load.dst_h; 1640 idata->opts.scale_load.dst_h = opts->scale_load.dst_h;
1106 im_entry->opts.scale_load.smooth = opts->scale_load.smooth; 1641 idata->opts.scale_load.smooth = opts->scale_load.smooth;
1107 im_entry->opts.scale_load.scale_hint = opts->scale_load.scale_hint; 1642 idata->opts.scale_load.scale_hint = opts->scale_load.scale_hint;
1108 im_entry->opts.degree = opts->degree; 1643 idata->opts.degree = opts->degree;
1109 im_entry->opts.orientation = opts->orientation; 1644 idata->opts.orientation = opts->orientation;
1110 } 1645 }
1111 1646 idata->valid = EINA_FALSE;
1112 return im_entry; 1647 idata->file_id = ref->entry->id;
1648 idata->refcount = 1;
1649 idata->id = image_id;
1650
1651 _image_key_set(idata->file_id, opts, buf, buf_size);
1652 eina_hash_add(image_entries, &image_id, ientry);
1653 eina_hash_add(image_ids, buf, (void *)(intptr_t) image_id);
1654
1655 if (client_image_id)
1656 {
1657 oldref = eina_hash_find(client->images.referencing, &client_image_id);
1658 ref = _entry_reference_add(ASENTRY(ientry), client, client_image_id);
1659 if (oldref)
1660 eina_hash_del_by_key(client->images.referencing, &client_image_id);
1661 eina_hash_add(client->images.referencing, &client_image_id, ref);
1662 }
1663 // else: See _cserve2_cache_fast_scaling_check()
1664
1665 return ientry;
1113} 1666}
1114 1667
1115static void 1668static void
1116_file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, void *data) 1669_file_changed_cb(const char *path EINA_UNUSED, Eina_Bool deleted EINA_UNUSED, void *data)
1117{ 1670{
1118 File_Watch *fw = data; 1671 File_Watch *fw = data;
1119 File_Data *e; 1672 File_Data *fd;
1120 Eina_List *l; 1673 Eina_List *l;
1121 1674
1122 EINA_LIST_FOREACH(fw->entries, l, e) 1675 EINA_LIST_FOREACH(fw->entries, l, fd)
1123 { 1676 {
1124 Eina_List *ll; 1677 Eina_List *ll;
1125 Image_Data *ie; 1678 Image_Entry *ie;
1679 File_Entry *fentry;
1126 1680
1127 e->invalid = EINA_TRUE; 1681 fd->invalid = EINA_TRUE;
1128 e->watcher = NULL; 1682 fentry = _file_entry_find(fd->id);
1683 if (!fentry) continue;
1129 1684
1130 EINA_LIST_FOREACH(e->images, ll, ie) 1685 fentry->watcher = NULL;
1686
1687 EINA_LIST_FOREACH(fentry->images, ll, ie)
1131 { 1688 {
1132 _image_id_free(ie); 1689 Image_Data *idata;
1133 eina_hash_set(image_entries, &ie->base.id, NULL); 1690
1134 if (ie->base.request /*&& !ie->base.request->processing*/) 1691 eina_hash_set(image_entries, &ENTRYID(ie), NULL);
1135 cserve2_request_cancel_all(ie->base.request, 1692 if (ASENTRY(ie)->request /*&& !ie->base.request->processing*/)
1693 cserve2_request_cancel_all(ASENTRY(ie)->request,
1136 CSERVE2_FILE_CHANGED); 1694 CSERVE2_FILE_CHANGED);
1137 ie->base.request = NULL; 1695 ASENTRY(ie)->request = NULL;
1138 if (ie->unused) 1696
1139 _image_entry_free(ie); 1697 idata = _image_data_find(ENTRYID(ie));
1698 if (idata)
1699 {
1700 _image_id_free(idata);
1701 if (idata->unused)
1702 _image_entry_free(ie);
1703 }
1140 } 1704 }
1141 1705
1142 _file_id_free(e); 1706 _file_id_free(fd);
1143 eina_hash_set(file_entries, &e->base.id, NULL); 1707 eina_hash_set(file_entries, &fd->id, NULL);
1144 if (e->base.request /*&& !e->base.request->processing*/) 1708 if (ASENTRY(fentry)->request
1145 cserve2_request_cancel_all(e->base.request, CSERVE2_FILE_CHANGED); 1709 /*&& !ASENTRY(fentry)->request->processing*/)
1146 e->base.request = NULL; 1710 {
1147 if (!e->images && !e->base.references) 1711 cserve2_request_cancel_all(ASENTRY(fentry)->request,
1148 _file_entry_free(e); 1712 CSERVE2_FILE_CHANGED);
1713 ASENTRY(fentry)->request = NULL;
1714 }
1715 if (!fentry->images && !ASENTRY(fentry)->references)
1716 _hash_file_entry_free(fentry);
1149 } 1717 }
1150 1718
1151 eina_hash_del_by_key(file_watch, fw->path); 1719 eina_hash_del_by_key(file_watch, fw->path);
@@ -1168,14 +1736,14 @@ _cserve2_font_entry_find(const char *name, unsigned int size, unsigned int rend_
1168 Font_Source tmp_fs; 1736 Font_Source tmp_fs;
1169 Font_Entry *fe; 1737 Font_Entry *fe;
1170 1738
1171 tmp_fs.key = eina_stringshare_add(name); 1739 tmp_fs.key = cserve2_shared_string_add(name);
1172 tmp_fe.src = &tmp_fs; 1740 tmp_fe.src = &tmp_fs;
1173 tmp_fe.size = size; 1741 tmp_fe.size = size;
1174 tmp_fe.rend_flags = rend_flags; 1742 tmp_fe.rend_flags = rend_flags;
1175 tmp_fe.dpi = dpi; 1743 tmp_fe.dpi = dpi;
1176 1744
1177 fe = eina_hash_find(font_entries, &tmp_fe); 1745 fe = eina_hash_find(font_entries, &tmp_fe);
1178 eina_stringshare_del(tmp_fs.key); 1746 cserve2_shared_string_del(tmp_fs.key);
1179 1747
1180 return fe; 1748 return fe;
1181} 1749}
@@ -1191,8 +1759,8 @@ _font_load_request_build(void *data, int *size)
1191 msg->rend_flags = fe->rend_flags; 1759 msg->rend_flags = fe->rend_flags;
1192 msg->size = fe->size; 1760 msg->size = fe->size;
1193 msg->dpi = fe->dpi; 1761 msg->dpi = fe->dpi;
1194 msg->name = fe->src->name; 1762 msg->name = cserve2_shared_string_get(fe->src->name);
1195 msg->file = fe->src->file; 1763 msg->file = cserve2_shared_string_get(fe->src->file);
1196 1764
1197 *size = 0; 1765 *size = 0;
1198 1766
@@ -1223,7 +1791,6 @@ _font_load_request_response(Font_Entry *fe, Slave_Msg_Font_Loaded *msg, int *siz
1223 1791
1224 if (fe->base.request) fe->base.request = NULL; 1792 if (fe->base.request) fe->base.request = NULL;
1225 1793
1226 /* could be a function, but it's too basic and only used here */
1227 resp = calloc(1, sizeof(*resp)); 1794 resp = calloc(1, sizeof(*resp));
1228 resp->base.type = CSERVE2_FONT_LOADED; 1795 resp->base.type = CSERVE2_FONT_LOADED;
1229 *size = sizeof(*resp); 1796 *size = sizeof(*resp);
@@ -1253,16 +1820,23 @@ static Slave_Request_Funcs _font_load_funcs = {
1253static Eina_Bool 1820static Eina_Bool
1254_glyphs_request_check(Glyphs_Request *req, Eina_Bool report_load) 1821_glyphs_request_check(Glyphs_Request *req, Eina_Bool report_load)
1255{ 1822{
1256 unsigned int i; 1823 unsigned int i, hint;
1257 Font_Entry *fe = req->fe; 1824 Font_Entry *fe = req->fe;
1258 1825
1259 req->answer = malloc(sizeof(*req->answer) * req->nglyphs); 1826 req->answer = malloc(sizeof(*req->answer) * req->nglyphs);
1260 req->nanswer = 0; 1827 req->nanswer = 0;
1261 1828
1829 hint = req->hint;
1830 if (hint > 2)
1831 {
1832 WRN("Invalid font hint requested. Defaulting to 0.");
1833 hint = 0;
1834 }
1835
1262 for (i = req->current; i < req->nglyphs; i++) 1836 for (i = req->current; i < req->nglyphs; i++)
1263 { 1837 {
1264 Glyph_Entry *ge; 1838 Glyph_Entry *ge;
1265 ge = fash_gl_find(fe->glyphs, req->glyphs[i]); 1839 ge = fash_gl_find(fe->glyph_entries[hint], req->glyphs[i]);
1266 if (ge) 1840 if (ge)
1267 { 1841 {
1268 req->answer[req->nanswer++] = ge; 1842 req->answer[req->nanswer++] = ge;
@@ -1272,7 +1846,7 @@ _glyphs_request_check(Glyphs_Request *req, Eina_Bool report_load)
1272 fe->gl_saved_time += 1846 fe->gl_saved_time +=
1273 (fe->gl_load_time / fe->nglyphs); 1847 (fe->gl_load_time / fe->nglyphs);
1274#endif 1848#endif
1275 ge->fc->inuse++; 1849 //ge->fc->inuse++;
1276 } 1850 }
1277 else 1851 else
1278 break; 1852 break;
@@ -1284,134 +1858,88 @@ _glyphs_request_check(Glyphs_Request *req, Eina_Bool report_load)
1284 return (req->nanswer == req->nglyphs); 1858 return (req->nanswer == req->nglyphs);
1285} 1859}
1286 1860
1287/* organize answer (cache1{gl1, gl2,}, cache2{gl3,gl4,gl5}, cache3{gl6})
1288 */
1289static Eina_List *
1290_glyphs_group_create(Glyphs_Request *req)
1291{
1292 Eina_List *groups = NULL;
1293 unsigned int i;
1294
1295 for (i = 0; i < req->nanswer; i++)
1296 {
1297 Eina_List *l;
1298 Glyphs_Group *iter, *gg = NULL;
1299 Font_Cache *fc = req->answer[i]->fc;
1300
1301 EINA_LIST_FOREACH(groups, l, iter)
1302 {
1303 if (iter->fc == fc)
1304 {
1305 gg = iter;
1306 break;
1307 }
1308 }
1309
1310 if (!gg)
1311 {
1312 gg = calloc(1, sizeof(*gg));
1313 gg->fc = fc;
1314 groups = eina_list_append(groups, gg);
1315 }
1316 gg->glyphs = eina_list_append(gg->glyphs, req->answer[i]);
1317 }
1318
1319 return groups;
1320}
1321
1322static Msg_Font_Glyphs_Loaded * 1861static Msg_Font_Glyphs_Loaded *
1323_glyphs_loaded_msg_create(Glyphs_Request *req, int *resp_size) 1862_glyphs_loaded_msg_create(Glyphs_Request *req, int *resp_size)
1324{ 1863{
1325 Msg_Font_Glyphs_Loaded msg; 1864 Msg_Font_Glyphs_Loaded *msg;
1865 Shared_Array *sa;
1326 unsigned int size; 1866 unsigned int size;
1327 Eina_List *ll, *answers = NULL; 1867 const char *shmname, *idxname;
1328 const char *shmname; 1868 unsigned int shmname_size, idxname_size;
1329 unsigned int shmsize; 1869 unsigned int k;
1330 unsigned int intsize; 1870 char *response, *buf;
1331 char *resp, *buf; 1871
1332 Glyphs_Group *iter; 1872 shmname = cserve2_shared_mempool_name_get(req->fe->mempool);
1333 1873 if (!shmname) return NULL;
1334 memset(&msg, 0, sizeof(msg)); 1874 shmname_size = strlen(shmname) + 1;
1335 msg.base.type = CSERVE2_FONT_GLYPHS_LOADED; 1875
1336 1876 sa = cserve2_shared_mempool_index_get(req->fe->mempool);
1337 answers = _glyphs_group_create(req); 1877 idxname = cserve2_shared_array_name_get(sa);
1338 msg.ncaches = eina_list_count(answers); 1878 if (!idxname) return NULL;
1339 size = sizeof(msg); 1879 idxname_size = strlen(idxname) + 1;
1340 1880
1341 // calculate size of message 1881 size = sizeof(Msg_Font_Glyphs_Loaded);
1342 // ncaches * sizeof(cache) + nglyphs1 * sizeof(glyph) + 1882 size += sizeof(int) * 3;
1343 // nglyphs2 * sizeof(glyph)... 1883 size += shmname_size + idxname_size;
1344 1884 size += req->nanswer * 10 * sizeof(int);
1345 intsize = sizeof(unsigned int); 1885
1346 1886 response = malloc(size);
1347 EINA_LIST_FOREACH(answers, ll, iter) 1887 if (!response) return NULL;
1348 { 1888 msg = (Msg_Font_Glyphs_Loaded *) response;
1349 shmname = cserve2_shm_name_get(iter->fc->shm); 1889 buf = response + sizeof(Msg_Font_Glyphs_Loaded);
1350 shmsize = eina_stringshare_strlen(shmname) + 1; 1890
1351 // shm namelen + name 1891 msg->base.type = CSERVE2_FONT_GLYPHS_LOADED;
1352 size += intsize + shmsize; 1892 memcpy(buf, &shmname_size, sizeof(int));
1353 1893 buf += sizeof(int);
1354 // nglyphs 1894 memcpy(buf, shmname, shmname_size);
1355 size += intsize; 1895 buf += shmname_size;
1356 // nglyphs * (index + offset + size + rows + width + pitch + 1896 memcpy(buf, &idxname_size, sizeof(int));
1357 // num_grays + pixel_mode) 1897 buf += sizeof(int);
1358 size += eina_list_count(iter->glyphs) * 8 * intsize; 1898 memcpy(buf, idxname, idxname_size);
1359 } 1899 buf += idxname_size;
1360 1900 memcpy(buf, &req->nanswer, sizeof(int));
1361 resp = malloc(size); 1901 buf += sizeof(int);
1362 memcpy(resp, &msg, sizeof(msg)); 1902
1363 buf = resp + sizeof(msg); 1903 for (k = 0; k < req->nanswer; k++)
1364
1365 EINA_LIST_FREE(answers, iter)
1366 { 1904 {
1367 Glyph_Entry *gl; 1905 Glyph_Entry *ge;
1368 unsigned int nglyphs; 1906 Glyph_Data *gldata;
1369
1370 shmname = cserve2_shm_name_get(iter->fc->shm);
1371 shmsize = eina_stringshare_strlen(shmname) + 1;
1372 memcpy(buf, &shmsize, intsize);
1373 buf += intsize;
1374 memcpy(buf, shmname, shmsize);
1375 buf += shmsize;
1376
1377 nglyphs = eina_list_count(iter->glyphs);
1378 memcpy(buf, &nglyphs, intsize);
1379 buf += intsize;
1380
1381 iter->fc->inuse -= eina_list_count(iter->glyphs);
1382 1907
1383 EINA_LIST_FREE(iter->glyphs, gl) 1908 ge = req->answer[k];
1909 gldata = _glyph_data_find(ge->fe->mempool, ge->gldata_id);
1910 if (!gldata)
1384 { 1911 {
1385 memcpy(buf, &gl->index, intsize); 1912 ERR("Glyph data not found for %d", ge->gldata_id);
1386 buf += intsize; 1913 continue;
1387 memcpy(buf, &gl->offset, intsize);
1388 buf += intsize;
1389 memcpy(buf, &gl->size, intsize);
1390 buf += intsize;
1391 memcpy(buf, &gl->rows, intsize);
1392 buf += intsize;
1393 memcpy(buf, &gl->width, intsize);
1394 buf += intsize;
1395 memcpy(buf, &gl->pitch, intsize);
1396 buf += intsize;
1397 memcpy(buf, &gl->num_grays, intsize);
1398 buf += intsize;
1399 memcpy(buf, &gl->pixel_mode, intsize);
1400 buf += intsize;
1401 } 1914 }
1402 1915
1403 /* We are removing SHMs from the beginning of the list, so this 1916 memcpy(buf, &gldata->index, sizeof(int));
1404 * gives a higher priority to them */ 1917 buf += sizeof(int);
1405 _font_shm_promote(iter->fc); 1918 memcpy(buf, &gldata->mempool_id, sizeof(string_t));
1406 eina_list_free(iter->glyphs); 1919 buf += sizeof(string_t);
1407 free(iter); 1920 memcpy(buf, &gldata->offset, sizeof(int));
1921 buf += sizeof(int);
1922 memcpy(buf, &gldata->size, sizeof(int));
1923 buf += sizeof(int);
1924 memcpy(buf, &gldata->rows, sizeof(int));
1925 buf += sizeof(int);
1926 memcpy(buf, &gldata->width, sizeof(int));
1927 buf += sizeof(int);
1928 memcpy(buf, &gldata->pitch, sizeof(int));
1929 buf += sizeof(int);
1930 memcpy(buf, &gldata->num_grays, sizeof(int));
1931 buf += sizeof(int);
1932 memcpy(buf, &gldata->pixel_mode, sizeof(int));
1933 buf += sizeof(int);
1934 memcpy(buf, &gldata->hint, sizeof(int));
1935 buf += sizeof(int);
1408 } 1936 }
1409 1937
1410 *resp_size = size; 1938 *resp_size = size;
1411 1939 return msg;
1412 return (Msg_Font_Glyphs_Loaded *)resp;
1413} 1940}
1414 1941
1942
1415static void 1943static void
1416_glyphs_loaded_send(Glyphs_Request *req, unsigned int rid) 1944_glyphs_loaded_send(Glyphs_Request *req, unsigned int rid)
1417{ 1945{
@@ -1458,7 +1986,10 @@ _file_path_join(const char *path, const char *end)
1458} 1986}
1459 1987
1460static Glyphs_Request * 1988static Glyphs_Request *
1461_glyphs_request_create(Client *client, const char *source, const char *name, unsigned int hint, unsigned int rend_flags, unsigned int size, unsigned int dpi, unsigned int *glyphs, unsigned int nglyphs) 1989_glyphs_request_create(Client *client, const char *source, const char *name,
1990 unsigned int hint, unsigned int rend_flags,
1991 unsigned int size, unsigned int dpi,
1992 unsigned int *glyphs, unsigned int nglyphs)
1462{ 1993{
1463 char *fullname; 1994 char *fullname;
1464 Glyphs_Request *req = calloc(1, sizeof(*req)); 1995 Glyphs_Request *req = calloc(1, sizeof(*req));
@@ -1504,7 +2035,7 @@ _glyphs_request_free(Glyphs_Request *req)
1504static void 2035static void
1505_glyphs_load_request_prepare(Glyphs_Request *req) 2036_glyphs_load_request_prepare(Glyphs_Request *req)
1506{ 2037{
1507 unsigned int i, max; 2038 unsigned int i, max, hint;
1508 req->nrender = 0; 2039 req->nrender = 0;
1509 Font_Entry *fe = req->fe; 2040 Font_Entry *fe = req->fe;
1510 2041
@@ -1514,6 +2045,13 @@ _glyphs_load_request_prepare(Glyphs_Request *req)
1514 return; 2045 return;
1515 } 2046 }
1516 2047
2048 hint = req->hint;
2049 if (hint > 2)
2050 {
2051 WRN("Invalid font hint requested. Defaulting to 0.");
2052 hint = 0;
2053 }
2054
1517 // Won't render more than this number of glyphs 2055 // Won't render more than this number of glyphs
1518 max = req->nglyphs - req->nanswer; 2056 max = req->nglyphs - req->nanswer;
1519 req->render = malloc(sizeof(*req->render) * max); 2057 req->render = malloc(sizeof(*req->render) * max);
@@ -1521,7 +2059,7 @@ _glyphs_load_request_prepare(Glyphs_Request *req)
1521 for (i = req->current; i < req->nglyphs; i++) 2059 for (i = req->current; i < req->nglyphs; i++)
1522 { 2060 {
1523 Glyph_Entry *ge; 2061 Glyph_Entry *ge;
1524 ge = fash_gl_find(fe->glyphs, req->glyphs[i]); 2062 ge = fash_gl_find(fe->glyph_entries[hint], req->glyphs[i]);
1525 if (ge) 2063 if (ge)
1526 { 2064 {
1527 req->answer[req->nanswer++] = ge; 2065 req->answer[req->nanswer++] = ge;
@@ -1531,7 +2069,7 @@ _glyphs_load_request_prepare(Glyphs_Request *req)
1531 fe->gl_saved_time += 2069 fe->gl_saved_time +=
1532 (fe->gl_load_time / fe->nglyphs); 2070 (fe->gl_load_time / fe->nglyphs);
1533#endif 2071#endif
1534 ge->fc->inuse++; 2072 //ge->fc->inuse++;
1535 } 2073 }
1536 else 2074 else
1537 req->render[req->nrender++] = req->glyphs[i]; 2075 req->render[req->nrender++] = req->glyphs[i];
@@ -1544,7 +2082,6 @@ _glyphs_load_request_build(void *data, int *size EINA_UNUSED)
1544 Glyphs_Request *req = data; 2082 Glyphs_Request *req = data;
1545 Slave_Msg_Font_Glyphs_Load *msg = NULL; 2083 Slave_Msg_Font_Glyphs_Load *msg = NULL;
1546 Font_Entry *fe = req->fe; 2084 Font_Entry *fe = req->fe;
1547 Font_Cache *fc;
1548 2085
1549#ifdef DEBUG_LOAD_TIME 2086#ifdef DEBUG_LOAD_TIME
1550 gettimeofday(&fe->rstart, NULL); 2087 gettimeofday(&fe->rstart, NULL);
@@ -1559,15 +2096,7 @@ _glyphs_load_request_build(void *data, int *size EINA_UNUSED)
1559 msg->font.rend_flags = fe->rend_flags; 2096 msg->font.rend_flags = fe->rend_flags;
1560 msg->glyphs.nglyphs = req->nrender; 2097 msg->glyphs.nglyphs = req->nrender;
1561 msg->glyphs.glyphs = req->render; 2098 msg->glyphs.glyphs = req->render;
1562 2099 msg->cache.mempool = fe->mempool;
1563 // Trying to reuse last filled cache.
1564 fc = fe->last_cache;
1565 if (fc)
1566 {
1567 msg->cache.shm = fc->shm;
1568 msg->cache.usage = fc->usage;
1569 msg->cache.nglyphs = fc->nglyphs;
1570 }
1571 2100
1572 return msg; 2101 return msg;
1573} 2102}
@@ -1580,67 +2109,80 @@ _glyphs_load_request_free(void *msg, void *data)
1580} 2109}
1581 2110
1582static Msg_Font_Glyphs_Loaded * 2111static Msg_Font_Glyphs_Loaded *
1583_glyphs_load_request_response(Glyphs_Request *req, Slave_Msg_Font_Glyphs_Loaded *msg, int *size) 2112_glyphs_load_request_response(Glyphs_Request *req,
2113 Slave_Msg_Font_Glyphs_Loaded *msg, int *size)
1584{ 2114{
1585 Font_Entry *fe = req->fe; 2115 Font_Entry *fe = req->fe;
1586 Font_Cache *fc = NULL; 2116 Shared_Mempool *mempool = msg->mempool;
1587 unsigned int i = 0; 2117 Shared_Array *index;
2118 unsigned int j, hint;
2119 string_t shm_id;
2120 Font_Data *fd;
1588 2121
1589 if (fe->last_cache && fe->last_cache->shm == msg->caches[0]->shm) 2122 if (!msg->nglyphs)
1590 fc = fe->last_cache; 2123 return _glyphs_loaded_msg_create(req, size);
1591 2124
1592 while (i < msg->ncaches) 2125 hint = req->hint;
2126 if (hint > 2)
1593 { 2127 {
1594 unsigned int j; 2128 WRN("Invalid font hint requested. Defaulting to 0.");
1595 Slave_Msg_Font_Cache *c = msg->caches[i++]; 2129 hint = 0;
2130 }
1596 2131
1597 if (!fc) 2132 fd = _font_data_find(fe->font_data_id);
1598 { 2133
1599 fc = calloc(1, sizeof(*fc)); 2134 DBG("Font memory usage [begin]: %d / %d", font_mem_usage, max_font_usage);
1600 fe->caches = eina_inlist_append(fe->caches, EINA_INLIST_GET(fc)); 2135
1601 fe->last_cache = fc; 2136 cserve2_shared_mempool_generation_id_set(mempool, _generation_id);
1602 fc->fe = fe; 2137 index = cserve2_shared_mempool_index_get(mempool);
1603 fc->shm = c->shm; 2138
1604 fc->glyphs = NULL; 2139 if (!fd->glyph_index_shm)
1605 fc->nglyphs = 0; 2140 {
1606 fc->inuse = 0; 2141 fd->glyph_index_shm = cserve2_shared_string_add
1607 font_shm_lru = eina_list_append(font_shm_lru, fc); 2142 (cserve2_shared_array_name_get(index));
1608 font_mem_usage += _font_shm_size_get(fc); 2143 }
1609 } 2144
1610 fc->usage = c->usage; 2145 shm_id = cserve2_shared_string_add(cserve2_shared_mempool_name_get(mempool));
1611 for (j = 0; j < c->nglyphs; j++) 2146 for (j = 0; j < msg->nglyphs; j++)
2147 {
2148 Glyph_Entry *gl;
2149
2150 gl = fash_gl_find(fe->glyph_entries[hint], msg->glyphs[j].index);
2151 if (!gl)
1612 { 2152 {
1613 Glyph_Entry *gl; 2153 Glyph_Data *gldata;
1614 2154
1615 gl = fash_gl_find(fe->glyphs, c->glyphs[j].index); 2155 gldata = _glyph_data_find(mempool, msg->glyphs[j].buffer_id);
1616 if (!gl) 2156 if (!gldata)
1617 { 2157 {
1618 gl = calloc(1, sizeof(*gl)); 2158 ERR("Could not find Glyph_Data %d", msg->glyphs[j].buffer_id);
1619 gl->fe = fe; 2159 // TODO: Return error?
1620 gl->fc = fc; 2160 continue;
1621 gl->index = c->glyphs[j].index;
1622 gl->offset = c->glyphs[j].offset;
1623 gl->size = c->glyphs[j].size;
1624 gl->rows = c->glyphs[j].rows;
1625 gl->width = c->glyphs[j].width;
1626 gl->pitch = c->glyphs[j].pitch;
1627 gl->num_grays = c->glyphs[j].num_grays;
1628 gl->pixel_mode = c->glyphs[j].pixel_mode;
1629 font_mem_usage += sizeof(*gl);
1630 fc->glyphs = eina_inlist_append(fc->glyphs, EINA_INLIST_GET(gl));
1631 fc->nglyphs++;
1632 fe->nglyphs++;
1633 fash_gl_add(fe->glyphs, gl->index, gl);
1634 } 2161 }
1635 req->answer[req->nanswer++] = gl;
1636 gl->fc->inuse++;
1637 }
1638 2162
1639 free(c); // FIXME: We are freeing this here because we only do a 2163 gl = calloc(1, sizeof(*gl));
1640 // simple free on the response message. Later we need to 2164 gl->fe = fe;
1641 // setup a free callback for the slave response. 2165 gl->gldata_id = gldata->id;
1642 fc = NULL; 2166
2167 gldata->mempool_id = cserve2_shared_string_ref(shm_id);
2168 gldata->index = msg->glyphs[j].index;
2169 gldata->offset = msg->glyphs[j].offset;
2170 gldata->size = msg->glyphs[j].size;
2171 gldata->rows = msg->glyphs[j].rows;
2172 gldata->width = msg->glyphs[j].width;
2173 gldata->pitch = msg->glyphs[j].pitch;
2174 gldata->num_grays = msg->glyphs[j].num_grays;
2175 gldata->pixel_mode = msg->glyphs[j].pixel_mode;
2176 gldata->hint = hint;
2177
2178 fe->nglyphs++;
2179 fash_gl_add(fe->glyph_entries[hint], gldata->index, gl);
2180
2181 font_mem_usage += sizeof(*gl);
2182 }
2183 req->answer[req->nanswer++] = gl;
1643 } 2184 }
2185 cserve2_shared_string_del(shm_id);
1644 2186
1645#ifdef DEBUG_LOAD_TIME 2187#ifdef DEBUG_LOAD_TIME
1646 gettimeofday(&fe->rfinish, NULL); 2188 gettimeofday(&fe->rfinish, NULL);
@@ -1650,7 +2192,13 @@ _glyphs_load_request_response(Glyphs_Request *req, Slave_Msg_Font_Glyphs_Loaded
1650 fe->gl_slave_time += msg->gl_slave_time; 2192 fe->gl_slave_time += msg->gl_slave_time;
1651#endif 2193#endif
1652 2194
1653 _font_shm_lru_flush(); 2195 fe->mempool = mempool;
2196 if (!fd->mempool_shm)
2197 fd->mempool_shm = cserve2_shared_string_add(
2198 cserve2_shared_mempool_name_get(mempool));
2199
2200 DBG("Font memory usage [end]: %d / %d", font_mem_usage, max_font_usage);
2201 _font_lru_flush();
1654 2202
1655 return _glyphs_loaded_msg_create(req, size); 2203 return _glyphs_loaded_msg_create(req, size);
1656} 2204}
@@ -1668,38 +2216,44 @@ static Slave_Request_Funcs _glyphs_load_funcs = {
1668}; 2216};
1669 2217
1670static Eina_Bool 2218static Eina_Bool
1671_font_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) 2219_font_requested_size_cb(const Eina_Hash *hash EINA_UNUSED,
2220 Glyph_Data *gldata, Msg_Stats *msg)
2221{
2222 if (gldata->refcount)
2223 msg->fonts.requested_size += gldata->size;
2224
2225 return EINA_TRUE;
2226}
2227
2228
2229static Eina_Bool
2230_font_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED,
2231 const void *key EINA_UNUSED, void *data, void *fdata)
1672{ 2232{
1673 Font_Entry *fe = data; 2233 Font_Entry *fe = data;
1674 Msg_Stats *msg = fdata; 2234 Msg_Stats *msg = fdata;
1675 Font_Cache *fc; 2235 unsigned int shmsize;
1676 int nrefs = eina_list_count(fe->base.references); 2236 Shared_Array *sa;
1677 2237
1678 msg->fonts.fonts_loaded++; 2238 msg->fonts.fonts_loaded++;
1679 if (fe->unused) msg->fonts.fonts_unused++; 2239 if (fe->unused) msg->fonts.fonts_unused++;
1680 2240
1681 // accounting size 2241 // accounting size
1682 EINA_INLIST_FOREACH(fe->caches, fc) 2242 shmsize = cserve2_shared_mempool_size_get(fe->mempool);
1683 { 2243 msg->fonts.real_size += shmsize;
1684 unsigned int fc_usage, shmsize; 2244 if (fe->unused) msg->fonts.unused_size += shmsize;
1685 /* This is not real requested usage, but an approximation. We don't
1686 * know how many times each glyph would be used by each client, but
1687 * assume that a similar set of glyphs from a given font would be used
1688 * by each client, thus counting them one time per client referencing
1689 * them.
1690 */
1691 fc_usage = fc->usage * nrefs;
1692 shmsize = cserve2_shm_size_get(fc->shm);
1693 2245
1694 msg->fonts.requested_size += fc_usage; 2246 sa = cserve2_shared_mempool_index_get(fe->mempool);
1695 msg->fonts.real_size += shmsize; 2247 if (sa)
1696 if (fe->unused) msg->fonts.unused_size += shmsize; 2248 {
2249 cserve2_shared_array_foreach
2250 (sa, EINA_EACH_CB(_font_requested_size_cb), msg);
1697 } 2251 }
1698 2252
1699#ifdef DEBUG_LOAD_TIME 2253#ifdef DEBUG_LOAD_TIME
1700 // accounting fonts load time 2254 // accounting fonts load time
1701 msg->fonts.fonts_load_time += fe->base.load_time; 2255 msg->fonts.fonts_load_time += fe->base.load_time;
1702 if (fe->caches) 2256 if (fe->mempool)
1703 { 2257 {
1704 msg->fonts.fonts_used_load_time += fe->base.load_time; 2258 msg->fonts.fonts_used_load_time += fe->base.load_time;
1705 msg->fonts.fonts_used_saved_time += fe->base.saved_time; 2259 msg->fonts.fonts_used_saved_time += fe->base.saved_time;
@@ -1720,21 +2274,21 @@ static Eina_Bool
1720_image_file_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) 2274_image_file_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
1721{ 2275{
1722 Msg_Stats *msg = fdata; 2276 Msg_Stats *msg = fdata;
1723 File_Data *fd = data; 2277 File_Entry *fentry = data;
1724 2278
1725 // accounting numbers 2279 // accounting numbers
1726 msg->images.files_loaded++; 2280 msg->images.files_loaded++;
1727 2281
1728 // accounting size 2282 // accounting size
1729 msg->images.files_size += sizeof(File_Data) + 2283 msg->images.files_size += sizeof(File_Data) +
1730 eina_list_count(fd->images) * sizeof(Eina_List *) + 2284 eina_list_count(fentry->images) * sizeof(Eina_List *) +
1731 eina_list_count(fd->base.references) * 2285 eina_list_count(ASENTRY(fentry)->references) *
1732 (sizeof(Slave_Request *) + sizeof(Eina_List *)); 2286 (sizeof(Slave_Request *) + sizeof(Eina_List *));
1733 2287
1734#ifdef DEBUG_LOAD_TIME 2288#ifdef DEBUG_LOAD_TIME
1735 // accounting file entries load time 2289 // accounting file entries load time
1736 msg->images.files_load_time += fd->base.load_time; 2290 msg->images.files_load_time += ASENTRY(fentry)->load_time;
1737 msg->images.files_saved_time += fd->base.saved_time; 2291 msg->images.files_saved_time += ASENTRY(fentry)->saved_time;
1738#endif 2292#endif
1739 2293
1740 return EINA_TRUE; 2294 return EINA_TRUE;
@@ -1744,25 +2298,33 @@ static Eina_Bool
1744_image_data_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) 2298_image_data_entry_stats_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
1745{ 2299{
1746 Msg_Stats *msg = fdata; 2300 Msg_Stats *msg = fdata;
1747 Image_Data *id = data; 2301 Image_Entry *ientry = data;
1748 unsigned int image_size; 2302 Image_Data *idata;
2303 File_Data *fd;
2304
2305 idata = _image_data_find(ENTRYID(ientry));
2306 if (!idata) return EINA_TRUE;
1749 2307
1750 // accounting numbers 2308 // accounting numbers
1751 msg->images.images_loaded++; 2309 msg->images.images_loaded++;
1752 if (id->unused) msg->images.images_unused++; 2310 if (idata->unused) msg->images.images_unused++;
1753 2311
1754 // accounting size 2312 // accounting size
1755 msg->images.images_size += _image_entry_size_get(id) * 1024; 2313 msg->images.images_size += _image_entry_size_get(ientry) * 1024;
1756 if (id->unused) msg->images.unused_size += _image_entry_size_get(id) * 1024; 2314 if (idata->unused) msg->images.unused_size += _image_entry_size_get(ientry) * 1024;
1757 2315
1758 image_size = id->file->w * id->file->h * 4; 2316 fd = _file_data_find(idata->file_id);
1759 msg->images.requested_size += 2317 if (fd)
1760 (image_size * eina_list_count(id->base.references)); 2318 {
2319 unsigned int image_size = fd->w * fd->h * 4;
2320 msg->images.requested_size +=
2321 (image_size * eina_list_count(ASENTRY(ientry)->references));
2322 }
1761 2323
1762#ifdef DEBUG_LOAD_TIME 2324#ifdef DEBUG_LOAD_TIME
1763 // accounting image entries load time 2325 // accounting image entries load time
1764 msg->images.images_load_time += id->base.load_time; 2326 msg->images.images_load_time += ASENTRY(ientry)->load_time;
1765 msg->images.images_saved_time += id->base.saved_time; 2327 msg->images.images_saved_time += ASENTRY(ientry)->saved_time;
1766#endif 2328#endif
1767 2329
1768 return EINA_TRUE; 2330 return EINA_TRUE;
@@ -1788,167 +2350,141 @@ struct _debug_info
1788}; 2350};
1789 2351
1790static Eina_Bool 2352static Eina_Bool
1791_font_entry_debug_size_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) 2353_font_entry_debug_size_cb(const Eina_Hash *hash EINA_UNUSED,
2354 const void *key EINA_UNUSED, void *data, void *fdata)
1792{ 2355{
1793 struct _debug_info *di = fdata; 2356 struct _debug_info *di = fdata;
1794 unsigned int size = di->size;
1795 Font_Entry *fe = data; 2357 Font_Entry *fe = data;
1796 Font_Cache *fc; 2358 const char *str;
1797 unsigned int intsize = sizeof(unsigned int);
1798 2359
1799 // filelen 2360 // filelen
1800 size += intsize; 2361 di->size+= sizeof(int);
1801 2362
1802 // file 2363 // file
1803 if (fe->src->file) 2364 if (fe->src->file)
1804 size += strlen(fe->src->file) + 1; 2365 {
2366 str = cserve2_shared_string_get(fe->src->file);
2367 di->size+= strlen(str) + 1;
2368 }
1805 2369
1806 // namelen 2370 // namelen
1807 size += intsize; 2371 di->size+= sizeof(int);
1808 2372
1809 // name 2373 // name
1810 if (fe->src->name) 2374 if (fe->src->name)
1811 size += strlen(fe->src->name) + 1;
1812
1813 // rend_flags, size, dpi
1814 size += 3 * intsize;
1815
1816 // unused
1817 size += intsize;
1818
1819 // ncaches
1820 size += intsize;
1821
1822 EINA_INLIST_FOREACH(fe->caches, fc)
1823 { 2375 {
1824 Glyph_Entry *gl; 2376 str = cserve2_shared_string_get(fe->src->file);
1825 2377 di->size+= strlen(str) + 1;
1826 // shmnamelen + shmname 2378 }
1827 size += intsize;
1828 size += strlen(cserve2_shm_name_get(fc->shm)) + 1;
1829
1830 // size + usage
1831 size += 2 * intsize;
1832 2379
1833 // nglyphs 2380 // rend_flags, size, dpi, unused
1834 size += intsize; 2381 di->size+= 4 * sizeof(int);
1835 2382
1836 EINA_INLIST_FOREACH(fc->glyphs, gl) 2383 // glyph_data_shm and glyph_mempool_shm (short strings)
1837 { 2384 di->size+= 2 * 64;
1838 // index, offset, size
1839 size += 3 * intsize;
1840 2385
1841 // rows, width, pitch 2386 // nglyphs
1842 size += 3 * intsize; 2387 di->size+= sizeof(int);
1843 2388
1844 // num_grays, pixel_mode 2389 // glyphs
1845 size += 2 * intsize; 2390 di->size+= fe->nglyphs * sizeof(Glyph_Data);
1846 }
1847 }
1848 2391
1849 di->size = size;
1850 di->nfonts++; 2392 di->nfonts++;
1851 2393
1852 return EINA_TRUE; 2394 return EINA_TRUE;
1853} 2395}
1854 2396
1855static Eina_Bool 2397static Eina_Bool
1856_font_entry_debug_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata) 2398_font_entry_debug_cb(const Eina_Hash *hash EINA_UNUSED,
2399 const void *key EINA_UNUSED, void *data, void *fdata)
1857{ 2400{
1858 char **pos = fdata; 2401 char **pos = fdata;
1859 char *buf = *pos; 2402 char *buf = *pos;
1860 Font_Entry *fe = data; 2403 Font_Entry *fe = data;
1861 Font_Cache *fc; 2404 unsigned int len, k, nglyphs;
1862 unsigned int len; 2405 const char *str;
1863 unsigned int unused; 2406 char *nglyphs_pos;
1864 unsigned int ncaches; 2407 Shared_Array *index = NULL;
1865 unsigned int intsize = sizeof(unsigned int); 2408
1866 2409 // file
1867 // filelen + file 2410 str = cserve2_shared_string_get(fe->src->file);
1868 len = 0; 2411 len = str ? (strlen(str) + 1) : 0;
1869 if (fe->src->file) 2412
1870 len = strlen(fe->src->file) + 1; 2413 memcpy(buf, &len, sizeof(int));
1871 memcpy(buf, &len, intsize); 2414 buf += sizeof(int);
1872 buf += intsize; 2415
1873 if (len) memcpy(buf, fe->src->file, len); 2416 if (len)
1874 buf += len;
1875
1876 // namelen + name
1877 len = 0;
1878 if (fe->src->name)
1879 len = strlen(fe->src->name) + 1;
1880 memcpy(buf, &len, intsize);
1881 buf += intsize;
1882 if (len) memcpy(buf, fe->src->name, len);
1883 buf += len;
1884
1885 // rend_flags, size, dpi
1886 memcpy(buf, &fe->rend_flags, intsize);
1887 buf += intsize;
1888 memcpy(buf, &fe->size, intsize);
1889 buf += intsize;
1890 memcpy(buf, &fe->dpi, intsize);
1891 buf += intsize;
1892
1893 // unused
1894 unused = fe->unused;
1895 memcpy(buf, &unused, intsize);
1896 buf += intsize;
1897
1898 // ncaches
1899 ncaches = eina_inlist_count(fe->caches);
1900 memcpy(buf, &ncaches, intsize);
1901 buf += intsize;
1902
1903 EINA_INLIST_FOREACH(fe->caches, fc)
1904 { 2417 {
1905 Glyph_Entry *gl; 2418 memcpy(buf, str, len);
1906 const char *shmname; 2419 buf += len;
1907 unsigned int shmsize; 2420 }
1908 2421
1909 // shmnamelen + shmname 2422 // name
1910 shmname = cserve2_shm_name_get(fc->shm); 2423 str = cserve2_shared_string_get(fe->src->name);
1911 len = strlen(shmname) + 1; 2424 len = str ? (strlen(str) + 1) : 0;
1912 memcpy(buf, &len, intsize); 2425
1913 buf += intsize; 2426 memcpy(buf, &len, sizeof(int));
1914 memcpy(buf, shmname, len); 2427 buf += sizeof(int);
2428
2429 if (len)
2430 {
2431 memcpy(buf, str, len);
1915 buf += len; 2432 buf += len;
2433 }
2434
2435 // rend_flags, size, dpi, unused
2436 memcpy(buf, &fe->rend_flags, sizeof(int));
2437 buf += sizeof(int);
2438 memcpy(buf, &fe->size, sizeof(int));
2439 buf += sizeof(int);
2440 memcpy(buf, &fe->dpi, sizeof(int));
2441 buf += sizeof(int);
1916 2442
1917 // size, usage, nglyphs 2443 len = fe->unused;
1918 shmsize = cserve2_shm_size_get(fc->shm); 2444 memcpy(buf, &len, sizeof(int));
1919 memcpy(buf, &shmsize, intsize); 2445 buf += sizeof(int);
1920 buf += intsize; 2446
1921 memcpy(buf, &fc->usage, intsize); 2447 // glyph shared index and mempool
1922 buf += intsize; 2448 if (fe->mempool)
1923 memcpy(buf, &fc->nglyphs, intsize); 2449 {
1924 buf += intsize; 2450 index = cserve2_shared_mempool_index_get(fe->mempool);
2451 eina_strlcpy(buf, cserve2_shared_mempool_name_get(fe->mempool), 64);
2452 buf += 64;
2453 eina_strlcpy(buf, cserve2_shared_array_name_get(index), 64);
2454 buf += 64;
2455 }
2456 else
2457 {
2458 memset(buf, 0, 128);
2459 buf += 128;
2460 }
1925 2461
1926 EINA_INLIST_FOREACH(fc->glyphs, gl) 2462 // skip nglyphs for now...
2463 nglyphs_pos = buf;
2464 buf += sizeof(int);
2465
2466 nglyphs = 0;
2467 if (index)
2468 {
2469 for (k = 0; k < fe->nglyphs; k++)
1927 { 2470 {
1928 // index, offset, size 2471 Glyph_Data *gd = cserve2_shared_array_item_data_get(index, k);
1929 memcpy(buf, &gl->index, intsize); 2472 if (!gd || !gd->id) break;
1930 buf += intsize; 2473
1931 memcpy(buf, &gl->offset, intsize); 2474 nglyphs++;
1932 buf += intsize; 2475 memcpy(buf, gd, sizeof(*gd));
1933 memcpy(buf, &gl->size, intsize); 2476 buf += sizeof(*gd);
1934 buf += intsize;
1935
1936 // rows, width, pitch
1937 memcpy(buf, &gl->rows, intsize);
1938 buf += intsize;
1939 memcpy(buf, &gl->width, intsize);
1940 buf += intsize;
1941 memcpy(buf, &gl->pitch, intsize);
1942 buf += intsize;
1943
1944 // num_grays, pixel_mode
1945 memcpy(buf, &gl->num_grays, intsize);
1946 buf += intsize;
1947 memcpy(buf, &gl->pixel_mode, intsize);
1948 buf += intsize;
1949 } 2477 }
1950 } 2478 }
1951 2479
2480 // write real value of nglyphs
2481 memcpy(nglyphs_pos, &nglyphs, sizeof(int));
2482 if (nglyphs != fe->nglyphs)
2483 {
2484 WRN("Found %u valid glyphs when the font advertised %u entries",
2485 nglyphs, fe->nglyphs);
2486 }
2487
1952 *pos = buf; 2488 *pos = buf;
1953 return EINA_TRUE; 2489 return EINA_TRUE;
1954} 2490}
@@ -1966,27 +2502,24 @@ _cserve2_cache_font_debug(unsigned int rid, unsigned int *size)
1966 2502
1967 msg.base.type = CSERVE2_FONT_DEBUG; 2503 msg.base.type = CSERVE2_FONT_DEBUG;
1968 msg.base.rid = rid; 2504 msg.base.rid = rid;
2505 eina_strlcpy(msg.fonts_index_path,
2506 cserve2_shared_array_name_get(_font_data_array),
2507 sizeof(msg.fonts_index_path));
1969 2508
1970 // First calculate how much size is needed for this message: 2509 // First calculate how much size is needed for this message
1971
1972 // nfonts
1973 di.size += sizeof(unsigned int);
1974
1975 // size needed for each font entry
1976 eina_hash_foreach(font_entries, _font_entry_debug_size_cb, &di); 2510 eina_hash_foreach(font_entries, _font_entry_debug_size_cb, &di);
1977 2511
1978 // Now really create the message 2512 // Now really create the message
1979 buf = malloc(di.size); 2513 buf = malloc(di.size);
1980 pos = buf; 2514 pos = buf;
1981 2515
2516 // nfonts
2517 msg.nfonts = di.nfonts;
2518
1982 // msg base 2519 // msg base
1983 memcpy(buf, &msg, sizeof(msg)); 2520 memcpy(buf, &msg, sizeof(msg));
1984 pos += sizeof(msg); 2521 pos += sizeof(msg);
1985 2522
1986 // nfonts
1987 memcpy(pos, &di.nfonts, sizeof(unsigned int));
1988 pos += sizeof(unsigned int);
1989
1990 eina_hash_foreach(font_entries, _font_entry_debug_cb, &pos); 2523 eina_hash_foreach(font_entries, _font_entry_debug_cb, &pos);
1991 2524
1992 *size = di.size; 2525 *size = di.size;
@@ -1994,22 +2527,27 @@ _cserve2_cache_font_debug(unsigned int rid, unsigned int *size)
1994} 2527}
1995 2528
1996int 2529int
1997cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char *path, const char *key, unsigned int rid) 2530cserve2_cache_file_open(Client *client, unsigned int client_file_id,
2531 const char *path, const char *key, unsigned int rid,
2532 Evas_Image_Load_Opts *lo)
1998{ 2533{
1999 unsigned int file_id; 2534 unsigned int file_id;
2000 File_Data *entry; 2535 File_Data *fd;
2001 Reference *ref; 2536 Reference *ref;
2002 File_Watch *fw; 2537 File_Watch *fw;
2003 char buf[4906]; 2538 char buf[4906];
2539 File_Entry *fentry;
2540 int idx;
2004 2541
2542#if 0
2005 // look for this file on client references 2543 // look for this file on client references
2006 ref = eina_hash_find(client->files.referencing, &client_file_id); 2544 ref = eina_hash_find(client->files.referencing, &client_file_id);
2007 if (ref) 2545 if (ref)
2008 { 2546 {
2009 entry = (File_Data *)ref->entry;
2010 _entry_load_reused(ref->entry); 2547 _entry_load_reused(ref->entry);
2011 2548
2012 if (entry->invalid) 2549 fd = _file_data_find(ref->entry->id);
2550 if (!fd || fd->invalid)
2013 { 2551 {
2014 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED); 2552 cserve2_client_error_send(client, rid, CSERVE2_FILE_CHANGED);
2015 return -1; 2553 return -1;
@@ -2019,22 +2557,23 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char
2019 ref->count++; 2557 ref->count++;
2020 2558
2021 // File already being loaded, just add the request to be replied 2559 // File already being loaded, just add the request to be replied
2022 if (entry->base.request) 2560 if (ref->entry->request)
2023 cserve2_request_waiter_add(entry->base.request, rid, client); 2561 cserve2_request_waiter_add(ref->entry->request, rid, client);
2024 else 2562 else
2025 _image_opened_send(client, entry, rid); 2563 _image_opened_send(client, fd, rid);
2026 return 0; 2564 return 0;
2027 } 2565 }
2566#endif
2028 2567
2029 // search whether the file is already opened by another client 2568 // search whether the file is already opened by another client
2030 snprintf(buf, sizeof(buf), "%s:%s", path, key); 2569 _file_hkey_get(buf, sizeof(buf), path, key, lo);
2031 file_id = (unsigned int)(uintptr_t)eina_hash_find(file_ids, buf); 2570 file_id = (unsigned int)(uintptr_t)eina_hash_find(file_ids, buf);
2032 if (file_id) 2571 if (file_id)
2033 { 2572 {
2034 DBG("found file_id %u for client file id %d", 2573 DBG("found file_id %u for client file id %d",
2035 file_id, client_file_id); 2574 file_id, client_file_id);
2036 entry = eina_hash_find(file_entries, &file_id); 2575 fentry = _file_entry_find(file_id);
2037 if (!entry) 2576 if (!fentry)
2038 { 2577 {
2039 ERR("file \"%s\" is in file_ids hash but not in entries hash.", 2578 ERR("file \"%s\" is in file_ids hash but not in entries hash.",
2040 buf); 2579 buf);
@@ -2042,48 +2581,70 @@ cserve2_cache_file_open(Client *client, unsigned int client_file_id, const char
2042 // FIXME: Maybe we should remove the entry from file_ids then? 2581 // FIXME: Maybe we should remove the entry from file_ids then?
2043 return -1; 2582 return -1;
2044 } 2583 }
2045 ref = _entry_reference_add((Entry *)entry, client, client_file_id); 2584 ref = _entry_reference_add(ASENTRY(fentry), client, client_file_id);
2046 _entry_load_reused(ref->entry); 2585 _entry_load_reused(ref->entry);
2047 eina_hash_add(client->files.referencing, &client_file_id, ref); 2586 eina_hash_add(client->files.referencing, &client_file_id, ref);
2048 if (entry->base.request) 2587 if (ref->entry->request)
2049 cserve2_request_waiter_add(entry->base.request, rid, client); 2588 cserve2_request_waiter_add(ref->entry->request, rid, client);
2050 else // File already loaded, otherwise there would be a request 2589 else // File already loaded, otherwise there would be a request
2051 _image_opened_send(client, entry, rid); 2590 {
2591 fd = _file_data_find(file_id);
2592 _image_opened_send(client, fd, rid);
2593 }
2052 return 0; 2594 return 0;
2053 } 2595 }
2054 2596
2055 file_id = _file_id++; 2597 file_id = ++_entry_id;
2056 while ((file_id == 0) || (eina_hash_find(file_entries, &file_id))) 2598 while (eina_hash_find(file_entries, &file_id))
2057 file_id = _file_id++; 2599 file_id = ++_entry_id;
2058 2600
2059 DBG("Creating new entry with file_id: %u for file \"%s:%s\"", 2601 idx = cserve2_shared_array_item_new(_file_data_array);
2060 file_id, path, key); 2602 fd = cserve2_shared_array_item_data_get(_file_data_array, idx);
2061 entry = calloc(1, sizeof(*entry)); 2603 DBG("Creating new entry with file_id: %u for file \"%s:%s\". Index %d at %p",
2062 entry->base.type = CSERVE2_IMAGE_FILE; 2604 file_id, path, key, idx, fd);
2063 entry->path = strdup(path); 2605 if (!fd)
2064 entry->key = strdup(key); 2606 {
2065 entry->base.id = file_id; 2607 ERR("Could not create new file entry!");
2066 eina_hash_add(file_entries, &file_id, entry); 2608 return -1;
2609 }
2610 fd->valid = EINA_FALSE;
2611 fd->path = cserve2_shared_string_add(path);
2612 fd->key = cserve2_shared_string_add(key);
2613 if (!lo) lo = (Evas_Image_Load_Opts *) &empty_lo;
2614 fd->lo.region.x = lo->region.x;
2615 fd->lo.region.y = lo->region.y;
2616 fd->lo.region.w = lo->region.w;
2617 fd->lo.region.h = lo->region.h;
2618 fd->lo.dpi = lo->dpi;
2619 fd->lo.w = lo->w;
2620 fd->lo.h = lo->h;
2621 fd->lo.scale_down_by = lo->scale_down_by;
2622 fd->lo.orientation = lo->orientation;
2623 fd->refcount = 1;
2624 fd->id = file_id;
2625
2626 fentry = calloc(1, sizeof(File_Entry));
2627 ASENTRY(fentry)->type = CSERVE2_IMAGE_FILE;
2628 ASENTRY(fentry)->id = file_id;
2629 eina_hash_add(file_entries, &file_id, fentry);
2067 eina_hash_add(file_ids, buf, (void*)(intptr_t)file_id); 2630 eina_hash_add(file_ids, buf, (void*)(intptr_t)file_id);
2068 ref = _entry_reference_add((Entry *)entry, client, client_file_id); 2631 ref = _entry_reference_add(ASENTRY(fentry), client, client_file_id);
2069 eina_hash_add(client->files.referencing, &client_file_id, ref); 2632 eina_hash_add(client->files.referencing, &client_file_id, ref);
2070 2633
2071 fw = eina_hash_find(file_watch, entry->path); 2634 fw = eina_hash_find(file_watch, cserve2_shared_string_get(fd->path));
2072 if (!fw) 2635 if (!fw)
2073 { 2636 {
2074 fw = calloc(1, sizeof(File_Watch)); 2637 fw = calloc(1, sizeof(File_Watch));
2075 fw->path = eina_stringshare_add(entry->path); 2638 fw->path = eina_stringshare_add(cserve2_shared_string_get(fd->path));
2076 cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw); 2639 cserve2_file_change_watch_add(fw->path, _file_changed_cb, fw);
2077 eina_hash_direct_add(file_watch, fw->path, fw); 2640 eina_hash_direct_add(file_watch, fw->path, fw);
2078 } 2641 }
2079 fw->entries = eina_list_append(fw->entries, entry); 2642 fw->entries = eina_list_append(fw->entries, fentry);
2080 entry->watcher = fw; 2643 fentry->watcher = fw;
2081 2644
2082 entry->base.request = cserve2_request_add(CSERVE2_REQ_IMAGE_OPEN, 2645 ASENTRY(fentry)->request = cserve2_request_add(CSERVE2_REQ_IMAGE_OPEN,
2083 rid, client, NULL, &_open_funcs, 2646 rid, client, NULL,
2084 entry); 2647 &_open_funcs, fentry);
2085
2086 // _open_image_default_set(entry);
2087 2648
2088 return 0; 2649 return 0;
2089} 2650}
@@ -2106,245 +2667,268 @@ cserve2_cache_file_close(Client *client, unsigned int client_file_id)
2106} 2667}
2107 2668
2108static int 2669static int
2109_cserve2_cache_fast_scaling_check(Client *client, Image_Data *entry) 2670_cserve2_cache_fast_scaling_check(Client *client, Image_Entry *ientry,
2671 int client_file_id)
2110{ 2672{
2111 Eina_Iterator *iter; 2673 Eina_Iterator *iter;
2112 Image_Data *i; 2674 Image_Entry *i;
2113 Image_Data *original = NULL; 2675 Image_Entry *orig_entry = NULL;
2676 Image_Data *orig_data = NULL;
2114 Evas_Image_Load_Opts unscaled; 2677 Evas_Image_Load_Opts unscaled;
2115 char buf[4096]; 2678 char buf[4096];
2116 unsigned int image_id; 2679 unsigned int image_id;
2117 int scaled_count = 0; 2680 int scaled_count = 0;
2118 int dst_w, dst_h; 2681 int dst_w, dst_h;
2119 Eina_Bool first_attempt = EINA_TRUE; 2682 Eina_Bool first_attempt = EINA_TRUE;
2683 File_Entry *fentry;
2684 Image_Data *idata;
2120 2685
2121 if (!entry) return -1; 2686 if (!ientry) return -1;
2122 if (!entry->file) return -1; 2687 idata = _image_data_find(ENTRYID(ientry));
2688 if (!idata) return -1;
2123 2689
2124 dst_w = entry->opts.scale_load.dst_w; 2690 dst_w = idata->opts.scale_load.dst_w;
2125 dst_h = entry->opts.scale_load.dst_h; 2691 dst_h = idata->opts.scale_load.dst_h;
2126 2692
2127 // Copy opts w/o scaling 2693 // Copy opts w/o scaling
2128 memset(&unscaled, 0, sizeof(unscaled)); 2694 memset(&unscaled, 0, sizeof(unscaled));
2129 unscaled.dpi = entry->opts.dpi; 2695 unscaled.dpi = idata->opts.dpi;
2130 //unscaled.w = entry->opts.w; 2696 unscaled.w = idata->opts.w;
2131 //unscaled.h = entry->opts.h; 2697 unscaled.h = idata->opts.h;
2132 //unscaled.scale_down_by = entry->opts.scale_down_by; 2698 unscaled.scale_down_by = idata->opts.scale_down_by;
2133 //unscaled.region.x = entry->opts.region.x; 2699 unscaled.region.x = idata->opts.region.x;
2134 //unscaled.region.y = entry->opts.region.y; 2700 unscaled.region.y = idata->opts.region.y;
2135 //unscaled.region.w = entry->opts.region.w; 2701 unscaled.region.w = idata->opts.region.w;
2136 //unscaled.region.h = entry->opts.region.h; 2702 unscaled.region.h = idata->opts.region.h;
2137 unscaled.scale_load.scale_hint = 0; 2703 unscaled.scale_load.scale_hint = 0;
2138 unscaled.degree = entry->opts.degree; 2704 unscaled.degree = idata->opts.degree;
2139 unscaled.orientation = entry->opts.orientation; 2705 unscaled.orientation = idata->opts.orientation;
2140 unscaled.scale_load.smooth = entry->opts.scale_load.smooth; 2706 unscaled.scale_load.smooth = idata->opts.scale_load.smooth;
2141 2707
2142try_again: 2708try_again:
2143 image_id = _img_opts_id_get(entry->file_id, &unscaled, buf, sizeof(buf)); 2709 image_id = _image_opts_id_get(idata->file_id, &unscaled, buf, sizeof(buf));
2144 if (image_id) 2710 if (image_id)
2145 { 2711 {
2146 original = eina_hash_find(image_entries, &image_id); 2712 orig_data = _image_data_find(image_id);
2147 if (!original) return -1; // Should not happen 2713 orig_entry = _image_entry_find(image_id);
2714 if (!orig_data || !orig_entry) return -1;
2715
2148 DBG("Found original image in hash: %d,%d:%dx%d -> %dx%d shm %p", 2716 DBG("Found original image in hash: %d,%d:%dx%d -> %dx%d shm %p",
2149 original->opts.scale_load.src_x, original->opts.scale_load.src_y, 2717 orig_data->opts.scale_load.src_x, orig_data->opts.scale_load.src_y,
2150 original->opts.scale_load.src_w, original->opts.scale_load.src_h, 2718 orig_data->opts.scale_load.src_w, orig_data->opts.scale_load.src_h,
2151 original->opts.scale_load.dst_w, original->opts.scale_load.dst_h, 2719 orig_data->opts.scale_load.dst_w, orig_data->opts.scale_load.dst_h,
2152 original->shm); 2720 orig_entry->shm);
2153 goto do_scaling; 2721 goto do_scaling;
2154 } 2722 }
2155 2723
2156 if (first_attempt) 2724 if (first_attempt && unscaled.scale_load.smooth)
2157 { 2725 {
2158 first_attempt = EINA_FALSE; 2726 first_attempt = EINA_FALSE;
2159 memset(&unscaled, 0, sizeof(unscaled)); 2727 unscaled.scale_load.smooth = 0;
2160 goto try_again; 2728 goto try_again;
2161 } 2729 }
2162 2730
2163 iter = eina_list_iterator_new(entry->file->images); 2731 fentry = _file_entry_find(idata->file_id);
2732 iter = eina_list_iterator_new(fentry->images);
2164 EINA_ITERATOR_FOREACH(iter, i) 2733 EINA_ITERATOR_FOREACH(iter, i)
2165 { 2734 {
2166 if (i == entry) continue; 2735 Image_Data *id;
2167 if (i->opts.w && i->opts.h && 2736
2168 (!i->opts.scale_load.dst_w && !i->opts.scale_load.dst_h)) 2737 if (i == ientry) continue;
2738 id = _image_data_find(ENTRYID(i));
2739 if (!id) continue;
2740
2741 if (id->opts.w && id->opts.h &&
2742 (!id->opts.scale_load.dst_w &&
2743 !id->opts.scale_load.dst_h))
2169 { 2744 {
2170 DBG("Found image in list: %d,%d:%dx%d -> %dx%d shm %p", 2745 DBG("Found image in list: %d,%d:%dx%d -> %dx%d shm %p",
2171 i->opts.scale_load.src_x, i->opts.scale_load.src_y, 2746 id->opts.scale_load.src_x, id->opts.scale_load.src_y,
2172 i->opts.scale_load.src_w, i->opts.scale_load.src_h, 2747 id->opts.scale_load.src_w, id->opts.scale_load.src_h,
2173 i->opts.scale_load.dst_w, i->opts.scale_load.dst_h, 2748 id->opts.scale_load.dst_w, id->opts.scale_load.dst_h,
2174 i->shm); 2749 i->shm);
2175 if (i->base.request || !i->shm) continue; // Not loaded yet 2750 if (i->base.request || !i->shm) continue; // Not loaded yet
2176 original = i; 2751 orig_entry = i;
2177 break; 2752 break;
2178 } 2753 }
2179 scaled_count++; 2754 scaled_count++;
2180 } 2755 }
2181 eina_iterator_free(iter); 2756 eina_iterator_free(iter);
2182 2757
2183 if (!original) 2758 if (!orig_entry)
2184 { 2759 {
2185 DBG("Found %d scaled images for %s:%s but none matches", 2760 DBG("Found %d scaled images for image %u but none matches",
2186 scaled_count, entry->file->path, entry->file->key); 2761 scaled_count, ENTRYID(ientry));
2187 2762
2188 if (scaled_count >= 4) 2763 // FIXME: The value 4 is completely arbitrary. No benchmarks done yet.
2764 if (scaled_count >= 4 && (unused_mem_usage < max_unused_mem_usage))
2189 { 2765 {
2190 DBG("Forcing load of original image now!"); 2766 DBG("Forcing load of original image now!");
2191 2767
2192 File_Data *fentry; 2768 orig_entry = _image_entry_new(client, 0, client_file_id,
2193 2769 0, &unscaled, buf, sizeof(buf));
2194 original = _image_entry_new(client, 0, entry->file_id, 2770 if (!orig_entry) return -1;
2195 0, &unscaled); 2771
2196 if (!original) return -1; 2772 image_id = orig_entry->base.id;
2197 2773 orig_data = _image_data_find(ENTRYID(orig_entry));
2198 image_id = _image_id++; 2774 orig_data->unused = EINA_TRUE;
2199 while ((image_id == 0) || (eina_hash_find(image_entries, &image_id))) 2775 fentry = _file_entry_find(orig_data->file_id);
2200 image_id = _image_id++; 2776 fentry->images = eina_list_append(fentry->images, orig_entry);
2201 DBG("Creating new image_id: %d", image_id); 2777 // TODO: Check validity of this call. Leak VS immediate delete?
2202 2778 //_entry_unused_push(orig_entry);
2203 original->base.id = image_id;
2204 eina_hash_add(image_entries, &image_id, original);
2205 eina_hash_add(image_ids, buf, (void *)(intptr_t)image_id);
2206 _entry_unused_push(original);
2207
2208 fentry = original->file;
2209 fentry->images = eina_list_append(fentry->images, original);
2210 } 2779 }
2211 else 2780 else
2212 return -1; 2781 return -1;
2213 } 2782 }
2214 2783
2215do_scaling: 2784do_scaling:
2216 if (!original) return -1; 2785 if (!orig_entry || !orig_data) return -1;
2217 if (!original->shm && !original->base.request) 2786 if (!orig_entry->shm && !orig_entry->base.request)
2218 { 2787 {
2219 if (original->base.id != image_id) abort(); 2788 if (orig_entry->base.id != image_id)
2220 original->base.request = cserve2_request_add( 2789 {
2790 CRIT("Entry IDs mismatch");
2791 return -1;
2792 }
2793 orig_entry->base.request = cserve2_request_add(
2221 CSERVE2_REQ_IMAGE_LOAD, 2794 CSERVE2_REQ_IMAGE_LOAD,
2222 0, NULL, 0, &_load_funcs, original); 2795 0, NULL, 0, &_load_funcs, orig_entry);
2223 } 2796 }
2224 if (original->base.request || !original->shm) 2797 if (orig_entry->base.request || !orig_entry->shm || !orig_data->valid)
2225 return -1; // Not loaded yet 2798 return -1; // Not loaded yet
2226 2799
2227 if (entry->shm) 2800 if (ientry->shm)
2228 cserve2_shm_unref(entry->shm); 2801 cserve2_shm_unref(ientry->shm);
2229 2802
2230 entry->shm = cserve2_shm_request("img", dst_w * dst_h * 4); 2803 ientry->shm = cserve2_shm_request("img", dst_w * dst_h * 4);
2231 if (!entry->shm) return -1; 2804 if (!ientry->shm) return -1;
2232 2805
2233 if (_scaling_do(entry->shm, entry, original) != 0) 2806 if (_scaling_do(ientry->shm, idata, orig_entry) != 0)
2234 { 2807 {
2235 cserve2_shm_unref(entry->shm); 2808 cserve2_shm_unref(ientry->shm);
2236 entry->shm = NULL; 2809 ientry->shm = NULL;
2237 return -1; 2810 return -1;
2238 } 2811 }
2239 2812
2240 if (original->unused) 2813 if (orig_data->unused)
2241 { 2814 {
2242 image_entries_lru = eina_list_remove(image_entries_lru, original); 2815 image_entries_lru = eina_list_remove(image_entries_lru, orig_entry);
2243 image_entries_lru = eina_list_prepend(image_entries_lru, original); 2816 image_entries_lru = eina_list_prepend(image_entries_lru, orig_entry);
2244 } 2817 }
2245 return 0; 2818 return 0;
2246} 2819}
2247 2820
2248int 2821int
2249cserve2_cache_image_entry_create(Client *client, int rid, 2822cserve2_cache_image_entry_create(Client *client, int rid,
2250 unsigned int file_id, 2823 unsigned int client_file_id,
2251 unsigned int client_image_id, 2824 unsigned int client_image_id,
2252 Evas_Image_Load_Opts *opts) 2825 const Evas_Image_Load_Opts *opts)
2253{ 2826{
2254 Image_Data *entry; 2827 Image_Data *idata;
2255 File_Data *fentry = NULL; 2828 Image_Entry *ientry;
2256 Reference *ref, *oldref; 2829 Reference *ref;
2257 unsigned int image_id; 2830 File_Entry *fentry;
2831 unsigned int image_id = 0;
2258 char buf[4096]; 2832 char buf[4096];
2259 2833
2260 oldref = eina_hash_find(client->images.referencing, &client_image_id); 2834 if (!opts)
2835 opts = &empty_lo;
2261 2836
2262 // search whether the image is already loaded by another client 2837 // search whether the image is already loaded by another client
2263 entry = _image_entry_new(client, rid, file_id, client_image_id, opts); 2838 ref = eina_hash_find(client->files.referencing, &client_file_id);
2264 if (!entry) 2839 if (ref)
2265 return -1; 2840 image_id = _image_opts_id_get(ref->entry->id, opts, buf, sizeof(buf));
2266 image_id = _image_data_opts_id_get(entry, buf, sizeof(buf)); 2841
2267 if (image_id) 2842 if (image_id)
2268 { // if so, just update the references 2843 {
2269 free(entry); 2844 // Just update the references
2845 Reference *oldref;
2846
2270 DBG("found image_id %d for client image id %d", 2847 DBG("found image_id %d for client image id %d",
2271 image_id, client_image_id); 2848 image_id, client_image_id);
2272 entry = eina_hash_find(image_entries, &image_id); 2849 ientry = _image_entry_find(image_id);
2273 if (!entry) 2850 idata = _image_data_find(image_id);
2851 if (!ientry || !idata)
2274 { 2852 {
2275 ERR("image id %d is in file_ids hash, but not in entries hash" 2853 ERR("image entry %d (client id: %d) corrupted: entry %p data %p",
2276 "with entry id %d.", client_image_id, image_id); 2854 image_id, client_image_id, ientry, idata);
2277 cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE); 2855 cserve2_client_error_send(client, rid, CSERVE2_INVALID_CACHE);
2278 return -1; 2856 return -1;
2279 } 2857 }
2280 2858
2281 if (entry->unused) 2859 // FIXME: This might be broken (wrt. refcounting)
2860 if (idata->unused)
2282 { 2861 {
2283 DBG("Re-using old image entry (id: %d) from the LRU list.", 2862 DBG("Re-using old image entry (id: %d) from the LRU list.",
2284 entry->base.id); 2863 ientry->base.id);
2285 entry->unused = EINA_FALSE; 2864 idata->unused = EINA_FALSE;
2286 image_entries_lru = eina_list_remove(image_entries_lru, entry); 2865 idata->refcount++;
2287 unused_mem_usage -= _image_entry_size_get(entry); 2866 image_entries_lru = eina_list_remove(image_entries_lru, ientry);
2867 unused_mem_usage -= _image_entry_size_get(ientry);
2288 } 2868 }
2289 _entry_load_reused(&entry->base); 2869 _entry_load_reused(&ientry->base);
2290 2870
2871 oldref = eina_hash_find(client->images.referencing, &client_image_id);
2291 if (oldref && (oldref->entry->id == image_id)) 2872 if (oldref && (oldref->entry->id == image_id))
2292 return 0; 2873 return 0;
2293 2874
2294 ref = _entry_reference_add((Entry *)entry, client, client_image_id); 2875 ref = _entry_reference_add(ASENTRY(ientry), client, client_image_id);
2295
2296 if (oldref) 2876 if (oldref)
2297 eina_hash_del_by_key(client->images.referencing, &client_image_id); 2877 eina_hash_del_by_key(client->images.referencing, &client_image_id);
2298
2299 eina_hash_add(client->images.referencing, &client_image_id, ref); 2878 eina_hash_add(client->images.referencing, &client_image_id, ref);
2879
2300 return 0; 2880 return 0;
2301 } 2881 }
2302 2882
2303 image_id = _image_id++; 2883 ientry = _image_entry_new(client, rid, client_file_id, client_image_id,
2304 while ((image_id == 0) || (eina_hash_find(image_entries, &image_id)))