[gnome-shell] Compress multiple load requests
- From: Colin Walters <walters src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] Compress multiple load requests
- Date: Fri, 25 Sep 2009 17:41:59 +0000 (UTC)
commit ec92bfba14d9900dfb43d73b5973a0d5c3e9ff54
Author: Colin Walters <walters verbum org>
Date: Wed Sep 23 18:07:19 2009 -0400
Compress multiple load requests
Before, if the texture cache received a request to load say
the themed icon for an application multiple times (as could happen
since we have multiple application displays), it would often create
a thread for each one and in fact, load the pixbuf multiple times.
Avoid this by keeping track of outstanding requests.
https://bugzilla.gnome.org/show_bug.cgi?id=596121
src/shell-texture-cache.c | 170 +++++++++++++++++++++++++++++++-------------
1 files changed, 120 insertions(+), 50 deletions(-)
---
diff --git a/src/shell-texture-cache.c b/src/shell-texture-cache.c
index 8ad8c14..bb51f29 100644
--- a/src/shell-texture-cache.c
+++ b/src/shell-texture-cache.c
@@ -20,7 +20,13 @@ typedef struct
struct _ShellTextureCachePrivate
{
+ /* Things that were loaded with a cache policy != NONE */
GHashTable *keyed_cache; /* CacheKey -> CoglTexture* */
+ /* Presently this is used to de-duplicate requests for GIcons,
+ * it could in theory be extended to async URL loading and other
+ * cases too.
+ */
+ GHashTable *outstanding_requests; /* CacheKey -> AsyncTextureLoadData * */
GnomeDesktopThumbnailFactory *thumbnails;
};
@@ -130,6 +136,8 @@ shell_texture_cache_init (ShellTextureCache *self)
self->priv = g_new0 (ShellTextureCachePrivate, 1);
self->priv->keyed_cache = g_hash_table_new_full (cache_key_hash, cache_key_equal,
cache_key_destroy, cogl_handle_unref);
+ self->priv->outstanding_requests = g_hash_table_new_full (cache_key_hash, cache_key_equal,
+ cache_key_destroy, NULL);
self->priv->thumbnails = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL);
}
@@ -647,7 +655,7 @@ typedef struct {
GtkIconInfo *icon_info;
guint width;
guint height;
- ClutterTexture *texture;
+ GSList *textures;
} AsyncTextureLoadData;
static CoglHandle
@@ -706,15 +714,31 @@ on_pixbuf_loaded (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
+ GSList *iter;
ShellTextureCache *cache;
AsyncTextureLoadData *data;
GdkPixbuf *pixbuf;
GError *error = NULL;
CoglHandle texdata = NULL;
- CacheKey *key;
+ CacheKey key;
data = user_data;
cache = SHELL_TEXTURE_CACHE (source);
+
+ memset (&key, 0, sizeof(key));
+ key.policy = data->policy;
+ if (data->icon)
+ key.icon = data->icon;
+ else if (data->recent_info && data->thumbnail)
+ key.thumbnail_uri = (char*)gtk_recent_info_get_uri (data->recent_info);
+ else if (data->thumbnail)
+ key.thumbnail_uri = (char*)data->uri;
+ else if (data->uri)
+ key.uri = data->uri;
+ key.size = data->width;
+
+ g_hash_table_remove (cache->priv->outstanding_requests, &key);
+
pixbuf = load_pixbuf_async_finish (cache, result, &error);
if (pixbuf == NULL)
pixbuf = load_pixbuf_fallback(data);
@@ -729,30 +753,20 @@ on_pixbuf_loaded (GObject *source,
{
gpointer orig_key, value;
- key = g_new0 (CacheKey, 1);
- key->policy = data->policy;
- if (data->icon)
- key->icon = g_object_ref (data->icon);
- else if (data->recent_info && data->thumbnail)
- key->thumbnail_uri = g_strdup (gtk_recent_info_get_uri (data->recent_info));
- else if (data->thumbnail)
- key->thumbnail_uri = g_strdup (data->uri);
- else if (data->uri)
- key->uri = g_strdup (data->uri);
- key->size = data->width;
-
- if (!g_hash_table_lookup_extended (cache->priv->keyed_cache, key,
+ if (!g_hash_table_lookup_extended (cache->priv->keyed_cache, &key,
&orig_key, &value))
{
cogl_handle_ref (texdata);
- g_hash_table_insert (cache->priv->keyed_cache, key,
+ g_hash_table_insert (cache->priv->keyed_cache, cache_key_dup (&key),
texdata);
}
- else
- cache_key_destroy (key);
}
- set_texture_cogl_texture (data->texture, texdata);
+ for (iter = data->textures; iter; iter = iter->next)
+ {
+ ClutterTexture *texture = iter->data;
+ set_texture_cogl_texture (texture, texdata);
+ }
out:
if (texdata)
@@ -772,7 +786,11 @@ out:
/* Alternatively we could weakref and just do nothing if the texture
is destroyed */
- g_object_unref (data->texture);
+ for (iter = data->textures; iter; iter = iter->next)
+ {
+ ClutterTexture *texture = iter->data;
+ g_object_unref (texture);
+ }
g_clear_error (&error);
g_free (data);
@@ -881,6 +899,59 @@ shell_texture_cache_bind_pixbuf_property (ShellTextureCache *cache,
}
/**
+ * create_texture_and_ensure_request:
+ * @cache:
+ * @key: A filled in #CacheKey
+ * @request: (out): If no request is outstanding, one will be created and returned here
+ * @texture: (out): A new texture, also added to the request
+ *
+ * Check for any outstanding load for the data represented by @key. If there
+ * is already a request pending, append it to that request to avoid loading
+ * the data multiple times.
+ *
+ * Returns: %TRUE iff there is already a request pending
+ */
+static gboolean
+create_texture_and_ensure_request (ShellTextureCache *cache,
+ CacheKey *key,
+ AsyncTextureLoadData **request,
+ ClutterActor **texture)
+{
+ CoglHandle texdata;
+ AsyncTextureLoadData *pending;
+ gboolean had_pending;
+
+ *texture = (ClutterActor *) create_default_texture (cache);
+ clutter_actor_set_size (*texture, key->size, key->size);
+
+ texdata = g_hash_table_lookup (cache->priv->keyed_cache, key);
+
+ if (texdata != NULL)
+ {
+ /* We had this cached already, just set the texture and we're done. */
+ set_texture_cogl_texture (CLUTTER_TEXTURE (*texture), texdata);
+ return TRUE;
+ }
+
+ pending = g_hash_table_lookup (cache->priv->outstanding_requests, key);
+ had_pending = pending != NULL;
+
+ if (pending == NULL)
+ {
+ /* Not cached and no pending request, create it */
+ *request = g_new0 (AsyncTextureLoadData, 1);
+ g_hash_table_insert (cache->priv->outstanding_requests, cache_key_dup (key), *request);
+ }
+ else
+ *request = pending;
+
+ /* Regardless of whether there was a pending request, prepend our texture here. */
+ (*request)->textures = g_slist_prepend ((*request)->textures, g_object_ref (*texture));
+
+ return had_pending;
+}
+
+/**
* shell_texture_cache_load_gicon:
*
* This method returns a new #ClutterClone for a given #GIcon. If the
@@ -893,44 +964,43 @@ shell_texture_cache_load_gicon (ShellTextureCache *cache,
GIcon *icon,
gint size)
{
- ClutterTexture *texture;
- CoglHandle texdata;
+ AsyncTextureLoadData *request;
+ ClutterActor *texture;
CacheKey key;
-
- texture = create_default_texture (cache);
- clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
+ GtkIconTheme *theme;
+ GtkIconInfo *info;
memset (&key, 0, sizeof(key));
key.icon = icon;
key.size = size;
- texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
- if (texdata == NULL)
- {
- GtkIconTheme *theme;
- GtkIconInfo *info;
+ if (create_texture_and_ensure_request (cache, &key, &request, &texture))
+ return texture;
- /* Do theme lookups in the main thread to avoid thread-unsafety */
- theme = gtk_icon_theme_get_default ();
+ /* Do theme lookups in the main thread to avoid thread-unsafety */
+ theme = gtk_icon_theme_get_default ();
- info = gtk_icon_theme_lookup_by_gicon (theme, icon, size, GTK_ICON_LOOKUP_USE_BUILTIN);
- if (info != NULL)
- {
- AsyncTextureLoadData *data;
- data = g_new0 (AsyncTextureLoadData, 1);
- /* hardcoded here for now; we should actually blow this away on
- * icon theme changes probably */
- data->policy = SHELL_TEXTURE_CACHE_POLICY_FOREVER;
- data->icon = g_object_ref (icon);
- data->icon_info = info;
- data->texture = g_object_ref (texture);
- data->width = data->height = size;
- load_icon_pixbuf_async (cache, icon, info, size, NULL, on_pixbuf_loaded, data);
- }
+ info = gtk_icon_theme_lookup_by_gicon (theme, icon, size, GTK_ICON_LOOKUP_USE_BUILTIN);
+ if (info != NULL)
+ {
+ /* hardcoded here for now; we should actually blow this away on
+ * icon theme changes probably */
+ request->policy = SHELL_TEXTURE_CACHE_POLICY_FOREVER;
+ request->icon = g_object_ref (icon);
+ request->icon_info = info;
+ request->width = request->height = size;
+
+ load_icon_pixbuf_async (cache, icon, info, size, NULL, on_pixbuf_loaded, request);
}
else
{
- set_texture_cogl_texture (texture, texdata);
+ /* Blah; we failed to find the icon, but we've added our texture to the outstanding
+ * requests. In that case, just undo what create_texture_lookup_status did.
+ */
+ g_slist_foreach (request->textures, (GFunc) g_object_unref, NULL);
+ g_slist_free (request->textures);
+ g_free (request);
+ g_hash_table_remove (cache->priv->outstanding_requests, &key);
}
return CLUTTER_ACTOR (texture);
@@ -991,7 +1061,7 @@ shell_texture_cache_load_uri_async (ShellTextureCache *cache,
data->uri = g_strdup (uri);
data->width = available_width;
data->height = available_height;
- data->texture = g_object_ref (texture);
+ data->textures = g_slist_prepend (data->textures, g_object_ref (texture));
load_uri_pixbuf_async (cache, uri, available_width, available_height, NULL, on_pixbuf_loaded, data);
return CLUTTER_ACTOR (texture);
@@ -1114,7 +1184,7 @@ shell_texture_cache_load_thumbnail (ShellTextureCache *cache,
data->thumbnail = TRUE;
data->width = size;
data->height = size;
- data->texture = g_object_ref (texture);
+ data->textures = g_slist_prepend (data->textures, g_object_ref (texture));
load_thumbnail_async (cache, uri, mimetype, size, NULL, on_pixbuf_loaded, data);
}
else
@@ -1190,7 +1260,7 @@ shell_texture_cache_load_recent_thumbnail (ShellTextureCache *cache,
data->recent_info = gtk_recent_info_ref (info);
data->width = size;
data->height = size;
- data->texture = g_object_ref (texture);
+ data->textures = g_slist_prepend (data->textures, g_object_ref (texture));
load_recent_thumbnail_async (cache, info, size, NULL, on_pixbuf_loaded, data);
}
else
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]