[gegl] transform_generic: flip or not on a per tile basis



commit 326a78d0f5b310f5ca6b3dc84363c4ee7a1c9e35
Author: Nicolas Robidoux <nrobidoux git gnome org>
Date:   Mon Dec 24 10:39:29 2012 -0500

    transform_generic: flip or not on a per tile basis

 gegl/buffer/gegl-sampler.c            |   12 +-
 gegl/buffer/gegl-sampler.h            |    2 +-
 operations/transform/transform-core.c |  303 +++++++++++++++------------------
 3 files changed, 144 insertions(+), 173 deletions(-)
---
diff --git a/gegl/buffer/gegl-sampler.c b/gegl/buffer/gegl-sampler.c
index 75c07d3..d1a2bcc 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -273,10 +273,10 @@ gegl_sampler_get_ptr (GeglSampler *const sampler,
       fetch_rectangle.height = maximum_height;
       fetch_rectangle.x =
         x + sampler->context_rect[0].x -
-        (maximum_width  - sampler->context_rect[0].width ) / (gint) 2;
+        (maximum_width  - sampler->context_rect[0].width ) / (gint) 8;
       fetch_rectangle.y =
         y + sampler->context_rect[0].y -
-        (maximum_height - sampler->context_rect[0].height) / (gint) 2;
+        (maximum_height - sampler->context_rect[0].height) / (gint) 8;
 
       gegl_buffer_get (sampler->buffer,
                        &fetch_rectangle,
@@ -346,9 +346,9 @@ gegl_sampler_get_from_buffer (GeglSampler *const sampler,
       fetch_rectangle.width  = maximum_width;
       fetch_rectangle.height = maximum_height;
       fetch_rectangle.x = x -
-        (maximum_width  - sampler->context_rect[0].width ) / (gint) 2;
+        (maximum_width  - sampler->context_rect[0].width ) / (gint) 8;
       fetch_rectangle.y = y -
-        (maximum_height - sampler->context_rect[0].height) / (gint) 2;
+        (maximum_height - sampler->context_rect[0].height) / (gint) 8;
 
       gegl_buffer_get (sampler->buffer,
                        &fetch_rectangle,
@@ -427,10 +427,10 @@ gegl_sampler_get_from_mipmap (GeglSampler *const sampler,
       fetch_rectangle.height = maximum_height;
       fetch_rectangle.x =
         x + sampler->context_rect[level].x -
-        (maximum_width  - sampler->context_rect[level].width ) / (gint) 2;
+        (maximum_width  - sampler->context_rect[level].width ) / (gint) 8;
       fetch_rectangle.y =
         y + sampler->context_rect[level].y -
-        (maximum_height - sampler->context_rect[level].height) / (gint) 2;
+        (maximum_height - sampler->context_rect[level].height) / (gint) 8;
 
       gegl_buffer_get (sampler->buffer,
                        &fetch_rectangle,
diff --git a/gegl/buffer/gegl-sampler.h b/gegl/buffer/gegl-sampler.h
index bee4bc0..999d32d 100644
--- a/gegl/buffer/gegl-sampler.h
+++ b/gegl/buffer/gegl-sampler.h
@@ -42,7 +42,7 @@ G_BEGIN_DECLS
  * twice as wide as they are tall.
  */
 #define GEGL_SAMPLER_MAXIMUM_HEIGHT (32)
-#define GEGL_SAMPLER_MAXIMUM_WIDTH (2*GEGL_SAMPLER_MAXIMUM_HEIGHT)
+#define GEGL_SAMPLER_MAXIMUM_WIDTH (GEGL_SAMPLER_MAXIMUM_HEIGHT)
 
 typedef struct _GeglSamplerClass GeglSamplerClass;
 
diff --git a/operations/transform/transform-core.c b/operations/transform/transform-core.c
index 6b4e61b..ca10900 100644
--- a/operations/transform/transform-core.c
+++ b/operations/transform/transform-core.c
@@ -529,20 +529,16 @@ gegl_transform_get_bounding_box (GeglOperation *op)
       /*
        * Does "- (gint) 1" interact badly with {*,*,0,0}?
        */
-      in_rect.width  += (
-                          context_rect.width  - (gint) 1 > (gint) 0
-                          ?
-                          context_rect.width  - (gint) 1
-                          :
-                          (gint) 0
-                        );
-      in_rect.height += (
-                          context_rect.height - (gint) 1 > (gint) 0
-                          ?
-                          context_rect.height - (gint) 1
-                          :
-                          (gint) 0
-                        );
+      in_rect.width  += context_rect.width  - (gint) 1 > (gint) 0
+	                ?
+                        context_rect.width  - (gint) 1
+                        :
+	                (gint) 0;
+      in_rect.height += context_rect.height - (gint) 1 > (gint) 0
+                        ?
+                        context_rect.height - (gint) 1
+                        :
+	                (gint) 0;
     }
 #endif
 
@@ -804,7 +800,7 @@ transform_affine (GeglBuffer  *dest,
   gint                 dest_pixels,
                        flip_x = 0,
                        flip_y = 0;
-  const Babl          *format = babl_format ("RaGaBaA float");
+  const Babl          *format = babl_format ("RaGaBaA float");  
 
   /*
    * XXX: fast paths as existing in files in the same dir as
@@ -924,7 +920,7 @@ transform_affine (GeglBuffer  *dest,
    * inner product with the vector (2,1).
    */
 
-  if ((gdouble) 2. * inverse.coeff [0][0] + inverse.coeff [1][0] <
+  if (inverse.coeff [0][0] + inverse.coeff [1][0] <
       (gdouble) 0.)
     {
       /*
@@ -939,7 +935,7 @@ transform_affine (GeglBuffer  *dest,
       flip_x = (gint) 1;
     }
 
-  if ((gdouble) 2. * inverse.coeff [0][1] + inverse.coeff [1][1] <
+  if (inverse.coeff [0][1] + inverse.coeff [1][1] <
       (gdouble) 0.)
     {
       /*
@@ -1020,96 +1016,11 @@ transform_generic (GeglBuffer  *dest,
   GeglBufferIterator  *i;
   const GeglRectangle *dest_extent;
   GeglMatrix3          inverse;
-  gdouble              u_start,
-                       v_start,
-                       w_start,
-                       u_float,
-                       v_float,
-                       w_float;
-  gint                 x,
-                       y,
-                       dest_pixels,
-                       bflip_x,
-                       bflip_y,
-                       flip_x,
-                       flip_y;
+  gint                 dest_pixels;
 
   g_object_get (dest, "pixels", &dest_pixels, NULL);
   dest_extent = gegl_buffer_get_extent (dest);
 
-  gegl_matrix3_copy_into (&inverse, matrix);
-  gegl_matrix3_invert (&inverse);
-
-  /*
-   * This code uses a variant of the (novel?) method of ensuring that
-   * scanlines stay, as much as possible, within an input "tile",
-   * given that these wider than tall "tiles" are biased so that there
-   * is more elbow room at the bottom and right than at the top and
-   * left, explained in the transform_affine function. It is not as
-   * foolproof because perspective transformations change the
-   * orientation of scanlines, and consequently what's good at the
-   * bottom may not be best at the top.
-   */
-  /*
-   * Determine whether tile access should be "flipped". First, in the
-   * y direction.
-   *
-   * Until we reach the iterator, we use u_start etc to compute
-   * information needed to set flags. These values will be
-   * "discarded".
-   */
-  u_start = inverse.coeff [0][0] * ((*dest_extent).x + (gdouble) 0.5) +
-            inverse.coeff [0][1] * ((*dest_extent).y + (gdouble) 0.5) +
-            inverse.coeff [0][2];
-  v_start = inverse.coeff [1][0] * ((*dest_extent).x + (gdouble) 0.5) +
-            inverse.coeff [1][1] * ((*dest_extent).y + (gdouble) 0.5) +
-            inverse.coeff [1][2];
-  w_start = inverse.coeff [2][0] * ((*dest_extent).x + (gdouble) 0.5) +
-            inverse.coeff [2][1] * ((*dest_extent).y + (gdouble) 0.5) +
-            inverse.coeff [2][2];
-
-  u_float = u_start + inverse.coeff [0][1] * ((*dest_extent).height - (gint) 1);
-  v_float = v_start + inverse.coeff [1][1] * ((*dest_extent).height - (gint) 1);
-  w_float = w_start + inverse.coeff [2][1] * ((*dest_extent).height - (gint) 1);
-
-  if (((gdouble) 2. * u_float + v_float)/w_float <
-      ((gdouble) 2. * u_start + v_start)/w_start)
-    {
-      /*
-       * Move to the start of the last "scanline".
-       */
-      u_start = u_float;
-      v_start = v_float;
-      w_start = w_float;
-      /*
-       * Set the "change of direction" sign.
-       */
-      bflip_y = (gint) 1;
-    }
-  else
-    {
-      bflip_y = (gint) 0;
-    }
-
-  flip_y = (gint) 1 - (gint) 2 * bflip_y;
-
-  /*
-   * Now in the horizontal direction. Done second because this is the
-   * most important one, and consequently we want to use the likely
-   * "initial scanline" to at least get that one about right.
-   */
-  u_float = u_start + inverse.coeff [0][0] * ((*dest_extent).width - (gint) 1);
-  v_float = v_start + inverse.coeff [1][0] * ((*dest_extent).width - (gint) 1);
-  w_float = w_start + inverse.coeff [2][0] * ((*dest_extent).width - (gint) 1);
-
-  bflip_x = (((gdouble) 2. * u_float + v_float)/w_float <
-	     ((gdouble) 2. * u_start + v_start)/w_start)
-            ?
-            (gint) 1
-            :
-            (gint) 0;
-  flip_x = (gint) 1 - (gint) 2 * bflip_x;
-
   /*
    * Construct an output tile iterator.
    */
@@ -1120,81 +1031,141 @@ transform_generic (GeglBuffer  *dest,
                                 GEGL_BUFFER_WRITE,
                                 GEGL_ABYSS_NONE);
 
+  gegl_matrix3_copy_into (&inverse, matrix);
+  gegl_matrix3_invert (&inverse);
+
   /*
    * Fill the output tiles.
    */
   while (gegl_buffer_iterator_next (i))
     {
-      GeglRectangle *roi = &i->roi[0];
+      GeglRectangle *roi         = &i->roi[0];
       gfloat * restrict dest_buf = (gfloat *)i->data[0];
-      gfloat * restrict dest_ptr =
-        dest_buf +
-        (gint) 4 * ( bflip_x * (roi->width  - (gint) 1) +
-                     bflip_y * (roi->height - (gint) 1) * roi->width );
-
-      u_start =
-        inverse.coeff [0][0] * ( roi->x + bflip_x * (roi->width  - (gint) 1) +
-                                 (gdouble) 0.5 ) +
-        inverse.coeff [0][1] * ( roi->y + bflip_y * (roi->height - (gint) 1) +
-                                 (gdouble) 0.5 ) +
-        inverse.coeff [0][2];
-      v_start =
-        inverse.coeff [1][0] * ( roi->x + bflip_x * (roi->width  - (gint) 1) +
-                                 (gdouble) 0.5 ) +
-        inverse.coeff [1][1] * ( roi->y + bflip_y * (roi->height - (gint) 1) +
-                                 (gdouble) 0.5 ) +
-        inverse.coeff [1][2];
-      w_start =
-        inverse.coeff [2][0] * ( roi->x + bflip_x * (roi->width  - (gint) 1) +
-                                 (gdouble) 0.5 ) +
-        inverse.coeff [2][1] * ( roi->y + bflip_y * (roi->height - (gint) 1) +
-                                 (gdouble) 0.5 ) +
-        inverse.coeff [2][2];
-
-      for (y = roi->height; y--;)
-        {
-          u_float = u_start;
-          v_float = v_start;
-          w_float = w_start;
-
-          for (x = roi->width; x--;)
-            {
-              GeglMatrix2 inverse_jacobian;
-
-              gdouble w_recip = (gdouble) 1.0 / w_float;
-              gdouble u = u_float * w_recip;
-              gdouble v = v_float * w_recip;
-
-              inverse_jacobian.coeff [0][0] =
-                (inverse.coeff [0][0] - inverse.coeff [2][0] * u) * w_recip;
-              inverse_jacobian.coeff [0][1] =
-                (inverse.coeff [0][1] - inverse.coeff [2][1] * u) * w_recip;
-              inverse_jacobian.coeff [1][0] =
-                (inverse.coeff [1][0] - inverse.coeff [2][0] * v) * w_recip;
-              inverse_jacobian.coeff [1][1] =
-                (inverse.coeff [1][1] - inverse.coeff [2][1] * v) * w_recip;
+      /*
+       * This code uses a variant of the (novel?) method of ensuring
+       * that scanlines stay, as much as possible, within an input
+       * "tile", given that these wider than tall "tiles" are biased
+       * so that there is more elbow room at the bottom and right than
+       * at the top and left, explained in the transform_affine
+       * function. It is not as foolproof because perspective
+       * transformations change the orientation of scanlines, and
+       * consequently what's good at the bottom may not be best at the
+       * top.
+       */
+      /*
+       * Determine whether tile access should be "flipped". First, in
+       * the y direction, because this is the one we can afford most
+       * not to get right.
+       */
+      const gdouble u_start_y =
+	inverse.coeff [0][0] * (roi->x + (gdouble) 0.5) +
+	inverse.coeff [0][1] * (roi->y + (gdouble) 0.5) +
+	inverse.coeff [0][2];
+      const gdouble v_start_y =
+	inverse.coeff [1][0] * (roi->x + (gdouble) 0.5) +
+	inverse.coeff [1][1] * (roi->y + (gdouble) 0.5) +
+	inverse.coeff [1][2];
+      const gdouble w_start_y =
+	inverse.coeff [2][0] * (roi->x + (gdouble) 0.5) +
+	inverse.coeff [2][1] * (roi->y + (gdouble) 0.5) +
+	inverse.coeff [2][2];
+
+      const gdouble u_float_y =
+	u_start_y + inverse.coeff [0][1] * (roi->height - (gint) 1);
+      const gdouble v_float_y =
+	v_start_y + inverse.coeff [1][1] * (roi->height - (gint) 1);
+      const gdouble w_float_y =
+	w_start_y + inverse.coeff [2][1] * (roi->height - (gint) 1);
+
+      const gint bflip_y =
+	(u_float_y + v_float_y)/w_float_y < (u_start_y + v_start_y)/w_start_y
+	?
+	(gint) 1
+	:
+	(gint) 0;
+      const gint flip_y = (gint) 1 - (gint) 2 * bflip_y;
 
-              gegl_sampler_get (sampler,
-                                u,
-                                v,
-                                &inverse_jacobian,
-                                dest_ptr,
-                                GEGL_ABYSS_NONE);
+      /*
+       * Now determine whether to flip in the horizontal
+       * direction. Done last because this is the most important one,
+       * and consequently we want to use the likely "initial scanline"
+       * to at least get that one about right.
+       */
+      const gdouble u_start_x = bflip_y ? u_float_y : u_start_y;
+      const gdouble v_start_x = bflip_y ? v_float_y : v_start_y;
+      const gdouble w_start_x = bflip_y ? w_float_y : w_start_y;
+
+      const gdouble u_float_x =
+	u_start_x + inverse.coeff [0][0] * (roi->width - (gint) 1);
+      const gdouble v_float_x =
+	v_start_x + inverse.coeff [1][0] * (roi->width - (gint) 1);
+      const gdouble w_float_x =
+	w_start_x + inverse.coeff [2][0] * (roi->width - (gint) 1);
+
+      const gint bflip_x =
+	(u_float_x + v_float_x)/w_float_x < (u_start_x + v_start_x)/w_start_x
+	?
+	(gint) 1
+	:
+	(gint) 0;
+      const gint flip_x = (gint) 1 - (gint) 2 * bflip_x;
+
+      gdouble u_start = bflip_x ? u_float_x : u_start_x;
+      gdouble v_start = bflip_x ? v_float_x : v_start_x;
+      gdouble w_start = bflip_x ? w_float_x : w_start_x;
 
-              u_float  += flip_x * inverse.coeff [0][0];
-              v_float  += flip_x * inverse.coeff [1][0];
-              w_float  += flip_x * inverse.coeff [2][0];
-              dest_ptr += flip_x * (gint) 4;
-            }
+      gfloat * restrict dest_ptr =
+	dest_buf +
+	(gint) 4 * ( bflip_x * (roi->width  - (gint) 1) +
+		     bflip_y * (roi->height - (gint) 1) * roi->width );
 
-          u_start  += flip_y * inverse.coeff [0][1];
-          v_start  += flip_y * inverse.coeff [1][1];
-          w_start  += flip_y * inverse.coeff [2][1];
-          dest_ptr += (gint) 4 * (flip_y - flip_x) * roi->width;
-        }
+      /*
+       * Assumes that height and width are > 0.
+       */
+      gint y = roi->height;
+      do {
+	gdouble u_float = u_start;
+	gdouble v_float = v_start;
+	gdouble w_float = w_start;
+	  
+	gint x = roi->width;
+	do {
+	  gdouble w_recip = (gdouble) 1.0 / w_float;
+	  gdouble u = u_float * w_recip;
+	  gdouble v = v_float * w_recip;
+	    
+	  GeglMatrix2 inverse_jacobian;
+	  inverse_jacobian.coeff [0][0] =
+	    (inverse.coeff [0][0] - inverse.coeff [2][0] * u) * w_recip;
+	  inverse_jacobian.coeff [0][1] =
+	    (inverse.coeff [0][1] - inverse.coeff [2][1] * u) * w_recip;
+	  inverse_jacobian.coeff [1][0] =
+	    (inverse.coeff [1][0] - inverse.coeff [2][0] * v) * w_recip;
+	  inverse_jacobian.coeff [1][1] =
+	    (inverse.coeff [1][1] - inverse.coeff [2][1] * v) * w_recip;
+	    
+	  gegl_sampler_get (sampler,
+			    u,
+			    v,
+			    &inverse_jacobian,
+			    dest_ptr,
+			    GEGL_ABYSS_NONE);
+
+	  dest_ptr += flip_x * (gint) 4;
+	  u_float += flip_x * inverse.coeff [0][0];
+	  v_float += flip_x * inverse.coeff [1][0];
+	  w_float += flip_x * inverse.coeff [2][0];
+	} while (--x);
+
+	dest_ptr += (gint) 4 * (flip_y - flip_x) * roi->width;
+	u_start += flip_y * inverse.coeff [0][1];
+	v_start += flip_y * inverse.coeff [1][1];
+	w_start += flip_y * inverse.coeff [2][1];
+      } while (--y);
     }
 }
 
+
 /*
  * Use to determine if key transform matrix coefficients are close
  * enough to zero or integers.



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