2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
15 #include "evas_common.h"
16 #include "evas_private.h"
17 #include "evas_image_private.h"
21 #define MAX_SCALEITEMS 32
22 #define MIN_SCALE_USES 3
23 //#define MIN_SCALE_AGE_GAP 5000
24 #define MAX_SCALECACHE_DIM 3200
26 #define MAX_FLOP_COUNT 16
28 #define SCALE_CACHE_SIZE 4 * 1024 * 1024
29 //#define SCALE_CACHE_SIZE 0
31 typedef struct _Scaleitem Scaleitem;
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;
43 #ifdef EVAS_FRAME_QUEUING
46 Eina_Bool forced_unload : 1;
48 Eina_Bool populate_me : 1;
52 static unsigned long long use_counter = 0;
55 static LK(cache_lock);
57 static Eina_Inlist *cache_list = NULL;
58 static int cache_size = 0;
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;
69 evas_common_scalecache_init(void)
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);
92 evas_common_scalecache_shutdown(void)
102 evas_common_rgba_image_scalecache_init(Image_Entry *ie)
105 RGBA_Image *im = (RGBA_Image *)ie;
111 evas_common_rgba_image_scalecache_shutdown(Image_Entry *ie)
114 RGBA_Image *im = (RGBA_Image *)ie;
115 evas_common_rgba_image_scalecache_dirty(ie);
121 evas_common_rgba_image_scalecache_dirty(Image_Entry *ie)
124 RGBA_Image *im = (RGBA_Image *)ie;
126 while (im->cache.list)
129 sci = im->cache.list->data;
130 #ifdef EVAS_FRAME_QUEUING
133 im->cache.list = eina_list_remove(im->cache.list, sci);
136 // INF(" 0- %i", sci->dst_w * sci->dst_h * 4);
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;
142 cache_size -= sci->size_adjust;
143 cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
146 #ifdef EVAS_FRAME_QUEUING
157 evas_common_rgba_image_scalecache_orig_use(Image_Entry *ie)
160 RGBA_Image *im = (RGBA_Image *)ie;
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;
172 evas_common_rgba_image_scalecache_usage_get(Image_Entry *ie)
175 RGBA_Image *im = (RGBA_Image *)ie;
180 EINA_LIST_FOREACH(im->cache.list, l, sci)
182 if (sci->im) size += sci->dst_w * sci->dst_h * 4;
193 _sci_fix_newest(RGBA_Image *im)
198 im->cache.newest_usage = 0;
199 im->cache.newest_usage_count = 0;
200 EINA_LIST_FOREACH(im->cache.list, l, sci)
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;
207 // INF("_sci_fix_newest! -> %i", im->cache.newest_usage);
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)
220 EINA_LIST_FOREACH(im->cache.list, l, sci)
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)
232 if (im->cache.list != l)
234 im->cache.list = eina_list_remove_list(im->cache.list, l);
235 im->cache.list = eina_list_prepend(im->cache.list, sci);
240 if (eina_list_count(im->cache.list) > max_scale_items)
242 l = eina_list_last(im->cache.list);
244 #ifdef EVAS_FRAME_QUEUING
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))
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;
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);
261 #ifdef EVAS_FRAME_QUEUING
264 if (max_scale_items < 1) return NULL;
268 if (max_scale_items < 1) return NULL;
270 if (eina_list_count(im->cache.list) > (max_scale_items - 1))
272 sci = malloc(sizeof(Scaleitem));
273 memset(sci, 0, sizeof(Eina_Inlist));
275 #ifdef EVAS_FRAME_QUEUING
280 sci->usage_count = 0;
281 sci->populate_me = 0;
282 sci->smooth = smooth;
283 sci->forced_unload = 0;
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);
297 _cache_prune(Scaleitem *notsci, Eina_Bool copies_only)
300 while (cache_size > max_cache_size)
302 if (!cache_list) break;
303 sci = (Scaleitem *)(cache_list);
306 while ((sci) && (!sci->parent_im->image.data))
307 sci = (Scaleitem *)(((Eina_Inlist *)sci)->next);
310 if (sci == notsci) return;
311 #ifdef EVAS_FRAME_QUEUING
316 evas_common_rgba_image_free(&sci->im->cache_entry);
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;
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));
329 #ifdef EVAS_FRAME_QUEUING
333 // INF("FLUSH %i > %i", cache_size, max_cache_size);
339 evas_common_rgba_image_scalecache_size_set(int size)
343 if (size != max_cache_size)
345 max_cache_size = size;
346 _cache_prune(NULL, 1);
353 evas_common_rgba_image_scalecache_size_get(void)
367 evas_common_rgba_image_scalecache_flush(void)
374 _cache_prune(NULL, 1);
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)
389 RGBA_Image *im = (RGBA_Image *)ie;
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;
396 if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
399 im->cache.orig_usage++;
400 im->cache.usage_count = use_counter;
404 if ((!im->cache_entry.flags.alpha) && (!smooth))
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;
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);
423 // INF("%10i | %4i %4i %4ix%4i -> %4i %4i %4ix%4i | %i",
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,
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))
435 if ((sci->dst_w < max_dimension) &&
436 (sci->dst_h < max_dimension))
438 if (sci->flop <= max_flop_count)
440 sci->populate_me = 1;
441 im->cache.populate_count++;
447 sci->usage_count = use_counter;
449 if (sci->usage > im->cache.newest_usage)
450 im->cache.newest_usage = sci->usage;
451 // INF("newset? %p %i > %i", im,
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);
462 //static int pops = 0;
463 //static int hits = 0;
464 //static int misses = 0;
465 //static int noscales = 0;
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)
477 RGBA_Image *im = (RGBA_Image *)ie;
487 INF("p: %6i, h: %6i, m: %6i, n: %6i",
488 pops, hits, misses, noscales);
492 if ((dst_region_w == 0) || (dst_region_h == 0) ||
493 (src_region_w == 0) || (src_region_h == 0)) return;
495 if ((src_region_w == dst_region_w) && (src_region_h == dst_region_h))
497 #ifdef EVAS_FRAME_QUEUING
498 if (!evas_common_frameq_enabled())
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);
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);
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);
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);
531 #ifdef EVAS_FRAME_QUEUING
532 if (!evas_common_frameq_enabled())
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);
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);
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);
558 if (sci->populate_me)
560 int size, osize, used;
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))
572 osize = sci->parent_im->cache_entry.w * sci->parent_im->cache_entry.h;
574 EINA_LIST_FOREACH(im->cache.list, l, sci2)
576 if (sci2->im) used += sci2->dst_w * sci2->dst_h;
578 if ((size < osize) && (used == 0))
579 sci->size_adjust = 0;
583 if (osize < 0) osize = 0;
585 sci->size_adjust = size * 4;
590 size *= sizeof(DATA32);
591 if ((cache_size + size) > max_cache_size)
593 sci->populate_me = 0;
594 im->cache.populate_count--;
598 if (sci->populate_me)
600 // INF("##! populate!");
601 sci->im = evas_common_image_new
602 (dst_region_w, dst_region_h, im->cache_entry.flags.alpha);
605 static RGBA_Draw_Context *ct = NULL;
608 im->cache.orig_usage++;
609 im->cache.usage_count = use_counter;
610 im->cache.populate_count--;
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);
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);
625 evas_common_scale_rgba_in_to_out_clip_smooth
627 src_region_x, src_region_y,
628 src_region_w, src_region_h,
630 dst_region_w, dst_region_h);
632 evas_common_scale_rgba_in_to_out_clip_sample
634 src_region_x, src_region_y,
635 src_region_w, src_region_h,
637 dst_region_w, dst_region_h);
638 sci->populate_me = 0;
639 #if 0 // visual debug of cached images
644 pp = sci->im->image.data;
645 for (yy = 0; yy < dst_region_h; yy++)
648 for (xx = 0; xx < dst_region_w; xx++)
652 if (xx & 0x1) *pp = 0x882288ff;
656 if (!(xx & 0x1)) *pp = 0x882288ff;
666 sci->forced_unload = 1;
667 cache_size += sci->size_adjust;
671 cache_size += sci->dst_w * sci->dst_h * 4;
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);
687 cache_list = eina_inlist_remove(cache_list, (Eina_Inlist *)sci);
688 cache_list = eina_inlist_append(cache_list, (Eina_Inlist *)sci);
693 if (sci->flop > 0) sci->flop -= FLOP_DEL;
695 // INF("use cached!");
696 #ifdef EVAS_FRAME_QUEUING
700 evas_common_scale_rgba_in_to_out_clip_sample
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
710 // INF("check %p %i < %i",
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.
723 ((im->cache_entry.flags.loaded) &&
729 (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)))
731 if ((dounload) || (im->cache.orig_usage <
732 (im->cache.newest_usage / 20)))
734 evas_common_rgba_image_unload(&im->cache_entry);
741 #ifdef EVAS_FRAME_QUEUING
742 if (!evas_common_frameq_enabled())
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);
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);
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);
768 RGBA_Image *im = (RGBA_Image *)ie;
769 #ifdef EVAS_FRAME_QUEUING
770 if (!evas_common_frameq_enabled())
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);
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);
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);
798 evas_common_rgba_image_scalecache_XXX(Image_Entry *ie)
801 RGBA_Image *im = (RGBA_Image *)ie;