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