[gegl/gsoc2009-gpu: 7/15] Introduce new tile locking mechanism and minor cosmetic changes
- From: Martin Nordholts <martinn src gnome org>
- To: svn-commits-list gnome org
- Subject: [gegl/gsoc2009-gpu: 7/15] Introduce new tile locking mechanism and minor cosmetic changes
- Date: Wed, 24 Jun 2009 05:38:34 +0000 (UTC)
commit 2eadf30839f683cf4b9e367b3c321fb3d6576dd1
Author: Jerson Michael Perpetua <jersonperpetua gmail com>
Date: Wed Jun 17 01:56:55 2009 +0800
Introduce new tile locking mechanism and minor cosmetic changes
This set of changes enables GeglTiles to lock for both read and
write operations, allowing the tile to synchronize GPU data to/from
the data in system memory. This also contains some minor changes
to most existing files that currently lock the tile when writing. Note
that the latter changes are made to only satisfy the compiler. Support
for read locks will be added to the relevant files in later commits.
Re: cosmetic changes, nothing much really; a few code-style
formatting here and there. And oh, apparently, I forgot to commit the
implementations for both gegl_tile_get_gpu_data() and _get_data()
in previous commits. This commit contains both implementations.
gegl/buffer/gegl-buffer-access.c | 6 +-
gegl/buffer/gegl-buffer-iterator.c | 2 +-
gegl/buffer/gegl-buffer-linear.c | 2 +-
gegl/buffer/gegl-buffer-load.c | 2 +-
gegl/buffer/gegl-tile-handler-zoom.c | 2 +-
gegl/buffer/gegl-tile.c | 201 ++++++++++++++++++++++++++--------
gegl/buffer/gegl-tile.h | 121 +++++++++++++--------
7 files changed, 238 insertions(+), 98 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 5470837..f59a2a9 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -98,7 +98,7 @@ gegl_buffer_pixel_set (GeglBuffer *buffer,
gint offsety = gegl_tile_offset (tiledy, tile_height);
guchar *tp;
- gegl_tile_lock (tile);
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
tp = gegl_tile_get_data (tile) +
(offsety * tile_width + offsetx) * px_size;
if (fish)
@@ -198,7 +198,7 @@ gegl_buffer_set_pixel (GeglBuffer *buffer,
gint offsety = gegl_tile_offset (tiledy, tile_height);
guchar *tp;
- gegl_tile_lock (tile);
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
tp = gegl_tile_get_data (tile) +
(offsety * tile_width + offsetx) * px_size;
@@ -484,7 +484,7 @@ gegl_buffer_iterate (GeglBuffer *buffer,
}
if (write)
- gegl_tile_lock (tile);
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
tile_base = gegl_tile_get_data (tile);
tp = ((guchar *) tile_base) + (offsety * tile_width + offsetx) * px_size;
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 537069f..ca7c712 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -187,7 +187,7 @@ gulp:
0);
if (i->write && tile_width==i->subrect.width)
{
- gegl_tile_lock (i->tile);
+ gegl_tile_lock (i->tile, GEGL_TILE_LOCK_WRITE);
}
i->data = gegl_tile_get_data (i->tile);
diff --git a/gegl/buffer/gegl-buffer-linear.c b/gegl/buffer/gegl-buffer-linear.c
index b908185..30c2089 100644
--- a/gegl/buffer/gegl-buffer-linear.c
+++ b/gegl/buffer/gegl-buffer-linear.c
@@ -152,7 +152,7 @@ gegl_buffer_linear_open (GeglBuffer *buffer,
0,0,0);
g_assert (tile);
gegl_buffer_lock (buffer);
- gegl_tile_lock (tile);
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
g_object_set_data (G_OBJECT (buffer), "linear-tile", tile);
diff --git a/gegl/buffer/gegl-buffer-load.c b/gegl/buffer/gegl-buffer-load.c
index dbf37e0..6e34856 100644
--- a/gegl/buffer/gegl-buffer-load.c
+++ b/gegl/buffer/gegl-buffer-load.c
@@ -401,7 +401,7 @@ gegl_buffer_load (const gchar *path)
g_assert (tile);
- gegl_tile_lock (tile);
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
data = gegl_tile_get_data (tile);
g_assert (data);
diff --git a/gegl/buffer/gegl-tile-handler-zoom.c b/gegl/buffer/gegl-tile-handler-zoom.c
index af126e7..e16b144 100644
--- a/gegl/buffer/gegl-tile-handler-zoom.c
+++ b/gegl/buffer/gegl-tile-handler-zoom.c
@@ -279,7 +279,7 @@ get_tile (GeglTileSource *gegl_tile_source,
}
}
}
- gegl_tile_lock (tile);
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
data = gegl_tile_get_data (tile);
for (i = 0; i < 2; i++)
diff --git a/gegl/buffer/gegl-tile.c b/gegl/buffer/gegl-tile.c
index 22a6f9a..9793ae5 100644
--- a/gegl/buffer/gegl-tile.c
+++ b/gegl/buffer/gegl-tile.c
@@ -38,6 +38,7 @@
#include "gegl-gpu-types.h"
#include "gegl-gpu-texture.h"
+
G_DEFINE_TYPE (GeglTile, gegl_tile, G_TYPE_OBJECT)
enum
{
@@ -139,7 +140,6 @@ dispose (GObject *object)
if (tile->destroy_notify)
tile->destroy_notify (tile->data, tile->gpu_data,
tile->destroy_notify_data);
-
tile->data = NULL;
tile->gpu_data = NULL;
}
@@ -201,9 +201,12 @@ gegl_tile_init (GeglTile *tile)
tile->tile_storage = NULL;
tile->rev = 0;
+ tile->gpu_rev = 0;
tile->stored_rev = 0;
- tile->lock = 0;
+ tile->read_locks = 0;
+ tile->write_locks = 0;
+ tile->lock_mode = GEGL_TILE_LOCK_NONE;
tile->next_shared = tile;
tile->prev_shared = tile;
@@ -227,6 +230,7 @@ gegl_tile_dup (GeglTile *src)
tile->tile_storage = src->tile_storage;
tile->rev = 1;
+ tile->gpu_rev = 1;
tile->stored_rev = 1;
tile->next_shared = src->next_shared;
@@ -238,9 +242,7 @@ gegl_tile_dup (GeglTile *src)
}
GeglTile *
-gegl_tile_new (gint width,
- gint height,
- const Babl *format)
+gegl_tile_new (gint width, gint height, const Babl *format)
{
GeglTile *tile = g_object_new (GEGL_TYPE_TILE, NULL);
@@ -270,6 +272,18 @@ gegl_tile_get_height (GeglTile *tile)
return tile->tile_storage->tile_height;
}
+void *
+gegl_tile_get_data (GeglTile *tile)
+{
+ return tile->data;
+}
+
+GeglGpuTexture *
+gegl_tile_get_gpu_data (GeglTile *tile)
+{
+ return tile->gpu_data;
+}
+
static gpointer
gegl_memdup (gpointer src, gsize size)
{
@@ -296,28 +310,83 @@ gegl_tile_unclone (GeglTile *tile)
}
}
-static gint total_locks = 0;
-static gint total_unlocks = 0;
+static gint total_write_locks = 0;
+static gint total_write_unlocks = 0;
+
+static gint total_read_locks = 0;
+static gint total_read_unlocks = 0;
void
-gegl_tile_lock (GeglTile *tile)
+gegl_tile_lock (GeglTile *tile, GeglTileLockMode lock_mode)
{
- if (tile->lock != 0)
+ if (tile->write_locks > 0)
+ {
+ if (lock_mode & ~GEGL_TILE_LOCK_WRITE
+ || lock_mode & ~GEGL_TILE_LOCK_GPU_WRITE)
+ {
+ g_print ("hm\n");
+ g_warning ("strange tile write-lock count: %i", tile->write_locks);
+ }
+
+ if (lock_mode & ~GEGL_TILE_LOCK_READ
+ || lock_mode & ~GEGL_TILE_LOCK_GPU_READ)
+ g_warning ("shouldn't lock for reading while write-lock (%i) is active",
+ tile->write_locks);
+ }
+
+ if (tile->read_locks > 0)
{
- g_print ("hm\n");
- g_warning ("strange tile lock count: %i", tile->lock);
+ if (lock_mode & ~GEGL_TILE_LOCK_READ
+ || lock_mode & ~GEGL_TILE_LOCK_GPU_READ)
+ {
+ g_print ("hm\n");
+ g_warning ("strange tile read-lock count: %i", tile->read_locks);
+ }
+
+ if (lock_mode & ~GEGL_TILE_LOCK_WRITE
+ || lock_mode & ~GEGL_TILE_LOCK_GPU_WRITE)
+ g_warning ("shouldn't lock for writing while read-lock (%i) is active",
+ tile->read_locks);
}
- total_locks++;
#if ENABLE_MP
- g_mutex_lock (tile->mutex);
+ g_static_mutex_lock (tile->mutex);
#endif
- tile->lock++;
- /*fprintf (stderr, "global tile locking: %i %i\n", locks, unlocks);*/
+ if (lock_mode & ~GEGL_TILE_LOCK_READ
+ || lock_mode & ~GEGL_TILE_LOCK_GPU_READ)
+ {
+ tile->read_locks++;
+ total_read_locks++;
+ }
+
+ if (lock_mode & ~GEGL_TILE_LOCK_WRITE
+ || lock_mode & ~GEGL_TILE_LOCK_GPU_WRITE)
+ {
+ tile->write_locks++;
+ total_write_locks++;
+
+ /*fprintf (stderr, "global tile locking: %i %i\n", locks, unlocks);*/
+ gegl_tile_unclone (tile);
+ /*gegl_buffer_add_dirty (tile->buffer, tile->x, tile->y);*/
+ }
+
+ if (lock_mode & ~GEGL_TILE_LOCK_GPU_READ && tile->rev > tile->gpu_rev)
+ {
+ gegl_gpu_texture_set (tile->gpu_data, NULL, tile->data,
+ gegl_tile_get_format (tile));
+
+ tile->gpu_rev = tile->rev;
+ }
- gegl_tile_unclone (tile);
- /*gegl_buffer_add_dirty (tile->buffer, tile->x, tile->y);*/
+ if (lock_mode & ~GEGL_TILE_LOCK_READ && tile->gpu_rev > tile->rev)
+ {
+ gegl_gpu_texture_get (tile->gpu_data, NULL, tile->data,
+ gegl_tile_get_format (tile));
+
+ tile->rev = tile->gpu_rev;
+ }
+ tile->lock_mode = lock_mode;
}
static void
@@ -337,7 +406,7 @@ gegl_tile_void_pyramid (GeglTile *tile)
{
if (tile->tile_storage &&
tile->tile_storage->seen_zoom &&
- tile->z == 0) /* we only accepting voiding the base level */
+ tile->z == 0) /* we only accept voiding the base level */
{
_gegl_tile_void_pyramid (GEGL_TILE_SOURCE (tile->tile_storage),
tile->x/2,
@@ -350,37 +419,60 @@ gegl_tile_void_pyramid (GeglTile *tile)
void
gegl_tile_unlock (GeglTile *tile)
{
- total_unlocks++;
- if (tile->lock == 0)
+ if (tile->lock_mode & ~GEGL_TILE_LOCK_WRITE
+ || tile->lock_mode & ~GEGL_TILE_LOCK_GPU_WRITE)
{
- g_warning ("unlocked a tile with lock count == 0");
+ total_write_unlocks++;
+
+ if (tile->write_locks == 0)
+ g_warning ("unlocked a tile with write-lock count == 0");
+ tile->write_locks--;
+
+ if (tile->write_locks == 0)
+ {
+ guint rev = tile->rev;
+ guint gpu_rev = tile->gpu_rev;
+
+ if (tile->lock_mode & ~GEGL_TILE_LOCK_GPU_WRITE)
+ tile->gpu_rev = MAX (gpu_rev, rev) + 1;
+
+ if (tile->lock_mode & ~GEGL_TILE_LOCK_WRITE)
+ tile->rev = MAX (rev, gpu_rev) + 1;
+
+ /* TODO: examine how this can be improved with h/w mipmaps */
+ if (tile->z == 0)
+ gegl_tile_void_pyramid (tile);
+ }
}
- tile->lock--;
- if (tile->lock == 0 &&
- tile->z == 0)
+
+ if (tile->lock_mode & ~GEGL_TILE_LOCK_READ
+ || tile->lock_mode & ~GEGL_TILE_LOCK_GPU_READ)
{
- gegl_tile_void_pyramid (tile);
+ total_read_unlocks++;
+
+ if (tile->read_locks == 0)
+ g_warning ("unlocked a tile with read-lock count == 0");
+ tile->read_locks--;
}
- if (tile->lock==0)
- tile->rev++;
#if ENABLE_MP
g_mutex_unlock (tile->mutex);
#endif
+ tile->lock_mode = GEGL_TILE_LOCK_NONE;
}
-
gboolean
gegl_tile_is_stored (GeglTile *tile)
{
- return tile->stored_rev == tile->rev;
+ return tile->stored_rev == MAX (tile->rev, tile->gpu_rev);
}
void
gegl_tile_void (GeglTile *tile)
{
- tile->stored_rev = tile->rev;
+ tile->stored_rev = MAX (tile->rev, tile->gpu_rev);
tile->tile_storage = NULL;
- if (tile->z==0)
+
+ if (tile->z == 0)
gegl_tile_void_pyramid (tile);
}
@@ -388,10 +480,13 @@ void
gegl_tile_cpy (GeglTile *src,
GeglTile *dst)
{
- gegl_tile_lock (dst);
+ gegl_tile_lock (src, GEGL_TILE_LOCK_ALL_READ);
+ gegl_tile_lock (dst, GEGL_TILE_LOCK_ALL_WRITE);
gegl_free (dst->data);
dst->data = NULL;
+ gegl_gpu_texture_free (dst->gpu_data);
+ dst->gpu_data = NULL;
dst->next_shared = src->next_shared;
src->next_shared = dst;
@@ -399,15 +494,21 @@ gegl_tile_cpy (GeglTile *src,
dst->next_shared->prev_shared = dst;
dst->data = src->data;
+ dst->gpu_data = src->gpu_data;
gegl_tile_unlock (dst);
+ gegl_tile_unlock (src);
}
void
gegl_tile_swp (GeglTile *a,
GeglTile *b)
{
- guchar *tmp;
+ guchar *tmp_data;
+ GeglGpuTexture *tmp_gpu_data;
+
+ gegl_tile_lock (a, GEGL_TILE_LOCK_ALL);
+ gegl_tile_lock (b, GEGL_TILE_LOCK_ALL);
gegl_tile_unclone (a);
gegl_tile_unclone (b);
@@ -417,24 +518,36 @@ gegl_tile_swp (GeglTile *a,
g_assert (a->size == b->size);
- tmp = a->data;
- a->data = b->data;
- b->data = tmp;
+ tmp_data = a->data;
+ a->data = b->data;
+ b->data = tmp_data;
+
+ tmp_gpu_data = a->gpu_data;
+ a->gpu_data = b->gpu_data;
+ b->gpu_data = tmp_gpu_data;
+
+ gegl_tile_unlock (a);
+ gegl_tile_unlock (b);
}
gboolean gegl_tile_store (GeglTile *tile)
{
+ gboolean stored;
+
if (gegl_tile_is_stored (tile))
return TRUE;
+
if (tile->tile_storage == NULL)
return FALSE;
- return gegl_tile_source_set_tile (GEGL_TILE_SOURCE (tile->tile_storage),
- tile->x,
- tile->y,
- tile->z,
- tile);
-}
-
-
+ gegl_tile_lock (tile, GEGL_TILE_LOCK_ALL_READ);
+ stored = gegl_tile_source_set_tile (GEGL_TILE_SOURCE (tile->tile_storage),
+ tile->x,
+ tile->y,
+ tile->z,
+ tile);
+ gegl_tile_unlock (tile);
+ /* XXX: shouldn't the revision numbers be updated just about here? */
+ return stored;
+}
diff --git a/gegl/buffer/gegl-tile.h b/gegl/buffer/gegl-tile.h
index 7736e4a..997213a 100644
--- a/gegl/buffer/gegl-tile.h
+++ b/gegl/buffer/gegl-tile.h
@@ -31,6 +31,24 @@
#define GEGL_IS_TILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEGL_TYPE_TILE))
#define GEGL_TILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEGL_TYPE_TILE, GeglTileClass))
+typedef enum
+{
+ GEGL_TILE_LOCK_NONE,
+ GEGL_TILE_LOCK_READ = (1 << 1),
+ GEGL_TILE_LOCK_WRITE = (1 << 2),
+ GEGL_TILE_LOCK_GPU_READ = (1 << 3),
+ GEGL_TILE_LOCK_GPU_WRITE = (1 << 4),
+ GEGL_TILE_LOCK_READWRITE = GEGL_TILE_LOCK_READ
+ | GEGL_TILE_LOCK_WRITE,
+ GEGL_TILE_LOCK_GPU_READWRITE = GEGL_TILE_LOCK_GPU_READ
+ | GEGL_TILE_LOCK_GPU_WRITE,
+ GEGL_TILE_LOCK_ALL_READ = GEGL_TILE_LOCK_READ
+ | GEGL_TILE_LOCK_GPU_READ,
+ GEGL_TILE_LOCK_ALL_WRITE = GEGL_TILE_LOCK_WRITE
+ | GEGL_TILE_LOCK_GPU_WRITE,
+ GEGL_TILE_LOCK_ALL = GEGL_TILE_LOCK_ALL_READ
+ | GEGL_TILE_LOCK_ALL_WRITE
+} GeglTileLockMode;
/* the instance size of a GeglTile is a bit large, and should if possible be
* trimmed down
@@ -39,25 +57,36 @@ struct _GeglTile
{
GObject parent_instance;
- guchar *data; /* actual pixel data for tile, a linear buffer*/
- gint size; /* The size of the linear buffer */
- GeglGpuTexture *gpu_data; /* pixel data for tile, stored in the GPU */
+ guchar *data; /* actual pixel data for tile,
+ * a linear buffer
+ */
+ gint size; /* The size of the linear buffer */
+ GeglGpuTexture *gpu_data; /* pixel data for tile, stored in the GPU */
GeglTileStorage *tile_storage; /* the buffer from which this tile was
- * retrieved needed for the tile to be able to
- * store itself back (for instance when it is
- * unreffed for the last time)
+ * retrieved, needed for the tile to be able
+ * to store itself back (for instance when it
+ * is unreffed for the last time)
*/
gint x, y, z;
+ guint rev; /* this tile's revision */
+ guint gpu_rev; /* this tile's GPU data revision */
+ guint stored_rev; /* what revision was the tile when it was
+ * committed to the tile_storage? (currently
+ * set to 1 when loaded from disk)
+ */
- guint rev; /* this tile revision */
- guint stored_rev; /* what revision was we when we from tile_storage?
- (currently set to 1 when loaded from disk */
+ guint read_locks; /* number of times the tile is read-locked,
+ * should in theory just have the values 0/1,
+ * note that we might want to have shared
+ * reads though (not yet implemented)
+ */
+ gchar write_locks; /* number of times the tile is write-locked,
+ * should in theory just have the values 0/1
+ */
+ GeglTileLockMode lock_mode;
- gchar lock; /* number of times the tile is write locked
- * should in theory just have the values 0/1
- */
#if ENABLE_MP
GMutex *mutex;
#endif
@@ -70,7 +99,7 @@ struct _GeglTile
GeglGpuTexture *gpu_data,
gpointer data);
- gpointer destroy_notify_data;
+ gpointer destroy_notify_data;
};
struct _GeglTileClass
@@ -78,21 +107,21 @@ struct _GeglTileClass
GObjectClass parent_class;
};
-GType gegl_tile_get_type (void) G_GNUC_CONST;
+GType gegl_tile_get_type (void) G_GNUC_CONST;
-GeglTile *gegl_tile_new (gint width,
- gint height,
- const Babl *format);
+GeglTile *gegl_tile_new (gint width,
+ gint height,
+ const Babl *format);
-void * gegl_tile_get_format (GeglTile *tile);
-gint gegl_tile_get_width (GeglTile *tile);
-gint gegl_tile_get_height (GeglTile *tile);
+void *gegl_tile_get_format (GeglTile *tile);
+gint gegl_tile_get_width (GeglTile *tile);
+gint gegl_tile_get_height (GeglTile *tile);
-
-/* lock a tile for writing, this would allow writing to buffers
- * later gotten with get_data()
+/* lock a tile for access, this would allow access to buffers
+ * later gotten with get_data() or get_gpu_data()
*/
-void gegl_tile_lock (GeglTile *tile);
+void gegl_tile_lock (GeglTile *tile,
+ GeglTileLockMode lock_mode);
/* get a pointer to the linear buffer of the tile */
void *gegl_tile_get_data (GeglTile *tile);
@@ -100,39 +129,37 @@ void *gegl_tile_get_data (GeglTile *tile);
/* get a pointer to the GPU data of the tile */
GeglGpuTexture *gegl_tile_get_gpu_data (GeglTile *tile);
-/* unlock the tile notifying the tile that we're done manipulating
- * the data.
+/* unlock the tile notifying the tile that we're done accessing
+ * the data
*/
-void gegl_tile_unlock (GeglTile *tile);
-
-
+void gegl_tile_unlock (GeglTile *tile);
-gboolean gegl_tile_is_stored (GeglTile *tile);
-gboolean gegl_tile_store (GeglTile *tile);
-void gegl_tile_void (GeglTile *tile);
-GeglTile *gegl_tile_dup (GeglTile *tile);
+gboolean gegl_tile_is_stored (GeglTile *tile);
+gboolean gegl_tile_store (GeglTile *tile);
+void gegl_tile_void (GeglTile *tile);
+GeglTile *gegl_tile_dup (GeglTile *tile);
-/* computes the positive integer remainder (also for negative dividends)
- */
+/* computes the positive integer remainder (also for negative dividends) */
#define GEGL_REMAINDER(dividend, divisor) \
(((dividend) < 0) ? \
- (divisor) - 1 - ((-((dividend) + 1)) % (divisor)) : \
- (dividend) % (divisor))
+ (divisor) - 1 - ((-((dividend) + 1)) % (divisor)) : \
+ (dividend) % (divisor))
-#define gegl_tile_offset(coordinate, stride) GEGL_REMAINDER((coordinate), (stride))
+#define gegl_tile_offset(coordinate, stride) \
+ GEGL_REMAINDER ((coordinate), (stride))
/* helper function to compute tile indices and offsets for coordinates
* based on a tile stride (tile_width or tile_height)
*/
-#define gegl_tile_index(coordinate,stride) \
- (((coordinate) >= 0)?\
- (coordinate) / (stride):\
- ((((coordinate) + 1) /(stride)) - 1))
+#define gegl_tile_indice(coordinate, stride) \
+ (((coordinate) >= 0) ? \
+ (coordinate) / (stride) : \
+ ((((coordinate) + 1) / (stride)) - 1))
/* utility low-level functions used by undo system */
-void gegl_tile_swp (GeglTile *a,
- GeglTile *b);
-void gegl_tile_cpy (GeglTile *src,
- GeglTile *dst);
+void gegl_tile_swp (GeglTile *a,
+ GeglTile *b);
+void gegl_tile_cpy (GeglTile *src,
+ GeglTile *dst);
-#endif
+#endif /* __GEGL_TILE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]