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