[gegl] noise-simplex: actually add the files



commit 3c4abdb5803eb89a152345c1db181fbc3888e215
Author: Øyvind Kolås <pippin gimp org>
Date:   Fri May 16 23:10:04 2014 +0200

    noise-simplex: actually add the files

 opencl/noise-simplex.cl                        |   88 +++++++
 operations/common/noise-simplex.c              |  325 ++++++++++++++++++++++++
 tests/compositions/noise-simplex.xml           |   29 ++
 tests/compositions/reference/noise-simplex.png |  Bin 0 -> 226715 bytes
 4 files changed, 442 insertions(+), 0 deletions(-)
---
diff --git a/opencl/noise-simplex.cl b/opencl/noise-simplex.cl
new file mode 100644
index 0000000..bb59758
--- /dev/null
+++ b/opencl/noise-simplex.cl
@@ -0,0 +1,88 @@
+#define MAX_RANK 3
+
+static float2
+philox (uint2 st,
+        uint k)
+{
+  ulong p;
+  int   i;
+
+  for (i = 0 ; i < 3 ; i += 1)
+    {
+      p = st.x * 0xcd9e8d57ul;
+
+      st.x = ((uint)(p >> 32)) ^ st.y ^ k;
+      st.y = (uint)p;
+
+      k += 0x9e3779b9u;
+    }
+
+  return convert_float2(st) / 2147483648.0 - 1.0;
+}
+
+__kernel void kernel_noise (__global float *out,
+                            const int x_0,
+                            const int y_0,
+                            const uint iterations,
+                            const float scale,
+                            const uint seed)
+{
+  const int gidx = get_global_id(0);
+  const int gidy = get_global_id(1);
+
+  float  c, d, m;
+  float2 p;
+  int    j;
+
+  for (j = 0, m = 0, c = 1, d = scale;
+       j < iterations;
+       c *= 2, d *= 2, j += 1)
+    {
+      float s, t, n;
+      float2 g[3], u[3], i, di;
+      int k;
+
+      p = (float2)(gidx + x_0, gidy + y_0) * d;
+
+      /* Skew the input point and find the lowest corner of the containing
+         simplex. */
+
+      s = (p.x + p.y) * (sqrt(3.0) - 1) / 2;
+      i = floor(p + s);
+
+      /* Calculate the (unskewed) distance between the input point and all
+         simplex corners. */
+
+      s = (i.x + i.y) * (3 - sqrt(3.0)) / 6;
+      u[0] = p - i + s;
+
+      di = u[0].x >= u[0].y ? (float2)(1, 0) : (float2)(0, 1);
+
+      u[1] = u[0] - di + (3 - sqrt(3.0)) / 6;
+      u[2] = u[0] - 1 + (3 - sqrt(3.0)) / 3;
+
+      /* Calculate gradients for each corner vertex. We convert to
+       * signed int first to avoid implementation-defined behavior for
+       * out-of-range values.  See section 6.2.3.3 of the OpenCL
+       * specification. */
+
+      g[0] = philox(convert_uint2(convert_int2(i)), seed);
+      g[1] = philox(convert_uint2(convert_int2(i + di)), seed);
+      g[2] = philox(convert_uint2(convert_int2(i + 1)), seed);
+
+      for (k = 0, n = 0 ; k < 3 ; k += 1)
+        {
+          t = 0.5 - dot(u[k], u[k]);
+
+          if (t > 0)
+            {
+              t *= t;
+              n += t * t * dot(g[k], u[k]);
+            }
+        }
+
+      m += 70 * n / c;
+    }
+
+  out[gidy * get_global_size(0) + gidx] = m;
+}
diff --git a/operations/common/noise-simplex.c b/operations/common/noise-simplex.c
new file mode 100644
index 0000000..f061465
--- /dev/null
+++ b/operations/common/noise-simplex.c
@@ -0,0 +1,325 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2014 Dimitris Papavasiliou <dpapavas google com>
+ */
+
+/* This plug-in generates noise textures originally presented by Ken
+ * Perlin during a SIGGRAPH 2002 course and further explained in the
+ * paper "Simplex noise demystified" by Stefan Gustavson.
+ *
+ * Comments and improvements for this code are welcome.
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_seed    (seed, rand, _("Random seed"),
+                    _("The random seed for the noise function"))
+gegl_chant_double  (scale, _("Scale"), 0, 20.0, 1.0,
+                    _("The scale of the noise function"))
+gegl_chant_int     (iterations, _("Iterations"), 1, 20, 1,
+                    _("The number of noise octaves."))
+
+#else
+
+#define GEGL_CHANT_TYPE_POINT_RENDER
+#define GEGL_CHANT_C_FILE       "noise-simplex.c"
+
+#include "gegl-chant.h"
+#include <gegl-buffer-cl-iterator.h>
+#include <gegl-debug.h>
+#include <math.h>
+
+#include "opencl/noise-simplex.cl.h"
+
+typedef struct
+{
+  guint seed;
+} Context;
+
+static GeglClRunData *cl_data = NULL;
+
+static inline gdouble
+dot_2(gdouble *p,
+      gdouble *q)
+{
+  return p[0] * q[0] + p[1] * q[1];
+}
+
+static inline void
+philox (guint    s,
+        guint    t,
+        guint    k,
+        gdouble *h)
+{
+  guint64 p;
+  gint    i;
+
+  /* For details regarding this hash function consult:
+
+     Salmon, J.K.; Moraes, M.A.; Dror, R.O.; Shaw, D.E., "Parallel
+     random numbers: As easy as 1, 2, 3," High Performance Computing,
+     Networking, Storage and Analysis (SC), 2011 International
+     Conference for , vol., no., pp.1,12, 12-18 Nov. 2011 */\
+
+  for (i = 0 ; i < 3 ; i += 1)
+    {
+      p = s * (guint64)0xcd9e8d57;
+
+      s = ((guint)(p >> 32)) ^ t ^ k;
+      t = (guint)p;
+
+      k += 0x9e3779b9;
+    }
+
+  h[0] = s / 2147483648.0 - 1.0;
+  h[1] = t / 2147483648.0 - 1.0;
+}
+
+static gdouble
+noise2 (gdouble  x,
+        gdouble  y,
+        Context *context)
+{
+  gdouble s, t, n;
+  gdouble g[3][2], u[3][2];
+  gint i, j, di, k;
+
+  /* Skew the input point and find the lowest corner of the containing
+     simplex. */
+
+  s = (x + y) * (sqrt(3) - 1) / 2;
+  i = (gint)floor(x + s);
+  j = (gint)floor(y + s);
+
+  /* Calculate the (unskewed) distance between the input point and all
+     simplex corners. */
+
+  s = (i + j) * (3 - sqrt(3)) / 6;
+  u[0][0] = x - i + s;
+  u[0][1] = y - j + s;
+
+  di = (u[0][0] >= u[0][1]);
+
+  u[1][0] = u[0][0] - di + (3 - sqrt(3)) / 6;
+  u[1][1] = u[0][1] - !di + (3 - sqrt(3)) / 6;
+
+  u[2][0] = u[0][0] - 1 + (3 - sqrt(3)) / 3;
+  u[2][1] = u[0][1] - 1 + (3 - sqrt(3)) / 3;
+
+  /* Calculate gradients for each corner vertex. */
+
+  philox(i, j, context->seed, g[0]);
+  philox(i + di, j + !di, context->seed, g[1]);
+  philox(i + 1, j + 1, context->seed, g[2]);
+
+  /* Finally accumulate the contribution of each vertex to the current
+   * pixel. */
+
+  for (k = 0, n = 0 ; k < 3 ; k += 1)
+    {
+      t = 0.5 - dot_2(u[k], u[k]);
+
+      if (t > 0)
+        {
+          t *= t;
+          n += t * t * dot_2(g[k], u[k]);
+        }
+    }
+
+  /* Normalize result to lie in [-1, 1]. */
+
+  return 70 * n;
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  gegl_operation_set_format (operation, "output", babl_format ("Y float"));
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+  return gegl_rectangle_infinite_plane ();
+}
+
+static gboolean
+cl_process (GeglOperation       *operation,
+            cl_mem               out_tex,
+            const GeglRectangle *roi)
+{
+  GeglChantO   *o          = GEGL_CHANT_PROPERTIES (operation);
+  const size_t  gbl_size[] = {roi->width, roi->height};
+  size_t        work_group_size;
+  cl_uint       cl_iterations   = o->iterations;
+  cl_int        cl_err          = 0;
+  cl_int        cl_x_0          = roi->x;
+  cl_int        cl_y_0          = roi->y;
+  cl_float      cl_scale        = o->scale / 50.0;
+  cl_uint       cl_seed         = o->seed;
+
+  if (!cl_data)
+    {
+      const char *kernel_name[] = {"kernel_noise", NULL};
+      cl_data = gegl_cl_compile_and_build (noise_simplex_cl_source,
+                                           kernel_name);
+
+      if (!cl_data)
+        return TRUE;
+    }
+
+  cl_err = gegl_cl_set_kernel_args (cl_data->kernel[0],
+                                    sizeof(cl_mem), &out_tex,
+                                    sizeof(cl_int), &cl_x_0,
+                                    sizeof(cl_int), &cl_y_0,
+                                    sizeof(cl_uint), &cl_iterations,
+                                    sizeof(cl_float), &cl_scale,
+                                    sizeof(cl_uint), &cl_seed,
+                                    NULL);
+  CL_CHECK;
+
+  cl_err = gegl_clGetKernelWorkGroupInfo (cl_data->kernel[0],
+                                          gegl_cl_get_device (),
+                                          CL_KERNEL_WORK_GROUP_SIZE,
+                                          sizeof (size_t), &work_group_size,
+                                          NULL);
+  CL_CHECK;
+
+  cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
+                                        cl_data->kernel[0], 2,
+                                        NULL, gbl_size, NULL,
+                                        0, NULL, NULL);
+  CL_CHECK;
+
+  cl_err = gegl_clFinish (gegl_cl_get_command_queue ());
+  CL_CHECK;
+
+  return FALSE;
+
+error:
+  return TRUE;
+}
+
+static gboolean
+c_process (GeglOperation       *operation,
+           void                *out_buf,
+           glong                n_pixels,
+           const GeglRectangle *roi,
+           gint                 level)
+{
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+  Context     context;
+  gfloat     *pixel;
+  gint        s, t;
+
+  context.seed = o->seed;
+
+  for (t = 0, pixel = out_buf ; t < roi->height ; t += 1)
+    {
+      for (s = 0 ; s < roi->width ; s += 1, pixel += 1)
+        {
+          gint    i;
+          gdouble c, d;
+
+          /* Pile up noise octaves onto the output value. */
+
+          for (i = 0, c = 1, d = o->scale / 50.0, *pixel = 0;
+               i < o->iterations;
+               c *= 2, d *= 2, i += 1)
+            {
+              *pixel += noise2 ((double) (s + roi->x) * d,
+                                (double) (t + roi->y) * d,
+                                &context) / c;
+            }
+        }
+    }
+
+  return TRUE;
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *out_buf,
+         const GeglRectangle *roi,
+         gint                 level)
+{
+  GeglBufferIterator *iter;
+  const Babl         *out_format = gegl_operation_get_format (operation,
+                                                              "output");
+
+  g_assert(babl_format_get_n_components (out_format) == 1 &&
+           babl_format_get_type (out_format, 0) == babl_type ("float"));
+
+  if (gegl_operation_use_opencl (operation))
+    {
+      GeglBufferClIterator *cl_iter;
+      gboolean              err;
+
+      GEGL_NOTE (GEGL_DEBUG_OPENCL, "GEGL_OPERATION_POINT_RENDER: %s", GEGL_OPERATION_GET_CLASS 
(operation)->name);
+
+      cl_iter = gegl_buffer_cl_iterator_new (out_buf, roi, out_format, GEGL_CL_BUFFER_WRITE);
+
+      while (gegl_buffer_cl_iterator_next (cl_iter, &err) && !err)
+        {
+          err = cl_process (operation, cl_iter->tex[0], cl_iter->roi);
+
+          if (err)
+            {
+              gegl_buffer_cl_iterator_stop (cl_iter);
+              break;
+            }
+        }
+
+      if (err)
+        GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", GEGL_OPERATION_GET_CLASS (operation)->name);
+      else
+        return TRUE;
+    }
+
+  iter = gegl_buffer_iterator_new (out_buf, roi, level, out_format,
+                                   GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+
+  while (gegl_buffer_iterator_next (iter))
+    c_process (operation, iter->data[0], iter->length, &iter->roi[0], level);
+
+  return  TRUE;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationSourceClass *source_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
+
+  source_class->process = process;
+  operation_class->get_bounding_box = get_bounding_box;
+  operation_class->prepare = prepare;
+  operation_class->opencl_support = TRUE;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name"       , "gegl:simplex-noise",
+    "categories" , "render",
+    "description", _("Generates a solid noise texture."),
+    NULL);
+}
+
+#endif
diff --git a/tests/compositions/noise-simplex.xml b/tests/compositions/noise-simplex.xml
new file mode 100644
index 0000000..06ce26b
--- /dev/null
+++ b/tests/compositions/noise-simplex.xml
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gegl>
+  <node operation='gegl:crop'>
+      <params>
+        <param name='x'>-128</param>
+        <param name='y'>-128</param>
+        <param name='width'>256</param>
+        <param name='height'>256</param>
+      </params>
+  </node>
+  <node operation='gegl:multiply'>
+      <params>
+        <param name='value'>0.5</param>
+      </params>
+  </node>
+  <node operation='gegl:add'>
+      <params>
+        <param name='value'>1</param>
+      </params>
+  </node>
+  <node operation='gegl:simplex-noise'>
+      <params>
+        <param name='seed'>0</param>
+        <param name='scale'>2.4</param>
+        <param name='iterations'>3</param>
+      </params>
+  </node>
+</gegl>
+
diff --git a/tests/compositions/reference/noise-simplex.png b/tests/compositions/reference/noise-simplex.png
new file mode 100644
index 0000000..9077ee9
Binary files /dev/null and b/tests/compositions/reference/noise-simplex.png differ


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