Browse Source

Backport scale, bp and pad nodes

Matthias Vogelgesang 11 years ago
parent
commit
3acc210a71
8 changed files with 1280 additions and 54 deletions
  1. 14 52
      src/CMakeLists.txt
  2. 2 2
      src/scale.cl
  3. 430 0
      src/ufo-lamino-bp-task.c
  4. 47 0
      src/ufo-lamino-bp-task.h
  5. 443 0
      src/ufo-padding-2d-task.c
  6. 47 0
      src/ufo-padding-2d-task.h
  7. 250 0
      src/ufo-scale-task.c
  8. 47 0
      src/ufo-scale-task.h

+ 14 - 52
src/CMakeLists.txt

@@ -2,12 +2,14 @@ cmake_minimum_required(VERSION 2.6)
 
 # --- Set sources -------------------------------------------------------------
 set(ufofilter_SRCS 
-    ufo-filter-scale.c
-    ufo-filter-lamino-bp-generic.c
-    ufo-filter-3d-edf-writer.c
-    ufo-filter-padding-2d.c
-    ufo-filter-lamino-ramp.c
-    ufo-filter-lamino-ft-conv.c
+    ufo-scale-task.c
+    ufo-padding-2d-task.c
+    ufo-lamino-bp-task.c
+    #    ufo-filter-lamino-bp-generic.c
+    #ufo-filter-3d-edf-writer.c
+    #ufo-filter-padding-2d.c
+    #ufo-filter-lamino-ramp.c
+    #ufo-filter-lamino-ft-conv.c
     )
 
 set(ufofilter_KERNELS
@@ -31,46 +33,6 @@ set(ufofilter_HEADERS
 link_directories(${UFO_LIBRARY_DIRS})
 
 
-# --- Add filters that depend on other libraries ------------------------------
-#find_package(TIFF)
-#find_package(OCLFFT)
-pkg_check_modules(UCA uca)
-#pkg_check_modules(OPENCV opencv)
-
-if (UCA_INCLUDE_DIRS AND UCA_LIBRARIES)
-#   set(ufofilter_SRCS ${ufofilter_SRCS} ufo-filter-cam-access.c)
-    set(ufofilter_LIBS ${ufofilter_LIBS} ${UCA_LIBRARIES})
-    include_directories(${UCA_INCLUDE_DIRS})
-endif ()
-
-# if (TIFF_FOUND)
-#     set(ufofilter_SRCS ${ufofilter_SRCS} ufo-filter-reader.c)
-#    set(ufofilter_SRCS ${ufofilter_SRCS} ufo-filter-writer.c)
-#    set(ufofilter_LIBS ${ufofilter_LIBS} ${TIFF_LIBRARIES})
-#    include_directories(${TIFF_INCLUDE_DIRS})
-# endif ()
-
-# if (OCLFFT_FOUND)
-#    set(ufofilter_SRCS ${ufofilter_SRCS} ufo-filter-fft.c)
-#    set(ufofilter_SRCS ${ufofilter_SRCS} ufo-filter-ifft.c)
-#    set(ufofilter_LIBS ${ufofilter_LIBS} ${OCLFFT_LIBRARIES})
-#    include_directories(${OCLFFT_INCLUDE_DIRS})
-# endif ()
-
-# if (OPENCV_FOUND)
-#    set(ufofilter_SRCS ${ufofilter_SRCS} ufo-filter-cv-show.c)
-#    set(ufofilter_LIBS ${ufofilter_LIBS} ${OPENCV_LIBRARIES})
-#    include_directories(${OPENCV_INCLUDE_DIRS})
-#endif ()
-
-
-# --- Add sources that belong to other libraries ------------------------------
-# set(optical_flow_lucas_kanade_misc_SRCS
-#    oflk_cl_buffer.c
-#    oflk_cl_image.c
-#    oflk_pyramid.c)
-
-
 # --- Target ------------------------------------------------------------------
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
@@ -83,21 +45,21 @@ set(all_targets)
 
 foreach(_src ${ufofilter_SRCS})
     # find plugin suffix
-    string(REGEX REPLACE "ufo-filter-([^ \\.]+).*" "\\1" filter "${_src}")
+    string(REGEX REPLACE "ufo-([^ \\.]+)-task.*" "\\1" task "${_src}")
 
     # build string to get miscalleanous sources
-    string(REPLACE "-" "_" _misc ${filter})
+    string(REPLACE "-" "_" _misc ${task})
     string(TOUPPER ${_misc} _misc_upper)
 
     # create an option name and add this to disable filters
     set(target_option "ENABLE_${_misc_upper}")
-    option(${target_option} "Build filter ${filter}" ON)
+    option(${target_option} "Build filter ${task}" ON)
 
-    if(${target_option})
-        set(documented_types "${documented_types}\nufo_filter_${_misc}_get_type")
+    if (${target_option})
+        set(documented_types "${documented_types}\nufo_${_misc}_task_get_type")
         set(_misc "${_misc}_misc_SRCS")
 
-        string(REPLACE "-" "" _targetname ${filter})
+        string(REPLACE "-" "" _targetname ${task})
         set(target "ufofilter${_targetname}")
         set(shared_objects "${shared_objects} -l${target}")
 

+ 2 - 2
src/scale.cl

@@ -1,8 +1,8 @@
-__kernel void scale ( __global float *in, __global float *out, const int width, const float factor )
+__kernel void scale ( __global float *in, __global float *out, const float factor )
 {
     const int idx = get_global_id(0);
     const int idy = get_global_id(1);
-    const int index = idy * width + idx;
+    const int index = idy * get_global_size(0) + idx;
     out[index] = in[index] * factor; 
 }
 

+ 430 - 0
src/ufo-lamino-bp-task.c

@@ -0,0 +1,430 @@
+/**
+ * SECTION:ufo-averager-task
+ * @Short_description: Write TIFF files
+ * @Title: averager
+ *
+ * The averager node writes each incoming image as a TIFF using libtiff to disk.
+ * Each file is prefixed with #UfoLaminoBpTask:prefix and written into
+ * #UfoLaminoBpTask:path.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <math.h>
+#include <ufo-gpu-task-iface.h>
+#include "ufo-lamino-bp-task.h"
+#include "lamino-filter-def.h"
+
+struct _UfoLaminoBpTaskPrivate {
+    cl_context      context;
+    cl_kernel       bp_kernel;
+    cl_kernel       clean_vol_kernel;
+    cl_kernel       norm_vol_kernel;
+    cl_mem          param_mem;
+    gint            proj_idx;
+    CLParameters    params;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_gpu_task_interface_init (UfoGpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoLaminoBpTask, ufo_lamino_bp_task, UFO_TYPE_TASK_NODE,
+                         G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+                                                ufo_task_interface_init)
+                         G_IMPLEMENT_INTERFACE (UFO_TYPE_GPU_TASK,
+                                                ufo_gpu_task_interface_init))
+
+#define UFO_LAMINO_BP_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_LAMINO_BP_TASK, UfoLaminoBpTaskPrivate))
+
+enum {
+    PROP_0 = 0,
+    PROP_THETA,
+    PROP_PSI,
+    PROP_ANGLE_STEP,
+    PROP_VOL_SX,
+    PROP_VOL_SY,
+    PROP_VOL_SZ,
+    PROP_VOL_OX,
+    PROP_VOL_OY,
+    PROP_VOL_OZ,
+    PROP_PROJ_OX,
+    PROP_PROJ_OY,
+    N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+
+UfoNode *
+ufo_lamino_bp_task_new (void)
+{
+    return UFO_NODE (g_object_new (UFO_TYPE_LAMINO_BP_TASK, NULL));
+}
+
+static void
+ufo_lamino_bp_task_setup (UfoTask *task,
+                          UfoResources *resources,
+                          GError **error)
+{
+    UfoLaminoBpTaskPrivate *priv;
+
+    priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (task);
+    priv->proj_idx = 0;
+    priv->context = ufo_resources_get_context (resources);
+    priv->bp_kernel = ufo_resources_get_kernel (resources, "lamino_bp_generic.cl", "lamino_bp_generic", error);
+    priv->norm_vol_kernel = ufo_resources_get_kernel (resources, "lamino_bp_generic.cl", "lamino_norm_vol", error);
+}
+
+static void
+ufo_lamino_bp_task_get_requisition (UfoTask *task,
+                                    UfoBuffer **inputs,
+                                    UfoRequisition *requisition)
+{
+    UfoLaminoBpTaskPrivate *priv;
+    UfoRequisition in_req;
+
+    priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (task);
+    ufo_buffer_get_requisition (inputs[0], &in_req);
+
+    priv->params.proj_sx = in_req.dims[0];
+    priv->params.proj_sy = in_req.dims[1];
+
+    if (priv->param_mem == NULL) {
+        priv->param_mem = clCreateBuffer (priv->context,
+                                          CL_MEM_READ_ONLY, sizeof (CLParameters),
+                                          NULL, NULL);
+    }
+
+    requisition->n_dims = 3;
+    requisition->dims[0] = priv->params.vol_sx;
+    requisition->dims[1] = priv->params.vol_sy;
+    requisition->dims[2] = priv->params.vol_sz;
+}
+
+static void
+ufo_lamino_bp_task_get_structure (UfoTask *task,
+                                  guint *n_inputs,
+                                  guint **n_dims,
+                                  UfoTaskMode *mode)
+{
+    *mode = UFO_TASK_MODE_REDUCE;
+    *n_inputs = 1;
+    *n_dims = g_new0 (guint, 1);
+    (*n_dims)[0] = 2;
+}
+
+static gboolean
+ufo_lamino_bp_task_process (UfoGpuTask *task,
+                            UfoBuffer **inputs,
+                            UfoBuffer *output,
+                            UfoRequisition *requisition,
+                            UfoGpuNode *node)
+{
+    UfoLaminoBpTaskPrivate *priv;
+    cl_command_queue cmd_queue;
+    cl_mem in_mem;
+    cl_mem out_mem;
+    cl_kernel kernel;
+    gfloat cf, ct, cg;
+    gfloat sf, st, sg;
+    
+    priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (task);
+
+    cf = cos(priv->params.phi);
+    ct = cos(priv->params.alpha);
+    cg = cos(priv->params.psi);
+    sf = sin(priv->params.phi);
+    st = sin(priv->params.alpha);
+    sg = sin(priv->params.psi);
+
+    priv->params.alpha = - 3 * G_PI/2 + priv->params.theta;
+    priv->params.phi   = priv->params.angle_step* ((float) priv->proj_idx);
+
+    priv->params.mat_0 =  cg * cf - sg * st * sf;
+    priv->params.mat_1 = -cg * sf - sg * st * cf;
+    priv->params.mat_2 = -sg * ct;
+    priv->params.mat_3 =  sg * cf + cg * st * sf;
+    priv->params.mat_4 = -sg * sf + cg * st * cf;
+    priv->params.mat_5 =  cg * ct;
+
+    // send parameters to GPU
+    g_print ("get_cmd_queue from %p\n", node);
+    cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+
+    UFO_RESOURCES_CHECK_CLERR (clEnqueueWriteBuffer (cmd_queue,
+                                                     priv->param_mem, CL_TRUE,
+                                                     0, sizeof(CLParameters), &priv->params,
+                                                     0, NULL, NULL));
+
+    in_mem = ufo_buffer_get_device_array (inputs[0], cmd_queue);
+    out_mem = ufo_buffer_get_device_array (output, cmd_queue);
+    kernel = priv->bp_kernel;
+
+    // copy projection to GPU
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(cl_mem), (void *) &in_mem));
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(cl_mem), (void *) &out_mem));
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 2, sizeof(cl_mem), (void *) &priv->param_mem));
+
+    // call backprojection routine
+    g_message("processing of %d-th projection", priv->proj_idx);
+    UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue, kernel,
+                                                       3, NULL, requisition->dims, NULL,
+                                                       0, NULL, NULL));
+    // clFinish(command_queue);
+
+    priv->proj_idx++;
+    return TRUE;
+}
+
+static void
+ufo_lamino_bp_task_reduce (UfoGpuTask *task,
+                           UfoBuffer *output,
+                           UfoRequisition *requisition,
+                           UfoGpuNode *node)
+{
+    UfoLaminoBpTaskPrivate *priv;
+    cl_command_queue cmd_queue;
+    cl_mem out_mem;
+    cl_kernel kernel;
+
+    priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (task);
+    g_print ("foo: get_cmd_queue from %p\n", node);
+    cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+    kernel = priv->norm_vol_kernel;
+    out_mem = ufo_buffer_get_device_array (output, cmd_queue);
+
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 0, sizeof(cl_mem), (void *) &out_mem));
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (kernel, 1, sizeof(float), &priv->params.angle_step));
+
+    // call normalization kernel
+    g_message("volume post-processing");
+    UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue, kernel,
+                                                       3, NULL, requisition->dims, NULL,
+                                                       0, NULL, NULL));
+}
+
+static void
+ufo_lamino_bp_task_set_property (GObject *object,
+                                 guint property_id,
+                                 const GValue *value,
+                                 GParamSpec *pspec)
+{
+    UfoLaminoBpTaskPrivate *priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_THETA:
+            priv->params.theta = (float) g_value_get_double(value);
+            break;
+        case PROP_PSI:
+            priv->params.psi = (float) g_value_get_double(value);
+            break;
+        case PROP_ANGLE_STEP:
+            priv->params.angle_step = (float) g_value_get_double(value);
+            break;
+        case PROP_VOL_SX:
+            priv->params.vol_sx = g_value_get_uint(value);
+            break;
+        case PROP_VOL_SY:
+            priv->params.vol_sy = g_value_get_uint(value);
+            break;
+        case PROP_VOL_SZ:
+            priv->params.vol_sz = g_value_get_uint(value);
+            break;
+        case PROP_VOL_OX:
+            priv->params.vol_ox = (float)g_value_get_double(value);
+            break;
+        case PROP_VOL_OY:
+            priv->params.vol_oy = (float)g_value_get_double(value);
+            break;
+        case PROP_VOL_OZ:
+            priv->params.vol_oz = (float)g_value_get_double(value);
+            break;
+        case PROP_PROJ_OX:
+            priv->params.proj_ox = (float)g_value_get_double(value);
+            break;
+        case PROP_PROJ_OY:
+            priv->params.proj_oy = (float)g_value_get_double(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+ufo_lamino_bp_task_get_property (GObject *object,
+                                 guint property_id,
+                                 GValue *value,
+                                 GParamSpec *pspec)
+{
+    UfoLaminoBpTaskPrivate *priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_THETA:
+            g_value_set_double(value, (double) priv->params.theta);
+            break;
+        case PROP_PSI:
+            g_value_set_double(value, (double) priv->params.psi);
+            break;
+        case PROP_ANGLE_STEP:
+            g_value_set_double(value, (double) priv->params.angle_step);
+            break;
+        case PROP_VOL_SX:
+            g_value_set_uint(value, priv->params.vol_sx);
+            break;
+        case PROP_VOL_SY:
+            g_value_set_uint(value, priv->params.vol_sy);
+            break;
+        case PROP_VOL_SZ:
+            g_value_set_uint(value, priv->params.vol_sz);
+            break;
+        case PROP_VOL_OX:
+            g_value_set_double(value, (double)priv->params.vol_ox);
+            break;
+        case PROP_VOL_OY:
+            g_value_set_double(value, (double)priv->params.vol_oy);
+            break;
+        case PROP_VOL_OZ:
+            g_value_set_double(value, (double)priv->params.vol_oz);
+            break;
+        case PROP_PROJ_OX:
+            g_value_set_double(value, (double)priv->params.proj_ox);
+            break;
+        case PROP_PROJ_OY:
+            g_value_set_double(value, (double)priv->params.proj_oy);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+ufo_lamino_bp_task_finalize (GObject *object)
+{
+    UfoLaminoBpTaskPrivate *priv = UFO_LAMINO_BP_TASK_GET_PRIVATE (object);
+
+    UFO_RESOURCES_CHECK_CLERR (clReleaseMemObject (priv->param_mem));
+    G_OBJECT_CLASS (ufo_lamino_bp_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+    iface->setup = ufo_lamino_bp_task_setup;
+    iface->get_structure = ufo_lamino_bp_task_get_structure;
+    iface->get_requisition = ufo_lamino_bp_task_get_requisition;
+}
+
+static void
+ufo_gpu_task_interface_init (UfoGpuTaskIface *iface)
+{
+    iface->process = ufo_lamino_bp_task_process;
+    iface->reduce = ufo_lamino_bp_task_reduce;
+}
+
+static void
+ufo_lamino_bp_task_class_init (UfoLaminoBpTaskClass *klass)
+{
+    GObjectClass *oclass;
+
+    oclass = G_OBJECT_CLASS (klass);
+
+    oclass->set_property = ufo_lamino_bp_task_set_property;
+    oclass->get_property = ufo_lamino_bp_task_get_property;
+    oclass->finalize = ufo_lamino_bp_task_finalize;
+
+    properties[PROP_THETA] =
+        g_param_spec_double("theta",
+                "Laminographic angle in radians",
+                "Laminographic angle in radians",
+                -4.0 * G_PI, +4.0 * G_PI, 0.0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_PSI] =
+        g_param_spec_double("psi",
+                "Axis misalignment angle in radians",
+                "Axis misalignment angle in radians",
+                -4.0 * G_PI, +4.0 * G_PI, 0.0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_ANGLE_STEP] =
+        g_param_spec_double("angle-step",
+                "Increment of rotation angle phi in radians",
+                "Increment of rotation angle phi in radians",
+                -4.0 * G_PI, +4.0 * G_PI, 0.0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_VOL_SX] =
+        g_param_spec_uint("vol-sx",
+                "Size of reconstructed volume along the 0X-axis in voxels",
+                "Size of reconstructed volume along the 0X-axis in voxels",
+                0, 1024*8, 512,
+                G_PARAM_READWRITE);
+
+    properties[PROP_VOL_SY] =
+        g_param_spec_uint("vol-sy",
+                "Size of reconstructed volume along the 0Y-axis in voxels",
+                "Size of reconstructed volume along the 0Y-axis in voxels",
+                0, 1024*8, 512,
+                G_PARAM_READWRITE);
+
+    properties[PROP_VOL_SZ] =
+        g_param_spec_uint("vol-sz",
+                "Size of reconstructed volume along the 0Z-axis in voxels",
+                "Size of reconstructed volume along the 0Z-axis in voxels",
+                0, 1024*8, 512,
+                G_PARAM_READWRITE);
+
+    properties[PROP_VOL_OX] =
+        g_param_spec_double("vol-ox",
+                "Volume origin offset from the center of a reco-box along the OX-axis in voxels",
+                "Volume origin offset from the center of a reco-box along the OX-axis in voxels",
+                -1024*8, 1024*8, 0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_VOL_OY] =
+        g_param_spec_double("vol-oy",
+                "Volume origin offset from the center of a reco-box along the OY-axis in voxels",
+                "Volume origin offset from the center of a reco-box along the OY-axis in voxels",
+                -1024*8, 1024*8, 0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_VOL_OZ] =
+        g_param_spec_double("vol-oz",
+                "Volume origin offset from the center of a reco-box along the OZ-axis in voxels",
+                "Volume origin offset from the center of a reco-box along the OZ-axis in voxels",
+                -1024*8, 1024*8, 0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_PROJ_OX] =
+        g_param_spec_double("proj-ox",
+                "Projection of the rotation center on the radiograph origin on the OX-axis",
+                "Projection of the rotation center on the radiograph origin on the OX-axis",
+                -1024*8, 1024*8, 0,
+                G_PARAM_READWRITE);
+
+    properties[PROP_PROJ_OY] =
+        g_param_spec_double("proj-oy",
+                "Projection of the rotation center on the radiograph origin on the OY-axis",
+                "Projection of the rotation center on the radiograph origin on the OY-axis",
+                -1024*8, 1024*8, 0,
+                G_PARAM_READWRITE);
+
+    for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+        g_object_class_install_property (oclass, i, properties[i]);
+
+    g_type_class_add_private (G_OBJECT_CLASS (klass), sizeof(UfoLaminoBpTaskPrivate));
+}
+
+static void
+ufo_lamino_bp_task_init(UfoLaminoBpTask *self)
+{
+    UfoLaminoBpTaskPrivate *priv;
+
+    self->priv = priv = UFO_LAMINO_BP_TASK_GET_PRIVATE(self);
+    priv->param_mem = NULL;
+}

+ 47 - 0
src/ufo-lamino-bp-task.h

@@ -0,0 +1,47 @@
+#ifndef __UFO_LAMINO_BP_TASK_H
+#define __UFO_LAMINO_BP_TASK_H
+
+#include <ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_LAMINO_BP_TASK             (ufo_lamino_bp_task_get_type())
+#define UFO_LAMINO_BP_TASK(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_LAMINO_BP_TASK, UfoLaminoBpTask))
+#define UFO_IS_LAMINO_BP_TASK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_LAMINO_BP_TASK))
+#define UFO_LAMINO_BP_TASK_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_LAMINO_BP_TASK, UfoLaminoBpTaskClass))
+#define UFO_IS_LAMINO_BP_TASK_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_LAMINO_BP_TASK))
+#define UFO_LAMINO_BP_TASK_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_LAMINO_BP_TASK, UfoLaminoBpTaskClass))
+
+typedef struct _UfoLaminoBpTask           UfoLaminoBpTask;
+typedef struct _UfoLaminoBpTaskClass      UfoLaminoBpTaskClass;
+typedef struct _UfoLaminoBpTaskPrivate    UfoLaminoBpTaskPrivate;
+
+/**
+ * UfoLaminoBpTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoLaminoBpTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoLaminoBpTask {
+    /*< private >*/
+    UfoTaskNode parent_instance;
+
+    UfoLaminoBpTaskPrivate *priv;
+};
+
+/**
+ * UfoLaminoBpTaskClass:
+ *
+ * #UfoLaminoBpTask class
+ */
+struct _UfoLaminoBpTaskClass {
+    /*< private >*/
+    UfoTaskNodeClass parent_class;
+};
+
+UfoNode  *ufo_lamino_bp_task_new       (void);
+GType     ufo_lamino_bp_task_get_type  (void);
+
+G_END_DECLS
+
+#endif

+ 443 - 0
src/ufo-padding-2d-task.c

@@ -0,0 +1,443 @@
+/**
+ * SECTION:ufo-filter-task
+ * @Short_description: Process arbitrary Filter kernels
+ * @Title: filter
+ *
+ * This module is used to load an arbitrary #UfoPadding2DTask:kernel from
+ * #UfoPadding2DTask:filename and execute it on each input. The kernel must have
+ * only two global float array parameters, the first represents the input, the
+ * second one the output. #UfoPadding2DTask:num-dims must be changed, if the kernel
+ * accesses either one or three dimensional index spaces.
+ */
+
+#ifdef __APPLE__
+#include <OpenCL/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <ufo-gpu-task-iface.h>
+#include "ufo-padding-2d-task.h"
+
+typedef enum {
+    PADDING_ZERO = 0,
+    PADDING_CONST,
+    PADDING_GAVG,
+    PADDING_BREP
+} PaddingMode;
+
+struct _UfoPadding2DTaskPrivate {
+    guint in_width;
+    guint in_height;
+    guint out_width;
+    guint out_height;
+
+    // extent adds
+    guint xl;
+    guint xr;
+    guint yt;
+    guint yb;
+
+    size_t global_work_size_small[2];
+    size_t global_work_size_large[2];
+
+    PaddingMode mode;
+    // padding constant
+    float pconst;
+    cl_kernel kernel_iconst;
+    cl_kernel kernel_cpyimg;
+    cl_kernel kernel_brep;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_gpu_task_interface_init (UfoGpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoPadding2DTask, ufo_padding_2d_task, UFO_TYPE_TASK_NODE,
+                         G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+                                                ufo_task_interface_init)
+                         G_IMPLEMENT_INTERFACE (UFO_TYPE_GPU_TASK,
+                                                ufo_gpu_task_interface_init))
+
+#define UFO_PADDING_2D_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_PADDING_2D_TASK, UfoPadding2DTaskPrivate))
+
+enum {
+    PROP_0,
+    PROP_XL,
+    PROP_XR,
+    PROP_YT,
+    PROP_YB,
+    PROP_MODE,
+    PROP_PCONST,
+    N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_padding_2d_task_new (void)
+{
+    return UFO_NODE (g_object_new (UFO_TYPE_PADDING_2D_TASK, NULL));
+}
+
+static gboolean
+ufo_padding_2d_task_process (UfoGpuTask *task,
+                             UfoBuffer **inputs,
+                             UfoBuffer *output,
+                             UfoRequisition *requisition,
+                             UfoGpuNode *node)
+{
+    UfoPadding2DTaskPrivate *priv;
+    cl_command_queue cmd_queue;
+    cl_mem in_mem;
+    cl_mem out_mem;
+
+    priv = UFO_PADDING_2D_TASK (task)->priv;
+
+    const PaddingMode mode = priv->mode;
+    const guint pxl = priv->xl;
+    const guint pyt = priv->yt;
+    float pval = priv->pconst;
+
+    const guint ixs = priv->in_width;
+    const guint iys = priv->in_height;
+    const guint oxs = priv->out_width;
+
+    if (mode == PADDING_GAVG) {
+        gfloat *indata = ufo_buffer_get_host_array (inputs[0], NULL);
+        gfloat sum = 0;
+        guint psz = ixs * iys;
+
+        for (guint i =0; i < psz; i++) 
+            sum += indata[i];
+
+        pval = sum / (gfloat) psz;
+    }
+
+    cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+    in_mem = ufo_buffer_get_device_array (inputs[0], cmd_queue);
+    out_mem = ufo_buffer_get_device_array (output, cmd_queue);
+
+    if ((mode == PADDING_ZERO) || (mode == PADDING_CONST) || (mode == PADDING_GAVG)) {
+        cl_kernel k_iconst = priv->kernel_iconst;
+        cl_kernel k_cpyimg = priv->kernel_cpyimg;
+
+        /// fill with constant
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_iconst, 0, sizeof(cl_mem), (void *) &out_mem));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_iconst, 1, sizeof(int),   &oxs));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_iconst, 2, sizeof(float), &pval));
+
+        UFO_RESOURCES_CHECK_CLERR(clEnqueueNDRangeKernel(cmd_queue,  k_iconst,
+                    2, NULL, priv->global_work_size_large, NULL,
+                    0, NULL, NULL));
+
+        /// copy old image
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg(  k_cpyimg, 0, sizeof(cl_mem), (void *) &in_mem));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg(  k_cpyimg, 1, sizeof(cl_mem), (void *) &out_mem));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg(  k_cpyimg, 2, sizeof(int),   &ixs));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg(  k_cpyimg, 3, sizeof(int),   &oxs));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg(  k_cpyimg, 4, sizeof(int),   &pxl));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg(  k_cpyimg, 5, sizeof(int),   &pyt));
+
+        UFO_RESOURCES_CHECK_CLERR(clEnqueueNDRangeKernel(cmd_queue,  k_cpyimg,
+                    2, NULL, priv->global_work_size_small, NULL,
+                    0, NULL, NULL));
+    }
+
+    if (mode == PADDING_BREP) {
+        cl_kernel k_brep   = priv->kernel_brep;
+
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 0, sizeof(cl_mem), (void *) &in_mem));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 1, sizeof(cl_mem), (void *) &out_mem));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 2, sizeof(int),   &ixs));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 3, sizeof(int),   &iys));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 4, sizeof(int),   &oxs));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 5, sizeof(int),   &pxl));
+        UFO_RESOURCES_CHECK_CLERR(clSetKernelArg( k_brep, 6, sizeof(int),   &pyt));
+
+        UFO_RESOURCES_CHECK_CLERR(clEnqueueNDRangeKernel(cmd_queue,  k_brep,
+                    2, NULL, priv->global_work_size_large, NULL,
+                    0, NULL, NULL));
+    }
+
+    return TRUE;
+}
+
+static void
+ufo_padding_2d_task_setup (UfoTask *task,
+                           UfoResources *resources,
+                           GError **error)
+{
+    UfoPadding2DTaskPrivate *priv;
+
+    priv = UFO_PADDING_2D_TASK_GET_PRIVATE (task);
+
+    priv->kernel_iconst = ufo_resources_get_kernel (resources, "padding_2d.cl", "padding_2d_init_const", error);
+    priv->kernel_cpyimg = ufo_resources_get_kernel (resources, "padding_2d.cl", "padding_2d_copy_in", error);
+    priv->kernel_brep   = ufo_resources_get_kernel (resources, "padding_2d.cl", "padding_2d_brep", error);
+}
+
+static void
+ufo_padding_2d_task_get_requisition (UfoTask *task,
+                                     UfoBuffer **inputs,
+                                     UfoRequisition *requisition)
+{
+    UfoPadding2DTaskPrivate *priv;
+    UfoRequisition in_req;
+
+    priv = UFO_PADDING_2D_TASK_GET_PRIVATE (task);
+    ufo_buffer_get_requisition (inputs[0], &in_req);
+
+    priv->in_width = in_req.dims[0];
+    priv->in_height = in_req.dims[1];
+
+    requisition->n_dims = 2;
+    requisition->dims[0] = priv->out_width  = priv->xl + priv->in_width + priv->xr;
+    requisition->dims[1] = priv->out_height = priv->yt + priv->in_height + priv->yb;
+
+    priv->global_work_size_small[0] = (size_t) priv->in_width;
+    priv->global_work_size_small[1] = (size_t) priv->in_height;
+    priv->global_work_size_large[0] = requisition->dims[0];
+    priv->global_work_size_large[1] = requisition->dims[1];
+}
+
+static void
+ufo_padding_2d_task_get_structure (UfoTask *task,
+                                   guint *n_inputs,
+                                   guint **n_dims,
+                                   UfoTaskMode *mode)
+{
+    UfoPadding2DTaskPrivate *priv;
+
+    priv = UFO_PADDING_2D_TASK_GET_PRIVATE (task);
+    *mode = UFO_TASK_MODE_SINGLE;
+    *n_inputs = 1;
+    *n_dims = g_new0 (guint, 1);
+    (*n_dims)[0] = 2;
+}
+
+static UfoNode *
+ufo_padding_2d_task_copy_real (UfoNode *node,
+                               GError **error)
+{
+    UfoPadding2DTask *orig;
+    UfoPadding2DTask *copy;
+
+    orig = UFO_PADDING_2D_TASK (node);
+    copy = UFO_PADDING_2D_TASK (ufo_padding_2d_task_new ());
+
+    copy->priv->xl = orig->priv->xl;
+    copy->priv->xr = orig->priv->xr;
+    copy->priv->yb = orig->priv->yb;
+    copy->priv->yt = orig->priv->yt;
+    copy->priv->mode = orig->priv->mode;
+    copy->priv->pconst = orig->priv->pconst;
+
+    return UFO_NODE (copy);
+}
+
+static gboolean
+ufo_padding_2d_task_equal_real (UfoNode *n1,
+                            UfoNode *n2)
+{
+    g_return_val_if_fail (UFO_IS_PADDING_2D_TASK (n1) && UFO_IS_PADDING_2D_TASK (n2), FALSE);
+    return TRUE;
+}
+
+static void
+ufo_padding_2d_task_finalize (GObject *object)
+{
+    UfoPadding2DTaskPrivate *priv;
+
+    priv = UFO_PADDING_2D_TASK_GET_PRIVATE (object);
+
+    G_OBJECT_CLASS (ufo_padding_2d_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+    iface->setup = ufo_padding_2d_task_setup;
+    iface->get_requisition = ufo_padding_2d_task_get_requisition;
+    iface->get_structure = ufo_padding_2d_task_get_structure;
+}
+
+static void
+ufo_gpu_task_interface_init (UfoGpuTaskIface *iface)
+{
+    iface->process = ufo_padding_2d_task_process;
+}
+
+static void
+ufo_padding_2d_task_set_property (GObject *object,
+                                  guint property_id,
+                                  const GValue *value,
+                                  GParamSpec *pspec)
+{
+    UfoPadding2DTaskPrivate *priv = UFO_PADDING_2D_TASK_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_XL:
+            priv->xl = g_value_get_uint(value);
+            break;
+        case PROP_XR:
+            priv->xr = g_value_get_uint(value);
+            break;
+        case PROP_YT:
+            priv->yt = g_value_get_uint(value);
+            break;
+        case PROP_YB:
+            priv->yb = g_value_get_uint(value);
+            break;
+        case PROP_MODE:
+            if (!g_strcmp0(g_value_get_string(value), "zero"))
+                priv->mode = PADDING_ZERO;
+            else if (!g_strcmp0(g_value_get_string(value), "const"))
+                priv->mode = PADDING_CONST;
+            else if (!g_strcmp0(g_value_get_string(value), "gavg"))
+                priv->mode = PADDING_GAVG;
+            else if (!g_strcmp0(g_value_get_string(value), "brep"))
+                priv->mode = PADDING_BREP;
+            else
+                G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+        case PROP_PCONST:
+            priv->pconst = (float) g_value_get_double(value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+ufo_padding_2d_task_get_property (GObject *object,
+                              guint property_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    UfoPadding2DTaskPrivate *priv = UFO_PADDING_2D_TASK_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_XL:
+            g_value_set_uint(value, priv->xl);
+            break;
+        case PROP_XR:
+            g_value_set_uint(value, priv->xr);
+            break;
+        case PROP_YT:
+            g_value_set_uint(value, priv->yt);
+            break;
+        case PROP_YB:
+            g_value_set_uint(value, priv->yb);
+            break;
+        case PROP_MODE:
+            switch (priv->mode) {
+                case PADDING_ZERO:
+                    g_value_set_string(value, "zero");
+                    break;
+                case PADDING_CONST:
+                    g_value_set_string(value, "const");
+                    break;
+                case PADDING_GAVG:
+                    g_value_set_string(value, "gavg");
+                    break;
+                case PADDING_BREP:
+                    g_value_set_string(value, "brep");
+                    break;
+                default:
+                    G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+                    break;
+            }
+            break;
+        case PROP_PCONST:
+            g_value_set_double(value, priv->pconst);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+ufo_padding_2d_task_class_init (UfoPadding2DTaskClass *klass)
+{
+    GObjectClass *oclass;
+    UfoNodeClass *node_class;
+    
+    oclass = G_OBJECT_CLASS (klass);
+    node_class = UFO_NODE_CLASS (klass);
+
+    oclass->finalize = ufo_padding_2d_task_finalize;
+    oclass->set_property = ufo_padding_2d_task_set_property;
+    oclass->get_property = ufo_padding_2d_task_get_property;
+
+    properties[PROP_XL] =
+        g_param_spec_uint("xl",
+                "Number of additional pixel on the left hand image side",
+                "Number of additional pixel on the left hand image side",
+                0, 16384, 1,
+                G_PARAM_READWRITE);
+
+    properties[PROP_XR] =
+        g_param_spec_uint("xr",
+                "Number of additional pixel on the right hand image side",
+                "Number of additional pixel on the right hand image side",
+                0, 16384, 1,
+                G_PARAM_READWRITE);
+
+    properties[PROP_YT] =
+        g_param_spec_uint("yt",
+                "Number of additional pixel on the top image side",
+                "Number of additional pixel on the top image side",
+                0, 16384, 1,
+                G_PARAM_READWRITE);
+
+    properties[PROP_YB] =
+        g_param_spec_uint("yb",
+                "Number of additional pixel on the bottom image side",
+                "Number of additional pixel on the bottom image side",
+                0, 16384, 1,
+                G_PARAM_READWRITE);
+
+    properties[PROP_MODE] =
+        g_param_spec_string("mode",
+                "Padding mode can be 'zero', 'const', 'gavg' or 'brep' ",
+                "Padding mode can be 'zero', 'const', 'gavg' or 'brep' ",
+                "zero",
+                G_PARAM_READWRITE);
+
+    properties[PROP_PCONST] =
+        g_param_spec_double("pconst",
+                "Padding constant",
+                "Padding constant",
+                -320000.0,
+                320000.0,
+                0.0,
+                G_PARAM_READWRITE);
+
+    for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+        g_object_class_install_property (oclass, i, properties[i]);
+
+    node_class->copy = ufo_padding_2d_task_copy_real;
+    node_class->equal = ufo_padding_2d_task_equal_real;
+
+    g_type_class_add_private(klass, sizeof(UfoPadding2DTaskPrivate));
+}
+
+static void
+ufo_padding_2d_task_init (UfoPadding2DTask *self)
+{
+    UfoPadding2DTaskPrivate *priv;
+    self->priv = priv = UFO_PADDING_2D_TASK_GET_PRIVATE (self);
+
+    priv->xl = 1;
+    priv->xr = 1;
+    priv->yt = 1;
+    priv->yb = 1;
+
+    priv->mode   = PADDING_ZERO;
+    priv->pconst = 0.0;
+
+    priv->kernel_iconst = NULL;
+    priv->kernel_cpyimg = NULL;
+    priv->kernel_brep   = NULL;
+}

+ 47 - 0
src/ufo-padding-2d-task.h

@@ -0,0 +1,47 @@
+#ifndef __UFO_PADDING_2D_TASK_H
+#define __UFO_PADDING_2D_TASK_H
+
+#include <ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_PADDING_2D_TASK             (ufo_padding_2d_task_get_type())
+#define UFO_PADDING_2D_TASK(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_PADDING_2D_TASK, UfoPadding2DTask))
+#define UFO_IS_PADDING_2D_TASK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_PADDING_2D_TASK))
+#define UFO_PADDING_2D_TASK_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_PADDING_2D_TASK, UfoPadding2DTaskClass))
+#define UFO_IS_PADDING_2D_TASK_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_PADDING_2D_TASK))
+#define UFO_PADDING_2D_TASK_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_PADDING_2D_TASK, UfoPadding2DTaskClass))
+
+typedef struct _UfoPadding2DTask           UfoPadding2DTask;
+typedef struct _UfoPadding2DTaskClass      UfoPadding2DTaskClass;
+typedef struct _UfoPadding2DTaskPrivate    UfoPadding2DTaskPrivate;
+
+/**
+ * UfoPadding2DTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoPadding2DTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoPadding2DTask {
+    /*< private >*/
+    UfoTaskNode parent_instance;
+
+    UfoPadding2DTaskPrivate *priv;
+};
+
+/**
+ * UfoPadding2DTaskClass:
+ *
+ * #UfoPadding2DTask class
+ */
+struct _UfoPadding2DTaskClass {
+    /*< private >*/
+    UfoTaskNodeClass parent_class;
+};
+
+UfoNode  *ufo_padding_2d_task_new       (void);
+GType     ufo_padding_2d_task_get_type  (void);
+
+G_END_DECLS
+
+#endif

+ 250 - 0
src/ufo-scale-task.c

@@ -0,0 +1,250 @@
+/**
+ * SECTION:ufo-filter-task
+ * @Short_description: Process arbitrary Filter kernels
+ * @Title: filter
+ *
+ * This module is used to load an arbitrary #UfoScaleTask:kernel from
+ * #UfoScaleTask:filename and execute it on each input. The kernel must have
+ * only two global float array parameters, the first represents the input, the
+ * second one the output. #UfoScaleTask:num-dims must be changed, if the kernel
+ * accesses either one or three dimensional index spaces.
+ */
+
+#ifdef __APPLE__
+#include <Filter/cl.h>
+#else
+#include <CL/cl.h>
+#endif
+#include <ufo-gpu-task-iface.h>
+#include "ufo-scale-task.h"
+
+struct _UfoScaleTaskPrivate {
+    cl_kernel kernel;
+    gfloat scale;
+};
+
+static void ufo_task_interface_init (UfoTaskIface *iface);
+static void ufo_gpu_task_interface_init (UfoGpuTaskIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (UfoScaleTask, ufo_scale_task, UFO_TYPE_TASK_NODE,
+                         G_IMPLEMENT_INTERFACE (UFO_TYPE_TASK,
+                                                ufo_task_interface_init)
+                         G_IMPLEMENT_INTERFACE (UFO_TYPE_GPU_TASK,
+                                                ufo_gpu_task_interface_init))
+
+#define UFO_SCALE_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_SCALE_TASK, UfoScaleTaskPrivate))
+
+enum {
+    PROP_0,
+    PROP_SCALE,
+    N_PROPERTIES
+};
+
+static GParamSpec *properties[N_PROPERTIES] = { NULL, };
+
+UfoNode *
+ufo_scale_task_new (void)
+{
+    return UFO_NODE (g_object_new (UFO_TYPE_SCALE_TASK, NULL));
+}
+
+static gboolean
+ufo_scale_task_process (UfoGpuTask *task,
+                         UfoBuffer **inputs,
+                         UfoBuffer *output,
+                         UfoRequisition *requisition,
+                         UfoGpuNode *node)
+{
+    UfoScaleTaskPrivate *priv;
+    cl_command_queue cmd_queue;
+    cl_mem in_mem;
+    cl_mem out_mem;
+
+    priv = UFO_SCALE_TASK (task)->priv;
+    cmd_queue = ufo_gpu_node_get_cmd_queue (node);
+    in_mem = ufo_buffer_get_device_array (inputs[0], cmd_queue);
+    out_mem = ufo_buffer_get_device_array (output, cmd_queue);
+
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->kernel, 0, sizeof (cl_mem), &in_mem));
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->kernel, 1, sizeof (cl_mem), &out_mem));
+    UFO_RESOURCES_CHECK_CLERR (clSetKernelArg (priv->kernel, 2, sizeof (cl_float), &priv->scale));
+
+    UFO_RESOURCES_CHECK_CLERR (clEnqueueNDRangeKernel (cmd_queue,
+                                                       priv->kernel,
+                                                       2, NULL, requisition->dims, NULL,
+                                                       0, NULL, NULL));
+
+    return TRUE;
+}
+
+static void
+ufo_scale_task_get_structure (UfoTask *task,
+                               guint *n_inputs,
+                               guint **n_dims,
+                               UfoTaskMode *mode)
+{
+    UfoScaleTaskPrivate *priv;
+
+    priv = UFO_SCALE_TASK_GET_PRIVATE (task);
+    *mode = UFO_TASK_MODE_SINGLE;
+    *n_inputs = 1;
+    *n_dims = g_new0 (guint, 1);
+    (*n_dims)[0] = 2;
+}
+
+static void
+ufo_scale_task_setup (UfoTask *task,
+                       UfoResources *resources,
+                       GError **error)
+{
+    UfoScaleTaskPrivate *priv;
+
+    priv = UFO_SCALE_TASK_GET_PRIVATE (task);
+
+    priv->kernel = ufo_resources_get_kernel (resources,
+                                             "scale.cl",
+                                             "scale",
+                                             error);
+
+    if (priv->kernel != NULL)
+        UFO_RESOURCES_CHECK_CLERR (clRetainKernel (priv->kernel));
+
+}
+
+static void
+ufo_scale_task_get_requisition (UfoTask *task,
+                                 UfoBuffer **inputs,
+                                 UfoRequisition *requisition)
+{
+    UfoScaleTaskPrivate *priv;
+
+    priv = UFO_SCALE_TASK_GET_PRIVATE (task);
+    ufo_buffer_get_requisition (inputs[0], requisition);
+}
+
+static UfoNode *
+ufo_scale_task_copy_real (UfoNode *node,
+                           GError **error)
+{
+    UfoScaleTask *orig;
+    UfoScaleTask *copy;
+
+    orig = UFO_SCALE_TASK (node);
+    copy = UFO_SCALE_TASK (ufo_scale_task_new ());
+
+    g_object_set (G_OBJECT (copy),
+                  "scale", orig->priv->scale,
+                  NULL);
+
+    return UFO_NODE (copy);
+}
+
+static gboolean
+ufo_scale_task_equal_real (UfoNode *n1,
+                            UfoNode *n2)
+{
+    g_return_val_if_fail (UFO_IS_SCALE_TASK (n1) && UFO_IS_SCALE_TASK (n2), FALSE);
+    return TRUE;
+}
+
+static void
+ufo_scale_task_finalize (GObject *object)
+{
+    UfoScaleTaskPrivate *priv;
+
+    priv = UFO_SCALE_TASK_GET_PRIVATE (object);
+
+    if (priv->kernel) {
+        clReleaseKernel (priv->kernel);
+        priv->kernel = NULL;
+    }
+
+    G_OBJECT_CLASS (ufo_scale_task_parent_class)->finalize (object);
+}
+
+static void
+ufo_task_interface_init (UfoTaskIface *iface)
+{
+    iface->setup = ufo_scale_task_setup;
+    iface->get_requisition = ufo_scale_task_get_requisition;
+    iface->get_structure = ufo_scale_task_get_structure;
+}
+
+static void
+ufo_gpu_task_interface_init (UfoGpuTaskIface *iface)
+{
+    iface->process = ufo_scale_task_process;
+}
+
+static void
+ufo_scale_task_set_property (GObject *object,
+                              guint property_id,
+                              const GValue *value,
+                              GParamSpec *pspec)
+{
+    UfoScaleTaskPrivate *priv = UFO_SCALE_TASK_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_SCALE:
+            priv->scale = g_value_get_float (value);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+ufo_scale_task_get_property (GObject *object,
+                              guint property_id,
+                              GValue *value,
+                              GParamSpec *pspec)
+{
+    UfoScaleTaskPrivate *priv = UFO_SCALE_TASK_GET_PRIVATE (object);
+
+    switch (property_id) {
+        case PROP_SCALE:
+            g_value_set_float (value, priv->scale);
+            break;
+        default:
+            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+            break;
+    }
+}
+
+static void
+ufo_scale_task_class_init (UfoScaleTaskClass *klass)
+{
+    GObjectClass *oclass;
+    UfoNodeClass *node_class;
+    
+    oclass = G_OBJECT_CLASS (klass);
+    node_class = UFO_NODE_CLASS (klass);
+
+    oclass->finalize = ufo_scale_task_finalize;
+    oclass->set_property = ufo_scale_task_set_property;
+    oclass->get_property = ufo_scale_task_get_property;
+
+    properties[PROP_SCALE] =
+        g_param_spec_float ("scale",
+                            "Scale",
+                            "Scale for each pixel",
+                            -5.0, 10.0, 1.0,
+                            G_PARAM_READWRITE);
+
+    for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
+        g_object_class_install_property (oclass, i, properties[i]);
+
+    node_class->copy = ufo_scale_task_copy_real;
+    node_class->equal = ufo_scale_task_equal_real;
+
+    g_type_class_add_private(klass, sizeof(UfoScaleTaskPrivate));
+}
+
+static void
+ufo_scale_task_init (UfoScaleTask *self)
+{
+    UfoScaleTaskPrivate *priv;
+    self->priv = priv = UFO_SCALE_TASK_GET_PRIVATE (self);
+    priv->kernel = NULL;
+}

+ 47 - 0
src/ufo-scale-task.h

@@ -0,0 +1,47 @@
+#ifndef __UFO_SCALE_TASK_H
+#define __UFO_SCALE_TASK_H
+
+#include <ufo-task-node.h>
+
+G_BEGIN_DECLS
+
+#define UFO_TYPE_SCALE_TASK             (ufo_scale_task_get_type())
+#define UFO_SCALE_TASK(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj), UFO_TYPE_SCALE_TASK, UfoScaleTask))
+#define UFO_IS_SCALE_TASK(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj), UFO_TYPE_SCALE_TASK))
+#define UFO_SCALE_TASK_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass), UFO_TYPE_SCALE_TASK, UfoScaleTaskClass))
+#define UFO_IS_SCALE_TASK_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass), UFO_TYPE_SCALE_TASK))
+#define UFO_SCALE_TASK_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), UFO_TYPE_SCALE_TASK, UfoScaleTaskClass))
+
+typedef struct _UfoScaleTask           UfoScaleTask;
+typedef struct _UfoScaleTaskClass      UfoScaleTaskClass;
+typedef struct _UfoScaleTaskPrivate    UfoScaleTaskPrivate;
+
+/**
+ * UfoScaleTask:
+ *
+ * Main object for organizing filters. The contents of the #UfoScaleTask structure
+ * are private and should only be accessed via the provided API.
+ */
+struct _UfoScaleTask {
+    /*< private >*/
+    UfoTaskNode parent_instance;
+
+    UfoScaleTaskPrivate *priv;
+};
+
+/**
+ * UfoScaleTaskClass:
+ *
+ * #UfoScaleTask class
+ */
+struct _UfoScaleTaskClass {
+    /*< private >*/
+    UfoTaskNodeClass parent_class;
+};
+
+UfoNode  *ufo_scale_task_new       (void);
+GType     ufo_scale_task_get_type  (void);
+
+G_END_DECLS
+
+#endif