[gegl] samplers use rectangular tiles



commit 9025ff2fc1f0e38635130c7fbc4c5f65ed71a94f
Author: Nicolas Robidoux <nrobidoux git gnome org>
Date:   Thu Dec 20 13:40:59 2012 -0500

    samplers use rectangular tiles

 gegl/buffer/gegl-sampler-cubic.c      |    8 ++--
 gegl/buffer/gegl-sampler-linear.c     |    4 +-
 gegl/buffer/gegl-sampler-lohalo.c     |    6 ++--
 gegl/buffer/gegl-sampler.c            |   40 +++++++++++----------
 gegl/buffer/gegl-sampler.h            |    2 +-
 operations/transform/transform-core.c |   64 ++++++++++++++++++--------------
 6 files changed, 67 insertions(+), 57 deletions(-)
---
diff --git a/gegl/buffer/gegl-sampler-cubic.c b/gegl/buffer/gegl-sampler-cubic.c
index 8448adf..33ba4b5 100644
--- a/gegl/buffer/gegl-sampler-cubic.c
+++ b/gegl/buffer/gegl-sampler-cubic.c
@@ -167,10 +167,10 @@ gegl_sampler_cubic_get (      GeglSampler     *self,
 {
   GeglSamplerCubic *cubic = (GeglSamplerCubic*)(self);
   const gint        offsets[16] =
-                      {-4-GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT   *4, 4, 4, 4,
-                         (GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT-3)*4, 4, 4, 4,
-                         (GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT-3)*4, 4, 4, 4,
-                         (GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT-3)*4, 4, 4, 4};
+                      {-4-2*GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT   *4, 4, 4, 4,
+                         (2*GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT-3)*4, 4, 4, 4,
+                         (2*GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT-3)*4, 4, 4, 4,
+                         (2*GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT-3)*4, 4, 4, 4};
   gfloat           *sampler_bptr;
   gfloat            factor;
   gfloat            newval[4] = {0.0, 0.0, 0.0, 0.0};
diff --git a/gegl/buffer/gegl-sampler-linear.c b/gegl/buffer/gegl-sampler-linear.c
index bb63b76..88c8da4 100644
--- a/gegl/buffer/gegl-sampler-linear.c
+++ b/gegl/buffer/gegl-sampler-linear.c
@@ -66,7 +66,7 @@ gegl_sampler_linear_class_init (GeglSamplerLinearClass *klass)
  * 0 if it is found that round off error never sends things "too far
  * away". Nicolas would be very surprised if more than 1 is necessary.
  */
-#define LINEAR_EXTRA_ELBOW_ROOM 1
+#define LINEAR_EXTRA_ELBOW_ROOM 0
 
 static void
 gegl_sampler_linear_init (GeglSamplerLinear *self)
@@ -86,7 +86,7 @@ gegl_sampler_linear_get (      GeglSampler*    restrict  self,
                                void*           restrict  output,
                                GeglAbyssPolicy           repeat_mode)
 {
-  const gint pixels_per_buffer_row = GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
+  const gint pixels_per_buffer_row = (gint) 2 * GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
   const gint channels = 4;
 
   /*
diff --git a/gegl/buffer/gegl-sampler-lohalo.c b/gegl/buffer/gegl-sampler-lohalo.c
index 07b09c3..20a142e 100644
--- a/gegl/buffer/gegl-sampler-lohalo.c
+++ b/gegl/buffer/gegl-sampler-lohalo.c
@@ -411,7 +411,7 @@ gegl_sampler_lohalo_class_init (GeglSamplerLohaloClass *klass)
 /*
  * IMPORTANT: LOHALO_OFFSET_0 SHOULD BE AN INTEGER >= 2.
  */
-#define LOHALO_OFFSET_0 (8)
+#define LOHALO_OFFSET_0 (7)
 #define LOHALO_SIZE_0 ( 1 + 2 * LOHALO_OFFSET_0 )
 
 /*
@@ -424,7 +424,7 @@ gegl_sampler_lohalo_class_init (GeglSamplerLohaloClass *klass)
  * mipmap level's offset should almost never be smaller than half the
  * previous level's offset.
  */
-#define LOHALO_OFFSET_MIPMAP (8)
+#define LOHALO_OFFSET_MIPMAP (7)
 #define LOHALO_SIZE_MIPMAP ( 1 + 2 * LOHALO_OFFSET_MIPMAP )
 
 #define LOHALO_OFFSET_1 LOHALO_OFFSET_MIPMAP
@@ -1442,7 +1442,7 @@ gegl_sampler_lohalo_get (      GeglSampler*    restrict  self,
    * corresponds to fetch_rectangle.width in gegl_sampler_get_ptr.
    */
   const gint channels  = 4;
-  const gint pixels_per_row = GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
+  const gint pixels_per_row = (gint) 2 * GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
   const gint row_skip = channels * pixels_per_row;
 
   /*
diff --git a/gegl/buffer/gegl-sampler.c b/gegl/buffer/gegl-sampler.c
index f2bc629..bd2a273 100644
--- a/gegl/buffer/gegl-sampler.c
+++ b/gegl/buffer/gegl-sampler.c
@@ -227,8 +227,10 @@ gegl_sampler_get_ptr (GeglSampler *const sampler,
    */
   const gint maximum_width_and_height =
     GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
-  g_assert (sampler->context_rect[0].width  <= maximum_width_and_height);
-  g_assert (sampler->context_rect[0].height <= maximum_width_and_height);
+  g_assert (sampler->context_rect[0].width  <=
+	    (gint) 2 * maximum_width_and_height);
+  g_assert (sampler->context_rect[0].height <=
+	    maximum_width_and_height);
 
   if ((sampler->sampler_buffer[0] == NULL)
       ||
@@ -267,14 +269,14 @@ gegl_sampler_get_ptr (GeglSampler *const sampler,
        */
       fetch_rectangle.x =
         x + sampler->context_rect[0].x -
-        (maximum_width_and_height - sampler->context_rect[0].width ) /
-        (gint) 8;
+        ((gint) 2 * maximum_width_and_height - sampler->context_rect[0].width ) /
+        (gint) 4;
       fetch_rectangle.y =
         y + sampler->context_rect[0].y -
         (maximum_width_and_height - sampler->context_rect[0].height) /
-        (gint) 8;
+        (gint) 4;
 
-      fetch_rectangle.width  = maximum_width_and_height;
+      fetch_rectangle.width  = (gint) 2 * maximum_width_and_height;
       fetch_rectangle.height = maximum_width_and_height;
 
       if (sampler->sampler_buffer[0] == NULL)
@@ -283,7 +285,7 @@ gegl_sampler_get_ptr (GeglSampler *const sampler,
            * Always request the same amount of pixels:
            */
           sampler->sampler_buffer[0] =
-            g_malloc0 (( maximum_width_and_height * maximum_width_and_height )
+            g_malloc0 (( (gint) 2 * maximum_width_and_height * maximum_width_and_height )
                        * bpp);
         }
 
@@ -327,7 +329,7 @@ gegl_sampler_get_from_buffer (GeglSampler *const sampler,
    */
   const gint maximum_width_and_height =
     GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
-  g_assert (sampler->context_rect[0].width  <= maximum_width_and_height);
+  g_assert (sampler->context_rect[0].width  <= (gint) 2 * maximum_width_and_height);
   g_assert (sampler->context_rect[0].height <= maximum_width_and_height);
 
   if ((sampler->sampler_buffer[0] == NULL)
@@ -349,13 +351,13 @@ gegl_sampler_get_from_buffer (GeglSampler *const sampler,
       GeglRectangle fetch_rectangle;
 
       fetch_rectangle.x = x -
-        (maximum_width_and_height - sampler->context_rect[0].width ) /
-        (gint) 8;
+        ((gint) 2 * maximum_width_and_height - sampler->context_rect[0].width ) /
+        (gint) 4;
       fetch_rectangle.y = y -
         (maximum_width_and_height - sampler->context_rect[0].height) /
-        (gint) 8;
+        (gint) 4;
 
-      fetch_rectangle.width  = maximum_width_and_height;
+      fetch_rectangle.width  = (gint) 2 * maximum_width_and_height;
       fetch_rectangle.height = maximum_width_and_height;
 
       if (sampler->sampler_buffer[0] == NULL)
@@ -364,7 +366,7 @@ gegl_sampler_get_from_buffer (GeglSampler *const sampler,
            * Always request the same amount of pixels:
            */
           sampler->sampler_buffer[0] =
-            g_malloc0 (( maximum_width_and_height * maximum_width_and_height )
+            g_malloc0 (( (gint) 2 * maximum_width_and_height * maximum_width_and_height )
                        * bpp);
         }
 
@@ -411,7 +413,7 @@ gegl_sampler_get_from_mipmap (GeglSampler *const sampler,
    */
   const gint maximum_width_and_height =
     GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT;
-  g_assert (sampler->context_rect[level].width  <= maximum_width_and_height);
+  g_assert (sampler->context_rect[level].width  <= (gint) 2 * maximum_width_and_height);
   g_assert (sampler->context_rect[level].height <= maximum_width_and_height);
   g_assert (level >= 0 && level < GEGL_SAMPLER_MIPMAP_LEVELS);
 
@@ -441,14 +443,14 @@ gegl_sampler_get_from_mipmap (GeglSampler *const sampler,
 
       fetch_rectangle.x =
         x + sampler->context_rect[level].x -
-        (maximum_width_and_height - sampler->context_rect[level].width ) /
-        (gint) 8;
+        ((gint) 2 * maximum_width_and_height - sampler->context_rect[level].width ) /
+        (gint) 4;
       fetch_rectangle.y =
         y + sampler->context_rect[level].y -
         (maximum_width_and_height - sampler->context_rect[level].height) /
-        (gint) 8;
+        (gint) 4;
 
-      fetch_rectangle.width  = maximum_width_and_height;
+      fetch_rectangle.width  = (gint) 2 * maximum_width_and_height;
       fetch_rectangle.height = maximum_width_and_height;
 
       if (sampler->sampler_buffer[level] == NULL)
@@ -457,7 +459,7 @@ gegl_sampler_get_from_mipmap (GeglSampler *const sampler,
            * Always request the same amount of pixels:
            */
           sampler->sampler_buffer[level] =
-            g_malloc0 (( maximum_width_and_height * maximum_width_and_height )
+            g_malloc0 (( (gint) 2 * maximum_width_and_height * maximum_width_and_height )
                        * bpp);
         }
 
diff --git a/gegl/buffer/gegl-sampler.h b/gegl/buffer/gegl-sampler.h
index 7b01ef3..c894067 100644
--- a/gegl/buffer/gegl-sampler.h
+++ b/gegl/buffer/gegl-sampler.h
@@ -41,7 +41,7 @@ G_BEGIN_DECLS
  * The way the samplers use mipmap levels, square buffers are
  * preferable to rectangular ones.
  */
-#define GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT 64
+#define GEGL_SAMPLER_MAXIMUM_WIDTH_AND_HEIGHT 32
 
 typedef struct _GeglSamplerClass GeglSamplerClass;
 
diff --git a/operations/transform/transform-core.c b/operations/transform/transform-core.c
index 1723726..6b4e61b 100644
--- a/operations/transform/transform-core.c
+++ b/operations/transform/transform-core.c
@@ -839,27 +839,26 @@ transform_affine (GeglBuffer  *dest,
    *
    * Explanation:
    *
-   * GEGL uses square buffer tiles in "output space", which this
-   * function fills with data. Pulling a scanline (within such a
-   * square tile) back to input space (with the inverse
+   * GEGL uses wider than tall rectangular buffer tiles in "output
+   * space", which this function fills with data. Pulling a scanline
+   * (within such a square tile) back to input space (with the inverse
    * transformation) with an arbitrary affine transformation may make
    * the scanline go from right to left in input space even though it
    * goes form left to right in input space. Similarly, a scanline
    * which is below the first one in output space may be above in
-   * input space. Unfortunately, input buffer tiles (which are square)
-   * are allocated with a bias: less elbow room around the
-   * context_rect (square of data needed by the sampler) is put at the
-   * left and top than at the right and bottom. (Such asymetrical
-   * elbow room is beneficial when resizing, for example, since input
-   * space is then traversed from left to right and top to bottom,
-   * which means that the left and top elbow room is not used in this
-   * situation.) When the affine transformation "flips" things,
-   * however, the elbow room is "on the wrong side", and for this
-   * reason such transformations run much much slower because many
-   * more input buffer tiles get created. One way to make things
-   * better is to traverse the output buffer tile in an appropriate
-   * chosen "reverse order" so that the "short" elbow room is "behind"
-   * instead of "ahead".
+   * input space. Unfortunately, input buffer tiles are allocated with
+   * a bias: less elbow room around the context_rect (square of data
+   * needed by the sampler) is put at the left and top than at the
+   * right and bottom. (Such asymetrical elbow room is beneficial when
+   * resizing, for example, since input space is then traversed from
+   * left to right and top to bottom, which means that the left and
+   * top elbow room is not used in this situation.) When the affine
+   * transformation "flips" things, however, the elbow room is "on the
+   * wrong side", and for this reason such transformations run much
+   * much slower because many more input buffer tiles get created. One
+   * way to make things better is to traverse the output buffer tile
+   * in an appropriate chosen "reverse order" so that the "short"
+   * elbow room is "behind" instead of "ahead".
    *
    * Things are actually a bit more complicated than that. Here is a
    * terse description of what's actually done, without a full
@@ -872,13 +871,13 @@ transform_affine (GeglBuffer  *dest,
    * input tile? Because the input tile is square and most of the
    * extra elbow room is at the bottom and right, the "best" direction
    * is going down the diagonal of the square, approximately from top
-   * left to bottom right.
+   * left to bottom right of the tile.
    *
    * Of course, we do not have control over the actual line traced by
    * the output scanline in input space. But what the above tells us
    * is that if the inner product of the pulled back "scanline vector"
-   * with the vector (1,1) (which corresponds to going diagonally from
-   * top-left to bottom-right in images) is negative, we are going
+   * with the vector (2,1) (which corresponds to going diagonally from
+   * top-left to bottom-right in the tile) is negative, we are going
    * opposite to "best". This can be rectified by filling the output
    * scanline in reverse order: from right to left in output space.
    *
@@ -887,7 +886,7 @@ transform_affine (GeglBuffer  *dest,
    * likely to "stick out". Repeating the same argument used for a
    * single scanline, we see that the sign of the inner product of the
    * inverse image of the vector that points straight down in output
-   * space with the input space vector (1,1) tells us whether we
+   * space with the input space vector (2,1) tells us whether we
    * should fill the output tile from the top down or from the bottom
    * up.
    *
@@ -919,8 +918,14 @@ transform_affine (GeglBuffer  *dest,
    * coordinate axes, or a centered disc, matters, irrespective of
    * orientation ("left-hand" VS "right-hand") issues.
    */
+  /*
+   * The criterion for flipping is based on tiles that are twice as
+   * wide as high. This is where the "(gdouble) 2. *" comes from:
+   * inner product with the vector (2,1).
+   */
 
-  if (inverse.coeff [0][0] + inverse.coeff [1][0] < (gdouble) 0.0)
+  if ((gdouble) 2. * inverse.coeff [0][0] + inverse.coeff [1][0] <
+      (gdouble) 0.)
     {
       /*
        * Flip the horizontal scan component of the inverse jacobian:
@@ -934,7 +939,8 @@ transform_affine (GeglBuffer  *dest,
       flip_x = (gint) 1;
     }
 
-  if (inverse.coeff [0][1] + inverse.coeff [1][1] < (gdouble) 0.0)
+  if ((gdouble) 2. * inverse.coeff [0][1] + inverse.coeff [1][1] <
+      (gdouble) 0.)
     {
       /*
        * Flip the vertical scan component of the inverse jacobian:
@@ -1037,9 +1043,9 @@ transform_generic (GeglBuffer  *dest,
   /*
    * 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 square "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
+   * 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.
@@ -1066,7 +1072,8 @@ transform_generic (GeglBuffer  *dest,
   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 ((u_float + v_float)/w_float < (u_start + v_start)/w_start)
+  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".
@@ -1095,7 +1102,8 @@ transform_generic (GeglBuffer  *dest,
   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 = ((u_float + v_float)/w_float < (u_start + v_start)/w_start)
+  bflip_x = (((gdouble) 2. * u_float + v_float)/w_float <
+	     ((gdouble) 2. * u_start + v_start)/w_start)
             ?
             (gint) 1
             :



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