|
Packit Service |
2781ba |
/* This file is part of GEGL.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2006,2007 Øyvind Kolås <pippin@gimp.org>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <glib.h>
|
|
Packit Service |
2781ba |
#include <glib-object.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl.h"
|
|
Packit Service |
2781ba |
#include "gegl-types-internal.h"
|
|
Packit Service |
2781ba |
#include "gegl-config.h"
|
|
Packit Service |
2781ba |
#include "gegl-buffer.h"
|
|
Packit Service |
2781ba |
#include "gegl-buffer-private.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile-handler-cache.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile-storage.h"
|
|
Packit Service |
2781ba |
#include "gegl-debug.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl-buffer-cl-cache.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/*
|
|
Packit Service |
2781ba |
#define GEGL_DEBUG_CACHE_HITS
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef struct CacheItem
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *handler; /* The specific handler that cached this item*/
|
|
Packit Service |
2781ba |
GeglTile *tile; /* The tile */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gint x; /* The coordinates this tile was cached for */
|
|
Packit Service |
2781ba |
gint y;
|
|
Packit Service |
2781ba |
gint z;
|
|
Packit Service |
2781ba |
} CacheItem;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void gegl_tile_handler_cache_dispose (GObject *object);
|
|
Packit Service |
2781ba |
static gboolean gegl_tile_handler_cache_wash (GeglTileHandlerCache *cache);
|
|
Packit Service |
2781ba |
static gpointer gegl_tile_handler_cache_command (GeglTileSource *tile_store,
|
|
Packit Service |
2781ba |
GeglTileCommand command,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z,
|
|
Packit Service |
2781ba |
gpointer data);
|
|
Packit Service |
2781ba |
static GeglTile * gegl_tile_handler_cache_get_tile (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z);
|
|
Packit Service |
2781ba |
static gboolean gegl_tile_handler_cache_has_tile (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z);
|
|
Packit Service |
2781ba |
void gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
GeglTile *tile,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z);
|
|
Packit Service |
2781ba |
static void gegl_tile_handler_cache_void (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z);
|
|
Packit Service |
2781ba |
static void gegl_tile_handler_cache_invalidate (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
|
|
Packit Service |
2781ba |
static GQueue *cache_queue = NULL;
|
|
Packit Service |
2781ba |
static GHashTable *cache_ht = NULL;
|
|
Packit Service |
2781ba |
static gint cache_wash_percentage = 20;
|
|
Packit Service |
2781ba |
static gint cache_total = 0; /* approximate amount of bytes stored */
|
|
Packit Service |
2781ba |
#ifdef GEGL_DEBUG_CACHE_HITS
|
|
Packit Service |
2781ba |
static gint cache_hits = 0;
|
|
Packit Service |
2781ba |
static gint cache_misses = 0;
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
G_DEFINE_TYPE (GeglTileHandlerCache, gegl_tile_handler_cache, GEGL_TYPE_TILE_HANDLER)
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_class_init (GeglTileHandlerCacheClass *class)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gobject_class->dispose = gegl_tile_handler_cache_dispose;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_init (GeglTileHandlerCache *cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
((GeglTileSource*)cache)->command = gegl_tile_handler_cache_command;
|
|
Packit Service |
2781ba |
gegl_tile_cache_init ();
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_reinit_buffer_tiles (gpointer itm,
|
|
Packit Service |
2781ba |
gpointer userdata)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item;
|
|
Packit Service |
2781ba |
item = itm;
|
|
Packit Service |
2781ba |
if (item->handler == userdata)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *cache = userdata;
|
|
Packit Service |
2781ba |
cache->free_list = g_slist_prepend (cache->free_list, item);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_reinit (GeglTileHandlerCache *cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item;
|
|
Packit Service |
2781ba |
GSList *iter;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (cache->tile_storage->hot_tile)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_unref (cache->tile_storage->hot_tile);
|
|
Packit Service |
2781ba |
cache->tile_storage->hot_tile = NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!cache->count)
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_static_mutex_lock (&mutex);
|
|
Packit Service |
2781ba |
/* only throw out items belonging to this cache instance */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
cache->free_list = NULL;
|
|
Packit Service |
2781ba |
g_queue_foreach (cache_queue, gegl_tile_handler_cache_reinit_buffer_tiles, cache);
|
|
Packit Service |
2781ba |
for (iter = cache->free_list; iter; iter = g_slist_next (iter))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
item = iter->data;
|
|
Packit Service |
2781ba |
if (item->tile)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
cache_total -= item->tile->size;
|
|
Packit Service |
2781ba |
gegl_tile_mark_as_stored (item->tile); /* to avoid saving */
|
|
Packit Service |
2781ba |
gegl_tile_unref (item->tile);
|
|
Packit Service |
2781ba |
cache->count--;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_queue_remove (cache_queue, item);
|
|
Packit Service |
2781ba |
g_hash_table_remove (cache_ht, item);
|
|
Packit Service |
2781ba |
g_slice_free (CacheItem, item);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_slist_free (cache->free_list);
|
|
Packit Service |
2781ba |
cache->free_list = NULL;
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_dispose_buffer_tiles (gpointer itm,
|
|
Packit Service |
2781ba |
gpointer userdata)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item;
|
|
Packit Service |
2781ba |
item = itm;
|
|
Packit Service |
2781ba |
if (item->handler == userdata)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *cache = userdata;
|
|
Packit Service |
2781ba |
cache->free_list = g_slist_prepend (cache->free_list, item);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_dispose (GObject *object)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *cache;
|
|
Packit Service |
2781ba |
CacheItem *item;
|
|
Packit Service |
2781ba |
GSList *iter;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
cache = GEGL_TILE_HANDLER_CACHE (object);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* only throw out items belonging to this cache instance */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
cache->free_list = NULL;
|
|
Packit Service |
2781ba |
/* XXX: for optimization this could be delayed,. or collected among multiple
|
|
Packit Service |
2781ba |
* buffer destructions, to avoid the overhead of walking the full queue for
|
|
Packit Service |
2781ba |
* every tiny buffer being destroyed.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (cache->count)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_static_mutex_lock (&mutex);
|
|
Packit Service |
2781ba |
g_queue_foreach (cache_queue, gegl_tile_handler_cache_dispose_buffer_tiles, cache);
|
|
Packit Service |
2781ba |
for (iter = cache->free_list; iter; iter = g_slist_next (iter))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
item = iter->data;
|
|
Packit Service |
2781ba |
if (item->tile)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
cache_total -= item->tile->size;
|
|
Packit Service |
2781ba |
gegl_tile_unref (item->tile);
|
|
Packit Service |
2781ba |
cache->count--;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_queue_remove (cache_queue, item);
|
|
Packit Service |
2781ba |
g_hash_table_remove (cache_ht, item);
|
|
Packit Service |
2781ba |
g_slice_free (CacheItem, item);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_slist_free (cache->free_list);
|
|
Packit Service |
2781ba |
cache->free_list = NULL;
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (cache->count != 0)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("cache-handler tile balance not zero: %i\n", cache->count);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
G_OBJECT_CLASS (gegl_tile_handler_cache_parent_class)->dispose (object);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglTile *
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_get_tile_command (GeglTileSource *tile_store,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *cache = GEGL_TILE_HANDLER_CACHE (tile_store);
|
|
Packit Service |
2781ba |
GeglTileSource *source = GEGL_TILE_HANDLER (tile_store)->source;
|
|
Packit Service |
2781ba |
GeglTile *tile = NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (gegl_cl_is_accelerated ())
|
|
Packit Service |
2781ba |
gegl_buffer_cl_cache_flush2 (cache, NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
tile = gegl_tile_handler_cache_get_tile (cache, x, y, z);
|
|
Packit Service |
2781ba |
if (tile)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
#ifdef GEGL_DEBUG_CACHE_HITS
|
|
Packit Service |
2781ba |
cache_hits++;
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
return tile;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
#ifdef GEGL_DEBUG_CACHE_HITS
|
|
Packit Service |
2781ba |
cache_misses++;
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (source)
|
|
Packit Service |
2781ba |
tile = gegl_tile_source_get_tile (source, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (tile)
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_insert (cache, tile, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return tile;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_command (GeglTileSource *tile_store,
|
|
Packit Service |
2781ba |
GeglTileCommand command,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z,
|
|
Packit Service |
2781ba |
gpointer data)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileHandler *handler = GEGL_TILE_HANDLER (tile_store);
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *cache = GEGL_TILE_HANDLER_CACHE (handler);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
switch (command)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case GEGL_TILE_FLUSH:
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GList *link;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (gegl_cl_is_accelerated ())
|
|
Packit Service |
2781ba |
gegl_buffer_cl_cache_flush2 (GEGL_TILE_HANDLER_CACHE (tile_store), NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (cache->count)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
for (link = g_queue_peek_head_link (cache_queue); link; link = link->next)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item = link->data;
|
|
Packit Service |
2781ba |
GeglTile *tile = item->tile;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (tile != NULL &&
|
|
Packit Service |
2781ba |
item->handler == cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_store (tile);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
case GEGL_TILE_GET:
|
|
Packit Service |
2781ba |
/* XXX: we should perhaps store a NIL result, and place the empty
|
|
Packit Service |
2781ba |
* generator after the cache, this would have to be possible to disable
|
|
Packit Service |
2781ba |
* to work in sync operation with backend.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
return gegl_tile_handler_cache_get_tile_command (tile_store, x, y, z);
|
|
Packit Service |
2781ba |
case GEGL_TILE_IS_CACHED:
|
|
Packit Service |
2781ba |
return GINT_TO_POINTER(gegl_tile_handler_cache_has_tile (cache, x, y, z));
|
|
Packit Service |
2781ba |
case GEGL_TILE_EXIST:
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gboolean exist = gegl_tile_handler_cache_has_tile (cache, x, y, z);
|
|
Packit Service |
2781ba |
if (exist)
|
|
Packit Service |
2781ba |
return (gpointer)TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
case GEGL_TILE_IDLE:
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gboolean action = gegl_tile_handler_cache_wash (cache);
|
|
Packit Service |
2781ba |
if (action)
|
|
Packit Service |
2781ba |
return GINT_TO_POINTER(action);
|
|
Packit Service |
2781ba |
/* with no action, we chain up to lower levels */
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
case GEGL_TILE_REFETCH:
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_invalidate (cache, x, y, z);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
case GEGL_TILE_VOID:
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_void (cache, x, y, z);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
case GEGL_TILE_REINIT:
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_reinit (cache);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return gegl_tile_handler_source_command (handler, command, x, y, z, data);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* write the least recently used dirty tile to disk if it
|
|
Packit Service |
2781ba |
* is in the wash_percentage (20%) least recently used tiles,
|
|
Packit Service |
2781ba |
* calling this function in an idle handler distributes the
|
|
Packit Service |
2781ba |
* tile flushing overhead over time.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
gboolean
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_wash (GeglTileHandlerCache *cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTile *last_dirty = NULL;
|
|
Packit Service |
2781ba |
guint count = 0;
|
|
Packit Service |
2781ba |
gint length = g_queue_get_length (cache_queue);
|
|
Packit Service |
2781ba |
gint wash_tiles = cache_wash_percentage * length / 100;
|
|
Packit Service |
2781ba |
GList *link;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (link = g_queue_peek_head_link (cache_queue); link; link = link->next)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item = link->data;
|
|
Packit Service |
2781ba |
GeglTile *tile = item->tile;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
count++;
|
|
Packit Service |
2781ba |
if (!gegl_tile_is_stored (tile))
|
|
Packit Service |
2781ba |
if (count > length - wash_tiles)
|
|
Packit Service |
2781ba |
last_dirty = tile;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (last_dirty != NULL)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_store (last_dirty);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* returns the requested Tile if it is in the cache, NULL otherwize.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static GeglTile *
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_get_tile (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *result;
|
|
Packit Service |
2781ba |
CacheItem pin;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (cache->count == 0)
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
pin.x = x;
|
|
Packit Service |
2781ba |
pin.y = y;
|
|
Packit Service |
2781ba |
pin.z = z;
|
|
Packit Service |
2781ba |
pin.handler = cache;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_static_mutex_lock (&mutex);
|
|
Packit Service |
2781ba |
result = g_hash_table_lookup (cache_ht, &pin;;
|
|
Packit Service |
2781ba |
if (result)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_queue_remove (cache_queue, result);
|
|
Packit Service |
2781ba |
g_queue_push_head (cache_queue, result);
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
return gegl_tile_ref (result->tile);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_has_tile (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTile *tile = gegl_tile_handler_cache_get_tile (cache, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (tile)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_unref (tile);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_trim (GeglTileHandlerCache *cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *last_writable;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
last_writable = g_queue_pop_tail (cache_queue);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (last_writable != NULL)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_hash_table_remove (cache_ht, last_writable);
|
|
Packit Service |
2781ba |
cache_total -= last_writable->tile->size;
|
|
Packit Service |
2781ba |
gegl_tile_unref (last_writable->tile);
|
|
Packit Service |
2781ba |
g_slice_free (CacheItem, last_writable);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_invalidate (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GList *link;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_static_mutex_lock (&mutex);
|
|
Packit Service |
2781ba |
for (link = g_queue_peek_head_link (cache_queue); link; link = link->next)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item = link->data;
|
|
Packit Service |
2781ba |
GeglTile *tile = item->tile;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (tile != NULL &&
|
|
Packit Service |
2781ba |
item->x == x &&
|
|
Packit Service |
2781ba |
item->y == y &&
|
|
Packit Service |
2781ba |
item->z == z &&
|
|
Packit Service |
2781ba |
item->handler == cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
cache_total -= item->tile->size;
|
|
Packit Service |
2781ba |
tile->tile_storage = NULL;
|
|
Packit Service |
2781ba |
gegl_tile_mark_as_stored (tile); /* to cheat it out of being stored */
|
|
Packit Service |
2781ba |
gegl_tile_unref (tile);
|
|
Packit Service |
2781ba |
g_hash_table_remove (cache_ht, item);
|
|
Packit Service |
2781ba |
g_slice_free (CacheItem, item);
|
|
Packit Service |
2781ba |
g_queue_delete_link (cache_queue, link);
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_void (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GList *link;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!cache_queue)
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_static_mutex_lock (&mutex);
|
|
Packit Service |
2781ba |
for (link = g_queue_peek_head_link (cache_queue); link; link = link->next)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item = link->data;
|
|
Packit Service |
2781ba |
GeglTile *tile = item->tile;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (tile != NULL &&
|
|
Packit Service |
2781ba |
item->x == x &&
|
|
Packit Service |
2781ba |
item->y == y &&
|
|
Packit Service |
2781ba |
item->z == z &&
|
|
Packit Service |
2781ba |
item->handler == cache)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gegl_tile_void (tile);
|
|
Packit Service |
2781ba |
cache_total -= item->tile->size;
|
|
Packit Service |
2781ba |
gegl_tile_unref (tile);
|
|
Packit Service |
2781ba |
g_hash_table_remove (cache_ht, item);
|
|
Packit Service |
2781ba |
g_slice_free (CacheItem, item);
|
|
Packit Service |
2781ba |
g_queue_delete_link (cache_queue, link);
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
return;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
|
|
Packit Service |
2781ba |
GeglTile *tile,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
CacheItem *item = g_slice_new (CacheItem);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
item->handler = cache;
|
|
Packit Service |
2781ba |
item->tile = gegl_tile_ref (tile);
|
|
Packit Service |
2781ba |
item->x = x;
|
|
Packit Service |
2781ba |
item->y = y;
|
|
Packit Service |
2781ba |
item->z = z;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_static_mutex_lock (&mutex);
|
|
Packit Service |
2781ba |
cache_total += item->tile->size;
|
|
Packit Service |
2781ba |
g_queue_push_head (cache_queue, item);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
cache->count ++;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_hash_table_insert (cache_ht, item, item);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
while (cache_total > gegl_config()->cache_size)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
#ifdef GEGL_DEBUG_CACHE_HITS
|
|
Packit Service |
2781ba |
GEGL_NOTE(GEGL_DEBUG_CACHE, "cache_total:%i > cache_size:%i", cache_total, gegl_config()->cache_size);
|
|
Packit Service |
2781ba |
GEGL_NOTE(GEGL_DEBUG_CACHE, "%f%% hit:%i miss:%i %i]", cache_hits*100.0/(cache_hits+cache_misses), cache_hits, cache_misses, g_queue_get_length (cache_queue));
|
|
Packit Service |
2781ba |
#endif
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_trim (cache);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
g_static_mutex_unlock (&mutex);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
GeglTileHandlerCache *
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_new (void)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return g_object_new (GEGL_TYPE_TILE_HANDLER_CACHE, NULL);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static guint
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_hashfunc (gconstpointer key)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const CacheItem *e = key;
|
|
Packit Service |
2781ba |
guint hash;
|
|
Packit Service |
2781ba |
gint i;
|
|
Packit Service |
2781ba |
gint srcA = e->x;
|
|
Packit Service |
2781ba |
gint srcB = e->y;
|
|
Packit Service |
2781ba |
gint srcC = e->z;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* interleave the 10 least significant bits of all coordinates,
|
|
Packit Service |
2781ba |
* this gives us Z-order / morton order of the space and should
|
|
Packit Service |
2781ba |
* work well as a hash
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
hash = 0;
|
|
Packit Service |
2781ba |
for (i = 9; i >= 0; i--)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
#define ADD_BIT(bit) do { hash |= (((bit) != 0) ? 1 : 0); hash <<= 1; } while (0)
|
|
Packit Service |
2781ba |
ADD_BIT (srcA & (1 << i));
|
|
Packit Service |
2781ba |
ADD_BIT (srcB & (1 << i));
|
|
Packit Service |
2781ba |
ADD_BIT (srcC & (1 << i));
|
|
Packit Service |
2781ba |
#undef ADD_BIT
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return hash ^ GPOINTER_TO_INT (e->handler);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
gegl_tile_handler_cache_equalfunc (gconstpointer a,
|
|
Packit Service |
2781ba |
gconstpointer b)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const CacheItem *ea = a;
|
|
Packit Service |
2781ba |
const CacheItem *eb = b;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (ea->x == eb->x &&
|
|
Packit Service |
2781ba |
ea->y == eb->y &&
|
|
Packit Service |
2781ba |
ea->z == eb->z &&
|
|
Packit Service |
2781ba |
ea->handler == eb->handler)
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_tile_cache_init (void)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (cache_queue == NULL)
|
|
Packit Service |
2781ba |
cache_queue = g_queue_new ();
|
|
Packit Service |
2781ba |
if (cache_ht == NULL)
|
|
Packit Service |
2781ba |
cache_ht = g_hash_table_new (gegl_tile_handler_cache_hashfunc, gegl_tile_handler_cache_equalfunc);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void
|
|
Packit Service |
2781ba |
gegl_tile_cache_destroy (void)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
if (cache_queue)
|
|
Packit Service |
2781ba |
g_queue_free (cache_queue);
|
|
Packit Service |
2781ba |
if (cache_ht)
|
|
Packit Service |
2781ba |
g_hash_table_destroy (cache_ht);
|
|
Packit Service |
2781ba |
cache_queue = NULL;
|
|
Packit Service |
2781ba |
cache_ht = NULL;
|
|
Packit Service |
2781ba |
}
|