[gegl] c2g, stress: use sampler and iterator instead of temporary linear buffers



commit 73a88d2d8f72f1c6babd0aabd76137d5a5660e1b
Author: Øyvind Kolås <pippin gimp org>
Date:   Sun Jun 15 08:03:24 2014 +0200

    c2g,stress: use sampler and iterator instead of temporary linear buffers
    
    For low radiuses, this makes the op slower - but for larger radiuses it makes
    it faster since the temporary memory requirements does not scale with the
    radius.

 operations/common/c2g.c       |  131 ++++++++++++++++++++---------------------
 operations/common/envelopes.h |   67 +++++++++-------------
 operations/common/stress.c    |   99 ++++++++++++++++---------------
 3 files changed, 140 insertions(+), 157 deletions(-)
---
diff --git a/operations/common/c2g.c b/operations/common/c2g.c
index aa3e74b..3bd4490 100644
--- a/operations/common/c2g.c
+++ b/operations/common/c2g.c
@@ -28,7 +28,7 @@ property_int (radius, _("Radius"), 300)
   description(_("Neighborhood taken into account, this is the radius "
                      "in pixels taken into account when deciding which "
                      "colors map to which gray values"))
-  value_range (2, 3000)
+  value_range (2, 6000)
   ui_range    (2, 1000)
   ui_gamma    (1.6)
   ui_meta     ("unit", "pixel-distance")
@@ -36,13 +36,13 @@ property_int (radius, _("Radius"), 300)
 property_int  (samples, _("Samples"), 4)
   description (_("Number of samples to do per iteration looking for the range of colors"))
   value_range (1, 1000) 
-  ui_range    (1, 20)
+  ui_range    (3, 17)
 
 property_int (iterations, _("Iterations"), 10)
   description(_("Number of iterations, a higher number of iterations "
                      "provides less noisy results at a computational cost"))
   value_range (1, 1000)
-  ui_range (1, 20)
+  ui_range (1, 30)
 
 /*
 property_double (rgamma, _("Radial Gamma"), 0.0, 8.0, 2.0,
@@ -56,7 +56,7 @@ property_double (rgamma, _("Radial Gamma"), 0.0, 8.0, 2.0,
 #include "gegl-op.h"
 #include <math.h>
 #include <stdlib.h>
-#include "envelopes.h"
+#include "envelopes2.h"
 
 #define RGAMMA 2.0
 
@@ -69,76 +69,71 @@ static void c2g (GeglBuffer          *src,
                  gint                 iterations,
                  gdouble              rgamma)
 {
-  gint x,y;
-  gint    dst_offset=0;
-  gfloat *src_buf;
-  gfloat *dst_buf;
-  gint    inw = src_rect->width;
-  gint    outw = dst_rect->width;
-  gint    inh = src_rect->height;
-
-  src_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 4);
-  dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 2);
-
-  gegl_buffer_get (src, src_rect, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE,
-                   GEGL_ABYSS_NONE);
+  const Babl *format = babl_format ("RGBA float");
+  
+  if (dst_rect->width > 0 && dst_rect->height > 0)
+  {
+    GeglBufferIterator *i = gegl_buffer_iterator_new (dst, dst_rect, 0, babl_format("YA float"), 
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+    GeglSampler *sampler = gegl_buffer_sampler_new (src, format, GEGL_SAMPLER_NEAREST);
 
-  for (y=radius; y<dst_rect->height+radius; y++)
+    while (gegl_buffer_iterator_next (i))
     {
-      gint src_offset = (inw*y+radius)*4;
-      for (x=radius; x<outw+radius; x++)
-        {
-          gfloat *pixel= src_buf + src_offset;
-          gfloat  min[4];
-          gfloat  max[4];
-
-          compute_envelopes (src_buf,
-                             inw, inh,
-                             x, y,
-                             radius, samples,
-                             iterations,
-                             FALSE, /* same spray */
-                             rgamma,
-                             min, max);
-          {
-            /* this should be replaced with a better/faster projection of
-             * pixel onto the vector spanned by min -> max, currently
-             * computed by comparing the distance to min with the sum
-             * of the distance to min/max.
-             */
-
-            gfloat nominator = 0;
-            gfloat denominator = 0;
-            gint c;
-            for (c=0; c<3; c++)
-              {
-                nominator   += (pixel[c] - min[c]) * (pixel[c] - min[c]);
-                denominator += (pixel[c] - max[c]) * (pixel[c] - max[c]);
-              }
+      gint x,y;
+      gint    dst_offset=0;
+      gfloat *dst_buf = i->data[0];
 
-            nominator = sqrt (nominator);
-            denominator = sqrt (denominator);
-            denominator = nominator + denominator;
-
-            if (denominator>0.000)
-              {
-                dst_buf[dst_offset+0] = nominator/denominator;
-              }
-            else
+      for (y=i->roi[0].y; y < i->roi[0].y + i->roi[0].height; y++)
+        {
+          for (x=i->roi[0].x; x < i->roi[0].x + i->roi[0].width; x++)
+            {
+              gfloat  min[4];
+              gfloat  max[4];
+              gfloat  pixel[4];
+
+              compute_envelopes (src, sampler,
+                                 x, y,
+                                 radius, samples,
+                                 iterations,
+                                 FALSE, /* same spray */
+                                 rgamma,
+                                 min, max, pixel, format);
               {
-                /* shouldn't happen */
-                dst_buf[dst_offset+0] = 0.5;
+                /* this should be replaced with a better/faster projection of
+                 * pixel onto the vector spanned by min -> max, currently
+                 * computed by comparing the distance to min with the sum
+                 * of the distance to min/max.
+                 */
+
+                gfloat nominator = 0;
+                gfloat denominator = 0;
+                gint c;
+                for (c=0; c<3; c++)
+                  {
+                    nominator   += (pixel[c] - min[c]) * (pixel[c] - min[c]);
+                    denominator += (pixel[c] - max[c]) * (pixel[c] - max[c]);
+                  }
+
+                nominator = sqrtf (nominator);
+                denominator = sqrtf (denominator);
+                denominator = nominator + denominator;
+
+                if (denominator>0.000)
+                  {
+                    dst_buf[dst_offset+0] = nominator/denominator;
+                  }
+                else
+                  {
+                    /* shouldn't happen */
+                    dst_buf[dst_offset+0] = 0.5;
+                  }
+                dst_buf[dst_offset+1] = pixel[3];
+                dst_offset+=2;
               }
-            dst_buf[dst_offset+1] = src_buf[src_offset+3];
-
-            src_offset+=4;
-            dst_offset+=2;
+            }
           }
-        }
     }
-  gegl_buffer_set (dst, dst_rect, 0, babl_format ("YA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
-  g_free (src_buf);
-  g_free (dst_buf);
+    g_object_unref (sampler);
+  }
 }
 
 static void prepare (GeglOperation *operation)
diff --git a/operations/common/envelopes.h b/operations/common/envelopes.h
index 40e3b4a..2180de8 100644
--- a/operations/common/envelopes.h
+++ b/operations/common/envelopes.h
@@ -52,43 +52,28 @@ static void compute_luts(gdouble rgamma)
 }
 
 static inline void
-sample (gfloat *buf,
-        gint    width,
-        gint    height,
-        gint    x,
-        gint    y,
-        gfloat *dst)
-{
-  gfloat *pixel = (buf + ((width * y) + x) * 4);
-  gint c;
-
-  for (c=0;c<4;c++)
-    {
-      dst[c] = pixel[c];
-    }
-}
-
-static inline void
-sample_min_max (gfloat *buf,
-                gint    width,
-                gint    height,
-                gint    x,
-                gint    y,
-                gint    radius,
-                gint    samples,
-                gfloat *min,
-                gfloat *max)
+sample_min_max (GeglBuffer  *buffer,
+                GeglSampler *sampler,
+                gint         x,
+                gint         y,
+                gint         radius,
+                gint         samples,
+                gfloat      *min,
+                gfloat      *max,
+                gfloat      *pixel,
+                const Babl  *format)
 {
   gfloat best_min[3];
   gfloat best_max[3];
-  gfloat *center_pix = (buf + (width * y + x) * 4);
-
+  gint width = gegl_buffer_get_width (buffer);
+  gint height = gegl_buffer_get_height (buffer);
+  
   gint i, c;
 
   for (c=0;c<3;c++)
     {
-      best_min[c]=center_pix[c];
-      best_max[c]=center_pix[c];
+      best_min[c]=pixel[c];
+      best_max[c]=pixel[c];
     }
 
   for (i=0; i<samples; i++)
@@ -119,7 +104,8 @@ retry:                      /* if we've sampled outside the valid image
         goto retry;
 
       {
-        gfloat *pixel = (buf + ((width * v) + u) * 4);
+        gfloat pixel[4];
+        gegl_sampler_get (sampler, u, v, NULL, (void*)(&pixel[0]), GEGL_ABYSS_CLAMP);
 
         if (pixel[3]>0.0) /* ignore fully transparent pixels */
           {
@@ -145,9 +131,8 @@ retry:                      /* if we've sampled outside the valid image
     }
 }
 
-static inline void compute_envelopes (gfloat  *buf,
-                                      gint     width,
-                                      gint     height,
+static inline void compute_envelopes (GeglBuffer *buffer,
+                                      GeglSampler *sampler,
                                       gint     x,
                                       gint     y,
                                       gint     radius,
@@ -156,13 +141,16 @@ static inline void compute_envelopes (gfloat  *buf,
                                       gboolean same_spray,
                                       gdouble  rgamma,
                                       gfloat  *min_envelope,
-                                      gfloat  *max_envelope)
+                                      gfloat  *max_envelope,
+                                      gfloat  *pixel,
+                                      const Babl *format)
 {
   gint    i;
   gint    c;
   gfloat  range_sum[4]               = {0,0,0,0};
   gfloat  relative_brightness_sum[4] = {0,0,0,0};
-  gfloat *pixel = buf + (width*y+x)*4;
+
+  gegl_sampler_get (sampler, x, y, NULL, (void*)(&pixel[0]), GEGL_ABYSS_CLAMP);
 
   /* compute lookuptables for the gamma, currently not used/exposed
    * as a tweakable property */
@@ -178,12 +166,11 @@ static inline void compute_envelopes (gfloat  *buf,
     {
       gfloat min[3], max[3];
 
-      sample_min_max (buf,
-                      width,
-                      height,
+      sample_min_max (buffer,
+                      sampler,
                       x, y,
                       radius, samples,
-                      min, max);
+                      min, max, pixel, format);
 
       for (c=0;c<3;c++)
         {
diff --git a/operations/common/stress.c b/operations/common/stress.c
index a402705..7be3cae 100644
--- a/operations/common/stress.c
+++ b/operations/common/stress.c
@@ -26,19 +26,20 @@
 
 property_int (radius, _("Radius"), 300)
     description(_("Neighborhood taken into account, for enhancement ideal values are close to the longest 
side of the image, increasing this increases the runtime"))
-    value_range (2, 5000)
-    ui_range    (2, 2000)
+    value_range (2, 6000)
+    ui_range    (2, 1000)
+    ui_gamma    (1.6)
     ui_meta     ("unit", "pixel-distance")
 
 property_int (samples, _("Samples"), 5)
     description(_("Number of samples to do per iteration looking for the range of colors"))
-    value_range (2, 200)
-    ui_range    (2, 10)
+    value_range (2, 500)
+    ui_range    (3, 17)
 
 property_int (iterations, _("Iterations"), 5)
     description(_("Number of iterations, a higher number of iterations provides a less noisy rendering at a 
computational cost"))
-    value_range (1, 200)
-    ui_range    (1, 10)
+    value_range (1, 1000)
+    ui_range    (1, 30)
 
 /*
 
@@ -72,64 +73,64 @@ static void stress (GeglBuffer          *src,
                     gint                 iterations,
                     gdouble              rgamma)
 {
-  gint x,y;
-  gint    dst_offset=0;
-  gfloat *src_buf;
-  gfloat *dst_buf;
-  gint    inw = src_rect->width;
-  gint    inh = src_rect->height;
-  gint   outw = dst_rect->width;
-
-  /* this use of huge linear buffers should be avoided and
-   * most probably would lead to great speed ups
-   */
-
-  src_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 4);
-  dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 4);
-
-  gegl_buffer_get (src, src_rect, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, 
GEGL_ABYSS_NONE);
-
-  for (y=radius; y<dst_rect->height+radius; y++)
+  const Babl *format = babl_format ("RGBA float");
+  
+  if (dst_rect->width > 0 && dst_rect->height > 0)
+  {
+    GeglBufferIterator *i = gegl_buffer_iterator_new (dst, dst_rect, 0, babl_format("RaGaBaA float"), 
GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+    GeglSampler *sampler = gegl_buffer_sampler_new (src, format, GEGL_SAMPLER_NEAREST);
+
+    while (gegl_buffer_iterator_next (i))
     {
-      gint src_offset = (inw*y+radius)*4;
-      for (x=radius; x<outw+radius; x++)
+      gint x,y;
+      gint    dst_offset=0;
+      gfloat *dst_buf = i->data[0];
+
+      for (y=i->roi[0].y; y < i->roi[0].y + i->roi[0].height; y++)
         {
-          gfloat *center_pix= src_buf + src_offset;
-          gfloat  min_envelope[4];
-          gfloat  max_envelope[4];
-
-          compute_envelopes (src_buf,
-                             inw, inh,
-                             x, y,
-                             radius, samples,
-                             iterations,
-                             FALSE, /* same-spray */
-                             rgamma,
-                             min_envelope, max_envelope);
-           {
+          for (x=i->roi[0].x; x < i->roi[0].x + i->roi[0].width; x++)
+            {
+              gfloat  min[4];
+              gfloat  max[4];
+              gfloat  pixel[4];
+
+              compute_envelopes (src, sampler,
+                                 x, y,
+                                 radius, samples,
+                                 iterations,
+                                 FALSE, /* same spray */
+                                 rgamma,
+                                 min, max, pixel, format);
+              {
+                /* this should be replaced with a better/faster projection of
+                 * pixel onto the vector spanned by min -> max, currently
+                 * computed by comparing the distance to min with the sum
+                 * of the distance to min/max.
+                 */
+
               gint c;
               for (c=0;c<3;c++)
                 {
-                  gfloat delta = max_envelope[c]-min_envelope[c];
+                  gfloat delta = max[c]-min[c];
                   if (delta != 0)
                     {
                       dst_buf[dst_offset+c] =
-                         (center_pix[c]-min_envelope[c])/delta;
+                         (pixel[c]-min[c])/delta;
                     }
                   else
                     {
                       dst_buf[dst_offset+c] = 0.5;
                     }
                 }
-           }
-          dst_buf[dst_offset+3] = src_buf[src_offset+3];
-          src_offset+=4;
-          dst_offset+=4;
-        }
+
+                dst_buf[dst_offset+3] = pixel[3];
+                dst_offset+=4;
+              }
+            }
+          }
     }
-  gegl_buffer_set (dst, dst_rect, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
-  g_free (src_buf);
-  g_free (dst_buf);
+    g_object_unref (sampler);
+  }
 }
 
 static void prepare (GeglOperation *operation)


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