[gegl] affine: Add fast paths for axis aligned reflect
- From: Øyvind Kolås <ok src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gegl] affine: Add fast paths for axis aligned reflect
- Date: Tue, 19 Jan 2010 22:43:51 +0000 (UTC)
commit 520d69ab8a78e38af2c557d69323e9f9c4158aac
Author: Debarshi Ray <debarshir src gnome org>
Date: Tue Jan 12 23:53:25 2010 +0200
affine: Add fast paths for axis aligned reflect
Fixing bug 592106
operations/affine/affine.c | 188 +++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 184 insertions(+), 4 deletions(-)
---
diff --git a/operations/affine/affine.c b/operations/affine/affine.c
index ec64ddf..641cf12 100644
--- a/operations/affine/affine.c
+++ b/operations/affine/affine.c
@@ -28,7 +28,9 @@
#include <math.h>
+#include <gegl.h>
#include <gegl-plugin.h>
+#include <gegl-utils.h>
#include "buffer/gegl-sampler.h"
#include <graph/gegl-pad.h>
#include <graph/gegl-node.h>
@@ -84,6 +86,19 @@ static GeglNode * gegl_affine_detect (GeglOperation
gint x,
gint y);
+static gboolean gegl_affine_matrix3_allow_fast_translate (GeglMatrix3 matrix);
+static gboolean gegl_affine_matrix3_allow_fast_reflect_x (GeglMatrix3 matrix);
+static gboolean gegl_affine_matrix3_allow_fast_reflect_y (GeglMatrix3 matrix);
+
+static void gegl_affine_fast_reflect_x (GeglBuffer *dest,
+ GeglBuffer *src,
+ const GeglRectangle *dest_rect,
+ const GeglRectangle *src_rect);
+static void gegl_affine_fast_reflect_y (GeglBuffer *dest,
+ GeglBuffer *src,
+ const GeglRectangle *dest_rect,
+ const GeglRectangle *src_rect);
+
/* ************************* */
@@ -719,6 +734,120 @@ affine_generic (GeglBuffer *dest,
}
}
+static gboolean
+gegl_affine_matrix3_allow_fast_translate (GeglMatrix3 matrix)
+{
+ if (! GEGL_FLOAT_EQUAL (matrix[0][2], (gint) matrix[0][2]) ||
+ ! GEGL_FLOAT_EQUAL (matrix[1][2], (gint) matrix[1][2]))
+ return FALSE;
+ return gegl_matrix3_is_translate (matrix);
+}
+
+static gboolean
+gegl_affine_matrix3_allow_fast_reflect_x (GeglMatrix3 matrix)
+{
+ GeglMatrix3 copy;
+
+ if (! GEGL_FLOAT_EQUAL (matrix[1][1], -1.0))
+ return FALSE;
+ gegl_matrix3_copy (copy, matrix);
+ copy[1][1] = 1.;
+ return gegl_affine_matrix3_allow_fast_translate (copy);
+}
+
+static gboolean
+gegl_affine_matrix3_allow_fast_reflect_y (GeglMatrix3 matrix)
+{
+ GeglMatrix3 copy;
+
+ if (! GEGL_FLOAT_EQUAL (matrix[0][0], -1.0))
+ return FALSE;
+ gegl_matrix3_copy (copy, matrix);
+ copy[0][0] = 1.;
+ return gegl_affine_matrix3_allow_fast_translate (copy);
+}
+
+static void
+gegl_affine_fast_reflect_x (GeglBuffer *dest,
+ GeglBuffer *src,
+ const GeglRectangle *dest_rect,
+ const GeglRectangle *src_rect)
+{
+ const Babl *format = gegl_buffer_get_format (src);
+ const gint px_size = babl_format_get_bytes_per_pixel (format),
+ rowstride = src_rect->width * px_size;
+ gint i;
+ guchar *buf = (guchar *) g_malloc (src_rect->height * rowstride);
+
+ gegl_buffer_get (src, 1.0, src_rect, format, buf, GEGL_AUTO_ROWSTRIDE);
+
+ for (i = 0; i < src_rect->height / 2; i++)
+ {
+ gint dest_offset = (src_rect->height - i - 1) * rowstride,
+ src_offset = i * rowstride,
+ j;
+
+ for (j = 0; j < rowstride; j++)
+ {
+ const guchar tmp = buf[src_offset];
+
+ buf[src_offset] = buf[dest_offset];
+ buf[dest_offset] = tmp;
+
+ dest_offset++;
+ src_offset++;
+ }
+ }
+
+ gegl_buffer_set (dest, dest_rect, format, buf, GEGL_AUTO_ROWSTRIDE);
+ g_free (buf);
+}
+
+static void
+gegl_affine_fast_reflect_y (GeglBuffer *dest,
+ GeglBuffer *src,
+ const GeglRectangle *dest_rect,
+ const GeglRectangle *src_rect)
+{
+ const Babl *format = gegl_buffer_get_format (src);
+ const gint px_size = babl_format_get_bytes_per_pixel (format),
+ rowstride = src_rect->width * px_size;
+ gint i;
+ guchar *buf = (guchar *) g_malloc (src_rect->height * rowstride);
+
+ gegl_buffer_get (src, 1.0, src_rect, format, buf, GEGL_AUTO_ROWSTRIDE);
+
+ for (i = 0; i < src_rect->height; i++)
+ {
+ gint src_offset = i * rowstride,
+ dest_offset = src_offset + rowstride,
+ j;
+
+ for (j = 0; j < src_rect->width / 2; j++)
+ {
+ gint k;
+
+ dest_offset -= px_size;
+
+ for (k = 0; k < px_size; k++)
+ {
+ const guchar tmp = buf[src_offset];
+
+ buf[src_offset] = buf[dest_offset];
+ buf[dest_offset] = tmp;
+
+ dest_offset++;
+ src_offset++;
+ }
+
+ dest_offset -= px_size;
+ }
+ }
+
+ gegl_buffer_set (dest, dest_rect, format, buf, GEGL_AUTO_ROWSTRIDE);
+ g_free (buf);
+}
+
void gegl_sampler_prepare (GeglSampler *self);
/*XXX: Eeeek, obsessive avoidance of public headers, the API needed to
* satisfy this use case should probably be provided.
@@ -747,10 +876,9 @@ gegl_affine_process (GeglOperation *operation,
gegl_operation_context_take_object (context, "output", G_OBJECT (input));
}
- else if (gegl_matrix3_is_translate (affine->matrix) &&
- (! strcmp (affine->filter, "nearest") ||
- (affine->matrix [0][2] == (gint) affine->matrix [0][2] &&
- affine->matrix [1][2] == (gint) affine->matrix [1][2])))
+ else if (gegl_affine_matrix3_allow_fast_translate (affine->matrix) ||
+ (gegl_matrix3_is_translate (affine->matrix) &&
+ ! strcmp (affine->filter, "nearest")))
{
/* doing a buffer shifting trick, (enhanced nop) */
input = gegl_operation_context_get_source (context, "input");
@@ -772,6 +900,58 @@ gegl_affine_process (GeglOperation *operation,
if (input != NULL)
g_object_unref (input);
}
+ else if (gegl_affine_matrix3_allow_fast_reflect_x (affine->matrix))
+ {
+ GeglRectangle src_rect;
+ GeglSampler *sampler;
+
+ input = gegl_operation_context_get_source (context, "input");
+ if (!input)
+ {
+ g_warning ("transform received NULL input");
+ return FALSE;
+ }
+
+ output = gegl_operation_context_get_target (context, "output");
+
+ src_rect = gegl_operation_get_required_for_output (operation, "output", result);
+ src_rect.y += 1;
+
+ sampler = op_affine_sampler (OP_AFFINE (operation));
+ src_rect.width -= sampler->context_rect.width;
+ src_rect.height -= sampler->context_rect.height;
+
+ gegl_affine_fast_reflect_x (output, input, result, &src_rect);
+
+ if (input != NULL)
+ g_object_unref (input);
+ }
+ else if (gegl_affine_matrix3_allow_fast_reflect_y (affine->matrix))
+ {
+ GeglRectangle src_rect;
+ GeglSampler *sampler;
+
+ input = gegl_operation_context_get_source (context, "input");
+ if (!input)
+ {
+ g_warning ("transform received NULL input");
+ return FALSE;
+ }
+
+ output = gegl_operation_context_get_target (context, "output");
+
+ src_rect = gegl_operation_get_required_for_output (operation, "output", result);
+ src_rect.x += 1;
+
+ sampler = op_affine_sampler (OP_AFFINE (operation));
+ src_rect.width -= sampler->context_rect.width;
+ src_rect.height -= sampler->context_rect.height;
+
+ gegl_affine_fast_reflect_y (output, input, result, &src_rect);
+
+ if (input != NULL)
+ g_object_unref (input);
+ }
else
{
/* for all other cases, do a proper resampling */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]