accelerate.c revision 0b8a2e9698d4d1588ad48ff4b29e169ba9d68759
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%     AAA     CCCC    CCCC  EEEEE  L      EEEEE  RRRR    AAA   TTTTT  EEEEE   %
7%    A   A   C       C      E      L      E      R   R  A   A    T    E       %
8%    AAAAA   C       C      EEE    L      EEE    RRRR   AAAAA    T    EEE     %
9%    A   A   C       C      E      L      E      R R    A   A    T    E       %
10%    A   A    CCCC    CCCC  EEEEE  LLLLL  EEEEE  R  R   A   A    T    EEEEE   %
11%                                                                             %
12%                                                                             %
13%                       MagickCore Acceleration Methods                       %
14%                                                                             %
15%                              Software Design                                %
16%                                  Cristy                                     %
17%                               SiuChi Chan                                   %
18%                               Guansong Zhang                                %
19%                               January 2010                                  %
20%                                                                             %
21%                                                                             %
22%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
23%  dedicated to making software imaging solutions freely available.           %
24%                                                                             %
25%  You may not use this file except in compliance with the License.  You may  %
26%  obtain a copy of the License at                                            %
27%                                                                             %
28%    http://www.imagemagick.org/script/license.php                            %
29%                                                                             %
30%  Unless required by applicable law or agreed to in writing, software        %
31%  distributed under the License is distributed on an "AS IS" BASIS,          %
32%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
33%  See the License for the specific language governing permissions and        %
34%  limitations under the License.                                             %
35%                                                                             %
36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37*/
38
39/*
40Include declarations.
41*/
42#include "MagickCore/studio.h"
43#include "MagickCore/accelerate.h"
44#include "MagickCore/accelerate-private.h"
45#include "MagickCore/artifact.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/cache-view.h"
49#include "MagickCore/color-private.h"
50#include "MagickCore/delegate-private.h"
51#include "MagickCore/enhance.h"
52#include "MagickCore/exception.h"
53#include "MagickCore/exception-private.h"
54#include "MagickCore/gem.h"
55#include "MagickCore/hashmap.h"
56#include "MagickCore/image.h"
57#include "MagickCore/image-private.h"
58#include "MagickCore/list.h"
59#include "MagickCore/memory_.h"
60#include "MagickCore/monitor-private.h"
61#include "MagickCore/accelerate.h"
62#include "MagickCore/opencl.h"
63#include "MagickCore/opencl-private.h"
64#include "MagickCore/option.h"
65#include "MagickCore/pixel-private.h"
66#include "MagickCore/prepress.h"
67#include "MagickCore/quantize.h"
68#include "MagickCore/random_.h"
69#include "MagickCore/random-private.h"
70#include "MagickCore/registry.h"
71#include "MagickCore/resize.h"
72#include "MagickCore/resize-private.h"
73#include "MagickCore/semaphore.h"
74#include "MagickCore/splay-tree.h"
75#include "MagickCore/statistic.h"
76#include "MagickCore/string_.h"
77#include "MagickCore/string-private.h"
78#include "MagickCore/token.h"
79
80#ifdef MAGICKCORE_CLPERFMARKER
81#include "CLPerfMarker.h"
82#endif
83
84#define MAGICK_MAX(x,y) (((x) >= (y))?(x):(y))
85#define MAGICK_MIN(x,y) (((x) <= (y))?(x):(y))
86
87#if defined(MAGICKCORE_OPENCL_SUPPORT)
88
89#define ALIGNED(pointer,type) ((((long)(pointer)) & (sizeof(type)-1)) == 0)
90/*#define ALIGNED(pointer,type) (0) */
91
92/* pad the global workgroup size to the next multiple of
93   the local workgroup size */
94inline static unsigned int
95  padGlobalWorkgroupSizeToLocalWorkgroupSize(const unsigned int orgGlobalSize,
96                                             const unsigned int localGroupSize)
97{
98  return ((orgGlobalSize+(localGroupSize-1))/localGroupSize*localGroupSize);
99}
100
101static MagickBooleanType checkOpenCLEnvironment(ExceptionInfo* exception)
102{
103  MagickBooleanType flag;
104
105  MagickCLEnv clEnv;
106  clEnv = GetDefaultOpenCLEnv();
107
108  GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
109    , sizeof(MagickBooleanType), &flag, exception);
110  if (flag != MagickFalse)
111    return MagickFalse;
112
113  GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED
114    , sizeof(MagickBooleanType), &flag, exception);
115  if (flag == MagickFalse)
116  {
117    if(InitOpenCLEnv(clEnv, exception) == MagickFalse)
118      return MagickFalse;
119
120    GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
121      , sizeof(MagickBooleanType), &flag, exception);
122    if (flag != MagickFalse)
123      return MagickFalse;
124  }
125
126  return MagickTrue;
127}
128
129
130static MagickBooleanType checkAccelerateCondition(const Image* image, const ChannelType channel)
131{
132  /* check if the image's colorspace is supported */
133  if (image->colorspace != RGBColorspace
134    && image->colorspace != sRGBColorspace
135    && image->colorspace != GRAYColorspace)
136    return MagickFalse;
137
138  /* check if the channel is supported */
139  if (((channel&RedChannel) == 0)
140  || ((channel&GreenChannel) == 0)
141  || ((channel&BlueChannel) == 0))
142  {
143    return MagickFalse;
144  }
145
146
147  /* check if if the virtual pixel method is compatible with the OpenCL implementation */
148  if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod)&&
149      (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod))
150    return MagickFalse;
151
152  return MagickTrue;
153}
154
155static MagickBooleanType checkHistogramCondition(Image *image, const ChannelType channel)
156{
157
158  /* ensure this is the only pass get in for now. */
159  if ((channel & SyncChannels) == 0)
160    return MagickFalse;
161
162  if (image->intensity == Rec601LuminancePixelIntensityMethod ||
163    image->intensity == Rec709LuminancePixelIntensityMethod)
164    return MagickFalse;
165
166  if (image->colorspace != sRGBColorspace)
167    return MagickFalse;
168
169  return MagickTrue;
170}
171
172
173static Image* ComputeConvolveImage(const Image* inputImage, const ChannelType channel, const KernelInfo *kernel, ExceptionInfo *exception)
174{
175  MagickBooleanType outputReady;
176  MagickCLEnv clEnv;
177
178  cl_int clStatus;
179  size_t global_work_size[3];
180  size_t localGroupSize[3];
181  size_t localMemoryRequirement;
182  Image* filteredImage;
183  MagickSizeType length;
184  const void *inputPixels;
185  void *filteredPixels;
186  cl_mem_flags mem_flags;
187  float* kernelBufferPtr;
188  unsigned kernelSize;
189  unsigned int i;
190  void *hostPtr;
191  unsigned int matte,
192    filterWidth, filterHeight,
193    imageWidth, imageHeight;
194
195  cl_context context;
196  cl_kernel clkernel;
197  cl_mem inputImageBuffer, filteredImageBuffer, convolutionKernel;
198  cl_ulong deviceLocalMemorySize;
199
200  cl_command_queue queue;
201
202  /* intialize all CL objects to NULL */
203  context = NULL;
204  inputImageBuffer = NULL;
205  filteredImageBuffer = NULL;
206  convolutionKernel = NULL;
207  clkernel = NULL;
208  queue = NULL;
209
210  filteredImage = NULL;
211  outputReady = MagickFalse;
212
213  clEnv = GetDefaultOpenCLEnv();
214  context = GetOpenCLContext(clEnv);
215
216  inputPixels = NULL;
217  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
218  if (inputPixels == (const void *) NULL)
219  {
220    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
221    goto cleanup;
222  }
223
224  /* Create and initialize OpenCL buffers. */
225
226  /* If the host pointer is aligned to the size of CLPixelPacket,
227     then use the host buffer directly from the GPU; otherwise,
228     create a buffer on the GPU and copy the data over */
229  if (ALIGNED(inputPixels,CLPixelPacket))
230  {
231    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
232  }
233  else
234  {
235    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
236  }
237  /* create a CL buffer from image pixel buffer */
238  length = inputImage->columns * inputImage->rows;
239  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
240  if (clStatus != CL_SUCCESS)
241  {
242    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
243    goto cleanup;
244  }
245
246  filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
247  assert(filteredImage != NULL);
248  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
249  {
250    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
251    goto cleanup;
252  }
253  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
254  if (filteredPixels == (void *) NULL)
255  {
256    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
257    goto cleanup;
258  }
259
260  if (ALIGNED(filteredPixels,CLPixelPacket))
261  {
262    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
263    hostPtr = filteredPixels;
264  }
265  else
266  {
267    mem_flags = CL_MEM_WRITE_ONLY;
268    hostPtr = NULL;
269  }
270  /* create a CL buffer from image pixel buffer */
271  length = inputImage->columns * inputImage->rows;
272  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
273  if (clStatus != CL_SUCCESS)
274  {
275    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
276    goto cleanup;
277  }
278
279  kernelSize = kernel->width * kernel->height;
280  convolutionKernel = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernelSize * sizeof(float), NULL, &clStatus);
281  if (clStatus != CL_SUCCESS)
282  {
283    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
284    goto cleanup;
285  }
286
287  queue = AcquireOpenCLCommandQueue(clEnv);
288
289  kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, convolutionKernel, CL_TRUE, CL_MAP_WRITE, 0, kernelSize * sizeof(float)
290          , 0, NULL, NULL, &clStatus);
291  if (clStatus != CL_SUCCESS)
292  {
293    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
294    goto cleanup;
295  }
296  for (i = 0; i < kernelSize; i++)
297  {
298    kernelBufferPtr[i] = (float) kernel->values[i];
299  }
300  clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, convolutionKernel, kernelBufferPtr, 0, NULL, NULL);
301  if (clStatus != CL_SUCCESS)
302  {
303    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
304    goto cleanup;
305  }
306  clEnv->library->clFlush(queue);
307
308  deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
309
310  /* Compute the local memory requirement for a 16x16 workgroup.
311     If it's larger than 16k, reduce the workgroup size to 8x8 */
312  localGroupSize[0] = 16;
313  localGroupSize[1] = 16;
314  localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
315    + kernel->width*kernel->height*sizeof(float);
316
317  if (localMemoryRequirement > deviceLocalMemorySize)
318  {
319    localGroupSize[0] = 8;
320    localGroupSize[1] = 8;
321    localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
322      + kernel->width*kernel->height*sizeof(float);
323  }
324  if (localMemoryRequirement <= deviceLocalMemorySize)
325  {
326    /* get the OpenCL kernel */
327    clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ConvolveOptimized");
328    if (clkernel == NULL)
329    {
330      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
331      goto cleanup;
332    }
333
334    /* set the kernel arguments */
335    i = 0;
336    clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
337    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
338    imageWidth = inputImage->columns;
339    imageHeight = inputImage->rows;
340    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
341    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
342    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
343    filterWidth = kernel->width;
344    filterHeight = kernel->height;
345    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
346    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
347    matte = (inputImage->matte==MagickTrue)?1:0;
348    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
349    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
350    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, (localGroupSize[0] + kernel->width-1)*(localGroupSize[1] + kernel->height-1)*sizeof(CLPixelPacket),NULL);
351    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, kernel->width*kernel->height*sizeof(float),NULL);
352    if (clStatus != CL_SUCCESS)
353    {
354      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
355      goto cleanup;
356    }
357
358    /* pad the global size to a multiple of the local work size dimension */
359    global_work_size[0] = ((inputImage->columns + localGroupSize[0]  - 1)/localGroupSize[0] ) * localGroupSize[0] ;
360    global_work_size[1] = ((inputImage->rows + localGroupSize[1] - 1)/localGroupSize[1]) * localGroupSize[1];
361
362    /* launch the kernel */
363    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL);
364    if (clStatus != CL_SUCCESS)
365    {
366      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
367      goto cleanup;
368    }
369  }
370  else
371  {
372    /* get the OpenCL kernel */
373    clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Convolve");
374    if (clkernel == NULL)
375    {
376      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
377      goto cleanup;
378    }
379
380    /* set the kernel arguments */
381    i = 0;
382    clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
383    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
384    imageWidth = inputImage->columns;
385    imageHeight = inputImage->rows;
386    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
387    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
388    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
389    filterWidth = kernel->width;
390    filterHeight = kernel->height;
391    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
392    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
393    matte = (inputImage->matte==MagickTrue)?1:0;
394    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
395    clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
396    if (clStatus != CL_SUCCESS)
397    {
398      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
399      goto cleanup;
400    }
401
402    localGroupSize[0] = 8;
403    localGroupSize[1] = 8;
404    global_work_size[0] = (inputImage->columns + (localGroupSize[0]-1))/localGroupSize[0] * localGroupSize[0];
405    global_work_size[1] = (inputImage->rows    + (localGroupSize[1]-1))/localGroupSize[1] * localGroupSize[1];
406    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL);
407
408    if (clStatus != CL_SUCCESS)
409    {
410      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
411      goto cleanup;
412    }
413  }
414  clEnv->library->clFlush(queue);
415
416  if (ALIGNED(filteredPixels,CLPixelPacket))
417  {
418    length = inputImage->columns * inputImage->rows;
419    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
420  }
421  else
422  {
423    length = inputImage->columns * inputImage->rows;
424    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
425  }
426  if (clStatus != CL_SUCCESS)
427  {
428    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
429    goto cleanup;
430  }
431
432  /* everything is fine! :) */
433  outputReady = MagickTrue;
434
435cleanup:
436  OpenCLLogException(__FUNCTION__,__LINE__,exception);
437
438  if (inputImageBuffer != NULL)
439    clEnv->library->clReleaseMemObject(inputImageBuffer);
440
441  if (filteredImageBuffer != NULL)
442    clEnv->library->clReleaseMemObject(filteredImageBuffer);
443
444  if (convolutionKernel != NULL)
445    clEnv->library->clReleaseMemObject(convolutionKernel);
446
447  if (clkernel != NULL)
448    RelinquishOpenCLKernel(clEnv, clkernel);
449
450  if (queue != NULL)
451    RelinquishOpenCLCommandQueue(clEnv, queue);
452
453  if (outputReady == MagickFalse)
454  {
455    if (filteredImage != NULL)
456    {
457      DestroyImage(filteredImage);
458      filteredImage = NULL;
459    }
460  }
461
462  return filteredImage;
463}
464
465/*
466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467%                                                                             %
468%                                                                             %
469%                                                                             %
470%     C o n v o l v e I m a g e  w i t h  O p e n C L                         %
471%                                                                             %
472%                                                                             %
473%                                                                             %
474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475%
476%  ConvolveImage() applies a custom convolution kernel to the image.
477%
478%  The format of the ConvolveImage method is:
479%
480%      Image *ConvolveImage(const Image *image,const size_t order,
481%        const double *kernel,ExceptionInfo *exception)
482%      Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
483%        const size_t order,const double *kernel,ExceptionInfo *exception)
484%
485%  A description of each parameter follows:
486%
487%    o image: the image.
488%
489%    o channel: the channel type.
490%
491%    o kernel: kernel info.
492%
493%    o exception: return any errors or warnings in this structure.
494%
495*/
496
497MagickExport Image* AccelerateConvolveImageChannel(const Image *image, const ChannelType channel, const KernelInfo *kernel, ExceptionInfo *exception)
498{
499  MagickBooleanType status;
500  Image* filteredImage = NULL;
501
502  assert(image != NULL);
503  assert(kernel != (KernelInfo *) NULL);
504  assert(exception != (ExceptionInfo *) NULL);
505
506  status = checkOpenCLEnvironment(exception);
507  if (status == MagickFalse)
508    return NULL;
509
510  status = checkAccelerateCondition(image, channel);
511  if (status == MagickFalse)
512    return NULL;
513
514  filteredImage = ComputeConvolveImage(image, channel, kernel, exception);
515  return filteredImage;
516}
517
518static MagickBooleanType ComputeFunctionImage(Image *image, const ChannelType channel,const MagickFunction function,
519  const size_t number_parameters,const double *parameters, ExceptionInfo *exception)
520{
521  MagickBooleanType status;
522
523  MagickCLEnv clEnv;
524
525  MagickSizeType length;
526  void* pixels;
527  float* parametersBufferPtr;
528
529  cl_int clStatus;
530  cl_context context;
531  cl_kernel clkernel;
532  cl_command_queue queue;
533  cl_mem_flags mem_flags;
534  cl_mem imageBuffer;
535  cl_mem parametersBuffer;
536  size_t globalWorkSize[2];
537
538  unsigned int i;
539
540  status = MagickFalse;
541
542  context = NULL;
543  clkernel = NULL;
544  queue = NULL;
545  imageBuffer = NULL;
546  parametersBuffer = NULL;
547
548  clEnv = GetDefaultOpenCLEnv();
549  context = GetOpenCLContext(clEnv);
550
551  pixels = GetPixelCachePixels(image, &length, exception);
552  if (pixels == (void *) NULL)
553  {
554    (void) OpenCLThrowMagickException(exception, GetMagickModule(), CacheWarning,
555      "GetPixelCachePixels failed.",
556      "'%s'", image->filename);
557    goto cleanup;
558  }
559
560
561  if (ALIGNED(pixels,CLPixelPacket))
562  {
563    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
564  }
565  else
566  {
567    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
568  }
569  /* create a CL buffer from image pixel buffer */
570  length = image->columns * image->rows;
571  imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)pixels, &clStatus);
572  if (clStatus != CL_SUCCESS)
573  {
574    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
575    goto cleanup;
576  }
577
578  parametersBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, number_parameters * sizeof(float), NULL, &clStatus);
579  if (clStatus != CL_SUCCESS)
580  {
581    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
582    goto cleanup;
583  }
584
585  queue = AcquireOpenCLCommandQueue(clEnv);
586
587  parametersBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, parametersBuffer, CL_TRUE, CL_MAP_WRITE, 0, number_parameters * sizeof(float)
588                , 0, NULL, NULL, &clStatus);
589  if (clStatus != CL_SUCCESS)
590  {
591    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
592    goto cleanup;
593  }
594  for (i = 0; i < number_parameters; i++)
595  {
596    parametersBufferPtr[i] = (float)parameters[i];
597  }
598  clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, parametersBuffer, parametersBufferPtr, 0, NULL, NULL);
599  if (clStatus != CL_SUCCESS)
600  {
601    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
602    goto cleanup;
603  }
604  clEnv->library->clFlush(queue);
605
606  clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "FunctionImage");
607  if (clkernel == NULL)
608  {
609    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
610    goto cleanup;
611  }
612
613  /* set the kernel arguments */
614  i = 0;
615  clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
616  clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
617  clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(MagickFunction),(void *)&function);
618  clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&number_parameters);
619  clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&parametersBuffer);
620  if (clStatus != CL_SUCCESS)
621  {
622    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
623    goto cleanup;
624  }
625
626  globalWorkSize[0] = image->columns;
627  globalWorkSize[1] = image->rows;
628  /* launch the kernel */
629  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, globalWorkSize, NULL, 0, NULL, NULL);
630  if (clStatus != CL_SUCCESS)
631  {
632    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
633    goto cleanup;
634  }
635  clEnv->library->clFlush(queue);
636
637
638  if (ALIGNED(pixels,CLPixelPacket))
639  {
640    length = image->columns * image->rows;
641    clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
642  }
643  else
644  {
645    length = image->columns * image->rows;
646    clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), pixels, 0, NULL, NULL);
647  }
648  if (clStatus != CL_SUCCESS)
649  {
650    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
651    goto cleanup;
652  }
653  status = MagickTrue;
654
655cleanup:
656  OpenCLLogException(__FUNCTION__,__LINE__,exception);
657
658  if (clkernel != NULL) RelinquishOpenCLKernel(clEnv, clkernel);
659  if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
660  if (imageBuffer != NULL) clEnv->library->clReleaseMemObject(imageBuffer);
661  if (parametersBuffer != NULL) clEnv->library->clReleaseMemObject(parametersBuffer);
662
663  return status;
664}
665
666
667
668MagickExport MagickBooleanType
669  AccelerateFunctionImage(Image *image, const ChannelType channel,const MagickFunction function,
670  const size_t number_parameters,const double *parameters, ExceptionInfo *exception)
671{
672  MagickBooleanType status;
673
674  status = MagickFalse;
675
676  assert(image != NULL);
677  assert(exception != (ExceptionInfo *) NULL);
678
679  status = checkOpenCLEnvironment(exception);
680  if (status != MagickFalse)
681  {
682    status = checkAccelerateCondition(image, channel);
683    if (status != MagickFalse)
684    {
685      status = ComputeFunctionImage(image, channel, function, number_parameters, parameters, exception);
686    }
687  }
688  return status;
689}
690
691
692static MagickBooleanType splitImage(const Image* inputImage)
693{
694  MagickBooleanType split;
695
696  MagickCLEnv clEnv;
697  unsigned long allocSize;
698  unsigned long tempSize;
699
700  clEnv = GetDefaultOpenCLEnv();
701
702  allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
703  tempSize = inputImage->columns * inputImage->rows * 4 * 4;
704
705  /*
706  printf("alloc size: %lu\n", allocSize);
707  printf("temp size: %lu\n", tempSize);
708  */
709
710  split = ((tempSize > allocSize) ? MagickTrue:MagickFalse);
711
712  return split;
713}
714
715static Image* ComputeBlurImage(const Image* inputImage, const ChannelType channel, const double radius, const double sigma, ExceptionInfo *exception)
716{
717  MagickBooleanType outputReady;
718  Image* filteredImage;
719  MagickCLEnv clEnv;
720
721  cl_int clStatus;
722
723  const void *inputPixels;
724  void *filteredPixels;
725  cl_mem_flags mem_flags;
726
727  cl_context context;
728  cl_mem inputImageBuffer, tempImageBuffer, filteredImageBuffer, imageKernelBuffer;
729  cl_kernel blurRowKernel, blurColumnKernel;
730  cl_command_queue queue;
731
732  void* hostPtr;
733  float* kernelBufferPtr;
734  MagickSizeType length;
735
736  char geometry[MaxTextExtent];
737  KernelInfo* kernel = NULL;
738  unsigned int kernelWidth;
739  unsigned int imageColumns, imageRows;
740
741  unsigned int i;
742
743  context = NULL;
744  filteredImage = NULL;
745  inputImageBuffer = NULL;
746  tempImageBuffer = NULL;
747  filteredImageBuffer = NULL;
748  imageKernelBuffer = NULL;
749  blurRowKernel = NULL;
750  blurColumnKernel = NULL;
751  queue = NULL;
752
753  outputReady = MagickFalse;
754
755  clEnv = GetDefaultOpenCLEnv();
756  context = GetOpenCLContext(clEnv);
757  queue = AcquireOpenCLCommandQueue(clEnv);
758
759  /* Create and initialize OpenCL buffers. */
760  {
761    inputPixels = NULL;
762    inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
763    if (inputPixels == (const void *) NULL)
764    {
765      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
766      goto cleanup;
767    }
768    /* If the host pointer is aligned to the size of CLPixelPacket,
769     then use the host buffer directly from the GPU; otherwise,
770     create a buffer on the GPU and copy the data over */
771    if (ALIGNED(inputPixels,CLPixelPacket))
772    {
773      mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
774    }
775    else
776    {
777      mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
778    }
779    /* create a CL buffer from image pixel buffer */
780    length = inputImage->columns * inputImage->rows;
781    inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
782    if (clStatus != CL_SUCCESS)
783    {
784      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
785      goto cleanup;
786    }
787  }
788
789  /* create output */
790  {
791    filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
792    assert(filteredImage != NULL);
793    if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
794    {
795      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
796      goto cleanup;
797    }
798    filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
799    if (filteredPixels == (void *) NULL)
800    {
801      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
802      goto cleanup;
803    }
804
805    if (ALIGNED(filteredPixels,CLPixelPacket))
806    {
807      mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
808      hostPtr = filteredPixels;
809    }
810    else
811    {
812      mem_flags = CL_MEM_WRITE_ONLY;
813      hostPtr = NULL;
814    }
815    /* create a CL buffer from image pixel buffer */
816    length = inputImage->columns * inputImage->rows;
817    filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
818    if (clStatus != CL_SUCCESS)
819    {
820      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
821      goto cleanup;
822    }
823  }
824
825  /* create processing kernel */
826  {
827    (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
828    kernel=AcquireKernelInfo(geometry);
829    if (kernel == (KernelInfo *) NULL)
830    {
831      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.",".");
832      goto cleanup;
833    }
834
835    imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernel->width * sizeof(float), NULL, &clStatus);
836    if (clStatus != CL_SUCCESS)
837    {
838      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
839      goto cleanup;
840    }
841    kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
842    if (clStatus != CL_SUCCESS)
843    {
844      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
845      goto cleanup;
846    }
847
848    for (i = 0; i < kernel->width; i++)
849    {
850      kernelBufferPtr[i] = (float) kernel->values[i];
851    }
852
853    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
854    if (clStatus != CL_SUCCESS)
855    {
856      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
857      goto cleanup;
858    }
859  }
860
861  {
862
863    /* create temp buffer */
864    {
865      length = inputImage->columns * inputImage->rows;
866      tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
867      if (clStatus != CL_SUCCESS)
868      {
869        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
870        goto cleanup;
871      }
872    }
873
874    /* get the OpenCL kernels */
875    {
876      blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow");
877      if (blurRowKernel == NULL)
878      {
879        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
880        goto cleanup;
881      };
882
883      blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumn");
884      if (blurColumnKernel == NULL)
885      {
886        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
887        goto cleanup;
888      };
889    }
890
891    {
892      /* need logic to decide this value */
893      int chunkSize = 256;
894
895      {
896        imageColumns = inputImage->columns;
897        imageRows = inputImage->rows;
898
899        /* set the kernel arguments */
900        i = 0;
901        clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
902        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
903        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
904        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
905        kernelWidth = kernel->width;
906        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
907        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
908        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
909        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
910        if (clStatus != CL_SUCCESS)
911        {
912          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
913          goto cleanup;
914        }
915      }
916
917      /* launch the kernel */
918      {
919        size_t gsize[2];
920        size_t wsize[2];
921
922        gsize[0] = chunkSize*((inputImage->columns+chunkSize-1)/chunkSize);
923        gsize[1] = inputImage->rows;
924        wsize[0] = chunkSize;
925        wsize[1] = 1;
926
927        clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
928        if (clStatus != CL_SUCCESS)
929        {
930          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
931          goto cleanup;
932        }
933        clEnv->library->clFlush(queue);
934      }
935    }
936
937    {
938      /* need logic to decide this value */
939      int chunkSize = 256;
940
941      {
942        imageColumns = inputImage->columns;
943        imageRows = inputImage->rows;
944
945        /* set the kernel arguments */
946        i = 0;
947        clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
948        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
949        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel);
950        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
951        kernelWidth = kernel->width;
952        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
953        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
954        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
955        clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL);
956        if (clStatus != CL_SUCCESS)
957        {
958          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
959          goto cleanup;
960        }
961      }
962
963      /* launch the kernel */
964      {
965        size_t gsize[2];
966        size_t wsize[2];
967
968        gsize[0] = inputImage->columns;
969        gsize[1] = chunkSize*((inputImage->rows+chunkSize-1)/chunkSize);
970        wsize[0] = 1;
971        wsize[1] = chunkSize;
972
973        clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
974        if (clStatus != CL_SUCCESS)
975        {
976          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
977          goto cleanup;
978        }
979        clEnv->library->clFlush(queue);
980      }
981    }
982
983  }
984
985  /* get result */
986  if (ALIGNED(filteredPixels,CLPixelPacket))
987  {
988    length = inputImage->columns * inputImage->rows;
989    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
990  }
991  else
992  {
993    length = inputImage->columns * inputImage->rows;
994    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
995  }
996  if (clStatus != CL_SUCCESS)
997  {
998    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
999    goto cleanup;
1000  }
1001
1002  outputReady = MagickTrue;
1003
1004cleanup:
1005  OpenCLLogException(__FUNCTION__,__LINE__,exception);
1006
1007  if (inputImageBuffer!=NULL)     clEnv->library->clReleaseMemObject(inputImageBuffer);
1008  if (tempImageBuffer!=NULL)      clEnv->library->clReleaseMemObject(tempImageBuffer);
1009  if (filteredImageBuffer!=NULL)  clEnv->library->clReleaseMemObject(filteredImageBuffer);
1010  if (imageKernelBuffer!=NULL)    clEnv->library->clReleaseMemObject(imageKernelBuffer);
1011  if (blurRowKernel!=NULL)        RelinquishOpenCLKernel(clEnv, blurRowKernel);
1012  if (blurColumnKernel!=NULL)     RelinquishOpenCLKernel(clEnv, blurColumnKernel);
1013  if (queue != NULL)              RelinquishOpenCLCommandQueue(clEnv, queue);
1014  if (kernel!=NULL)               DestroyKernelInfo(kernel);
1015  if (outputReady == MagickFalse)
1016  {
1017    if (filteredImage != NULL)
1018    {
1019      DestroyImage(filteredImage);
1020      filteredImage = NULL;
1021    }
1022  }
1023  return filteredImage;
1024}
1025
1026static Image* ComputeBlurImageSection(const Image* inputImage, const ChannelType channel, const double radius, const double sigma, ExceptionInfo *exception)
1027{
1028  MagickBooleanType outputReady;
1029  Image* filteredImage;
1030  MagickCLEnv clEnv;
1031
1032  cl_int clStatus;
1033
1034  const void *inputPixels;
1035  void *filteredPixels;
1036  cl_mem_flags mem_flags;
1037
1038  cl_context context;
1039  cl_mem inputImageBuffer, tempImageBuffer, filteredImageBuffer, imageKernelBuffer;
1040  cl_kernel blurRowKernel, blurColumnKernel;
1041  cl_command_queue queue;
1042
1043  void* hostPtr;
1044  float* kernelBufferPtr;
1045  MagickSizeType length;
1046
1047  char geometry[MaxTextExtent];
1048  KernelInfo* kernel = NULL;
1049  unsigned int kernelWidth;
1050  unsigned int imageColumns, imageRows;
1051
1052  unsigned int i;
1053
1054  context = NULL;
1055  filteredImage = NULL;
1056  inputImageBuffer = NULL;
1057  tempImageBuffer = NULL;
1058  filteredImageBuffer = NULL;
1059  imageKernelBuffer = NULL;
1060  blurRowKernel = NULL;
1061  blurColumnKernel = NULL;
1062  queue = NULL;
1063
1064  outputReady = MagickFalse;
1065
1066  clEnv = GetDefaultOpenCLEnv();
1067  context = GetOpenCLContext(clEnv);
1068  queue = AcquireOpenCLCommandQueue(clEnv);
1069
1070  /* Create and initialize OpenCL buffers. */
1071  {
1072    inputPixels = NULL;
1073    inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
1074    if (inputPixels == (const void *) NULL)
1075    {
1076      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
1077      goto cleanup;
1078    }
1079    /* If the host pointer is aligned to the size of CLPixelPacket,
1080     then use the host buffer directly from the GPU; otherwise,
1081     create a buffer on the GPU and copy the data over */
1082    if (ALIGNED(inputPixels,CLPixelPacket))
1083    {
1084      mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1085    }
1086    else
1087    {
1088      mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1089    }
1090    /* create a CL buffer from image pixel buffer */
1091    length = inputImage->columns * inputImage->rows;
1092    inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1093    if (clStatus != CL_SUCCESS)
1094    {
1095      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1096      goto cleanup;
1097    }
1098  }
1099
1100  /* create output */
1101  {
1102    filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
1103    assert(filteredImage != NULL);
1104    if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
1105    {
1106      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
1107      goto cleanup;
1108    }
1109    filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
1110    if (filteredPixels == (void *) NULL)
1111    {
1112      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
1113      goto cleanup;
1114    }
1115
1116    if (ALIGNED(filteredPixels,CLPixelPacket))
1117    {
1118      mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1119      hostPtr = filteredPixels;
1120    }
1121    else
1122    {
1123      mem_flags = CL_MEM_WRITE_ONLY;
1124      hostPtr = NULL;
1125    }
1126    /* create a CL buffer from image pixel buffer */
1127    length = inputImage->columns * inputImage->rows;
1128    filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
1129    if (clStatus != CL_SUCCESS)
1130    {
1131      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1132      goto cleanup;
1133    }
1134  }
1135
1136  /* create processing kernel */
1137  {
1138    (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
1139    kernel=AcquireKernelInfo(geometry);
1140    if (kernel == (KernelInfo *) NULL)
1141    {
1142      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.",".");
1143      goto cleanup;
1144    }
1145
1146    imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernel->width * sizeof(float), NULL, &clStatus);
1147    if (clStatus != CL_SUCCESS)
1148    {
1149      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1150      goto cleanup;
1151    }
1152    kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
1153    if (clStatus != CL_SUCCESS)
1154    {
1155      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
1156      goto cleanup;
1157    }
1158
1159    for (i = 0; i < kernel->width; i++)
1160    {
1161      kernelBufferPtr[i] = (float) kernel->values[i];
1162    }
1163
1164    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
1165    if (clStatus != CL_SUCCESS)
1166    {
1167      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
1168      goto cleanup;
1169    }
1170  }
1171
1172  {
1173    unsigned int offsetRows;
1174    unsigned int sec;
1175
1176    /* create temp buffer */
1177    {
1178      length = inputImage->columns * (inputImage->rows / 2 + 1 + (kernel->width-1) / 2);
1179      tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
1180      if (clStatus != CL_SUCCESS)
1181      {
1182        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1183        goto cleanup;
1184      }
1185    }
1186
1187    /* get the OpenCL kernels */
1188    {
1189      blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection");
1190      if (blurRowKernel == NULL)
1191      {
1192        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
1193        goto cleanup;
1194      };
1195
1196      blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumnSection");
1197      if (blurColumnKernel == NULL)
1198      {
1199        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
1200        goto cleanup;
1201      };
1202    }
1203
1204    for (sec = 0; sec < 2; sec++)
1205    {
1206      {
1207        /* need logic to decide this value */
1208        int chunkSize = 256;
1209
1210        {
1211          imageColumns = inputImage->columns;
1212          if (sec == 0)
1213            imageRows = inputImage->rows / 2 + (kernel->width-1) / 2;
1214          else
1215            imageRows = (inputImage->rows - inputImage->rows / 2) + (kernel->width-1) / 2;
1216
1217          offsetRows = sec * inputImage->rows / 2;
1218
1219          kernelWidth = kernel->width;
1220
1221          /* set the kernel arguments */
1222          i = 0;
1223          clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1224          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1225          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
1226          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1227          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1228          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1229          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1230          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
1231          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
1232          clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec);
1233          if (clStatus != CL_SUCCESS)
1234          {
1235            (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
1236            goto cleanup;
1237          }
1238        }
1239
1240        /* launch the kernel */
1241        {
1242          size_t gsize[2];
1243          size_t wsize[2];
1244
1245          gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize);
1246          gsize[1] = imageRows;
1247          wsize[0] = chunkSize;
1248          wsize[1] = 1;
1249
1250          clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
1251          if (clStatus != CL_SUCCESS)
1252          {
1253            (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
1254            goto cleanup;
1255          }
1256          clEnv->library->clFlush(queue);
1257        }
1258      }
1259
1260      {
1261        /* need logic to decide this value */
1262        int chunkSize = 256;
1263
1264        {
1265          imageColumns = inputImage->columns;
1266          if (sec == 0)
1267            imageRows = inputImage->rows / 2;
1268          else
1269            imageRows = (inputImage->rows - inputImage->rows / 2);
1270
1271          offsetRows = sec * inputImage->rows / 2;
1272
1273          kernelWidth = kernel->width;
1274
1275          /* set the kernel arguments */
1276          i = 0;
1277          clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1278          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1279          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel);
1280          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1281          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1282          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1283          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1284          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL);
1285          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
1286          clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&sec);
1287          if (clStatus != CL_SUCCESS)
1288          {
1289            (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
1290            goto cleanup;
1291          }
1292        }
1293
1294        /* launch the kernel */
1295        {
1296          size_t gsize[2];
1297          size_t wsize[2];
1298
1299          gsize[0] = imageColumns;
1300          gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize);
1301          wsize[0] = 1;
1302          wsize[1] = chunkSize;
1303
1304          clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
1305          if (clStatus != CL_SUCCESS)
1306          {
1307            (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
1308            goto cleanup;
1309          }
1310          clEnv->library->clFlush(queue);
1311        }
1312      }
1313    }
1314
1315  }
1316
1317  /* get result */
1318  if (ALIGNED(filteredPixels,CLPixelPacket))
1319  {
1320    length = inputImage->columns * inputImage->rows;
1321    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
1322  }
1323  else
1324  {
1325    length = inputImage->columns * inputImage->rows;
1326    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
1327  }
1328  if (clStatus != CL_SUCCESS)
1329  {
1330    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
1331    goto cleanup;
1332  }
1333
1334  outputReady = MagickTrue;
1335
1336cleanup:
1337  OpenCLLogException(__FUNCTION__,__LINE__,exception);
1338
1339  if (inputImageBuffer!=NULL)     clEnv->library->clReleaseMemObject(inputImageBuffer);
1340  if (tempImageBuffer!=NULL)      clEnv->library->clReleaseMemObject(tempImageBuffer);
1341  if (filteredImageBuffer!=NULL)  clEnv->library->clReleaseMemObject(filteredImageBuffer);
1342  if (imageKernelBuffer!=NULL)    clEnv->library->clReleaseMemObject(imageKernelBuffer);
1343  if (blurRowKernel!=NULL)        RelinquishOpenCLKernel(clEnv, blurRowKernel);
1344  if (blurColumnKernel!=NULL)     RelinquishOpenCLKernel(clEnv, blurColumnKernel);
1345  if (queue != NULL)              RelinquishOpenCLCommandQueue(clEnv, queue);
1346  if (kernel!=NULL)               DestroyKernelInfo(kernel);
1347  if (outputReady == MagickFalse)
1348  {
1349    if (filteredImage != NULL)
1350    {
1351      DestroyImage(filteredImage);
1352      filteredImage = NULL;
1353    }
1354  }
1355  return filteredImage;
1356}
1357
1358/*
1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1360%                                                                             %
1361%                                                                             %
1362%                                                                             %
1363%     B l u r I m a g e  w i t h  O p e n C L                                 %
1364%                                                                             %
1365%                                                                             %
1366%                                                                             %
1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1368%
1369%  BlurImage() blurs an image.  We convolve the image with a Gaussian operator
1370%  of the given radius and standard deviation (sigma).  For reasonable results,
1371%  the radius should be larger than sigma.  Use a radius of 0 and BlurImage()
1372%  selects a suitable radius for you.
1373%
1374%  The format of the BlurImage method is:
1375%
1376%      Image *BlurImage(const Image *image,const double radius,
1377%        const double sigma,ExceptionInfo *exception)
1378%      Image *BlurImageChannel(const Image *image,const ChannelType channel,
1379%        const double radius,const double sigma,ExceptionInfo *exception)
1380%
1381%  A description of each parameter follows:
1382%
1383%    o image: the image.
1384%
1385%    o channel: the channel type.
1386%
1387%    o radius: the radius of the Gaussian, in pixels, not counting the center
1388%      pixel.
1389%
1390%    o sigma: the standard deviation of the Gaussian, in pixels.
1391%
1392%    o exception: return any errors or warnings in this structure.
1393%
1394*/
1395
1396MagickExport
1397Image* AccelerateBlurImage(const Image *image, const ChannelType channel, const double radius, const double sigma,ExceptionInfo *exception)
1398{
1399  MagickBooleanType status;
1400  Image* filteredImage = NULL;
1401
1402  assert(image != NULL);
1403  assert(exception != (ExceptionInfo *) NULL);
1404
1405  status = checkOpenCLEnvironment(exception);
1406  if (status == MagickFalse)
1407    return NULL;
1408
1409  status = checkAccelerateCondition(image, channel);
1410  if (status == MagickFalse)
1411    return NULL;
1412
1413  if (splitImage(image) && (image->rows / 2 > radius))
1414    filteredImage = ComputeBlurImageSection(image, channel, radius, sigma, exception);
1415  else
1416    filteredImage = ComputeBlurImage(image, channel, radius, sigma, exception);
1417
1418  return filteredImage;
1419}
1420
1421
1422static Image* ComputeRadialBlurImage(const Image *inputImage, const ChannelType channel, const double angle, ExceptionInfo *exception)
1423{
1424
1425  MagickBooleanType outputReady;
1426  Image* filteredImage;
1427  MagickCLEnv clEnv;
1428
1429  cl_int clStatus;
1430  size_t global_work_size[2];
1431
1432  cl_context context;
1433  cl_mem_flags mem_flags;
1434  cl_mem inputImageBuffer, filteredImageBuffer, sinThetaBuffer, cosThetaBuffer;
1435  cl_kernel radialBlurKernel;
1436  cl_command_queue queue;
1437
1438  const void *inputPixels;
1439  void *filteredPixels;
1440  void* hostPtr;
1441  float* sinThetaPtr;
1442  float* cosThetaPtr;
1443  MagickSizeType length;
1444  unsigned int matte;
1445  MagickPixelPacket bias;
1446  cl_float4 biasPixel;
1447  cl_float2 blurCenter;
1448  float blurRadius;
1449  unsigned int cossin_theta_size;
1450  float offset, theta;
1451
1452  unsigned int i;
1453
1454  outputReady = MagickFalse;
1455  context = NULL;
1456  filteredImage = NULL;
1457  inputImageBuffer = NULL;
1458  filteredImageBuffer = NULL;
1459  sinThetaBuffer = NULL;
1460  cosThetaBuffer = NULL;
1461  queue = NULL;
1462  radialBlurKernel = NULL;
1463
1464
1465  clEnv = GetDefaultOpenCLEnv();
1466  context = GetOpenCLContext(clEnv);
1467
1468
1469  /* Create and initialize OpenCL buffers. */
1470
1471  inputPixels = NULL;
1472  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
1473  if (inputPixels == (const void *) NULL)
1474  {
1475    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
1476    goto cleanup;
1477  }
1478
1479  /* If the host pointer is aligned to the size of CLPixelPacket,
1480     then use the host buffer directly from the GPU; otherwise,
1481     create a buffer on the GPU and copy the data over */
1482  if (ALIGNED(inputPixels,CLPixelPacket))
1483  {
1484    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1485  }
1486  else
1487  {
1488    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1489  }
1490  /* create a CL buffer from image pixel buffer */
1491  length = inputImage->columns * inputImage->rows;
1492  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1493  if (clStatus != CL_SUCCESS)
1494  {
1495    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1496    goto cleanup;
1497  }
1498
1499
1500  filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
1501  assert(filteredImage != NULL);
1502  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
1503  {
1504    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
1505    goto cleanup;
1506  }
1507  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
1508  if (filteredPixels == (void *) NULL)
1509  {
1510    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
1511    goto cleanup;
1512  }
1513
1514  if (ALIGNED(filteredPixels,CLPixelPacket))
1515  {
1516    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1517    hostPtr = filteredPixels;
1518  }
1519  else
1520  {
1521    mem_flags = CL_MEM_WRITE_ONLY;
1522    hostPtr = NULL;
1523  }
1524  /* create a CL buffer from image pixel buffer */
1525  length = inputImage->columns * inputImage->rows;
1526  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
1527  if (clStatus != CL_SUCCESS)
1528  {
1529    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1530    goto cleanup;
1531  }
1532
1533  blurCenter.s[0] = (float) (inputImage->columns-1)/2.0;
1534  blurCenter.s[1] = (float) (inputImage->rows-1)/2.0;
1535  blurRadius=hypot(blurCenter.s[0],blurCenter.s[1]);
1536  cossin_theta_size=(unsigned int) fabs(4.0*DegreesToRadians(angle)*sqrt((double)blurRadius)+2UL);
1537
1538  /* create a buffer for sin_theta and cos_theta */
1539  sinThetaBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, cossin_theta_size * sizeof(float), NULL, &clStatus);
1540  if (clStatus != CL_SUCCESS)
1541  {
1542    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1543    goto cleanup;
1544  }
1545  cosThetaBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, cossin_theta_size * sizeof(float), NULL, &clStatus);
1546  if (clStatus != CL_SUCCESS)
1547  {
1548    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1549    goto cleanup;
1550  }
1551
1552
1553  queue = AcquireOpenCLCommandQueue(clEnv);
1554  sinThetaPtr = (float*) clEnv->library->clEnqueueMapBuffer(queue, sinThetaBuffer, CL_TRUE, CL_MAP_WRITE, 0, cossin_theta_size*sizeof(float), 0, NULL, NULL, &clStatus);
1555  if (clStatus != CL_SUCCESS)
1556  {
1557    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.",".");
1558    goto cleanup;
1559  }
1560
1561  cosThetaPtr = (float*) clEnv->library->clEnqueueMapBuffer(queue, cosThetaBuffer, CL_TRUE, CL_MAP_WRITE, 0, cossin_theta_size*sizeof(float), 0, NULL, NULL, &clStatus);
1562  if (clStatus != CL_SUCCESS)
1563  {
1564    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.",".");
1565    goto cleanup;
1566  }
1567
1568  theta=DegreesToRadians(angle)/(MagickRealType) (cossin_theta_size-1);
1569  offset=theta*(MagickRealType) (cossin_theta_size-1)/2.0;
1570  for (i=0; i < (ssize_t) cossin_theta_size; i++)
1571  {
1572    cosThetaPtr[i]=(float)cos((double) (theta*i-offset));
1573    sinThetaPtr[i]=(float)sin((double) (theta*i-offset));
1574  }
1575
1576  clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, sinThetaBuffer, sinThetaPtr, 0, NULL, NULL);
1577  clStatus |= clEnv->library->clEnqueueUnmapMemObject(queue, cosThetaBuffer, cosThetaPtr, 0, NULL, NULL);
1578  if (clStatus != CL_SUCCESS)
1579  {
1580    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
1581    goto cleanup;
1582  }
1583
1584  /* get the OpenCL kernel */
1585  radialBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RadialBlur");
1586  if (radialBlurKernel == NULL)
1587  {
1588    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
1589    goto cleanup;
1590  }
1591
1592
1593  /* set the kernel arguments */
1594  i = 0;
1595  clStatus=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1596  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1597
1598  GetMagickPixelPacket(inputImage,&bias);
1599  biasPixel.s[0] = bias.red;
1600  biasPixel.s[1] = bias.green;
1601  biasPixel.s[2] = bias.blue;
1602  biasPixel.s[3] = bias.opacity;
1603  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_float4), &biasPixel);
1604  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(ChannelType), &channel);
1605
1606  matte = (inputImage->matte != MagickFalse)?1:0;
1607  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(unsigned int), &matte);
1608
1609  clStatus=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_float2), &blurCenter);
1610
1611  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&cosThetaBuffer);
1612  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&sinThetaBuffer);
1613  clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(unsigned int), &cossin_theta_size);
1614  if (clStatus != CL_SUCCESS)
1615  {
1616    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
1617    goto cleanup;
1618  }
1619
1620
1621  global_work_size[0] = inputImage->columns;
1622  global_work_size[1] = inputImage->rows;
1623  /* launch the kernel */
1624  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, radialBlurKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
1625  if (clStatus != CL_SUCCESS)
1626  {
1627    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
1628    goto cleanup;
1629  }
1630  clEnv->library->clFlush(queue);
1631
1632  if (ALIGNED(filteredPixels,CLPixelPacket))
1633  {
1634    length = inputImage->columns * inputImage->rows;
1635    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
1636  }
1637  else
1638  {
1639    length = inputImage->columns * inputImage->rows;
1640    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
1641  }
1642  if (clStatus != CL_SUCCESS)
1643  {
1644    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
1645    goto cleanup;
1646  }
1647  outputReady = MagickTrue;
1648
1649cleanup:
1650  OpenCLLogException(__FUNCTION__,__LINE__,exception);
1651
1652  if (filteredImageBuffer!=NULL)  clEnv->library->clReleaseMemObject(filteredImageBuffer);
1653  if (inputImageBuffer!=NULL)     clEnv->library->clReleaseMemObject(inputImageBuffer);
1654  if (sinThetaBuffer!=NULL)       clEnv->library->clReleaseMemObject(sinThetaBuffer);
1655  if (cosThetaBuffer!=NULL)       clEnv->library->clReleaseMemObject(cosThetaBuffer);
1656  if (radialBlurKernel!=NULL)     RelinquishOpenCLKernel(clEnv, radialBlurKernel);
1657  if (queue != NULL)              RelinquishOpenCLCommandQueue(clEnv, queue);
1658  if (outputReady == MagickFalse)
1659  {
1660    if (filteredImage != NULL)
1661    {
1662      DestroyImage(filteredImage);
1663      filteredImage = NULL;
1664    }
1665  }
1666  return filteredImage;
1667}
1668
1669/*
1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1671%                                                                             %
1672%                                                                             %
1673%                                                                             %
1674%     R a d i a l B l u r I m a g e  w i t h  O p e n C L                     %
1675%                                                                             %
1676%                                                                             %
1677%                                                                             %
1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1679%
1680%  RadialBlurImage() applies a radial blur to the image.
1681%
1682%  Andrew Protano contributed this effect.
1683%
1684%  The format of the RadialBlurImage method is:
1685%
1686%    Image *RadialBlurImage(const Image *image,const double angle,
1687%      ExceptionInfo *exception)
1688%    Image *RadialBlurImageChannel(const Image *image,const ChannelType channel,
1689%      const double angle,ExceptionInfo *exception)
1690%
1691%  A description of each parameter follows:
1692%
1693%    o image: the image.
1694%
1695%    o channel: the channel type.
1696%
1697%    o angle: the angle of the radial blur.
1698%
1699%    o exception: return any errors or warnings in this structure.
1700%
1701*/
1702
1703MagickExport
1704Image* AccelerateRadialBlurImage(const Image *image, const ChannelType channel, const double angle, ExceptionInfo *exception)
1705{
1706  MagickBooleanType status;
1707  Image* filteredImage;
1708
1709
1710  assert(image != NULL);
1711  assert(exception != NULL);
1712
1713  status = checkOpenCLEnvironment(exception);
1714  if (status == MagickFalse)
1715    return NULL;
1716
1717  status = checkAccelerateCondition(image, channel);
1718  if (status == MagickFalse)
1719    return NULL;
1720
1721  filteredImage = ComputeRadialBlurImage(image, channel, angle, exception);
1722  return filteredImage;
1723}
1724
1725
1726
1727static Image* ComputeUnsharpMaskImage(const Image *inputImage, const ChannelType channel,const double radius,const double sigma,
1728          const double gain,const double threshold,ExceptionInfo *exception)
1729{
1730  MagickBooleanType outputReady = MagickFalse;
1731  Image* filteredImage = NULL;
1732  MagickCLEnv clEnv = NULL;
1733
1734  cl_int clStatus;
1735
1736  const void *inputPixels;
1737  void *filteredPixels;
1738  cl_mem_flags mem_flags;
1739
1740  KernelInfo *kernel = NULL;
1741  char geometry[MaxTextExtent];
1742
1743  cl_context context = NULL;
1744  cl_mem inputImageBuffer = NULL;
1745  cl_mem filteredImageBuffer = NULL;
1746  cl_mem tempImageBuffer = NULL;
1747  cl_mem imageKernelBuffer = NULL;
1748  cl_kernel blurRowKernel = NULL;
1749  cl_kernel unsharpMaskBlurColumnKernel = NULL;
1750  cl_command_queue queue = NULL;
1751
1752  void* hostPtr;
1753  float* kernelBufferPtr;
1754  MagickSizeType length;
1755  unsigned int kernelWidth;
1756  float fGain;
1757  float fThreshold;
1758  unsigned int imageColumns, imageRows;
1759  int chunkSize;
1760  unsigned int i;
1761
1762  clEnv = GetDefaultOpenCLEnv();
1763  context = GetOpenCLContext(clEnv);
1764  queue = AcquireOpenCLCommandQueue(clEnv);
1765
1766  /* Create and initialize OpenCL buffers. */
1767  {
1768    inputPixels = NULL;
1769    inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
1770    if (inputPixels == (const void *) NULL)
1771    {
1772      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
1773      goto cleanup;
1774    }
1775
1776    /* If the host pointer is aligned to the size of CLPixelPacket,
1777     then use the host buffer directly from the GPU; otherwise,
1778     create a buffer on the GPU and copy the data over */
1779    if (ALIGNED(inputPixels,CLPixelPacket))
1780    {
1781      mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1782    }
1783    else
1784    {
1785      mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1786    }
1787    /* create a CL buffer from image pixel buffer */
1788    length = inputImage->columns * inputImage->rows;
1789    inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1790    if (clStatus != CL_SUCCESS)
1791    {
1792      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1793      goto cleanup;
1794    }
1795  }
1796
1797  /* create output */
1798  {
1799    filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
1800    assert(filteredImage != NULL);
1801    if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
1802    {
1803      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
1804      goto cleanup;
1805    }
1806    filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
1807    if (filteredPixels == (void *) NULL)
1808    {
1809      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
1810      goto cleanup;
1811    }
1812
1813    if (ALIGNED(filteredPixels,CLPixelPacket))
1814    {
1815      mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1816      hostPtr = filteredPixels;
1817    }
1818    else
1819    {
1820      mem_flags = CL_MEM_WRITE_ONLY;
1821      hostPtr = NULL;
1822    }
1823
1824    /* create a CL buffer from image pixel buffer */
1825    length = inputImage->columns * inputImage->rows;
1826    filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
1827    if (clStatus != CL_SUCCESS)
1828    {
1829      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1830      goto cleanup;
1831    }
1832  }
1833
1834  /* create the blur kernel */
1835  {
1836    (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
1837    kernel=AcquireKernelInfo(geometry);
1838    if (kernel == (KernelInfo *) NULL)
1839    {
1840      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.",".");
1841      goto cleanup;
1842    }
1843
1844    imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus);
1845    if (clStatus != CL_SUCCESS)
1846    {
1847      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1848      goto cleanup;
1849    }
1850
1851
1852    kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
1853    if (clStatus != CL_SUCCESS)
1854    {
1855      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
1856      goto cleanup;
1857    }
1858    for (i = 0; i < kernel->width; i++)
1859    {
1860      kernelBufferPtr[i] = (float) kernel->values[i];
1861    }
1862    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
1863    if (clStatus != CL_SUCCESS)
1864    {
1865      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
1866      goto cleanup;
1867    }
1868  }
1869
1870  {
1871    /* create temp buffer */
1872    {
1873      length = inputImage->columns * inputImage->rows;
1874      tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
1875      if (clStatus != CL_SUCCESS)
1876      {
1877        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1878        goto cleanup;
1879      }
1880    }
1881
1882    /* get the opencl kernel */
1883    {
1884      blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow");
1885      if (blurRowKernel == NULL)
1886      {
1887        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
1888        goto cleanup;
1889      };
1890
1891      unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumn");
1892      if (unsharpMaskBlurColumnKernel == NULL)
1893      {
1894        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
1895        goto cleanup;
1896      };
1897    }
1898
1899    {
1900      chunkSize = 256;
1901
1902      imageColumns = inputImage->columns;
1903      imageRows = inputImage->rows;
1904
1905      kernelWidth = kernel->width;
1906
1907      /* set the kernel arguments */
1908      i = 0;
1909      clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1910      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1911      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
1912      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1913      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1914      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1915      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1916      clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
1917      if (clStatus != CL_SUCCESS)
1918      {
1919        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
1920        goto cleanup;
1921      }
1922    }
1923
1924    /* launch the kernel */
1925    {
1926      size_t gsize[2];
1927      size_t wsize[2];
1928
1929      gsize[0] = chunkSize*((inputImage->columns+chunkSize-1)/chunkSize);
1930      gsize[1] = inputImage->rows;
1931      wsize[0] = chunkSize;
1932      wsize[1] = 1;
1933
1934      clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
1935      if (clStatus != CL_SUCCESS)
1936      {
1937        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
1938        goto cleanup;
1939      }
1940      clEnv->library->clFlush(queue);
1941    }
1942
1943
1944    {
1945      chunkSize = 256;
1946      imageColumns = inputImage->columns;
1947      imageRows = inputImage->rows;
1948      kernelWidth = kernel->width;
1949      fGain = (float)gain;
1950      fThreshold = (float)threshold;
1951
1952      i = 0;
1953      clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1954      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1955      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1956      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1957      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1958      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
1959      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL);
1960      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel);
1961      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1962      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1963      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
1964      clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
1965
1966      if (clStatus != CL_SUCCESS)
1967      {
1968        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
1969        goto cleanup;
1970      }
1971    }
1972
1973    /* launch the kernel */
1974    {
1975      size_t gsize[2];
1976      size_t wsize[2];
1977
1978      gsize[0] = inputImage->columns;
1979      gsize[1] = chunkSize*((inputImage->rows+chunkSize-1)/chunkSize);
1980      wsize[0] = 1;
1981      wsize[1] = chunkSize;
1982
1983      clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
1984      if (clStatus != CL_SUCCESS)
1985      {
1986        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
1987        goto cleanup;
1988      }
1989      clEnv->library->clFlush(queue);
1990    }
1991
1992  }
1993
1994  /* get result */
1995  if (ALIGNED(filteredPixels,CLPixelPacket))
1996  {
1997    length = inputImage->columns * inputImage->rows;
1998    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
1999  }
2000  else
2001  {
2002    length = inputImage->columns * inputImage->rows;
2003    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
2004  }
2005  if (clStatus != CL_SUCCESS)
2006  {
2007    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
2008    goto cleanup;
2009  }
2010
2011  outputReady = MagickTrue;
2012
2013cleanup:
2014  OpenCLLogException(__FUNCTION__,__LINE__,exception);
2015
2016  if (kernel != NULL)			      kernel=DestroyKernelInfo(kernel);
2017  if (inputImageBuffer!=NULL)		      clEnv->library->clReleaseMemObject(inputImageBuffer);
2018  if (filteredImageBuffer!=NULL)              clEnv->library->clReleaseMemObject(filteredImageBuffer);
2019  if (tempImageBuffer!=NULL)                  clEnv->library->clReleaseMemObject(tempImageBuffer);
2020  if (imageKernelBuffer!=NULL)                clEnv->library->clReleaseMemObject(imageKernelBuffer);
2021  if (blurRowKernel!=NULL)                    RelinquishOpenCLKernel(clEnv, blurRowKernel);
2022  if (unsharpMaskBlurColumnKernel!=NULL)      RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel);
2023  if (queue != NULL)                          RelinquishOpenCLCommandQueue(clEnv, queue);
2024  if (outputReady == MagickFalse)
2025  {
2026    if (filteredImage != NULL)
2027    {
2028      DestroyImage(filteredImage);
2029      filteredImage = NULL;
2030    }
2031  }
2032  return filteredImage;
2033}
2034
2035
2036static Image* ComputeUnsharpMaskImageSection(const Image *inputImage, const ChannelType channel,const double radius,const double sigma,
2037          const double gain,const double threshold,ExceptionInfo *exception)
2038{
2039  MagickBooleanType outputReady = MagickFalse;
2040  Image* filteredImage = NULL;
2041  MagickCLEnv clEnv = NULL;
2042
2043  cl_int clStatus;
2044
2045  const void *inputPixels;
2046  void *filteredPixels;
2047  cl_mem_flags mem_flags;
2048
2049  KernelInfo *kernel = NULL;
2050  char geometry[MaxTextExtent];
2051
2052  cl_context context = NULL;
2053  cl_mem inputImageBuffer = NULL;
2054  cl_mem filteredImageBuffer = NULL;
2055  cl_mem tempImageBuffer = NULL;
2056  cl_mem imageKernelBuffer = NULL;
2057  cl_kernel blurRowKernel = NULL;
2058  cl_kernel unsharpMaskBlurColumnKernel = NULL;
2059  cl_command_queue queue = NULL;
2060
2061  void* hostPtr;
2062  float* kernelBufferPtr;
2063  MagickSizeType length;
2064  unsigned int kernelWidth;
2065  float fGain;
2066  float fThreshold;
2067  unsigned int imageColumns, imageRows;
2068  int chunkSize;
2069  unsigned int i;
2070
2071  clEnv = GetDefaultOpenCLEnv();
2072  context = GetOpenCLContext(clEnv);
2073  queue = AcquireOpenCLCommandQueue(clEnv);
2074
2075  /* Create and initialize OpenCL buffers. */
2076  {
2077    inputPixels = NULL;
2078    inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
2079    if (inputPixels == (const void *) NULL)
2080    {
2081      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
2082      goto cleanup;
2083    }
2084
2085    /* If the host pointer is aligned to the size of CLPixelPacket,
2086     then use the host buffer directly from the GPU; otherwise,
2087     create a buffer on the GPU and copy the data over */
2088    if (ALIGNED(inputPixels,CLPixelPacket))
2089    {
2090      mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2091    }
2092    else
2093    {
2094      mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2095    }
2096    /* create a CL buffer from image pixel buffer */
2097    length = inputImage->columns * inputImage->rows;
2098    inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
2099    if (clStatus != CL_SUCCESS)
2100    {
2101      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2102      goto cleanup;
2103    }
2104  }
2105
2106  /* create output */
2107  {
2108    filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
2109    assert(filteredImage != NULL);
2110    if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
2111    {
2112      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
2113      goto cleanup;
2114    }
2115    filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
2116    if (filteredPixels == (void *) NULL)
2117    {
2118      (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
2119      goto cleanup;
2120    }
2121
2122    if (ALIGNED(filteredPixels,CLPixelPacket))
2123    {
2124      mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
2125      hostPtr = filteredPixels;
2126    }
2127    else
2128    {
2129      mem_flags = CL_MEM_WRITE_ONLY;
2130      hostPtr = NULL;
2131    }
2132
2133    /* create a CL buffer from image pixel buffer */
2134    length = inputImage->columns * inputImage->rows;
2135    filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
2136    if (clStatus != CL_SUCCESS)
2137    {
2138      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2139      goto cleanup;
2140    }
2141  }
2142
2143  /* create the blur kernel */
2144  {
2145    (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
2146    kernel=AcquireKernelInfo(geometry);
2147    if (kernel == (KernelInfo *) NULL)
2148    {
2149      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.",".");
2150      goto cleanup;
2151    }
2152
2153    imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus);
2154    if (clStatus != CL_SUCCESS)
2155    {
2156      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2157      goto cleanup;
2158    }
2159
2160
2161    kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
2162    if (clStatus != CL_SUCCESS)
2163    {
2164      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
2165      goto cleanup;
2166    }
2167    for (i = 0; i < kernel->width; i++)
2168    {
2169      kernelBufferPtr[i] = (float) kernel->values[i];
2170    }
2171    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
2172    if (clStatus != CL_SUCCESS)
2173    {
2174      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
2175      goto cleanup;
2176    }
2177  }
2178
2179  {
2180    unsigned int offsetRows;
2181    unsigned int sec;
2182
2183    /* create temp buffer */
2184    {
2185      length = inputImage->columns * (inputImage->rows / 2 + 1 + (kernel->width-1) / 2);
2186      tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
2187      if (clStatus != CL_SUCCESS)
2188      {
2189        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2190        goto cleanup;
2191      }
2192    }
2193
2194    /* get the opencl kernel */
2195    {
2196      blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection");
2197      if (blurRowKernel == NULL)
2198      {
2199        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
2200        goto cleanup;
2201      };
2202
2203      unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumnSection");
2204      if (unsharpMaskBlurColumnKernel == NULL)
2205      {
2206        (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
2207        goto cleanup;
2208      };
2209    }
2210
2211    for (sec = 0; sec < 2; sec++)
2212    {
2213      {
2214        chunkSize = 256;
2215
2216        imageColumns = inputImage->columns;
2217        if (sec == 0)
2218          imageRows = inputImage->rows / 2 + (kernel->width-1) / 2;
2219        else
2220          imageRows = (inputImage->rows - inputImage->rows / 2) + (kernel->width-1) / 2;
2221
2222        offsetRows = sec * inputImage->rows / 2;
2223
2224        kernelWidth = kernel->width;
2225
2226        /* set the kernel arguments */
2227        i = 0;
2228        clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
2229        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2230        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
2231        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2232        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2233        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2234        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2235        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
2236        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
2237        clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec);
2238        if (clStatus != CL_SUCCESS)
2239        {
2240          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
2241          goto cleanup;
2242        }
2243      }
2244      /* launch the kernel */
2245      {
2246        size_t gsize[2];
2247        size_t wsize[2];
2248
2249        gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize);
2250        gsize[1] = imageRows;
2251        wsize[0] = chunkSize;
2252        wsize[1] = 1;
2253
2254        clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
2255        if (clStatus != CL_SUCCESS)
2256        {
2257          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
2258          goto cleanup;
2259        }
2260        clEnv->library->clFlush(queue);
2261      }
2262
2263
2264      {
2265        chunkSize = 256;
2266
2267        imageColumns = inputImage->columns;
2268        if (sec == 0)
2269          imageRows = inputImage->rows / 2;
2270        else
2271          imageRows = (inputImage->rows - inputImage->rows / 2);
2272
2273        offsetRows = sec * inputImage->rows / 2;
2274
2275        kernelWidth = kernel->width;
2276
2277        fGain = (float)gain;
2278        fThreshold = (float)threshold;
2279
2280        i = 0;
2281        clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
2282        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2283        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
2284        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2285        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2286        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
2287        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL);
2288        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel);
2289        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2290        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2291        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
2292        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
2293        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
2294        clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&sec);
2295
2296        if (clStatus != CL_SUCCESS)
2297        {
2298          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
2299          goto cleanup;
2300        }
2301      }
2302
2303      /* launch the kernel */
2304      {
2305        size_t gsize[2];
2306        size_t wsize[2];
2307
2308        gsize[0] = imageColumns;
2309        gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize);
2310        wsize[0] = 1;
2311        wsize[1] = chunkSize;
2312
2313        clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
2314        if (clStatus != CL_SUCCESS)
2315        {
2316          (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
2317          goto cleanup;
2318        }
2319        clEnv->library->clFlush(queue);
2320      }
2321    }
2322  }
2323
2324  /* get result */
2325  if (ALIGNED(filteredPixels,CLPixelPacket))
2326  {
2327    length = inputImage->columns * inputImage->rows;
2328    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
2329  }
2330  else
2331  {
2332    length = inputImage->columns * inputImage->rows;
2333    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
2334  }
2335  if (clStatus != CL_SUCCESS)
2336  {
2337    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
2338    goto cleanup;
2339  }
2340
2341  outputReady = MagickTrue;
2342
2343cleanup:
2344  OpenCLLogException(__FUNCTION__,__LINE__,exception);
2345
2346  if (kernel != NULL)			      kernel=DestroyKernelInfo(kernel);
2347  if (inputImageBuffer!=NULL)		      clEnv->library->clReleaseMemObject(inputImageBuffer);
2348  if (filteredImageBuffer!=NULL)              clEnv->library->clReleaseMemObject(filteredImageBuffer);
2349  if (tempImageBuffer!=NULL)                  clEnv->library->clReleaseMemObject(tempImageBuffer);
2350  if (imageKernelBuffer!=NULL)                clEnv->library->clReleaseMemObject(imageKernelBuffer);
2351  if (blurRowKernel!=NULL)                    RelinquishOpenCLKernel(clEnv, blurRowKernel);
2352  if (unsharpMaskBlurColumnKernel!=NULL)      RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel);
2353  if (queue != NULL)                          RelinquishOpenCLCommandQueue(clEnv, queue);
2354  if (outputReady == MagickFalse)
2355  {
2356    if (filteredImage != NULL)
2357    {
2358      DestroyImage(filteredImage);
2359      filteredImage = NULL;
2360    }
2361  }
2362  return filteredImage;
2363}
2364
2365
2366/*
2367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2368%                                                                             %
2369%                                                                             %
2370%                                                                             %
2371%     U n s h a r p M a s k I m a g e  w i t h  O p e n C L                   %
2372%                                                                             %
2373%                                                                             %
2374%                                                                             %
2375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2376%
2377%  UnsharpMaskImage() sharpens one or more image channels.  We convolve the
2378%  image with a Gaussian operator of the given radius and standard deviation
2379%  (sigma).  For reasonable results, radius should be larger than sigma.  Use a
2380%  radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
2381%
2382%  The format of the UnsharpMaskImage method is:
2383%
2384%    Image *UnsharpMaskImage(const Image *image,const double radius,
2385%      const double sigma,const double amount,const double threshold,
2386%      ExceptionInfo *exception)
2387%    Image *UnsharpMaskImageChannel(const Image *image,
2388%      const ChannelType channel,const double radius,const double sigma,
2389%      const double gain,const double threshold,ExceptionInfo *exception)
2390%
2391%  A description of each parameter follows:
2392%
2393%    o image: the image.
2394%
2395%    o channel: the channel type.
2396%
2397%    o radius: the radius of the Gaussian, in pixels, not counting the center
2398%      pixel.
2399%
2400%    o sigma: the standard deviation of the Gaussian, in pixels.
2401%
2402%    o gain: the percentage of the difference between the original and the
2403%      blur image that is added back into the original.
2404%
2405%    o threshold: the threshold in pixels needed to apply the diffence gain.
2406%
2407%    o exception: return any errors or warnings in this structure.
2408%
2409*/
2410
2411
2412MagickExport
2413Image* AccelerateUnsharpMaskImage(const Image *image, const ChannelType channel,const double radius,const double sigma,
2414          const double gain,const double threshold,ExceptionInfo *exception)
2415{
2416  MagickBooleanType status;
2417  Image* filteredImage;
2418
2419
2420  assert(image != NULL);
2421  assert(exception != NULL);
2422
2423  status = checkOpenCLEnvironment(exception);
2424  if (status == MagickFalse)
2425    return NULL;
2426
2427  status = checkAccelerateCondition(image, channel);
2428  if (status == MagickFalse)
2429    return NULL;
2430
2431  if (splitImage(image) && (image->rows / 2 > radius))
2432    filteredImage = ComputeUnsharpMaskImageSection(image,channel,radius,sigma,gain,threshold,exception);
2433  else
2434    filteredImage = ComputeUnsharpMaskImage(image,channel,radius,sigma,gain,threshold,exception);
2435  return filteredImage;
2436
2437}
2438
2439static MagickBooleanType resizeHorizontalFilter(cl_mem inputImage
2440                                 , const unsigned int inputImageColumns, const unsigned int inputImageRows, const unsigned int matte
2441                                 , cl_mem resizedImage, const unsigned int resizedColumns, const unsigned int resizedRows
2442                                 , const ResizeFilter* resizeFilter, cl_mem resizeFilterCubicCoefficients, const float xFactor
2443                                 , MagickCLEnv clEnv, cl_command_queue queue, ExceptionInfo *exception)
2444{
2445  MagickBooleanType status = MagickFalse;
2446
2447  float scale, support;
2448  unsigned int i;
2449  cl_kernel horizontalKernel = NULL;
2450  cl_int clStatus;
2451  size_t global_work_size[2];
2452  size_t local_work_size[2];
2453  int resizeFilterType, resizeWindowType;
2454  float resizeFilterScale, resizeFilterSupport, resizeFilterWindowSupport, resizeFilterBlur;
2455  size_t totalLocalMemorySize;
2456  size_t imageCacheLocalMemorySize, pixelAccumulatorLocalMemorySize
2457        , weightAccumulatorLocalMemorySize, gammaAccumulatorLocalMemorySize;
2458  size_t deviceLocalMemorySize;
2459  int cacheRangeStart, cacheRangeEnd, numCachedPixels;
2460
2461  const unsigned int workgroupSize = 256;
2462  unsigned int pixelPerWorkgroup;
2463  unsigned int chunkSize;
2464
2465  /*
2466  Apply filter to resize vertically from image to resize image.
2467  */
2468  scale=MAGICK_MAX(1.0/xFactor+MagickEpsilon,1.0);
2469  support=scale*GetResizeFilterSupport(resizeFilter);
2470  if (support < 0.5)
2471  {
2472    /*
2473    Support too small even for nearest neighbour: Reduce to point
2474    sampling.
2475    */
2476    support=(MagickRealType) 0.5;
2477    scale=1.0;
2478  }
2479  scale=PerceptibleReciprocal(scale);
2480
2481  if (resizedColumns < workgroupSize)
2482  {
2483    chunkSize = 32;
2484    pixelPerWorkgroup = 32;
2485  }
2486  else
2487  {
2488    chunkSize = workgroupSize;
2489    pixelPerWorkgroup = workgroupSize;
2490  }
2491
2492  /* get the local memory size supported by the device */
2493  deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
2494
2495DisableMSCWarning(4127)
2496  while(1)
2497RestoreMSCWarning
2498  {
2499    /* calculate the local memory size needed per workgroup */
2500    cacheRangeStart = (int) (((0 + 0.5)/xFactor+MagickEpsilon)-support+0.5);
2501    cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/xFactor+MagickEpsilon)+support+0.5);
2502    numCachedPixels = cacheRangeEnd - cacheRangeStart + 1;
2503    imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket);
2504    totalLocalMemorySize = imageCacheLocalMemorySize;
2505
2506    /* local size for the pixel accumulator */
2507    pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4);
2508    totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
2509
2510    /* local memory size for the weight accumulator */
2511    weightAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2512    totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
2513
2514    /* local memory size for the gamma accumulator */
2515    if (matte == 0)
2516      gammaAccumulatorLocalMemorySize = sizeof(float);
2517    else
2518      gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2519    totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
2520
2521    if (totalLocalMemorySize <= deviceLocalMemorySize)
2522      break;
2523    else
2524    {
2525      pixelPerWorkgroup = pixelPerWorkgroup/2;
2526      chunkSize = chunkSize/2;
2527      if (pixelPerWorkgroup == 0
2528          || chunkSize == 0)
2529      {
2530        /* quit, fallback to CPU */
2531        goto cleanup;
2532      }
2533    }
2534  }
2535
2536  resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter);
2537  resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter);
2538
2539
2540  if (resizeFilterType == SincFastWeightingFunction
2541    && resizeWindowType == SincFastWeightingFunction)
2542  {
2543    horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilterSinc");
2544  }
2545  else
2546  {
2547    horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilter");
2548  }
2549  if (horizontalKernel == NULL)
2550  {
2551    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
2552    goto cleanup;
2553  }
2554
2555  i = 0;
2556  clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&inputImage);
2557  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageColumns);
2558  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageRows);
2559  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte);
2560  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&xFactor);
2561  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage);
2562
2563  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns);
2564  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows);
2565
2566  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType);
2567  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType);
2568  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients);
2569
2570  resizeFilterScale = (float) GetResizeFilterScale(resizeFilter);
2571  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale);
2572
2573  resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter);
2574  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport);
2575
2576  resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter);
2577  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport);
2578
2579  resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter);
2580  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur);
2581
2582
2583  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL);
2584  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels);
2585  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup);
2586  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize);
2587
2588
2589  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL);
2590  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL);
2591  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL);
2592
2593  if (clStatus != CL_SUCCESS)
2594  {
2595    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
2596    goto cleanup;
2597  }
2598
2599  global_work_size[0] = (resizedColumns+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize;
2600  global_work_size[1] = resizedRows;
2601
2602  local_work_size[0] = workgroupSize;
2603  local_work_size[1] = 1;
2604  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
2605  if (clStatus != CL_SUCCESS)
2606  {
2607    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
2608    goto cleanup;
2609  }
2610  clEnv->library->clFlush(queue);
2611  status = MagickTrue;
2612
2613
2614cleanup:
2615  OpenCLLogException(__FUNCTION__,__LINE__,exception);
2616
2617  if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2618
2619  return status;
2620}
2621
2622
2623static MagickBooleanType resizeVerticalFilter(cl_mem inputImage
2624                                 , const unsigned int inputImageColumns, const unsigned int inputImageRows, const unsigned int matte
2625                                 , cl_mem resizedImage, const unsigned int resizedColumns, const unsigned int resizedRows
2626                                 , const ResizeFilter* resizeFilter, cl_mem resizeFilterCubicCoefficients, const float yFactor
2627                                 , MagickCLEnv clEnv, cl_command_queue queue, ExceptionInfo *exception)
2628{
2629  MagickBooleanType status = MagickFalse;
2630
2631  float scale, support;
2632  unsigned int i;
2633  cl_kernel horizontalKernel = NULL;
2634  cl_int clStatus;
2635  size_t global_work_size[2];
2636  size_t local_work_size[2];
2637  int resizeFilterType, resizeWindowType;
2638  float resizeFilterScale, resizeFilterSupport, resizeFilterWindowSupport, resizeFilterBlur;
2639  size_t totalLocalMemorySize;
2640  size_t imageCacheLocalMemorySize, pixelAccumulatorLocalMemorySize
2641        , weightAccumulatorLocalMemorySize, gammaAccumulatorLocalMemorySize;
2642  size_t deviceLocalMemorySize;
2643  int cacheRangeStart, cacheRangeEnd, numCachedPixels;
2644
2645  const unsigned int workgroupSize = 256;
2646  unsigned int pixelPerWorkgroup;
2647  unsigned int chunkSize;
2648
2649  /*
2650  Apply filter to resize vertically from image to resize image.
2651  */
2652  scale=MAGICK_MAX(1.0/yFactor+MagickEpsilon,1.0);
2653  support=scale*GetResizeFilterSupport(resizeFilter);
2654  if (support < 0.5)
2655  {
2656    /*
2657    Support too small even for nearest neighbour: Reduce to point
2658    sampling.
2659    */
2660    support=(MagickRealType) 0.5;
2661    scale=1.0;
2662  }
2663  scale=PerceptibleReciprocal(scale);
2664
2665  if (resizedRows < workgroupSize)
2666  {
2667    chunkSize = 32;
2668    pixelPerWorkgroup = 32;
2669  }
2670  else
2671  {
2672    chunkSize = workgroupSize;
2673    pixelPerWorkgroup = workgroupSize;
2674  }
2675
2676  /* get the local memory size supported by the device */
2677  deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
2678
2679DisableMSCWarning(4127)
2680  while(1)
2681RestoreMSCWarning
2682  {
2683    /* calculate the local memory size needed per workgroup */
2684    cacheRangeStart = (int) (((0 + 0.5)/yFactor+MagickEpsilon)-support+0.5);
2685    cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/yFactor+MagickEpsilon)+support+0.5);
2686    numCachedPixels = cacheRangeEnd - cacheRangeStart + 1;
2687    imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket);
2688    totalLocalMemorySize = imageCacheLocalMemorySize;
2689
2690    /* local size for the pixel accumulator */
2691    pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4);
2692    totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
2693
2694    /* local memory size for the weight accumulator */
2695    weightAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2696    totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
2697
2698    /* local memory size for the gamma accumulator */
2699    if (matte == 0)
2700      gammaAccumulatorLocalMemorySize = sizeof(float);
2701    else
2702      gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2703    totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
2704
2705    if (totalLocalMemorySize <= deviceLocalMemorySize)
2706      break;
2707    else
2708    {
2709      pixelPerWorkgroup = pixelPerWorkgroup/2;
2710      chunkSize = chunkSize/2;
2711      if (pixelPerWorkgroup == 0
2712          || chunkSize == 0)
2713      {
2714        /* quit, fallback to CPU */
2715        goto cleanup;
2716      }
2717    }
2718  }
2719
2720  resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter);
2721  resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter);
2722
2723  if (resizeFilterType == SincFastWeightingFunction
2724    && resizeWindowType == SincFastWeightingFunction)
2725    horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilterSinc");
2726  else
2727    horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilter");
2728
2729  if (horizontalKernel == NULL)
2730  {
2731    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
2732    goto cleanup;
2733  }
2734
2735  i = 0;
2736  clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&inputImage);
2737  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageColumns);
2738  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageRows);
2739  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte);
2740  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&yFactor);
2741  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage);
2742
2743  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns);
2744  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows);
2745
2746  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType);
2747  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType);
2748  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients);
2749
2750  resizeFilterScale = (float) GetResizeFilterScale(resizeFilter);
2751  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale);
2752
2753  resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter);
2754  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport);
2755
2756  resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter);
2757  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport);
2758
2759  resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter);
2760  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur);
2761
2762
2763  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL);
2764  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels);
2765  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup);
2766  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize);
2767
2768
2769  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL);
2770  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL);
2771  clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL);
2772
2773  if (clStatus != CL_SUCCESS)
2774  {
2775    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
2776    goto cleanup;
2777  }
2778
2779  global_work_size[0] = resizedColumns;
2780  global_work_size[1] = (resizedRows+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize;
2781
2782  local_work_size[0] = 1;
2783  local_work_size[1] = workgroupSize;
2784  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
2785  if (clStatus != CL_SUCCESS)
2786  {
2787    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
2788    goto cleanup;
2789  }
2790  clEnv->library->clFlush(queue);
2791  status = MagickTrue;
2792
2793
2794cleanup:
2795  OpenCLLogException(__FUNCTION__,__LINE__,exception);
2796
2797  if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2798
2799  return status;
2800}
2801
2802
2803
2804static Image* ComputeResizeImage(const Image* inputImage, const size_t resizedColumns, const size_t resizedRows
2805        , const ResizeFilter* resizeFilter, ExceptionInfo *exception)
2806{
2807
2808  MagickBooleanType outputReady = MagickFalse;
2809  Image* filteredImage = NULL;
2810  MagickCLEnv clEnv = NULL;
2811
2812  cl_int clStatus;
2813  MagickBooleanType status;
2814  const void *inputPixels;
2815  void* filteredPixels;
2816  void* hostPtr;
2817  const MagickRealType* resizeFilterCoefficient;
2818  float* mappedCoefficientBuffer;
2819  float xFactor, yFactor;
2820  MagickSizeType length;
2821
2822  cl_mem_flags mem_flags;
2823  cl_context context = NULL;
2824  cl_mem inputImageBuffer = NULL;
2825  cl_mem tempImageBuffer = NULL;
2826  cl_mem filteredImageBuffer = NULL;
2827  cl_mem cubicCoefficientsBuffer = NULL;
2828  cl_command_queue queue = NULL;
2829
2830  unsigned int i;
2831
2832  clEnv = GetDefaultOpenCLEnv();
2833  context = GetOpenCLContext(clEnv);
2834
2835  /* Create and initialize OpenCL buffers. */
2836  inputPixels = NULL;
2837  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
2838  if (inputPixels == (const void *) NULL)
2839  {
2840    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
2841    goto cleanup;
2842  }
2843
2844  /* If the host pointer is aligned to the size of CLPixelPacket,
2845     then use the host buffer directly from the GPU; otherwise,
2846     create a buffer on the GPU and copy the data over */
2847  if (ALIGNED(inputPixels,CLPixelPacket))
2848  {
2849    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2850  }
2851  else
2852  {
2853    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2854  }
2855  /* create a CL buffer from image pixel buffer */
2856  length = inputImage->columns * inputImage->rows;
2857  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
2858  if (clStatus != CL_SUCCESS)
2859  {
2860    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2861    goto cleanup;
2862  }
2863
2864  cubicCoefficientsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, 7 * sizeof(float), NULL, &clStatus);
2865  if (clStatus != CL_SUCCESS)
2866  {
2867    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2868    goto cleanup;
2869  }
2870  queue = AcquireOpenCLCommandQueue(clEnv);
2871  mappedCoefficientBuffer = (float*)clEnv->library->clEnqueueMapBuffer(queue, cubicCoefficientsBuffer, CL_TRUE, CL_MAP_WRITE, 0, 7 * sizeof(float)
2872          , 0, NULL, NULL, &clStatus);
2873  if (clStatus != CL_SUCCESS)
2874  {
2875    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
2876    goto cleanup;
2877  }
2878  resizeFilterCoefficient = GetResizeFilterCoefficient(resizeFilter);
2879  for (i = 0; i < 7; i++)
2880  {
2881    mappedCoefficientBuffer[i] = (float) resizeFilterCoefficient[i];
2882  }
2883  clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, cubicCoefficientsBuffer, mappedCoefficientBuffer, 0, NULL, NULL);
2884  if (clStatus != CL_SUCCESS)
2885  {
2886    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
2887    goto cleanup;
2888  }
2889
2890  filteredImage = CloneImage(inputImage,resizedColumns,resizedRows,MagickTrue,exception);
2891  if (filteredImage == NULL)
2892    goto cleanup;
2893
2894  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
2895  {
2896    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
2897    goto cleanup;
2898  }
2899  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
2900  if (filteredPixels == (void *) NULL)
2901  {
2902    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
2903    goto cleanup;
2904  }
2905
2906  if (ALIGNED(filteredPixels,CLPixelPacket))
2907  {
2908    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
2909    hostPtr = filteredPixels;
2910  }
2911  else
2912  {
2913    mem_flags = CL_MEM_WRITE_ONLY;
2914    hostPtr = NULL;
2915  }
2916
2917  /* create a CL buffer from image pixel buffer */
2918  length = filteredImage->columns * filteredImage->rows;
2919  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
2920  if (clStatus != CL_SUCCESS)
2921  {
2922    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2923    goto cleanup;
2924  }
2925
2926  xFactor=(float) resizedColumns/(float) inputImage->columns;
2927  yFactor=(float) resizedRows/(float) inputImage->rows;
2928  if (xFactor > yFactor)
2929  {
2930
2931    length = resizedColumns*inputImage->rows;
2932    tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus);
2933    if (clStatus != CL_SUCCESS)
2934    {
2935      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2936      goto cleanup;
2937    }
2938
2939    status = resizeHorizontalFilter(inputImageBuffer, inputImage->columns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0
2940          , tempImageBuffer, resizedColumns, inputImage->rows
2941          , resizeFilter, cubicCoefficientsBuffer
2942          , xFactor, clEnv, queue, exception);
2943    if (status != MagickTrue)
2944      goto cleanup;
2945
2946    status = resizeVerticalFilter(tempImageBuffer, resizedColumns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0
2947       , filteredImageBuffer, resizedColumns, resizedRows
2948       , resizeFilter, cubicCoefficientsBuffer
2949       , yFactor, clEnv, queue, exception);
2950    if (status != MagickTrue)
2951      goto cleanup;
2952  }
2953  else
2954  {
2955    length = inputImage->columns*resizedRows;
2956    tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus);
2957    if (clStatus != CL_SUCCESS)
2958    {
2959      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2960      goto cleanup;
2961    }
2962
2963    status = resizeVerticalFilter(inputImageBuffer, inputImage->columns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0
2964       , tempImageBuffer, inputImage->columns, resizedRows
2965       , resizeFilter, cubicCoefficientsBuffer
2966       , yFactor, clEnv, queue, exception);
2967    if (status != MagickTrue)
2968      goto cleanup;
2969
2970    status = resizeHorizontalFilter(tempImageBuffer, inputImage->columns, resizedRows, (inputImage->matte != MagickFalse)?1:0
2971       , filteredImageBuffer, resizedColumns, resizedRows
2972       , resizeFilter, cubicCoefficientsBuffer
2973       , xFactor, clEnv, queue, exception);
2974    if (status != MagickTrue)
2975      goto cleanup;
2976  }
2977  length = resizedColumns*resizedRows;
2978  if (ALIGNED(filteredPixels,CLPixelPacket))
2979  {
2980    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
2981  }
2982  else
2983  {
2984    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
2985  }
2986  if (clStatus != CL_SUCCESS)
2987  {
2988    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
2989    goto cleanup;
2990  }
2991  outputReady = MagickTrue;
2992
2993cleanup:
2994  OpenCLLogException(__FUNCTION__,__LINE__,exception);
2995
2996  if (inputImageBuffer!=NULL)		  clEnv->library->clReleaseMemObject(inputImageBuffer);
2997  if (tempImageBuffer!=NULL)		  clEnv->library->clReleaseMemObject(tempImageBuffer);
2998  if (filteredImageBuffer!=NULL)	  clEnv->library->clReleaseMemObject(filteredImageBuffer);
2999  if (cubicCoefficientsBuffer!=NULL)      clEnv->library->clReleaseMemObject(cubicCoefficientsBuffer);
3000  if (queue != NULL)  	                  RelinquishOpenCLCommandQueue(clEnv, queue);
3001  if (outputReady == MagickFalse)
3002  {
3003    if (filteredImage != NULL)
3004    {
3005      DestroyImage(filteredImage);
3006      filteredImage = NULL;
3007    }
3008  }
3009
3010  return filteredImage;
3011}
3012
3013const ResizeWeightingFunctionType supportedResizeWeighting[] =
3014{
3015  BoxWeightingFunction
3016  ,TriangleWeightingFunction
3017  ,HanningWeightingFunction
3018  ,HammingWeightingFunction
3019  ,BlackmanWeightingFunction
3020  ,CubicBCWeightingFunction
3021  ,SincWeightingFunction
3022  ,SincFastWeightingFunction
3023  ,LastWeightingFunction
3024};
3025
3026static MagickBooleanType gpuSupportedResizeWeighting(ResizeWeightingFunctionType f)
3027{
3028  MagickBooleanType supported = MagickFalse;
3029  unsigned int i;
3030  for (i = 0; ;i++)
3031  {
3032    if (supportedResizeWeighting[i] == LastWeightingFunction)
3033      break;
3034    if (supportedResizeWeighting[i] == f)
3035    {
3036      supported = MagickTrue;
3037      break;
3038    }
3039  }
3040  return supported;
3041}
3042
3043
3044/*
3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046%                                                                             %
3047%                                                                             %
3048%                                                                             %
3049%   A c c e l e r a t e R e s i z e I m a g e                                 %
3050%                                                                             %
3051%                                                                             %
3052%                                                                             %
3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054%
3055%  AccelerateResizeImage() is an OpenCL implementation of ResizeImage()
3056%
3057%  AccelerateResizeImage() scales an image to the desired dimensions, using the given
3058%  filter (see AcquireFilterInfo()).
3059%
3060%  If an undefined filter is given the filter defaults to Mitchell for a
3061%  colormapped image, a image with a matte channel, or if the image is
3062%  enlarged.  Otherwise the filter defaults to a Lanczos.
3063%
3064%  AccelerateResizeImage() was inspired by Paul Heckbert's "zoom" program.
3065%
3066%  The format of the AccelerateResizeImage method is:
3067%
3068%      Image *ResizeImage(Image *image,const size_t columns,
3069%        const size_t rows, const ResizeFilter* filter,
3070%        ExceptionInfo *exception)
3071%
3072%  A description of each parameter follows:
3073%
3074%    o image: the image.
3075%
3076%    o columns: the number of columns in the scaled image.
3077%
3078%    o rows: the number of rows in the scaled image.
3079%
3080%    o filter: Image filter to use.
3081%
3082%    o exception: return any errors or warnings in this structure.
3083%
3084*/
3085
3086MagickExport
3087Image* AccelerateResizeImage(const Image* image, const size_t resizedColumns, const size_t resizedRows
3088          , const ResizeFilter* resizeFilter, ExceptionInfo *exception)
3089{
3090  MagickBooleanType status;
3091  Image* filteredImage;
3092
3093  assert(image != NULL);
3094  assert(resizeFilter != NULL);
3095
3096  status = checkOpenCLEnvironment(exception);
3097  if (status == MagickFalse)
3098    return NULL;
3099
3100  status = checkAccelerateCondition(image, AllChannels);
3101  if (status == MagickFalse)
3102    return NULL;
3103
3104  if (gpuSupportedResizeWeighting(GetResizeFilterWeightingType(resizeFilter)) == MagickFalse
3105    || gpuSupportedResizeWeighting(GetResizeFilterWindowWeightingType(resizeFilter)) == MagickFalse)
3106    return NULL;
3107
3108  filteredImage = ComputeResizeImage(image,resizedColumns,resizedRows,resizeFilter,exception);
3109  return filteredImage;
3110
3111}
3112
3113
3114static MagickBooleanType ComputeContrastImage(Image *inputImage, const MagickBooleanType sharpen, ExceptionInfo *exception)
3115{
3116  MagickBooleanType outputReady = MagickFalse;
3117  MagickCLEnv clEnv = NULL;
3118
3119  cl_int clStatus;
3120  size_t global_work_size[2];
3121
3122  void *inputPixels = NULL;
3123  MagickSizeType length;
3124  unsigned int uSharpen;
3125  unsigned int i;
3126
3127  cl_mem_flags mem_flags;
3128  cl_context context = NULL;
3129  cl_mem inputImageBuffer = NULL;
3130  cl_kernel filterKernel = NULL;
3131  cl_command_queue queue = NULL;
3132
3133  clEnv = GetDefaultOpenCLEnv();
3134  context = GetOpenCLContext(clEnv);
3135
3136  /* Create and initialize OpenCL buffers. */
3137  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3138  if (inputPixels == (void *) NULL)
3139  {
3140    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
3141    goto cleanup;
3142  }
3143
3144  /* If the host pointer is aligned to the size of CLPixelPacket,
3145     then use the host buffer directly from the GPU; otherwise,
3146     create a buffer on the GPU and copy the data over */
3147  if (ALIGNED(inputPixels,CLPixelPacket))
3148  {
3149    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3150  }
3151  else
3152  {
3153    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3154  }
3155  /* create a CL buffer from image pixel buffer */
3156  length = inputImage->columns * inputImage->rows;
3157  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3158  if (clStatus != CL_SUCCESS)
3159  {
3160    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3161    goto cleanup;
3162  }
3163
3164  filterKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Contrast");
3165  if (filterKernel == NULL)
3166  {
3167    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3168    goto cleanup;
3169  }
3170
3171  i = 0;
3172  clStatus=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3173
3174  uSharpen = (sharpen == MagickFalse)?0:1;
3175  clStatus|=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_uint),&uSharpen);
3176  if (clStatus != CL_SUCCESS)
3177  {
3178    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3179    goto cleanup;
3180  }
3181
3182  global_work_size[0] = inputImage->columns;
3183  global_work_size[1] = inputImage->rows;
3184  /* launch the kernel */
3185  queue = AcquireOpenCLCommandQueue(clEnv);
3186  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, filterKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3187  if (clStatus != CL_SUCCESS)
3188  {
3189    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3190    goto cleanup;
3191  }
3192  clEnv->library->clFlush(queue);
3193
3194  if (ALIGNED(inputPixels,CLPixelPacket))
3195  {
3196    length = inputImage->columns * inputImage->rows;
3197    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3198  }
3199  else
3200  {
3201    length = inputImage->columns * inputImage->rows;
3202    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3203  }
3204  if (clStatus != CL_SUCCESS)
3205  {
3206    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3207    goto cleanup;
3208  }
3209  outputReady = MagickTrue;
3210
3211cleanup:
3212  OpenCLLogException(__FUNCTION__,__LINE__,exception);
3213
3214  if (inputImageBuffer!=NULL)		      clEnv->library->clReleaseMemObject(inputImageBuffer);
3215  if (filterKernel!=NULL)                     RelinquishOpenCLKernel(clEnv, filterKernel);
3216  if (queue != NULL)                          RelinquishOpenCLCommandQueue(clEnv, queue);
3217  return outputReady;
3218}
3219
3220/*
3221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3222%                                                                             %
3223%                                                                             %
3224%                                                                             %
3225%     C o n t r a s t I m a g e  w i t h  O p e n C L                         %
3226%                                                                             %
3227%                                                                             %
3228%                                                                             %
3229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3230%
3231%  ContrastImage() enhances the intensity differences between the lighter and
3232%  darker elements of the image.  Set sharpen to a MagickTrue to increase the
3233%  image contrast otherwise the contrast is reduced.
3234%
3235%  The format of the ContrastImage method is:
3236%
3237%      MagickBooleanType ContrastImage(Image *image,
3238%        const MagickBooleanType sharpen)
3239%
3240%  A description of each parameter follows:
3241%
3242%    o image: the image.
3243%
3244%    o sharpen: Increase or decrease image contrast.
3245%
3246*/
3247
3248MagickExport
3249MagickBooleanType AccelerateContrastImage(Image* image, const MagickBooleanType sharpen, ExceptionInfo* exception)
3250{
3251  MagickBooleanType status;
3252
3253  assert(image != NULL);
3254  assert(exception != NULL);
3255
3256  status = checkOpenCLEnvironment(exception);
3257  if (status == MagickFalse)
3258    return MagickFalse;
3259
3260  status = checkAccelerateCondition(image, AllChannels);
3261  if (status == MagickFalse)
3262    return MagickFalse;
3263
3264  status = ComputeContrastImage(image,sharpen,exception);
3265  return status;
3266}
3267
3268
3269
3270MagickBooleanType ComputeModulateImage(Image* image, double percent_brightness, double percent_hue, double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
3271{
3272  register ssize_t
3273    i;
3274
3275  cl_float
3276    bright,
3277    hue,
3278    saturation;
3279
3280  cl_int color;
3281
3282  MagickBooleanType outputReady;
3283
3284  MagickCLEnv clEnv;
3285
3286  void *inputPixels;
3287
3288  MagickSizeType length;
3289
3290  cl_context context;
3291  cl_command_queue queue;
3292  cl_kernel modulateKernel;
3293
3294  cl_mem inputImageBuffer;
3295  cl_mem_flags mem_flags;
3296
3297  cl_int clStatus;
3298
3299  Image * inputImage = image;
3300
3301  inputPixels = NULL;
3302  inputImageBuffer = NULL;
3303  modulateKernel = NULL;
3304
3305  assert(inputImage != (Image *) NULL);
3306  assert(inputImage->signature == MagickSignature);
3307  if (inputImage->debug != MagickFalse)
3308    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
3309
3310  /*
3311   * initialize opencl env
3312   */
3313  clEnv = GetDefaultOpenCLEnv();
3314  context = GetOpenCLContext(clEnv);
3315  queue = AcquireOpenCLCommandQueue(clEnv);
3316
3317  outputReady = MagickFalse;
3318
3319  /* Create and initialize OpenCL buffers.
3320   inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
3321   assume this  will get a writable image
3322   */
3323  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3324  if (inputPixels == (void *) NULL)
3325  {
3326    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
3327    goto cleanup;
3328  }
3329
3330  /* If the host pointer is aligned to the size of CLPixelPacket,
3331   then use the host buffer directly from the GPU; otherwise,
3332   create a buffer on the GPU and copy the data over
3333   */
3334  if (ALIGNED(inputPixels,CLPixelPacket))
3335  {
3336    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3337  }
3338  else
3339  {
3340    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3341  }
3342  /* create a CL buffer from image pixel buffer */
3343  length = inputImage->columns * inputImage->rows;
3344  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3345  if (clStatus != CL_SUCCESS)
3346  {
3347    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3348    goto cleanup;
3349  }
3350
3351  modulateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Modulate");
3352  if (modulateKernel == NULL)
3353  {
3354    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3355    goto cleanup;
3356  }
3357
3358  bright=percent_brightness;
3359  hue=percent_hue;
3360  saturation=percent_saturation;
3361  color=colorspace;
3362
3363  i = 0;
3364  clStatus=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3365  clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&bright);
3366  clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&hue);
3367  clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&saturation);
3368  clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&color);
3369  if (clStatus != CL_SUCCESS)
3370  {
3371    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3372    printf("no kernel\n");
3373    goto cleanup;
3374  }
3375
3376  {
3377    size_t global_work_size[2];
3378    global_work_size[0] = inputImage->columns;
3379    global_work_size[1] = inputImage->rows;
3380    /* launch the kernel */
3381    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, modulateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3382    if (clStatus != CL_SUCCESS)
3383    {
3384      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3385      goto cleanup;
3386    }
3387    clEnv->library->clFlush(queue);
3388  }
3389
3390  if (ALIGNED(inputPixels,CLPixelPacket))
3391  {
3392    length = inputImage->columns * inputImage->rows;
3393    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3394  }
3395  else
3396  {
3397    length = inputImage->columns * inputImage->rows;
3398    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3399  }
3400  if (clStatus != CL_SUCCESS)
3401  {
3402    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3403    goto cleanup;
3404  }
3405
3406  outputReady = MagickTrue;
3407
3408cleanup:
3409  OpenCLLogException(__FUNCTION__,__LINE__,exception);
3410
3411  if (inputPixels) {
3412    //ReleasePixelCachePixels();
3413    inputPixels = NULL;
3414  }
3415
3416  if (inputImageBuffer!=NULL)
3417    clEnv->library->clReleaseMemObject(inputImageBuffer);
3418  if (modulateKernel!=NULL)
3419    RelinquishOpenCLKernel(clEnv, modulateKernel);
3420  if (queue != NULL)
3421    RelinquishOpenCLCommandQueue(clEnv, queue);
3422
3423  return outputReady;
3424
3425}
3426
3427/*
3428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3429%                                                                             %
3430%                                                                             %
3431%                                                                             %
3432%     M o d u l a t e I m a g e  w i t h  O p e n C L                         %
3433%                                                                             %
3434%                                                                             %
3435%                                                                             %
3436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3437%
3438%  ModulateImage() lets you control the brightness, saturation, and hue
3439%  of an image.  Modulate represents the brightness, saturation, and hue
3440%  as one parameter (e.g. 90,150,100).  If the image colorspace is HSL, the
3441%  modulation is lightness, saturation, and hue.  For HWB, use blackness,
3442%  whiteness, and hue. And for HCL, use chrome, luma, and hue.
3443%
3444%  The format of the ModulateImage method is:
3445%
3446%      MagickBooleanType ModulateImage(Image *image,const char *modulate)
3447%
3448%  A description of each parameter follows:
3449%
3450%    o image: the image.
3451%
3452%    o percent_*: Define the percent change in brightness, saturation, and
3453%      hue.
3454%
3455*/
3456
3457MagickExport
3458MagickBooleanType AccelerateModulateImage(Image* image, double percent_brightness, double percent_hue, double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
3459{
3460  MagickBooleanType status;
3461
3462  assert(image != NULL);
3463  assert(exception != NULL);
3464
3465  status = checkOpenCLEnvironment(exception);
3466  if (status == MagickFalse)
3467    return MagickFalse;
3468
3469  status = checkAccelerateCondition(image, AllChannels);
3470  if (status == MagickFalse)
3471    return MagickFalse;
3472
3473  if ((colorspace != HSLColorspace && colorspace != UndefinedColorspace))
3474    return MagickFalse;
3475
3476
3477  status = ComputeModulateImage(image,percent_brightness, percent_hue, percent_saturation, colorspace, exception);
3478  return status;
3479}
3480
3481MagickBooleanType ComputeNegateImageChannel(Image* image, const ChannelType channel, const MagickBooleanType magick_unused(grayscale), ExceptionInfo* exception)
3482{
3483  register ssize_t
3484    i;
3485
3486  MagickBooleanType outputReady;
3487
3488  MagickCLEnv clEnv;
3489
3490  void *inputPixels;
3491
3492  MagickSizeType length;
3493
3494  cl_context context;
3495  cl_command_queue queue;
3496  cl_kernel negateKernel;
3497
3498  cl_mem inputImageBuffer;
3499  cl_mem_flags mem_flags;
3500
3501  cl_int clStatus;
3502
3503  Image * inputImage = image;
3504
3505  magick_unreferenced(grayscale);
3506
3507  inputPixels = NULL;
3508  inputImageBuffer = NULL;
3509  negateKernel = NULL;
3510
3511  assert(inputImage != (Image *) NULL);
3512  assert(inputImage->signature == MagickSignature);
3513  if (inputImage->debug != MagickFalse)
3514    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
3515
3516  /*
3517   * initialize opencl env
3518   */
3519  clEnv = GetDefaultOpenCLEnv();
3520  context = GetOpenCLContext(clEnv);
3521  queue = AcquireOpenCLCommandQueue(clEnv);
3522
3523  outputReady = MagickFalse;
3524
3525  /* Create and initialize OpenCL buffers.
3526   inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
3527   assume this  will get a writable image
3528   */
3529  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3530  if (inputPixels == (void *) NULL)
3531  {
3532    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
3533    goto cleanup;
3534  }
3535
3536  /* If the host pointer is aligned to the size of CLPixelPacket,
3537   then use the host buffer directly from the GPU; otherwise,
3538   create a buffer on the GPU and copy the data over
3539   */
3540  if (ALIGNED(inputPixels,CLPixelPacket))
3541  {
3542    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3543  }
3544  else
3545  {
3546    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3547  }
3548  /* create a CL buffer from image pixel buffer */
3549  length = inputImage->columns * inputImage->rows;
3550  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3551  if (clStatus != CL_SUCCESS)
3552  {
3553    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3554    goto cleanup;
3555  }
3556
3557  negateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Negate");
3558  if (negateKernel == NULL)
3559  {
3560    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3561    goto cleanup;
3562  }
3563
3564  i = 0;
3565  clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3566  clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(ChannelType),(void *)&channel);
3567  if (clStatus != CL_SUCCESS)
3568  {
3569    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3570    printf("no kernel\n");
3571    goto cleanup;
3572  }
3573
3574  {
3575    size_t global_work_size[2];
3576    global_work_size[0] = inputImage->columns;
3577    global_work_size[1] = inputImage->rows;
3578    /* launch the kernel */
3579    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, negateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3580    if (clStatus != CL_SUCCESS)
3581    {
3582      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3583      goto cleanup;
3584    }
3585    clEnv->library->clFlush(queue);
3586  }
3587
3588  if (ALIGNED(inputPixels,CLPixelPacket))
3589  {
3590    length = inputImage->columns * inputImage->rows;
3591    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3592  }
3593  else
3594  {
3595    length = inputImage->columns * inputImage->rows;
3596    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3597  }
3598  if (clStatus != CL_SUCCESS)
3599  {
3600    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3601    goto cleanup;
3602  }
3603
3604  outputReady = MagickTrue;
3605
3606cleanup:
3607  OpenCLLogException(__FUNCTION__,__LINE__,exception);
3608
3609  if (inputPixels) {
3610    //ReleasePixelCachePixels();
3611    inputPixels = NULL;
3612  }
3613
3614  if (inputImageBuffer!=NULL)
3615    clEnv->library->clReleaseMemObject(inputImageBuffer);
3616  if (negateKernel!=NULL)
3617    RelinquishOpenCLKernel(clEnv, negateKernel);
3618  if (queue != NULL)
3619    RelinquishOpenCLCommandQueue(clEnv, queue);
3620
3621  return outputReady;
3622
3623}
3624
3625
3626/*
3627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3628%                                                                             %
3629%                                                                             %
3630%                                                                             %
3631%     N e g a t e I m a g e  w i t h  O p e n C L                             %
3632%                                                                             %
3633%                                                                             %
3634%                                                                             %
3635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3636%
3637%
3638%  A description of each parameter follows:
3639%
3640%    o image: the image.
3641%
3642%    o channel: the channel.
3643%
3644%    o grayscale: If MagickTrue, only negate grayscale pixels within the image.
3645%
3646*/
3647
3648MagickExport
3649MagickBooleanType AccelerateNegateImageChannel(Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception)
3650{
3651  MagickBooleanType status;
3652
3653  assert(image != NULL);
3654  assert(exception != NULL);
3655
3656  status = checkOpenCLEnvironment(exception);
3657  if (status == MagickFalse)
3658    return MagickFalse;
3659
3660  status = checkAccelerateCondition(image, AllChannels);
3661  if (status == MagickFalse)
3662    return MagickFalse;
3663
3664  status = ComputeNegateImageChannel(image,channel,grayscale,exception);
3665
3666  return status;
3667}
3668
3669
3670MagickBooleanType ComputeGrayscaleImage(Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
3671{
3672  register ssize_t
3673    i;
3674
3675  cl_int intensityMethod;
3676  cl_int colorspace;
3677
3678  MagickBooleanType outputReady;
3679
3680  MagickCLEnv clEnv;
3681
3682  void *inputPixels;
3683
3684  MagickSizeType length;
3685
3686  cl_context context;
3687  cl_command_queue queue;
3688  cl_kernel grayscaleKernel;
3689
3690  cl_mem inputImageBuffer;
3691  cl_mem_flags mem_flags;
3692
3693  cl_int clStatus;
3694
3695  Image * inputImage = image;
3696
3697  inputPixels = NULL;
3698  inputImageBuffer = NULL;
3699  grayscaleKernel = NULL;
3700
3701  assert(inputImage != (Image *) NULL);
3702  assert(inputImage->signature == MagickSignature);
3703  if (inputImage->debug != MagickFalse)
3704    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
3705
3706  /*
3707   * initialize opencl env
3708   */
3709  clEnv = GetDefaultOpenCLEnv();
3710  context = GetOpenCLContext(clEnv);
3711  queue = AcquireOpenCLCommandQueue(clEnv);
3712
3713  outputReady = MagickFalse;
3714
3715  /* Create and initialize OpenCL buffers.
3716   inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
3717   assume this  will get a writable image
3718   */
3719  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
3720  if (inputPixels == (void *) NULL)
3721  {
3722    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
3723    goto cleanup;
3724  }
3725
3726  /* If the host pointer is aligned to the size of CLPixelPacket,
3727   then use the host buffer directly from the GPU; otherwise,
3728   create a buffer on the GPU and copy the data over
3729   */
3730  if (ALIGNED(inputPixels,CLPixelPacket))
3731  {
3732    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3733  }
3734  else
3735  {
3736    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3737  }
3738  /* create a CL buffer from image pixel buffer */
3739  length = inputImage->columns * inputImage->rows;
3740  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3741  if (clStatus != CL_SUCCESS)
3742  {
3743    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3744    goto cleanup;
3745  }
3746
3747  intensityMethod = method;
3748  colorspace = image->colorspace;
3749
3750  grayscaleKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Grayscale");
3751  if (grayscaleKernel == NULL)
3752  {
3753    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3754    goto cleanup;
3755  }
3756
3757  i = 0;
3758  clStatus=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3759  clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&intensityMethod);
3760  clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&colorspace);
3761  if (clStatus != CL_SUCCESS)
3762  {
3763    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3764    printf("no kernel\n");
3765    goto cleanup;
3766  }
3767
3768  {
3769    size_t global_work_size[2];
3770    global_work_size[0] = inputImage->columns;
3771    global_work_size[1] = inputImage->rows;
3772    /* launch the kernel */
3773    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, grayscaleKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3774    if (clStatus != CL_SUCCESS)
3775    {
3776      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3777      goto cleanup;
3778    }
3779    clEnv->library->clFlush(queue);
3780  }
3781
3782  if (ALIGNED(inputPixels,CLPixelPacket))
3783  {
3784    length = inputImage->columns * inputImage->rows;
3785    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3786  }
3787  else
3788  {
3789    length = inputImage->columns * inputImage->rows;
3790    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3791  }
3792  if (clStatus != CL_SUCCESS)
3793  {
3794    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3795    goto cleanup;
3796  }
3797
3798  outputReady = MagickTrue;
3799
3800cleanup:
3801  OpenCLLogException(__FUNCTION__,__LINE__,exception);
3802
3803  if (inputPixels) {
3804    //ReleasePixelCachePixels();
3805    inputPixels = NULL;
3806  }
3807
3808  if (inputImageBuffer!=NULL)
3809    clEnv->library->clReleaseMemObject(inputImageBuffer);
3810  if (grayscaleKernel!=NULL)
3811    RelinquishOpenCLKernel(clEnv, grayscaleKernel);
3812  if (queue != NULL)
3813    RelinquishOpenCLCommandQueue(clEnv, queue);
3814
3815  return outputReady;
3816
3817}
3818/*
3819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3820%                                                                             %
3821%                                                                             %
3822%                                                                             %
3823%     G r a y s c a l e I m a g e  w i t h  O p e n C L                       %
3824%                                                                             %
3825%                                                                             %
3826%                                                                             %
3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3828%
3829%  GrayscaleImage() converts the colors in the reference image to gray.
3830%
3831%  The format of the GrayscaleImageChannel method is:
3832%
3833%      MagickBooleanType GrayscaleImage(Image *image,
3834%        const PixelIntensityMethod method)
3835%
3836%  A description of each parameter follows:
3837%
3838%    o image: the image.
3839%
3840%    o channel: the channel.
3841%
3842*/
3843
3844MagickExport
3845MagickBooleanType AccelerateGrayscaleImage(Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
3846{
3847  MagickBooleanType status;
3848
3849  assert(image != NULL);
3850  assert(exception != NULL);
3851
3852  status = checkOpenCLEnvironment(exception);
3853  if (status == MagickFalse)
3854    return MagickFalse;
3855
3856  status = checkAccelerateCondition(image, AllChannels);
3857  if (status == MagickFalse)
3858    return MagickFalse;
3859
3860  if (method == Rec601LuminancePixelIntensityMethod || method == Rec709LuminancePixelIntensityMethod)
3861    return MagickFalse;
3862
3863  if (image->colorspace != sRGBColorspace)
3864    return MagickFalse;
3865
3866  status = ComputeGrayscaleImage(image,method,exception);
3867
3868  return status;
3869}
3870
3871static MagickBooleanType LaunchHistogramKernel(MagickCLEnv clEnv,
3872                                              cl_command_queue queue,
3873                                              cl_mem inputImageBuffer,
3874                                              cl_mem histogramBuffer,
3875                                              Image *inputImage,
3876                                              const ChannelType channel,
3877                                              ExceptionInfo * _exception)
3878{
3879  ExceptionInfo
3880    *exception=_exception;
3881
3882  register ssize_t
3883    i;
3884
3885  MagickBooleanType outputReady;
3886
3887  cl_int clStatus;
3888
3889  size_t global_work_size[2];
3890
3891  cl_kernel histogramKernel;
3892
3893  cl_int method;
3894  cl_int colorspace;
3895
3896  histogramKernel = NULL;
3897
3898  outputReady = MagickFalse;
3899  method = inputImage->intensity;
3900  colorspace = inputImage->colorspace;
3901
3902  /* get the OpenCL kernel */
3903  histogramKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Histogram");
3904  if (histogramKernel == NULL)
3905  {
3906    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3907    goto cleanup;
3908  }
3909
3910  /* set the kernel arguments */
3911  i = 0;
3912  clStatus=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
3913  clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(ChannelType),&channel);
3914  clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&method);
3915  clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&colorspace);
3916  clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&histogramBuffer);
3917  if (clStatus != CL_SUCCESS)
3918  {
3919    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3920    goto cleanup;
3921  }
3922
3923  /* launch the kernel */
3924  global_work_size[0] = inputImage->columns;
3925  global_work_size[1] = inputImage->rows;
3926
3927  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, histogramKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3928
3929  if (clStatus != CL_SUCCESS)
3930  {
3931    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3932    goto cleanup;
3933  }
3934  clEnv->library->clFlush(queue);
3935
3936  outputReady = MagickTrue;
3937
3938cleanup:
3939  OpenCLLogException(__FUNCTION__,__LINE__,exception);
3940
3941  if (histogramKernel!=NULL)
3942    RelinquishOpenCLKernel(clEnv, histogramKernel);
3943
3944  return outputReady;
3945}
3946
3947
3948MagickExport MagickBooleanType ComputeEqualizeImage(Image *inputImage, const ChannelType channel, ExceptionInfo * _exception)
3949{
3950#define EqualizeImageTag  "Equalize/Image"
3951
3952  ExceptionInfo
3953    *exception=_exception;
3954
3955  FloatPixelPacket
3956    white,
3957    black,
3958    intensity,
3959    *map=NULL;
3960
3961  cl_uint4
3962    *histogram=NULL;
3963
3964  PixelPacket
3965    *equalize_map=NULL;
3966
3967  register ssize_t
3968    i;
3969
3970  Image * image = inputImage;
3971
3972  MagickBooleanType outputReady;
3973
3974  MagickCLEnv clEnv;
3975
3976  cl_int clStatus;
3977  MagickBooleanType status;
3978
3979  size_t global_work_size[2];
3980
3981  void *inputPixels;
3982  cl_mem_flags mem_flags;
3983
3984  cl_context context;
3985  cl_mem inputImageBuffer;
3986  cl_mem histogramBuffer;
3987  cl_mem equalizeMapBuffer;
3988  cl_kernel histogramKernel;
3989  cl_kernel equalizeKernel;
3990  cl_command_queue queue;
3991
3992  void* hostPtr;
3993
3994  MagickSizeType length;
3995
3996  inputPixels = NULL;
3997  inputImageBuffer = NULL;
3998  histogramBuffer = NULL;
3999  equalizeMapBuffer = NULL;
4000  histogramKernel = NULL;
4001  equalizeKernel = NULL;
4002  context = NULL;
4003  queue = NULL;
4004  outputReady = MagickFalse;
4005
4006  assert(inputImage != (Image *) NULL);
4007  assert(inputImage->signature == MagickSignature);
4008  if (inputImage->debug != MagickFalse)
4009    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename);
4010
4011  /*
4012   * initialize opencl env
4013   */
4014  clEnv = GetDefaultOpenCLEnv();
4015  context = GetOpenCLContext(clEnv);
4016  queue = AcquireOpenCLCommandQueue(clEnv);
4017
4018  /*
4019    Allocate and initialize histogram arrays.
4020  */
4021  histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
4022  if (histogram == (cl_uint4 *) NULL)
4023      ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
4024
4025  /* reset histogram */
4026  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
4027
4028  /* Create and initialize OpenCL buffers. */
4029  /* inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); */
4030  /* assume this  will get a writable image */
4031  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
4032
4033  if (inputPixels == (void *) NULL)
4034  {
4035    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
4036    goto cleanup;
4037  }
4038  /* If the host pointer is aligned to the size of CLPixelPacket,
4039     then use the host buffer directly from the GPU; otherwise,
4040     create a buffer on the GPU and copy the data over */
4041  if (ALIGNED(inputPixels,CLPixelPacket))
4042  {
4043    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4044  }
4045  else
4046  {
4047    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
4048  }
4049  /* create a CL buffer from image pixel buffer */
4050  length = inputImage->columns * inputImage->rows;
4051  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4052  if (clStatus != CL_SUCCESS)
4053  {
4054    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4055    goto cleanup;
4056  }
4057
4058  /* If the host pointer is aligned to the size of cl_uint,
4059     then use the host buffer directly from the GPU; otherwise,
4060     create a buffer on the GPU and copy the data over */
4061  if (ALIGNED(histogram,cl_uint4))
4062  {
4063    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4064    hostPtr = histogram;
4065  }
4066  else
4067  {
4068    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4069    hostPtr = histogram;
4070  }
4071  /* create a CL buffer for histogram  */
4072  length = (MaxMap+1);
4073  histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
4074  if (clStatus != CL_SUCCESS)
4075  {
4076    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4077    goto cleanup;
4078  }
4079
4080  status = LaunchHistogramKernel(clEnv, queue, inputImageBuffer, histogramBuffer, image, channel, exception);
4081  if (status == MagickFalse)
4082    goto cleanup;
4083
4084  /* read from the kenel output */
4085  if (ALIGNED(histogram,cl_uint4))
4086  {
4087    length = (MaxMap+1);
4088    clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
4089  }
4090  else
4091  {
4092    length = (MaxMap+1);
4093    clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
4094  }
4095  if (clStatus != CL_SUCCESS)
4096  {
4097    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4098    goto cleanup;
4099  }
4100
4101  /* unmap, don't block gpu to use this buffer again.  */
4102  if (ALIGNED(histogram,cl_uint4))
4103  {
4104    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
4105    if (clStatus != CL_SUCCESS)
4106    {
4107      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
4108      goto cleanup;
4109    }
4110  }
4111
4112  /* recreate input buffer later, in case image updated */
4113#ifdef RECREATEBUFFER
4114  if (inputImageBuffer!=NULL)
4115    clEnv->library->clReleaseMemObject(inputImageBuffer);
4116#endif
4117
4118  /* CPU stuff */
4119  equalize_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*equalize_map));
4120  if (equalize_map == (PixelPacket *) NULL)
4121    ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
4122
4123  map=(FloatPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
4124  if (map == (FloatPixelPacket *) NULL)
4125    ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
4126
4127  /*
4128    Integrate the histogram to get the equalization map.
4129  */
4130  (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
4131  for (i=0; i <= (ssize_t) MaxMap; i++)
4132  {
4133    if ((channel & SyncChannels) != 0)
4134    {
4135      intensity.red+=histogram[i].s[2];
4136      map[i]=intensity;
4137      continue;
4138    }
4139    if ((channel & RedChannel) != 0)
4140      intensity.red+=histogram[i].s[2];
4141    if ((channel & GreenChannel) != 0)
4142      intensity.green+=histogram[i].s[1];
4143    if ((channel & BlueChannel) != 0)
4144      intensity.blue+=histogram[i].s[0];
4145    if ((channel & OpacityChannel) != 0)
4146      intensity.opacity+=histogram[i].s[3];
4147    /*
4148    if (((channel & IndexChannel) != 0) &&
4149        (image->colorspace == CMYKColorspace))
4150    {
4151      intensity.index+=histogram[i].index;
4152    }
4153    */
4154    map[i]=intensity;
4155  }
4156  black=map[0];
4157  white=map[(int) MaxMap];
4158  (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map));
4159  for (i=0; i <= (ssize_t) MaxMap; i++)
4160  {
4161    if ((channel & SyncChannels) != 0)
4162    {
4163      if (white.red != black.red)
4164        equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4165                (map[i].red-black.red))/(white.red-black.red)));
4166      continue;
4167    }
4168    if (((channel & RedChannel) != 0) && (white.red != black.red))
4169      equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4170              (map[i].red-black.red))/(white.red-black.red)));
4171    if (((channel & GreenChannel) != 0) && (white.green != black.green))
4172      equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4173              (map[i].green-black.green))/(white.green-black.green)));
4174    if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
4175      equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4176              (map[i].blue-black.blue))/(white.blue-black.blue)));
4177    if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity))
4178      equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4179              (map[i].opacity-black.opacity))/(white.opacity-black.opacity)));
4180    /*
4181    if ((((channel & IndexChannel) != 0) &&
4182          (image->colorspace == CMYKColorspace)) &&
4183        (white.index != black.index))
4184      equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4185              (map[i].index-black.index))/(white.index-black.index)));
4186    */
4187  }
4188
4189  if (image->storage_class == PseudoClass)
4190  {
4191    /*
4192       Equalize colormap.
4193       */
4194    for (i=0; i < (ssize_t) image->colors; i++)
4195    {
4196      if ((channel & SyncChannels) != 0)
4197      {
4198        if (white.red != black.red)
4199        {
4200          image->colormap[i].red=equalize_map[
4201            ScaleQuantumToMap(image->colormap[i].red)].red;
4202          image->colormap[i].green=equalize_map[
4203            ScaleQuantumToMap(image->colormap[i].green)].red;
4204          image->colormap[i].blue=equalize_map[
4205            ScaleQuantumToMap(image->colormap[i].blue)].red;
4206          image->colormap[i].opacity=equalize_map[
4207            ScaleQuantumToMap(image->colormap[i].opacity)].red;
4208        }
4209        continue;
4210      }
4211      if (((channel & RedChannel) != 0) && (white.red != black.red))
4212        image->colormap[i].red=equalize_map[
4213          ScaleQuantumToMap(image->colormap[i].red)].red;
4214      if (((channel & GreenChannel) != 0) && (white.green != black.green))
4215        image->colormap[i].green=equalize_map[
4216          ScaleQuantumToMap(image->colormap[i].green)].green;
4217      if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
4218        image->colormap[i].blue=equalize_map[
4219          ScaleQuantumToMap(image->colormap[i].blue)].blue;
4220      if (((channel & OpacityChannel) != 0) &&
4221          (white.opacity != black.opacity))
4222        image->colormap[i].opacity=equalize_map[
4223          ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
4224    }
4225  }
4226
4227  /*
4228    Equalize image.
4229  */
4230
4231  /* GPU can work on this again, image and equalize map as input
4232    image:        uchar4 (CLPixelPacket)
4233    equalize_map: uchar4 (PixelPacket)
4234    black, white: float4 (FloatPixelPacket) */
4235
4236#ifdef RECREATEBUFFER
4237  /* If the host pointer is aligned to the size of CLPixelPacket,
4238     then use the host buffer directly from the GPU; otherwise,
4239     create a buffer on the GPU and copy the data over */
4240  if (ALIGNED(inputPixels,CLPixelPacket))
4241  {
4242    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4243  }
4244  else
4245  {
4246    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4247  }
4248  /* create a CL buffer from image pixel buffer */
4249  length = inputImage->columns * inputImage->rows;
4250  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4251  if (clStatus != CL_SUCCESS)
4252  {
4253    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4254    goto cleanup;
4255  }
4256#endif
4257
4258  /* Create and initialize OpenCL buffers. */
4259  if (ALIGNED(equalize_map, PixelPacket))
4260  {
4261    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4262    hostPtr = equalize_map;
4263  }
4264  else
4265  {
4266    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4267    hostPtr = equalize_map;
4268  }
4269  /* create a CL buffer for eqaulize_map  */
4270  length = (MaxMap+1);
4271  equalizeMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
4272  if (clStatus != CL_SUCCESS)
4273  {
4274    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4275    goto cleanup;
4276  }
4277
4278  /* get the OpenCL kernel */
4279  equalizeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Equalize");
4280  if (equalizeKernel == NULL)
4281  {
4282    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
4283    goto cleanup;
4284  }
4285
4286  /* set the kernel arguments */
4287  i = 0;
4288  clStatus=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
4289  clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(ChannelType),&channel);
4290  clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&equalizeMapBuffer);
4291  clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&white);
4292  clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&black);
4293  if (clStatus != CL_SUCCESS)
4294  {
4295    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
4296    goto cleanup;
4297  }
4298
4299  /* launch the kernel */
4300  global_work_size[0] = inputImage->columns;
4301  global_work_size[1] = inputImage->rows;
4302
4303  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, equalizeKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
4304
4305  if (clStatus != CL_SUCCESS)
4306  {
4307    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
4308    goto cleanup;
4309  }
4310  clEnv->library->clFlush(queue);
4311
4312  /* read the data back */
4313  if (ALIGNED(inputPixels,CLPixelPacket))
4314  {
4315    length = inputImage->columns * inputImage->rows;
4316    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
4317  }
4318  else
4319  {
4320    length = inputImage->columns * inputImage->rows;
4321    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
4322  }
4323  if (clStatus != CL_SUCCESS)
4324  {
4325    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4326    goto cleanup;
4327  }
4328
4329  outputReady = MagickTrue;
4330
4331cleanup:
4332  OpenCLLogException(__FUNCTION__,__LINE__,exception);
4333
4334  if (inputPixels) {
4335    /*ReleasePixelCachePixels();*/
4336    inputPixels = NULL;
4337  }
4338
4339  if (inputImageBuffer!=NULL)
4340    clEnv->library->clReleaseMemObject(inputImageBuffer);
4341
4342  if (map!=NULL)
4343    map=(FloatPixelPacket *) RelinquishMagickMemory(map);
4344
4345  if (equalizeMapBuffer!=NULL)
4346    clEnv->library->clReleaseMemObject(equalizeMapBuffer);
4347  if (equalize_map!=NULL)
4348    equalize_map=(PixelPacket *) RelinquishMagickMemory(equalize_map);
4349
4350  if (histogramBuffer!=NULL)
4351    clEnv->library->clReleaseMemObject(histogramBuffer);
4352  if (histogram!=NULL)
4353    histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
4354
4355  if (histogramKernel!=NULL)
4356    RelinquishOpenCLKernel(clEnv, histogramKernel);
4357  if (equalizeKernel!=NULL)
4358    RelinquishOpenCLKernel(clEnv, equalizeKernel);
4359
4360  if (queue != NULL)
4361    RelinquishOpenCLCommandQueue(clEnv, queue);
4362
4363  return outputReady;
4364}
4365
4366/*
4367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4368%                                                                             %
4369%                                                                             %
4370%                                                                             %
4371%     E q u a l i z e I m a g e  w i t h  O p e n C L                         %
4372%                                                                             %
4373%                                                                             %
4374%                                                                             %
4375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4376%
4377%  EqualizeImage() applies a histogram equalization to the image.
4378%
4379%  The format of the EqualizeImage method is:
4380%
4381%      MagickBooleanType EqualizeImage(Image *image)
4382%      MagickBooleanType EqualizeImageChannel(Image *image,
4383%        const ChannelType channel)
4384%
4385%  A description of each parameter follows:
4386%
4387%    o image: the image.
4388%
4389%    o channel: the channel.
4390%
4391*/
4392
4393
4394MagickExport
4395MagickBooleanType AccelerateEqualizeImage(Image* image, const ChannelType channel, ExceptionInfo* exception)
4396{
4397  MagickBooleanType status;
4398
4399  assert(image != NULL);
4400  assert(exception != NULL);
4401
4402  status = checkOpenCLEnvironment(exception);
4403  if (status == MagickFalse)
4404    return MagickFalse;
4405
4406  status = checkAccelerateCondition(image, channel);
4407  if (status == MagickFalse)
4408    return MagickFalse;
4409
4410  status = checkHistogramCondition(image, channel);
4411  if (status == MagickFalse)
4412    return MagickFalse;
4413
4414  status = ComputeEqualizeImage(image,channel,exception);
4415  return status;
4416}
4417
4418
4419
4420MagickExport MagickBooleanType ComputeContrastStretchImageChannel(Image *image,
4421  const ChannelType channel,const double black_point,const double white_point,
4422  ExceptionInfo * _exception)
4423{
4424#define MaxRange(color)  ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
4425#define ContrastStretchImageTag  "ContrastStretch/Image"
4426
4427  ExceptionInfo
4428    *exception=_exception;
4429
4430  double
4431    intensity;
4432
4433  FloatPixelPacket
4434    black,
4435    white;
4436
4437  cl_uint4
4438    *histogram=NULL;
4439
4440  PixelPacket
4441    *stretch_map=NULL;
4442
4443  register ssize_t
4444    i;
4445
4446  Image * inputImage;
4447
4448  MagickBooleanType outputReady;
4449
4450  MagickCLEnv clEnv;
4451
4452  cl_int clStatus;
4453  MagickBooleanType status;
4454
4455  size_t global_work_size[2];
4456
4457  void *inputPixels;
4458  cl_mem_flags mem_flags;
4459
4460  cl_context context;
4461  cl_mem inputImageBuffer;
4462  cl_mem histogramBuffer;
4463  cl_mem stretchMapBuffer;
4464  cl_kernel histogramKernel;
4465  cl_kernel stretchKernel;
4466  cl_command_queue queue;
4467
4468  void* hostPtr;
4469
4470  MagickSizeType length;
4471
4472  inputImage = image;
4473  inputPixels = NULL;
4474  inputImageBuffer = NULL;
4475  histogramBuffer = NULL;
4476  stretchMapBuffer = NULL;
4477  histogramKernel = NULL;
4478  stretchKernel = NULL;
4479  context = NULL;
4480  queue = NULL;
4481  outputReady = MagickFalse;
4482
4483
4484  assert(image != (Image *) NULL);
4485  assert(image->signature == MagickSignature);
4486  if (image->debug != MagickFalse)
4487    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4488
4489  //exception=(&image->exception);
4490
4491  /*
4492   * initialize opencl env
4493   */
4494  clEnv = GetDefaultOpenCLEnv();
4495  context = GetOpenCLContext(clEnv);
4496  queue = AcquireOpenCLCommandQueue(clEnv);
4497
4498  /*
4499    Allocate and initialize histogram arrays.
4500  */
4501  histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
4502
4503  if ((histogram == (cl_uint4 *) NULL))
4504    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename);
4505
4506  /* reset histogram */
4507  (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
4508
4509  /*
4510  if (IsGrayImage(image,exception) != MagickFalse)
4511    (void) SetImageColorspace(image,GRAYColorspace);
4512  */
4513
4514  status=MagickTrue;
4515
4516
4517  /*
4518    Form histogram.
4519  */
4520  /* Create and initialize OpenCL buffers. */
4521  /* inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); */
4522  /* assume this  will get a writable image */
4523  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
4524
4525  if (inputPixels == (void *) NULL)
4526  {
4527    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
4528    goto cleanup;
4529  }
4530  /* If the host pointer is aligned to the size of CLPixelPacket,
4531     then use the host buffer directly from the GPU; otherwise,
4532     create a buffer on the GPU and copy the data over */
4533  if (ALIGNED(inputPixels,CLPixelPacket))
4534  {
4535    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4536  }
4537  else
4538  {
4539    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
4540  }
4541  /* create a CL buffer from image pixel buffer */
4542  length = inputImage->columns * inputImage->rows;
4543  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4544  if (clStatus != CL_SUCCESS)
4545  {
4546    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4547    goto cleanup;
4548  }
4549
4550  /* If the host pointer is aligned to the size of cl_uint,
4551     then use the host buffer directly from the GPU; otherwise,
4552     create a buffer on the GPU and copy the data over */
4553  if (ALIGNED(histogram,cl_uint4))
4554  {
4555    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4556    hostPtr = histogram;
4557  }
4558  else
4559  {
4560    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4561    hostPtr = histogram;
4562  }
4563  /* create a CL buffer for histogram  */
4564  length = (MaxMap+1);
4565  histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
4566  if (clStatus != CL_SUCCESS)
4567  {
4568    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4569    goto cleanup;
4570  }
4571
4572  status = LaunchHistogramKernel(clEnv, queue, inputImageBuffer, histogramBuffer, image, channel, exception);
4573  if (status == MagickFalse)
4574    goto cleanup;
4575
4576  /* read from the kenel output */
4577  if (ALIGNED(histogram,cl_uint4))
4578  {
4579    length = (MaxMap+1);
4580    clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
4581  }
4582  else
4583  {
4584    length = (MaxMap+1);
4585    clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
4586  }
4587  if (clStatus != CL_SUCCESS)
4588  {
4589    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4590    goto cleanup;
4591  }
4592
4593  /* unmap, don't block gpu to use this buffer again.  */
4594  if (ALIGNED(histogram,cl_uint4))
4595  {
4596    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
4597    if (clStatus != CL_SUCCESS)
4598    {
4599      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
4600      goto cleanup;
4601    }
4602  }
4603
4604  /* recreate input buffer later, in case image updated */
4605#ifdef RECREATEBUFFER
4606  if (inputImageBuffer!=NULL)
4607    clEnv->library->clReleaseMemObject(inputImageBuffer);
4608#endif
4609
4610  /* CPU stuff */
4611  /*
4612     Find the histogram boundaries by locating the black/white levels.
4613  */
4614  black.red=0.0;
4615  white.red=MaxRange(QuantumRange);
4616  if ((channel & RedChannel) != 0)
4617  {
4618    intensity=0.0;
4619    for (i=0; i <= (ssize_t) MaxMap; i++)
4620    {
4621      intensity+=histogram[i].s[2];
4622      if (intensity > black_point)
4623        break;
4624    }
4625    black.red=(MagickRealType) i;
4626    intensity=0.0;
4627    for (i=(ssize_t) MaxMap; i != 0; i--)
4628    {
4629      intensity+=histogram[i].s[2];
4630      if (intensity > ((double) image->columns*image->rows-white_point))
4631        break;
4632    }
4633    white.red=(MagickRealType) i;
4634  }
4635  black.green=0.0;
4636  white.green=MaxRange(QuantumRange);
4637  if ((channel & GreenChannel) != 0)
4638  {
4639    intensity=0.0;
4640    for (i=0; i <= (ssize_t) MaxMap; i++)
4641    {
4642      intensity+=histogram[i].s[2];
4643      if (intensity > black_point)
4644        break;
4645    }
4646    black.green=(MagickRealType) i;
4647    intensity=0.0;
4648    for (i=(ssize_t) MaxMap; i != 0; i--)
4649    {
4650      intensity+=histogram[i].s[2];
4651      if (intensity > ((double) image->columns*image->rows-white_point))
4652        break;
4653    }
4654    white.green=(MagickRealType) i;
4655  }
4656  black.blue=0.0;
4657  white.blue=MaxRange(QuantumRange);
4658  if ((channel & BlueChannel) != 0)
4659  {
4660    intensity=0.0;
4661    for (i=0; i <= (ssize_t) MaxMap; i++)
4662    {
4663      intensity+=histogram[i].s[2];
4664      if (intensity > black_point)
4665        break;
4666    }
4667    black.blue=(MagickRealType) i;
4668    intensity=0.0;
4669    for (i=(ssize_t) MaxMap; i != 0; i--)
4670    {
4671      intensity+=histogram[i].s[2];
4672      if (intensity > ((double) image->columns*image->rows-white_point))
4673        break;
4674    }
4675    white.blue=(MagickRealType) i;
4676  }
4677  black.opacity=0.0;
4678  white.opacity=MaxRange(QuantumRange);
4679  if ((channel & OpacityChannel) != 0)
4680  {
4681    intensity=0.0;
4682    for (i=0; i <= (ssize_t) MaxMap; i++)
4683    {
4684      intensity+=histogram[i].s[2];
4685      if (intensity > black_point)
4686        break;
4687    }
4688    black.opacity=(MagickRealType) i;
4689    intensity=0.0;
4690    for (i=(ssize_t) MaxMap; i != 0; i--)
4691    {
4692      intensity+=histogram[i].s[2];
4693      if (intensity > ((double) image->columns*image->rows-white_point))
4694        break;
4695    }
4696    white.opacity=(MagickRealType) i;
4697  }
4698  /*
4699  black.index=0.0;
4700  white.index=MaxRange(QuantumRange);
4701  if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
4702  {
4703    intensity=0.0;
4704    for (i=0; i <= (ssize_t) MaxMap; i++)
4705    {
4706      intensity+=histogram[i].index;
4707      if (intensity > black_point)
4708        break;
4709    }
4710    black.index=(MagickRealType) i;
4711    intensity=0.0;
4712    for (i=(ssize_t) MaxMap; i != 0; i--)
4713    {
4714      intensity+=histogram[i].index;
4715      if (intensity > ((double) image->columns*image->rows-white_point))
4716        break;
4717    }
4718    white.index=(MagickRealType) i;
4719  }
4720  */
4721
4722
4723  stretch_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
4724    sizeof(*stretch_map));
4725
4726  if ((stretch_map == (PixelPacket *) NULL))
4727    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
4728      image->filename);
4729
4730  /*
4731    Stretch the histogram to create the stretched image mapping.
4732  */
4733  (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map));
4734  for (i=0; i <= (ssize_t) MaxMap; i++)
4735  {
4736    if ((channel & RedChannel) != 0)
4737    {
4738      if (i < (ssize_t) black.red)
4739        stretch_map[i].red=(Quantum) 0;
4740      else
4741        if (i > (ssize_t) white.red)
4742          stretch_map[i].red=QuantumRange;
4743        else
4744          if (black.red != white.red)
4745            stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
4746                  (i-black.red)/(white.red-black.red)));
4747    }
4748    if ((channel & GreenChannel) != 0)
4749    {
4750      if (i < (ssize_t) black.green)
4751        stretch_map[i].green=0;
4752      else
4753        if (i > (ssize_t) white.green)
4754          stretch_map[i].green=QuantumRange;
4755        else
4756          if (black.green != white.green)
4757            stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
4758                  (i-black.green)/(white.green-black.green)));
4759    }
4760    if ((channel & BlueChannel) != 0)
4761    {
4762      if (i < (ssize_t) black.blue)
4763        stretch_map[i].blue=0;
4764      else
4765        if (i > (ssize_t) white.blue)
4766          stretch_map[i].blue= QuantumRange;
4767        else
4768          if (black.blue != white.blue)
4769            stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
4770                  (i-black.blue)/(white.blue-black.blue)));
4771    }
4772    if ((channel & OpacityChannel) != 0)
4773    {
4774      if (i < (ssize_t) black.opacity)
4775        stretch_map[i].opacity=0;
4776      else
4777        if (i > (ssize_t) white.opacity)
4778          stretch_map[i].opacity=QuantumRange;
4779        else
4780          if (black.opacity != white.opacity)
4781            stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap*
4782                  (i-black.opacity)/(white.opacity-black.opacity)));
4783    }
4784    /*
4785    if (((channel & IndexChannel) != 0) &&
4786        (image->colorspace == CMYKColorspace))
4787    {
4788      if (i < (ssize_t) black.index)
4789        stretch_map[i].index=0;
4790      else
4791        if (i > (ssize_t) white.index)
4792          stretch_map[i].index=QuantumRange;
4793        else
4794          if (black.index != white.index)
4795            stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
4796                  (i-black.index)/(white.index-black.index)));
4797    }
4798    */
4799  }
4800
4801  /*
4802    Stretch the image.
4803  */
4804  if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
4805      (image->colorspace == CMYKColorspace)))
4806    image->storage_class=DirectClass;
4807  if (image->storage_class == PseudoClass)
4808  {
4809    /*
4810       Stretch colormap.
4811       */
4812    for (i=0; i < (ssize_t) image->colors; i++)
4813    {
4814      if ((channel & RedChannel) != 0)
4815      {
4816        if (black.red != white.red)
4817          image->colormap[i].red=stretch_map[
4818            ScaleQuantumToMap(image->colormap[i].red)].red;
4819      }
4820      if ((channel & GreenChannel) != 0)
4821      {
4822        if (black.green != white.green)
4823          image->colormap[i].green=stretch_map[
4824            ScaleQuantumToMap(image->colormap[i].green)].green;
4825      }
4826      if ((channel & BlueChannel) != 0)
4827      {
4828        if (black.blue != white.blue)
4829          image->colormap[i].blue=stretch_map[
4830            ScaleQuantumToMap(image->colormap[i].blue)].blue;
4831      }
4832      if ((channel & OpacityChannel) != 0)
4833      {
4834        if (black.opacity != white.opacity)
4835          image->colormap[i].opacity=stretch_map[
4836            ScaleQuantumToMap(image->colormap[i].opacity)].opacity;
4837      }
4838    }
4839  }
4840
4841  /*
4842    Stretch image.
4843  */
4844
4845
4846  /* GPU can work on this again, image and equalize map as input
4847    image:        uchar4 (CLPixelPacket)
4848    stretch_map:  uchar4 (PixelPacket)
4849    black, white: float4 (FloatPixelPacket) */
4850
4851#ifdef RECREATEBUFFER
4852  /* If the host pointer is aligned to the size of CLPixelPacket,
4853     then use the host buffer directly from the GPU; otherwise,
4854     create a buffer on the GPU and copy the data over */
4855  if (ALIGNED(inputPixels,CLPixelPacket))
4856  {
4857    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4858  }
4859  else
4860  {
4861    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4862  }
4863  /* create a CL buffer from image pixel buffer */
4864  length = inputImage->columns * inputImage->rows;
4865  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4866  if (clStatus != CL_SUCCESS)
4867  {
4868    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4869    goto cleanup;
4870  }
4871#endif
4872
4873  /* Create and initialize OpenCL buffers. */
4874  if (ALIGNED(stretch_map, PixelPacket))
4875  {
4876    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4877    hostPtr = stretch_map;
4878  }
4879  else
4880  {
4881    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4882    hostPtr = stretch_map;
4883  }
4884  /* create a CL buffer for stretch_map  */
4885  length = (MaxMap+1);
4886  stretchMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
4887  if (clStatus != CL_SUCCESS)
4888  {
4889    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4890    goto cleanup;
4891  }
4892
4893  /* get the OpenCL kernel */
4894  stretchKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Stretch");
4895  if (stretchKernel == NULL)
4896  {
4897    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
4898    goto cleanup;
4899  }
4900
4901  /* set the kernel arguments */
4902  i = 0;
4903  clStatus=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
4904  clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(ChannelType),&channel);
4905  clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&stretchMapBuffer);
4906  clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&white);
4907  clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&black);
4908  if (clStatus != CL_SUCCESS)
4909  {
4910    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
4911    goto cleanup;
4912  }
4913
4914  /* launch the kernel */
4915  global_work_size[0] = inputImage->columns;
4916  global_work_size[1] = inputImage->rows;
4917
4918  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, stretchKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
4919
4920  if (clStatus != CL_SUCCESS)
4921  {
4922    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
4923    goto cleanup;
4924  }
4925  clEnv->library->clFlush(queue);
4926
4927  /* read the data back */
4928  if (ALIGNED(inputPixels,CLPixelPacket))
4929  {
4930    length = inputImage->columns * inputImage->rows;
4931    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
4932  }
4933  else
4934  {
4935    length = inputImage->columns * inputImage->rows;
4936    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
4937  }
4938  if (clStatus != CL_SUCCESS)
4939  {
4940    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4941    goto cleanup;
4942  }
4943
4944  outputReady = MagickTrue;
4945
4946cleanup:
4947  OpenCLLogException(__FUNCTION__,__LINE__,exception);
4948
4949  if (inputPixels) {
4950    /*ReleasePixelCachePixels();*/
4951    inputPixels = NULL;
4952  }
4953
4954  if (inputImageBuffer!=NULL)
4955    clEnv->library->clReleaseMemObject(inputImageBuffer);
4956
4957  if (stretchMapBuffer!=NULL)
4958    clEnv->library->clReleaseMemObject(stretchMapBuffer);
4959  if (stretch_map!=NULL)
4960    stretch_map=(PixelPacket *) RelinquishMagickMemory(stretch_map);
4961
4962
4963  if (histogramBuffer!=NULL)
4964    clEnv->library->clReleaseMemObject(histogramBuffer);
4965  if (histogram!=NULL)
4966    histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
4967
4968
4969  if (histogramKernel!=NULL)
4970    RelinquishOpenCLKernel(clEnv, histogramKernel);
4971  if (stretchKernel!=NULL)
4972    RelinquishOpenCLKernel(clEnv, stretchKernel);
4973
4974  if (queue != NULL)
4975    RelinquishOpenCLCommandQueue(clEnv, queue);
4976
4977  return outputReady;
4978}
4979
4980
4981/*
4982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4983%                                                                             %
4984%                                                                             %
4985%                                                                             %
4986%     C o n t r a s t S t r e t c h I m a g e  w i t h  O p e n C L           %
4987%                                                                             %
4988%                                                                             %
4989%                                                                             %
4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4991%
4992%  ContrastStretchImage() is a simple image enhancement technique that attempts
4993%  to improve the contrast in an image by `stretching' the range of intensity
4994%  values it contains to span a desired range of values. It differs from the
4995%  more sophisticated histogram equalization in that it can only apply a
4996%  linear scaling function to the image pixel values.  As a result the
4997%  `enhancement' is less harsh.
4998%
4999%  The format of the ContrastStretchImage method is:
5000%
5001%      MagickBooleanType ContrastStretchImage(Image *image,
5002%        const char *levels)
5003%      MagickBooleanType ContrastStretchImageChannel(Image *image,
5004%        const size_t channel,const double black_point,
5005%        const double white_point)
5006%
5007%  A description of each parameter follows:
5008%
5009%    o image: the image.
5010%
5011%    o channel: the channel.
5012%
5013%    o black_point: the black point.
5014%
5015%    o white_point: the white point.
5016%
5017%    o levels: Specify the levels where the black and white points have the
5018%      range of 0 to number-of-pixels (e.g. 1%, 10x90%, etc.).
5019%
5020*/
5021
5022MagickExport MagickBooleanType AccelerateContrastStretchImageChannel(
5023    Image * image, const ChannelType channel, const double black_point, const double white_point,
5024    ExceptionInfo* exception)
5025{
5026   MagickBooleanType status;
5027
5028  assert(image != NULL);
5029  assert(exception != NULL);
5030
5031  status = checkOpenCLEnvironment(exception);
5032  if (status == MagickFalse)
5033    return MagickFalse;
5034
5035  status = checkAccelerateCondition(image, channel);
5036  if (status == MagickFalse)
5037    return MagickFalse;
5038
5039  status = checkHistogramCondition(image, channel);
5040  if (status == MagickFalse)
5041    return MagickFalse;
5042
5043  status = ComputeContrastStretchImageChannel(image,channel, black_point, white_point, exception);
5044
5045  return status;
5046}
5047
5048
5049static Image* ComputeDespeckleImage(const Image* inputImage, ExceptionInfo* exception)
5050{
5051
5052  MagickBooleanType outputReady = MagickFalse;
5053  MagickCLEnv clEnv = NULL;
5054
5055  cl_int clStatus;
5056  size_t global_work_size[2];
5057
5058  const void *inputPixels = NULL;
5059  Image* filteredImage = NULL;
5060  void *filteredPixels = NULL;
5061  void *hostPtr;
5062  MagickSizeType length;
5063
5064  cl_mem_flags mem_flags;
5065  cl_context context = NULL;
5066  cl_mem inputImageBuffer = NULL;
5067  cl_mem tempImageBuffer[2];
5068  cl_mem filteredImageBuffer = NULL;
5069  cl_command_queue queue = NULL;
5070  cl_kernel hullPass1 = NULL;
5071  cl_kernel hullPass2 = NULL;
5072
5073  unsigned int imageWidth, imageHeight;
5074  int matte;
5075  int k;
5076
5077  static const int
5078    X[4] = {0, 1, 1,-1},
5079    Y[4] = {1, 0, 1, 1};
5080
5081  tempImageBuffer[0] = tempImageBuffer[1] = NULL;
5082  clEnv = GetDefaultOpenCLEnv();
5083  context = GetOpenCLContext(clEnv);
5084  queue = AcquireOpenCLCommandQueue(clEnv);
5085
5086  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
5087  if (inputPixels == (void *) NULL)
5088  {
5089    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
5090    goto cleanup;
5091  }
5092
5093  if (ALIGNED(inputPixels,CLPixelPacket))
5094  {
5095    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5096  }
5097  else
5098  {
5099    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5100  }
5101  /* create a CL buffer from image pixel buffer */
5102  length = inputImage->columns * inputImage->rows;
5103  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
5104  if (clStatus != CL_SUCCESS)
5105  {
5106    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5107    goto cleanup;
5108  }
5109
5110  mem_flags = CL_MEM_READ_WRITE;
5111  length = inputImage->columns * inputImage->rows;
5112  for (k = 0; k < 2; k++)
5113  {
5114    tempImageBuffer[k] = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), NULL, &clStatus);
5115    if (clStatus != CL_SUCCESS)
5116    {
5117      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5118      goto cleanup;
5119    }
5120  }
5121
5122  filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
5123  assert(filteredImage != NULL);
5124  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
5125  {
5126    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
5127    goto cleanup;
5128  }
5129  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
5130  if (filteredPixels == (void *) NULL)
5131  {
5132    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
5133    goto cleanup;
5134  }
5135
5136  if (ALIGNED(filteredPixels,CLPixelPacket))
5137  {
5138    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5139    hostPtr = filteredPixels;
5140  }
5141  else
5142  {
5143    mem_flags = CL_MEM_WRITE_ONLY;
5144    hostPtr = NULL;
5145  }
5146  /* create a CL buffer from image pixel buffer */
5147  length = inputImage->columns * inputImage->rows;
5148  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
5149  if (clStatus != CL_SUCCESS)
5150  {
5151    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5152    goto cleanup;
5153  }
5154
5155  hullPass1 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass1");
5156  hullPass2 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass2");
5157
5158  clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)&inputImageBuffer);
5159  clStatus |=clEnv->library->clSetKernelArg(hullPass1,1,sizeof(cl_mem),(void *)(tempImageBuffer+1));
5160  imageWidth = inputImage->columns;
5161  clStatus |=clEnv->library->clSetKernelArg(hullPass1,2,sizeof(unsigned int),(void *)&imageWidth);
5162  imageHeight = inputImage->rows;
5163  clStatus |=clEnv->library->clSetKernelArg(hullPass1,3,sizeof(unsigned int),(void *)&imageHeight);
5164  matte = (inputImage->matte==MagickFalse)?0:1;
5165  clStatus |=clEnv->library->clSetKernelArg(hullPass1,6,sizeof(int),(void *)&matte);
5166  if (clStatus != CL_SUCCESS)
5167  {
5168    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5169    goto cleanup;
5170  }
5171
5172  clStatus = clEnv->library->clSetKernelArg(hullPass2,0,sizeof(cl_mem),(void *)(tempImageBuffer+1));
5173  clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)tempImageBuffer);
5174  imageWidth = inputImage->columns;
5175  clStatus |=clEnv->library->clSetKernelArg(hullPass2,2,sizeof(unsigned int),(void *)&imageWidth);
5176  imageHeight = inputImage->rows;
5177  clStatus |=clEnv->library->clSetKernelArg(hullPass2,3,sizeof(unsigned int),(void *)&imageHeight);
5178  matte = (inputImage->matte==MagickFalse)?0:1;
5179  clStatus |=clEnv->library->clSetKernelArg(hullPass2,6,sizeof(int),(void *)&matte);
5180  if (clStatus != CL_SUCCESS)
5181  {
5182    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5183    goto cleanup;
5184  }
5185
5186
5187  global_work_size[0] = inputImage->columns;
5188  global_work_size[1] = inputImage->rows;
5189
5190
5191  for (k = 0; k < 4; k++)
5192  {
5193    cl_int2 offset;
5194    int polarity;
5195
5196
5197    offset.s[0] = X[k];
5198    offset.s[1] = Y[k];
5199    polarity = 1;
5200    clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5201    clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5202    clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5203    clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
5204    if (clStatus != CL_SUCCESS)
5205    {
5206      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5207      goto cleanup;
5208    }
5209    /* launch the kernel */
5210    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5211    if (clStatus != CL_SUCCESS)
5212    {
5213      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5214      goto cleanup;
5215    }
5216    /* launch the kernel */
5217    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5218    if (clStatus != CL_SUCCESS)
5219    {
5220      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5221      goto cleanup;
5222    }
5223
5224
5225    if (k == 0)
5226      clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)(tempImageBuffer));
5227    offset.s[0] = -X[k];
5228    offset.s[1] = -Y[k];
5229    polarity = 1;
5230    clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5231    clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5232    clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5233    clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
5234    if (clStatus != CL_SUCCESS)
5235    {
5236      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5237      goto cleanup;
5238    }
5239    /* launch the kernel */
5240    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5241    if (clStatus != CL_SUCCESS)
5242    {
5243      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5244      goto cleanup;
5245    }
5246    /* launch the kernel */
5247    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5248    if (clStatus != CL_SUCCESS)
5249    {
5250      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5251      goto cleanup;
5252    }
5253
5254    offset.s[0] = -X[k];
5255    offset.s[1] = -Y[k];
5256    polarity = -1;
5257    clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5258    clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5259    clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5260    clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
5261    if (clStatus != CL_SUCCESS)
5262    {
5263      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5264      goto cleanup;
5265    }
5266    /* launch the kernel */
5267    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5268    if (clStatus != CL_SUCCESS)
5269    {
5270      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5271      goto cleanup;
5272    }
5273    /* launch the kernel */
5274    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5275    if (clStatus != CL_SUCCESS)
5276    {
5277      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5278      goto cleanup;
5279    }
5280
5281    offset.s[0] = X[k];
5282    offset.s[1] = Y[k];
5283    polarity = -1;
5284    clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5285    clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5286    clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5287    clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
5288
5289    if (k == 3)
5290      clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)&filteredImageBuffer);
5291
5292    if (clStatus != CL_SUCCESS)
5293    {
5294      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5295      goto cleanup;
5296    }
5297    /* launch the kernel */
5298    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5299    if (clStatus != CL_SUCCESS)
5300    {
5301      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5302      goto cleanup;
5303    }
5304    /* launch the kernel */
5305    clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5306    if (clStatus != CL_SUCCESS)
5307    {
5308      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5309      goto cleanup;
5310    }
5311  }
5312
5313  if (ALIGNED(filteredPixels,CLPixelPacket))
5314  {
5315    length = inputImage->columns * inputImage->rows;
5316    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
5317  }
5318  else
5319  {
5320    length = inputImage->columns * inputImage->rows;
5321    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
5322  }
5323  if (clStatus != CL_SUCCESS)
5324  {
5325    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
5326    goto cleanup;
5327  }
5328
5329  outputReady = MagickTrue;
5330
5331cleanup:
5332  OpenCLLogException(__FUNCTION__,__LINE__,exception);
5333
5334  if (queue != NULL)                          RelinquishOpenCLCommandQueue(clEnv, queue);
5335  if (inputImageBuffer!=NULL)		      clEnv->library->clReleaseMemObject(inputImageBuffer);
5336  for (k = 0; k < 2; k++)
5337  {
5338    if (tempImageBuffer[k]!=NULL)	      clEnv->library->clReleaseMemObject(tempImageBuffer[k]);
5339  }
5340  if (filteredImageBuffer!=NULL)	      clEnv->library->clReleaseMemObject(filteredImageBuffer);
5341  if (hullPass1!=NULL)			      RelinquishOpenCLKernel(clEnv, hullPass1);
5342  if (hullPass2!=NULL)			      RelinquishOpenCLKernel(clEnv, hullPass2);
5343  if (outputReady == MagickFalse)
5344  {
5345    if (filteredImage != NULL)
5346    {
5347      DestroyImage(filteredImage);
5348      filteredImage = NULL;
5349    }
5350  }
5351  return filteredImage;
5352}
5353
5354/*
5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5356%                                                                             %
5357%                                                                             %
5358%                                                                             %
5359%     D e s p e c k l e I m a g e  w i t h  O p e n C L                       %
5360%                                                                             %
5361%                                                                             %
5362%                                                                             %
5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5364%
5365%  DespeckleImage() reduces the speckle noise in an image while perserving the
5366%  edges of the original image.  A speckle removing filter uses a complementary
5367%  hulling technique (raising pixels that are darker than their surrounding
5368%  neighbors, then complementarily lowering pixels that are brighter than their
5369%  surrounding neighbors) to reduce the speckle index of that image (reference
5370%  Crimmins speckle removal).
5371%
5372%  The format of the DespeckleImage method is:
5373%
5374%      Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
5375%
5376%  A description of each parameter follows:
5377%
5378%    o image: the image.
5379%
5380%    o exception: return any errors or warnings in this structure.
5381%
5382*/
5383
5384MagickExport
5385Image* AccelerateDespeckleImage(const Image* image, ExceptionInfo* exception)
5386{
5387  MagickBooleanType status;
5388  Image* newImage = NULL;
5389
5390  assert(image != NULL);
5391  assert(exception != NULL);
5392
5393  status = checkOpenCLEnvironment(exception);
5394  if (status == MagickFalse)
5395    return NULL;
5396
5397  status = checkAccelerateCondition(image, AllChannels);
5398  if (status == MagickFalse)
5399    return NULL;
5400
5401  newImage = ComputeDespeckleImage(image,exception);
5402  return newImage;
5403}
5404
5405static Image* ComputeAddNoiseImage(const Image* inputImage,
5406         const ChannelType channel, const NoiseType noise_type,
5407         ExceptionInfo *exception)
5408{
5409  MagickBooleanType outputReady = MagickFalse;
5410  MagickCLEnv clEnv = NULL;
5411
5412  cl_int clStatus;
5413  size_t global_work_size[2];
5414
5415  const void *inputPixels = NULL;
5416  Image* filteredImage = NULL;
5417  void *filteredPixels = NULL;
5418  void *hostPtr;
5419  unsigned int inputColumns, inputRows;
5420  float attenuate;
5421  float *randomNumberBufferPtr = NULL;
5422  MagickSizeType length;
5423  unsigned int numRandomNumberPerPixel;
5424  unsigned int numRowsPerKernelLaunch;
5425  unsigned int numRandomNumberPerBuffer;
5426  unsigned int r;
5427  unsigned int k;
5428  int i;
5429
5430  RandomInfo **restrict random_info;
5431  const char *option;
5432#if defined(MAGICKCORE_OPENMP_SUPPORT)
5433  unsigned long key;
5434#endif
5435
5436  cl_mem_flags mem_flags;
5437  cl_context context = NULL;
5438  cl_mem inputImageBuffer = NULL;
5439  cl_mem randomNumberBuffer = NULL;
5440  cl_mem filteredImageBuffer = NULL;
5441  cl_command_queue queue = NULL;
5442  cl_kernel addNoiseKernel = NULL;
5443
5444
5445  clEnv = GetDefaultOpenCLEnv();
5446  context = GetOpenCLContext(clEnv);
5447  queue = AcquireOpenCLCommandQueue(clEnv);
5448
5449  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
5450  if (inputPixels == (void *) NULL)
5451  {
5452    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
5453    goto cleanup;
5454  }
5455
5456  if (ALIGNED(inputPixels,CLPixelPacket))
5457  {
5458    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5459  }
5460  else
5461  {
5462    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5463  }
5464  /* create a CL buffer from image pixel buffer */
5465  length = inputImage->columns * inputImage->rows;
5466  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
5467  if (clStatus != CL_SUCCESS)
5468  {
5469    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5470    goto cleanup;
5471  }
5472
5473
5474  filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
5475  assert(filteredImage != NULL);
5476  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
5477  {
5478    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
5479    goto cleanup;
5480  }
5481  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
5482  if (filteredPixels == (void *) NULL)
5483  {
5484    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
5485    goto cleanup;
5486  }
5487
5488  if (ALIGNED(filteredPixels,CLPixelPacket))
5489  {
5490    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5491    hostPtr = filteredPixels;
5492  }
5493  else
5494  {
5495    mem_flags = CL_MEM_WRITE_ONLY;
5496    hostPtr = NULL;
5497  }
5498  /* create a CL buffer from image pixel buffer */
5499  length = inputImage->columns * inputImage->rows;
5500  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
5501  if (clStatus != CL_SUCCESS)
5502  {
5503    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5504    goto cleanup;
5505  }
5506
5507  /* find out how many random numbers needed by pixel */
5508  numRandomNumberPerPixel = 0;
5509  {
5510    unsigned int numRandPerChannel = 0;
5511    switch (noise_type)
5512    {
5513    case UniformNoise:
5514    case ImpulseNoise:
5515    case LaplacianNoise:
5516    case RandomNoise:
5517    default:
5518      numRandPerChannel = 1;
5519      break;
5520    case GaussianNoise:
5521    case MultiplicativeGaussianNoise:
5522    case PoissonNoise:
5523      numRandPerChannel = 2;
5524      break;
5525    };
5526
5527    if ((channel & RedChannel) != 0)
5528      numRandomNumberPerPixel+=numRandPerChannel;
5529    if ((channel & GreenChannel) != 0)
5530      numRandomNumberPerPixel+=numRandPerChannel;
5531    if ((channel & BlueChannel) != 0)
5532      numRandomNumberPerPixel+=numRandPerChannel;
5533    if ((channel & OpacityChannel) != 0)
5534      numRandomNumberPerPixel+=numRandPerChannel;
5535  }
5536
5537  numRowsPerKernelLaunch = 512;
5538  /* create a buffer for random numbers */
5539  numRandomNumberPerBuffer = (inputImage->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel;
5540  randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, numRandomNumberPerBuffer*sizeof(float)
5541                                      , NULL, &clStatus);
5542
5543
5544  /* set up the random number generators */
5545  attenuate=1.0;
5546  option=GetImageArtifact(inputImage,"attenuate");
5547  if (option != (char *) NULL)
5548    attenuate=StringToDouble(option,(char **) NULL);
5549  random_info=AcquireRandomInfoThreadSet();
5550#if defined(MAGICKCORE_OPENMP_SUPPORT)
5551  key=GetRandomSecretKey(random_info[0]);
5552#endif
5553
5554  addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage");
5555
5556  k = 0;
5557  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&inputImageBuffer);
5558  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer);
5559  inputColumns = inputImage->columns;
5560  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns);
5561  inputRows = inputImage->rows;
5562  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows);
5563  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel);
5564  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type);
5565  attenuate=1.0f;
5566  option=GetImageArtifact(inputImage,"attenuate");
5567  if (option != (char *) NULL)
5568    attenuate=(float)StringToDouble(option,(char **) NULL);
5569  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate);
5570  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
5571  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel);
5572
5573  global_work_size[0] = inputColumns;
5574  for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch)
5575  {
5576    /* Generate random numbers in the buffer */
5577    randomNumberBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, randomNumberBuffer, CL_TRUE, CL_MAP_WRITE, 0
5578      , numRandomNumberPerBuffer*sizeof(float), 0, NULL, NULL, &clStatus);
5579    if (clStatus != CL_SUCCESS)
5580    {
5581      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
5582      goto cleanup;
5583    }
5584
5585#if defined(MAGICKCORE_OPENMP_SUPPORT)
5586  #pragma omp parallel for schedule(static,4) \
5587    num_threads((key == ~0UL) == 0 ? 1 : (size_t) GetMagickResourceLimit(ThreadResource))
5588#endif
5589    for (i = 0; i < numRandomNumberPerBuffer; i++)
5590    {
5591      const int id = GetOpenMPThreadId();
5592      randomNumberBufferPtr[i] = (float)GetPseudoRandomValue(random_info[id]);
5593    }
5594
5595    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberBuffer, randomNumberBufferPtr, 0, NULL, NULL);
5596    if (clStatus != CL_SUCCESS)
5597    {
5598      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.",".");
5599      goto cleanup;
5600    }
5601
5602    /* set the row offset */
5603    clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r);
5604    global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r);
5605    clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
5606  }
5607
5608  if (ALIGNED(filteredPixels,CLPixelPacket))
5609  {
5610    length = inputImage->columns * inputImage->rows;
5611    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
5612  }
5613  else
5614  {
5615    length = inputImage->columns * inputImage->rows;
5616    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
5617  }
5618  if (clStatus != CL_SUCCESS)
5619  {
5620    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
5621    goto cleanup;
5622  }
5623
5624  outputReady = MagickTrue;
5625
5626cleanup:
5627  OpenCLLogException(__FUNCTION__,__LINE__,exception);
5628
5629  if (queue!=NULL)                  RelinquishOpenCLCommandQueue(clEnv, queue);
5630  if (addNoiseKernel!=NULL)         RelinquishOpenCLKernel(clEnv, addNoiseKernel);
5631  if (inputImageBuffer!=NULL)		    clEnv->library->clReleaseMemObject(inputImageBuffer);
5632  if (randomNumberBuffer!=NULL)     clEnv->library->clReleaseMemObject(randomNumberBuffer);
5633  if (filteredImageBuffer!=NULL)	  clEnv->library->clReleaseMemObject(filteredImageBuffer);
5634  if (outputReady == MagickFalse
5635      && filteredImage != NULL)
5636  {
5637      DestroyImage(filteredImage);
5638      filteredImage = NULL;
5639  }
5640  return filteredImage;
5641}
5642
5643
5644static Image* ComputeAddNoiseImageOptRandomNum(const Image* inputImage,
5645         const ChannelType channel, const NoiseType noise_type,
5646         ExceptionInfo *exception)
5647{
5648  MagickBooleanType outputReady = MagickFalse;
5649  MagickCLEnv clEnv = NULL;
5650
5651  cl_int clStatus;
5652  size_t global_work_size[2];
5653  size_t random_work_size;
5654
5655  const void *inputPixels = NULL;
5656  Image* filteredImage = NULL;
5657  void *filteredPixels = NULL;
5658  void *hostPtr;
5659  unsigned int inputColumns, inputRows;
5660  float attenuate;
5661  MagickSizeType length;
5662  unsigned int numRandomNumberPerPixel;
5663  unsigned int numRowsPerKernelLaunch;
5664  unsigned int numRandomNumberPerBuffer;
5665  unsigned int numRandomNumberGenerators;
5666  unsigned int initRandom;
5667  float fNormalize;
5668  unsigned int r;
5669  unsigned int k;
5670  int i;
5671  const char *option;
5672
5673  cl_mem_flags mem_flags;
5674  cl_context context = NULL;
5675  cl_mem inputImageBuffer = NULL;
5676  cl_mem randomNumberBuffer = NULL;
5677  cl_mem filteredImageBuffer = NULL;
5678  cl_mem randomNumberSeedsBuffer = NULL;
5679  cl_command_queue queue = NULL;
5680  cl_kernel addNoiseKernel = NULL;
5681  cl_kernel randomNumberGeneratorKernel = NULL;
5682
5683
5684  clEnv = GetDefaultOpenCLEnv();
5685  context = GetOpenCLContext(clEnv);
5686  queue = AcquireOpenCLCommandQueue(clEnv);
5687
5688  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
5689  if (inputPixels == (void *) NULL)
5690  {
5691    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
5692    goto cleanup;
5693  }
5694
5695  if (ALIGNED(inputPixels,CLPixelPacket))
5696  {
5697    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5698  }
5699  else
5700  {
5701    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5702  }
5703  /* create a CL buffer from image pixel buffer */
5704  length = inputImage->columns * inputImage->rows;
5705  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
5706  if (clStatus != CL_SUCCESS)
5707  {
5708    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5709    goto cleanup;
5710  }
5711
5712
5713  filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception);
5714  assert(filteredImage != NULL);
5715  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
5716  {
5717    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
5718    goto cleanup;
5719  }
5720  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
5721  if (filteredPixels == (void *) NULL)
5722  {
5723    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
5724    goto cleanup;
5725  }
5726
5727  if (ALIGNED(filteredPixels,CLPixelPacket))
5728  {
5729    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5730    hostPtr = filteredPixels;
5731  }
5732  else
5733  {
5734    mem_flags = CL_MEM_WRITE_ONLY;
5735    hostPtr = NULL;
5736  }
5737  /* create a CL buffer from image pixel buffer */
5738  length = inputImage->columns * inputImage->rows;
5739  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
5740  if (clStatus != CL_SUCCESS)
5741  {
5742    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5743    goto cleanup;
5744  }
5745
5746  /* find out how many random numbers needed by pixel */
5747  numRandomNumberPerPixel = 0;
5748  {
5749    unsigned int numRandPerChannel = 0;
5750    switch (noise_type)
5751    {
5752    case UniformNoise:
5753    case ImpulseNoise:
5754    case LaplacianNoise:
5755    case RandomNoise:
5756    default:
5757      numRandPerChannel = 1;
5758      break;
5759    case GaussianNoise:
5760    case MultiplicativeGaussianNoise:
5761    case PoissonNoise:
5762      numRandPerChannel = 2;
5763      break;
5764    };
5765
5766    if ((channel & RedChannel) != 0)
5767      numRandomNumberPerPixel+=numRandPerChannel;
5768    if ((channel & GreenChannel) != 0)
5769      numRandomNumberPerPixel+=numRandPerChannel;
5770    if ((channel & BlueChannel) != 0)
5771      numRandomNumberPerPixel+=numRandPerChannel;
5772    if ((channel & OpacityChannel) != 0)
5773      numRandomNumberPerPixel+=numRandPerChannel;
5774  }
5775
5776  numRowsPerKernelLaunch = 512;
5777
5778  /* create a buffer for random numbers */
5779  numRandomNumberPerBuffer = (inputImage->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel;
5780  randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, numRandomNumberPerBuffer*sizeof(float)
5781    , NULL, &clStatus);
5782
5783  {
5784    /* setup the random number generators */
5785    unsigned long* seeds;
5786    numRandomNumberGenerators = 512;
5787    randomNumberSeedsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR|CL_MEM_READ_WRITE
5788                                            , numRandomNumberGenerators * 4 * sizeof(unsigned long), NULL, &clStatus);
5789    if (clStatus != CL_SUCCESS)
5790    {
5791      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5792      goto cleanup;
5793    }
5794    seeds = (unsigned long*) clEnv->library->clEnqueueMapBuffer(queue, randomNumberSeedsBuffer, CL_TRUE, CL_MAP_WRITE, 0
5795                                                , numRandomNumberGenerators*4*sizeof(unsigned long), 0, NULL, NULL, &clStatus);
5796    if (clStatus != CL_SUCCESS)
5797    {
5798      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
5799      goto cleanup;
5800    }
5801
5802    for (i = 0; i < numRandomNumberGenerators; i++) {
5803      RandomInfo* randomInfo = AcquireRandomInfo();
5804      const unsigned long* s = GetRandomInfoSeed(randomInfo);
5805
5806      if (i == 0)
5807        fNormalize = GetRandomInfoNormalize(randomInfo);
5808
5809      seeds[i*4] = s[0];
5810      randomInfo = DestroyRandomInfo(randomInfo);
5811    }
5812
5813    clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberSeedsBuffer, seeds, 0, NULL, NULL);
5814    if (clStatus != CL_SUCCESS)
5815    {
5816      (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.",".");
5817      goto cleanup;
5818    }
5819
5820    randomNumberGeneratorKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE
5821                                                        ,"randomNumberGeneratorKernel");
5822
5823    k = 0;
5824    clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberSeedsBuffer);
5825    clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(float),(void *)&fNormalize);
5826    clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
5827    initRandom = 1;
5828    clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&initRandom);
5829    clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerBuffer);
5830
5831    random_work_size = numRandomNumberGenerators;
5832  }
5833
5834  addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage");
5835  k = 0;
5836  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&inputImageBuffer);
5837  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer);
5838  inputColumns = inputImage->columns;
5839  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns);
5840  inputRows = inputImage->rows;
5841  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows);
5842  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel);
5843  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type);
5844  attenuate=1.0f;
5845  option=GetImageArtifact(inputImage,"attenuate");
5846  if (option != (char *) NULL)
5847    attenuate=(float)StringToDouble(option,(char **) NULL);
5848  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate);
5849  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
5850  clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel);
5851
5852  global_work_size[0] = inputColumns;
5853  for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch)
5854  {
5855    size_t generator_local_size = 64;
5856    /* Generate random numbers in the buffer */
5857    clEnv->library->clEnqueueNDRangeKernel(queue,randomNumberGeneratorKernel,1,NULL
5858                            ,&random_work_size,&generator_local_size,0,NULL,NULL);
5859    if (initRandom != 0)
5860    {
5861      /* make sure we only do init once */
5862      initRandom = 0;
5863      clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,3,sizeof(unsigned int),(void *)&initRandom);
5864    }
5865
5866    /* set the row offset */
5867    clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r);
5868    global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r);
5869    clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
5870  }
5871
5872  if (ALIGNED(filteredPixels,CLPixelPacket))
5873  {
5874    length = inputImage->columns * inputImage->rows;
5875    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
5876  }
5877  else
5878  {
5879    length = inputImage->columns * inputImage->rows;
5880    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
5881  }
5882  if (clStatus != CL_SUCCESS)
5883  {
5884    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
5885    goto cleanup;
5886  }
5887
5888  outputReady = MagickTrue;
5889
5890cleanup:
5891  OpenCLLogException(__FUNCTION__,__LINE__,exception);
5892
5893  if (queue!=NULL)                  RelinquishOpenCLCommandQueue(clEnv, queue);
5894  if (addNoiseKernel!=NULL)         RelinquishOpenCLKernel(clEnv, addNoiseKernel);
5895  if (randomNumberGeneratorKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomNumberGeneratorKernel);
5896  if (inputImageBuffer!=NULL)		    clEnv->library->clReleaseMemObject(inputImageBuffer);
5897  if (randomNumberBuffer!=NULL)     clEnv->library->clReleaseMemObject(randomNumberBuffer);
5898  if (filteredImageBuffer!=NULL)	  clEnv->library->clReleaseMemObject(filteredImageBuffer);
5899  if (randomNumberSeedsBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberSeedsBuffer);
5900  if (outputReady == MagickFalse
5901      && filteredImage != NULL)
5902  {
5903      DestroyImage(filteredImage);
5904      filteredImage = NULL;
5905  }
5906  return filteredImage;
5907}
5908
5909
5910
5911MagickExport
5912Image* AccelerateAddNoiseImage(const Image *image, const ChannelType channel,
5913          const NoiseType noise_type,ExceptionInfo *exception)
5914{
5915  MagickBooleanType status;
5916  Image* filteredImage = NULL;
5917
5918  assert(image != NULL);
5919  assert(exception != NULL);
5920
5921  status = checkOpenCLEnvironment(exception);
5922  if (status == MagickFalse)
5923    return NULL;
5924
5925  status = checkAccelerateCondition(image, channel);
5926  if (status == MagickFalse)
5927    return NULL;
5928
5929DisableMSCWarning(4127)
5930  if (sizeof(unsigned long) == 4)
5931RestoreMSCWarning
5932    filteredImage = ComputeAddNoiseImageOptRandomNum(image,channel,noise_type,exception);
5933  else
5934    filteredImage = ComputeAddNoiseImage(image,channel,noise_type,exception);
5935
5936  return filteredImage;
5937}
5938
5939static MagickBooleanType LaunchRandomImageKernel(MagickCLEnv clEnv,
5940                                              cl_command_queue queue,
5941                                              cl_mem inputImageBuffer,
5942                                              const unsigned int imageColumns,
5943                                              const unsigned int imageRows,
5944                                              cl_mem seedBuffer,
5945                                              const unsigned int numGenerators,
5946                                              ExceptionInfo *exception)
5947{
5948  MagickBooleanType status = MagickFalse;
5949  size_t global_work_size;
5950  size_t local_work_size;
5951  int k;
5952
5953  cl_int clStatus;
5954  cl_kernel randomImageKernel = NULL;
5955
5956  randomImageKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RandomImage");
5957
5958  k = 0;
5959  clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&inputImageBuffer);
5960  clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageColumns);
5961  clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageRows);
5962  clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&seedBuffer);
5963  {
5964    const float randNormNumerator = 1.0f;
5965    const unsigned int randNormDenominator = (unsigned int)(~0UL);
5966    clEnv->library->clSetKernelArg(randomImageKernel,k++,
5967          sizeof(float),(void*)&randNormNumerator);
5968    clEnv->library->clSetKernelArg(randomImageKernel,k++,
5969          sizeof(cl_uint),(void*)&randNormDenominator);
5970  }
5971
5972
5973  global_work_size = numGenerators;
5974  local_work_size = 64;
5975
5976  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue,randomImageKernel,1,NULL,&global_work_size,
5977                                    &local_work_size,0,NULL,NULL);
5978
5979  if (clStatus != CL_SUCCESS)
5980  {
5981    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning,
5982                                      "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5983    goto cleanup;
5984  }
5985  status = MagickTrue;
5986
5987cleanup:
5988  if (randomImageKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomImageKernel);
5989  return status;
5990}
5991
5992static MagickBooleanType ComputeRandomImage(Image* inputImage,
5993                                            ExceptionInfo* exception)
5994{
5995  MagickBooleanType status = MagickFalse;
5996
5997  MagickBooleanType outputReady = MagickFalse;
5998  MagickCLEnv clEnv = NULL;
5999
6000  cl_int clStatus;
6001
6002  void *inputPixels = NULL;
6003  MagickSizeType length;
6004
6005  cl_mem_flags mem_flags;
6006  cl_context context = NULL;
6007  cl_mem inputImageBuffer = NULL;
6008  cl_command_queue queue = NULL;
6009
6010  /* Don't release this buffer in this function !!! */
6011  cl_mem randomNumberSeedsBuffer;
6012
6013  clEnv = GetDefaultOpenCLEnv();
6014  context = GetOpenCLContext(clEnv);
6015
6016  /* Create and initialize OpenCL buffers. */
6017  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
6018  if (inputPixels == (void *) NULL)
6019  {
6020    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename);
6021    goto cleanup;
6022  }
6023
6024  /* If the host pointer is aligned to the size of CLPixelPacket,
6025     then use the host buffer directly from the GPU; otherwise,
6026     create a buffer on the GPU and copy the data over */
6027  if (ALIGNED(inputPixels,CLPixelPacket))
6028  {
6029    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
6030  }
6031  else
6032  {
6033    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
6034  }
6035  /* create a CL buffer from image pixel buffer */
6036  length = inputImage->columns * inputImage->rows;
6037  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6038  if (clStatus != CL_SUCCESS)
6039  {
6040    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6041    goto cleanup;
6042  }
6043
6044  queue = AcquireOpenCLCommandQueue(clEnv);
6045
6046  randomNumberSeedsBuffer = GetAndLockRandSeedBuffer(clEnv);
6047  if (randomNumberSeedsBuffer==NULL)
6048  {
6049    (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6050           ResourceLimitWarning, "Failed to get GPU random number generators.",
6051           "'%s'", ".");
6052    goto cleanup;
6053  }
6054
6055  status = LaunchRandomImageKernel(clEnv,queue,
6056                                   inputImageBuffer,
6057                                   inputImage->columns,
6058                                   inputImage->rows,
6059                                   randomNumberSeedsBuffer,
6060                                   GetNumRandGenerators(clEnv),
6061                                   exception);
6062  if (status==MagickFalse)
6063  {
6064    goto cleanup;
6065  }
6066
6067  if (ALIGNED(inputPixels,CLPixelPacket))
6068  {
6069    length = inputImage->columns * inputImage->rows;
6070    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
6071  }
6072  else
6073  {
6074    length = inputImage->columns * inputImage->rows;
6075    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
6076  }
6077  if (clStatus != CL_SUCCESS)
6078  {
6079    (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
6080    goto cleanup;
6081  }
6082  outputReady = MagickTrue;
6083
6084cleanup:
6085  OpenCLLogException(__FUNCTION__,__LINE__,exception);
6086
6087  UnlockRandSeedBuffer(clEnv);
6088  if (inputImageBuffer!=NULL)		      clEnv->library->clReleaseMemObject(inputImageBuffer);
6089  if (queue != NULL)                  RelinquishOpenCLCommandQueue(clEnv, queue);
6090  return outputReady;
6091}
6092
6093MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception)
6094{
6095  MagickBooleanType status = MagickFalse;
6096
6097  status = checkOpenCLEnvironment(exception);
6098  if (status==MagickFalse)
6099    return status;
6100
6101  status = checkAccelerateCondition(image, AllChannels);
6102  if (status==MagickFalse)
6103    return status;
6104
6105  status = ComputeRandomImage(image,exception);
6106  return status;
6107}
6108
6109static Image* ComputeMotionBlurImage(const Image *inputImage,
6110  const ChannelType channel, const double *kernel, const size_t width,
6111  const OffsetInfo *offset, ExceptionInfo *exception)
6112{
6113  MagickBooleanType outputReady;
6114  Image* filteredImage;
6115  MagickCLEnv clEnv;
6116
6117  cl_int clStatus;
6118  size_t global_work_size[2];
6119  size_t local_work_size[2];
6120
6121  cl_context context;
6122  cl_mem_flags mem_flags;
6123  cl_mem inputImageBuffer, filteredImageBuffer, imageKernelBuffer,
6124    offsetBuffer;
6125  cl_kernel motionBlurKernel;
6126  cl_command_queue queue;
6127
6128  const void *inputPixels;
6129  void *filteredPixels;
6130  void* hostPtr;
6131  float* kernelBufferPtr;
6132  int* offsetBufferPtr;
6133  MagickSizeType length;
6134  unsigned int matte;
6135  MagickPixelPacket bias;
6136  cl_float4 biasPixel;
6137  unsigned int imageWidth, imageHeight;
6138
6139  unsigned int i;
6140
6141  outputReady = MagickFalse;
6142  context = NULL;
6143  filteredImage = NULL;
6144  inputImageBuffer = NULL;
6145  filteredImageBuffer = NULL;
6146  imageKernelBuffer = NULL;
6147  motionBlurKernel = NULL;
6148  queue = NULL;
6149
6150
6151  clEnv = GetDefaultOpenCLEnv();
6152  context = GetOpenCLContext(clEnv);
6153
6154  /* Create and initialize OpenCL buffers. */
6155
6156  inputPixels = NULL;
6157  inputPixels = AcquirePixelCachePixels(inputImage, &length, exception);
6158  if (inputPixels == (const void *) NULL)
6159  {
6160    (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
6161      "UnableToReadPixelCache.","`%s'",inputImage->filename);
6162    goto cleanup;
6163  }
6164
6165  // If the host pointer is aligned to the size of CLPixelPacket,
6166  // then use the host buffer directly from the GPU; otherwise,
6167  // create a buffer on the GPU and copy the data over
6168  if (ALIGNED(inputPixels,CLPixelPacket))
6169  {
6170    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
6171  }
6172  else
6173  {
6174    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
6175  }
6176  // create a CL buffer from image pixel buffer
6177  length = inputImage->columns * inputImage->rows;
6178  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6179    length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6180  if (clStatus != CL_SUCCESS)
6181  {
6182    (void) ThrowMagickException(exception, GetMagickModule(),
6183      ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6184    goto cleanup;
6185  }
6186
6187
6188  filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,
6189    MagickTrue,exception);
6190  assert(filteredImage != NULL);
6191  if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue)
6192  {
6193    (void) ThrowMagickException(exception, GetMagickModule(),
6194      ResourceLimitError, "CloneImage failed.", "'%s'", ".");
6195    goto cleanup;
6196  }
6197  filteredPixels = GetPixelCachePixels(filteredImage, &length, exception);
6198  if (filteredPixels == (void *) NULL)
6199  {
6200    (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
6201      "UnableToReadPixelCache.","`%s'",filteredImage->filename);
6202    goto cleanup;
6203  }
6204
6205  if (ALIGNED(filteredPixels,CLPixelPacket))
6206  {
6207    mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
6208    hostPtr = filteredPixels;
6209  }
6210  else
6211  {
6212    mem_flags = CL_MEM_WRITE_ONLY;
6213    hostPtr = NULL;
6214  }
6215  // create a CL buffer from image pixel buffer
6216  length = inputImage->columns * inputImage->rows;
6217  filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6218    length * sizeof(CLPixelPacket), hostPtr, &clStatus);
6219  if (clStatus != CL_SUCCESS)
6220  {
6221    (void) ThrowMagickException(exception, GetMagickModule(),
6222      ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6223    goto cleanup;
6224  }
6225
6226
6227  imageKernelBuffer = clEnv->library->clCreateBuffer(context,
6228    CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(float), NULL,
6229    &clStatus);
6230  if (clStatus != CL_SUCCESS)
6231  {
6232    (void) ThrowMagickException(exception, GetMagickModule(),
6233      ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6234    goto cleanup;
6235  }
6236
6237  queue = AcquireOpenCLCommandQueue(clEnv);
6238  kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer,
6239    CL_TRUE, CL_MAP_WRITE, 0, width * sizeof(float), 0, NULL, NULL, &clStatus);
6240  if (clStatus != CL_SUCCESS)
6241  {
6242    (void) ThrowMagickException(exception, GetMagickModule(),
6243      ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
6244    goto cleanup;
6245  }
6246  for (i = 0; i < width; i++)
6247  {
6248    kernelBufferPtr[i] = (float) kernel[i];
6249  }
6250  clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr,
6251    0, NULL, NULL);
6252 if (clStatus != CL_SUCCESS)
6253  {
6254    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6255      "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
6256    goto cleanup;
6257  }
6258
6259  offsetBuffer = clEnv->library->clCreateBuffer(context,
6260    CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(cl_int2), NULL,
6261    &clStatus);
6262  if (clStatus != CL_SUCCESS)
6263  {
6264    (void) ThrowMagickException(exception, GetMagickModule(),
6265      ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6266    goto cleanup;
6267  }
6268
6269  offsetBufferPtr = (int*)clEnv->library->clEnqueueMapBuffer(queue, offsetBuffer, CL_TRUE,
6270    CL_MAP_WRITE, 0, width * sizeof(cl_int2), 0, NULL, NULL, &clStatus);
6271  if (clStatus != CL_SUCCESS)
6272  {
6273    (void) ThrowMagickException(exception, GetMagickModule(),
6274      ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
6275    goto cleanup;
6276  }
6277  for (i = 0; i < width; i++)
6278  {
6279    offsetBufferPtr[2*i] = (int)offset[i].x;
6280    offsetBufferPtr[2*i+1] = (int)offset[i].y;
6281  }
6282  clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, offsetBuffer, offsetBufferPtr, 0,
6283    NULL, NULL);
6284 if (clStatus != CL_SUCCESS)
6285  {
6286    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6287      "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
6288    goto cleanup;
6289  }
6290
6291
6292 // get the OpenCL kernel
6293  motionBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE,
6294    "MotionBlur");
6295  if (motionBlurKernel == NULL)
6296  {
6297    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6298      "AcquireOpenCLKernel failed.", "'%s'", ".");
6299    goto cleanup;
6300  }
6301
6302  // set the kernel arguments
6303  i = 0;
6304  clStatus=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6305    (void *)&inputImageBuffer);
6306  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6307    (void *)&filteredImageBuffer);
6308  imageWidth = inputImage->columns;
6309  imageHeight = inputImage->rows;
6310  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6311    &imageWidth);
6312  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6313    &imageHeight);
6314  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6315    (void *)&imageKernelBuffer);
6316  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6317    &width);
6318  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6319    (void *)&offsetBuffer);
6320
6321  GetMagickPixelPacket(inputImage,&bias);
6322  biasPixel.s[0] = bias.red;
6323  biasPixel.s[1] = bias.green;
6324  biasPixel.s[2] = bias.blue;
6325  biasPixel.s[3] = bias.opacity;
6326  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_float4), &biasPixel);
6327
6328  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(ChannelType), &channel);
6329  matte = (inputImage->matte == MagickTrue)?1:0;
6330  clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), &matte);
6331  if (clStatus != CL_SUCCESS)
6332  {
6333    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6334      "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
6335    goto cleanup;
6336  }
6337
6338  // launch the kernel
6339  local_work_size[0] = 16;
6340  local_work_size[1] = 16;
6341  global_work_size[0] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
6342                                inputImage->columns,local_work_size[0]);
6343  global_work_size[1] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
6344                                inputImage->rows,local_work_size[1]);
6345  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, motionBlurKernel, 2, NULL,
6346    global_work_size, local_work_size, 0, NULL, NULL);
6347
6348  if (clStatus != CL_SUCCESS)
6349  {
6350    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6351      "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
6352    goto cleanup;
6353  }
6354  clEnv->library->clFlush(queue);
6355
6356  if (ALIGNED(filteredPixels,CLPixelPacket))
6357  {
6358    length = inputImage->columns * inputImage->rows;
6359    clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE,
6360      CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
6361      NULL, &clStatus);
6362  }
6363  else
6364  {
6365    length = inputImage->columns * inputImage->rows;
6366    clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0,
6367      length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
6368  }
6369  if (clStatus != CL_SUCCESS)
6370  {
6371    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6372      "Reading output image from CL buffer failed.", "'%s'", ".");
6373    goto cleanup;
6374  }
6375  outputReady = MagickTrue;
6376
6377cleanup:
6378
6379  if (filteredImageBuffer!=NULL)  clEnv->library->clReleaseMemObject(filteredImageBuffer);
6380  if (inputImageBuffer!=NULL)     clEnv->library->clReleaseMemObject(inputImageBuffer);
6381  if (imageKernelBuffer!=NULL)    clEnv->library->clReleaseMemObject(imageKernelBuffer);
6382  if (motionBlurKernel!=NULL)  RelinquishOpenCLKernel(clEnv, motionBlurKernel);
6383  if (queue != NULL)           RelinquishOpenCLCommandQueue(clEnv, queue);
6384  if (outputReady == MagickFalse)
6385  {
6386    if (filteredImage != NULL)
6387    {
6388      DestroyImage(filteredImage);
6389      filteredImage = NULL;
6390    }
6391  }
6392
6393  return filteredImage;
6394}
6395
6396
6397MagickExport
6398Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel,
6399  const double* kernel, const size_t width, const OffsetInfo *offset,
6400  ExceptionInfo *exception)
6401{
6402  MagickBooleanType status;
6403  Image* filteredImage = NULL;
6404
6405  assert(image != NULL);
6406  assert(kernel != (double *) NULL);
6407  assert(offset != (OffsetInfo *) NULL);
6408  assert(exception != (ExceptionInfo *) NULL);
6409
6410  status = checkOpenCLEnvironment(exception);
6411  if (status == MagickFalse)
6412    return NULL;
6413
6414  status = checkAccelerateCondition(image, channel);
6415  if (status == MagickFalse)
6416    return NULL;
6417
6418  filteredImage = ComputeMotionBlurImage(image, channel, kernel, width,
6419    offset, exception);
6420  return filteredImage;
6421
6422}
6423
6424
6425static MagickBooleanType LaunchCompositeKernel(MagickCLEnv clEnv,
6426    cl_command_queue queue,
6427  cl_mem inputImageBuffer,
6428  const unsigned int inputWidth, const unsigned int inputHeight,
6429  const unsigned int matte,
6430  const ChannelType channel,const CompositeOperator compose,
6431  const cl_mem compositeImageBuffer,
6432  const unsigned int compositeWidth,
6433  const unsigned int compositeHeight,
6434  const float destination_dissolve,const float source_dissolve,
6435  ExceptionInfo *magick_unused(exception))
6436{
6437  size_t global_work_size[2];
6438  size_t local_work_size[2];
6439  unsigned int composeOp;
6440  int k;
6441
6442  cl_int clStatus;
6443  cl_kernel compositeKernel = NULL;
6444
6445  magick_unreferenced(exception);
6446
6447  compositeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE,
6448    "Composite");
6449
6450  k = 0;
6451  clStatus=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&inputImageBuffer);
6452  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputWidth);
6453  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputHeight);
6454  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&compositeImageBuffer);
6455  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeWidth);
6456  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeHeight);
6457  composeOp = (unsigned int)compose;
6458  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&composeOp);
6459  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(ChannelType),(void*)&channel);
6460  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&matte);
6461  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&destination_dissolve);
6462  clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&source_dissolve);
6463
6464  if (clStatus!=CL_SUCCESS)
6465    return MagickFalse;
6466
6467  local_work_size[0] = 64;
6468  local_work_size[1] = 1;
6469
6470  global_work_size[0] = padGlobalWorkgroupSizeToLocalWorkgroupSize(inputWidth,
6471    local_work_size[0]);
6472  global_work_size[1] = inputHeight;
6473  clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, compositeKernel, 2, NULL,
6474    global_work_size, local_work_size, 0, NULL, NULL);
6475
6476
6477  RelinquishOpenCLKernel(clEnv, compositeKernel);
6478
6479  return (clStatus==CL_SUCCESS)?MagickTrue:MagickFalse;
6480}
6481
6482
6483static MagickBooleanType ComputeCompositeImage(Image *inputImage,
6484  const ChannelType channel,const CompositeOperator compose,
6485  const Image *compositeImage,const ssize_t magick_unused(x_offset),const ssize_t magick_unused(y_offset),
6486  const float destination_dissolve,const float source_dissolve,
6487  ExceptionInfo *exception)
6488{
6489  MagickBooleanType status = MagickFalse;
6490
6491  MagickBooleanType outputReady = MagickFalse;
6492  MagickCLEnv clEnv = NULL;
6493
6494  cl_int clStatus;
6495
6496  void *inputPixels = NULL;
6497  const void *composePixels = NULL;
6498  MagickSizeType length;
6499
6500  cl_mem_flags mem_flags;
6501  cl_context context = NULL;
6502  cl_mem inputImageBuffer = NULL;
6503  cl_mem compositeImageBuffer = NULL;
6504  cl_command_queue queue = NULL;
6505
6506  magick_unreferenced(x_offset);
6507  magick_unreferenced(y_offset);
6508
6509  clEnv = GetDefaultOpenCLEnv();
6510  context = GetOpenCLContext(clEnv);
6511  queue = AcquireOpenCLCommandQueue(clEnv);
6512
6513  /* Create and initialize OpenCL buffers. */
6514  inputPixels = GetPixelCachePixels(inputImage, &length, exception);
6515  if (inputPixels == (void *) NULL)
6516  {
6517    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,
6518      "UnableToReadPixelCache.","`%s'",inputImage->filename);
6519    goto cleanup;
6520  }
6521
6522  /* If the host pointer is aligned to the size of CLPixelPacket,
6523     then use the host buffer directly from the GPU; otherwise,
6524     create a buffer on the GPU and copy the data over */
6525  if (ALIGNED(inputPixels,CLPixelPacket))
6526  {
6527    mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
6528  }
6529  else
6530  {
6531    mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
6532  }
6533  /* create a CL buffer from image pixel buffer */
6534  length = inputImage->columns * inputImage->rows;
6535  inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6536    length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6537  if (clStatus != CL_SUCCESS)
6538  {
6539    (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6540      ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6541    goto cleanup;
6542  }
6543
6544
6545  /* Create and initialize OpenCL buffers. */
6546  composePixels = AcquirePixelCachePixels(compositeImage, &length, exception);
6547  if (composePixels == (void *) NULL)
6548  {
6549    (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,
6550      "UnableToReadPixelCache.","`%s'",compositeImage->filename);
6551    goto cleanup;
6552  }
6553
6554  /* If the host pointer is aligned to the size of CLPixelPacket,
6555     then use the host buffer directly from the GPU; otherwise,
6556     create a buffer on the GPU and copy the data over */
6557  if (ALIGNED(composePixels,CLPixelPacket))
6558  {
6559    mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
6560  }
6561  else
6562  {
6563    mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
6564  }
6565  /* create a CL buffer from image pixel buffer */
6566  length = compositeImage->columns * compositeImage->rows;
6567  compositeImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6568    length * sizeof(CLPixelPacket), (void*)composePixels, &clStatus);
6569  if (clStatus != CL_SUCCESS)
6570  {
6571    (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6572      ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6573    goto cleanup;
6574  }
6575
6576  status = LaunchCompositeKernel(clEnv,queue,inputImageBuffer,
6577           (unsigned int) inputImage->columns,
6578           (unsigned int) inputImage->rows,
6579           (unsigned int) inputImage->matte,
6580           channel, compose, compositeImageBuffer,
6581           (unsigned int) compositeImage->columns,
6582           (unsigned int) compositeImage->rows,
6583           destination_dissolve,source_dissolve,
6584           exception);
6585
6586  if (status==MagickFalse)
6587    goto cleanup;
6588
6589  length = inputImage->columns * inputImage->rows;
6590  if (ALIGNED(inputPixels,CLPixelPacket))
6591  {
6592    clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE,
6593      CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
6594      NULL, &clStatus);
6595  }
6596  else
6597  {
6598    clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0,
6599      length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
6600  }
6601  if (clStatus==CL_SUCCESS)
6602    outputReady = MagickTrue;
6603
6604cleanup:
6605  if (inputImageBuffer!=NULL)      clEnv->library->clReleaseMemObject(inputImageBuffer);
6606  if (compositeImageBuffer!=NULL)  clEnv->library->clReleaseMemObject(compositeImageBuffer);
6607  if (queue != NULL)               RelinquishOpenCLCommandQueue(clEnv, queue);
6608
6609  return outputReady;
6610}
6611
6612
6613MagickExport
6614MagickBooleanType AccelerateCompositeImage(Image *image,
6615  const ChannelType channel,const CompositeOperator compose,
6616  const Image *composite,const ssize_t x_offset,const ssize_t y_offset,
6617  const float destination_dissolve,const float source_dissolve,
6618  ExceptionInfo *exception)
6619{
6620  MagickBooleanType status;
6621
6622  assert(image != NULL);
6623  assert(composite != NULL);
6624  assert(exception != (ExceptionInfo *) NULL);
6625
6626  status = checkOpenCLEnvironment(exception);
6627  if (status == MagickFalse)
6628    return MagickFalse;
6629
6630  status = checkAccelerateCondition(image, channel);
6631  if (status == MagickFalse)
6632    return MagickFalse;
6633
6634  /* only support zero offset and
6635     images with the size for now */
6636  if (x_offset!=0
6637    || y_offset!=0
6638    || image->columns!=composite->columns
6639    || image->rows!=composite->rows)
6640    return MagickFalse;
6641
6642  switch(compose) {
6643  case ColorDodgeCompositeOp:
6644  case BlendCompositeOp:
6645    break;
6646  default:
6647    // unsupported compose operator, quit
6648    return MagickFalse;
6649  };
6650
6651  status = ComputeCompositeImage(image,channel,compose,composite,
6652    x_offset,y_offset,destination_dissolve,source_dissolve,exception);
6653
6654  return status;
6655}
6656
6657
6658
6659#else  /* MAGICKCORE_OPENCL_SUPPORT  */
6660
6661MagickExport Image *AccelerateConvolveImageChannel(
6662  const Image *magick_unused(image),const ChannelType magick_unused(channel),
6663  const KernelInfo *magick_unused(kernel),
6664  ExceptionInfo *magick_unused(exception))
6665{
6666  magick_unreferenced(image);
6667  magick_unreferenced(channel);
6668  magick_unreferenced(kernel);
6669  magick_unreferenced(exception);
6670
6671  return NULL;
6672}
6673
6674MagickExport MagickBooleanType AccelerateFunctionImage(
6675  Image *magick_unused(image),const ChannelType magick_unused(channel),
6676  const MagickFunction magick_unused(function),
6677  const size_t magick_unused(number_parameters),
6678  const double *magick_unused(parameters),
6679  ExceptionInfo *magick_unused(exception))
6680{
6681  magick_unreferenced(image);
6682  magick_unreferenced(channel);
6683  magick_unreferenced(function);
6684  magick_unreferenced(number_parameters);
6685  magick_unreferenced(parameters);
6686  magick_unreferenced(exception);
6687
6688  return MagickFalse;
6689}
6690
6691MagickExport Image *AccelerateBlurImage(const Image *magick_unused(image),
6692  const ChannelType magick_unused(channel),const double magick_unused(radius),
6693  const double magick_unused(sigma),ExceptionInfo *magick_unused(exception))
6694{
6695  magick_unreferenced(image);
6696  magick_unreferenced(channel);
6697  magick_unreferenced(radius);
6698  magick_unreferenced(sigma);
6699  magick_unreferenced(exception);
6700
6701  return NULL;
6702}
6703
6704MagickExport Image *AccelerateRadialBlurImage(
6705  const Image *magick_unused(image),const ChannelType magick_unused(channel),
6706  const double magick_unused(angle),ExceptionInfo *magick_unused(exception))
6707{
6708  magick_unreferenced(image);
6709  magick_unreferenced(channel);
6710  magick_unreferenced(angle);
6711  magick_unreferenced(exception);
6712
6713  return NULL;
6714}
6715
6716
6717MagickExport Image *AccelerateUnsharpMaskImage(
6718  const Image *magick_unused(image),const ChannelType magick_unused(channel),
6719  const double magick_unused(radius),const double magick_unused(sigma),
6720  const double magick_unused(gain),const double magick_unused(threshold),
6721  ExceptionInfo *magick_unused(exception))
6722{
6723  magick_unreferenced(image);
6724  magick_unreferenced(channel);
6725  magick_unreferenced(radius);
6726  magick_unreferenced(sigma);
6727  magick_unreferenced(gain);
6728  magick_unreferenced(threshold);
6729  magick_unreferenced(exception);
6730
6731  return NULL;
6732}
6733
6734MagickExport
6735MagickBooleanType AccelerateCompositeImage(Image *image,
6736  const ChannelType channel,const CompositeOperator compose,
6737  const Image *composite,const ssize_t x_offset,const ssize_t y_offset,
6738  const float destination_dissolve,const float source_dissolve,
6739  ExceptionInfo *exception)
6740{
6741  magick_unreferenced(image);
6742
6743  return MagickFalse;
6744}
6745
6746
6747MagickExport MagickBooleanType AccelerateContrastImage(
6748  Image* magick_unused(image),const MagickBooleanType magick_unused(sharpen),
6749  ExceptionInfo* magick_unused(exception))
6750{
6751  magick_unreferenced(image);
6752  magick_unreferenced(sharpen);
6753  magick_unreferenced(exception);
6754
6755  return MagickFalse;
6756}
6757
6758MagickExport MagickBooleanType AccelerateContrastStretchImageChannel(
6759    Image * image, const ChannelType channel, const double black_point, const double white_point,
6760    ExceptionInfo* magick_unused(exception))
6761{
6762  magick_unreferenced(image);
6763  magick_unreferenced(channel);
6764  magick_unreferenced(black_point);
6765  magick_unreferenced(white_point);
6766  magick_unreferenced(exception);
6767
6768  return MagickFalse;
6769}
6770
6771MagickExport MagickBooleanType AccelerateEqualizeImage(
6772  Image* magick_unused(image), const ChannelType magick_unused(channel),
6773  ExceptionInfo* magick_unused(exception))
6774{
6775  magick_unreferenced(image);
6776  magick_unreferenced(channel);
6777  magick_unreferenced(exception);
6778
6779  return MagickFalse;
6780}
6781
6782MagickExport Image *AccelerateDespeckleImage(const Image* magick_unused(image),
6783  ExceptionInfo* magick_unused(exception))
6784{
6785  magick_unreferenced(image);
6786  magick_unreferenced(exception);
6787
6788  return NULL;
6789}
6790
6791MagickExport Image *AccelerateResizeImage(const Image* magick_unused(image),
6792  const size_t magick_unused(resizedColumns),
6793  const size_t magick_unused(resizedRows),
6794  const ResizeFilter* magick_unused(resizeFilter),
6795  ExceptionInfo *magick_unused(exception))
6796{
6797  magick_unreferenced(image);
6798  magick_unreferenced(resizedColumns);
6799  magick_unreferenced(resizedRows);
6800  magick_unreferenced(resizeFilter);
6801  magick_unreferenced(exception);
6802
6803  return NULL;
6804}
6805
6806MagickExport
6807MagickBooleanType AccelerateModulateImage(
6808  Image* image, double percent_brightness, double percent_hue,
6809  double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
6810{
6811  magick_unreferenced(image);
6812  magick_unreferenced(percent_brightness);
6813  magick_unreferenced(percent_hue);
6814  magick_unreferenced(percent_saturation);
6815  magick_unreferenced(colorspace);
6816  magick_unreferenced(exception);
6817  return(MagickFalse);
6818}
6819
6820MagickExport
6821MagickBooleanType AccelerateNegateImageChannel(
6822  Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception)
6823{
6824  magick_unreferenced(image);
6825  magick_unreferenced(channel);
6826  magick_unreferenced(grayscale);
6827  magick_unreferenced(exception);
6828  return(MagickFalse);
6829}
6830
6831MagickExport
6832MagickBooleanType AccelerateGrayscaleImage(
6833  Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
6834{
6835  magick_unreferenced(image);
6836  magick_unreferenced(method);
6837  magick_unreferenced(exception);
6838  return(MagickFalse);
6839}
6840
6841MagickExport Image *AccelerateAddNoiseImage(const Image *image,
6842  const ChannelType channel, const NoiseType noise_type,ExceptionInfo *exception)
6843{
6844  magick_unreferenced(image);
6845  magick_unreferenced(channel);
6846  magick_unreferenced(noise_type);
6847  magick_unreferenced(exception);
6848  return NULL;
6849}
6850
6851
6852MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception)
6853{
6854  magick_unreferenced(image);
6855  magick_unreferenced(exception);
6856  return MagickFalse;
6857}
6858
6859MagickExport
6860Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel,
6861                                const double* kernel, const size_t width,
6862                                const OffsetInfo *offset,
6863                                ExceptionInfo *exception)
6864{
6865  magick_unreferenced(image);
6866  magick_unreferenced(channel);
6867  magick_unreferenced(kernel);
6868  magick_unreferenced(width);
6869  magick_unreferenced(offset);
6870  magick_unreferenced(exception);
6871  return NULL;
6872}
6873
6874#endif /* MAGICKCORE_OPENCL_SUPPORT */
6875
6876MagickExport MagickBooleanType AccelerateConvolveImage(
6877  const Image *magick_unused(image),const KernelInfo *magick_unused(kernel),
6878  Image *magick_unused(convolve_image),ExceptionInfo *magick_unused(exception))
6879{
6880  magick_unreferenced(image);
6881  magick_unreferenced(kernel);
6882  magick_unreferenced(convolve_image);
6883  magick_unreferenced(exception);
6884
6885  /* legacy, do not use */
6886  return(MagickFalse);
6887}
6888
6889