big patch from Samsung SAIT (Advanced research group) for async multi-frame
[framework/uifw/evas.git] / src / lib / engines / common / evas_image_scalecache.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include "config.h"
7 #endif
8
9 #ifdef HAVE_EVIL
10 # include <Evil.h>
11 #endif
12
13 #include <assert.h>
14
15 #include "evas_common.h"
16 #include "evas_private.h"
17 #include "evas_image_private.h"
18
19 #define SCALECACHE 1
20
21 #define MAX_SCALEITEMS 32
22 #define MIN_SCALE_USES 3
23 //#define MIN_SCALE_AGE_GAP 5000
24 #define MAX_SCALECACHE_DIM 3200
25 #define FLOP_ADD 4
26 #define MAX_FLOP_COUNT 16
27 #define FLOP_DEL 1
28 #define SCALE_CACHE_SIZE 4 * 1024 * 1024
29 //#define SCALE_CACHE_SIZE 0
30
31 typedef struct _Scaleitem Scaleitem;
32
33 struct _Scaleitem
34 {
35    EINA_INLIST;
36    unsigned long long usage;
37    unsigned long long usage_count;
38    RGBA_Image *im, *parent_im;
39    int src_x, src_y, src_w, src_h;
40    int dst_w, dst_h;
41    int flop;
42    int size_adjust;
43 #ifdef EVAS_FRAME_QUEUING
44    RWLK(lock);
45 #endif
46    Eina_Bool forced_unload : 1;
47    Eina_Bool smooth : 1;
48    Eina_Bool populate_me : 1;
49 };
50
51 #ifdef SCALECACHE
52 static unsigned long long use_counter = 0;
53
54 #ifdef BUILD_PTHREAD
55 static LK(cache_lock);
56 #endif
57 static Eina_Inlist *cache_list = NULL;
58 static int cache_size = 0;
59 static int init = 0;
60
61 static int max_cache_size = SCALE_CACHE_SIZE;
62 static int max_dimension = MAX_SCALECACHE_DIM;
63 static int max_flop_count = MAX_FLOP_COUNT;
64 static int max_scale_items = MAX_SCALEITEMS;
65 static int min_scale_uses = MIN_SCALE_USES;
66 #endif
67
68 void
69 evas_common_scalecache_init(void)
70 {
71 #ifdef SCALECACHE
72    const char *s;
73
74    init++;
75    if (init > 1) return;
76    use_counter = 0;
77    LKI(cache_lock);
78    s = getenv("EVAS_SCALECACHE_SIZE");
79    if (s) max_cache_size = atoi(s) * 1024;
80    s = getenv("EVAS_SCALECACHE_MAX_DIMENSION");
81    if (s) max_dimension = atoi(s);
82    s = getenv("EVAS_SCALECACHE_MAX_FLOP_COUNT");
83    if (s) max_flop_count = atoi(s);
84    s = getenv("EVAS_SCALECACHE_MAX_ITEMS");
85    if (s) max_scale_items = atoi(s);
86    s = getenv("EVAS_SCALECACHE_MIN_USES");
87    if (s) min_scale_uses = atoi(s);
88 #endif
89 }
90
91 void
92 evas_common_scalecache_shutdown(void)
93 {
94 #ifdef SCALECACHE
95    init--;
96    if (init ==0)
97       LKD(cache_lock);
98 #endif
99 }
100
101 void
102 evas_common_rgba_image_scalecache_init(Image_Entry *ie)
103 {
104 #ifdef SCALECACHE
105    RGBA_Image *im = (RGBA_Image *)ie;
106    LKI(im->cache.lock);
107 #endif
108 }
109
110 void
111 evas_common_rgba_image_scalecache_shutdown(Image_Entry *ie)
112 {
113 #ifdef SCALECACHE
114    RGBA_Image *im = (RGBA_Image *)ie;
115    evas_common_rgba_image_scalecache_dirty(ie);
116    LKD(im->cache.lock);
117 #endif
118 }
119
120 void
121 evas_common_rgba_image_scalecache_dirty(Image_Entry *ie)
122 {
123 #ifdef SCALECACHE
124    RGBA_Image *im = (RGBA_Image *)ie;
125    LKL(im->cache.lock);
126    while (im->cache.list)
127      {
128         Scaleitem *sci;
129         sci = im->cache.list->data;
130 #ifdef EVAS_FRAME_QUEUING
131         WRLKL(sci->lock);
132 #endif
133         im->cache.list = eina_list_remove(im->cache.list, sci);
134         if (sci->im)
135           {
136 //             INF(" 0- %i", sci->dst_w * sci->dst_h * 4);
137              LKL(cache_lock);
138              evas_common_rgba_image_free(&sci->im->cache_entry);
139              if (!sci->forced_unload)
140                cache_size -= sci->dst_w * sci->dst_h * 4;
141              else
142                cache_size -= sci->size_adjust;
143              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
144              LKU(cache_lock);
145           }
146 #ifdef EVAS_FRAME_QUEUING
147          RWLKU(sci->lock);
148          RWLKD(sci->lock);
149 #endif
150         free(sci);
151      }
152    LKU(im->cache.lock);
153 #endif
154 }
155
156 void
157 evas_common_rgba_image_scalecache_orig_use(Image_Entry *ie)
158 {
159 #ifdef SCALECACHE
160    RGBA_Image *im = (RGBA_Image *)ie;
161    LKL(im->cache.lock);
162    use_counter++;
163    // FIXME: if orig not loaded, reload
164    // FIXME: mark orig with current used counter
165    im->cache.orig_usage++;
166    im->cache.usage_count = use_counter;
167    LKU(im->cache.lock);
168 #endif
169 }
170
171 int
172 evas_common_rgba_image_scalecache_usage_get(Image_Entry *ie)
173 {
174 #ifdef SCALECACHE
175    RGBA_Image *im = (RGBA_Image *)ie;
176    int size = 0;
177    Eina_List *l;
178    Scaleitem *sci;
179    LKL(im->cache.lock);
180    EINA_LIST_FOREACH(im->cache.list, l, sci)
181      {
182         if (sci->im) size += sci->dst_w * sci->dst_h * 4;
183      }
184    LKU(im->cache.lock);
185    return size;
186 #else
187    return 0;
188 #endif
189 }
190
191 #ifdef SCALECACHE
192 static void
193 _sci_fix_newest(RGBA_Image *im)
194 {
195    Eina_List *l;
196    Scaleitem *sci;
197    
198    im->cache.newest_usage = 0;
199    im->cache.newest_usage_count = 0;
200    EINA_LIST_FOREACH(im->cache.list, l, sci)
201      {
202         if (sci->usage > im->cache.newest_usage)
203           im->cache.newest_usage = sci->usage;
204         if (sci->usage_count > im->cache.newest_usage_count)
205           im->cache.newest_usage_count = sci->usage_count;
206      }
207 //   INF("_sci_fix_newest! -> %i", im->cache.newest_usage);
208 }
209
210 static Scaleitem *
211 _sci_find(RGBA_Image *im,
212           RGBA_Draw_Context *dc __UNUSED__, int smooth,
213           int src_region_x, int src_region_y,
214           int src_region_w, int src_region_h,
215           int dst_region_w, int dst_region_h)
216 {
217    Eina_List *l;
218    Scaleitem *sci;
219
220    EINA_LIST_FOREACH(im->cache.list, l, sci)
221      {
222         if (
223             (sci->src_w == src_region_w) &&
224             (sci->src_h == src_region_h) &&
225             (sci->dst_w == dst_region_w) &&
226             (sci->dst_h == dst_region_h) &&
227             (sci->src_x == src_region_x) &&
228             (sci->src_y == src_region_y) &&
229             (sci->smooth == smooth)
230             )
231           {
232              if (im->cache.list != l)
233                {
234                   im->cache.list = eina_list_remove_list(im->cache.list, l);
235                   im->cache.list = eina_list_prepend(im->cache.list, sci);
236                }
237              return sci;
238           }
239      }
240    if (eina_list_count(im->cache.list) > max_scale_items)
241      {
242         l = eina_list_last(im->cache.list);
243         sci = l->data;
244 #ifdef EVAS_FRAME_QUEUING
245         WRLKL(sci->lock);
246 #endif
247         im->cache.list = eina_list_remove_list(im->cache.list, l);
248         if ((sci->usage == im->cache.newest_usage) ||
249             (sci->usage_count == im->cache.newest_usage_count))
250           _sci_fix_newest(im);
251         if (sci->im)
252           {
253              evas_common_rgba_image_free(&sci->im->cache_entry);
254              if (!sci->forced_unload)
255                cache_size -= sci->dst_w * sci->dst_h * 4;
256              else
257                cache_size -= sci->size_adjust;
258 //             INF(" 1- %i", sci->dst_w * sci->dst_h * 4);
259              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
260           }
261 #ifdef EVAS_FRAME_QUEUING
262         RWLKU(sci->lock);
263 #endif
264         if (max_scale_items < 1) return NULL;
265      }
266    else
267      {
268         if (max_scale_items < 1) return NULL;
269
270         if (eina_list_count(im->cache.list) > (max_scale_items - 1))
271           return NULL;
272         sci = malloc(sizeof(Scaleitem));
273         memset(sci, 0, sizeof(Eina_Inlist));
274         sci->parent_im = im;
275 #ifdef EVAS_FRAME_QUEUING
276         RWLKI(sci->lock);
277 #endif
278      }
279    sci->usage = 0;
280    sci->usage_count = 0;
281    sci->populate_me = 0;
282    sci->smooth = smooth;
283    sci->forced_unload = 0;
284    sci->flop = 0;
285    sci->im = NULL;
286    sci->src_x = src_region_x;
287    sci->src_y = src_region_y;
288    sci->src_w = src_region_w;
289    sci->src_h = src_region_h;
290    sci->dst_w = dst_region_w;
291    sci->dst_h = dst_region_h;
292    im->cache.list = eina_list_prepend(im->cache.list, sci);
293    return sci;
294 }
295
296 static void
297 _cache_prune(Scaleitem *notsci, Eina_Bool copies_only)
298 {
299    Scaleitem *sci;
300    while (cache_size > max_cache_size)
301      {
302         if (!cache_list) break;
303         sci = (Scaleitem *)(cache_list);
304         if (copies_only)
305           {
306              while ((sci) && (!sci->parent_im->image.data))
307                sci = (Scaleitem *)(((Eina_Inlist *)sci)->next);
308              if (!sci) return;
309           }
310         if (sci == notsci) return;
311 #ifdef EVAS_FRAME_QUEUING
312         WRLKL(sci->lock);
313 #endif
314         if (sci->im)
315           {
316              evas_common_rgba_image_free(&sci->im->cache_entry);
317              sci->im = NULL;
318              sci->usage = 0;
319              sci->usage_count = 0;
320              sci->flop += FLOP_ADD;
321              if (!sci->forced_unload)
322                cache_size -= sci->dst_w * sci->dst_h * 4;
323              else
324                cache_size -= sci->size_adjust;
325 //             INF(" 2- %i", sci->dst_w * sci->dst_h * 4);
326              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
327              memset(sci, 0, sizeof(Eina_Inlist));
328           }
329 #ifdef EVAS_FRAME_QUEUING
330         RWLKU(sci->lock);
331 #endif
332
333 //        INF("FLUSH %i > %i", cache_size, max_cache_size);
334       }
335 }
336 #endif
337
338 EAPI void
339 evas_common_rgba_image_scalecache_size_set(int size)
340 {
341 #ifdef SCALECACHE
342    LKL(cache_lock);
343    if (size != max_cache_size)
344      {
345         max_cache_size = size;
346         _cache_prune(NULL, 1);
347      }
348    LKU(cache_lock);
349 #endif   
350 }
351
352 EAPI int
353 evas_common_rgba_image_scalecache_size_get(void)
354 {
355 #ifdef SCALECACHE
356    int t;
357    LKL(cache_lock);
358    t = max_cache_size;
359    LKU(cache_lock);
360    return t;
361 #else
362    return 0;
363 #endif   
364 }
365
366 EAPI void
367 evas_common_rgba_image_scalecache_flush(void)
368 {
369 #ifdef SCALECACHE
370    int t;
371    LKL(cache_lock);
372    t = max_cache_size;
373    max_cache_size = 0;
374    _cache_prune(NULL, 1);
375    max_cache_size = t;
376    LKU(cache_lock);
377 #endif   
378 }
379
380 EAPI void
381 evas_common_rgba_image_scalecache_prepare(Image_Entry *ie, RGBA_Image *dst __UNUSED__,
382                                           RGBA_Draw_Context *dc, int smooth,
383                                           int src_region_x, int src_region_y,
384                                           int src_region_w, int src_region_h,
385                                           int dst_region_x __UNUSED__, int dst_region_y __UNUSED__,
386                                           int dst_region_w, int dst_region_h)
387 {
388 #ifdef SCALECACHE
389    RGBA_Image *im = (RGBA_Image *)ie;
390    Scaleitem *sci;
391    if (!im->image.data) return;
392    if ((dst_region_w == 0) || (dst_region_h == 0) ||
393        (src_region_w == 0) || (src_region_h == 0)) return;
394    LKL(im->cache.lock);
395    use_counter++;
396    if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
397      {
398         // 1:1 scale.
399         im->cache.orig_usage++;
400         im->cache.usage_count = use_counter;
401         LKU(im->cache.lock);
402         return;
403      }
404    if ((!im->cache_entry.flags.alpha) && (!smooth))
405      {
406         // solid nearest scaling - it's actually the same speed cached or not,
407         // or in some cases faster not cached
408         im->cache.orig_usage++;
409         im->cache.usage_count = use_counter;
410         LKU(im->cache.lock);
411         return;
412      }
413    LKL(cache_lock);
414    sci = _sci_find(im, dc, smooth, 
415                    src_region_x, src_region_y, src_region_w, src_region_h, 
416                    dst_region_w, dst_region_h);
417    if (!sci)
418      {
419         LKU(cache_lock);
420         LKU(im->cache.lock);
421         return;
422      }
423 //   INF("%10i | %4i %4i %4ix%4i -> %4i %4i %4ix%4i | %i",
424 //          (int)use_counter,
425 //          src_region_x, src_region_y, src_region_w, src_region_h,
426 //          dst_region_x, dst_region_y, dst_region_w, dst_region_h,
427 //          smooth);
428    if ((sci->usage >= min_scale_uses)
429        && (ie->scale_hint != EVAS_IMAGE_SCALE_HINT_DYNAMIC)
430 //       && (sci->usage_count > (use_counter - MIN_SCALE_AGE_GAP))
431        )
432      {
433         if (!sci->im)
434           {
435              if ((sci->dst_w < max_dimension) && 
436                  (sci->dst_h < max_dimension))
437                {
438                   if (sci->flop <= max_flop_count)
439                     {
440                        sci->populate_me = 1;
441                        im->cache.populate_count++;
442                     }
443                }
444           }
445      }
446    sci->usage++;
447    sci->usage_count = use_counter;
448    LKU(cache_lock);
449    if (sci->usage > im->cache.newest_usage) 
450      im->cache.newest_usage = sci->usage;
451 //   INF("newset? %p %i > %i", im, 
452 //          (int)sci->usage, 
453 //          (int)im->cache.newest_usage);
454    if (sci->usage_count > im->cache.newest_usage_count) 
455      im->cache.newest_usage_count = sci->usage_count;
456 //   INF("  -------------- used %8i#, %8i@", (int)sci->usage, (int)sci->usage_count);
457    LKU(im->cache.lock);
458 #endif
459 }
460
461 #ifdef SCALECACHE
462 //static int pops = 0;
463 //static int hits = 0;
464 //static int misses = 0;
465 //static int noscales = 0;
466 #endif
467
468 EAPI void
469 evas_common_rgba_image_scalecache_do(Image_Entry *ie, RGBA_Image *dst,
470                                      RGBA_Draw_Context *dc, int smooth,
471                                      int src_region_x, int src_region_y,
472                                      int src_region_w, int src_region_h,
473                                      int dst_region_x, int dst_region_y,
474                                      int dst_region_w, int dst_region_h)
475 {
476 #ifdef SCALECACHE
477    RGBA_Image *im = (RGBA_Image *)ie;
478    Scaleitem *sci;
479    int didpop = 0;
480    int dounload = 0;
481 /*
482    static int i = 0;
483
484    i++;
485    if (i > 2000)
486      {
487         INF("p: %6i, h: %6i, m: %6i, n: %6i",
488                pops, hits, misses, noscales);
489         i = 0;
490      }
491  */
492    if ((dst_region_w == 0) || (dst_region_h == 0) ||
493        (src_region_w == 0) || (src_region_h == 0)) return;
494    LKL(im->cache.lock);
495    if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
496      {
497 #ifdef EVAS_FRAME_QUEUING
498         if (!evas_common_frameq_enabled())
499 #endif
500          {
501             if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
502                evas_cache_image_load_data(&im->cache_entry);
503             evas_common_image_colorspace_normalize(im);
504          }
505 //        noscales++;
506         LKU(im->cache.lock);
507         if (im->image.data)
508           {
509              if (smooth)
510                evas_common_scale_rgba_in_to_out_clip_smooth(im, dst, dc,
511                                                             src_region_x, src_region_y, 
512                                                             src_region_w, src_region_h,
513                                                             dst_region_x, dst_region_y, 
514                                                             dst_region_w, dst_region_h);
515              else
516                evas_common_scale_rgba_in_to_out_clip_sample(im, dst, dc,
517                                                             src_region_x, src_region_y, 
518                                                             src_region_w, src_region_h,
519                                                             dst_region_x, dst_region_y, 
520                                                             dst_region_w, dst_region_h);
521           }
522         return;
523      }
524    LKL(cache_lock);
525    sci = _sci_find(im, dc, smooth,
526                    src_region_x, src_region_y, src_region_w, src_region_h,
527                    dst_region_w, dst_region_h);
528    LKU(cache_lock);
529    if (!sci)
530      {
531 #ifdef EVAS_FRAME_QUEUING
532         if (!evas_common_frameq_enabled())
533 #endif
534           {
535              if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
536                 evas_cache_image_load_data(&im->cache_entry);
537              evas_common_image_colorspace_normalize(im);
538           }
539 //        misses++;
540         LKU(im->cache.lock);
541         if (im->image.data)
542           {
543              if (smooth)
544                evas_common_scale_rgba_in_to_out_clip_smooth(im, dst, dc,
545                                                             src_region_x, src_region_y, 
546                                                             src_region_w, src_region_h,
547                                                             dst_region_x, dst_region_y, 
548                                                             dst_region_w, dst_region_h);
549              else
550                evas_common_scale_rgba_in_to_out_clip_sample(im, dst, dc,
551                                                             src_region_x, src_region_y, 
552                                                             src_region_w, src_region_h,
553                                                             dst_region_x, dst_region_y, 
554                                                             dst_region_w, dst_region_h);
555           }
556         return;
557      }
558    if (sci->populate_me)
559      {
560         int size, osize, used;
561         
562         size = dst_region_w * dst_region_h;
563         if (((((dst_region_w > 640) || (dst_region_h > 640)) &&
564              (size > (480 * 480))) ||
565              (ie->scale_hint == EVAS_IMAGE_SCALE_HINT_STATIC)) &&
566             (ie->scale_hint != EVAS_IMAGE_SCALE_HINT_DYNAMIC))
567           {
568              Eina_List *l;
569              Scaleitem *sci2;
570              
571              dounload = 1;
572              osize = sci->parent_im->cache_entry.w * sci->parent_im->cache_entry.h;
573              used = 0;
574              EINA_LIST_FOREACH(im->cache.list, l, sci2)
575                {
576                   if (sci2->im) used += sci2->dst_w * sci2->dst_h;
577                }
578              if ((size < osize) && (used == 0))
579                sci->size_adjust = 0;
580              else
581                {
582                   osize -= used;
583                   if (osize < 0) osize = 0;
584                   size -= osize;
585                   sci->size_adjust = size * 4; 
586                }
587           }
588         else
589           {
590              size *= sizeof(DATA32);
591              if ((cache_size + size) > max_cache_size)
592                {
593                   sci->populate_me = 0;
594                   im->cache.populate_count--;
595                }
596           }
597      }
598    if (sci->populate_me)
599      {
600 //        INF("##! populate!");
601         sci->im = evas_common_image_new
602           (dst_region_w, dst_region_h, im->cache_entry.flags.alpha);
603         if (sci->im)
604           {
605              static RGBA_Draw_Context *ct = NULL;
606         
607              LKL(cache_lock);
608              im->cache.orig_usage++;
609              im->cache.usage_count = use_counter;
610              im->cache.populate_count--;
611 //             pops++;
612              if (!ct)
613                {
614                   // FIXME: static ct - never can free on shutdown? not a leak
615                   // or real harm - just annoying valgrind bitch
616                   ct = evas_common_draw_context_new();
617                   evas_common_draw_context_set_render_op(ct, _EVAS_RENDER_COPY);
618                }
619              if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
620                evas_cache_image_load_data(&im->cache_entry);
621              evas_common_image_colorspace_normalize(im);
622              if (im->image.data)
623                {
624                   if (smooth)
625                     evas_common_scale_rgba_in_to_out_clip_smooth
626                     (im, sci->im, ct,
627                      src_region_x, src_region_y, 
628                      src_region_w, src_region_h,
629                      0, 0,
630                      dst_region_w, dst_region_h);
631                   else
632                     evas_common_scale_rgba_in_to_out_clip_sample
633                     (im, sci->im, ct,
634                      src_region_x, src_region_y, 
635                      src_region_w, src_region_h,
636                      0, 0,
637                      dst_region_w, dst_region_h);
638                   sci->populate_me = 0;
639 #if 0 // visual debug of cached images                  
640                     {
641                        int xx, yy;
642                        DATA32 *pp;
643                        
644                        pp = sci->im->image.data;
645                        for (yy = 0; yy < dst_region_h; yy++)
646                          {
647                             
648                             for (xx = 0; xx < dst_region_w; xx++)
649                               {
650                                  if (yy & 0x1)
651                                    {
652                                       if (xx & 0x1) *pp = 0x882288ff;
653                                    }
654                                  else
655                                    { 
656                                       if (!(xx & 0x1)) *pp = 0x882288ff;
657                                   }
658                                  pp++;
659                               }
660                          }
661                     }
662 #endif                  
663                }
664              if (dounload)
665                {
666                   sci->forced_unload = 1;
667                   cache_size += sci->size_adjust;
668                }
669              else
670                {
671                   cache_size += sci->dst_w * sci->dst_h * 4;
672                }
673 //             INF(" + %i @ flop: %i (%ix%i)", 
674 //                    sci->dst_w * sci->dst_h * 4, sci->flop, 
675 //                    sci->dst_w, sci->dst_h);
676              cache_list = eina_inlist_append(cache_list, (Eina_Inlist *)sci);
677              _cache_prune(sci, 0);
678              LKU(cache_lock);
679              didpop = 1;
680           }
681      }
682    if (sci->im)
683      {
684         if (!didpop)
685           {
686              LKL(cache_lock);
687              cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
688              cache_list = eina_inlist_append(cache_list, (Eina_Inlist *)sci);
689              LKU(cache_lock);
690           }
691         else
692           {
693              if (sci->flop > 0) sci->flop -= FLOP_DEL;
694           }
695 //        INF("use cached!");
696 #ifdef EVAS_FRAME_QUEUING
697         RDLKL(sci->lock);
698 #endif
699         LKU(im->cache.lock);
700         evas_common_scale_rgba_in_to_out_clip_sample
701           (sci->im, dst, dc,
702            0, 0,
703            dst_region_w, dst_region_h,
704            dst_region_x, dst_region_y, 
705            dst_region_w, dst_region_h);
706 #ifdef EVAS_FRAME_QUEUING
707         RWLKU(sci->lock);
708 #endif
709 //        hits++;
710 //        INF("check %p %i < %i", 
711 //               im,
712 //               (int)im->cache.orig_usage, 
713 //               (int)im->cache.newest_usage);
714 #ifndef EVAS_FRAME_QUEUING
715         /* while framequeuing is applied,
716          * original image data is loaded by the main thread 
717          * just before enqueuing the rendering op into the pipe.
718          * so unloading the original image data here 
719          * causes only speed-down side-effect and no memory usage gain;
720          * it will be loaded again for the very next rendering for this image.
721          */
722         if ((dounload) || 
723             ((im->cache_entry.flags.loaded) && 
724              ((!im->cs.no_free) 
725 #ifdef EVAS_CSERVE             
726              || (ie->data1)
727 #endif             
728               )  &&
729              (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)))
730           {
731              if ((dounload) || (im->cache.orig_usage < 
732                                 (im->cache.newest_usage / 20)))
733                {
734                   evas_common_rgba_image_unload(&im->cache_entry);
735                }
736           }
737 #endif
738      }
739    else
740      {
741 #ifdef EVAS_FRAME_QUEUING
742         if (!evas_common_frameq_enabled())
743 #endif
744           {
745              if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
746                 evas_cache_image_load_data(&im->cache_entry);
747              evas_common_image_colorspace_normalize(im);
748           }
749 //        misses++;
750         LKU(im->cache.lock);
751         if (im->image.data)
752           {
753              if (smooth)
754                evas_common_scale_rgba_in_to_out_clip_smooth(im, dst, dc,
755                                                             src_region_x, src_region_y, 
756                                                             src_region_w, src_region_h,
757                                                             dst_region_x, dst_region_y, 
758                                                             dst_region_w, dst_region_h);
759              else
760                evas_common_scale_rgba_in_to_out_clip_sample(im, dst, dc,
761                                                             src_region_x, src_region_y, 
762                                                             src_region_w, src_region_h,
763                                                             dst_region_x, dst_region_y, 
764                                                             dst_region_w, dst_region_h);
765           }
766      }
767 #else   
768    RGBA_Image *im = (RGBA_Image *)ie;
769 #ifdef EVAS_FRAME_QUEUING
770    if (!evas_common_frameq_enabled())
771 #endif
772      {
773         if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
774            evas_cache_image_load_data(&im->cache_entry);
775         evas_common_image_colorspace_normalize(im);
776      }
777    if (im->image.data)
778      {
779         if (smooth)
780           evas_common_scale_rgba_in_to_out_clip_smooth(im, dst, dc,
781                                                        src_region_x, src_region_y, 
782                                                        src_region_w, src_region_h,
783                                                        dst_region_x, dst_region_y, 
784                                                        dst_region_w, dst_region_h);
785         else
786           evas_common_scale_rgba_in_to_out_clip_sample(im, dst, dc,
787                                                        src_region_x, src_region_y, 
788                                                        src_region_w, src_region_h,
789                                                        dst_region_x, dst_region_y, 
790                                                        dst_region_w, dst_region_h);
791      }
792 #endif
793 }
794
795 #if 0
796 // to be done
797 void
798 evas_common_rgba_image_scalecache_XXX(Image_Entry *ie)
799 {
800 #ifdef SCALECACHE
801    RGBA_Image *im = (RGBA_Image *)ie;
802    LKL(im->cache.lock);
803    // FIXME: XXX
804    LKU(im->cache.lock);
805 #endif
806 }
807 #endif