1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #ifdef _WIN32
6 # include <windows.h>
7 #endif
8
9 #include <assert.h>
10
11 #include "evas_common_private.h"
12 #include "evas_private.h"
13 #include "evas_image_private.h"
14
15 #define SCALECACHE 1
16
17 #define MAX_SCALEITEMS 32
18 #define MIN_SCALE_USES 3
19 //#define MIN_SCALE_AGE_GAP 5000
20 #define MAX_SCALECACHE_DIM 3200
21 #define FLOP_ADD 4
22 #define MAX_FLOP_COUNT 16
23 #define FLOP_DEL 1
24 #define SCALE_CACHE_SIZE 4 * 1024 * 1024
25 //#define SCALE_CACHE_SIZE 0
26
27 typedef struct _ScaleitemKey ScaleitemKey;
28 typedef struct _Scaleitem Scaleitem;
29
30 struct _ScaleitemKey
31 {
32 int src_x, src_y;
33 unsigned int src_w, src_h;
34 unsigned int dst_w, dst_h;
35 Eina_Bool smooth : 1;
36 };
37
38 struct _Scaleitem
39 {
40 EINA_INLIST;
41 unsigned long long usage;
42 unsigned long long usage_count;
43 RGBA_Image *im, *parent_im;
44 Eina_List *item;
45 unsigned int flop;
46 unsigned int size_adjust;
47
48 ScaleitemKey key;
49
50 Eina_Bool forced_unload : 1;
51 Eina_Bool populate_me : 1;
52 };
53
54 #ifdef SCALECACHE
55 static unsigned long long use_counter = 0;
56
57 static SLK(cache_lock);
58 static Eina_Inlist *cache_list = NULL;
59 static unsigned int cache_size = 0;
60 static int init = 0;
61
62 static unsigned int max_cache_size = SCALE_CACHE_SIZE;
63 static unsigned int max_dimension = MAX_SCALECACHE_DIM;
64 static unsigned int max_flop_count = MAX_FLOP_COUNT;
65 static unsigned int max_scale_items = MAX_SCALEITEMS;
66 static unsigned int min_scale_uses = MIN_SCALE_USES;
67 #endif
68
69 static int
_evas_common_scalecache_key_hash(const void * key,int key_length EINA_UNUSED)70 _evas_common_scalecache_key_hash(const void *key, int key_length EINA_UNUSED)
71 {
72 const ScaleitemKey *skey;
73 unsigned int tohash;
74 int r;
75
76 skey = key;
77
78 tohash = (skey->src_x ^ skey->src_y) ^ ((skey->src_w ^ skey->src_h) ^ (skey->dst_w ^ skey->dst_h));
79 r = eina_hash_int32(&tohash, sizeof (int));
80
81 return r;
82 }
83
84 static unsigned int
_evas_common_scalecache_key_length(const void * key EINA_UNUSED)85 _evas_common_scalecache_key_length(const void *key EINA_UNUSED)
86 {
87 return sizeof (ScaleitemKey);
88 }
89
90 static int
_evas_common_scalecache_key_cmp(const void * key1,int key1_length EINA_UNUSED,const void * key2,int key2_length EINA_UNUSED)91 _evas_common_scalecache_key_cmp(const void *key1, int key1_length EINA_UNUSED,
92 const void *key2, int key2_length EINA_UNUSED)
93 {
94 const ScaleitemKey *sk1 = key1;
95 const ScaleitemKey *sk2 = key2;
96
97 #define CMP_SKEY(Sk1, Sk2, Name) \
98 if (Sk1->Name != Sk2->Name) \
99 return Sk1->Name - Sk2->Name;
100
101 CMP_SKEY(sk1, sk2, src_w);
102 CMP_SKEY(sk1, sk2, src_h);
103 CMP_SKEY(sk1, sk2, dst_w);
104 CMP_SKEY(sk1, sk2, dst_h);
105 CMP_SKEY(sk1, sk2, src_x);
106 CMP_SKEY(sk1, sk2, src_y);
107 CMP_SKEY(sk1, sk2, smooth);
108
109 return 0;
110 }
111
112 void
evas_common_scalecache_init(void)113 evas_common_scalecache_init(void)
114 {
115 #ifdef SCALECACHE
116 const char *s;
117
118 init++;
119 if (init > 1) return;
120 use_counter = 0;
121 SLKI(cache_lock);
122 s = getenv("EVAS_SCALECACHE_SIZE");
123 if (s) max_cache_size = atoi(s) * 1024;
124 s = getenv("EVAS_SCALECACHE_MAX_DIMENSION");
125 if (s) max_dimension = atoi(s);
126 s = getenv("EVAS_SCALECACHE_MAX_FLOP_COUNT");
127 if (s) max_flop_count = atoi(s);
128 s = getenv("EVAS_SCALECACHE_MAX_ITEMS");
129 if (s) max_scale_items = atoi(s);
130 s = getenv("EVAS_SCALECACHE_MIN_USES");
131 if (s) min_scale_uses = atoi(s);
132 #endif
133 }
134
135 void
evas_common_scalecache_shutdown(void)136 evas_common_scalecache_shutdown(void)
137 {
138 #ifdef SCALECACHE
139 init--;
140 if (init ==0)
141 SLKD(cache_lock);
142 #endif
143 }
144
145 void
evas_common_rgba_image_scalecache_init(Image_Entry * ie)146 evas_common_rgba_image_scalecache_init(Image_Entry *ie)
147 {
148 #ifdef SCALECACHE
149 RGBA_Image *im = (RGBA_Image *)ie;
150 // NOTE: this conflicts with evas image cache init and del of lock
151 SLKI(im->cache.lock);
152 #endif
153 }
154
155 void
evas_common_rgba_image_scalecache_shutdown(Image_Entry * ie)156 evas_common_rgba_image_scalecache_shutdown(Image_Entry *ie)
157 {
158 #ifdef SCALECACHE
159 RGBA_Image *im = (RGBA_Image *)ie;
160 evas_common_rgba_image_scalecache_dirty(ie);
161 // NOTE: this conflicts with evas image cache init and del of lock
162 SLKD(im->cache.lock);
163 #endif
164 }
165
166 void
evas_common_rgba_image_scalecache_dirty(Image_Entry * ie)167 evas_common_rgba_image_scalecache_dirty(Image_Entry *ie)
168 {
169 #ifdef SCALECACHE
170 RGBA_Image *im = (RGBA_Image *)ie;
171
172 SLKL(im->cache.lock);
173 while (im->cache.list)
174 {
175 Scaleitem *sci = im->cache.list->data;
176
177 im->cache.list = eina_list_remove_list(im->cache.list, im->cache.list);
178 if ((sci->im) && (sci->im->cache_entry.references == 0))
179 {
180 SLKL(cache_lock);
181
182 evas_common_rgba_image_free(&sci->im->cache_entry);
183 sci->im = NULL;
184
185 if (!sci->forced_unload)
186 cache_size -= sci->key.dst_w * sci->key.dst_h * 4;
187 else
188 cache_size -= sci->size_adjust;
189 cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
190
191 SLKU(cache_lock);
192 }
193
194 if (!sci->im)
195 {
196 Eina_Inlist *il = (Eina_Inlist *)sci;
197
198 if ((il->next) || (il->prev) || (il == cache_list))
199 {
200 SLKL(cache_lock);
201 cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
202 SLKU(cache_lock);
203 }
204 free(sci);
205 }
206 }
207 eina_hash_free(im->cache.hash);
208 im->cache.hash = NULL;
209 SLKU(im->cache.lock);
210 #endif
211 }
212
213 void
evas_common_rgba_image_scalecache_orig_use(Image_Entry * ie)214 evas_common_rgba_image_scalecache_orig_use(Image_Entry *ie)
215 {
216 #ifdef SCALECACHE
217 RGBA_Image *im = (RGBA_Image *)ie;
218 SLKL(im->cache.lock);
219 use_counter++;
220 // FIXME: if orig not loaded, reload
221 // FIXME: mark orig with current used counter
222 im->cache.orig_usage++;
223 im->cache.usage_count = use_counter;
224 SLKU(im->cache.lock);
225 #endif
226 }
227
228 int
evas_common_rgba_image_scalecache_usage_get(Image_Entry * ie)229 evas_common_rgba_image_scalecache_usage_get(Image_Entry *ie)
230 {
231 #ifdef SCALECACHE
232 RGBA_Image *im = (RGBA_Image *)ie;
233 int size = 0;
234 Eina_List *l;
235 Scaleitem *sci;
236 SLKL(im->cache.lock);
237 EINA_LIST_FOREACH(im->cache.list, l, sci)
238 {
239 if (sci->im) size += sci->key.dst_w * sci->key.dst_h * 4;
240 }
241 SLKU(im->cache.lock);
242 return size;
243 #else
244 return 0;
245 #endif
246 }
247
248 /* receives original Image_Entry */
249 void
evas_common_rgba_image_scalecache_items_ref(Image_Entry * ie,Eina_Array * ret)250 evas_common_rgba_image_scalecache_items_ref(Image_Entry *ie, Eina_Array *ret)
251 {
252 #ifdef SCALECACHE
253 RGBA_Image *im = (RGBA_Image *)ie;
254 Eina_List *l;
255 Scaleitem *sci;
256
257 SLKL(im->cache.lock);
258 EINA_LIST_FOREACH(im->cache.list, l, sci)
259 {
260 if (sci->im)
261 {
262 Image_Entry *scie = (Image_Entry *)sci->im;
263 assert(scie->references >= 0);
264 scie->references++;
265 eina_array_push(ret, scie);
266 }
267 }
268 SLKU(im->cache.lock);
269 #endif
270 }
271
272 /* receives scaled Image_Entry */
273 void
evas_common_rgba_image_scalecache_item_unref(Image_Entry * scie)274 evas_common_rgba_image_scalecache_item_unref(Image_Entry *scie)
275 {
276 #ifdef SCALECACHE
277 scie->references--;
278 assert(scie->references >= 0);
279 #endif
280 }
281
282 #ifdef SCALECACHE
283 static void
_sci_fix_newest(RGBA_Image * im)284 _sci_fix_newest(RGBA_Image *im)
285 {
286 Eina_List *l;
287 Scaleitem *sci;
288
289 im->cache.newest_usage = 0;
290 im->cache.newest_usage_count = 0;
291 EINA_LIST_FOREACH(im->cache.list, l, sci)
292 {
293 if (sci->usage > im->cache.newest_usage)
294 im->cache.newest_usage = sci->usage;
295 if (sci->usage_count > im->cache.newest_usage_count)
296 im->cache.newest_usage_count = sci->usage_count;
297 }
298 // INF("_sci_fix_newest! -> %i", im->cache.newest_usage);
299 }
300
301 static Scaleitem *
_sci_find(RGBA_Image * im,RGBA_Draw_Context * dc EINA_UNUSED,int smooth,int src_x,int src_y,unsigned int src_w,unsigned int src_h,unsigned int dst_w,unsigned int dst_h)302 _sci_find(RGBA_Image *im,
303 RGBA_Draw_Context *dc EINA_UNUSED, int smooth,
304 int src_x, int src_y,
305 unsigned int src_w, unsigned int src_h,
306 unsigned int dst_w, unsigned int dst_h)
307 {
308 Eina_List *l;
309 Scaleitem *sci;
310 ScaleitemKey key;
311
312 #define SET_SKEY(S, Name) \
313 S.Name = Name
314
315 if (im->cache.hash)
316 {
317 SET_SKEY(key, src_w);
318 SET_SKEY(key, src_h);
319 SET_SKEY(key, dst_w);
320 SET_SKEY(key, dst_h);
321 SET_SKEY(key, src_x);
322 SET_SKEY(key, src_y);
323 SET_SKEY(key, smooth);
324
325 sci = eina_hash_find(im->cache.hash, &key);
326 if (sci)
327 {
328 im->cache.list = eina_list_promote_list(im->cache.list, sci->item);
329 return sci;
330 }
331 }
332
333 if (eina_list_count(im->cache.list) > max_scale_items)
334 {
335 l = eina_list_last(im->cache.list);
336 sci = eina_list_data_get(l);
337
338 eina_hash_del(im->cache.hash, &sci->key, sci);
339 im->cache.list = eina_list_remove_list(im->cache.list, l);
340 if ((sci->usage == im->cache.newest_usage) ||
341 (sci->usage_count == im->cache.newest_usage_count))
342 _sci_fix_newest(im);
343
344 if (sci->im)
345 {
346 if (sci->im->cache_entry.references > 0) goto try_alloc;
347
348 evas_common_rgba_image_free(&sci->im->cache_entry);
349 sci->im = NULL;
350 if (!sci->forced_unload)
351 cache_size -= sci->key.dst_w * sci->key.dst_h * 4;
352 else
353 cache_size -= sci->size_adjust;
354 // INF(" 1- %i", sci->dst_w * sci->dst_h * 4);
355 cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
356 if (max_scale_items < 1)
357 {
358 free(sci);
359 sci = NULL;
360 }
361 }
362 if (max_scale_items < 1) return NULL;
363 }
364 else
365 {
366 try_alloc:
367 if (max_scale_items < 1) return NULL;
368 if (eina_list_count(im->cache.list) > (max_scale_items - 1))
369 return NULL;
370
371 sci = calloc(1, sizeof(Scaleitem));
372 sci->parent_im = im;
373 }
374 sci->usage = 0;
375 sci->usage_count = 0;
376 sci->populate_me = 0;
377 sci->key.smooth = smooth;
378 sci->forced_unload = 0;
379 sci->flop = 0;
380 sci->im = NULL;
381 sci->key.src_x = src_x;
382 sci->key.src_y = src_y;
383 sci->key.src_w = src_w;
384 sci->key.src_h = src_h;
385 sci->key.dst_w = dst_w;
386 sci->key.dst_h = dst_h;
387 if (!im->cache.hash)
388 im->cache.hash = eina_hash_new(_evas_common_scalecache_key_length,
389 _evas_common_scalecache_key_cmp,
390 _evas_common_scalecache_key_hash,
391 NULL,
392 3);
393 eina_hash_direct_add(im->cache.hash, &sci->key, sci);
394 im->cache.list = eina_list_prepend(im->cache.list, sci);
395 sci->item = im->cache.list;
396 return sci;
397 }
398
399 static void
_cache_prune(Scaleitem * notsci,Eina_Bool copies_only)400 _cache_prune(Scaleitem *notsci, Eina_Bool copies_only)
401 {
402 Eina_Inlist *next;
403
404 if (!cache_list) return;
405
406 next = cache_list;
407 while ((next) && (cache_size > max_cache_size))
408 {
409 Scaleitem *sci;
410 Image_Entry *scie;
411
412 sci = EINA_INLIST_CONTAINER_GET(next, Scaleitem);
413
414 if (copies_only)
415 {
416 while (!sci->parent_im->image.data)
417 {
418 next = EINA_INLIST_GET(sci)->next;
419 if (!next) return;
420 sci = EINA_INLIST_CONTAINER_GET(next, Scaleitem);
421 }
422 }
423
424 scie = (Image_Entry *)sci->im;
425 next = EINA_INLIST_GET(sci)->next;
426
427 if (sci == notsci) continue;
428 if ((!scie) || (scie->references > 0)) continue;
429
430 evas_common_rgba_image_free(scie);
431 sci->im = NULL;
432 sci->usage = 0;
433 sci->usage_count = 0;
434 sci->flop += FLOP_ADD;
435
436 if (!sci->forced_unload)
437 cache_size -= sci->key.dst_w * sci->key.dst_h * 4;
438 else
439 cache_size -= sci->size_adjust;
440
441 cache_list = eina_inlist_remove(cache_list, EINA_INLIST_GET(sci));
442 memset(sci, 0, sizeof(Eina_Inlist));
443 }
444 }
445 #endif
446
447 EAPI void
evas_common_rgba_image_scalecache_size_set(unsigned int size)448 evas_common_rgba_image_scalecache_size_set(unsigned int size)
449 {
450 #ifdef SCALECACHE
451 SLKL(cache_lock);
452 if (size != max_cache_size)
453 {
454 max_cache_size = size;
455 _cache_prune(NULL, 1);
456 }
457 SLKU(cache_lock);
458 #endif
459 }
460
461 EAPI unsigned int
evas_common_rgba_image_scalecache_size_get(void)462 evas_common_rgba_image_scalecache_size_get(void)
463 {
464 #ifdef SCALECACHE
465 int t;
466 SLKL(cache_lock);
467 t = max_cache_size;
468 SLKU(cache_lock);
469 return t;
470 #else
471 return 0;
472 #endif
473 }
474
475 EAPI void
evas_common_rgba_image_scalecache_prune(void)476 evas_common_rgba_image_scalecache_prune(void)
477 {
478 #ifdef SCALECACHE
479 SLKL(cache_lock);
480 _cache_prune(NULL, 0);
481 SLKU(cache_lock);
482 #endif
483 }
484
485 EAPI void
evas_common_rgba_image_scalecache_dump(void)486 evas_common_rgba_image_scalecache_dump(void)
487 {
488 #ifdef SCALECACHE
489 int t;
490 SLKL(cache_lock);
491 t = max_cache_size;
492 max_cache_size = 0;
493 _cache_prune(NULL, 0);
494 max_cache_size = t;
495 SLKU(cache_lock);
496 #endif
497 }
498
499 EAPI void
evas_common_rgba_image_scalecache_flush(void)500 evas_common_rgba_image_scalecache_flush(void)
501 {
502 #ifdef SCALECACHE
503 int t;
504 SLKL(cache_lock);
505 t = max_cache_size;
506 max_cache_size = 0;
507 _cache_prune(NULL, 1);
508 max_cache_size = t;
509 SLKU(cache_lock);
510 #endif
511 }
512
513 EAPI Eina_Bool
evas_common_rgba_image_scalecache_prepare(Image_Entry * ie,RGBA_Image * dst EINA_UNUSED,RGBA_Draw_Context * dc,int smooth,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x EINA_UNUSED,int dst_region_y EINA_UNUSED,int dst_region_w,int dst_region_h)514 evas_common_rgba_image_scalecache_prepare(Image_Entry *ie, RGBA_Image *dst EINA_UNUSED,
515 RGBA_Draw_Context *dc, int smooth,
516 int src_region_x, int src_region_y,
517 int src_region_w, int src_region_h,
518 int dst_region_x EINA_UNUSED, int dst_region_y EINA_UNUSED,
519 int dst_region_w, int dst_region_h)
520 {
521 #ifdef SCALECACHE
522 int locked = 0;
523 Eina_Lock_Result ret;
524 RGBA_Image *im = (RGBA_Image *)ie;
525 Scaleitem *sci;
526
527 if ((dst_region_w == 0) || (dst_region_h == 0) ||
528 (src_region_w == 0) || (src_region_h == 0)) return EINA_TRUE;
529 // was having major lock issues here - SLKL was deadlocking. what was
530 // going on? it may have been an eina treads badness but this will stay here
531 // for now for debug
532 #if 1
533 ret = SLKT(im->cache.lock);
534 if (ret == EINA_FALSE) /* can't get image lock */
535 {
536 useconds_t slp = 1, slpt = 0;
537
538 while (slpt < 500000)
539 {
540 #ifdef _WIN32
541 Sleep(slp / 1000);
542 #else
543 usleep(slp);
544 #endif
545 slpt += slp;
546 slp++;
547 ret = SLKT(im->cache.lock);
548 if (ret == EINA_LOCK_DEADLOCK)
549 {
550 printf("WARNING: DEADLOCK on image %p (%s)\n", im, ie->file);
551 }
552 else
553 {
554 locked = 1;
555 break;
556 }
557 }
558 if (ret == EINA_FALSE)
559 {
560 printf("WARNING: lock still there after %i usec\n", slpt);
561 printf("WARNING: stucklock on image %p (%s)\n", im, ie->file);
562 /* SLKDBG(im->cache.lock); */
563 }
564 }
565 else if (ret == EINA_LOCK_DEADLOCK)
566 {
567 printf("WARNING: DEADLOCK on image %p (%s)\n", im, ie->file);
568 }
569 else locked = 1;
570 #endif
571 if (!locked) { SLKL(im->cache.lock); locked = 1; }
572 use_counter++;
573 if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
574 {
575 // 1:1 scale.
576 im->cache.orig_usage++;
577 im->cache.usage_count = use_counter;
578 if (locked) SLKU(im->cache.lock);
579 return EINA_FALSE;
580 }
581 if ((!im->cache_entry.flags.alpha) && (!smooth))
582 {
583 // solid nearest scaling - it's actually the same speed cached or not,
584 // or in some cases faster not cached
585 im->cache.orig_usage++;
586 im->cache.usage_count = use_counter;
587 if (locked) SLKU(im->cache.lock);
588 return EINA_FALSE;
589 }
590 SLKL(cache_lock);
591 sci = _sci_find(im, dc, smooth,
592 src_region_x, src_region_y, src_region_w, src_region_h,
593 dst_region_w, dst_region_h);
594 if (!sci)
595 {
596 SLKU(cache_lock);
597 if (locked) SLKU(im->cache.lock);
598 return EINA_FALSE;
599 }
600 // INF("%10i | %4i %4i %4ix%4i -> %4i %4i %4ix%4i | %i",
601 // (int)use_counter,
602 // src_region_x, src_region_y, src_region_w, src_region_h,
603 // dst_region_x, dst_region_y, dst_region_w, dst_region_h,
604 // smooth);
605 if ((sci->usage >= min_scale_uses)
606 && (ie->scale_hint != EVAS_IMAGE_SCALE_HINT_DYNAMIC)
607 // && (sci->usage_count > (use_counter - MIN_SCALE_AGE_GAP))
608 )
609 {
610 if (!sci->im)
611 {
612 if ((sci->key.dst_w < max_dimension) &&
613 (sci->key.dst_h < max_dimension))
614 {
615 if (sci->flop <= max_flop_count)
616 {
617 sci->populate_me = 1;
618 im->cache.populate_count++;
619 }
620 }
621 }
622 }
623 sci->usage++;
624 sci->usage_count = use_counter;
625 SLKU(cache_lock);
626 if (sci->usage > im->cache.newest_usage)
627 im->cache.newest_usage = sci->usage;
628 // INF("newset? %p %i > %i", im,
629 // (int)sci->usage,
630 // (int)im->cache.newest_usage);
631 if (sci->usage_count > im->cache.newest_usage_count)
632 im->cache.newest_usage_count = sci->usage_count;
633 // INF(" -------------- used %8i#, %8i@", (int)sci->usage, (int)sci->usage_count);
634 if (locked) SLKU(im->cache.lock);
635 #endif
636 if ((!im->image.data) && (sci->populate_me)) return EINA_FALSE;
637 return EINA_TRUE;
638 }
639
640 #ifdef SCALECACHE
641 //static int pops = 0;
642 //static int hits = 0;
643 //static int misses = 0;
644 //static int noscales = 0;
645 #endif
646
647 EAPI Eina_Bool
evas_common_rgba_image_scalecache_do_cbs(Image_Entry * ie,RGBA_Image * dst,RGBA_Draw_Context * dc,int smooth,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h,Evas_Common_Scale_In_To_Out_Clip_Cb cb_sample,Evas_Common_Scale_In_To_Out_Clip_Cb cb_smooth)648 evas_common_rgba_image_scalecache_do_cbs(Image_Entry *ie, RGBA_Image *dst,
649 RGBA_Draw_Context *dc, int smooth,
650 int src_region_x, int src_region_y,
651 int src_region_w, int src_region_h,
652 int dst_region_x, int dst_region_y,
653 int dst_region_w, int dst_region_h,
654 Evas_Common_Scale_In_To_Out_Clip_Cb cb_sample,
655 Evas_Common_Scale_In_To_Out_Clip_Cb cb_smooth)
656 {
657 #ifdef SCALECACHE
658 RGBA_Image *im = (RGBA_Image *)ie;
659 Scaleitem *sci;
660 int didpop = 0;
661 int dounload = 0;
662 Eina_Bool ret = EINA_FALSE;
663 /*
664 static int i = 0;
665
666 i++;
667 if (i > 2000)
668 {
669 INF("p: %6i, h: %6i, m: %6i, n: %6i",
670 pops, hits, misses, noscales);
671 i = 0;
672 }
673 */
674 if ((dst_region_w == 0) || (dst_region_h == 0) ||
675 (src_region_w == 0) || (src_region_h == 0)) return EINA_FALSE;
676 if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
677 {
678 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
679 evas_cache_image_load_data(&im->cache_entry);
680 evas_common_image_colorspace_normalize(im);
681
682 // noscales++;
683 if (im->image.data)
684 {
685 return cb_sample(im, dst, dc,
686 src_region_x, src_region_y,
687 src_region_w, src_region_h,
688 dst_region_x, dst_region_y,
689 dst_region_w, dst_region_h);
690 }
691 return EINA_FALSE;
692 }
693 SLKL(cache_lock);
694 sci = _sci_find(im, dc, smooth,
695 src_region_x, src_region_y, src_region_w, src_region_h,
696 dst_region_w, dst_region_h);
697 SLKU(cache_lock);
698 if (!sci)
699 {
700 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
701 evas_cache_image_load_data(&im->cache_entry);
702 evas_common_image_colorspace_normalize(im);
703
704 // misses++;
705 if (im->image.data)
706 {
707 if (smooth)
708 return cb_smooth(im, dst, dc,
709 src_region_x, src_region_y,
710 src_region_w, src_region_h,
711 dst_region_x, dst_region_y,
712 dst_region_w, dst_region_h);
713 else
714 return cb_sample(im, dst, dc,
715 src_region_x, src_region_y,
716 src_region_w, src_region_h,
717 dst_region_x, dst_region_y,
718 dst_region_w, dst_region_h);
719 }
720 return EINA_FALSE;
721 }
722 SLKL(im->cache.lock);
723 if (sci->populate_me)
724 {
725 int size, osize, used;
726
727 size = dst_region_w * dst_region_h;
728 if (((((dst_region_w > 640) || (dst_region_h > 640)) &&
729 (size > (480 * 480))) ||
730 (ie->scale_hint == EVAS_IMAGE_SCALE_HINT_STATIC)) &&
731 (ie->scale_hint != EVAS_IMAGE_SCALE_HINT_DYNAMIC))
732 {
733 Eina_List *l;
734 Scaleitem *sci2;
735
736 dounload = 1;
737 osize = sci->parent_im->cache_entry.w * sci->parent_im->cache_entry.h;
738 used = 0;
739 EINA_LIST_FOREACH(im->cache.list, l, sci2)
740 {
741 if (sci2->im) used += sci2->key.dst_w * sci2->key.dst_h;
742 }
743 if ((size < osize) && (used == 0))
744 sci->size_adjust = 0;
745 else
746 {
747 osize -= used;
748 if (osize < 0) osize = 0;
749 size -= osize;
750 sci->size_adjust = size * 4;
751 }
752 }
753 else
754 {
755 size *= sizeof(DATA32);
756 if ((cache_size + size) > max_cache_size)
757 {
758 sci->populate_me = 0;
759 im->cache.populate_count--;
760 }
761 }
762 }
763
764 if (sci->populate_me)
765 {
766 // INF("##! populate!");
767 sci->im = evas_common_image_new
768 (dst_region_w, dst_region_h, im->cache_entry.flags.alpha);
769 if (sci->im)
770 {
771 static RGBA_Draw_Context *ct = NULL;
772
773 SLKL(cache_lock);
774 im->cache.orig_usage++;
775 im->cache.usage_count = use_counter;
776 im->cache.populate_count--;
777 // pops++;
778 if (!ct)
779 {
780 // FIXME: static ct - never can free on shutdown? not a leak
781 // or real harm - just annoying valgrind bitch
782 ct = evas_common_draw_context_new();
783 evas_common_draw_context_set_render_op(ct, _EVAS_RENDER_COPY);
784 }
785 SLKU(cache_lock);
786 SLKU(im->cache.lock);
787
788 SLKL(cache_lock);
789 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
790 evas_cache_image_load_data(&im->cache_entry);
791 SLKU(cache_lock);
792
793 SLKL(im->cache.lock);
794 SLKL(cache_lock);
795 evas_common_image_colorspace_normalize(im);
796 if (im->image.data)
797 {
798 if (smooth)
799 ret = cb_smooth(im, sci->im, ct,
800 src_region_x, src_region_y,
801 src_region_w, src_region_h,
802 0, 0,
803 dst_region_w, dst_region_h);
804 else
805 ret = cb_sample(im, sci->im, ct,
806 src_region_x, src_region_y,
807 src_region_w, src_region_h,
808 0, 0,
809 dst_region_w, dst_region_h);
810 sci->populate_me = 0;
811 #if 0 // visual debug of cached images
812 {
813 int xx, yy;
814 DATA32 *pp;
815
816 pp = sci->im->image.data;
817 for (yy = 0; yy < dst_region_h; yy++)
818 {
819
820 for (xx = 0; xx < dst_region_w; xx++)
821 {
822 if (yy & 0x1)
823 {
824 if (xx & 0x1) *pp = 0x882288ff;
825 }
826 else
827 {
828 if (!(xx & 0x1)) *pp = 0x882288ff;
829 }
830 pp++;
831 }
832 }
833 }
834 #endif
835 }
836 if (dounload)
837 {
838 sci->forced_unload = 1;
839 cache_size += sci->size_adjust;
840 }
841 else
842 {
843 cache_size += sci->key.dst_w * sci->key.dst_h * 4;
844 }
845 // INF(" + %i @ flop: %i (%ix%i)",
846 // sci->dst_w * sci->dst_h * 4, sci->flop,
847 // sci->dst_w, sci->dst_h);
848 cache_list = eina_inlist_append(cache_list, (Eina_Inlist *)sci);
849 SLKU(cache_lock);
850 didpop = 1;
851 }
852 }
853 if (sci->im && !ie->animated.animated)
854 {
855 if (!didpop)
856 {
857 SLKL(cache_lock);
858 cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
859 cache_list = eina_inlist_append(cache_list, (Eina_Inlist *)sci);
860 SLKU(cache_lock);
861 }
862 else
863 {
864 if (sci->flop >= FLOP_DEL) sci->flop -= FLOP_DEL;
865 }
866 // INF("use cached!");
867 SLKU(im->cache.lock);
868 ret |= cb_sample(sci->im, dst, dc,
869 0, 0,
870 dst_region_w, dst_region_h,
871 dst_region_x, dst_region_y,
872 dst_region_w, dst_region_h);
873 // hits++;
874 // INF("check %p %i < %i",
875 // im,
876 // (int)im->cache.orig_usage,
877 // (int)im->cache.newest_usage);
878 /* while framequeuing is applied,
879 * original image data is loaded by the main thread
880 * just before enqueuing the rendering op into the pipe.
881 * so unloading the original image data here
882 * causes only speed-down side-effect and no memory usage gain;
883 * it will be loaded again for the very next rendering for this image.
884 */
885 if (ie->scale_hint != EVAS_IMAGE_SCALE_HINT_DYNAMIC)
886 {
887 if ((dounload) ||
888 ((im->cache_entry.flags.loaded) &&
889 ((!im->cs.no_free)) &&
890 (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)))
891 {
892 if ((dounload) || (im->cache.orig_usage <
893 (im->cache.newest_usage / 20)))
894 {
895 //FIXME: imagedataunload - inform owners
896 /* FIXME: must be the _cache version, no? */
897 evas_common_rgba_image_unload(&im->cache_entry);
898 }
899 }
900 }
901 }
902 else
903 {
904 SLKU(im->cache.lock);
905 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
906 evas_cache_image_load_data(&im->cache_entry);
907 evas_common_image_colorspace_normalize(im);
908 // misses++;
909 if (im->image.data)
910 {
911 if (smooth)
912 ret |= cb_smooth(im, dst, dc,
913 src_region_x, src_region_y,
914 src_region_w, src_region_h,
915 dst_region_x, dst_region_y,
916 dst_region_w, dst_region_h);
917 else
918 ret |= cb_sample(im, dst, dc,
919 src_region_x, src_region_y,
920 src_region_w, src_region_h,
921 dst_region_x, dst_region_y,
922 dst_region_w, dst_region_h);
923 }
924 }
925
926 return ret;
927
928 #else
929
930 RGBA_Image *im = (RGBA_Image *)ie;
931
932 if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
933 evas_cache_image_load_data(&im->cache_entry);
934 evas_common_image_colorspace_normalize(im);
935 if (im->image.data)
936 {
937 if (smooth)
938 return cb_smooth(im, dst, dc,
939 src_region_x, src_region_y,
940 src_region_w, src_region_h,
941 dst_region_x, dst_region_y,
942 dst_region_w, dst_region_h);
943 else
944 return cb_sample(im, dst, dc,
945 src_region_x, src_region_y,
946 src_region_w, src_region_h,
947 dst_region_x, dst_region_y,
948 dst_region_w, dst_region_h);
949 }
950
951 return EINA_FALSE;
952 #endif
953 }
954
955
956 EAPI void
evas_common_rgba_image_scalecache_do(Image_Entry * ie,RGBA_Image * dst,RGBA_Draw_Context * dc,int smooth,int src_region_x,int src_region_y,int src_region_w,int src_region_h,int dst_region_x,int dst_region_y,int dst_region_w,int dst_region_h)957 evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
958 RGBA_Draw_Context *dc, int smooth,
959 int src_region_x, int src_region_y,
960 int src_region_w, int src_region_h,
961 int dst_region_x, int dst_region_y,
962 int dst_region_w, int dst_region_h)
963 {
964 evas_common_rgba_image_scalecache_do_cbs(
965 ie, dst, dc, smooth,
966 src_region_x, src_region_y, src_region_w, src_region_h,
967 dst_region_x, dst_region_y, dst_region_w, dst_region_h,
968 evas_common_scale_rgba_in_to_out_clip_sample,
969 evas_common_scale_rgba_in_to_out_clip_smooth);
970 evas_common_rgba_image_scalecache_prune();
971 }
972