Blame operations/common/motion-blur.c

Packit Service 2781ba
/* This file is an image processing operation for GEGL
Packit Service 2781ba
 *
Packit Service 2781ba
 * GEGL is free software; you can redistribute it and/or
Packit Service 2781ba
 * modify it under the terms of the GNU Lesser General Public
Packit Service 2781ba
 * License as published by the Free Software Foundation; either
Packit Service 2781ba
 * version 3 of the License, or (at your option) any later version.
Packit Service 2781ba
 *
Packit Service 2781ba
 * GEGL is distributed in the hope that it will be useful,
Packit Service 2781ba
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2781ba
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 2781ba
 * Lesser General Public License for more details.
Packit Service 2781ba
 *
Packit Service 2781ba
 * You should have received a copy of the GNU Lesser General Public
Packit Service 2781ba
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Copyright 2006 Øyvind Kolås <pippin@gimp.org>
Packit Service 2781ba
 */
Packit Service 2781ba
Packit Service 2781ba
#include "config.h"
Packit Service 2781ba
Packit Service 2781ba
#include <glib/gi18n-lib.h>
Packit Service 2781ba
#include <math.h>
Packit Service 2781ba
Packit Service 2781ba
#ifdef GEGL_CHANT_PROPERTIES
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
gegl_chant_double_ui (length, _("Length"), 0.0, 1000.0, 10.0, 0.0, 300.0, 1.5,
Packit Service 2781ba
                     _("Length of blur in pixels"))
Packit Service 2781ba
gegl_chant_double_ui (angle,  _("Angle"),  -360, 360, 0, -180.0, 180.0, 1.0,
Packit Service 2781ba
                     _("Angle of blur in degrees"))
Packit Service 2781ba
Packit Service 2781ba
#else
Packit Service 2781ba
Packit Service 2781ba
#define GEGL_CHANT_TYPE_AREA_FILTER
Packit Service 2781ba
#define GEGL_CHANT_C_FILE       "motion-blur.c"
Packit Service 2781ba
Packit Service 2781ba
#include "gegl-chant.h"
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
prepare (GeglOperation *operation)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglOperationAreaFilter* op_area = GEGL_OPERATION_AREA_FILTER (operation);
Packit Service 2781ba
  GeglChantO* o = GEGL_CHANT_PROPERTIES (operation);
Packit Service 2781ba
Packit Service 2781ba
  gdouble theta = o->angle * G_PI / 180.0;
Packit Service 2781ba
  gdouble offset_x = fabs(o->length * cos(theta));
Packit Service 2781ba
  gdouble offset_y = fabs(o->length * sin(theta));
Packit Service 2781ba
Packit Service 2781ba
  op_area->left   =
Packit Service 2781ba
  op_area->right  = (gint)ceil(0.5 * offset_x);
Packit Service 2781ba
  op_area->top    =
Packit Service 2781ba
  op_area->bottom = (gint)ceil(0.5 * offset_y);
Packit Service 2781ba
Packit Service 2781ba
  gegl_operation_set_format (operation, "input", babl_format ("RaGaBaA float"));
Packit Service 2781ba
  gegl_operation_set_format (operation, "output", babl_format ("RaGaBaA float"));
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
#include "opencl/gegl-cl.h"
Packit Service 2781ba
#include "buffer/gegl-buffer-cl-iterator.h"
Packit Service 2781ba
Packit Service 2781ba
static const char* kernel_source =
Packit Service 2781ba
"int CLAMP(int val,int lo,int hi)                                      \n"
Packit Service 2781ba
"{                                                                     \n"
Packit Service 2781ba
"    return (val < lo) ? lo : ((hi < val) ? hi : val);                 \n"
Packit Service 2781ba
"}                                                                     \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"float4 get_pixel_color_CL(const __global float4 *in_buf,              \n"
Packit Service 2781ba
"                          int     rect_width,                         \n"
Packit Service 2781ba
"                          int     rect_height,                        \n"
Packit Service 2781ba
"                          int     rect_x,                             \n"
Packit Service 2781ba
"                          int     rect_y,                             \n"
Packit Service 2781ba
"                          int     x,                                  \n"
Packit Service 2781ba
"                          int     y)                                  \n"
Packit Service 2781ba
"{                                                                     \n"
Packit Service 2781ba
"    int ix = x - rect_x;                                              \n"
Packit Service 2781ba
"    int iy = y - rect_y;                                              \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"    ix = CLAMP(ix, 0, rect_width-1);                                  \n"
Packit Service 2781ba
"    iy = CLAMP(iy, 0, rect_height-1);                                 \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"    return in_buf[iy * rect_width + ix];                              \n"
Packit Service 2781ba
"}                                                                     \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"__kernel void motion_blur_CL(const __global float4 *src_buf,          \n"
Packit Service 2781ba
"                             int     src_width,                       \n"
Packit Service 2781ba
"                             int     src_height,                      \n"
Packit Service 2781ba
"                             int     src_x,                           \n"
Packit Service 2781ba
"                             int     src_y,                           \n"
Packit Service 2781ba
"                             __global float4 *dst_buf,                \n"
Packit Service 2781ba
"                             int     dst_x,                           \n"
Packit Service 2781ba
"                             int     dst_y,                           \n"
Packit Service 2781ba
"                             int     num_steps,                       \n"
Packit Service 2781ba
"                             float   offset_x,                        \n"
Packit Service 2781ba
"                             float   offset_y)                        \n"
Packit Service 2781ba
"{                                                                     \n"
Packit Service 2781ba
"    int gidx = get_global_id(0);                                      \n"
Packit Service 2781ba
"    int gidy = get_global_id(1);                                      \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"    float4 sum = 0.0f;                                                \n"
Packit Service 2781ba
"    int px = gidx + dst_x;                                            \n"
Packit Service 2781ba
"    int py = gidy + dst_y;                                            \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"    for(int step = 0; step < num_steps; ++step)                       \n"
Packit Service 2781ba
"    {                                                                 \n"
Packit Service 2781ba
"        float t = num_steps == 1 ? 0.0f :                             \n"
Packit Service 2781ba
"            step / (float)(num_steps - 1) - 0.5f;                     \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        float xx = px + t * offset_x;                                 \n"
Packit Service 2781ba
"        float yy = py + t * offset_y;                                 \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        int   ix = (int)floor(xx);                                    \n"
Packit Service 2781ba
"        int   iy = (int)floor(yy);                                    \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        float dx = xx - floor(xx);                                    \n"
Packit Service 2781ba
"        float dy = yy - floor(yy);                                    \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        float4 mixy0,mixy1,pix0,pix1,pix2,pix3;                       \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        pix0 = get_pixel_color_CL(src_buf, src_width,                 \n"
Packit Service 2781ba
"            src_height, src_x, src_y, ix,   iy);                      \n"
Packit Service 2781ba
"        pix1 = get_pixel_color_CL(src_buf, src_width,                 \n"
Packit Service 2781ba
"            src_height, src_x, src_y, ix+1, iy);                      \n"
Packit Service 2781ba
"        pix2 = get_pixel_color_CL(src_buf, src_width,                 \n"
Packit Service 2781ba
"            src_height, src_x, src_y, ix,   iy+1);                    \n"
Packit Service 2781ba
"        pix3 = get_pixel_color_CL(src_buf, src_width,                 \n"
Packit Service 2781ba
"            src_height, src_x, src_y, ix+1, iy+1);                    \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        mixy0 = dy * (pix2 - pix0) + pix0;                            \n"
Packit Service 2781ba
"        mixy1 = dy * (pix3 - pix1) + pix1;                            \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"        sum  += dx * (mixy1 - mixy0) + mixy0;                         \n"
Packit Service 2781ba
"    }                                                                 \n"
Packit Service 2781ba
"                                                                      \n"
Packit Service 2781ba
"    dst_buf[gidy * get_global_size(0) + gidx] =                       \n"
Packit Service 2781ba
"        sum / num_steps;                                              \n"
Packit Service 2781ba
"}                                                                     \n";
Packit Service 2781ba
Packit Service 2781ba
static gegl_cl_run_data *cl_data = NULL;
Packit Service 2781ba
Packit Service 2781ba
static cl_int
Packit Service 2781ba
cl_motion_blur (cl_mem                in_tex,
Packit Service 2781ba
                cl_mem                out_tex,
Packit Service 2781ba
                size_t                global_worksize,
Packit Service 2781ba
                const GeglRectangle  *roi,
Packit Service 2781ba
                const GeglRectangle  *src_rect,
Packit Service 2781ba
                gint                  num_steps,
Packit Service 2781ba
                gfloat                offset_x,
Packit Service 2781ba
                gfloat                offset_y)
Packit Service 2781ba
{
Packit Service 2781ba
  cl_int cl_err = 0;
Packit Service 2781ba
  size_t global_ws[2];
Packit Service 2781ba
Packit Service 2781ba
  if (!cl_data)
Packit Service 2781ba
  {
Packit Service 2781ba
    const char *kernel_name[] = {"motion_blur_CL", NULL};
Packit Service 2781ba
    cl_data = gegl_cl_compile_and_build (kernel_source, kernel_name);
Packit Service 2781ba
  }
Packit Service 2781ba
Packit Service 2781ba
  if (!cl_data) return 1;
Packit Service 2781ba
Packit Service 2781ba
  global_ws[0] = roi->width;
Packit Service 2781ba
  global_ws[1] = roi->height;
Packit Service 2781ba
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  0, sizeof(cl_mem),   (void*)&in_tex);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  1, sizeof(cl_int),   (void*)&src_rect->width);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  2, sizeof(cl_int),   (void*)&src_rect->height);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  3, sizeof(cl_int),   (void*)&src_rect->x);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  4, sizeof(cl_int),   (void*)&src_rect->y);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  5, sizeof(cl_mem),   (void*)&out_tex);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  6, sizeof(cl_int),   (void*)&roi->x);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  7, sizeof(cl_int),   (void*)&roi->y);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  8, sizeof(cl_int),   (void*)&num_steps);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0],  9, sizeof(cl_float), (void*)&offset_x);
Packit Service 2781ba
  cl_err |= gegl_clSetKernelArg(cl_data->kernel[0], 10, sizeof(cl_float), (void*)&offset_y);
Packit Service 2781ba
  if (cl_err != CL_SUCCESS) return cl_err;
Packit Service 2781ba
Packit Service 2781ba
  cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
Packit Service 2781ba
                                       cl_data->kernel[0], 2,
Packit Service 2781ba
                                       NULL, global_ws, NULL,
Packit Service 2781ba
                                       0, NULL, NULL);
Packit Service 2781ba
  if (cl_err != CL_SUCCESS) return cl_err;
Packit Service 2781ba
Packit Service 2781ba
  return cl_err;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static gboolean
Packit Service 2781ba
cl_process (GeglOperation       *operation,
Packit Service 2781ba
            GeglBuffer          *input,
Packit Service 2781ba
            GeglBuffer          *output,
Packit Service 2781ba
            const GeglRectangle *result,
Packit Service 2781ba
            const GeglRectangle *src_rect)
Packit Service 2781ba
{
Packit Service 2781ba
  const Babl *in_format  = gegl_operation_get_format (operation, "input");
Packit Service 2781ba
  const Babl *out_format = gegl_operation_get_format (operation, "output");
Packit Service 2781ba
  gint err;
Packit Service 2781ba
  gint j;
Packit Service 2781ba
  cl_int cl_err;
Packit Service 2781ba
Packit Service 2781ba
  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
Packit Service 2781ba
  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
Packit Service 2781ba
Packit Service 2781ba
  gdouble theta = o->angle * G_PI / 180.0;
Packit Service 2781ba
  gfloat  offset_x = (gfloat)(o->length * cos(theta));
Packit Service 2781ba
  gfloat  offset_y = (gfloat)(o->length * sin(theta));
Packit Service 2781ba
  gint num_steps = (gint)ceil(o->length) + 1;
Packit Service 2781ba
Packit Service 2781ba
  GeglBufferClIterator *i = gegl_buffer_cl_iterator_new (output,   result, out_format, GEGL_CL_BUFFER_WRITE, GEGL_ABYSS_NONE);
Packit Service 2781ba
                gint read = gegl_buffer_cl_iterator_add_2 (i, input, result, in_format,  GEGL_CL_BUFFER_READ,
Packit Service 2781ba
                                                           op_area->left, op_area->right, op_area->top, op_area->bottom, GEGL_ABYSS_NONE);
Packit Service 2781ba
  while (gegl_buffer_cl_iterator_next (i, &err))
Packit Service 2781ba
  {
Packit Service 2781ba
    if (err) return FALSE;
Packit Service 2781ba
    for (j=0; j < i->n; j++)
Packit Service 2781ba
    {
Packit Service 2781ba
      cl_err = cl_motion_blur(i->tex[read][j], i->tex[0][j], i->size[0][j], &i->roi[0][j], &i->roi[read][j], num_steps, offset_x, offset_y);
Packit Service 2781ba
      if (cl_err != CL_SUCCESS)
Packit Service 2781ba
      {
Packit Service 2781ba
        g_warning("[OpenCL] Error in gegl:motion-blur: %s", gegl_cl_errstring(cl_err));
Packit Service 2781ba
        return FALSE;
Packit Service 2781ba
      }
Packit Service 2781ba
    }
Packit Service 2781ba
  }
Packit Service 2781ba
  return TRUE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static inline gfloat*
Packit Service 2781ba
get_pixel_color(gfloat* in_buf,
Packit Service 2781ba
                const GeglRectangle* rect,
Packit Service 2781ba
                gint x,
Packit Service 2781ba
                gint y)
Packit Service 2781ba
{
Packit Service 2781ba
  gint ix = x - rect->x;
Packit Service 2781ba
  gint iy = y - rect->y;
Packit Service 2781ba
  ix = CLAMP(ix, 0, rect->width-1);
Packit Service 2781ba
  iy = CLAMP(iy, 0, rect->height-1);
Packit Service 2781ba
Packit Service 2781ba
  return &in_buf[(iy*rect->width + ix) * 4];
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static gboolean
Packit Service 2781ba
process (GeglOperation       *operation,
Packit Service 2781ba
         GeglBuffer          *input,
Packit Service 2781ba
         GeglBuffer          *output,
Packit Service 2781ba
         const GeglRectangle *roi,
Packit Service 2781ba
         gint                 level)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglRectangle src_rect;
Packit Service 2781ba
  GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
Packit Service 2781ba
  GeglOperationAreaFilter *op_area;
Packit Service 2781ba
  gfloat* in_buf;
Packit Service 2781ba
  gfloat* out_buf;
Packit Service 2781ba
  gfloat* out_pixel;
Packit Service 2781ba
  gint x,y;
Packit Service 2781ba
Packit Service 2781ba
  gdouble theta = o->angle * G_PI / 180.0;
Packit Service 2781ba
  gdouble offset_x = o->length * cos(theta);
Packit Service 2781ba
  gdouble offset_y = o->length * sin(theta);
Packit Service 2781ba
  gint num_steps = (gint)ceil(o->length) + 1;
Packit Service 2781ba
  gfloat inv_num_steps = 1.0f / num_steps;
Packit Service 2781ba
Packit Service 2781ba
  op_area = GEGL_OPERATION_AREA_FILTER (operation);
Packit Service 2781ba
Packit Service 2781ba
  src_rect = *roi;
Packit Service 2781ba
  src_rect.x -= op_area->left;
Packit Service 2781ba
  src_rect.y -= op_area->top;
Packit Service 2781ba
  src_rect.width += op_area->left + op_area->right;
Packit Service 2781ba
  src_rect.height += op_area->top + op_area->bottom;
Packit Service 2781ba
Packit Service 2781ba
  if (gegl_cl_is_accelerated ())
Packit Service 2781ba
    if (cl_process (operation, input, output, roi, &src_rect))
Packit Service 2781ba
      return TRUE;
Packit Service 2781ba
Packit Service 2781ba
  in_buf = g_new (gfloat, src_rect.width * src_rect.height * 4);
Packit Service 2781ba
  out_buf = g_new0 (gfloat, roi->width * roi->height * 4);
Packit Service 2781ba
  out_pixel = out_buf;
Packit Service 2781ba
Packit Service 2781ba
  gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RaGaBaA float"), in_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
Packit Service 2781ba
Packit Service 2781ba
  for (y=0; y<roi->height; ++y)
Packit Service 2781ba
    {
Packit Service 2781ba
      for (x=0; x<roi->width; ++x)
Packit Service 2781ba
        {
Packit Service 2781ba
          gint step;
Packit Service 2781ba
          gint c;
Packit Service 2781ba
          gint px = x+roi->x;
Packit Service 2781ba
          gint py = y+roi->y;
Packit Service 2781ba
          gfloat sum[4] = {0,0,0,0};
Packit Service 2781ba
          for (step=0; step
Packit Service 2781ba
            {
Packit Service 2781ba
              gdouble t = num_steps == 1 ? 0.0 : step / (gdouble)(num_steps-1) - 0.5;
Packit Service 2781ba
Packit Service 2781ba
              /* get the interpolated pixel position for this step */
Packit Service 2781ba
              gdouble xx = px + t*offset_x;
Packit Service 2781ba
              gdouble yy = py + t*offset_y;
Packit Service 2781ba
              gint ix = (gint)floor(xx);
Packit Service 2781ba
              gint iy = (gint)floor(yy);
Packit Service 2781ba
              gdouble dx = xx - floor(xx);
Packit Service 2781ba
              gdouble dy = yy - floor(yy);
Packit Service 2781ba
Packit Service 2781ba
              /* do bilinear interpolation to get a nice smooth result */
Packit Service 2781ba
              gfloat *pix0, *pix1, *pix2, *pix3;
Packit Service 2781ba
              gfloat mixy0[4];
Packit Service 2781ba
              gfloat mixy1[4];
Packit Service 2781ba
Packit Service 2781ba
              pix0 = get_pixel_color(in_buf, &src_rect, ix, iy);
Packit Service 2781ba
              pix1 = get_pixel_color(in_buf, &src_rect, ix+1, iy);
Packit Service 2781ba
              pix2 = get_pixel_color(in_buf, &src_rect, ix, iy+1);
Packit Service 2781ba
              pix3 = get_pixel_color(in_buf, &src_rect, ix+1, iy+1);
Packit Service 2781ba
              for (c=0; c<4; ++c)
Packit Service 2781ba
                {
Packit Service 2781ba
                  mixy0[c] = dy*(pix2[c] - pix0[c]) + pix0[c];
Packit Service 2781ba
                  mixy1[c] = dy*(pix3[c] - pix1[c]) + pix1[c];
Packit Service 2781ba
                  sum[c] += dx*(mixy1[c] - mixy0[c]) + mixy0[c];
Packit Service 2781ba
                }
Packit Service 2781ba
            }
Packit Service 2781ba
Packit Service 2781ba
          for (c=0; c<4; ++c)
Packit Service 2781ba
            *out_pixel++ = sum[c] * inv_num_steps;
Packit Service 2781ba
        }
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  gegl_buffer_set (output, roi, 0, babl_format ("RaGaBaA float"), out_buf, GEGL_AUTO_ROWSTRIDE);
Packit Service 2781ba
Packit Service 2781ba
  g_free (in_buf);
Packit Service 2781ba
  g_free (out_buf);
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
  return  TRUE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_chant_class_init (GeglChantClass *klass)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglOperationClass            *operation_class;
Packit Service 2781ba
  GeglOperationFilterClass      *filter_class;
Packit Service 2781ba
Packit Service 2781ba
  operation_class = GEGL_OPERATION_CLASS (klass);
Packit Service 2781ba
  filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
Packit Service 2781ba
Packit Service 2781ba
  filter_class->process = process;
Packit Service 2781ba
  operation_class->prepare = prepare;
Packit Service 2781ba
Packit Service 2781ba
  operation_class->opencl_support = TRUE;
Packit Service 2781ba
Packit Service 2781ba
  gegl_operation_class_set_keys (operation_class,
Packit Service 2781ba
    "name"       , "gegl:motion-blur",
Packit Service 2781ba
    "categories" , "blur",
Packit Service 2781ba
    "description", _("Linear motion blur"),
Packit Service 2781ba
    NULL);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
#endif