|
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 GEGL; 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 <string.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include <glib-object.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl-buffer-backend.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile-backend.h"
|
|
Packit Service |
2781ba |
#include "gegl-tile-backend-ram.h"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void dbg_alloc (int size);
|
|
Packit Service |
2781ba |
static void dbg_dealloc (int size);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef struct _RamEntry RamEntry;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
struct _RamEntry
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint x;
|
|
Packit Service |
2781ba |
gint y;
|
|
Packit Service |
2781ba |
gint z;
|
|
Packit Service |
2781ba |
guchar *offset;
|
|
Packit Service |
2781ba |
};
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
ram_entry_read (GeglTileBackendRam *ram,
|
|
Packit Service |
2781ba |
RamEntry *entry,
|
|
Packit Service |
2781ba |
guchar *dest)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (ram));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
memcpy (dest, entry->offset, tile_size);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
ram_entry_write (GeglTileBackendRam *ram,
|
|
Packit Service |
2781ba |
RamEntry *entry,
|
|
Packit Service |
2781ba |
guchar *source)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (ram));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
memcpy (entry->offset, source, tile_size);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline RamEntry *
|
|
Packit Service |
2781ba |
ram_entry_new (GeglTileBackendRam *ram)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
RamEntry *self = g_slice_new (RamEntry);
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (ram));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
self->offset = g_malloc (tile_size);
|
|
Packit Service |
2781ba |
dbg_alloc (tile_size);
|
|
Packit Service |
2781ba |
return self;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline void
|
|
Packit Service |
2781ba |
ram_entry_destroy (RamEntry *entry,
|
|
Packit Service |
2781ba |
GeglTileBackendRam *ram)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (ram));
|
|
Packit Service |
2781ba |
g_free (entry->offset);
|
|
Packit Service |
2781ba |
g_hash_table_remove (ram->entries, entry);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
dbg_dealloc (tile_size);
|
|
Packit Service |
2781ba |
g_slice_free (RamEntry, entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
G_DEFINE_TYPE (GeglTileBackendRam, gegl_tile_backend_ram, GEGL_TYPE_TILE_BACKEND)
|
|
Packit Service |
2781ba |
static GObjectClass * parent_class = NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gint allocs = 0;
|
|
Packit Service |
2781ba |
static gint ram_size = 0;
|
|
Packit Service |
2781ba |
static gint peak_allocs = 0;
|
|
Packit Service |
2781ba |
static gint peak_ram_size = 0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
void gegl_tile_backend_ram_stats (void)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("leaked: %i chunks (%f mb) peak: %i (%i bytes %fmb))",
|
|
Packit Service |
2781ba |
allocs, ram_size / 1024 / 1024.0, peak_allocs, peak_ram_size, peak_ram_size / 1024 / 1024.0);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void dbg_alloc (gint size)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
allocs++;
|
|
Packit Service |
2781ba |
ram_size += size;
|
|
Packit Service |
2781ba |
if (allocs > peak_allocs)
|
|
Packit Service |
2781ba |
peak_allocs = allocs;
|
|
Packit Service |
2781ba |
if (ram_size > peak_ram_size)
|
|
Packit Service |
2781ba |
peak_ram_size = ram_size;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void dbg_dealloc (gint size)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
allocs--;
|
|
Packit Service |
2781ba |
ram_size -= size;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static inline RamEntry *
|
|
Packit Service |
2781ba |
lookup_entry (GeglTileBackendRam *self,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
RamEntry key;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
key.x = x;
|
|
Packit Service |
2781ba |
key.y = y;
|
|
Packit Service |
2781ba |
key.z = z;
|
|
Packit Service |
2781ba |
key.offset = 0;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return g_hash_table_lookup (self->entries, &key);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* this is the only place that actually should
|
|
Packit Service |
2781ba |
* instantiate tiles, when the cache is large enough
|
|
Packit Service |
2781ba |
* that should make sure we don't hit this function
|
|
Packit Service |
2781ba |
* too often.
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
static GeglTile *
|
|
Packit Service |
2781ba |
get_tile (GeglTileSource *tile_store,
|
|
Packit Service |
2781ba |
gint x,
|
|
Packit Service |
2781ba |
gint y,
|
|
Packit Service |
2781ba |
gint z)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackendRam *tile_backend_ram = GEGL_TILE_BACKEND_RAM (tile_store);
|
|
Packit Service |
2781ba |
GeglTileBackend *backend = GEGL_TILE_BACKEND (tile_store);
|
|
Packit Service |
2781ba |
GeglTile *tile = NULL;
|
|
Packit Service |
2781ba |
gint tile_size = gegl_tile_backend_get_tile_size (backend);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
RamEntry *entry = lookup_entry (tile_backend_ram, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!entry)
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
tile = gegl_tile_new (tile_size);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ram_entry_read (tile_backend_ram, entry, gegl_tile_get_data (tile));
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return tile;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static
|
|
Packit Service |
2781ba |
gboolean set_tile (GeglTileSource *store,
|
|
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 |
GeglTileBackend *backend = GEGL_TILE_BACKEND (store);
|
|
Packit Service |
2781ba |
GeglTileBackendRam *tile_backend_ram = GEGL_TILE_BACKEND_RAM (backend);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
RamEntry *entry = lookup_entry (tile_backend_ram, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (entry == NULL)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
entry = ram_entry_new (tile_backend_ram);
|
|
Packit Service |
2781ba |
entry->x = x;
|
|
Packit Service |
2781ba |
entry->y = y;
|
|
Packit Service |
2781ba |
entry->z = z;
|
|
Packit Service |
2781ba |
g_hash_table_insert (tile_backend_ram->entries, entry, entry);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
ram_entry_write (tile_backend_ram, entry, gegl_tile_get_data (tile));
|
|
Packit Service |
2781ba |
gegl_tile_mark_as_stored (tile);
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static
|
|
Packit Service |
2781ba |
gboolean void_tile (GeglTileSource *store,
|
|
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 |
GeglTileBackend *backend = GEGL_TILE_BACKEND (store);
|
|
Packit Service |
2781ba |
GeglTileBackendRam *tile_backend_ram = GEGL_TILE_BACKEND_RAM (backend);
|
|
Packit Service |
2781ba |
RamEntry *entry = lookup_entry (tile_backend_ram, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (entry != NULL)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
ram_entry_destroy (entry, tile_backend_ram);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static
|
|
Packit Service |
2781ba |
gboolean exist_tile (GeglTileSource *store,
|
|
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 |
GeglTileBackend *backend = GEGL_TILE_BACKEND (store);
|
|
Packit Service |
2781ba |
GeglTileBackendRam *tile_backend_ram = GEGL_TILE_BACKEND_RAM (backend);
|
|
Packit Service |
2781ba |
RamEntry *entry = lookup_entry (tile_backend_ram, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return entry != NULL;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
enum
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
PROP_0
|
|
Packit Service |
2781ba |
};
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gpointer
|
|
Packit Service |
2781ba |
gegl_tile_backend_ram_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 |
switch (command)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case GEGL_TILE_GET:
|
|
Packit Service |
2781ba |
return get_tile (tile_store, x, y, z);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_SET:
|
|
Packit Service |
2781ba |
set_tile (tile_store, data, x, y, z);
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_IDLE:
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_VOID:
|
|
Packit Service |
2781ba |
void_tile (tile_store, data, x, y, z);
|
|
Packit Service |
2781ba |
return NULL;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case GEGL_TILE_EXIST:
|
|
Packit Service |
2781ba |
return GINT_TO_POINTER(exist_tile (tile_store, data, x, y, z));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_assert (command < GEGL_TILE_LAST_COMMAND &&
|
|
Packit Service |
2781ba |
command >= 0);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void set_property (GObject *object,
|
|
Packit Service |
2781ba |
guint property_id,
|
|
Packit Service |
2781ba |
const GValue *value,
|
|
Packit Service |
2781ba |
GParamSpec *pspec)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
switch (property_id)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void get_property (GObject *object,
|
|
Packit Service |
2781ba |
guint property_id,
|
|
Packit Service |
2781ba |
GValue *value,
|
|
Packit Service |
2781ba |
GParamSpec *pspec)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
switch (property_id)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
finalize (GObject *object)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglTileBackendRam *self = (GeglTileBackendRam *) object;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_hash_table_unref (self->entries);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
(*G_OBJECT_CLASS (parent_class)->finalize)(object);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static guint hashfunc (gconstpointer key)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const RamEntry *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; \
|
|
Packit Service |
2781ba |
} \
|
|
Packit Service |
2781ba |
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;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean equalfunc (gconstpointer a,
|
|
Packit Service |
2781ba |
gconstpointer b)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
const RamEntry *ea = a;
|
|
Packit Service |
2781ba |
const RamEntry *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 |
return TRUE;
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GObject *
|
|
Packit Service |
2781ba |
gegl_tile_backend_ram_constructor (GType type,
|
|
Packit Service |
2781ba |
guint n_params,
|
|
Packit Service |
2781ba |
GObjectConstructParam *params)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GObject *object;
|
|
Packit Service |
2781ba |
GeglTileBackendRam *ram;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
|
|
Packit Service |
2781ba |
ram = GEGL_TILE_BACKEND_RAM (object);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ram->entries = g_hash_table_new (hashfunc, equalfunc);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return object;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_ram_class_init (GeglTileBackendRamClass *klass)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
parent_class = g_type_class_peek_parent (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gobject_class->get_property = get_property;
|
|
Packit Service |
2781ba |
gobject_class->set_property = set_property;
|
|
Packit Service |
2781ba |
gobject_class->constructor = gegl_tile_backend_ram_constructor;
|
|
Packit Service |
2781ba |
gobject_class->finalize = finalize;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_tile_backend_ram_init (GeglTileBackendRam *self)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
((GeglTileSource*)self)->command = gegl_tile_backend_ram_command;
|
|
Packit Service |
2781ba |
self->entries = NULL;
|
|
Packit Service |
2781ba |
}
|