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