]> granicus.if.org Git - imagemagick/blob - MagickCore/accelerate.c
The 8bim profile will be updated when the iptc profile is changed.
[imagemagick] / MagickCore / accelerate.c
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 /*
40 Include 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 */
94 inline static unsigned int 
95   padGlobalWorkgroupSizeToLocalWorkgroupSize(const unsigned int orgGlobalSize,
96                                              const unsigned int localGroupSize) 
97 {
98   return ((orgGlobalSize+(localGroupSize-1))/localGroupSize*localGroupSize);
99 }
100
101 static 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
130 static 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
155 static 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
173 static 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
435 cleanup:
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
497 MagickExport 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
518 static 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
655 cleanup:
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
668 MagickExport 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
692 static 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
715 static 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
1004 cleanup:
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
1026 static 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
1336 cleanup:
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
1396 MagickExport
1397 Image* 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
1422 static Image* ComputeRotationalBlurImage(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 rotationalBlurKernel;
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   rotationalBlurKernel = 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   rotationalBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RotationalBlur");
1586   if (rotationalBlurKernel == 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(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer);
1596   clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,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(rotationalBlurKernel,i++,sizeof(cl_float4), &biasPixel);
1604   clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(ChannelType), &channel);
1605
1606   matte = (inputImage->matte != MagickFalse)?1:0;
1607   clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(unsigned int), &matte);
1608
1609   clStatus=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_float2), &blurCenter);
1610
1611   clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&cosThetaBuffer);
1612   clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&sinThetaBuffer);
1613   clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,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, rotationalBlurKernel, 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
1649 cleanup:
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 (rotationalBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, rotationalBlurKernel);
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 o t a t i o n 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 %  RotationalBlurImage() applies a rotational blur to the image.
1681 %
1682 %  Andrew Protano contributed this effect.
1683 %
1684 %  The format of the RotationalBlurImage method is:
1685 %
1686 %    Image *RotationalBlurImage(const Image *image,const double angle,
1687 %      ExceptionInfo *exception)
1688 %    Image *RotationalBlurImageChannel(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 rotational blur.
1698 %
1699 %    o exception: return any errors or warnings in this structure.
1700 %
1701 */
1702
1703 MagickExport
1704 Image* AccelerateRotationalBlurImage(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 = ComputeRotationalBlurImage(image, channel, angle, exception);
1722   return filteredImage;
1723 }
1724
1725
1726
1727 static 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   
2013 cleanup:
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
2036 static 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   
2343 cleanup:
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
2412 MagickExport
2413 Image* 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
2439 static 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
2495 DisableMSCWarning(4127)
2496   while(1)
2497 RestoreMSCWarning
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
2614 cleanup:
2615   OpenCLLogException(__FUNCTION__,__LINE__,exception);
2616
2617   if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2618
2619   return status;
2620 }
2621
2622
2623 static 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
2679 DisableMSCWarning(4127)
2680   while(1)
2681 RestoreMSCWarning
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
2794 cleanup:
2795   OpenCLLogException(__FUNCTION__,__LINE__,exception);
2796
2797   if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2798
2799   return status;
2800 }
2801
2802
2803
2804 static 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
2993 cleanup:
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
3013 const ResizeWeightingFunctionType supportedResizeWeighting[] = 
3014 {
3015   BoxWeightingFunction
3016   ,TriangleWeightingFunction
3017   ,HanningWeightingFunction
3018   ,HammingWeightingFunction
3019   ,BlackmanWeightingFunction
3020   ,CubicBCWeightingFunction
3021   ,SincWeightingFunction
3022   ,SincFastWeightingFunction
3023   ,LastWeightingFunction
3024 };
3025
3026 static 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
3086 MagickExport
3087 Image* 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
3114 static 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
3211 cleanup:
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
3248 MagickExport
3249 MagickBooleanType 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
3270 MagickBooleanType 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
3408 cleanup:
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
3457 MagickExport
3458 MagickBooleanType 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
3481 MagickBooleanType 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
3606 cleanup:
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
3648 MagickExport
3649 MagickBooleanType 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
3670 MagickBooleanType 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
3800 cleanup:
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
3844 MagickExport
3845 MagickBooleanType 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
3871 static 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
3938 cleanup:
3939   OpenCLLogException(__FUNCTION__,__LINE__,exception);
3940  
3941   if (histogramKernel!=NULL)                     
3942     RelinquishOpenCLKernel(clEnv, histogramKernel);
3943
3944   return outputReady;
3945 }
3946
3947
3948 MagickExport 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
4331 cleanup:
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
4394 MagickExport
4395 MagickBooleanType 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
4420 MagickExport 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
4946 cleanup:
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
5022 MagickExport 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
5049 static 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
5331 cleanup:
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
5384 MagickExport
5385 Image* 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
5405 static 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
5626 cleanup:
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
5644 static 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
5890 cleanup:
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
5911 MagickExport 
5912 Image* 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
5929 DisableMSCWarning(4127)
5930   if (sizeof(unsigned long) == 4)
5931 RestoreMSCWarning
5932     filteredImage = ComputeAddNoiseImageOptRandomNum(image,channel,noise_type,exception);
5933   else
5934     filteredImage = ComputeAddNoiseImage(image,channel,noise_type,exception);
5935   
5936   return filteredImage;
5937 }
5938
5939 static 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
5987 cleanup:
5988   if (randomImageKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomImageKernel);
5989   return status;
5990 }
5991
5992 static 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
6084 cleanup:
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
6093 MagickExport 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
6109 static 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
6377 cleanup:
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
6397 MagickExport
6398 Image* 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
6425 static 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
6483 static 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
6604 cleanup:
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
6613 MagickExport
6614 MagickBooleanType 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
6661 MagickExport 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
6674 MagickExport 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
6691 MagickExport 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
6704 MagickExport Image *AccelerateRotationalBlurImage(
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
6717 MagickExport 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
6734 MagickExport
6735 MagickBooleanType 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   magick_unreferenced(channel);
6743   magick_unreferenced(compose);
6744   magick_unreferenced(composite);
6745   magick_unreferenced(x_offset);
6746   magick_unreferenced(y_offset);
6747   magick_unreferenced(destination_dissolve);
6748   magick_unreferenced(source_dissolve);
6749   magick_unreferenced(exception);
6750
6751   return MagickFalse;
6752 }
6753
6754
6755 MagickExport MagickBooleanType AccelerateContrastImage(
6756   Image* magick_unused(image),const MagickBooleanType magick_unused(sharpen),
6757   ExceptionInfo* magick_unused(exception))
6758 {
6759   magick_unreferenced(image);
6760   magick_unreferenced(sharpen);
6761   magick_unreferenced(exception);
6762
6763   return MagickFalse;
6764 }
6765
6766 MagickExport MagickBooleanType AccelerateContrastStretchImageChannel(
6767     Image * image, const ChannelType channel, const double black_point, const double white_point, 
6768     ExceptionInfo* magick_unused(exception))
6769 {
6770   magick_unreferenced(image);
6771   magick_unreferenced(channel);
6772   magick_unreferenced(black_point);
6773   magick_unreferenced(white_point);
6774   magick_unreferenced(exception);
6775
6776   return MagickFalse;
6777 }
6778
6779 MagickExport MagickBooleanType AccelerateEqualizeImage(
6780   Image* magick_unused(image), const ChannelType magick_unused(channel),
6781   ExceptionInfo* magick_unused(exception))
6782 {
6783   magick_unreferenced(image);
6784   magick_unreferenced(channel);
6785   magick_unreferenced(exception);
6786
6787   return MagickFalse;
6788 }
6789
6790 MagickExport Image *AccelerateDespeckleImage(const Image* magick_unused(image),
6791   ExceptionInfo* magick_unused(exception))
6792 {
6793   magick_unreferenced(image);
6794   magick_unreferenced(exception);
6795
6796   return NULL;
6797 }
6798
6799 MagickExport Image *AccelerateResizeImage(const Image* magick_unused(image),
6800   const size_t magick_unused(resizedColumns),
6801   const size_t magick_unused(resizedRows),
6802   const ResizeFilter* magick_unused(resizeFilter),
6803   ExceptionInfo *magick_unused(exception))
6804 {
6805   magick_unreferenced(image);
6806   magick_unreferenced(resizedColumns);
6807   magick_unreferenced(resizedRows);
6808   magick_unreferenced(resizeFilter);
6809   magick_unreferenced(exception);
6810
6811   return NULL;
6812 }
6813
6814 MagickExport
6815 MagickBooleanType AccelerateModulateImage(
6816   Image* image, double percent_brightness, double percent_hue, 
6817   double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
6818 {
6819   magick_unreferenced(image);
6820   magick_unreferenced(percent_brightness);
6821   magick_unreferenced(percent_hue);
6822   magick_unreferenced(percent_saturation);
6823   magick_unreferenced(colorspace);
6824   magick_unreferenced(exception);
6825   return(MagickFalse);
6826 }
6827
6828 MagickExport
6829 MagickBooleanType AccelerateNegateImageChannel(
6830   Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception)
6831 {
6832   magick_unreferenced(image);
6833   magick_unreferenced(channel);
6834   magick_unreferenced(grayscale);
6835   magick_unreferenced(exception);
6836   return(MagickFalse);
6837 }
6838
6839 MagickExport
6840 MagickBooleanType AccelerateGrayscaleImage(
6841   Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
6842 {
6843   magick_unreferenced(image);
6844   magick_unreferenced(method);
6845   magick_unreferenced(exception);
6846   return(MagickFalse);
6847 }
6848
6849 MagickExport Image *AccelerateAddNoiseImage(const Image *image, 
6850   const ChannelType channel, const NoiseType noise_type,ExceptionInfo *exception) 
6851 {
6852   magick_unreferenced(image);
6853   magick_unreferenced(channel);
6854   magick_unreferenced(noise_type);
6855   magick_unreferenced(exception);
6856   return NULL;
6857 }
6858
6859
6860 MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception)
6861 {
6862   magick_unreferenced(image);
6863   magick_unreferenced(exception);
6864   return MagickFalse;
6865 }
6866
6867 MagickExport
6868 Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel,
6869                                 const double* kernel, const size_t width,
6870                                 const OffsetInfo *offset, 
6871                                 ExceptionInfo *exception)
6872 {
6873   magick_unreferenced(image);
6874   magick_unreferenced(channel);
6875   magick_unreferenced(kernel);
6876   magick_unreferenced(width);
6877   magick_unreferenced(offset);
6878   magick_unreferenced(exception);
6879   return NULL;
6880 }
6881
6882 #endif /* MAGICKCORE_OPENCL_SUPPORT */
6883
6884 MagickExport MagickBooleanType AccelerateConvolveImage(
6885   const Image *magick_unused(image),const KernelInfo *magick_unused(kernel),
6886   Image *magick_unused(convolve_image),ExceptionInfo *magick_unused(exception))
6887 {
6888   magick_unreferenced(image);
6889   magick_unreferenced(kernel);
6890   magick_unreferenced(convolve_image);
6891   magick_unreferenced(exception);
6892
6893   /* legacy, do not use */
6894   return(MagickFalse);
6895 }
6896