gegl r2289 - in trunk: . gegl/buffer gegl/operation



Author: ok
Date: Fri May 16 17:01:36 2008
New Revision: 2289
URL: http://svn.gnome.org/viewvc/gegl?rev=2289&view=rev

Log:
* gegl/buffer/gegl-buffer-access.c: added gegl_buffer_scan_iterator.
* gegl/buffer/gegl-buffer-private.h: added iterator data structures
for tiles as well as scanlines.
* gegl/buffer/gegl-tile.c: use gegl_malloc for allocating aligned
tile memory.
* gegl/operation/gegl-operation-point-filter.c: make use of scan
iteration when possible between formats.


Modified:
   trunk/ChangeLog
   trunk/gegl/buffer/gegl-buffer-access.c
   trunk/gegl/buffer/gegl-buffer-private.h
   trunk/gegl/buffer/gegl-tile.c
   trunk/gegl/operation/gegl-operation-point-filter.c

Modified: trunk/gegl/buffer/gegl-buffer-access.c
==============================================================================
--- trunk/gegl/buffer/gegl-buffer-access.c	(original)
+++ trunk/gegl/buffer/gegl-buffer-access.c	Fri May 16 17:01:36 2008
@@ -41,6 +41,226 @@
 #endif
 
 
+
+void gegl_buffer_tile_iterator_init (GeglBufferTileIterator *i,
+                                            GeglBuffer             *buffer,
+                                            GeglRectangle           roi,
+                                            gboolean                write)
+{
+  g_assert (i);
+  memset (i, 0, sizeof (GeglBufferTileIterator));
+  i->buffer = buffer;
+  i->roi = roi;
+  i->row    = 0;
+  i->col = 0;
+  i->tile = NULL;
+  i->write = write;
+}
+
+
+GeglBufferTileIterator *
+gegl_buffer_tile_iterator_new (GeglBuffer    *buffer,
+                               GeglRectangle  roi,
+                               gboolean       write)
+{
+  GeglBufferTileIterator *i = g_malloc (sizeof (GeglBufferTileIterator));
+  gegl_buffer_tile_iterator_init (i, buffer, roi, write);
+  return i; 
+}
+
+void gegl_buffer_scan_iterator_init (GeglBufferScanIterator *i,
+                                     GeglBuffer             *buffer,
+                                     GeglRectangle           roi,
+                                     gboolean                write)
+{
+  GeglBufferTileIterator *tile_i = (GeglBufferTileIterator*)i;
+  g_assert (i);
+  memset (i, 0, sizeof (GeglBufferScanIterator));
+  gegl_buffer_tile_iterator_init (tile_i, buffer, roi, write);
+  i->max_size = tile_i->buffer->tile_storage->tile_width *
+                tile_i->buffer->tile_storage->tile_height *
+                tile_i->buffer->format->format.bytes_per_pixel;
+}
+
+GeglBufferScanIterator *gegl_buffer_scan_iterator_new (GeglBuffer             *buffer,
+                                                       GeglRectangle           roi,
+                                                       gboolean                write)
+{
+  GeglBufferScanIterator *i = g_malloc (sizeof (GeglBufferScanIterator));
+  gegl_buffer_scan_iterator_init (i, buffer, roi, write);
+  return i;
+}
+
+gboolean
+gegl_buffer_scan_iterator_next (GeglBufferScanIterator *i)
+{
+  GeglBufferTileIterator *tile_i = (GeglBufferTileIterator*)i;
+
+  if (tile_i->tile==NULL)
+    {
+      gulp:
+      if (!gegl_buffer_tile_iterator_next (tile_i))
+        return FALSE;
+      i->width = tile_i->subrect.width;
+      i->row = 0;
+    }
+  /* we should now have a valid tile */
+
+  if (tile_i->subrect.width == tile_i->buffer->tile_storage->tile_width &&
+      i->row < tile_i->subrect.height)
+    /* the entire contents of the tile can be expressed as one long scan */
+    {
+      gint  px_size = tile_i->buffer->format->format.bytes_per_pixel;
+      guchar *data = tile_i->data;
+      i->width = tile_i->subrect.width * tile_i->subrect.height;
+      i->data = data + px_size * (tile_i->subrect.width * tile_i->subrect.y);
+      i->row = tile_i->subrect.height;
+      return TRUE;
+    }
+  else if (i->row < tile_i->subrect.height)
+    /* iterate thorugh the scanlines in the subrect */
+    {
+      guchar *data = tile_i->sub_data;
+      i->data = data + i->row * tile_i->rowstride;
+      i->row ++;
+      return TRUE;
+    }
+  else
+    { /* we're done with that tile go get another one if possible */
+      goto gulp;
+    }
+
+  return FALSE;
+}
+
+
+gboolean gegl_buffer_scan_compatible (GeglBuffer *input,
+                                      GeglBuffer *output)
+{
+  if (input->tile_storage->tile_width !=
+      output->tile_storage->tile_width)
+    return FALSE;
+  if (input->tile_storage->tile_height !=
+      output->tile_storage->tile_height)
+    return FALSE;
+  if (input->shift_x !=
+      output->shift_x)
+    return FALSE;
+  if (input->shift_y !=
+      output->shift_y)
+    return FALSE;
+  return TRUE;
+}
+
+gboolean
+gegl_buffer_tile_iterator_next (GeglBufferTileIterator *i)
+{
+  GeglBuffer *buffer = i->buffer;
+  gint  tile_width   = buffer->tile_storage->tile_width;
+  gint  tile_height  = buffer->tile_storage->tile_height;
+  gint  buffer_shift_x = buffer->shift_x;
+  gint  buffer_shift_y = buffer->shift_y;
+  gint  buffer_x       = buffer->extent.x + buffer_shift_x;
+  gint  buffer_y       = buffer->extent.y + buffer_shift_y;
+  gint  buffer_abyss_x = buffer->abyss.x + buffer_shift_x;
+  gint  abyss_x_total  = buffer_abyss_x + buffer->abyss.width;
+
+  if (i->roi.width == 0 || i->roi.height == 0)
+    return FALSE;
+
+gulp:
+
+  /* unref previous held tile */
+  if (i->tile)
+    {
+      if (i->write)
+        {
+          gegl_tile_unlock (i->tile);
+        }
+      g_object_unref (i->tile);
+      i->tile = NULL;
+    }
+
+  if (i->col < i->roi.width)
+    { /* return tile on this row */
+      gint tiledx = buffer_x + i->col;
+      gint tiledy = buffer_y + i->row;
+      gint offsetx = gegl_tile_offset (tiledx, tile_width);
+      gint offsety = gegl_tile_offset (tiledy, tile_height);
+      gint pixels; 
+
+      if (i->roi.width + offsetx - i->col < tile_width)
+        pixels = (i->roi.width + offsetx - i->col) - offsetx;
+      else
+        pixels = tile_width - offsetx;
+
+     if (!(buffer_x + i->col + tile_width >= buffer_abyss_x &&
+                      buffer_x + i->col < abyss_x_total))
+       { 
+          g_warning ("entire tile in abyss?");
+
+          i->col += tile_width - offsetx;
+       }
+     else
+       {
+         /* gap between left side of tile, and abyss */
+         i->subrect.x = offsetx;
+         i->subrect.y = offsety;
+         /* gap between right side of tile, and abyss */
+
+
+         i->subrect.width = (i->roi.width - i->col < tile_width) ?
+                             (i->roi.width - i->col) - i->subrect.x:
+                             tile_width - i->subrect.x;
+
+         i->subrect.height = (i->roi.height - i->row < tile_height) ?
+                             (i->roi.height - i->row) - i->subrect.y:
+                             tile_height - i->subrect.y;
+
+         i->tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
+                                               gegl_tile_indice (tiledx, tile_width),
+                                               gegl_tile_indice (tiledy, tile_height),
+                                               0);
+         if (i->write)
+           {
+             gegl_tile_lock (i->tile);
+           }
+         i->data = gegl_tile_get_data (i->tile);
+
+         {
+         gint bpp = i->buffer->format->format.bytes_per_pixel;
+         i->rowstride = bpp * tile_width;
+         i->sub_data = (guchar*)(i->data) + bpp * (i->subrect.y * tile_width + i->subrect.x);
+         }
+
+         /* update with new future position (note this means that the
+          * coordinates read from the iterator do not make full sense 
+          * */
+         i->col += tile_width - offsetx;
+
+         return TRUE;
+       }
+    }
+  else /* move down to next row */
+    {
+      gint tiledy = buffer_y + i->row;
+      gint offsety = gegl_tile_offset (tiledy, tile_height);
+
+      i->row += tile_height - offsety;
+      i->col=0;
+
+      if (i->row < i->roi.height)
+        {
+          goto gulp; /* return the first tile in the next row */
+        }
+
+      return FALSE;
+    }
+  return FALSE;
+}
+                                    
+
+
 #ifdef BABL
 #undef BABL
 #endif
@@ -310,6 +530,7 @@
 }
 
 
+
 static void inline
 gegl_buffer_iterate (GeglBuffer *buffer,
                      guchar     *buf,
@@ -579,14 +800,7 @@
 #if ENABLE_MP
   g_static_rec_mutex_lock (&mutex);
 #endif
-  if (gegl_buffer_is_shared(buffer))
-    {
-      while (gegl_buffer_try_lock (buffer)==FALSE)
-        {
-          g_print ("failed to aquire lock sleeping 100ms");
-          g_usleep (100000);
-        }
-    }
+  gegl_buffer_lock (buffer);
 
   if (format == NULL)
     format = buffer->format;
@@ -613,8 +827,8 @@
   if (gegl_buffer_is_shared(buffer))
     {
       gegl_buffer_flush (buffer);
-      gegl_buffer_unlock (buffer);
     }
+  gegl_buffer_unlock (buffer); /* XXX: should this happen before flush? */
 #if ENABLE_MP
   g_static_rec_mutex_unlock (&mutex);
 #endif
@@ -1250,4 +1464,3 @@
                     new, gegl_buffer_get_extent (buffer));
   return new;
 }
-

Modified: trunk/gegl/buffer/gegl-buffer-private.h
==============================================================================
--- trunk/gegl/buffer/gegl-buffer-private.h	(original)
+++ trunk/gegl/buffer/gegl-buffer-private.h	Fri May 16 17:01:36 2008
@@ -96,7 +96,51 @@
 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);
 
 
+typedef struct GeglBufferTileIterator
+{
+  GeglBuffer    *buffer;
+  GeglTile      *tile;
+  GeglRectangle  roi;
+  gint           col;
+  gint           row;
+  gboolean       write; /* perhaps in a subclass struct? */
+  GeglRectangle  subrect; /* has negative x when entire tile is valid */
+  gpointer       data;
+  gpointer       sub_data;
+  gint           rowstride;
+} GeglBufferTileIterator;
+
+typedef struct GeglBufferScanIterator {
+  GeglBufferTileIterator tile_iterator;
+  gint                   max_size; /*  in bytes */
+  gint                   width;
+  gint                   row;
+  gpointer               data;
+} GeglBufferScanIterator;
+
+gboolean                gegl_buffer_tile_iterator_next (GeglBufferTileIterator *i);
+gboolean                gegl_buffer_scan_iterator_next (GeglBufferScanIterator *i);
+GeglBufferTileIterator *gegl_buffer_tile_iterator_new  (GeglBuffer             *buffer,
+                                                        GeglRectangle           roi,
+                                                        gboolean                write);
+void                    gegl_buffer_tile_iterator_init (GeglBufferTileIterator *i,
+                                                        GeglBuffer             *buffer,
+                                                        GeglRectangle           roi,
+                                                        gboolean                write);
+
+void gegl_buffer_scan_iterator_init (GeglBufferScanIterator *i,
+                                     GeglBuffer             *buffer,
+                                     GeglRectangle           roi,
+                                     gboolean                write);
+GeglBufferScanIterator *gegl_buffer_scan_iterator_new (GeglBuffer             *buffer,
+                                                       GeglRectangle           roi,
+                                                       gboolean                write);
+gboolean                gegl_buffer_scan_compatible   (GeglBuffer *input,
+                                                       GeglBuffer *output);
+
+
 #endif

Modified: trunk/gegl/buffer/gegl-tile.c
==============================================================================
--- trunk/gegl/buffer/gegl-tile.c	(original)
+++ trunk/gegl/buffer/gegl-tile.c	Fri May 16 17:01:36 2008
@@ -106,6 +106,8 @@
     }
 }
 
+#include "gegl-utils.h"
+
 static void
 dispose (GObject *object)
 {
@@ -118,7 +120,7 @@
     {
       if (tile->next_shared == tile)
         { /* no clones */
-          g_free (tile->data);
+          gegl_free (tile->data);
           tile->data = NULL;
         }
       else
@@ -211,7 +213,7 @@
 {
   GeglTile *tile = g_object_new (GEGL_TYPE_TILE, NULL);
 
-  tile->data       = g_malloc (size);
+  tile->data       = gegl_malloc (size);
   tile->size       = size;
   tile->stored_rev = 1;
 
@@ -219,6 +221,15 @@
   return tile;
 }
 
+static gpointer
+gegl_memdup (gpointer src, gsize size)
+{
+  gpointer ret;
+  ret = gegl_malloc (size);
+  memcpy (ret, src, size);
+  return ret;
+}
+
 static void
 gegl_tile_unclone (GeglTile *tile)
 {
@@ -227,7 +238,7 @@
       /* the tile data is shared with other tiles,
        * create a local copy
        */
-      tile->data                     = g_memdup (tile->data, tile->size);
+      tile->data                     = gegl_memdup (tile->data, tile->size);
       tile->prev_shared->next_shared = tile->next_shared;
       tile->next_shared->prev_shared = tile->prev_shared;
       tile->prev_shared              = tile;
@@ -243,7 +254,8 @@
 {
   if (tile->lock != 0)
     {
-      g_warning ("locking a tile for the second time");
+      g_print ("hm\n");
+      g_warning ("strange tile lock count: %i", tile->lock);
     }
   total_locks++;
 
@@ -327,7 +339,7 @@
 {
   gegl_tile_lock (dst);
 
-  g_free (dst->data);
+  gegl_free (dst->data);
   dst->data = NULL;
 
   dst->next_shared              = src->next_shared;

Modified: trunk/gegl/operation/gegl-operation-point-filter.c
==============================================================================
--- trunk/gegl/operation/gegl-operation-point-filter.c	(original)
+++ trunk/gegl/operation/gegl-operation-point-filter.c	Fri May 16 17:01:36 2008
@@ -28,6 +28,9 @@
 #include "gegl-utils.h"
 #include <string.h>
 
+#include "gegl-buffer-private.h"
+#include "gegl-tile-storage.h"
+
 static gboolean process_inner (GeglOperation       *operation,
                                GeglBuffer          *input,
                                GeglBuffer          *output,
@@ -56,6 +59,7 @@
 {
 }
 
+
 static gboolean
 process_inner (GeglOperation       *operation,
                GeglBuffer          *input,
@@ -65,6 +69,9 @@
   GeglPad    *pad;
   const Babl *in_format;
   const Babl *out_format;
+  GeglOperationPointFilterClass *point_filter_class;
+
+  point_filter_class = GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation);
 
   pad       = gegl_node_get_pad (operation->node, "input");
   in_format = gegl_pad_get_format (pad);
@@ -84,6 +91,103 @@
 
   if ((result->width > 0) && (result->height > 0))
     {
+      if (gegl_buffer_scan_compatible (input, output))
+        /* We can use the fastest possible path with the least possible
+         * copies using paralell scan iteratator with possibly direct
+         * read write access to buffers.
+         */
+        {
+          GTimer       *timer       = g_timer_new ();
+          gint input_bpp  = in_format->format.bytes_per_pixel;
+          gint output_bpp = output->format->format.bytes_per_pixel;
+          gpointer     *in_buf = NULL;
+          gpointer     *out_buf = NULL;
+          Babl         *infish;
+          Babl         *outfish;
+
+          GeglBufferScanIterator read;
+          GeglBufferScanIterator write;
+          gegl_buffer_scan_iterator_init (&read,  input,  *result, FALSE);
+          gegl_buffer_scan_iterator_init (&write, output, *result, TRUE);
+
+          g_assert (input->tile_storage->tile_width == output->tile_storage->tile_width);
+
+          in_buf  = gegl_malloc (input_bpp * input->tile_storage->tile_width *
+                                             input->tile_storage->tile_height);
+          out_buf = gegl_malloc (output_bpp * output->tile_storage->tile_width *
+                                              output->tile_storage->tile_height);
+
+          infish = babl_fish (input->format, in_format);
+          outfish = babl_fish (out_format, output->format);
+         
+          gegl_buffer_lock (output); 
+          {
+          gboolean a = FALSE, b = FALSE;
+          if (in_format == input->format &&
+              out_format == output->format)
+            {
+              while (  (a = gegl_buffer_scan_iterator_next (&read)) &&
+                       (b = gegl_buffer_scan_iterator_next (&write)))
+                {
+                  g_assert (read.width == write.width);
+                  point_filter_class->process (operation, read.data, write.data, write.width);
+                }
+            }
+          else if (in_format == input->format &&
+                   out_format != output->format)
+            {
+              while (  (a = gegl_buffer_scan_iterator_next (&read)) &&
+                       (b = gegl_buffer_scan_iterator_next (&write)))
+                {
+                  g_assert (read.width == write.width);
+                  point_filter_class->process (operation, read.data, out_buf, read.width);
+                  babl_process (outfish, out_buf, write.data, write.width);
+                }
+            }
+          else if (in_format != input->format &&
+                   out_format == output->format)
+            {
+              while (  (a = gegl_buffer_scan_iterator_next (&read)) &&
+                       (b = gegl_buffer_scan_iterator_next (&write)))
+                {
+                  if (read.width < 0)
+                    continue;
+                  g_assert (read.width == write.width);
+                  babl_process (infish, read.data, in_buf, read.width);
+                  point_filter_class->process (operation, in_buf, write.data, read.width);
+                }
+            }
+          else if (in_format != input->format &&
+                   out_format != output->format)
+            {
+              while (  (a = gegl_buffer_scan_iterator_next (&read)) &&
+                       (b = gegl_buffer_scan_iterator_next (&write)))
+                {
+                  g_assert (read.width == write.width);
+                  babl_process (infish, read.data, in_buf, read.width);
+                  point_filter_class->process (operation, in_buf, out_buf, read.width);
+                  babl_process (outfish, out_buf, write.data, write.width);
+                }
+            }
+
+          if (a)
+            while (gegl_buffer_scan_iterator_next (&read));
+          if (b)
+            while (gegl_buffer_scan_iterator_next (&write));
+          }
+
+          gegl_free (in_buf);
+          gegl_free (out_buf);
+          gegl_buffer_unlock (output); 
+
+          g_printerr ("%s: %d x %d %g Mpixels/sec\n",
+              G_STRFUNC,
+              output->extent.width,
+              output->extent.height,
+              ( output->extent.width* output->extent.height) /
+               (1000000 * g_timer_elapsed (timer, NULL)));
+          g_timer_destroy (timer);
+        }
     /* eek: this fails,..
       if (!(input->width == output->width &&
           input->height == output->height))
@@ -93,23 +197,8 @@
       g_assert (input->width == output->width &&
                 input->height == output->height);
      */
-      if (in_format == out_format)
-        {
-          gfloat *buf;
-          buf = gegl_malloc (in_format->format.bytes_per_pixel *
-                          output->extent.width * output->extent.height);
-
-          gegl_buffer_get (input, 1.0, result, in_format, buf, GEGL_AUTO_ROWSTRIDE);
-
-          GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation)->process (
-            operation,
-            buf,
-            buf,
-            output->extent.width * output->extent.height);
 
-          gegl_buffer_set (output, result, out_format, buf, GEGL_AUTO_ROWSTRIDE);
-          gegl_free (buf);
-        }
+#if 0
       else
         {
           gfloat *in_buf;
@@ -130,7 +219,41 @@
           gegl_buffer_set (output, result, out_format, out_buf, GEGL_AUTO_ROWSTRIDE);
           gegl_free (in_buf);
           gegl_free (out_buf);
+#else
+      else
+        {
+          gfloat *in_buf;
+          GeglRectangle roi;
+          gint skip = 32;
+          gfloat *out_buf;
+          in_buf = gegl_malloc (in_format->format.bytes_per_pixel * result->width * skip);
+          out_buf = gegl_malloc (out_format->format.bytes_per_pixel * result->width * skip);
+
+
+          roi = *result;
+          while (roi.y < result->y + result->height && skip >0 )
+            {
+              for (roi.height=skip; (roi.y + skip <= result->y + result->height);
+                   roi.y+=skip)
+                {
+                  gegl_buffer_get (input, 1.0, &roi, in_format, in_buf, GEGL_AUTO_ROWSTRIDE);
+
+                  GEGL_OPERATION_POINT_FILTER_GET_CLASS (operation)->process (
+                    operation,
+                    in_buf,
+                    out_buf,
+                    result->width * skip);
+
+                  gegl_buffer_set (output, &roi, out_format, out_buf, GEGL_AUTO_ROWSTRIDE);
+                }
+                skip /= 2;
+              }
+
+
+          gegl_free (in_buf);
+          gegl_free (out_buf);
         }
+#endif
     }
   return TRUE;
 }



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