[gtk+/wip/ebassi/gsk-renderer] gsk: Add GskResourceCache
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/ebassi/gsk-renderer] gsk: Add GskResourceCache
- Date: Thu, 1 Sep 2016 16:11:24 +0000 (UTC)
commit f273107acf21fe3232121151ec0b5be6cfb7b785
Author: Emmanuele Bassi <ebassi gnome org>
Date: Wed Aug 31 11:47:43 2016 +0100
gsk: Add GskResourceCache
GskResourceCache is a base class for caching graphical resources, like
surfaces, images, and glyphs.
gsk/Makefile.am | 3 +
gsk/gsk.h | 1 +
gsk/gskresourcecache.c | 427 +++++++++++++++++++++++++++++++++++++++++
gsk/gskresourcecache.h | 73 +++++++
gsk/gskresourcecacheprivate.h | 26 +++
5 files changed, 530 insertions(+), 0 deletions(-)
---
diff --git a/gsk/Makefile.am b/gsk/Makefile.am
index 7fdfb3b..1ffd41a 100644
--- a/gsk/Makefile.am
+++ b/gsk/Makefile.am
@@ -32,6 +32,7 @@ gsk_public_source_h = \
gskrenderer.h \
gskrendernode.h \
gskrendernodeiter.h \
+ gskresourcecache.h \
gsktypes.h
gsk_private_source_h = \
gskcairorendererprivate.h \
@@ -43,6 +44,7 @@ gsk_private_source_h = \
gskprofilerprivate.h \
gskrendererprivate.h \
gskrendernodeprivate.h \
+ gskresourcecacheprivate.h \
gskshaderbuilderprivate.h
gsk_private_source_c = \
gskprivate.c
@@ -62,6 +64,7 @@ gsk_source_c = \
gskrenderer.c \
gskrendernode.c \
gskrendernodeiter.c \
+ gskresourcecache.c \
gskshaderbuilder.c
all_sources = \
diff --git a/gsk/gsk.h b/gsk/gsk.h
index 01c4569..c068b50 100644
--- a/gsk/gsk.h
+++ b/gsk/gsk.h
@@ -24,6 +24,7 @@
#include <gsk/gskrenderer.h>
#include <gsk/gskrendernode.h>
#include <gsk/gskrendernodeiter.h>
+#include <gsk/gskresourcecache.h>
#include <gsk/gsktypes.h>
#include <gsk/gskenumtypes.h>
diff --git a/gsk/gskresourcecache.c b/gsk/gskresourcecache.c
new file mode 100644
index 0000000..274474b
--- /dev/null
+++ b/gsk/gskresourcecache.c
@@ -0,0 +1,427 @@
+#include "config.h"
+
+#include "gskresourcecacheprivate.h"
+
+typedef struct {
+ GHashTable *resources;
+
+ GHashFunc key_hash;
+ GEqualFunc key_equal;
+ GDestroyNotify key_notify;
+
+ GType value_type;
+
+ /* Interned, do not free */
+ const char *name;
+} GskResourceCachePrivate;
+
+typedef struct {
+ GType value_type;
+ gpointer value;
+ gint64 last_access_time;
+ gint64 age;
+} ResourceCacheItem;
+
+enum {
+ PROP_NAME = 1,
+
+ N_PROPERTIES
+};
+
+static GParamSpec *gsk_resource_cache_properties[N_PROPERTIES];
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GskResourceCache, gsk_resource_cache, G_TYPE_OBJECT)
+
+static void
+gsk_resource_cache_dispose (GObject *gobject)
+{
+ GskResourceCache *self = GSK_RESOURCE_CACHE (gobject);
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (self);
+
+ g_clear_pointer (&priv->resources, g_hash_table_unref);
+
+ G_OBJECT_CLASS (gsk_resource_cache_parent_class)->dispose (gobject);
+}
+
+static void
+gsk_resource_cache_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GskResourceCache *self = GSK_RESOURCE_CACHE (gobject);
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ if (g_value_get_string (value) != NULL)
+ priv->name = g_intern_static_string (g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ }
+}
+
+static void
+gsk_resource_cache_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GskResourceCache *self = GSK_RESOURCE_CACHE (gobject);
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ }
+}
+
+static void
+gsk_resource_cache_class_init (GskResourceCacheClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->set_property = gsk_resource_cache_set_property;
+ gobject_class->get_property = gsk_resource_cache_get_property;
+ gobject_class->dispose = gsk_resource_cache_dispose;
+
+ gsk_resource_cache_properties[PROP_NAME] =
+ g_param_spec_string ("name", "Name", "The (short) name of the resource cache",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+}
+
+static void
+gsk_resource_cache_init (GskResourceCache *self)
+{
+}
+
+/**
+ * gsk_resource_cache_set_hash_func:
+ * @cache: a #GskResourceCache
+ * @key_hash: a hashing function for the key
+ *
+ * Sets the hashing function for the keys inside the resource @cache.
+ *
+ * Since: 3.22
+ */
+void
+gsk_resource_cache_set_hash_func (GskResourceCache *cache,
+ GHashFunc key_hash)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+
+ g_return_if_fail (GSK_IS_RESOURCE_CACHE (cache));
+ g_return_if_fail (priv->resources == NULL);
+
+ priv->key_hash = key_hash;
+}
+
+/**
+ * gsk_resource_cache_set_equal_func:
+ * @cache: a #GskResourceCache
+ * @key_equal: a function for checking two keys for equality
+ *
+ * Sets the comparison function for two keys in the resource @cache.
+ *
+ * Since: 3.22
+ */
+void
+gsk_resource_cache_set_equal_func (GskResourceCache *cache,
+ GEqualFunc key_equal)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+
+ g_return_if_fail (GSK_IS_RESOURCE_CACHE (cache));
+ g_return_if_fail (priv->resources == NULL);
+
+ priv->key_equal = key_equal;
+}
+
+/**
+ * gsk_resource_cache_set_free_func:
+ * @cache: a #GskResourceCache
+ * @key_notify: a function to be called when removing a key
+ *
+ * Sets the function to be called when removing a key from the resource @cache.
+ *
+ * Since: 3.22
+ */
+void
+gsk_resource_cache_set_free_func (GskResourceCache *cache,
+ GDestroyNotify key_notify)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+
+ g_return_if_fail (GSK_IS_RESOURCE_CACHE (cache));
+ g_return_if_fail (priv->resources == NULL);
+
+ priv->key_notify = key_notify;
+}
+
+/**
+ * gsk_resource_cache_set_value_type:
+ * @cache: a #GskResourceCache
+ * @value_type: the type of the data to be stored inside the cache
+ *
+ * Sets the #GType of the values inside the resource @cache.
+ *
+ * Only pointer-sized types can be stored inside the cache, i.e. the only
+ * admissible types for @value_type are:
+ *
+ * - %G_TYPE_POINTER (no memory management)
+ * - %G_TYPE_BOXED (the cache will copy the data)
+ * - %G_TYPE_OBJECT (the cache will acquire a reference to the data)
+ *
+ * Since: 3.22
+ */
+void
+gsk_resource_cache_set_value_type (GskResourceCache *cache,
+ GType value_type)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+
+ g_return_if_fail (GSK_IS_RESOURCE_CACHE (cache));
+ g_return_if_fail (priv->resources == NULL);
+ g_return_if_fail (value_type != G_TYPE_INVALID);
+
+ if (G_TYPE_FUNDAMENTAL (value_type) != G_TYPE_POINTER ||
+ G_TYPE_FUNDAMENTAL (value_type) != G_TYPE_BOXED ||
+ G_TYPE_FUNDAMENTAL (value_type) != G_TYPE_OBJECT)
+ {
+ g_critical ("Unsupported resource type '%s'", g_type_name (value_type));
+ return;
+ }
+
+ priv->value_type = value_type;
+}
+
+/**
+ * gsk_resource_cache_set_name:
+ * @cache: a #GskResourceCache
+ * @name: a name for the @cache
+ *
+ * Sets a name for the resource @cache, for debugging purposes.
+ *
+ * Since: 3.22
+ */
+void
+gsk_resource_cache_set_name (GskResourceCache *cache,
+ const char *name)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+
+ g_return_if_fail (GSK_IS_RESOURCE_CACHE (cache));
+
+ priv->name = g_intern_string (name);
+}
+
+static ResourceCacheItem *
+resource_cache_item_new (GType value_type,
+ gpointer value)
+{
+ ResourceCacheItem *item;
+
+ if (value_type == G_TYPE_INVALID)
+ {
+ g_critical ("Invalid resource type; did you forget to call "
+ "gsk_resource_cache_set_value_type()?");
+ return NULL;
+ }
+
+ item = g_slice_new0 (ResourceCacheItem);
+ item->value_type = value_type;
+
+ switch (G_TYPE_FUNDAMENTAL (item->value_type))
+ {
+ case G_TYPE_POINTER:
+ item->value = value;
+ break;
+
+ case G_TYPE_BOXED:
+ if (value != NULL)
+ item->value = g_boxed_copy (item->value_type, value);
+ break;
+
+ case G_TYPE_OBJECT:
+ if (value != NULL)
+ item->value = g_object_ref (value);
+ break;
+
+ default:
+ g_critical ("Unsupported resource type '%s'", g_type_name (value_type));
+ g_slice_free (ResourceCacheItem, item);
+ return NULL;
+ }
+
+ item->age = 1;
+
+ return item;
+}
+
+static gpointer
+resource_cache_item_get_value (ResourceCacheItem *item)
+{
+ item->last_access_time = g_get_monotonic_time ();
+
+ return item->value;
+}
+
+static void
+resource_cache_item_free (gpointer data)
+{
+ ResourceCacheItem *item = data;
+
+ if (data == NULL)
+ return;
+
+ switch (G_TYPE_FUNDAMENTAL (item->value_type))
+ {
+ case G_TYPE_POINTER:
+ break;
+
+ case G_TYPE_BOXED:
+ if (item->value != NULL)
+ g_boxed_free (item->value_type, item->value);
+ break;
+
+ case G_TYPE_OBJECT:
+ if (item->value != NULL)
+ g_object_unref (item->value);
+ break;
+
+ default:
+ g_critical ("Unsupported resource type '%s'", g_type_name (item->value_type));
+ }
+
+ g_slice_free (ResourceCacheItem, item);
+}
+
+void
+gsk_resource_cache_add_item (GskResourceCache *cache,
+ gpointer key,
+ gpointer value)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+ ResourceCacheItem *item;
+
+ g_return_if_fail (GSK_IS_RESOURCE_CACHE (cache));
+
+ if (priv->resources == NULL)
+ {
+ priv->resources = g_hash_table_new_full (priv->key_hash, priv->key_equal,
+ priv->key_notify,
+ resource_cache_item_free);
+ }
+
+ item = g_hash_table_lookup (priv->resources, key);
+ if (item != NULL)
+ {
+ item->age += 1;
+ return;
+ }
+
+ item = resource_cache_item_new (priv->value_type, value);
+ if (item != NULL)
+ g_hash_table_insert (priv->resources, key, item);
+}
+
+gboolean
+gsk_resource_cache_has_item (GskResourceCache *cache,
+ gpointer key)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+
+ g_return_val_if_fail (GSK_IS_RESOURCE_CACHE (cache), FALSE);
+
+ if (priv->resources == NULL)
+ return FALSE;
+
+ return g_hash_table_lookup (priv->resources, key) != NULL;
+}
+
+gpointer
+gsk_resource_cache_get_item (GskResourceCache *cache,
+ gpointer key)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+ ResourceCacheItem *item;
+
+ g_return_val_if_fail (GSK_IS_RESOURCE_CACHE (cache), FALSE);
+
+ if (priv->resources == NULL)
+ return NULL;
+
+ item = g_hash_table_lookup (priv->resources, key);
+ if (item == NULL)
+ return NULL;
+
+ return resource_cache_item_get_value (item);
+}
+
+gboolean
+gsk_resource_cache_invalidate_item (GskResourceCache *cache,
+ gpointer key)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+ ResourceCacheItem *item;
+
+ g_return_val_if_fail (GSK_IS_RESOURCE_CACHE (cache), FALSE);
+
+ if (priv->resources == NULL)
+ return FALSE;
+
+ item = g_hash_table_lookup (priv->resources, key);
+ if (item == NULL)
+ return FALSE;
+
+ item->age -= 1;
+ if (item->age < 0)
+ {
+ g_critical ("Too many invalidations for item of type '%s'", g_type_name (priv->value_type));
+ item->age = 0;
+ }
+
+ return TRUE;
+}
+
+int
+gsk_resource_cache_collect_items (GskResourceCache *cache)
+{
+ GskResourceCachePrivate *priv = gsk_resource_cache_get_instance_private (cache);
+ GHashTableIter iter;
+ gpointer item_p;
+ int res = 0;
+
+ g_return_val_if_fail (GSK_IS_RESOURCE_CACHE (cache), 0);
+
+ if (priv->resources == NULL)
+ return 0;
+
+ g_hash_table_iter_init (&iter, priv->resources);
+ while (g_hash_table_iter_next (&iter, NULL, &item_p))
+ {
+ ResourceCacheItem *item = item_p;
+
+ if (item->age == 0)
+ {
+ g_hash_table_iter_remove (&iter);
+ res += 1;
+ continue;
+ }
+
+ item->age -= 1;
+ }
+
+ return res;
+}
diff --git a/gsk/gskresourcecache.h b/gsk/gskresourcecache.h
new file mode 100644
index 0000000..fbdb780
--- /dev/null
+++ b/gsk/gskresourcecache.h
@@ -0,0 +1,73 @@
+/* GSK - The GTK Scene Kit
+ *
+ * Copyright 2016 Endless
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GSK_RESOURCE_CACHE_H__
+#define __GSK_RESOURCE_CACHE_H__
+
+#if !defined (__GSK_H_INSIDE__) && !defined (GSK_COMPILATION)
+#error "Only <gsk/gsk.h> can be included directly."
+#endif
+
+#include <gsk/gsktypes.h>
+
+G_BEGIN_DECLS
+
+#define GSK_TYPE_RESOURCE_CACHE (gsk_resource_cache_get_type())
+
+#define GSK_RESOURCE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_RESOURCE_CACHE,
GskResourceCache))
+#define GSK_IS_RESOURCE_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_RESOURCE_CACHE))
+
+typedef struct _GskResourceCache GskResourceCache;
+typedef struct _GskResourceCacheClass GskResourceCacheClass;
+
+GDK_AVAILABLE_IN_3_22
+GType gsk_resource_cache_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_22
+void gsk_resource_cache_set_hash_func (GskResourceCache *cache,
+ GHashFunc key_hash);
+GDK_AVAILABLE_IN_3_22
+void gsk_resource_cache_set_equal_func (GskResourceCache *cache,
+ GEqualFunc key_equal);
+GDK_AVAILABLE_IN_3_22
+void gsk_resource_cache_set_free_func (GskResourceCache *cache,
+ GDestroyNotify key_notify);
+GDK_AVAILABLE_IN_3_22
+void gsk_resource_cache_set_value_type (GskResourceCache *cache,
+ GType value_type);
+GDK_AVAILABLE_IN_3_22
+void gsk_resource_cache_set_name (GskResourceCache *cache,
+ const char *name);
+
+GDK_AVAILABLE_IN_3_22
+void gsk_resource_cache_add_item (GskResourceCache *cache,
+ gpointer key,
+ gpointer value);
+GDK_AVAILABLE_IN_3_22
+gboolean gsk_resource_cache_has_item (GskResourceCache *cache,
+ gpointer key);
+GDK_AVAILABLE_IN_3_22
+gpointer gsk_resource_cache_get_item (GskResourceCache *cache,
+ gpointer key);
+GDK_AVAILABLE_IN_3_22
+gboolean gsk_resource_cache_invalidate_item (GskResourceCache *cache,
+ gpointer key);
+
+G_END_DECLS
+
+#endif /* __GSK_RESOURCE_CACHE_H__ */
diff --git a/gsk/gskresourcecacheprivate.h b/gsk/gskresourcecacheprivate.h
new file mode 100644
index 0000000..6daa909
--- /dev/null
+++ b/gsk/gskresourcecacheprivate.h
@@ -0,0 +1,26 @@
+#ifndef __GSK_RESOURCE_CACHE_PRIVATE_H__
+#define __GSK_RESOURCE_CACHE_PRIVATE_H__
+
+#include "gskresourcecache.h"
+
+G_BEGIN_DECLS
+
+#define GSK_RESOURCE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_RESOURCE_CACHE,
GskResourceCacheClass))
+#define GSK_IS_RESOURCE_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_RESOURCE_CACHE))
+#define GSK_RESOURCE_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RESOURCE_CACHE,
GskResourceCacheClass))
+
+struct _GskResourceCache
+{
+ GObject parent_instance;
+};
+
+struct _GskResourceCacheClass
+{
+ GObjectClass parent_class;
+};
+
+int gsk_resource_cache_collect_items (GskResourceCache *cache);
+
+G_END_DECLS
+
+#endif /* __GSK_RESOURCE_CACHE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]