[gegl/soc-2013-n-point-deformation] buffer: added GeglTileBackendSwap which stores data of all buffers with the backend in a single file
- From: Marek Dvoroznak <dvoromar src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl/soc-2013-n-point-deformation] buffer: added GeglTileBackendSwap which stores data of all buffers with the backend in a single file
- Date: Wed, 3 Jul 2013 17:23:15 +0000 (UTC)
commit d94e6b925f602b2ff6038823c0620a0b5251ebdc
Author: Ville Sokk <ville sokk gmail com>
Date: Thu Jun 27 12:49:59 2013 +0300
buffer: added GeglTileBackendSwap which stores data of all buffers with the backend in a single file
gegl/buffer/Makefile.am | 2 +
gegl/buffer/gegl-buffer.c | 12 +-
gegl/buffer/gegl-tile-backend-swap.c | 887 ++++++++++++++++++++++++++++++++++
gegl/buffer/gegl-tile-backend-swap.h | 53 ++
4 files changed, 947 insertions(+), 7 deletions(-)
---
diff --git a/gegl/buffer/Makefile.am b/gegl/buffer/Makefile.am
index bc19f2e..ff12bc1 100644
--- a/gegl/buffer/Makefile.am
+++ b/gegl/buffer/Makefile.am
@@ -38,6 +38,7 @@ libbuffer_la_SOURCES = \
gegl-tile-backend.c \
gegl-tile-backend-file-async.c \
gegl-tile-backend-ram.c \
+ gegl-tile-backend-swap.c \
gegl-tile-handler.c \
gegl-tile-handler-private.h \
gegl-tile-handler-cache.c \
@@ -69,6 +70,7 @@ libbuffer_la_SOURCES = \
gegl-tile-storage.h \
gegl-tile-backend.h \
gegl-tile-backend-file.h \
+ gegl-tile-backend-swap.h \
gegl-tile-backend-tiledir.h \
gegl-tile-backend-ram.h \
gegl-tile-handler.h \
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index e0c08e1..6c1c661 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -48,6 +48,7 @@
#include "gegl-tile-storage.h"
#include "gegl-tile-backend.h"
#include "gegl-tile-backend-file.h"
+#include "gegl-tile-backend-swap.h"
#include "gegl-tile-backend-tiledir.h"
#include "gegl-tile-backend-ram.h"
#include "gegl-tile.h"
@@ -446,7 +447,8 @@ gegl_buffer_dispose (GObject *object)
/* only flush non-internal backends,. */
if (!(GEGL_IS_TILE_BACKEND_FILE (backend) ||
GEGL_IS_TILE_BACKEND_RAM (backend) ||
- GEGL_IS_TILE_BACKEND_TILE_DIR (backend)))
+ GEGL_IS_TILE_BACKEND_TILE_DIR (backend) ||
+ GEGL_IS_TILE_BACKEND_SWAP (backend)))
gegl_buffer_flush (buffer);
gegl_tile_source_reinit (GEGL_TILE_SOURCE (handler->source));
@@ -621,15 +623,11 @@ gegl_buffer_constructor (GType type,
}
else
{
- gchar *path = get_next_swap_path ();
-
- backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE,
+ backend = g_object_new (GEGL_TYPE_TILE_BACKEND_SWAP,
"tile-width", buffer->tile_width,
"tile-height", buffer->tile_height,
"format", buffer->format,
- "path", path,
NULL);
- g_free (path);
}
buffer->backend = backend;
@@ -1241,7 +1239,7 @@ gegl_buffer_try_lock (GeglBuffer *buffer)
return TRUE;
}
if (gegl_buffer_is_shared(buffer))
- ret =gegl_tile_backend_file_try_lock (GEGL_TILE_BACKEND_FILE (backend));
+ ret = gegl_tile_backend_file_try_lock (GEGL_TILE_BACKEND_FILE (backend));
else
ret = TRUE;
if (ret)
diff --git a/gegl/buffer/gegl-tile-backend-swap.c b/gegl/buffer/gegl-tile-backend-swap.c
new file mode 100644
index 0000000..0b88056
--- /dev/null
+++ b/gegl/buffer/gegl-tile-backend-swap.c
@@ -0,0 +1,887 @@
+/* This file is part of GEGL.
+ *
+ * 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 3 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 GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2006, 2007, 2008 Øyvind Kolås <pippin gimp org>
+ * 2012, 2013 Ville Sokk <ville sokk gmail com>
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#ifdef G_OS_WIN32
+#include <process.h>
+#define getpid() _getpid()
+#endif
+
+#include <glib-object.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
+
+#include "gegl.h"
+#include "gegl-buffer-types.h"
+#include "gegl-buffer-backend.h"
+#include "gegl-tile-backend.h"
+#include "gegl-tile-backend-swap.h"
+#include "gegl-debug.h"
+#include "gegl-config.h"
+
+
+#ifndef HAVE_FSYNC
+
+#ifdef G_OS_WIN32
+#define fsync _commit
+#endif
+
+#endif
+
+
+G_DEFINE_TYPE (GeglTileBackendSwap, gegl_tile_backend_swap, GEGL_TYPE_TILE_BACKEND)
+
+static GObjectClass * parent_class = NULL;
+
+
+typedef enum
+{
+ OP_WRITE,
+ OP_TRUNCATE,
+} ThreadOp;
+
+typedef struct
+{
+ guint64 offset;
+ GList *link;
+ gint x;
+ gint y;
+ gint z;
+} SwapEntry;
+
+typedef struct
+{
+ SwapEntry *entry;
+ gint length;
+ guchar *source;
+ ThreadOp operation;
+} ThreadParams;
+
+typedef struct
+{
+ guint64 start;
+ guint64 end;
+} SwapGap;
+
+
+static void gegl_tile_backend_swap_push_queue (ThreadParams *params);
+static void gegl_tile_backend_swap_write (ThreadParams *params);
+static gpointer gegl_tile_backend_swap_writer_thread (gpointer ignored);
+static void gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
+ SwapEntry *entry,
+ guchar *dest);
+static void gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
+ SwapEntry *entry,
+ guchar *source);
+static SwapEntry * gegl_tile_backend_swap_entry_create (gint x,
+ gint y,
+ gint z);
+static guint64 gegl_tile_backend_swap_find_offset (gint tile_size);
+static SwapGap * gegl_tile_backend_swap_gap_new (guint64 start,
+ guint64 end);
+static void gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
+ SwapEntry *entry);
+static void gegl_tile_backend_swap_resize (guint64 size);
+static SwapEntry * gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
+ gint x,
+ gint y,
+ gint z);
+static GeglTile * gegl_tile_backend_swap_get_tile (GeglTileSource *self,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_set_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_void_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_exist_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z);
+static gpointer gegl_tile_backend_swap_command (GeglTileSource *self,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data);
+static guint gegl_tile_backend_swap_hashfunc (gconstpointer key);
+static gboolean gegl_tile_backend_swap_equalfunc (gconstpointer a,
+ gconstpointer b);
+static GObject * gegl_tile_backend_swap_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params);
+static void gegl_tile_backend_swap_finalize (GObject *object);
+static void gegl_tile_backend_swap_ensure_exist (void);
+static void gegl_tile_backend_swap_class_init (GeglTileBackendSwapClass *klass);
+static void gegl_tile_backend_swap_init (GeglTileBackendSwap *self);
+void gegl_tile_backend_swap_cleanup (void);
+
+
+static gchar *path = NULL;
+static gint in_fd = -1;
+static gint out_fd = -1;
+static guint64 in_offset = 0;
+static guint64 out_offset = 0;
+static GList *gap_list = NULL;
+static guint64 total = 0;
+
+static GThread *writer_thread = NULL;
+static GQueue *queue = NULL;
+static ThreadParams *in_progress = NULL;
+static gboolean exit_thread = FALSE;
+static gint queue_size = 0;
+static GMutex mutex;
+static GCond queue_cond;
+static GCond max_cond;
+
+
+static void
+gegl_tile_backend_swap_push_queue (ThreadParams *params)
+{
+ g_mutex_lock (&mutex);
+
+ /* block if the queue has gotten too big */
+ while (queue_size > gegl_config ()->queue_size)
+ g_cond_wait (&max_cond, &mutex);
+
+ g_queue_push_tail (queue, params);
+
+ if (params->operation == OP_WRITE)
+ {
+ params->entry->link = g_queue_peek_tail_link (queue);
+ queue_size += params->length + sizeof (GList) +
+ sizeof (ThreadParams);
+ }
+
+ /* wake up the writer thread */
+ g_cond_signal (&queue_cond);
+
+ g_mutex_unlock (&mutex);
+}
+
+static void
+gegl_tile_backend_swap_write (ThreadParams *params)
+{
+ gint to_be_written = params->length;
+ guint64 offset = params->entry->offset;
+
+ if (out_offset != offset)
+ {
+ if (lseek (out_fd, offset, SEEK_SET) < 0)
+ {
+ g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
+ return;
+ }
+ out_offset = offset;
+ }
+
+ while (to_be_written > 0)
+ {
+ gint wrote;
+ wrote = write (out_fd,
+ params->source + params->length - to_be_written,
+ to_be_written);
+ if (wrote <= 0)
+ {
+ g_message ("unable to write tile data to self: "
+ "%s (%d/%d bytes written)",
+ g_strerror (errno), wrote, to_be_written);
+ break;
+ }
+
+ to_be_written -= wrote;
+ out_offset += wrote;
+ }
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "writer thread wrote at %i", (gint)offset);
+}
+
+static gpointer
+gegl_tile_backend_swap_writer_thread (gpointer ignored)
+{
+ while (TRUE)
+ {
+ ThreadParams *params;
+
+ g_mutex_lock (&mutex);
+
+ while (g_queue_is_empty (queue) && !exit_thread)
+ g_cond_wait (&queue_cond, &mutex);
+
+ if (exit_thread)
+ {
+ g_mutex_unlock (&mutex);
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "exiting writer thread");
+ return NULL;
+ }
+
+ params = (ThreadParams *)g_queue_pop_head (queue);
+ if (params->operation == OP_WRITE)
+ {
+ in_progress = params;
+ params->entry->link = NULL;
+ }
+
+ g_mutex_unlock (&mutex);
+
+ switch (params->operation)
+ {
+ case OP_WRITE:
+ gegl_tile_backend_swap_write (params);
+ break;
+ case OP_TRUNCATE:
+ ftruncate (out_fd, total);
+ break;
+ }
+
+ g_mutex_lock (&mutex);
+
+ in_progress = NULL;
+
+ if (params->operation == OP_WRITE)
+ {
+ queue_size -= params->length + sizeof (GList) +
+ sizeof (ThreadParams);
+ g_free (params->source);
+
+ /* unblock the main thread if the queue had gotten too big */
+ if (queue_size < gegl_config ()->queue_size)
+ g_cond_signal (&max_cond);
+ }
+
+ g_slice_free (ThreadParams, params);
+
+ g_mutex_unlock (&mutex);
+ }
+
+ return NULL;
+}
+
+static void
+gegl_tile_backend_swap_entry_read (GeglTileBackendSwap *self,
+ SwapEntry *entry,
+ guchar *dest)
+{
+ gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ gint to_be_read = tile_size;
+ guint64 offset = entry->offset;
+
+ gegl_tile_backend_swap_ensure_exist ();
+
+ if (entry->link || in_progress)
+ {
+ ThreadParams *queued_op = NULL;
+ g_mutex_lock (&mutex);
+
+ if (entry->link)
+ queued_op = entry->link->data;
+ else if (in_progress && in_progress->entry == entry)
+ queued_op = in_progress;
+
+ if (queued_op)
+ {
+ memcpy (dest, queued_op->source, to_be_read);
+ g_mutex_unlock (&mutex);
+
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from queue", entry->x, entry->y,
entry->z);
+
+ return;
+ }
+
+ g_mutex_unlock (&mutex);
+ }
+
+ if (in_offset != offset)
+ {
+ if (lseek (in_fd, offset, SEEK_SET) < 0)
+ {
+ g_warning ("unable to seek to tile in buffer: %s", g_strerror (errno));
+ return;
+ }
+ in_offset = offset;
+ }
+
+ while (to_be_read > 0)
+ {
+ GError *error = NULL;
+ gint byte_read;
+
+ byte_read = read (in_fd, dest + tile_size - to_be_read, to_be_read);
+ if (byte_read <= 0)
+ {
+ g_message ("unable to read tile data from swap: "
+ "%s (%d/%d bytes read) %s",
+ g_strerror (errno), byte_read, to_be_read, error?error->message:"--");
+ return;
+ }
+ to_be_read -= byte_read;
+ in_offset += byte_read;
+ }
+
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "read entry %i, %i, %i from %i", entry->x, entry->y, entry->z,
(gint)offset);
+}
+
+static void
+gegl_tile_backend_swap_entry_write (GeglTileBackendSwap *self,
+ SwapEntry *entry,
+ guchar *source)
+{
+ ThreadParams *params;
+ gint length = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ guchar *new_source;
+
+ gegl_tile_backend_swap_ensure_exist ();
+
+ if (entry->link)
+ {
+ g_mutex_lock (&mutex);
+
+ if (entry->link)
+ {
+ params = entry->link->data;
+ memcpy (params->source, source, length);
+ g_mutex_unlock (&mutex);
+
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "overwrote queue entry %i, %i, %i at %i", entry->x, entry->y,
entry->z, (gint)entry->offset);
+
+ return;
+ }
+
+ g_mutex_unlock (&mutex);
+ }
+
+ new_source = g_malloc (length);
+ memcpy (new_source, source, length);
+
+ params = g_slice_new0 (ThreadParams);
+ params->operation = OP_WRITE;
+ params->length = length;
+ params->source = new_source;
+ params->entry = entry;
+
+ gegl_tile_backend_swap_push_queue (params);
+
+ GEGL_NOTE(GEGL_DEBUG_TILE_BACKEND, "pushed write of entry %i, %i, %i at %i", entry->x, entry->y, entry->z,
(gint)entry->offset);
+}
+
+static SwapEntry *
+gegl_tile_backend_swap_entry_create (gint x,
+ gint y,
+ gint z)
+{
+ SwapEntry *entry = g_slice_new0 (SwapEntry);
+
+ entry->x = x;
+ entry->y = y;
+ entry->z = z;
+ entry->link = NULL;
+
+ return entry;
+}
+
+static guint64
+gegl_tile_backend_swap_find_offset (gint tile_size)
+{
+ SwapGap *gap;
+ guint64 offset;
+
+ if (gap_list)
+ {
+ GList *link = gap_list;
+ SwapGap *gap = link->data;
+
+ while (link)
+ {
+ gint length = gap->end - gap->start;
+
+ if (length > tile_size)
+ {
+ offset = gap->start;
+ gap->start += tile_size;
+
+ return offset;
+ }
+ else if (length == tile_size)
+ {
+ offset = gap->start;
+ g_slice_free (SwapGap, gap);
+ gap_list = g_list_delete_link (gap_list, link);
+
+ return offset;
+ }
+
+ link = link->next;
+ }
+ }
+
+ offset = total;
+
+ gegl_tile_backend_swap_resize (total + 32 * tile_size);
+
+ gap = gegl_tile_backend_swap_gap_new (offset + tile_size, total);
+ gap_list = g_list_append (gap_list, gap);
+
+ return offset;
+}
+
+static SwapGap *
+gegl_tile_backend_swap_gap_new (guint64 start,
+ guint64 end)
+{
+ SwapGap *gap = g_slice_new (SwapGap);
+
+ gap->start = start;
+ gap->end = end;
+
+ return gap;
+}
+
+static void
+gegl_tile_backend_swap_entry_destroy (GeglTileBackendSwap *self,
+ SwapEntry *entry)
+{
+ guint64 start, end;
+ gint tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ GList *hlink;
+
+ if (entry->link)
+ {
+ GList *link = entry->link;
+
+ g_mutex_lock (&mutex);
+
+ if (link)
+ {
+ ThreadParams *queued_op = link->data;
+ g_queue_delete_link (queue, link);
+ g_free (queued_op->source);
+ g_slice_free (ThreadParams, queued_op);
+ }
+
+ g_mutex_unlock (&mutex);
+ }
+
+ start = entry->offset;
+ end = start + tile_size;
+
+ hlink = gap_list;
+ while (hlink)
+ {
+ GList *llink = hlink->prev;
+ SwapGap *lgap, *hgap;
+
+ if (llink)
+ lgap = llink->data;
+
+ hgap = hlink->data;
+
+ /* attempt to merge lower, upper and this gap */
+ if (llink != NULL && lgap->end == start &&
+ hgap->start == end)
+ {
+ llink->next = hlink->next;
+ if (hlink->next)
+ hlink->next->prev = llink;
+ lgap->end = hgap->end;
+
+ g_slice_free (SwapGap, hgap);
+ hlink->next = NULL;
+ hlink->prev = NULL;
+ g_list_free (hlink);
+ break;
+ }
+ /* attempt to merge with upper gap */
+ else if (hgap->start == end)
+ {
+ hgap->start = start;
+ break;
+ }
+ /* attempt to merge with lower gap */
+ else if (llink != NULL && lgap->end == start)
+ {
+ lgap->end = end;
+ break;
+ }
+ /* create new gap */
+ else if (hgap->start > end)
+ {
+ lgap = gegl_tile_backend_swap_gap_new (start, end);
+ gap_list = g_list_insert_before (gap_list, hlink, lgap);
+ break;
+ }
+
+ /* if there's no more elements in the list after this */
+ else if (hlink->next == NULL)
+ {
+ /* attempt to merge with the last gap */
+ if (hgap->end == start)
+ {
+ hgap->end = end;
+ }
+ /* create a new gap in the end of the list */
+ else
+ {
+ GList *new_link;
+ hgap = gegl_tile_backend_swap_gap_new (start, end);
+ new_link = g_list_alloc ();
+ new_link->next = NULL;
+ new_link->prev = hlink;
+ new_link->data = hgap;
+ hlink->next = new_link;
+ }
+ break;
+ }
+
+ hlink = hlink->next;
+ }
+
+ g_hash_table_remove (self->index, entry);
+ g_slice_free (SwapEntry, entry);
+}
+
+static void
+gegl_tile_backend_swap_resize (guint64 size)
+{
+ ThreadParams *params;
+
+ total = size;
+ params = g_slice_new0 (ThreadParams);
+ params->operation = OP_TRUNCATE;
+
+ gegl_tile_backend_swap_push_queue (params);
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "pushed resize to %i", (gint)total);
+}
+
+static SwapEntry *
+gegl_tile_backend_swap_lookup_entry (GeglTileBackendSwap *self,
+ gint x,
+ gint y,
+ gint z)
+{
+ SwapEntry *ret = NULL;
+ SwapEntry *key = gegl_tile_backend_swap_entry_create (x, y, z);
+
+ ret = g_hash_table_lookup (self->index, key);
+ g_slice_free (SwapEntry, key);
+
+ return ret;
+}
+
+static GeglTile *
+gegl_tile_backend_swap_get_tile (GeglTileSource *self,
+ gint x,
+ gint y,
+ gint z)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendSwap *tile_backend_swap;
+ SwapEntry *entry;
+ GeglTile *tile = NULL;
+ gint tile_size;
+
+ backend = GEGL_TILE_BACKEND (self);
+ tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend);
+ entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
+
+ if (!entry)
+ return NULL;
+
+ tile_size = gegl_tile_backend_get_tile_size (GEGL_TILE_BACKEND (self));
+ tile = gegl_tile_new (tile_size);
+ gegl_tile_mark_as_stored (tile);
+
+ gegl_tile_backend_swap_entry_read (tile_backend_swap, entry, gegl_tile_get_data (tile));
+
+ return tile;
+}
+
+static gpointer
+gegl_tile_backend_swap_set_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendSwap *tile_backend_swap;
+ SwapEntry *entry;
+
+ backend = GEGL_TILE_BACKEND (self);
+ tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend);
+ entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
+
+ gegl_tile_backend_swap_ensure_exist ();
+
+ if (entry == NULL)
+ {
+ entry = gegl_tile_backend_swap_entry_create (x, y, z);
+ entry->offset = gegl_tile_backend_swap_find_offset (gegl_tile_backend_get_tile_size (backend));
+ g_hash_table_insert (tile_backend_swap->index, entry, entry);
+ }
+
+ gegl_tile_backend_swap_entry_write (tile_backend_swap, entry, gegl_tile_get_data (tile));
+
+ gegl_tile_mark_as_stored (tile);
+
+ return NULL;
+}
+
+static gpointer
+gegl_tile_backend_swap_void_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendSwap *tile_backend_swap;
+ SwapEntry *entry;
+
+ backend = GEGL_TILE_BACKEND (self);
+ tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend);
+ entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
+
+ if (entry != NULL)
+ {
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "void tile %i, %i, %i", x, y, z);
+
+ gegl_tile_backend_swap_entry_destroy (tile_backend_swap, entry);
+ }
+
+ return NULL;
+}
+
+static gpointer
+gegl_tile_backend_swap_exist_tile (GeglTileSource *self,
+ GeglTile *tile,
+ gint x,
+ gint y,
+ gint z)
+{
+ GeglTileBackend *backend;
+ GeglTileBackendSwap *tile_backend_swap;
+ SwapEntry *entry;
+
+ backend = GEGL_TILE_BACKEND (self);
+ tile_backend_swap = GEGL_TILE_BACKEND_SWAP (backend);
+ entry = gegl_tile_backend_swap_lookup_entry (tile_backend_swap, x, y, z);
+
+ return entry!=NULL?((gpointer)0x1):NULL;
+}
+
+static gpointer
+gegl_tile_backend_swap_command (GeglTileSource *self,
+ GeglTileCommand command,
+ gint x,
+ gint y,
+ gint z,
+ gpointer data)
+{
+ switch (command)
+ {
+ case GEGL_TILE_GET:
+ return gegl_tile_backend_swap_get_tile (self, x, y, z);
+ case GEGL_TILE_SET:
+ return gegl_tile_backend_swap_set_tile (self, data, x, y, z);
+ case GEGL_TILE_IDLE:
+ return NULL;
+ case GEGL_TILE_VOID:
+ return gegl_tile_backend_swap_void_tile (self, data, x, y, z);
+ case GEGL_TILE_EXIST:
+ return gegl_tile_backend_swap_exist_tile (self, data, x, y, z);
+ case GEGL_TILE_FLUSH:
+ return NULL;
+
+ default:
+ g_assert (command < GEGL_TILE_LAST_COMMAND &&
+ command >= 0);
+ }
+ return FALSE;
+}
+
+static guint
+gegl_tile_backend_swap_hashfunc (gconstpointer key)
+{
+ const SwapEntry *entry = key;
+ guint hash;
+ gint i;
+ gint srcA = entry->x;
+ gint srcB = entry->y;
+ gint srcC = entry->z;
+
+ /* interleave the 10 least significant bits of all coordinates,
+ * this gives us Z-order / morton order of the space and should
+ * work well as a hash
+ */
+ hash = 0;
+ for (i = 9; i >= 0; i--)
+ {
+#define ADD_BIT(bit) do { hash |= (((bit) != 0) ? 1 : 0); hash <<= 1; } while (0)
+ ADD_BIT (srcA & (1 << i));
+ ADD_BIT (srcB & (1 << i));
+ ADD_BIT (srcC & (1 << i));
+#undef ADD_BIT
+ }
+ return hash;
+}
+
+static gboolean
+gegl_tile_backend_swap_equalfunc (gconstpointer a,
+ gconstpointer b)
+{
+ const SwapEntry *ea = a;
+ const SwapEntry *eb = b;
+
+ if (ea->x == eb->x &&
+ ea->y == eb->y &&
+ ea->z == eb->z)
+ return TRUE;
+
+ return FALSE;
+}
+
+static GObject *
+gegl_tile_backend_swap_constructor (GType type,
+ guint n_params,
+ GObjectConstructParam *params)
+{
+ GObject *object;
+ GeglTileBackendSwap *self;
+ GeglTileBackend *backend;
+
+ object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
+ self = GEGL_TILE_BACKEND_SWAP (object);
+ backend = GEGL_TILE_BACKEND (object);
+
+ self->index = g_hash_table_new (gegl_tile_backend_swap_hashfunc,
+ gegl_tile_backend_swap_equalfunc);
+
+ backend->priv->shared = FALSE;
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "constructing swap backend");
+
+ return object;
+}
+
+static void
+gegl_tile_backend_swap_finalize (GObject *object)
+{
+ GeglTileBackendSwap *self = GEGL_TILE_BACKEND_SWAP (object);
+
+ if (self->index)
+ {
+ GList *tiles = g_hash_table_get_keys (self->index);
+
+ if (tiles != NULL)
+ {
+ GList *iter;
+
+ for (iter = tiles; iter; iter = iter->next)
+ gegl_tile_backend_swap_entry_destroy (self, iter->data);
+ }
+
+ g_list_free (tiles);
+
+ g_hash_table_unref (self->index);
+
+ self->index = NULL;
+ }
+
+ (*G_OBJECT_CLASS (parent_class)->finalize)(object);
+}
+
+static void
+gegl_tile_backend_swap_ensure_exist (void)
+{
+ if (in_fd == -1 || out_fd == -1)
+ {
+ gchar *filename = g_strdup_printf ("%i-shared.swap", getpid ());
+ path = g_build_filename (gegl_config ()->swap, filename, NULL);
+ g_free (filename);
+
+ GEGL_NOTE (GEGL_DEBUG_TILE_BACKEND, "creating swapfile %s", path);
+
+ out_fd = g_open (path, O_RDWR|O_CREAT, 0770);
+ in_fd = g_open (path, O_RDONLY);
+
+ if (out_fd == -1 || in_fd == -1)
+ g_warning ("Could not open swap file '%s': %s", path, g_strerror (errno));
+ }
+}
+
+static void
+gegl_tile_backend_swap_class_init (GeglTileBackendSwapClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->constructor = gegl_tile_backend_swap_constructor;
+ gobject_class->finalize = gegl_tile_backend_swap_finalize;
+
+ queue = g_queue_new ();
+ writer_thread = g_thread_new ("swap writer",
+ gegl_tile_backend_swap_writer_thread,
+ NULL);
+}
+
+void
+gegl_tile_backend_swap_cleanup (void)
+{
+ if (in_fd != -1 && out_fd != -1)
+ {
+ exit_thread = TRUE;
+ g_cond_signal (&queue_cond);
+ g_thread_join (writer_thread);
+
+ if (g_queue_get_length (queue) != 0)
+ g_warning ("tile-backend-swap writer queue wasn't empty before freeing\n");
+ g_queue_free (queue);
+
+ if (g_list_length (gap_list) > 1)
+ g_warning ("tile-backend-swap gap list had more than one element\n");
+ g_slice_free (SwapGap, gap_list->data);
+ g_list_free (gap_list);
+
+ close (in_fd);
+ close (out_fd);
+ }
+}
+
+static void
+gegl_tile_backend_swap_init (GeglTileBackendSwap *self)
+{
+ ((GeglTileSource*)self)->command = gegl_tile_backend_swap_command;
+}
diff --git a/gegl/buffer/gegl-tile-backend-swap.h b/gegl/buffer/gegl-tile-backend-swap.h
new file mode 100644
index 0000000..87a98f1
--- /dev/null
+++ b/gegl/buffer/gegl-tile-backend-swap.h
@@ -0,0 +1,53 @@
+/* This file is part of GEGL.
+ *
+ * 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 3 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 GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2012 Ville Sokk <ville sokk gmail com>
+ */
+
+#ifndef __GEGL_TILE_BACKEND_SWAP_H__
+#define __GEGL_TILE_BACKEND_SWAP_H__
+
+#include <glib.h>
+#include "gegl-tile-backend.h"
+
+G_BEGIN_DECLS
+
+#define GEGL_TYPE_TILE_BACKEND_SWAP (gegl_tile_backend_swap_get_type ())
+#define GEGL_TILE_BACKEND_SWAP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GEGL_TYPE_TILE_BACKEND_SWAP, GeglTileBackendSwap))
+#define GEGL_TILE_BACKEND_SWAP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GEGL_TYPE_TILE_BACKEND_SWAP, GeglTileBackendSwapClass))
+#define GEGL_IS_TILE_BACKEND_SWAP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GEGL_TYPE_TILE_BACKEND_SWAP))
+#define GEGL_IS_TILE_BACKEND_SWAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GEGL_TYPE_TILE_BACKEND_SWAP))
+#define GEGL_TILE_BACKEND_SWAP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GEGL_TYPE_TILE_BACKEND_SWAP, GeglTileBackendSwapClass))
+
+
+typedef struct _GeglTileBackendSwap GeglTileBackendSwap;
+typedef struct _GeglTileBackendSwapClass GeglTileBackendSwapClass;
+
+struct _GeglTileBackendSwapClass
+{
+ GeglTileBackendClass parent_class;
+};
+
+struct _GeglTileBackendSwap
+{
+ GeglTileBackend parent_instance;
+ GHashTable *index;
+};
+
+GType gegl_tile_backend_swap_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]