[gegl/gsoc2011-opencl: 9/21] Locking for Tiles



commit 3d973cbd36a0d2d9bef4262ee302621e61c1c0f2
Author: Victor Oliveira <victormatheus gmail com>
Date:   Thu Jun 9 18:42:06 2011 -0300

    Locking for Tiles
    
    I'm basing this code on the gsoc2009 branch.
    The changes create 4 locks in GeglTile, read and write for cpu and opencl, instead of
    the old general one.
    this is necessary because we can't guarantee anymore reading is in sync, because
    we can change data in the gpu without updating the correspondent data in cpu (and vice-versa).

 gegl/buffer/gegl-buffer-access.c     |    4 +-
 gegl/buffer/gegl-buffer-backend.h    |    2 +-
 gegl/buffer/gegl-buffer-iterator.c   |    2 +-
 gegl/buffer/gegl-buffer-linear.c     |    2 +-
 gegl/buffer/gegl-buffer-load.c       |    2 +-
 gegl/buffer/gegl-buffer-private.h    |   30 +++++++-
 gegl/buffer/gegl-buffer.c            |    2 +-
 gegl/buffer/gegl-tile-handler-zoom.c |    2 +-
 gegl/buffer/gegl-tile.c              |  137 +++++++++++++++++++++++++---------
 gegl/buffer/gegl-tile.h              |    3 +-
 10 files changed, 140 insertions(+), 46 deletions(-)
---
diff --git a/gegl/buffer/gegl-buffer-access.c b/gegl/buffer/gegl-buffer-access.c
index 92e7648..c115e62 100644
--- a/gegl/buffer/gegl-buffer-access.c
+++ b/gegl/buffer/gegl-buffer-access.c
@@ -187,7 +187,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;
@@ -470,7 +470,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-backend.h b/gegl/buffer/gegl-buffer-backend.h
index 4d8320e..2256571 100644
--- a/gegl/buffer/gegl-buffer-backend.h
+++ b/gegl/buffer/gegl-buffer-backend.h
@@ -29,10 +29,10 @@ typedef struct _GeglTileBackendPrivate    GeglTileBackendPrivate;
 
 typedef struct _GeglTile                  GeglTile;
 
-
 typedef void   (*GeglTileCallback)       (GeglTile *tile,
                                           gpointer user_data);
 
+typedef enum _GeglTileLockMode            GeglTileLockMode;
 
 #include "gegl-types.h"
 #include "gegl-tile-backend.h"
diff --git a/gegl/buffer/gegl-buffer-iterator.c b/gegl/buffer/gegl-buffer-iterator.c
index 5ef5565..360a2f2 100644
--- a/gegl/buffer/gegl-buffer-iterator.c
+++ b/gegl/buffer/gegl-buffer-iterator.c
@@ -188,7 +188,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 2263b73..82308bd 100644
--- a/gegl/buffer/gegl-buffer-linear.c
+++ b/gegl/buffer/gegl-buffer-linear.c
@@ -151,7 +151,7 @@ gegl_buffer_linear_open (GeglBuffer          *buffer,
       tile = gegl_tile_source_get_tile ((GeglTileSource*) (buffer),
                                         0,0,0);
       g_assert (tile);
-      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 8a7300b..b6f5ae2 100644
--- a/gegl/buffer/gegl-buffer-load.c
+++ b/gegl/buffer/gegl-buffer-load.c
@@ -320,7 +320,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-buffer-private.h b/gegl/buffer/gegl-buffer-private.h
index 2f0510b..306abdb 100644
--- a/gegl/buffer/gegl-buffer-private.h
+++ b/gegl/buffer/gegl-buffer-private.h
@@ -134,6 +134,25 @@ void            gegl_buffer_sampler           (GeglBuffer     *buffer,
 
 
 
+enum _GeglTileLockMode
+{
+  GEGL_TILE_LOCK_NONE         = 0,
+  GEGL_TILE_LOCK_READ         = (1 << 0),
+  GEGL_TILE_LOCK_WRITE        = (1 << 1),
+  GEGL_TILE_LOCK_CL_READ      = (1 << 2),
+  GEGL_TILE_LOCK_CL_WRITE     = (1 << 3),
+  GEGL_TILE_LOCK_READWRITE    = GEGL_TILE_LOCK_READ
+                                | GEGL_TILE_LOCK_WRITE,
+  GEGL_TILE_LOCK_CL_READWRITE = GEGL_TILE_LOCK_CL_READ
+                                | GEGL_TILE_LOCK_CL_WRITE,
+  GEGL_TILE_LOCK_ALL_READ     = GEGL_TILE_LOCK_READ
+                                | GEGL_TILE_LOCK_CL_READ,
+  GEGL_TILE_LOCK_ALL_WRITE    = GEGL_TILE_LOCK_WRITE
+                                | GEGL_TILE_LOCK_CL_WRITE,
+  GEGL_TILE_LOCK_ALL          = GEGL_TILE_LOCK_READWRITE
+                                | GEGL_TILE_LOCK_CL_READWRITE,
+};
+
 /* the instance size of a GeglTile is a bit large, and should if possible be
  * trimmed down
  */
@@ -160,9 +179,17 @@ struct _GeglTile
   guint            stored_rev;  /* what revision was we when we from tile_storage?
                                    (currently set to 1 when loaded from disk */
 
-  gchar            lock;        /* number of times the tile is write locked
+  guint            read_locks;  /* number of times the tile is read locked
+                                 * if lock/unlock are correctly done, it should
+                                   be 0/1, but there is no problem with shared reads
+                                 */
+
+  gchar            write_locks; /* number of times the tile is write locked
                                  * should in theory just have the values 0/1
                                  */
+
+  GeglTileLockMode lock_mode;
+
   GMutex          *mutex;
 
   /* the shared list is a doubly linked circular list */
@@ -182,6 +209,7 @@ struct _GeglTile
 
 #ifndef __GEGL_TILE_C
 #define gegl_tile_get_data(tile)  ((guchar*)((tile)->data))
+#define gegl_tile_get_cl_data(tile)  ((tile)->cl_data))
 #endif // __GEGL_TILE_C
 
 
diff --git a/gegl/buffer/gegl-buffer.c b/gegl/buffer/gegl-buffer.c
index 7c18aef..5434e58 100644
--- a/gegl/buffer/gegl-buffer.c
+++ b/gegl/buffer/gegl-buffer.c
@@ -740,7 +740,7 @@ gegl_buffer_get_tile (GeglTileSource *source,
       {
         if (!tile->tile_storage)
           {
-            gegl_tile_lock (tile);
+            gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
             tile->tile_storage = buffer->tile_storage;
             gegl_tile_unlock (tile);
           }
diff --git a/gegl/buffer/gegl-tile-handler-zoom.c b/gegl/buffer/gegl-tile-handler-zoom.c
index c94cb73..60b034c 100644
--- a/gegl/buffer/gegl-tile-handler-zoom.c
+++ b/gegl/buffer/gegl-tile-handler-zoom.c
@@ -267,7 +267,7 @@ get_tile (GeglTileSource *gegl_tile_source,
         if (zoom->cache)
           gegl_tile_handler_cache_insert (zoom->cache, tile, x, y, z);
       }
-    gegl_tile_lock (tile);
+    gegl_tile_lock (tile, GEGL_TILE_LOCK_WRITE);
 
     for (i = 0; i < 2; i++)
       for (j = 0; j < 2; j++)
diff --git a/gegl/buffer/gegl-tile.c b/gegl/buffer/gegl-tile.c
index cec8eaf..e6faa37 100644
--- a/gegl/buffer/gegl-tile.c
+++ b/gegl/buffer/gegl-tile.c
@@ -103,7 +103,9 @@ gegl_tile_new_bare (void)
   tile->stored_rev = 1;
   tile->rev        = 1;
   tile->cl_rev     = 0;
-  tile->lock       = 0;
+  tile->read_locks  = 0;
+  tile->write_locks = 0;
+  tile->lock_mode   = GEGL_TILE_LOCK_NONE;
   tile->data       = NULL;
   tile->cl_data    = NULL;
 
@@ -162,10 +164,11 @@ gegl_tile_cl_enable (GeglTile *tile,
                      gint height)
 {
   if (gegl_cl_is_accelerated ())
-    // if there is no memory available,
-    // tile->cl_data will be NULL anyway
-    tile->cl_data = gegl_cl_texture_new (width, height);
-
+    {
+      // if there is no memory available,
+      // tile->cl_data will be NULL anyway
+      tile->cl_data = gegl_cl_texture_new (width, height);
+    }
   return (tile->cl_data != NULL);
 }
 
@@ -206,37 +209,76 @@ static gint total_unlocks = 0;
 void gegl_bt (void);
 
 void
-gegl_tile_lock (GeglTile *tile)
+gegl_tile_lock (GeglTile *tile,
+                GeglTileLockMode lock_mode)
 {
-  g_mutex_lock (tile->mutex);
+  if (lock_mode != GEGL_TILE_LOCK_NONE)
+    g_mutex_lock (tile->mutex);
+  else
+    g_warning ("%s called with lock_mode GEGL_TILE_LOCK_NONE", G_STRFUNC);
 
-  if (tile->lock != 0)
+  if (!tile->cl_data)
     {
-      g_warning ("strange tile lock count: %i", tile->lock);
-      gegl_bt ();
+      lock_mode &= ~GEGL_TILE_LOCK_CL_READWRITE;
     }
+
+  if (tile->write_locks != 0)
+    {
+      if (lock_mode & GEGL_TILE_LOCK_ALL_WRITE)
+        {
+          g_warning ("strange tile lock count: %i", tile->write_locks);
+          gegl_bt ();
+        }
+      if (lock_mode & GEGL_TILE_LOCK_ALL_READ)
+        {
+          g_warning ("shouldn't lock for reading while write-lock (%i) is active",
+                     tile->write_locks);
+          gegl_bt ();
+        }
+    }
+
+  if (tile->read_locks > 0)
+    {
+      if (lock_mode & GEGL_TILE_LOCK_ALL_READ)
+        {
+          g_warning ("strange tile lock count: %i", tile->read_locks);
+          gegl_bt ();
+        }
+      if (lock_mode & GEGL_TILE_LOCK_ALL_WRITE)
+        {
+          g_warning ("shouldn't lock for writing while read-lock (%i) is active",
+                     tile->read_locks);
+          gegl_bt ();
+        }
+    }
+
+
 #if 0
   total_locks++;
 #endif
 
-  tile->lock++;
+  if (lock_mode & GEGL_TILE_LOCK_ALL_READ)
+    tile->read_locks++;
+
+  if (lock_mode & GEGL_TILE_LOCK_ALL_WRITE)
+    tile->write_locks++;
+
   /*fprintf (stderr, "global tile locking: %i %i\n", locks, unlocks);*/
 
   gegl_tile_unclone (tile);
 
-  if (gegl_cl_is_accelerated ())
+  if (lock_mode & GEGL_TILE_LOCK_CL_READ && tile->rev > tile->cl_rev)
     {
-      if (tile->rev > tile->cl_rev)
-        {
-          gegl_cl_texture_set (tile->cl_data, tile->data);
-          tile->cl_rev = tile->rev;
-        }
-      else if (tile->cl_rev > tile->rev)
-        {
-          gegl_cl_texture_get (tile->cl_data, tile->data);
-          tile->rev = tile->cl_rev;
-        }
+      gegl_cl_texture_set (tile->cl_data, tile->data);
+      tile->cl_rev = tile->rev;
     }
+  else if (lock_mode & GEGL_TILE_LOCK_READ && tile->cl_rev > tile->rev)
+    {
+      gegl_cl_texture_get (tile->cl_data, tile->data);
+      tile->rev = tile->cl_rev;
+    }
+
+  tile->lock_mode = lock_mode;
 }
 
 static void
@@ -278,27 +320,50 @@ gegl_tile_unlock (GeglTile *tile)
       tile->unlock_notify (tile, tile->unlock_notify_data);
     }
 
-  if (tile->lock == 0)
+  if (tile->lock_mode & GEGL_TILE_LOCK_ALL_WRITE)
     {
-      g_warning ("unlocked a tile with lock count == 0");
-    }
-  tile->lock--;
+      if (tile->write_locks == 0)
+        {
+          g_warning ("unlocked a tile with write-lock count == 0");
+          gegl_bt ();
+        }
+      tile->write_locks--;
 
-  if (tile->lock == 0 &&
-      tile->z == 0)
-    {
-      gegl_tile_void_pyramid (tile);
+      if (tile->write_locks == 0
+        && tile->z == 0)
+        {
+          gegl_tile_void_pyramid (tile);
+        }
+
+      if (tile->write_locks==0)
+        {
+          if (tile->lock_mode & GEGL_TILE_LOCK_CL_WRITE)
+            {
+              tile->cl_rev = MAX(tile->rev, tile->cl_rev)+1; //cl is updated
+              if (tile->lock_mode & GEGL_TILE_LOCK_WRITE)
+                tile->rev = tile->cl_rev; //cl and cpu are in sync
+            }
+          else
+            tile->rev++;
+        }
     }
 
-  if (tile->lock==0)
+  if (tile->lock_mode & GEGL_TILE_LOCK_ALL_READ)
     {
-      if (gegl_cl_is_accelerated ())
-          tile->rev = tile->cl_rev = MAX(tile->rev, tile->cl_rev)+1;
-      else
-          tile->rev++;
+      if (tile->read_locks == 0)
+        {
+          g_warning ("unlocked a tile with read-lock count == 0");
+          gegl_bt ();
+        }
+      tile->read_locks--;
     }
 
-  g_mutex_unlock (tile->mutex);
+  if (tile->lock_mode != GEGL_TILE_LOCK_NONE)
+    g_mutex_unlock (tile->mutex);
+  else
+    g_warning ("%s called with lock_mode GEGL_TILE_LOCK_NONE", G_STRFUNC);
+
+  tile->lock_mode = GEGL_TILE_LOCK_NONE;
 }
 
 
diff --git a/gegl/buffer/gegl-tile.h b/gegl/buffer/gegl-tile.h
index fa1ee32..96477f0 100644
--- a/gegl/buffer/gegl-tile.h
+++ b/gegl/buffer/gegl-tile.h
@@ -30,7 +30,8 @@ void         gegl_tile_unref          (GeglTile         *tile);
 /* lock a tile for writing, this would allow writing to buffers
  * later gotten with get_data()
  */
-void         gegl_tile_lock           (GeglTile         *tile);
+void         gegl_tile_lock           (GeglTile *tile,
+                                       GeglTileLockMode lock_mode);
 
 /* unlock the tile notifying the tile that we're done manipulating
  * the data.



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]