jpeg pushed a commit to branch master.
commit c6db8ba782fe6ddb8067f67f03d7931c3da20fe9
Author: Jean-Philippe Andre <[email protected]>
Date: Fri Jul 5 10:36:19 2013 +0900
evas/cserve2: Implement fast(er) scaling of images
In its current model, cserve2 will reopen, reload and scale an
image whenever a new scaled version is requested by the client.
Instead, we can load the original image when too many scaled
versions are requested, and place the original in the LRU.
---
src/bin/evas/evas_cserve2.h | 2 +-
src/bin/evas/evas_cserve2_cache.c | 210 ++++++++++++++++++++++++++++++++++----
src/bin/evas/evas_cserve2_main.c | 9 +-
3 files changed, 194 insertions(+), 27 deletions(-)
diff --git a/src/bin/evas/evas_cserve2.h b/src/bin/evas/evas_cserve2.h
index 7708919..db4cecf 100644
--- a/src/bin/evas/evas_cserve2.h
+++ b/src/bin/evas/evas_cserve2.h
@@ -281,7 +281,7 @@ void cserve2_cache_client_new(Client *client);
void cserve2_cache_client_del(Client *client);
int cserve2_cache_file_open(Client *client, unsigned int client_file_id, const
char *path, const char *key, unsigned int rid);
void cserve2_cache_file_close(Client *client, unsigned int client_file_id);
-int cserve2_cache_image_opts_set(Client *client, int rid, unsigned int
file_id, unsigned int image_id, Evas_Image_Load_Opts *opts);
+int cserve2_cache_image_entry_create(Client *client, int rid, unsigned int
file_id, unsigned int image_id, Evas_Image_Load_Opts *opts);
void cserve2_rgba_image_scale_do(void *src_data, void *dst_data, int src_x,
int src_y, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h,
int alpha, int smooth);
void cserve2_cache_image_load(Client *client, unsigned int client_image_id,
unsigned int rid);
void cserve2_cache_image_preload(Client *client, unsigned int client_image_id,
unsigned int rid);
diff --git a/src/bin/evas/evas_cserve2_cache.c
b/src/bin/evas/evas_cserve2_cache.c
index 3b2c299..92babaf 100644
--- a/src/bin/evas/evas_cserve2_cache.c
+++ b/src/bin/evas/evas_cserve2_cache.c
@@ -491,7 +491,7 @@ _scaling_needed(Image_Data *entry, Slave_Msg_Image_Loaded
*resp)
}
static int
-_scaling_do(Shm_Handle *scale_shm, Image_Data *entry)
+_scaling_do(Shm_Handle *scale_shm, Image_Data *entry, Image_Data *original)
{
char *scale_map, *orig_map;
void *src_data, *dst_data;
@@ -503,7 +503,7 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry)
return -1;
}
- orig_map = cserve2_shm_map(entry->shm);
+ orig_map = cserve2_shm_map(original->shm);
if (orig_map == MAP_FAILED)
{
ERR("Failed to memory map file for original image.");
@@ -512,7 +512,7 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry)
return -1;
}
- src_data = orig_map + cserve2_shm_map_offset_get(entry->shm);
+ src_data = orig_map + cserve2_shm_map_offset_get(original->shm);
dst_data = scale_map + cserve2_shm_map_offset_get(scale_shm);
DBG("Scaling image ([%d,%d:%dx%d] --> [%d,%d:%dx%d])",
@@ -528,7 +528,7 @@ _scaling_do(Shm_Handle *scale_shm, Image_Data *entry)
entry->opts.scale_load.dst_w,
entry->opts.scale_load.dst_h,
entry->file->alpha,
entry->opts.scale_load.smooth);
- cserve2_shm_unmap(entry->shm);
+ cserve2_shm_unmap(original->shm);
cserve2_shm_unmap(scale_shm);
return 0;
@@ -546,7 +546,7 @@ _scaling_prepare_and_do(Image_Data *orig)
DBG("Scale image's shm path %s", cserve2_shm_name_get(scale_shm));
- if (_scaling_do(scale_shm, orig)) return -1;
+ if (_scaling_do(scale_shm, orig, orig)) return -1;
cserve2_shm_unref(orig->shm); /* unreference old shm */
orig->shm = scale_shm; /* update shm */
@@ -590,26 +590,33 @@ static Slave_Request_Funcs _load_funcs = {
};
static unsigned int
-_img_opts_id_get(Image_Data *im, char *buf, int size)
+_img_opts_id_get(unsigned int file_id, Evas_Image_Load_Opts *opts,
+ char *buf, int size)
{
uintptr_t image_id;
snprintf(buf, size,
"%u:%0.3f:%dx%d:%d:%d,%d+%dx%d:!([%d,%d:%dx%d]-[%dx%d:%d]):%d:%d",
- im->file_id, im->opts.dpi, im->opts.w, im->opts.h,
- im->opts.scale_down_by, im->opts.region.x, im->opts.region.y,
- im->opts.region.w, im->opts.region.h,
- im->opts.scale_load.src_x, im->opts.scale_load.src_y,
- im->opts.scale_load.src_w, im->opts.scale_load.src_h,
- im->opts.scale_load.dst_w, im->opts.scale_load.dst_h,
- im->opts.scale_load.smooth, im->opts.degree,
- im->opts.orientation);
+ file_id, opts->dpi, opts->w, opts->h,
+ opts->scale_down_by, opts->region.x, opts->region.y,
+ opts->region.w, opts->region.h,
+ opts->scale_load.src_x, opts->scale_load.src_y,
+ opts->scale_load.src_w, opts->scale_load.src_h,
+ opts->scale_load.dst_w, opts->scale_load.dst_h,
+ opts->scale_load.smooth, opts->degree,
+ opts->orientation);
image_id = (uintptr_t)eina_hash_find(image_ids, buf);
return image_id;
}
+static unsigned int
+_image_data_opts_id_get(Image_Data *im, char *buf, int size)
+{
+ return _img_opts_id_get(im->file_id, &im->opts, buf, size);
+}
+
static int
_image_entry_size_get(Image_Data *e)
{
@@ -638,7 +645,7 @@ _image_id_free(Image_Data *entry)
DBG("Removing entry image id: %d", entry->base.id);
- _img_opts_id_get(entry, buf, sizeof(buf));
+ _image_data_opts_id_get(entry, buf, sizeof(buf));
eina_hash_del_by_key(image_ids, buf);
}
@@ -913,10 +920,23 @@ _entry_unused_push(Image_Data *e)
eina_hash_del_by_key(image_entries, &e->base.id);
return;
}
- while (size > (max_unused_mem_usage - unused_mem_usage))
+ while (image_entries_lru &&
+ (size > (max_unused_mem_usage - unused_mem_usage)))
{
Entry *ie = eina_list_data_get(eina_list_last(image_entries_lru));
- eina_hash_del_by_key(image_entries, &ie->id);
+ Eina_Bool ok = eina_hash_del_by_key(image_entries, &ie->id);
+ if (!ok)
+ {
+ DBG("Image %d was not found in the hash table!", ie->id);
+ image_entries_lru = eina_list_remove(image_entries_lru, ie);
+ _image_entry_free((Image_Data*) ie);
+ }
+ }
+ if (!image_entries_lru && (unused_mem_usage != 0))
+ {
+ DBG("Invalid accounting of LRU size (was empty but size: %d)",
+ unused_mem_usage);
+ unused_mem_usage = 0;
}
image_entries_lru = eina_list_append(image_entries_lru, e);
e->unused = EINA_TRUE;
@@ -2084,10 +2104,151 @@ cserve2_cache_file_close(Client *client, unsigned int
client_file_id)
eina_hash_del_by_key(client->files.referencing, &client_file_id);
}
+static int
+_cserve2_cache_fast_scaling_check(Client *client, Image_Data *entry)
+{
+ Eina_Iterator *iter;
+ Image_Data *i;
+ Image_Data *original = NULL;
+ Evas_Image_Load_Opts unscaled;
+ char buf[4096];
+ unsigned int image_id;
+ int scaled_count = 0;
+ int dst_w, dst_h;
+ Eina_Bool first_attempt = EINA_TRUE;
+
+ if (!entry) return -1;
+ if (!entry->file) return -1;
+
+ dst_w = entry->opts.scale_load.dst_w;
+ dst_h = entry->opts.scale_load.dst_h;
+
+ // Copy opts w/o scaling
+ memset(&unscaled, 0, sizeof(unscaled));
+ unscaled.dpi = entry->opts.dpi;
+ //unscaled.w = entry->opts.w;
+ //unscaled.h = entry->opts.h;
+ //unscaled.scale_down_by = entry->opts.scale_down_by;
+ //unscaled.region.x = entry->opts.region.x;
+ //unscaled.region.y = entry->opts.region.y;
+ //unscaled.region.w = entry->opts.region.w;
+ //unscaled.region.h = entry->opts.region.h;
+ unscaled.scale_load.scale_hint = 0;
+ unscaled.degree = entry->opts.degree;
+ unscaled.orientation = entry->opts.orientation;
+ unscaled.scale_load.smooth = entry->opts.scale_load.smooth;
+
+try_again:
+ image_id = _img_opts_id_get(entry->file_id, &unscaled, buf, sizeof(buf));
+ if (image_id)
+ {
+ original = eina_hash_find(image_entries, &image_id);
+ if (!original) return -1; // Should not happen
+ DBG("Found original image in hash: %d,%d:%dx%d -> %dx%d shm %p",
+ original->opts.scale_load.src_x,
original->opts.scale_load.src_y,
+ original->opts.scale_load.src_w,
original->opts.scale_load.src_h,
+ original->opts.scale_load.dst_w,
original->opts.scale_load.dst_h,
+ original->shm);
+ goto do_scaling;
+ }
+
+ if (first_attempt)
+ {
+ first_attempt = EINA_FALSE;
+ memset(&unscaled, 0, sizeof(unscaled));
+ goto try_again;
+ }
+
+ iter = eina_list_iterator_new(entry->file->images);
+ EINA_ITERATOR_FOREACH(iter, i)
+ {
+ if (i == entry) continue;
+ if (i->opts.w && i->opts.h &&
+ (!i->opts.scale_load.dst_w && !i->opts.scale_load.dst_h))
+ {
+ DBG("Found image in list: %d,%d:%dx%d -> %dx%d shm %p",
+ i->opts.scale_load.src_x, i->opts.scale_load.src_y,
+ i->opts.scale_load.src_w, i->opts.scale_load.src_h,
+ i->opts.scale_load.dst_w, i->opts.scale_load.dst_h,
+ i->shm);
+ if (i->base.request || !i->shm) continue; // Not loaded yet
+ original = i;
+ break;
+ }
+ scaled_count++;
+ }
+ eina_iterator_free(iter);
+
+ if (!original)
+ {
+ DBG("Found %d scaled images for %s:%s but none matches",
+ scaled_count, entry->file->path, entry->file->key);
+
+ if (scaled_count >= 4)
+ {
+ DBG("Forcing load of original image now!");
+
+ File_Data *fentry;
+
+ original = _image_entry_new(client, 0, entry->file_id,
+ 0, &unscaled);
+ if (!original) return -1;
+
+ image_id = _image_id++;
+ while ((image_id == 0) || (eina_hash_find(image_entries,
&image_id)))
+ image_id = _image_id++;
+ DBG("Creating new image_id: %d", image_id);
+
+ original->base.id = image_id;
+ eina_hash_add(image_entries, &image_id, original);
+ eina_hash_add(image_ids, buf, (void *)(intptr_t)image_id);
+ _entry_unused_push(original);
+
+ fentry = original->file;
+ fentry->images = eina_list_append(fentry->images, original);
+ }
+ else
+ return -1;
+ }
+
+do_scaling:
+ if (!original) return -1;
+ if (!original->shm && !original->base.request)
+ {
+ if (original->base.id != image_id) abort();
+ original->base.request = cserve2_request_add(
+ CSERVE2_REQ_IMAGE_LOAD,
+ 0, NULL, 0, &_load_funcs, original);
+ }
+ if (original->base.request || !original->shm)
+ return -1; // Not loaded yet
+
+ if (entry->shm)
+ cserve2_shm_unref(entry->shm);
+
+ entry->shm = cserve2_shm_request(dst_w * dst_h * 4);
+ if (!entry->shm) return -1;
+
+ if (_scaling_do(entry->shm, entry, original) != 0)
+ {
+ cserve2_shm_unref(entry->shm);
+ entry->shm = NULL;
+ return -1;
+ }
+
+ if (original->unused)
+ {
+ image_entries_lru = eina_list_remove(image_entries_lru, original);
+ image_entries_lru = eina_list_prepend(image_entries_lru, original);
+ }
+ return 0;
+}
+
int
-cserve2_cache_image_opts_set(Client *client, int rid,
- unsigned int file_id, unsigned int
client_image_id,
- Evas_Image_Load_Opts *opts)
+cserve2_cache_image_entry_create(Client *client, int rid,
+ unsigned int file_id,
+ unsigned int client_image_id,
+ Evas_Image_Load_Opts *opts)
{
Image_Data *entry;
File_Data *fentry = NULL;
@@ -2101,7 +2262,7 @@ cserve2_cache_image_opts_set(Client *client, int rid,
entry = _image_entry_new(client, rid, file_id, client_image_id, opts);
if (!entry)
return -1;
- image_id = _img_opts_id_get(entry, buf, sizeof(buf));
+ image_id = _image_data_opts_id_get(entry, buf, sizeof(buf));
if (image_id)
{ // if so, just update the references
free(entry);
@@ -2135,7 +2296,6 @@ cserve2_cache_image_opts_set(Client *client, int rid,
eina_hash_del_by_key(client->images.referencing, &client_image_id);
eina_hash_add(client->images.referencing, &client_image_id, ref);
-
return 0;
}
@@ -2155,6 +2315,12 @@ cserve2_cache_image_opts_set(Client *client, int rid,
fentry = entry->file;
fentry->images = eina_list_append(fentry->images, entry);
+ if (opts && opts->scale_load.dst_w && opts->scale_load.dst_h)
+ {
+ if (!_cserve2_cache_fast_scaling_check(client, entry))
+ return 0;
+ }
+
entry->base.request = cserve2_request_add(CSERVE2_REQ_IMAGE_SPEC_LOAD,
0, NULL, fentry->base.request,
&_load_funcs, entry);
diff --git a/src/bin/evas/evas_cserve2_main.c b/src/bin/evas/evas_cserve2_main.c
index 1162edb..5f5852f 100644
--- a/src/bin/evas/evas_cserve2_main.c
+++ b/src/bin/evas/evas_cserve2_main.c
@@ -94,8 +94,8 @@ _cserve2_client_open(Client *client)
cserve2_cache_file_open(client, msg->file_id, path, key, msg->base.rid);
if (!msg->has_load_opts)
- cserve2_cache_image_opts_set(client, msg->base.rid,
- msg->file_id, msg->image_id, NULL);
+ cserve2_cache_image_entry_create(client, msg->base.rid,
+ msg->file_id, msg->image_id, NULL);
else
{
// FIXME: Check message size first?
@@ -119,8 +119,9 @@ _cserve2_client_open(Client *client)
DBG("\tdegree: %d", opts->degree);
DBG("\torientation: %d", opts->orientation);
- cserve2_cache_image_opts_set(client, msg->base.rid,
- msg->file_id, msg->image_id, opts);
+ cserve2_cache_image_entry_create(client, msg->base.rid,
+ msg->file_id, msg->image_id,
+ opts);
}
}
--
------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:
Build for Windows Store.
http://p.sf.net/sfu/windows-dev2dev