[gegl] Improved locking in GEGL
- From: Øyvind Kolås <ok src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gegl] Improved locking in GEGL
- Date: Fri, 20 Nov 2009 01:43:01 +0000 (UTC)
commit 3cffea77c943527457eec469a6f876dc1e5e005a
Author: �yvind Kolås <pippin gimp org>
Date: Fri Nov 20 01:37:34 2009 +0000
Improved locking in GEGL
Resurrected GEGL multi threaded locks with locking at the tile level,
the performance gained from multi threading is small if detectable,
through the added overhead and lock contention. There still are
outstanding paralellisation issues.
There is a per tile mutex, per buffer (in ->tile_backend) mutex and
a per node mutex. You need to pass --enable-mt to configure/autogen
to enable the multi threading support.
bin/gegl.c | 1 +
configure.ac | 63 ++++++----
examples/gegl-paint.c | 3 +-
examples/hello-world.c | 1 +
examples/util/gegl-view.c | 3 +
gegl/buffer/gegl-buffer-access.c | 108 ++++++---------
gegl/buffer/gegl-buffer-iterator.c | 75 +++++++++--
gegl/buffer/gegl-buffer-linear.c | 18 ++-
gegl/buffer/gegl-buffer-private.h | 43 ++++---
gegl/buffer/gegl-buffer.c | 42 ++++---
gegl/buffer/gegl-cache.c | 15 ++
gegl/buffer/gegl-sampler.c | 4 -
gegl/buffer/gegl-tile-backend.c | 2 +-
gegl/buffer/gegl-tile-handler-cache.c | 71 +++++++++-
gegl/buffer/gegl-tile-storage.c | 2 +
gegl/buffer/gegl-tile-storage.h | 1 +
gegl/buffer/gegl-tile.c | 30 ++++-
gegl/gegl-instrument.c | 2 +
gegl/graph/gegl-node.c | 235 +++++++++++++++++++++++++++++----
gegl/graph/gegl-node.h | 4 +
gegl/graph/gegl-visitor.c | 6 +
gegl/process/gegl-eval-mgr.c | 6 +
gegl/property-types/gegl-path.c | 14 +-
operations/affine/affine.c | 89 +++++++------
operations/affine/affine.h | 1 -
tools/introspect.c | 1 +
26 files changed, 607 insertions(+), 233 deletions(-)
---
diff --git a/bin/gegl.c b/bin/gegl.c
index a5b117d..e8ba51c 100644
--- a/bin/gegl.c
+++ b/bin/gegl.c
@@ -92,6 +92,7 @@ main (gint argc,
gegl_enable_fatal_warnings ();
}
+ g_thread_init (NULL);
gegl_init (&argc, &argv);
#ifdef HAVE_SPIRO
gegl_path_spiro_init ();
diff --git a/configure.ac b/configure.ac
index 493c464..38146ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,6 +185,20 @@ else
AC_MSG_RESULT([no])
fi
+AC_MSG_CHECKING([whether to enable multi threading])
+AC_ARG_ENABLE(mt,
+ [ --enable-mt turn on multi-threading (default=no)],
+)
+if eval "test x$enable_mt = xyes"; then
+ AC_DEFINE(ENABLE_MT, 1, [Defined to 1 if multi-threading is enabled.])
+ AC_MSG_RESULT([yes])
+ enable_mt="yes"
+else
+ enable_mt="no"
+ AC_MSG_RESULT([no])
+fi
+
+
changequote(,)dnl
if eval "test x$GCC = xyes"; then
case " $CFLAGS " in
@@ -1013,30 +1027,31 @@ AC_MSG_RESULT([
Building GEGL with prefix=$prefix
Optional features:
- GEGL docs: $enable_docs
- Build workshop: $enable_workshop
- Build website: $have_asciidoc
- SIMD: sse:$enable_sse mmx:$enable_mmx
+ GEGL docs: $enable_docs
+ Build workshop: $enable_workshop
+ Build website: $have_asciidoc
+ SIMD: sse:$enable_sse mmx:$enable_mmx
+ Multi threading: $enable_mt
Optional dependencies:
- asciidoc: $have_asciidoc
- enscript: $have_enscript
- GIO: $have_gio
- GTK+: $have_gtk
- Ruby: $have_ruby
- Lua: $have_lua
- Cairo: $have_cairo
- Pango: $have_pango
- pangocairo: $have_pangocairo
- GDKPixbuf: $have_gdk_pixbuf
- JPEG: $jpeg_ok
- PNG: $have_libpng
- OpenEXR: $have_openexr
- rsvg: $have_librsvg
- SDL: $have_sdl
- openraw: $have_libopenraw
- graphviz: $have_graphviz
- avformat: $have_libavformat
- V4L: $have_v4l
- spiro: $spiro_ok
+ asciidoc: $have_asciidoc
+ enscript: $have_enscript
+ GIO: $have_gio
+ GTK+: $have_gtk
+ Ruby: $have_ruby
+ Lua: $have_lua
+ Cairo: $have_cairo
+ Pango: $have_pango
+ pangocairo: $have_pangocairo
+ GDKPixbuf: $have_gdk_pixbuf
+ JPEG: $jpeg_ok
+ PNG: $have_libpng
+ OpenEXR: $have_openexr
+ rsvg: $have_librsvg
+ SDL: $have_sdl
+ openraw: $have_libopenraw
+ graphviz: $have_graphviz
+ avformat: $have_libavformat
+ V4L: $have_v4l
+ spiro: $spiro_ok
]);
diff --git a/examples/gegl-paint.c b/examples/gegl-paint.c
index d6741d5..c78850c 100644
--- a/examples/gegl-paint.c
+++ b/examples/gegl-paint.c
@@ -111,7 +111,7 @@ static gboolean paint_release (GtkWidget *widget,
processor = gegl_node_new_processor (writebuf, &roi);
while (gegl_processor_work (processor, NULL)) ;
- g_object_unref (processor);
+ gegl_processor_destroy (processor);
g_object_unref (writebuf);
gegl_node_link_many (top, out, NULL);
@@ -132,6 +132,7 @@ main (gint argc,
gchar **argv)
{
+ g_thread_init (NULL);
gtk_init (&argc, &argv);
gegl_init (&argc, &argv);
diff --git a/examples/hello-world.c b/examples/hello-world.c
index 6caaeb2..97358e3 100644
--- a/examples/hello-world.c
+++ b/examples/hello-world.c
@@ -7,6 +7,7 @@ gint
main (gint argc,
gchar **argv)
{
+ g_thread_init (NULL);
gegl_init (&argc, &argv); /* initialize the GEGL library */
{
diff --git a/examples/util/gegl-view.c b/examples/util/gegl-view.c
index b965033..b60b7cb 100644
--- a/examples/util/gegl-view.c
+++ b/examples/util/gegl-view.c
@@ -195,6 +195,9 @@ finalize (GObject *gobject)
if (priv->node)
g_object_unref (priv->node);
+ if (priv->processor)
+ g_object_unref (priv->processor);
+
G_OBJECT_CLASS (gegl_view_parent_class)->finalize (gobject);
}
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index c36520a..a91a1f1 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -43,11 +43,6 @@
#include "gegl-tile-backend.h"
#include "gegl-buffer-iterator.h"
-#if ENABLE_MP
-GStaticRecMutex mutex = G_STATIC_REC_MUTEX_INIT;
-#endif
-
-
#if 0
static inline void
gegl_buffer_pixel_set (GeglBuffer *buffer,
@@ -584,19 +579,12 @@ gegl_buffer_iterate (GeglBuffer *buffer,
}
void
-gegl_buffer_set (GeglBuffer *buffer,
- const GeglRectangle *rect,
- const Babl *format,
- void *src,
- gint rowstride)
+gegl_buffer_set_unlocked (GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ const Babl *format,
+ void *src,
+ gint rowstride)
{
- g_return_if_fail (GEGL_IS_BUFFER (buffer));
-
-#if ENABLE_MP
- g_static_rec_mutex_lock (&mutex);
-#endif
- gegl_buffer_lock (buffer);
-
if (format == NULL)
format = buffer->format;
@@ -613,12 +601,23 @@ gegl_buffer_set (GeglBuffer *buffer,
{
gegl_buffer_flush (buffer);
}
- gegl_buffer_unlock (buffer); /* XXX: should this happen before flush? */
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
}
+void
+gegl_buffer_set (GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ const Babl *format,
+ void *src,
+ gint rowstride)
+{
+ g_return_if_fail (GEGL_IS_BUFFER (buffer));
+
+ gegl_buffer_lock (buffer);
+ gegl_buffer_set_unlocked (buffer, rect, format, src, rowstride);
+ gegl_buffer_unlock (buffer);
+}
+
+
#if 0
@@ -935,18 +934,15 @@ resample_boxfilter_u8 (void *dest_buf,
}
}
+
void
-gegl_buffer_get (GeglBuffer *buffer,
- gdouble scale,
- const GeglRectangle *rect,
- const Babl *format,
- gpointer dest_buf,
- gint rowstride)
+gegl_buffer_get_unlocked (GeglBuffer *buffer,
+ gdouble scale,
+ const GeglRectangle *rect,
+ const Babl *format,
+ gpointer dest_buf,
+ gint rowstride)
{
- g_return_if_fail (GEGL_IS_BUFFER (buffer));
-#if ENABLE_MP
- g_static_rec_mutex_lock (&mutex);
-#endif
if (format == NULL)
format = buffer->format;
@@ -957,34 +953,22 @@ gegl_buffer_get (GeglBuffer *buffer,
rect->height == 1) /* fast path */
{
gegl_buffer_get_pixel (buffer, rect->x, rect->y, format, dest_buf);
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
return;
}
if (!rect && scale == 1.0)
{
gegl_buffer_iterate (buffer, NULL, dest_buf, rowstride, FALSE, format, 0);
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
return;
}
if (rect->width == 0 ||
rect->height == 0)
{
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
return;
}
if (GEGL_FLOAT_EQUAL (scale, 1.0))
{
gegl_buffer_iterate (buffer, rect, dest_buf, rowstride, FALSE, format, 0);
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
return;
}
else
@@ -1066,9 +1050,20 @@ gegl_buffer_get (GeglBuffer *buffer,
}
g_free (sample_buf);
}
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
+}
+
+void
+gegl_buffer_get (GeglBuffer *buffer,
+ gdouble scale,
+ const GeglRectangle *rect,
+ const Babl *format,
+ gpointer dest_buf,
+ gint rowstride)
+{
+ g_return_if_fail (GEGL_IS_BUFFER (buffer));
+ gegl_buffer_lock (buffer);
+ gegl_buffer_get_unlocked (buffer, scale, rect, format, dest_buf, rowstride);
+ gegl_buffer_unlock (buffer);
}
const GeglRectangle *
@@ -1097,9 +1092,7 @@ gegl_buffer_sample (GeglBuffer *buffer,
return;
#endif
-#if ENABLE_MP
- g_static_rec_mutex_lock (&mutex);
-#endif
+ gegl_buffer_lock (buffer);
desired_type = gegl_sampler_type_from_interpolation (interpolation);
@@ -1121,16 +1114,9 @@ gegl_buffer_sample (GeglBuffer *buffer,
}
gegl_sampler_get (buffer->sampler, x, y, dest);
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
-
- /* if none found, create a singleton sampler for this buffer,
- * a function to clean up the samplers set for a buffer should
- * also be provided */
+ gegl_buffer_unlock (buffer);
/* if (scale < 1.0) do decimation, possibly using pyramid instead */
-
}
void
@@ -1239,13 +1225,5 @@ gegl_buffer_sampler (GeglBuffer *buffer,
g_return_if_fail (GEGL_IS_BUFFER (buffer));
g_return_if_fail (GEGL_IS_SAMPLER (sampler));
-#if ENABLE_MP
- g_static_rec_mutex_lock (&mutex);
-#endif
-
gegl_sampler_get (sampler, x, y, dest);
-
-#if ENABLE_MP
- g_static_rec_mutex_unlock (&mutex);
-#endif
}
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 3c7d16b..d429e88 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -32,7 +32,6 @@
#include "gegl-tile-storage.h"
#include "gegl-utils.h"
-
typedef struct GeglBufferTileIterator
{
GeglBuffer *buffer;
@@ -265,6 +264,7 @@ gegl_buffer_iterator_add (GeglBufferIterator *iterator,
roi = self==0?&(buffer->extent):&(i->rect[0]);
i->rect[self]=*roi;
+ /* XXX: if this buffer creation could be avoided, it would be a speedup */
i->buffer[self]=gegl_buffer_create_sub_buffer (buffer, roi);
if (format)
i->format[self]=format;
@@ -312,9 +312,17 @@ typedef struct BufInfo {
static GArray *buf_pool = NULL;
+#if ENABLE_MP
+static GStaticMutex pool_mutex = G_STATIC_MUTEX_INIT;
+#endif
+
static gpointer iterator_buf_pool_get (gint size)
{
gint i;
+#if ENABLE_MP
+ g_static_mutex_lock (&pool_mutex);
+#endif
+
if (G_UNLIKELY (!buf_pool))
{
buf_pool = g_array_new (TRUE, TRUE, sizeof (BufInfo));
@@ -325,7 +333,10 @@ static gpointer iterator_buf_pool_get (gint size)
if (info->size >= size && info->used == 0)
{
info->used ++;
+#if ENABLE_MP
+ g_static_mutex_unlock (&pool_mutex);
return info->buf;
+#endif
}
}
{
@@ -333,6 +344,9 @@ static gpointer iterator_buf_pool_get (gint size)
info.size = size;
info.buf = gegl_malloc (size);
g_array_append_val (buf_pool, info);
+#if ENABLE_MP
+ g_static_mutex_unlock (&pool_mutex);
+#endif
return info.buf;
}
}
@@ -340,23 +354,29 @@ static gpointer iterator_buf_pool_get (gint size)
static void iterator_buf_pool_release (gpointer buf)
{
gint i;
+#if ENABLE_MP
+ g_static_mutex_lock (&pool_mutex);
+#endif
for (i=0; i<buf_pool->len; i++)
{
BufInfo *info = &g_array_index (buf_pool, BufInfo, i);
if (info->buf == buf)
{
info->used --;
+#if ENABLE_MP
+ g_static_mutex_unlock (&pool_mutex);
+#endif
return;
}
}
g_assert (0);
+#if ENABLE_MP
+ g_static_mutex_unlock (&pool_mutex);
+#endif
}
static void ensure_buf (GeglBufferIterators *i, gint no)
{
- /* XXX: keeping a small pool of such buffres around for the used formats
- * would probably improve performance
- */
if (i->buf[no]==NULL)
i->buf[no] = iterator_buf_pool_get (babl_format_get_bytes_per_pixel (i->format[no]) *
i->i[0].max_size);
@@ -367,12 +387,30 @@ gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator)
GeglBufferIterators *i = (gpointer)iterator;
gboolean result = FALSE;
gint no;
- /* first we need to finish off any pending write work */
if (i->buf[0] == (void*)0xdeadbeef)
g_error ("%s called on finished buffer iterator", G_STRFUNC);
- if (i->iteration_no > 0)
+ if (i->iteration_no == 0)
{
+#if ENABLE_MP
+ for (no=0; no<i->iterators;no++)
+ {
+ gint j;
+ gboolean found = FALSE;
+ for (j=0; j<no; j++)
+ if (i->buffer[no]==i->buffer[j])
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ gegl_buffer_lock (i->buffer[no]);
+ }
+#endif
+ }
+ else
+ {
+ /* complete pending write work */
for (no=0; no<i->iterators;no++)
{
if (i->flags[no] & GEGL_BUFFER_WRITE)
@@ -395,7 +433,7 @@ gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator)
ensure_buf (i, no);
- gegl_buffer_set (i->buffer[no], &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE);
+ gegl_buffer_set_unlocked (i->buffer[no], &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE);
}
}
}
@@ -439,7 +477,7 @@ gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator)
if (i->flags[no] & GEGL_BUFFER_READ)
{
- gegl_buffer_get (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE);
+ gegl_buffer_get_unlocked (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE);
}
i->data[no]=i->buf[no];
@@ -459,7 +497,7 @@ gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator)
if (i->flags[no] & GEGL_BUFFER_READ)
{
- gegl_buffer_get (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE);
+ gegl_buffer_get_unlocked (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE);
}
i->data[no]=i->buf[no];
@@ -474,6 +512,23 @@ gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator)
if (result == FALSE)
{
+
+#if ENABLE_MP
+ for (no=0; no<i->iterators;no++)
+ {
+ gint j;
+ gboolean found = FALSE;
+ for (j=0; j<no; j++)
+ if (i->buffer[no]==i->buffer[j])
+ {
+ found = TRUE;
+ break;
+ }
+ if (!found)
+ gegl_buffer_unlock (i->buffer[no]);
+ }
+#endif
+
for (no=0; no<i->iterators;no++)
{
if (i->buf[no])
@@ -488,6 +543,8 @@ gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator)
i->buf[0]=(void*)0xdeadbeef;
g_free (i);
}
+
+
return result;
}
diff --git a/gegl/buffer/gegl-buffer-linear.c b/gegl/buffer/gegl-buffer-linear.c
index d50453e..f7c1ded 100644
--- a/gegl/buffer/gegl-buffer-linear.c
+++ b/gegl/buffer/gegl-buffer-linear.c
@@ -132,6 +132,10 @@ gegl_buffer_linear_open (GeglBuffer *buffer,
if (extent == NULL)
extent=&buffer->extent;
+ /*gegl_buffer_lock (buffer);*/
+#if ENABLE_MP
+ g_mutex_lock (buffer->tile_storage->mutex);
+#endif
if (extent->x == buffer->extent.x &&
extent->y == buffer->extent.y &&
extent->width == buffer->tile_width &&
@@ -151,7 +155,6 @@ gegl_buffer_linear_open (GeglBuffer *buffer,
tile = gegl_tile_source_get_tile ((GeglTileSource*) (buffer),
0,0,0);
g_assert (tile);
- gegl_buffer_lock (buffer);
gegl_tile_lock (tile);
g_object_set_data (G_OBJECT (buffer), "linear-tile", tile);
@@ -179,6 +182,7 @@ gegl_buffer_linear_open (GeglBuffer *buffer,
)
{
info->refs++;
+ g_print ("!!!!!! sharing a linear buffer!!!!!\n");
return info->buf;
}
}
@@ -199,7 +203,7 @@ gegl_buffer_linear_open (GeglBuffer *buffer,
if(rowstride)*rowstride = rs;
info->buf = gegl_malloc (rs * info->extent.height);
- gegl_buffer_get (buffer, 1.0, &info->extent, format, info->buf, rs);
+ gegl_buffer_get_unlocked (buffer, 1.0, &info->extent, format, info->buf, rs);
return info->buf;
}
return NULL;
@@ -214,7 +218,6 @@ gegl_buffer_linear_close (GeglBuffer *buffer,
if (tile)
{
gegl_tile_unlock (tile);
- gegl_buffer_unlock (buffer);
g_object_set_data (G_OBJECT (buffer), "linear-tile", NULL);
tile = NULL;
}
@@ -233,11 +236,14 @@ gegl_buffer_linear_close (GeglBuffer *buffer,
info->refs--;
if (info->refs>0)
+ {
+ g_print ("EEeeek! %s\n", G_STRLOC);
return; /* there are still others holding a reference to
* this linear buffer
*/
+ }
- gegl_buffer_set (buffer, &info->extent, info->format, info->buf, 0);
+ gegl_buffer_set_unlocked (buffer, &info->extent, info->format, info->buf, 0);
break;
}
else
@@ -255,5 +261,9 @@ gegl_buffer_linear_close (GeglBuffer *buffer,
g_object_set_data (G_OBJECT (buffer), "linear-buffers", linear_buffers);
}
+ /*gegl_buffer_unlock (buffer);*/
+#if ENABLE_MP
+ g_mutex_unlock (buffer->tile_storage->mutex);
+#endif
return;
}
diff --git a/gegl/buffer/gegl-buffer-private.h b/gegl/buffer/gegl-buffer-private.h
index c6c98ba..1f55193 100644
--- a/gegl/buffer/gegl-buffer-private.h
+++ b/gegl/buffer/gegl-buffer-private.h
@@ -79,35 +79,40 @@ struct _GeglBufferClass
-gint gegl_buffer_leaks (void);
+gint gegl_buffer_leaks (void);
-void gegl_buffer_stats (void);
+void gegl_buffer_stats (void);
-void gegl_buffer_save (GeglBuffer *buffer,
- const gchar *path,
- const GeglRectangle *roi);
+void gegl_buffer_save (GeglBuffer *buffer,
+ const gchar *path,
+ const GeglRectangle *roi);
-const gchar *gegl_swap_dir (void);
+const gchar *gegl_swap_dir (void);
-void gegl_tile_cache_init (void);
+void gegl_tile_cache_init (void);
-void gegl_tile_cache_destroy (void);
+void gegl_tile_cache_destroy (void);
-GeglTileBackend * gegl_buffer_backend (GeglBuffer *buffer);
+GeglTileBackend * gegl_buffer_backend (GeglBuffer *buffer);
-gboolean gegl_buffer_is_shared (GeglBuffer *buffer);
-
-gboolean gegl_buffer_try_lock (GeglBuffer *buffer);
-#if 0
-gboolean gegl_buffer_lock (GeglBuffer *buffer);
-gboolean gegl_buffer_unlock (GeglBuffer *buffer);
-#else
-#define gegl_buffer_lock(o) {}
-#define gegl_buffer_unlock(o) {}
-#endif
+gboolean gegl_buffer_is_shared (GeglBuffer *buffer);
+gboolean gegl_buffer_try_lock (GeglBuffer *buffer);
+gboolean gegl_buffer_lock (GeglBuffer *buffer);
+gboolean gegl_buffer_unlock (GeglBuffer *buffer);
+void gegl_buffer_set_unlocked (GeglBuffer *buffer,
+ const GeglRectangle *rect,
+ const Babl *format,
+ void *src,
+ gint rowstride);
+void gegl_buffer_get_unlocked (GeglBuffer *buffer,
+ gdouble scale,
+ const GeglRectangle *rect,
+ const Babl *format,
+ gpointer dest_buf,
+ gint rowstride);
GeglBuffer *
gegl_buffer_new_ram (const GeglRectangle *extent,
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index 61c467a..dad5669 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -71,11 +71,13 @@
#include "gegl-buffer-index.h"
#include "gegl-config.h"
+//#define GEGL_BUFFER_DEBUG_ALLOCATIONS
+
/* #define GEGL_BUFFER_DEBUG_ALLOCATIONS to print allocation stack
* traces for leaked GeglBuffers using GNU C libs backtrace_symbols()
*/
-#ifdef GEGL_BUFFER_DEBUG_ALLOCATIONS
#include <execinfo.h>
+#ifdef GEGL_BUFFER_DEBUG_ALLOCATIONS
#endif
@@ -705,6 +707,7 @@ gegl_buffer_get_tile (GeglTileSource *source,
{
GeglBuffer *buffer = GEGL_BUFFER (handler);
+ /* XXX: lock buffer? */
if (x < buffer->min_x)
buffer->min_x = x;
if (y < buffer->min_y)
@@ -721,7 +724,12 @@ gegl_buffer_get_tile (GeglTileSource *source,
* coordinates.
*/
{
- tile->tile_storage = buffer->tile_storage;
+ if (!tile->tile_storage)
+ {
+ gegl_tile_lock (tile);
+ tile->tile_storage = buffer->tile_storage;
+ gegl_tile_unlock (tile);
+ }
tile->x = x;
tile->y = y;
tile->z = z;
@@ -857,6 +865,7 @@ gegl_buffer_class_init (GeglBufferClass *class)
}
#ifdef GEGL_BUFFER_DEBUG_ALLOCATIONS
+#endif
#define MAX_N_FUNCTIONS 100
static gchar *
gegl_buffer_get_alloc_stack (void)
@@ -890,7 +899,12 @@ gegl_buffer_get_alloc_stack (void)
return result;
}
-#endif
+
+void gegl_bt (void);
+void gegl_bt (void)
+{
+ g_print ("%s\n", gegl_buffer_get_alloc_stack ());
+}
static void
gegl_buffer_init (GeglBuffer *buffer)
@@ -1180,14 +1194,14 @@ gboolean gegl_buffer_is_shared (GeglBuffer *buffer)
gboolean gegl_buffer_try_lock (GeglBuffer *buffer)
{
+#if 0
GeglTileBackend *backend = gegl_buffer_backend (buffer);
- gboolean ret;
-
if (buffer->lock_count>0)
{
buffer->lock_count++;
return TRUE;
}
+ gboolean ret;
if (gegl_buffer_is_shared(buffer))
ret =gegl_tile_backend_file_try_lock (GEGL_TILE_BACKEND_FILE (backend));
else
@@ -1195,27 +1209,21 @@ gboolean gegl_buffer_try_lock (GeglBuffer *buffer)
if (ret)
buffer->lock_count++;
return TRUE;
+#else
+ return g_mutex_trylock (buffer->tile_storage->mutex);
+#endif
}
-#if 0
+#if 1
gboolean gegl_buffer_lock (GeglBuffer *buffer)
{
- while (gegl_buffer_try_lock (buffer)==FALSE)
- {
- g_print ("failed to aquire lock blocking ..");
- g_usleep (100000);
- }
+ if(0)g_mutex_lock (buffer->tile_storage->mutex);
return TRUE;
}
gboolean gegl_buffer_unlock (GeglBuffer *buffer)
{
- GeglTileBackend *backend = gegl_buffer_backend (buffer);
- g_assert (buffer->lock_count>=0);
- buffer->lock_count--;
- g_assert (buffer->lock_count>=0);
- if (buffer->lock_count==0 && gegl_buffer_is_shared (buffer))
- return gegl_tile_backend_file_unlock (GEGL_TILE_BACKEND_FILE (backend));
+ if(0)g_mutex_unlock (buffer->tile_storage->mutex);
return TRUE;
}
#endif
diff --git a/gegl/buffer/gegl-cache.c b/gegl/buffer/gegl-cache.c
index c50449b..8691051 100644
--- a/gegl/buffer/gegl-cache.c
+++ b/gegl/buffer/gegl-cache.c
@@ -33,6 +33,9 @@
#include "gegl-cache.h"
#include "gegl-region.h"
+#if ENABLE_MP
+static GStaticRecMutex mutex = G_STATIC_REC_MUTEX_INIT;
+#endif
enum
{
@@ -367,6 +370,9 @@ void
gegl_cache_invalidate (GeglCache *self,
const GeglRectangle *roi)
{
+#if ENABLE_MP
+ g_static_rec_mutex_lock (&mutex);
+#endif
#if 0
if (roi)
{
@@ -399,6 +405,9 @@ gegl_cache_invalidate (GeglCache *self,
g_signal_emit (self, gegl_cache_signals[INVALIDATED], 0,
&rect, NULL);
}
+#if ENABLE_MP
+ g_static_rec_mutex_unlock (&mutex);
+#endif
}
void
@@ -408,6 +417,12 @@ gegl_cache_computed (GeglCache *self,
g_return_if_fail (GEGL_IS_CACHE (self));
g_return_if_fail (rect != NULL);
+#if ENABLE_MP
+ g_static_rec_mutex_lock (&mutex);
+#endif
gegl_region_union_with_rect (self->valid_region, rect);
g_signal_emit (self, gegl_cache_signals[COMPUTED], 0, rect, NULL);
+#if ENABLE_MP
+ g_static_rec_mutex_unlock (&mutex);
+#endif
}
diff --git a/gegl/buffer/gegl-sampler.c b/gegl/buffer/gegl-sampler.c
index 887582c..8b9872c 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -34,10 +34,6 @@
#include "gegl-sampler-sharp.h"
#include "gegl-sampler-yafr.h"
-#if ENABLE_MP
-GStaticRecMutex mutex = G_STATIC_REC_MUTEX_INIT;
-#endif
-
enum
{
PROP_0,
diff --git a/gegl/buffer/gegl-tile-backend.c b/gegl/buffer/gegl-tile-backend.c
index ce5c4a0..2222aae 100644
--- a/gegl/buffer/gegl-tile-backend.c
+++ b/gegl/buffer/gegl-tile-backend.c
@@ -115,13 +115,13 @@ constructor (GType type,
g_assert (backend->tile_width > 0 && backend->tile_height > 0);
g_assert (backend->format);
+
backend->px_size = babl_format_get_bytes_per_pixel (backend->format);
backend->tile_size = backend->tile_width * backend->tile_height * backend->px_size;
return object;
}
-
static void
gegl_tile_backend_class_init (GeglTileBackendClass *klass)
{
diff --git a/gegl/buffer/gegl-tile-handler-cache.c b/gegl/buffer/gegl-tile-handler-cache.c
index 268706a..5910f08 100644
--- a/gegl/buffer/gegl-tile-handler-cache.c
+++ b/gegl/buffer/gegl-tile-handler-cache.c
@@ -30,12 +30,17 @@
#include "gegl-tile-handler-cache.h"
#include "gegl-debug.h"
+#if ENABLE_MP
+static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+#endif
+
struct _GeglTileHandlerCache
{
GeglTileHandler parent_instance;
GSList *free_list;
};
+
G_DEFINE_TYPE (GeglTileHandlerCache, gegl_tile_handler_cache, GEGL_TYPE_TILE_HANDLER)
typedef struct CacheItem
@@ -51,8 +56,10 @@ typedef struct CacheItem
static GQueue *cache_queue = NULL;
static GHashTable *cache_ht = NULL;
static gint cache_wash_percentage = 20;
+#if 0
static gint cache_hits = 0;
static gint cache_misses = 0;
+#endif
static gint cache_total = 0; /* approximate amount of bytes stored */
@@ -157,7 +164,8 @@ static void
gegl_tile_handler_cache_dispose_buffer_tiles (gpointer itm,
gpointer userdata)
{
- CacheItem *item = itm;
+ CacheItem *item;
+ item = itm;
if (item->handler == userdata)
{
GeglTileHandlerCache *cache = userdata;
@@ -173,6 +181,9 @@ dispose (GObject *object)
CacheItem *item;
GSList *iter;
+#ifdef ENABLE_MP
+ g_static_mutex_lock (&mutex);
+#endif
cache = GEGL_TILE_HANDLER_CACHE (object);
/* only throw out items belonging to this cache instance */
@@ -193,6 +204,9 @@ dispose (GObject *object)
}
g_slist_free (cache->free_list);
cache->free_list = NULL;
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
G_OBJECT_CLASS (gegl_tile_handler_cache_parent_class)->dispose (object);
}
@@ -210,10 +224,14 @@ get_tile (GeglTileSource *tile_store,
tile = gegl_tile_handler_cache_get_tile (cache, x, y, z);
if (tile)
{
+#if 0
cache_hits++;
+#endif
return tile;
}
+#if 0
cache_misses++;
+#endif
if (source)
tile = gegl_tile_source_get_tile (source, x, y, z);
@@ -350,19 +368,27 @@ gegl_tile_handler_cache_get_tile (GeglTileHandlerCache *cache,
CacheItem *result;
CacheItem pin;
- GList *link;
pin.x = x;
pin.y = y;
pin.z = z;
pin.handler = cache;
+#ifdef ENABLE_MP
+ g_static_mutex_lock (&mutex);
+#endif
result = g_hash_table_lookup (cache_ht, &pin);
if (result)
{
g_queue_remove (cache_queue, result);
g_queue_push_head (cache_queue, result);
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
return g_object_ref (result->tile);
}
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
return NULL;
}
@@ -386,7 +412,12 @@ gegl_tile_handler_cache_has_tile (GeglTileHandlerCache *cache,
static gboolean
gegl_tile_handler_cache_trim (GeglTileHandlerCache *cache)
{
- CacheItem *last_writable = g_queue_pop_tail (cache_queue);
+ CacheItem *last_writable;
+
+#ifdef ENABLE_MP
+ g_static_mutex_lock (&mutex);
+#endif
+ last_writable = g_queue_pop_tail (cache_queue);
if (last_writable != NULL)
{
@@ -394,8 +425,14 @@ gegl_tile_handler_cache_trim (GeglTileHandlerCache *cache)
cache_total -= last_writable->tile->size;
g_object_unref (last_writable->tile);
g_slice_free (CacheItem, last_writable);
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
return TRUE;
}
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
return FALSE;
}
@@ -408,6 +445,9 @@ gegl_tile_handler_cache_invalidate (GeglTileHandlerCache *cache,
{
GList *link;
+#ifdef ENABLE_MP
+ g_static_mutex_lock (&mutex);
+#endif
for (link = g_queue_peek_head_link (cache_queue); link; link = link->next)
{
CacheItem *item = link->data;
@@ -426,9 +466,15 @@ gegl_tile_handler_cache_invalidate (GeglTileHandlerCache *cache,
g_hash_table_remove (cache_ht, item);
g_slice_free (CacheItem, item);
g_queue_delete_link (cache_queue, link);
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
return;
}
}
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
}
@@ -443,6 +489,9 @@ gegl_tile_handler_cache_void (GeglTileHandlerCache *cache,
if (!cache_queue)
return;
+#ifdef ENABLE_MP
+ g_static_mutex_lock (&mutex);
+#endif
for (link = g_queue_peek_head_link (cache_queue); link; link = link->next)
{
CacheItem *item = link->data;
@@ -455,14 +504,20 @@ gegl_tile_handler_cache_void (GeglTileHandlerCache *cache,
item->handler == cache)
{
gegl_tile_void (tile);
- cache_total -= item->tile->size;
+ cache_total -= item->tile->size;
g_object_unref (tile);
g_hash_table_remove (cache_ht, item);
g_slice_free (CacheItem, item);
g_queue_delete_link (cache_queue, link);
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
return;
}
}
+#ifdef ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
}
void
@@ -480,8 +535,11 @@ gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
item->x = x;
item->y = y;
item->z = z;
- cache_total += item->tile->size;
+#if ENABLE_MP
+ g_static_mutex_lock (&mutex);
+#endif
+ cache_total += item->tile->size;
g_queue_push_head (cache_queue, item);
count = g_queue_get_length (cache_queue);
@@ -493,4 +551,7 @@ gegl_tile_handler_cache_insert (GeglTileHandlerCache *cache,
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));*/
gegl_tile_handler_cache_trim (cache);
}
+#if ENABLE_MP
+ g_static_mutex_unlock (&mutex);
+#endif
}
diff --git a/gegl/buffer/gegl-tile-storage.c b/gegl/buffer/gegl-tile-storage.c
index a4d9848..badb283 100644
--- a/gegl/buffer/gegl-tile-storage.c
+++ b/gegl/buffer/gegl-tile-storage.c
@@ -273,6 +273,7 @@ gegl_tile_storage_constructor (GType type,
tile_storage,
NULL);
tile_storage->seen_zoom = FALSE;
+ tile_storage->mutex = g_mutex_new ();
return object;
}
@@ -287,6 +288,7 @@ gegl_tile_storage_finalize (GObject *object)
if (self->path)
g_free (self->path);
+ g_mutex_free (self->mutex);
(*G_OBJECT_CLASS (parent_class)->finalize)(object);
}
diff --git a/gegl/buffer/gegl-tile-storage.h b/gegl/buffer/gegl-tile-storage.h
index 7af3fe2..f20fa86 100644
--- a/gegl/buffer/gegl-tile-storage.h
+++ b/gegl/buffer/gegl-tile-storage.h
@@ -32,6 +32,7 @@ struct _GeglTileStorage
{
GeglTileHandlerChain parent_instance;
+ GMutex *mutex;
Babl *format;
gint tile_width;
gint tile_height;
diff --git a/gegl/buffer/gegl-tile.c b/gegl/buffer/gegl-tile.c
index 4e0febc..39b45d7 100644
--- a/gegl/buffer/gegl-tile.c
+++ b/gegl/buffer/gegl-tile.c
@@ -139,6 +139,7 @@ dispose (GObject *object)
}
}
+//#define ENABLE_MP 1
#if ENABLE_MP
if (tile->mutex)
{
@@ -213,7 +214,19 @@ gegl_tile_dup (GeglTile *src)
tile->next_shared = src->next_shared;
src->next_shared = tile;
tile->prev_shared = src;
+#if ENABLE_MP
+ if (tile->next_shared != src)
+ {
+ g_mutex_lock (tile->next_shared->mutex);
+ }
+#endif
tile->next_shared->prev_shared = tile;
+#if ENABLE_MP
+ if (tile->next_shared != src)
+ {
+ g_mutex_unlock (tile->next_shared->mutex);
+ }
+#endif
return tile;
}
@@ -254,22 +267,27 @@ gegl_tile_unclone (GeglTile *tile)
tile->next_shared = tile;
}
}
-
+#if 0
static gint total_locks = 0;
static gint total_unlocks = 0;
+#endif
+
+void gegl_bt (void);
void
gegl_tile_lock (GeglTile *tile)
{
+#if ENABLE_MP
+ g_mutex_lock (tile->mutex);
+#endif
+
if (tile->lock != 0)
{
- g_print ("hm\n");
g_warning ("strange tile lock count: %i", tile->lock);
+ gegl_bt ();
}
+#if 0
total_locks++;
-
-#if ENABLE_MP
- g_mutex_lock (tile->mutex);
#endif
tile->lock++;
@@ -309,7 +327,9 @@ gegl_tile_void_pyramid (GeglTile *tile)
void
gegl_tile_unlock (GeglTile *tile)
{
+#if 0
total_unlocks++;
+#endif
if (tile->lock == 0)
{
g_warning ("unlocked a tile with lock count == 0");
diff --git a/gegl/gegl-instrument.c b/gegl/gegl-instrument.c
index 1292b67..2683274 100644
--- a/gegl/gegl-instrument.c
+++ b/gegl/gegl-instrument.c
@@ -104,6 +104,8 @@ gegl_instrument (const gchar *parent_name,
Timing *iter;
Timing *parent;
+ return;
+
if (root == NULL)
{
root = g_slice_new0 (Timing);
diff --git a/gegl/graph/gegl-node.c b/gegl/graph/gegl-node.c
index 6c7eda0..aee71af 100644
--- a/gegl/graph/gegl-node.c
+++ b/gegl/graph/gegl-node.c
@@ -69,7 +69,7 @@ struct _GeglNodePrivate
GeglNode *parent;
gchar *name;
GeglProcessor *processor;
- GeglEvalMgr *eval_mgr;
+ GeglEvalMgr *eval_mgr[16];
GHashTable *contexts;
};
@@ -198,6 +198,9 @@ gegl_node_init (GeglNode *self)
self->operation = NULL;
self->is_graph = FALSE;
self->cache = NULL;
+#if ENABLE_MP
+ self->mutex = g_mutex_new ();
+#endif
}
@@ -230,11 +233,15 @@ gegl_node_dispose (GObject *gobject)
self->cache = NULL;
}
- if (self->priv->eval_mgr)
- {
- g_object_unref (self->priv->eval_mgr);
- self->priv->eval_mgr = NULL;
- }
+ {
+ gint i;
+ for (i=0; i<4; i++)
+ if (self->priv->eval_mgr[i])
+ {
+ g_object_unref (self->priv->eval_mgr[i]);
+ self->priv->eval_mgr[i] = NULL;
+ }
+ }
if (self->priv->processor)
{
@@ -273,6 +280,9 @@ gegl_node_finalize (GObject *gobject)
g_free (self->priv->name);
}
g_hash_table_destroy (self->priv->contexts);
+#if ENABLE_MP
+ g_mutex_free (self->mutex);
+#endif
G_OBJECT_CLASS (gegl_node_parent_class)->finalize (gobject);
}
@@ -811,10 +821,11 @@ gegl_node_link_many (GeglNode *source,
}
static void gegl_node_ensure_eval_mgr (GeglNode *self,
- const gchar *pad)
+ const gchar *pad,
+ gint no)
{
- if (!self->priv->eval_mgr)
- self->priv->eval_mgr = gegl_eval_mgr_new (self, pad);
+ if (!self->priv->eval_mgr[no])
+ self->priv->eval_mgr[no] = gegl_eval_mgr_new (self, pad);
}
/* Will set the eval_mgr's roi to the supplied roi if defined, otherwise
@@ -824,24 +835,78 @@ static void gegl_node_ensure_eval_mgr (GeglNode *self,
static GeglBuffer *
gegl_node_apply_roi (GeglNode *self,
const gchar *output_pad_name,
- const GeglRectangle *roi)
+ const GeglRectangle *roi,
+ gint tid)
{
+ /* This is a potential spot to multiplex paralell processing,
+ * doing so, might cause a lot of tile overlap between
+ * processes if were not careful (wouldn't neccesarily be totally
+ * bad if that happens though.
+ */
GeglBuffer *buffer;
- gegl_node_ensure_eval_mgr (self, output_pad_name);
+ //g_print ("%i %i %i %i %i\n", tid, roi->x, roi->y, roi->width, roi->height);
if (roi)
{
- self->priv->eval_mgr->roi = *roi;
+ self->priv->eval_mgr[tid]->roi = *roi;
}
else
{
- self->priv->eval_mgr->roi = gegl_node_get_bounding_box (self);
+ self->priv->eval_mgr[tid]->roi = gegl_node_get_bounding_box (self);
}
- buffer = gegl_eval_mgr_apply (self->priv->eval_mgr);
+ buffer = gegl_eval_mgr_apply (self->priv->eval_mgr[tid]);
return buffer;
}
+
+#if ENABLE_MP
+typedef struct ThreadData
+{
+ GeglNode *node;
+ gint tid;
+ GeglRectangle roi;
+ const gchar *pad;
+
+ const Babl *format;
+ gpointer destination_buf;
+ gint rowstride;
+ GeglBlitFlags flags;
+} ThreadData;
+
+static GThreadPool *pool = NULL;
+static GMutex *mutex = NULL;
+static GCond *cond = NULL;
+static gint remaining_tasks = 0;
+
+static void spawnrender (gpointer data,
+ gpointer foo)
+{
+ ThreadData *td = data;
+ GeglBuffer * buffer;
+ buffer = gegl_node_apply_roi (td->node, td->pad, &td->roi, td->tid);
+
+ if ((buffer ) && td->destination_buf)
+ {
+ gegl_buffer_get (buffer, 1.0, &td->roi, td->format, td->destination_buf, td->rowstride);
+ }
+
+ /* and unrefing to ultimately clean it off from the graph */
+ if (buffer)
+ g_object_unref (buffer);
+
+ g_mutex_lock (mutex);
+ remaining_tasks --;
+ if (remaining_tasks == 0)
+ {
+ /* we were the last task, we're not busy rendering any more */
+ g_cond_signal (cond);
+ }
+ g_mutex_unlock (mutex);
+}
+#endif
+
+
void
gegl_node_blit (GeglNode *self,
gdouble scale,
@@ -851,24 +916,112 @@ gegl_node_blit (GeglNode *self,
gint rowstride,
GeglBlitFlags flags)
{
+ gint threads;
g_return_if_fail (GEGL_IS_NODE (self));
g_return_if_fail (roi != NULL);
+ threads = 2; /* tunable here for now, should be picked up through GeglConfig */
+#if ENABLE_MP
+ if (pool == NULL)
+ {
+ pool = g_thread_pool_new (spawnrender, NULL, threads, TRUE, NULL);
+ mutex = g_mutex_new ();
+ cond = g_cond_new ();
+ }
+
#if 0
if (flags == GEGL_BLIT_DEFAULT)
flags = GEGL_BLIT_CACHE;
#endif
- /* temporarily made blit use caching, but render
- * blocking, this to be able to have less coupling
- * with the processor
- */
-#if 1
+ flags = GEGL_BLIT_DEFAULT; /* force all rendering through this path,
+ * to have less code to worry about making
+ * multi thread safe
+ */
if (flags == GEGL_BLIT_DEFAULT)
{
+ ThreadData data[16];
+ gint i;
+
+ /* Subdivide along the largest of width/height, this should be further
+ * extended similar to the subdivizion done in GeglProcessor, to get as
+ * square as possible subregions.
+ */
+ gboolean horizontal = roi->width > roi->height;
+
+ gint rowskip = 0;
+
+ if (!format)
+ format = babl_format ("RGBA float"); /* XXX: This probably duplicates
+ another hardcoded format, they
+ should be turned into a
+ constant. */
+ if (horizontal)
+ rowskip = (roi->width/threads) * babl_format_get_bytes_per_pixel (format);
+
+ if (rowstride == GEGL_AUTO_ROWSTRIDE)
+ rowstride = roi->width * babl_format_get_bytes_per_pixel (format);
+
+ data[0].node = self;
+ data[0].pad = "output";
+ data[0].format = format;
+ data[0].destination_buf = destination_buf;
+ data[0].rowstride = rowstride;
+ data[0].flags = flags;
+
+ for (i=0;i<threads;i++)
+ {
+ data[i] = data[0];
+ data[i].roi = *roi;
+ gegl_node_ensure_eval_mgr (self, "output", i);
+ if (horizontal)
+ {
+ data[i].roi.width = roi->width / threads;
+ data[i].roi.x = roi->x + roi->width/threads * i;
+ }
+ else
+ {
+ data[i].roi.height = roi->height / threads;
+ data[i].roi.y = roi->y + roi->height/threads * i;
+ }
+
+ data[i].tid = i;
+ if (horizontal)
+ data[i].destination_buf = ((gchar*)destination_buf + rowskip * i);
+ else
+ data[i].destination_buf = ((gchar*)destination_buf + rowstride * (roi->height/threads) * i);
+ }
+ if (horizontal)
+ data[threads-1].roi.width = roi->width - (roi->width / threads)*(threads-1);
+ else
+ data[threads-1].roi.height = roi->height - (roi->height / threads)*(threads-1);
+
+ remaining_tasks+=threads;
+
+ if (threads==1)
+ {
+ for (i=0; i<threads; i++)
+ spawnrender (&data[i], NULL);
+ }
+ else
+ {
+ for (i=0; i<threads-1; i++)
+ g_thread_pool_push (pool, &data[i], NULL);
+ spawnrender (&data[threads-1], NULL);
+
+ g_mutex_lock (mutex);
+ while (remaining_tasks!=0)
+ g_cond_wait (cond, mutex);
+ g_mutex_unlock (mutex);
+ }
+ }
+#else
+ if (flags == GEGL_BLIT_DEFAULT)
+ {
GeglBuffer *buffer;
- buffer = gegl_node_apply_roi (self, "output", roi);
+ gegl_node_ensure_eval_mgr (self, "output", 0);
+ buffer = gegl_node_apply_roi (self, "output", roi, 0);
if (buffer && destination_buf)
{
if (destination_buf)
@@ -886,9 +1039,8 @@ gegl_node_blit (GeglNode *self,
if (buffer)
g_object_unref (buffer);
}
- else
#endif
-
+ else /* these code paths currently not used */
if ((flags & GEGL_BLIT_CACHE) ||
(flags & GEGL_BLIT_DIRTY))
{
@@ -908,7 +1060,6 @@ gegl_node_blit (GeglNode *self,
}
}
-
GSList *
gegl_node_get_depends_on (GeglNode *self)
{
@@ -1599,7 +1750,7 @@ gegl_node_process (GeglNode *self)
input = gegl_node_get_producer (self, "input", NULL);
defined = gegl_node_get_bounding_box (input);
- buffer = gegl_node_apply_roi (input, "output", &defined);
+ buffer = gegl_node_apply_roi (input, "output", &defined, 3);
g_assert (GEGL_IS_BUFFER (buffer));
context = gegl_node_add_context (self, &defined);
@@ -1626,12 +1777,17 @@ gegl_node_get_context (GeglNode *self,
gpointer context_id)
{
GeglOperationContext *context = NULL;
+#if ENABLE_MP
+ g_mutex_lock (self->mutex);
+#endif
g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
g_return_val_if_fail (context_id != NULL, NULL);
context = g_hash_table_lookup (self->priv->contexts, context_id);
-
+#if ENABLE_MP
+ g_mutex_unlock (self->mutex);
+#endif
return context;
}
@@ -1645,14 +1801,23 @@ gegl_node_remove_context (GeglNode *self,
g_return_if_fail (context_id != NULL);
context = gegl_node_get_context (self, context_id);
+#if ENABLE_MP
+ g_mutex_lock (self->mutex);
+#endif
if (!context)
{
g_warning ("didn't find context %p for %s",
context_id, gegl_node_get_debug_name (self));
+#if ENABLE_MP
+ g_mutex_unlock (self->mutex);
+#endif
return;
}
g_hash_table_remove (self->priv->contexts, context_id);
gegl_operation_context_destroy (context);
+#if ENABLE_MP
+ g_mutex_unlock (self->mutex);
+#endif
}
/* Creates, sets up and returns a new context for the node, or just returns it
@@ -1667,18 +1832,27 @@ gegl_node_add_context (GeglNode *self,
g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
g_return_val_if_fail (context_id != NULL, NULL);
+#if ENABLE_MP
+ g_mutex_lock (self->mutex);
+#endif
context = g_hash_table_lookup (self->priv->contexts, context_id);
if (context)
{
/* silently ignore, since multiple traversals of prepare are done
* to saturate the graph */
+#if ENABLE_MP
+ g_mutex_unlock (self->mutex);
+#endif
return context;
}
context = gegl_operation_context_new ();
context->operation = self->operation;
g_hash_table_insert (self->priv->contexts, context_id, context);
+#if ENABLE_MP
+ g_mutex_unlock (self->mutex);
+#endif
return context;
}
@@ -1825,6 +1999,9 @@ gegl_node_get_cache (GeglNode *node)
GeglPad *pad;
const Babl *format;
+ /* XXX: it should be possible to have cache for other pads than
+ * only "output" pads
+ */
pad = gegl_node_get_pad (node, "output");
g_assert (pad);
format = gegl_pad_get_format (pad);
@@ -1872,7 +2049,7 @@ gegl_node_remove_children (GeglNode *self)
{
GeglNode *child = gegl_node_get_nth_child (self, 0);
- if (child)
+ if (child && GEGL_IS_NODE (child))
gegl_node_remove_child (self, child);
else
break;
@@ -1901,11 +2078,14 @@ gegl_node_remove_child (GeglNode *self,
GeglNode *child)
{
g_return_val_if_fail (GEGL_IS_NODE (self), NULL);
+ if (!GEGL_IS_NODE (child))
+ {
+ g_print ("%p %s\n", child, G_OBJECT_TYPE_NAME (child));
+ }
g_return_val_if_fail (GEGL_IS_NODE (child), NULL);
g_assert (child->priv->parent == self ||
child->priv->parent == NULL);
- g_return_val_if_fail (GEGL_IS_NODE (child), NULL);
self->priv->children = g_slist_remove (self->priv->children, child);
@@ -1917,7 +2097,6 @@ gegl_node_remove_child (GeglNode *self,
g_object_unref (child);
}
-
if (self->priv->children == NULL)
self->is_graph = FALSE;
diff --git a/gegl/graph/gegl-node.h b/gegl/graph/gegl-node.h
index bc45801..97c810b 100644
--- a/gegl/graph/gegl-node.h
+++ b/gegl/graph/gegl-node.h
@@ -75,6 +75,10 @@ struct _GeglNode
/* Whether result is cached or not, inherited by children */
gboolean dont_cache;
+#if ENABLE_MP
+ GMutex *mutex;
+#endif
+
/*< private >*/
GeglNodePrivate *priv;
};
diff --git a/gegl/graph/gegl-visitor.c b/gegl/graph/gegl-visitor.c
index 44fb96d..9e109a3 100644
--- a/gegl/graph/gegl-visitor.c
+++ b/gegl/graph/gegl-visitor.c
@@ -537,5 +537,11 @@ static void
visit_node (GeglVisitor *self,
GeglNode *node)
{
+#if ENABLE_MP
+ g_mutex_lock (node->mutex);
+#endif
self->visits_list = g_slist_prepend (self->visits_list, node);
+#if ENABLE_MP
+ g_mutex_unlock (node->mutex);
+#endif
}
diff --git a/gegl/process/gegl-eval-mgr.c b/gegl/process/gegl-eval-mgr.c
index a575db0..b8a4ab7 100644
--- a/gegl/process/gegl-eval-mgr.c
+++ b/gegl/process/gegl-eval-mgr.c
@@ -179,6 +179,12 @@ gegl_eval_mgr_apply (GeglEvalMgr *self)
/* set up the context's rectangle (breadth first traversal) */
gegl_visitor_reset (self->need_visitor);
+
+ /* should the need rect be moved into the context, making this
+ * part of gegl re-entrable without locking?.. or does that
+ * hamper other useful API that depends on the need_rect to be
+ * in the nodes?
+ */
gegl_visitor_bfs_traverse (self->need_visitor, GEGL_VISITABLE (root));
#if 0
diff --git a/gegl/property-types/gegl-path.c b/gegl/property-types/gegl-path.c
index 9a71312..3896f38 100644
--- a/gegl/property-types/gegl-path.c
+++ b/gegl/property-types/gegl-path.c
@@ -185,15 +185,17 @@ gegl_path_list_append_item (GeglPathList *head,
if (iter)
{
+ /* the +3 is padding, +1 was excpected to be sufficient */
iter->next =
- g_slice_alloc0 (sizeof (gpointer) + sizeof (gchar) + sizeof (gfloat)*2 *(info->n_items+1)/2);
+ g_slice_alloc0 (sizeof (gpointer) + sizeof (gchar) + sizeof (gfloat)*2 *(info->n_items+3)/2);
iter->next->d.type = type;
iter = iter->next;
}
else /* creating new path */
{
+ /* the +3 is padding, +1 was excpected to be sufficient */
head =
- g_slice_alloc0 (sizeof (gpointer) + sizeof (gchar) + sizeof (gfloat)*2 *(info->n_items+1)/2);
+ g_slice_alloc0 (sizeof (gpointer) + sizeof (gchar) + sizeof (gfloat)*2 *(info->n_items+3)/2);
head->d.type = type;
iter=head;
}
@@ -1993,7 +1995,7 @@ static void gegl_path_stamp (GeglBuffer *buffer,
}
g_assert (s.buf);
- gegl_buffer_get (buffer, 1.0, &roi, s.format, s.buf, 0);
+ gegl_buffer_get_unlocked (buffer, 1.0, &roi, s.format, s.buf, 0);
{
gint u, v;
@@ -2031,7 +2033,7 @@ static void gegl_path_stamp (GeglBuffer *buffer,
}
}
}
- gegl_buffer_set (buffer, &roi, s.format, s.buf, 0);
+ gegl_buffer_set_unlocked (buffer, &roi, s.format, s.buf, 0);
}
@@ -2083,8 +2085,7 @@ void gegl_path_stroke (GeglBuffer *buffer,
{
return;
}
- if (gegl_buffer_is_shared (buffer))
- while (!gegl_buffer_try_lock (buffer));
+ gegl_buffer_lock (buffer);
/*gegl_buffer_clear (buffer, &extent);*/
@@ -2163,7 +2164,6 @@ void gegl_path_stroke (GeglBuffer *buffer,
iter=iter->next;
}
- if (gegl_buffer_is_shared (buffer))
gegl_buffer_unlock (buffer);
}
diff --git a/operations/affine/affine.c b/operations/affine/affine.c
index 600a2e8..d65960d 100644
--- a/operations/affine/affine.c
+++ b/operations/affine/affine.c
@@ -132,8 +132,8 @@ GType
gegl_sampler_type_from_interpolation (GeglInterpolation interpolation);
/* ************************* */
-static void
-op_affine_sampler_init (OpAffine *self)
+static GeglSampler *
+op_affine_sampler (OpAffine *self)
{
Babl *format;
GeglSampler *sampler;
@@ -145,6 +145,33 @@ op_affine_sampler_init (OpAffine *self)
interpolation = gegl_buffer_interpolation_from_string (self->filter);
desired_type = gegl_sampler_type_from_interpolation (interpolation);
+ if (interpolation == GEGL_INTERPOLATION_LANCZOS)
+ {
+ sampler = g_object_new (desired_type,
+ "format", format,
+ "lanczos_width", self->lanczos_width,
+ NULL);
+ }
+ else
+ {
+ sampler = g_object_new (desired_type,
+ "format", format,
+ NULL);
+ }
+ return sampler;
+}
+/* XXX: keep a pool of samplers */
+
+#if 0
+static void
+op_affine_sampler_init (OpAffine *self)
+{
+ GType desired_type;
+ GeglInterpolation interpolation;
+
+ interpolation = gegl_buffer_interpolation_from_string (self->filter);
+ desired_type = gegl_sampler_type_from_interpolation (interpolation);
+
if (self->sampler != NULL &&
!G_TYPE_CHECK_INSTANCE_TYPE (self->sampler, desired_type))
{
@@ -153,48 +180,21 @@ op_affine_sampler_init (OpAffine *self)
self->sampler = NULL;
}
- if (self->sampler == NULL)
- {
- if (interpolation == GEGL_INTERPOLATION_LANCZOS)
- {
- sampler = g_object_new (desired_type,
- "format", format,
- "lanczos_width", self->lanczos_width,
- NULL);
- }
- else
- {
- sampler = g_object_new (desired_type,
- "format", format,
- NULL);
- }
- self->sampler = g_object_ref(sampler);
- }
+ self->sampler = op_affine_sampler (self);
}
+#endif
static void
gegl_affine_prepare (GeglOperation *operation)
{
- OpAffine *affine = (OpAffine *) operation;
Babl *format = babl_format ("RaGaBaA float");
- op_affine_sampler_init (affine);
+ /*op_affine_sampler_init (affine);*/
/*gegl_operation_set_format (operation, "input", format);
gegl_operation_set_format (operation, "aux", format); XXX(not used yet) */
gegl_operation_set_format (operation, "output", format);
}
static void
-gegl_affine_finalize (GObject *object)
-{
- OpAffine *affine = (OpAffine *) object;
- if (affine->sampler != NULL)
- {
- g_object_unref(affine->sampler);
- affine->sampler = NULL;
- }
-}
-
-static void
op_affine_class_init (OpAffineClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
@@ -203,7 +203,6 @@ op_affine_class_init (OpAffineClass *klass)
gobject_class->set_property = gegl_affine_set_property;
gobject_class->get_property = gegl_affine_get_property;
- gobject_class->finalize = gegl_affine_finalize;
op_class->get_invalidated_by_change = gegl_affine_get_invalidated_by_change;
op_class->get_bounding_box = gegl_affine_get_bounding_box;
@@ -441,9 +440,9 @@ gegl_affine_get_bounding_box (GeglOperation *op)
GeglRectangle context_rect;
GeglSampler *sampler;
- op_affine_sampler_init (affine);
- sampler = affine->sampler;
+ sampler = op_affine_sampler (OP_AFFINE (op));
context_rect = sampler->context_rect;
+ g_object_unref (sampler);
if (gegl_operation_source_get_bounding_box (op, "input"))
@@ -542,8 +541,9 @@ gegl_affine_get_required_for_output (GeglOperation *op,
gint i;
requested_rect = *region;
- sampler = affine->sampler;
+ sampler = op_affine_sampler (OP_AFFINE (op));
context_rect = sampler->context_rect;
+ g_object_unref (sampler);
gegl_matrix3_copy (inverse, affine->matrix);
gegl_matrix3_invert (inverse);
@@ -595,9 +595,9 @@ gegl_affine_get_invalidated_by_change (GeglOperation *op,
gint i;
GeglRectangle region = *input_region;
- op_affine_sampler_init (affine);
- sampler = affine->sampler;
+ sampler = op_affine_sampler (OP_AFFINE (op));
context_rect = sampler->context_rect;
+ g_object_unref (sampler);
/* invoke child's matrix creation function */
g_assert (klass->create_matrix);
gegl_matrix3_identity (affine->matrix);
@@ -764,15 +764,18 @@ gegl_affine_process (GeglOperation *operation,
else
{
/* for all other cases, do a proper resampling */
+ GeglSampler *sampler;
input = gegl_operation_context_get_source (context, "input");
output = gegl_operation_context_get_target (context, "output");
- g_object_set(affine->sampler, "buffer", input, NULL);
- gegl_sampler_prepare (affine->sampler);
- affine_generic (output, input, affine->matrix, affine->sampler);
- g_object_unref(affine->sampler->buffer);
- affine->sampler->buffer = NULL;
+ sampler = op_affine_sampler (affine);
+ g_object_set(sampler, "buffer", input, NULL);
+ gegl_sampler_prepare (sampler);
+ affine_generic (output, input, affine->matrix, sampler);
+ g_object_unref(sampler->buffer);
+ sampler->buffer = NULL;
+ g_object_unref (sampler);
if (input != NULL)
g_object_unref (input);
diff --git a/operations/affine/affine.h b/operations/affine/affine.h
index 41c09ad..9a1ee31 100644
--- a/operations/affine/affine.h
+++ b/operations/affine/affine.h
@@ -26,7 +26,6 @@ struct _OpAffine
gchar *filter;
gboolean hard_edges;
gint lanczos_width;
- GeglSampler *sampler;
};
typedef struct _OpAffineClass OpAffineClass;
diff --git a/tools/introspect.c b/tools/introspect.c
index ebe54f0..034293a 100644
--- a/tools/introspect.c
+++ b/tools/introspect.c
@@ -449,6 +449,7 @@ gint
stuff (gint argc,
gchar **argv)
{
+ g_thread_init (NULL);
gegl_init (&argc, &argv);
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]