2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 %
13 % MagickCore Acceleration Methods %
24 % Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
25 % dedicated to making software imaging solutions freely available. %
27 % You may not use this file except in compliance with the License. You may %
28 % obtain a copy of the License at %
30 % https://www.imagemagick.org/script/license.php %
32 % Unless required by applicable law or agreed to in writing, software %
33 % distributed under the License is distributed on an "AS IS" BASIS, %
34 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
35 % See the License for the specific language governing permissions and %
36 % limitations under the License. %
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/accelerate-private.h"
46 #include "MagickCore/accelerate-kernels-private.h"
47 #include "MagickCore/artifact.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/cache-private.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/color-private.h"
52 #include "MagickCore/delegate-private.h"
53 #include "MagickCore/enhance.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/gem.h"
57 #include "MagickCore/image.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/linked-list.h"
60 #include "MagickCore/list.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/opencl.h"
64 #include "MagickCore/opencl-private.h"
65 #include "MagickCore/option.h"
66 #include "MagickCore/pixel-accessor.h"
67 #include "MagickCore/pixel-private.h"
68 #include "MagickCore/prepress.h"
69 #include "MagickCore/quantize.h"
70 #include "MagickCore/quantum-private.h"
71 #include "MagickCore/random_.h"
72 #include "MagickCore/random-private.h"
73 #include "MagickCore/registry.h"
74 #include "MagickCore/resize.h"
75 #include "MagickCore/resize-private.h"
76 #include "MagickCore/semaphore.h"
77 #include "MagickCore/splay-tree.h"
78 #include "MagickCore/statistic.h"
79 #include "MagickCore/string_.h"
80 #include "MagickCore/string-private.h"
81 #include "MagickCore/token.h"
83 #define MAGICK_MAX(x,y) (((x) >= (y))?(x):(y))
84 #define MAGICK_MIN(x,y) (((x) <= (y))?(x):(y))
86 #if defined(MAGICKCORE_OPENCL_SUPPORT)
91 #define ALIGNED(pointer,type) ((((size_t)(pointer)) & (sizeof(type)-1)) == 0)
96 static const ResizeWeightingFunctionType supportedResizeWeighting[] =
99 TriangleWeightingFunction,
100 HannWeightingFunction,
101 HammingWeightingFunction,
102 BlackmanWeightingFunction,
103 CubicBCWeightingFunction,
104 SincWeightingFunction,
105 SincFastWeightingFunction,
106 LastWeightingFunction
112 static MagickBooleanType checkAccelerateCondition(const Image* image)
114 /* check if the image's colorspace is supported */
115 if (image->colorspace != RGBColorspace &&
116 image->colorspace != sRGBColorspace &&
117 image->colorspace != GRAYColorspace)
120 /* check if the virtual pixel method is compatible with the OpenCL implementation */
121 if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod) &&
122 (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod))
125 /* check if the image has read / write mask */
126 if (image->read_mask != MagickFalse || image->write_mask != MagickFalse)
129 if (image->number_channels > 4)
132 /* check if pixel order is R */
133 if (GetPixelChannelOffset(image,RedPixelChannel) != 0)
136 if (image->number_channels == 1)
139 /* check if pixel order is RA */
140 if ((image->number_channels == 2) &&
141 (GetPixelChannelOffset(image,AlphaPixelChannel) == 1))
144 if (image->number_channels == 2)
147 /* check if pixel order is RGB */
148 if ((GetPixelChannelOffset(image,GreenPixelChannel) != 1) ||
149 (GetPixelChannelOffset(image,BluePixelChannel) != 2))
152 if (image->number_channels == 3)
155 /* check if pixel order is RGBA */
156 if (GetPixelChannelOffset(image,AlphaPixelChannel) != 3)
162 static MagickBooleanType checkAccelerateConditionRGBA(const Image* image)
164 if (checkAccelerateCondition(image) == MagickFalse)
167 /* the order will be RGBA if the image has 4 channels */
168 if (image->number_channels != 4)
171 if ((GetPixelRedTraits(image) == UndefinedPixelTrait) ||
172 (GetPixelGreenTraits(image) == UndefinedPixelTrait) ||
173 (GetPixelBlueTraits(image) == UndefinedPixelTrait) ||
174 (GetPixelAlphaTraits(image) == UndefinedPixelTrait))
180 static MagickBooleanType checkPixelIntensity(const Image *image,
181 const PixelIntensityMethod method)
183 /* EncodePixelGamma and DecodePixelGamma are not supported */
184 if ((method == Rec601LumaPixelIntensityMethod) ||
185 (method == Rec709LumaPixelIntensityMethod))
187 if (image->colorspace == RGBColorspace)
191 if ((method == Rec601LuminancePixelIntensityMethod) ||
192 (method == Rec709LuminancePixelIntensityMethod))
194 if (image->colorspace == sRGBColorspace)
201 static MagickBooleanType checkHistogramCondition(const Image *image,
202 const PixelIntensityMethod method)
204 /* ensure this is the only pass get in for now. */
205 if ((image->channel_mask & SyncChannels) == 0)
208 return(checkPixelIntensity(image,method));
211 static MagickCLEnv getOpenCLEnvironment(ExceptionInfo* exception)
216 clEnv=GetCurrentOpenCLEnv();
217 if (clEnv == (MagickCLEnv) NULL)
218 return((MagickCLEnv) NULL);
220 if (clEnv->enabled == MagickFalse)
221 return((MagickCLEnv) NULL);
223 if (InitializeOpenCL(clEnv,exception) == MagickFalse)
224 return((MagickCLEnv) NULL);
229 static Image *cloneImage(const Image* image,ExceptionInfo *exception)
234 if (((image->channel_mask & RedChannel) != 0) &&
235 ((image->channel_mask & GreenChannel) != 0) &&
236 ((image->channel_mask & BlueChannel) != 0) &&
237 ((image->channel_mask & AlphaChannel) != 0))
238 clone=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
241 clone=CloneImage(image,0,0,MagickTrue,exception);
242 if (clone != (Image *) NULL)
243 SyncImagePixelCache(clone,exception);
248 /* pad the global workgroup size to the next multiple of
249 the local workgroup size */
250 inline static unsigned int padGlobalWorkgroupSizeToLocalWorkgroupSize(
251 const unsigned int orgGlobalSize,const unsigned int localGroupSize)
253 return ((orgGlobalSize+(localGroupSize-1))/localGroupSize*localGroupSize);
256 static cl_mem createKernelInfo(MagickCLDevice device,const double radius,
257 const double sigma,cl_uint *width,ExceptionInfo *exception)
260 geometry[MagickPathExtent];
277 (void) FormatLocaleString(geometry,MagickPathExtent,
278 "blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
279 kernel=AcquireKernelInfo(geometry,exception);
280 if (kernel == (KernelInfo *) NULL)
282 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
283 ResourceLimitWarning,"AcquireKernelInfo failed.",".");
284 return((cl_mem) NULL);
286 kernelBufferPtr=(float *)AcquireMagickMemory(kernel->width*
287 sizeof(*kernelBufferPtr));
288 for (i = 0; i < (ssize_t) kernel->width; i++)
289 kernelBufferPtr[i] = (float)kernel->values[i];
290 imageKernelBuffer=CreateOpenCLBuffer(device,CL_MEM_COPY_HOST_PTR |
291 CL_MEM_READ_ONLY,kernel->width*sizeof(*kernelBufferPtr),kernelBufferPtr);
292 *width=(cl_uint) kernel->width;
293 kernelBufferPtr=(float *) RelinquishMagickMemory(kernelBufferPtr);
294 kernel=DestroyKernelInfo(kernel);
295 if (imageKernelBuffer == (cl_mem) NULL)
296 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
297 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
298 return(imageKernelBuffer);
301 static MagickBooleanType LaunchHistogramKernel(MagickCLEnv clEnv,
302 MagickCLDevice device,cl_command_queue queue,cl_mem imageBuffer,
303 cl_mem histogramBuffer,Image *image,const ChannelType channel,
304 ExceptionInfo *exception)
328 histogramKernel = NULL;
330 outputReady = MagickFalse;
331 colorspace = image->colorspace;
332 method = image->intensity;
334 /* get the OpenCL kernel */
335 histogramKernel = AcquireOpenCLKernel(device,"Histogram");
336 if (histogramKernel == NULL)
338 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
342 /* set the kernel arguments */
344 clStatus=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
345 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(ChannelType),&channel);
346 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_uint),&colorspace);
347 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_uint),&method);
348 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&histogramBuffer);
349 if (clStatus != CL_SUCCESS)
351 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
355 /* launch the kernel */
356 global_work_size[0] = image->columns;
357 global_work_size[1] = image->rows;
359 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, histogramKernel, 2, NULL, global_work_size, NULL, 0, NULL, &event);
361 if (clStatus != CL_SUCCESS)
363 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
366 RecordProfileData(device,histogramKernel,event);
368 outputReady = MagickTrue;
372 if (histogramKernel!=NULL)
373 ReleaseOpenCLKernel(histogramKernel);
379 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 % A c c e l e r a t e A d d N o i s e I m a g e %
387 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 static Image *ComputeAddNoiseImage(const Image *image,MagickCLEnv clEnv,
391 const NoiseType noise_type,ExceptionInfo *exception)
413 numRandomNumberPerPixel,
445 outputReady=MagickFalse;
447 device=RequestOpenCLDevice(clEnv);
448 queue=AcquireOpenCLCommandQueue(device);
449 if (queue == (cl_command_queue) NULL)
451 filteredImage=cloneImage(image,exception);
452 if (filteredImage == (Image *) NULL)
454 if (filteredImage->number_channels != image->number_channels)
456 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
457 if (imageBuffer == (cl_mem) NULL)
459 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
460 if (filteredImageBuffer == (cl_mem) NULL)
463 /* find out how many random numbers needed by pixel */
465 numRandomNumberPerPixel=0;
476 case MultiplicativeGaussianNoise:
481 if (GetPixelRedTraits(image) != UndefinedPixelTrait)
482 numRandomNumberPerPixel+=(cl_uint) numRandPerChannel;
483 if (GetPixelGreenTraits(image) != UndefinedPixelTrait)
484 numRandomNumberPerPixel+=(cl_uint) numRandPerChannel;
485 if (GetPixelBlueTraits(image) != UndefinedPixelTrait)
486 numRandomNumberPerPixel+=(cl_uint) numRandPerChannel;
487 if (GetPixelAlphaTraits(image) != UndefinedPixelTrait)
488 numRandomNumberPerPixel+=(cl_uint) numRandPerChannel;
490 addNoiseKernel=AcquireOpenCLKernel(device,"AddNoise");
491 if (addNoiseKernel == (cl_kernel) NULL)
493 (void)OpenCLThrowMagickException(device,exception,GetMagickModule(),
494 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
498 /* 256 work items per group, 2 groups per CU */
499 workItemCount=device->max_compute_units*2*256;
500 inputPixelCount=(cl_int) (image->columns*image->rows);
501 pixelsPerWorkitem=(inputPixelCount+workItemCount-1)/workItemCount;
502 pixelsPerWorkitem=((pixelsPerWorkitem+3)/4)*4;
504 gsize[0]=workItemCount;
506 randomInfo=AcquireRandomInfo();
507 s=GetRandomInfoSeed(randomInfo);
509 (void) GetPseudoRandomValue(randomInfo);
511 randomInfo=DestroyRandomInfo(randomInfo);
513 number_channels=(cl_uint) image->number_channels;
514 bufferLength=(cl_uint) (image->columns*image->rows*image->number_channels);
516 option=GetImageArtifact(image,"attenuate");
517 if (option != (char *) NULL)
518 attenuate=(float)StringToDouble(option,(char **) NULL);
521 status =SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
522 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_uint),(void *)&number_channels);
523 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(ChannelType),(void *)&image->channel_mask);
524 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_uint),(void *)&bufferLength);
525 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_uint),(void *)&pixelsPerWorkitem);
526 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(NoiseType),(void *)&noise_type);
527 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_float),(void *)&attenuate);
528 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_uint),(void *)&seed0);
529 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_uint),(void *)&seed1);
530 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_uint),(void *)&numRandomNumberPerPixel);
531 status|=SetOpenCLKernelArg(addNoiseKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
532 if (status != CL_SUCCESS)
534 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
535 ResourceLimitWarning,"clSetKernelArg failed.",".");
539 outputReady=EnqueueOpenCLKernel(queue,addNoiseKernel,1,(const size_t *) NULL,gsize,
540 lsize,image,filteredImage,MagickFalse,exception);
544 if (addNoiseKernel != (cl_kernel) NULL)
545 ReleaseOpenCLKernel(addNoiseKernel);
546 if (queue != (cl_command_queue) NULL)
547 ReleaseOpenCLCommandQueue(device,queue);
548 if (device != (MagickCLDevice) NULL)
549 ReleaseOpenCLDevice(device);
550 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
551 filteredImage=DestroyImage(filteredImage);
553 return(filteredImage);
556 MagickPrivate Image *AccelerateAddNoiseImage(const Image *image,
557 const NoiseType noise_type,ExceptionInfo *exception)
565 assert(image != NULL);
566 assert(exception != (ExceptionInfo *) NULL);
568 if (checkAccelerateCondition(image) == MagickFalse)
569 return((Image *) NULL);
571 clEnv=getOpenCLEnvironment(exception);
572 if (clEnv == (MagickCLEnv) NULL)
573 return((Image *) NULL);
575 filteredImage=ComputeAddNoiseImage(image,clEnv,noise_type,exception);
576 return(filteredImage);
580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 % A c c e l e r a t e B l u r I m a g e %
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591 static Image *ComputeBlurImage(const Image* image,MagickCLEnv clEnv,
592 const double radius,const double sigma,ExceptionInfo *exception)
635 tempImageBuffer=NULL;
636 imageKernelBuffer=NULL;
638 blurColumnKernel=NULL;
639 outputReady=MagickFalse;
641 device=RequestOpenCLDevice(clEnv);
642 queue=AcquireOpenCLCommandQueue(device);
643 filteredImage=cloneImage(image,exception);
644 if (filteredImage == (Image *) NULL)
646 if (filteredImage->number_channels != image->number_channels)
648 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
649 if (imageBuffer == (cl_mem) NULL)
651 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
652 if (filteredImageBuffer == (cl_mem) NULL)
655 imageKernelBuffer=createKernelInfo(device,radius,sigma,&kernelWidth,
657 if (imageKernelBuffer == (cl_mem) NULL)
660 length=image->columns*image->rows;
661 tempImageBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_WRITE,length*
662 sizeof(cl_float4),(void *) NULL);
663 if (tempImageBuffer == (cl_mem) NULL)
666 blurRowKernel=AcquireOpenCLKernel(device,"BlurRow");
667 if (blurRowKernel == (cl_kernel) NULL)
669 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
670 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
674 number_channels=(cl_uint) image->number_channels;
675 imageColumns=(cl_uint) image->columns;
676 imageRows=(cl_uint) image->rows;
679 status =SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
680 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),&number_channels);
681 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(ChannelType),&image->channel_mask);
682 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
683 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),(void *)&kernelWidth);
684 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),(void *)&imageColumns);
685 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),(void *)&imageRows);
686 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_float4)*(chunkSize+kernelWidth),(void *) NULL);
687 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
688 if (status != CL_SUCCESS)
690 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
691 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
695 gsize[0]=chunkSize*((image->columns+chunkSize-1)/chunkSize);
696 gsize[1]=image->rows;
700 outputReady=EnqueueOpenCLKernel(queue,blurRowKernel,2,(size_t *) NULL,gsize,
701 lsize,image,filteredImage,MagickFalse,exception);
702 if (outputReady == MagickFalse)
705 blurColumnKernel=AcquireOpenCLKernel(device,"BlurColumn");
706 if (blurColumnKernel == (cl_kernel) NULL)
708 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
709 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
714 status =SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
715 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_uint),&number_channels);
716 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&image->channel_mask);
717 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
718 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_uint),(void *)&kernelWidth);
719 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_uint),(void *)&imageColumns);
720 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_uint),(void *)&imageRows);
721 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernelWidth),(void *) NULL);
722 status|=SetOpenCLKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
723 if (status != CL_SUCCESS)
725 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
726 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
730 gsize[0]=image->columns;
731 gsize[1]=chunkSize*((image->rows+chunkSize-1)/chunkSize);
735 outputReady=EnqueueOpenCLKernel(queue,blurColumnKernel,2,(size_t *) NULL,gsize,
736 lsize,image,filteredImage,MagickFalse,exception);
740 if (tempImageBuffer != (cl_mem) NULL)
741 ReleaseOpenCLMemObject(tempImageBuffer);
742 if (imageKernelBuffer != (cl_mem) NULL)
743 ReleaseOpenCLMemObject(imageKernelBuffer);
744 if (blurRowKernel != (cl_kernel) NULL)
745 ReleaseOpenCLKernel(blurRowKernel);
746 if (blurColumnKernel != (cl_kernel) NULL)
747 ReleaseOpenCLKernel(blurColumnKernel);
748 if (queue != (cl_command_queue) NULL)
749 ReleaseOpenCLCommandQueue(device,queue);
750 if (device != (MagickCLDevice) NULL)
751 ReleaseOpenCLDevice(device);
752 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
753 filteredImage=DestroyImage(filteredImage);
755 return(filteredImage);
758 MagickPrivate Image* AccelerateBlurImage(const Image *image,
759 const double radius,const double sigma,ExceptionInfo *exception)
767 assert(image != NULL);
768 assert(exception != (ExceptionInfo *) NULL);
770 if (checkAccelerateCondition(image) == MagickFalse)
771 return((Image *) NULL);
773 clEnv=getOpenCLEnvironment(exception);
774 if (clEnv == (MagickCLEnv) NULL)
775 return((Image *) NULL);
777 filteredImage=ComputeBlurImage(image,clEnv,radius,sigma,exception);
778 return(filteredImage);
782 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
786 % A c c e l e r a t e C o n t r a s t I m a g e %
790 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
793 static MagickBooleanType ComputeContrastImage(Image *image,MagickCLEnv clEnv,
794 const MagickBooleanType sharpen,ExceptionInfo *exception)
826 outputReady=MagickFalse;
828 device=RequestOpenCLDevice(clEnv);
829 queue=AcquireOpenCLCommandQueue(device);
830 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
831 if (imageBuffer == (cl_mem) NULL)
834 contrastKernel=AcquireOpenCLKernel(device,"Contrast");
835 if (contrastKernel == (cl_kernel) NULL)
837 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
838 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
842 number_channels=(cl_uint) image->number_channels;
843 sign=sharpen != MagickFalse ? 1 : -1;
846 status =SetOpenCLKernelArg(contrastKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
847 status|=SetOpenCLKernelArg(contrastKernel,i++,sizeof(cl_uint),&number_channels);
848 status|=SetOpenCLKernelArg(contrastKernel,i++,sizeof(cl_int),&sign);
849 if (status != CL_SUCCESS)
851 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
852 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
856 gsize[0]=image->columns;
857 gsize[1]=image->rows;
859 outputReady=EnqueueOpenCLKernel(queue,contrastKernel,2,(const size_t *) NULL,
860 gsize,(const size_t *) NULL,image,(Image *) NULL,MagickFalse,exception);
864 if (contrastKernel != (cl_kernel) NULL)
865 ReleaseOpenCLKernel(contrastKernel);
866 if (queue != (cl_command_queue) NULL)
867 ReleaseOpenCLCommandQueue(device,queue);
868 if (device != (MagickCLDevice) NULL)
869 ReleaseOpenCLDevice(device);
874 MagickPrivate MagickBooleanType AccelerateContrastImage(Image *image,
875 const MagickBooleanType sharpen,ExceptionInfo *exception)
883 assert(image != NULL);
884 assert(exception != (ExceptionInfo *) NULL);
886 if (checkAccelerateCondition(image) == MagickFalse)
889 clEnv=getOpenCLEnvironment(exception);
890 if (clEnv == (MagickCLEnv) NULL)
893 status=ComputeContrastImage(image,clEnv,sharpen,exception);
898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902 % 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 %
906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 static MagickBooleanType ComputeContrastStretchImage(Image *image,
910 MagickCLEnv clEnv,const double black_point,const double white_point,
911 ExceptionInfo *exception)
913 #define ContrastStretchImageTag "ContrastStretch/Image"
914 #define MaxRange(color) ((cl_float) ScaleQuantumToMap((Quantum) (color)))
977 histogramBuffer = NULL;
978 stretchMapBuffer = NULL;
979 histogramKernel = NULL;
980 stretchKernel = NULL;
982 outputReady = MagickFalse;
985 assert(image != (Image *) NULL);
986 assert(image->signature == MagickCoreSignature);
987 if (image->debug != MagickFalse)
988 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
990 //exception=(&image->exception);
993 * initialize opencl env
995 device = RequestOpenCLDevice(clEnv);
996 queue = AcquireOpenCLCommandQueue(device);
999 Allocate and initialize histogram arrays.
1001 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
1003 if (histogram == (cl_uint4 *) NULL)
1004 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename);
1006 /* reset histogram */
1007 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
1010 if (IsGrayImage(image,exception) != MagickFalse)
1011 (void) SetImageColorspace(image,GRAYColorspace);
1020 /* Create and initialize OpenCL buffers. */
1021 /* inputPixels = AcquirePixelCachePixels(image, &length, exception); */
1022 /* assume this will get a writable image */
1023 image_view=AcquireAuthenticCacheView(image,exception);
1024 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
1026 if (inputPixels == (void *) NULL)
1028 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
1031 /* If the host pointer is aligned to the size of CLPixelPacket,
1032 then use the host buffer directly from the GPU; otherwise,
1033 create a buffer on the GPU and copy the data over */
1034 if (ALIGNED(inputPixels,CLPixelPacket))
1036 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1040 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1042 /* create a CL buffer from image pixel buffer */
1043 length = image->columns * image->rows;
1044 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1045 if (clStatus != CL_SUCCESS)
1047 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1051 /* If the host pointer is aligned to the size of cl_uint,
1052 then use the host buffer directly from the GPU; otherwise,
1053 create a buffer on the GPU and copy the data over */
1054 if (ALIGNED(histogram,cl_uint4))
1056 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
1057 hostPtr = histogram;
1061 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
1062 hostPtr = histogram;
1064 /* create a CL buffer for histogram */
1065 length = (MaxMap+1);
1066 histogramBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
1067 if (clStatus != CL_SUCCESS)
1069 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1073 status = LaunchHistogramKernel(clEnv, device, queue, imageBuffer, histogramBuffer, image, image->channel_mask,exception);
1074 if (status == MagickFalse)
1077 /* read from the kenel output */
1078 if (ALIGNED(histogram,cl_uint4))
1080 length = (MaxMap+1);
1081 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
1085 length = (MaxMap+1);
1086 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
1088 if (clStatus != CL_SUCCESS)
1090 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
1094 /* unmap, don't block gpu to use this buffer again. */
1095 if (ALIGNED(histogram,cl_uint4))
1097 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
1098 if (clStatus != CL_SUCCESS)
1100 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", ".");
1105 /* recreate input buffer later, in case image updated */
1106 #ifdef RECREATEBUFFER
1107 if (imageBuffer!=NULL)
1108 clEnv->library->clReleaseMemObject(imageBuffer);
1113 Find the histogram boundaries by locating the black/white levels.
1116 white.x=MaxRange(QuantumRange);
1117 if ((image->channel_mask & RedChannel) != 0)
1120 for (i=0; i <= (ssize_t) MaxMap; i++)
1122 intensity+=histogram[i].s[2];
1123 if (intensity > black_point)
1126 black.x=(cl_float) i;
1128 for (i=(ssize_t) MaxMap; i != 0; i--)
1130 intensity+=histogram[i].s[2];
1131 if (intensity > ((double) image->columns*image->rows-white_point))
1134 white.x=(cl_float) i;
1137 white.y=MaxRange(QuantumRange);
1138 if ((image->channel_mask & GreenChannel) != 0)
1141 for (i=0; i <= (ssize_t) MaxMap; i++)
1143 intensity+=histogram[i].s[2];
1144 if (intensity > black_point)
1147 black.y=(cl_float) i;
1149 for (i=(ssize_t) MaxMap; i != 0; i--)
1151 intensity+=histogram[i].s[2];
1152 if (intensity > ((double) image->columns*image->rows-white_point))
1155 white.y=(cl_float) i;
1158 white.z=MaxRange(QuantumRange);
1159 if ((image->channel_mask & BlueChannel) != 0)
1162 for (i=0; i <= (ssize_t) MaxMap; i++)
1164 intensity+=histogram[i].s[2];
1165 if (intensity > black_point)
1168 black.z=(cl_float) i;
1170 for (i=(ssize_t) MaxMap; i != 0; i--)
1172 intensity+=histogram[i].s[2];
1173 if (intensity > ((double) image->columns*image->rows-white_point))
1176 white.z=(cl_float) i;
1179 white.w=MaxRange(QuantumRange);
1180 if ((image->channel_mask & AlphaChannel) != 0)
1183 for (i=0; i <= (ssize_t) MaxMap; i++)
1185 intensity+=histogram[i].s[2];
1186 if (intensity > black_point)
1189 black.w=(cl_float) i;
1191 for (i=(ssize_t) MaxMap; i != 0; i--)
1193 intensity+=histogram[i].s[2];
1194 if (intensity > ((double) image->columns*image->rows-white_point))
1197 white.w=(cl_float) i;
1200 stretch_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
1201 sizeof(*stretch_map));
1203 if (stretch_map == (PixelPacket *) NULL)
1204 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
1208 Stretch the histogram to create the stretched image mapping.
1210 (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map));
1211 for (i=0; i <= (ssize_t) MaxMap; i++)
1213 if ((image->channel_mask & RedChannel) != 0)
1215 if (i < (ssize_t) black.x)
1216 stretch_map[i].red=(Quantum) 0;
1218 if (i > (ssize_t) white.x)
1219 stretch_map[i].red=QuantumRange;
1221 if (black.x != white.x)
1222 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
1223 (i-black.x)/(white.x-black.x)));
1225 if ((image->channel_mask & GreenChannel) != 0)
1227 if (i < (ssize_t) black.y)
1228 stretch_map[i].green=0;
1230 if (i > (ssize_t) white.y)
1231 stretch_map[i].green=QuantumRange;
1233 if (black.y != white.y)
1234 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
1235 (i-black.y)/(white.y-black.y)));
1237 if ((image->channel_mask & BlueChannel) != 0)
1239 if (i < (ssize_t) black.z)
1240 stretch_map[i].blue=0;
1242 if (i > (ssize_t) white.z)
1243 stretch_map[i].blue= QuantumRange;
1245 if (black.z != white.z)
1246 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
1247 (i-black.z)/(white.z-black.z)));
1249 if ((image->channel_mask & AlphaChannel) != 0)
1251 if (i < (ssize_t) black.w)
1252 stretch_map[i].alpha=0;
1254 if (i > (ssize_t) white.w)
1255 stretch_map[i].alpha=QuantumRange;
1257 if (black.w != white.w)
1258 stretch_map[i].alpha=ScaleMapToQuantum((MagickRealType) (MaxMap*
1259 (i-black.w)/(white.w-black.w)));
1266 if (((image->channel_mask & AlphaChannel) != 0) || (((image->channel_mask & IndexChannel) != 0) &&
1267 (image->colorspace == CMYKColorspace)))
1268 image->storage_class=DirectClass;
1269 if (image->storage_class == PseudoClass)
1274 for (i=0; i < (ssize_t) image->colors; i++)
1276 if ((image->channel_mask & RedChannel) != 0)
1278 if (black.x != white.x)
1279 image->colormap[i].red=stretch_map[
1280 ScaleQuantumToMap(image->colormap[i].red)].red;
1282 if ((image->channel_mask & GreenChannel) != 0)
1284 if (black.y != white.y)
1285 image->colormap[i].green=stretch_map[
1286 ScaleQuantumToMap(image->colormap[i].green)].green;
1288 if ((image->channel_mask & BlueChannel) != 0)
1290 if (black.z != white.z)
1291 image->colormap[i].blue=stretch_map[
1292 ScaleQuantumToMap(image->colormap[i].blue)].blue;
1294 if ((image->channel_mask & AlphaChannel) != 0)
1296 if (black.w != white.w)
1297 image->colormap[i].alpha=stretch_map[
1298 ScaleQuantumToMap(image->colormap[i].alpha)].alpha;
1308 /* GPU can work on this again, image and equalize map as input
1309 image: uchar4 (CLPixelPacket)
1310 stretch_map: uchar4 (PixelPacket)
1311 black, white: float4 (FloatPixelPacket) */
1313 #ifdef RECREATEBUFFER
1314 /* If the host pointer is aligned to the size of CLPixelPacket,
1315 then use the host buffer directly from the GPU; otherwise,
1316 create a buffer on the GPU and copy the data over */
1317 if (ALIGNED(inputPixels,CLPixelPacket))
1319 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
1323 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
1325 /* create a CL buffer from image pixel buffer */
1326 length = image->columns * image->rows;
1327 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1328 if (clStatus != CL_SUCCESS)
1330 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1335 /* Create and initialize OpenCL buffers. */
1336 if (ALIGNED(stretch_map, PixelPacket))
1338 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1339 hostPtr = stretch_map;
1343 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
1344 hostPtr = stretch_map;
1346 /* create a CL buffer for stretch_map */
1347 length = (MaxMap+1);
1348 stretchMapBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
1349 if (clStatus != CL_SUCCESS)
1351 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1355 /* get the OpenCL kernel */
1356 stretchKernel = AcquireOpenCLKernel(device,"ContrastStretch");
1357 if (stretchKernel == NULL)
1359 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
1363 /* set the kernel arguments */
1365 clStatus=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
1366 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(ChannelType),&image->channel_mask);
1367 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&stretchMapBuffer);
1368 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_float4),&white);
1369 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_float4),&black);
1370 if (clStatus != CL_SUCCESS)
1372 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
1376 /* launch the kernel */
1377 global_work_size[0] = image->columns;
1378 global_work_size[1] = image->rows;
1380 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, stretchKernel, 2, NULL, global_work_size, NULL, 0, NULL, &event);
1382 if (clStatus != CL_SUCCESS)
1384 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
1387 RecordProfileData(device,stretchKernel,event);
1389 /* read the data back */
1390 if (ALIGNED(inputPixels,CLPixelPacket))
1392 length = image->columns * image->rows;
1393 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
1397 length = image->columns * image->rows;
1398 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
1400 if (clStatus != CL_SUCCESS)
1402 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
1406 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
1410 image_view=DestroyCacheView(image_view);
1412 if (imageBuffer!=NULL)
1413 clEnv->library->clReleaseMemObject(imageBuffer);
1415 if (stretchMapBuffer!=NULL)
1416 clEnv->library->clReleaseMemObject(stretchMapBuffer);
1417 if (stretch_map!=NULL)
1418 stretch_map=(PixelPacket *) RelinquishMagickMemory(stretch_map);
1419 if (histogramBuffer!=NULL)
1420 clEnv->library->clReleaseMemObject(histogramBuffer);
1421 if (histogram!=NULL)
1422 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
1423 if (histogramKernel!=NULL)
1424 ReleaseOpenCLKernel(histogramKernel);
1425 if (stretchKernel!=NULL)
1426 ReleaseOpenCLKernel(stretchKernel);
1428 ReleaseOpenCLCommandQueue(device,queue);
1430 ReleaseOpenCLDevice(device);
1432 return(outputReady);
1435 MagickPrivate MagickBooleanType AccelerateContrastStretchImage(
1436 Image *image,const double black_point,const double white_point,
1437 ExceptionInfo *exception)
1445 assert(image != NULL);
1446 assert(exception != (ExceptionInfo *) NULL);
1448 if ((checkAccelerateConditionRGBA(image) == MagickFalse) ||
1449 (checkHistogramCondition(image,image->intensity) == MagickFalse))
1450 return(MagickFalse);
1452 clEnv=getOpenCLEnvironment(exception);
1453 if (clEnv == (MagickCLEnv) NULL)
1454 return(MagickFalse);
1456 status=ComputeContrastStretchImage(image,clEnv,black_point,white_point,
1462 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1466 % A c c e l e r a t e C o n v o l v e I m a g e %
1470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1473 static Image *ComputeConvolveImage(const Image* image,MagickCLEnv clEnv,
1474 const KernelInfo *kernel,ExceptionInfo *exception)
1477 *filteredImage_view,
1494 filteredImageBuffer,
1519 global_work_size[3],
1521 localMemoryRequirement;
1538 /* intialize all CL objects to NULL */
1540 filteredImageBuffer = NULL;
1541 convolutionKernel = NULL;
1545 filteredImage = NULL;
1546 filteredImage_view = NULL;
1547 outputReady = MagickFalse;
1549 device = RequestOpenCLDevice(clEnv);
1551 image_view=AcquireAuthenticCacheView(image,exception);
1552 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
1553 if (inputPixels == (const void *) NULL)
1555 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
1559 /* Create and initialize OpenCL buffers. */
1561 /* If the host pointer is aligned to the size of CLPixelPacket,
1562 then use the host buffer directly from the GPU; otherwise,
1563 create a buffer on the GPU and copy the data over */
1564 if (ALIGNED(inputPixels,CLPixelPacket))
1566 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1570 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1572 /* create a CL buffer from image pixel buffer */
1573 length = image->columns * image->rows;
1574 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1575 if (clStatus != CL_SUCCESS)
1577 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1581 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1582 assert(filteredImage != NULL);
1583 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
1585 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", ".");
1588 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
1589 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
1590 if (filteredPixels == (void *) NULL)
1592 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
1596 if (ALIGNED(filteredPixels,CLPixelPacket))
1598 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1599 hostPtr = filteredPixels;
1603 mem_flags = CL_MEM_WRITE_ONLY;
1606 /* create a CL buffer from image pixel buffer */
1607 length = image->columns * image->rows;
1608 filteredImageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
1609 if (clStatus != CL_SUCCESS)
1611 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1615 kernelSize = (unsigned int) (kernel->width * kernel->height);
1616 convolutionKernel = clEnv->library->clCreateBuffer(device->context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernelSize * sizeof(float), NULL, &clStatus);
1617 if (clStatus != CL_SUCCESS)
1619 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1623 queue = AcquireOpenCLCommandQueue(device);
1625 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, convolutionKernel, CL_TRUE, CL_MAP_WRITE, 0, kernelSize * sizeof(float)
1626 , 0, NULL, NULL, &clStatus);
1627 if (clStatus != CL_SUCCESS)
1629 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
1632 for (i = 0; i < kernelSize; i++)
1634 kernelBufferPtr[i] = (float) kernel->values[i];
1636 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, convolutionKernel, kernelBufferPtr, 0, NULL, NULL);
1637 if (clStatus != CL_SUCCESS)
1639 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", ".");
1643 /* Compute the local memory requirement for a 16x16 workgroup.
1644 If it's larger than 16k, reduce the workgroup size to 8x8 */
1645 localGroupSize[0] = 16;
1646 localGroupSize[1] = 16;
1647 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
1648 + kernel->width*kernel->height*sizeof(float);
1650 if (localMemoryRequirement > device->local_memory_size)
1652 localGroupSize[0] = 8;
1653 localGroupSize[1] = 8;
1654 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
1655 + kernel->width*kernel->height*sizeof(float);
1657 if (localMemoryRequirement <= device->local_memory_size)
1659 /* get the OpenCL kernel */
1660 clkernel = AcquireOpenCLKernel(device,"ConvolveOptimized");
1661 if (clkernel == NULL)
1663 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
1667 /* set the kernel arguments */
1669 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
1670 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1671 imageWidth = (unsigned int) image->columns;
1672 imageHeight = (unsigned int) image->rows;
1673 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
1674 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
1675 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
1676 filterWidth = (unsigned int) kernel->width;
1677 filterHeight = (unsigned int) kernel->height;
1678 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
1679 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
1680 matte = (image->alpha_trait > CopyPixelTrait)?1:0;
1681 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
1682 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&image->channel_mask);
1683 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, (localGroupSize[0] + kernel->width-1)*(localGroupSize[1] + kernel->height-1)*sizeof(CLPixelPacket),NULL);
1684 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, kernel->width*kernel->height*sizeof(float),NULL);
1685 if (clStatus != CL_SUCCESS)
1687 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
1691 /* pad the global size to a multiple of the local work size dimension */
1692 global_work_size[0] = ((image->columns + localGroupSize[0] - 1)/localGroupSize[0] ) * localGroupSize[0] ;
1693 global_work_size[1] = ((image->rows + localGroupSize[1] - 1)/localGroupSize[1]) * localGroupSize[1];
1695 /* launch the kernel */
1696 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, &event);
1697 if (clStatus != CL_SUCCESS)
1699 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
1702 RecordProfileData(device,clkernel,event);
1706 /* get the OpenCL kernel */
1707 clkernel = AcquireOpenCLKernel(device,"Convolve");
1708 if (clkernel == NULL)
1710 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
1714 /* set the kernel arguments */
1716 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
1717 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1718 imageWidth = (unsigned int) image->columns;
1719 imageHeight = (unsigned int) image->rows;
1720 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
1721 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
1722 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
1723 filterWidth = (unsigned int) kernel->width;
1724 filterHeight = (unsigned int) kernel->height;
1725 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
1726 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
1727 matte = (image->alpha_trait > CopyPixelTrait)?1:0;
1728 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
1729 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&image->channel_mask);
1730 if (clStatus != CL_SUCCESS)
1732 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
1736 localGroupSize[0] = 8;
1737 localGroupSize[1] = 8;
1738 global_work_size[0] = (image->columns + (localGroupSize[0]-1))/localGroupSize[0] * localGroupSize[0];
1739 global_work_size[1] = (image->rows + (localGroupSize[1]-1))/localGroupSize[1] * localGroupSize[1];
1740 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, &event);
1742 if (clStatus != CL_SUCCESS)
1744 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
1748 RecordProfileData(device,clkernel,event);
1750 if (ALIGNED(filteredPixels,CLPixelPacket))
1752 length = image->columns * image->rows;
1753 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
1757 length = image->columns * image->rows;
1758 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
1760 if (clStatus != CL_SUCCESS)
1762 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
1766 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
1770 image_view=DestroyCacheView(image_view);
1771 if (filteredImage_view != NULL)
1772 filteredImage_view=DestroyCacheView(filteredImage_view);
1773 if (imageBuffer != NULL)
1774 clEnv->library->clReleaseMemObject(imageBuffer);
1775 if (filteredImageBuffer != NULL)
1776 clEnv->library->clReleaseMemObject(filteredImageBuffer);
1777 if (convolutionKernel != NULL)
1778 clEnv->library->clReleaseMemObject(convolutionKernel);
1779 if (clkernel != NULL)
1780 ReleaseOpenCLKernel(clkernel);
1782 ReleaseOpenCLCommandQueue(device,queue);
1784 ReleaseOpenCLDevice(device);
1785 if (outputReady == MagickFalse)
1787 if (filteredImage != NULL)
1789 DestroyImage(filteredImage);
1790 filteredImage = NULL;
1794 return(filteredImage);
1797 MagickPrivate Image *AccelerateConvolveImage(const Image *image,
1798 const KernelInfo *kernel,ExceptionInfo *exception)
1800 /* Temporary disabled due to access violation
1805 assert(image != NULL);
1806 assert(kernel != (KernelInfo *) NULL);
1807 assert(exception != (ExceptionInfo *) NULL);
1808 if ((checkAccelerateConditionRGBA(image) == MagickFalse) ||
1809 (checkOpenCLEnvironment(exception) == MagickFalse))
1810 return((Image *) NULL);
1812 filteredImage=ComputeConvolveImage(image,kernel,exception);
1813 return(filteredImage);
1815 magick_unreferenced(image);
1816 magick_unreferenced(kernel);
1817 magick_unreferenced(exception);
1818 return((Image *)NULL);
1822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1826 % A c c e l e r a t e D e s p e c k l e I m a g e %
1830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833 static Image *ComputeDespeckleImage(const Image *image,MagickCLEnv clEnv,
1834 ExceptionInfo*exception)
1837 X[4] = {0, 1, 1,-1},
1838 Y[4] = {1, 0, 1, 1};
1841 *filteredImage_view,
1861 filteredImageBuffer,
1885 global_work_size[2];
1895 outputReady = MagickFalse;
1897 filteredImage = NULL;
1898 filteredImage_view = NULL;
1899 filteredPixels = NULL;
1901 filteredImageBuffer = NULL;
1905 tempImageBuffer[0] = tempImageBuffer[1] = NULL;
1907 device = RequestOpenCLDevice(clEnv);
1908 queue = AcquireOpenCLCommandQueue(device);
1910 image_view=AcquireAuthenticCacheView(image,exception);
1911 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
1912 if (inputPixels == (void *) NULL)
1914 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
1918 if (ALIGNED(inputPixels,CLPixelPacket))
1920 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1924 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1926 /* create a CL buffer from image pixel buffer */
1927 length = image->columns * image->rows;
1928 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
1929 if (clStatus != CL_SUCCESS)
1931 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1935 mem_flags = CL_MEM_READ_WRITE;
1936 length = image->columns * image->rows;
1937 for (k = 0; k < 2; k++)
1939 tempImageBuffer[k] = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), NULL, &clStatus);
1940 if (clStatus != CL_SUCCESS)
1942 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1947 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1948 assert(filteredImage != NULL);
1949 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
1951 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", ".");
1954 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
1955 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
1956 if (filteredPixels == (void *) NULL)
1958 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
1962 if (ALIGNED(filteredPixels,CLPixelPacket))
1964 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1965 hostPtr = filteredPixels;
1969 mem_flags = CL_MEM_WRITE_ONLY;
1972 /* create a CL buffer from image pixel buffer */
1973 length = image->columns * image->rows;
1974 filteredImageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
1975 if (clStatus != CL_SUCCESS)
1977 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
1981 hullPass1 = AcquireOpenCLKernel(device,"HullPass1");
1982 hullPass2 = AcquireOpenCLKernel(device,"HullPass2");
1984 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)&imageBuffer);
1985 clStatus |=clEnv->library->clSetKernelArg(hullPass1,1,sizeof(cl_mem),(void *)(tempImageBuffer+1));
1986 imageWidth = (unsigned int) image->columns;
1987 clStatus |=clEnv->library->clSetKernelArg(hullPass1,2,sizeof(unsigned int),(void *)&imageWidth);
1988 imageHeight = (unsigned int) image->rows;
1989 clStatus |=clEnv->library->clSetKernelArg(hullPass1,3,sizeof(unsigned int),(void *)&imageHeight);
1990 matte = (image->alpha_trait > CopyPixelTrait)?1:0;
1991 clStatus |=clEnv->library->clSetKernelArg(hullPass1,6,sizeof(int),(void *)&matte);
1992 if (clStatus != CL_SUCCESS)
1994 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
1998 clStatus = clEnv->library->clSetKernelArg(hullPass2,0,sizeof(cl_mem),(void *)(tempImageBuffer+1));
1999 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)tempImageBuffer);
2000 imageWidth = (unsigned int) image->columns;
2001 clStatus |=clEnv->library->clSetKernelArg(hullPass2,2,sizeof(unsigned int),(void *)&imageWidth);
2002 imageHeight = (unsigned int) image->rows;
2003 clStatus |=clEnv->library->clSetKernelArg(hullPass2,3,sizeof(unsigned int),(void *)&imageHeight);
2004 matte = (image->alpha_trait > CopyPixelTrait)?1:0;
2005 clStatus |=clEnv->library->clSetKernelArg(hullPass2,6,sizeof(int),(void *)&matte);
2006 if (clStatus != CL_SUCCESS)
2008 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
2013 global_work_size[0] = image->columns;
2014 global_work_size[1] = image->rows;
2017 for (k = 0; k < 4; k++)
2026 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
2027 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
2028 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
2029 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
2030 if (clStatus != CL_SUCCESS)
2032 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
2035 /* launch the kernel */
2036 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2037 if (clStatus != CL_SUCCESS)
2039 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2042 RecordProfileData(device,hullPass1,event);
2044 /* launch the kernel */
2045 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2046 if (clStatus != CL_SUCCESS)
2048 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2051 RecordProfileData(device,hullPass2,event);
2054 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)(tempImageBuffer));
2055 offset.s[0] = -X[k];
2056 offset.s[1] = -Y[k];
2058 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
2059 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
2060 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
2061 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
2062 if (clStatus != CL_SUCCESS)
2064 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
2067 /* launch the kernel */
2068 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2069 if (clStatus != CL_SUCCESS)
2071 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2074 RecordProfileData(device,hullPass1,event);
2076 /* launch the kernel */
2077 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2078 if (clStatus != CL_SUCCESS)
2080 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2083 RecordProfileData(device,hullPass2,event);
2085 offset.s[0] = -X[k];
2086 offset.s[1] = -Y[k];
2088 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
2089 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
2090 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
2091 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
2092 if (clStatus != CL_SUCCESS)
2094 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
2097 /* launch the kernel */
2098 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2099 if (clStatus != CL_SUCCESS)
2101 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2104 RecordProfileData(device,hullPass1,event);
2106 /* launch the kernel */
2107 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2108 if (clStatus != CL_SUCCESS)
2110 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2113 RecordProfileData(device,hullPass2,event);
2118 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
2119 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
2120 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
2121 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
2124 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)&filteredImageBuffer);
2126 if (clStatus != CL_SUCCESS)
2128 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
2131 /* launch the kernel */
2132 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2133 if (clStatus != CL_SUCCESS)
2135 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2138 RecordProfileData(device,hullPass1,event);
2140 /* launch the kernel */
2141 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2142 if (clStatus != CL_SUCCESS)
2144 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2147 RecordProfileData(device,hullPass2,event);
2150 if (ALIGNED(filteredPixels,CLPixelPacket))
2152 length = image->columns * image->rows;
2153 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
2157 length = image->columns * image->rows;
2158 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
2160 if (clStatus != CL_SUCCESS)
2162 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
2166 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
2170 image_view=DestroyCacheView(image_view);
2171 if (filteredImage_view != NULL)
2172 filteredImage_view=DestroyCacheView(filteredImage_view);
2175 ReleaseOpenCLCommandQueue(device,queue);
2177 ReleaseOpenCLDevice(device);
2178 if (imageBuffer!=NULL)
2179 clEnv->library->clReleaseMemObject(imageBuffer);
2180 for (k = 0; k < 2; k++)
2182 if (tempImageBuffer[k]!=NULL)
2183 clEnv->library->clReleaseMemObject(tempImageBuffer[k]);
2185 if (filteredImageBuffer!=NULL)
2186 clEnv->library->clReleaseMemObject(filteredImageBuffer);
2187 if (hullPass1!=NULL)
2188 ReleaseOpenCLKernel(hullPass1);
2189 if (hullPass2!=NULL)
2190 ReleaseOpenCLKernel(hullPass2);
2191 if (outputReady == MagickFalse && filteredImage != NULL)
2192 filteredImage=DestroyImage(filteredImage);
2194 return(filteredImage);
2197 MagickPrivate Image *AccelerateDespeckleImage(const Image* image,
2198 ExceptionInfo* exception)
2206 assert(image != NULL);
2207 assert(exception != (ExceptionInfo *) NULL);
2209 if (checkAccelerateConditionRGBA(image) == MagickFalse)
2210 return((Image *) NULL);
2212 clEnv=getOpenCLEnvironment(exception);
2213 if (clEnv == (MagickCLEnv) NULL)
2214 return((Image *) NULL);
2216 filteredImage=ComputeDespeckleImage(image,clEnv,exception);
2217 return(filteredImage);
2221 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2225 % A c c e l e r a t e E q u a l i z e I m a g e %
2229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232 static MagickBooleanType ComputeEqualizeImage(Image *image,MagickCLEnv clEnv,
2233 ExceptionInfo *exception)
2235 #define EqualizeImageTag "Equalize/Image"
2287 global_work_size[2];
2298 histogramBuffer = NULL;
2299 equalizeMapBuffer = NULL;
2300 histogramKernel = NULL;
2301 equalizeKernel = NULL;
2303 outputReady = MagickFalse;
2305 assert(image != (Image *) NULL);
2306 assert(image->signature == MagickCoreSignature);
2307 if (image->debug != MagickFalse)
2308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2311 * initialize opencl env
2313 device = RequestOpenCLDevice(clEnv);
2314 queue = AcquireOpenCLCommandQueue(device);
2317 Allocate and initialize histogram arrays.
2319 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
2320 if (histogram == (cl_uint4 *) NULL)
2321 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
2323 /* reset histogram */
2324 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
2326 /* Create and initialize OpenCL buffers. */
2327 /* inputPixels = AcquirePixelCachePixels(image, &length, exception); */
2328 /* assume this will get a writable image */
2329 image_view=AcquireAuthenticCacheView(image,exception);
2330 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
2332 if (inputPixels == (void *) NULL)
2334 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
2337 /* If the host pointer is aligned to the size of CLPixelPacket,
2338 then use the host buffer directly from the GPU; otherwise,
2339 create a buffer on the GPU and copy the data over */
2340 if (ALIGNED(inputPixels,CLPixelPacket))
2342 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2346 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2348 /* create a CL buffer from image pixel buffer */
2349 length = image->columns * image->rows;
2350 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
2351 if (clStatus != CL_SUCCESS)
2353 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2357 /* If the host pointer is aligned to the size of cl_uint,
2358 then use the host buffer directly from the GPU; otherwise,
2359 create a buffer on the GPU and copy the data over */
2360 if (ALIGNED(histogram,cl_uint4))
2362 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
2363 hostPtr = histogram;
2367 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
2368 hostPtr = histogram;
2370 /* create a CL buffer for histogram */
2371 length = (MaxMap+1);
2372 histogramBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
2373 if (clStatus != CL_SUCCESS)
2375 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2379 status = LaunchHistogramKernel(clEnv, device, queue, imageBuffer, histogramBuffer, image, image->channel_mask, exception);
2380 if (status == MagickFalse)
2383 /* read from the kenel output */
2384 if (ALIGNED(histogram,cl_uint4))
2386 length = (MaxMap+1);
2387 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
2391 length = (MaxMap+1);
2392 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
2394 if (clStatus != CL_SUCCESS)
2396 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
2400 /* unmap, don't block gpu to use this buffer again. */
2401 if (ALIGNED(histogram,cl_uint4))
2403 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
2404 if (clStatus != CL_SUCCESS)
2406 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", ".");
2411 /* recreate input buffer later, in case image updated */
2412 #ifdef RECREATEBUFFER
2413 if (imageBuffer!=NULL)
2414 clEnv->library->clReleaseMemObject(imageBuffer);
2418 equalize_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*equalize_map));
2419 if (equalize_map == (PixelPacket *) NULL)
2420 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
2422 map=(cl_float4 *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
2423 if (map == (cl_float4 *) NULL)
2424 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
2427 Integrate the histogram to get the equalization map.
2429 (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
2430 for (i=0; i <= (ssize_t) MaxMap; i++)
2432 if ((image->channel_mask & SyncChannels) != 0)
2434 intensity.x+=histogram[i].s[2];
2438 if ((image->channel_mask & RedChannel) != 0)
2439 intensity.x+=histogram[i].s[2];
2440 if ((image->channel_mask & GreenChannel) != 0)
2441 intensity.y+=histogram[i].s[1];
2442 if ((image->channel_mask & BlueChannel) != 0)
2443 intensity.z+=histogram[i].s[0];
2444 if ((image->channel_mask & AlphaChannel) != 0)
2445 intensity.w+=histogram[i].s[3];
2449 white=map[(int) MaxMap];
2450 (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map));
2451 for (i=0; i <= (ssize_t) MaxMap; i++)
2453 if ((image->channel_mask & SyncChannels) != 0)
2455 if (white.x != black.x)
2456 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
2457 (map[i].x-black.x))/(white.x-black.x)));
2460 if (((image->channel_mask & RedChannel) != 0) && (white.x != black.x))
2461 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
2462 (map[i].x-black.x))/(white.x-black.x)));
2463 if (((image->channel_mask & GreenChannel) != 0) && (white.y != black.y))
2464 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
2465 (map[i].y-black.y))/(white.y-black.y)));
2466 if (((image->channel_mask & BlueChannel) != 0) && (white.z != black.z))
2467 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
2468 (map[i].z-black.z))/(white.z-black.z)));
2469 if (((image->channel_mask & AlphaChannel) != 0) && (white.w != black.w))
2470 equalize_map[i].alpha=ScaleMapToQuantum((MagickRealType) ((MaxMap*
2471 (map[i].w-black.w))/(white.w-black.w)));
2474 if (image->storage_class == PseudoClass)
2479 for (i=0; i < (ssize_t) image->colors; i++)
2481 if ((image->channel_mask & SyncChannels) != 0)
2483 if (white.x != black.x)
2485 image->colormap[i].red=equalize_map[
2486 ScaleQuantumToMap(image->colormap[i].red)].red;
2487 image->colormap[i].green=equalize_map[
2488 ScaleQuantumToMap(image->colormap[i].green)].red;
2489 image->colormap[i].blue=equalize_map[
2490 ScaleQuantumToMap(image->colormap[i].blue)].red;
2491 image->colormap[i].alpha=equalize_map[
2492 ScaleQuantumToMap(image->colormap[i].alpha)].red;
2496 if (((image->channel_mask & RedChannel) != 0) && (white.x != black.x))
2497 image->colormap[i].red=equalize_map[
2498 ScaleQuantumToMap(image->colormap[i].red)].red;
2499 if (((image->channel_mask & GreenChannel) != 0) && (white.y != black.y))
2500 image->colormap[i].green=equalize_map[
2501 ScaleQuantumToMap(image->colormap[i].green)].green;
2502 if (((image->channel_mask & BlueChannel) != 0) && (white.z != black.z))
2503 image->colormap[i].blue=equalize_map[
2504 ScaleQuantumToMap(image->colormap[i].blue)].blue;
2505 if (((image->channel_mask & AlphaChannel) != 0) && (white.w != black.w))
2506 image->colormap[i].alpha=equalize_map[
2507 ScaleQuantumToMap(image->colormap[i].alpha)].alpha;
2515 /* GPU can work on this again, image and equalize map as input
2516 image: uchar4 (CLPixelPacket)
2517 equalize_map: uchar4 (PixelPacket)
2518 black, white: float4 (FloatPixelPacket) */
2520 #ifdef RECREATEBUFFER
2521 /* If the host pointer is aligned to the size of CLPixelPacket,
2522 then use the host buffer directly from the GPU; otherwise,
2523 create a buffer on the GPU and copy the data over */
2524 if (ALIGNED(inputPixels,CLPixelPacket))
2526 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
2530 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
2532 /* create a CL buffer from image pixel buffer */
2533 length = image->columns * image->rows;
2534 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
2535 if (clStatus != CL_SUCCESS)
2537 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2542 /* Create and initialize OpenCL buffers. */
2543 if (ALIGNED(equalize_map, PixelPacket))
2545 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2546 hostPtr = equalize_map;
2550 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
2551 hostPtr = equalize_map;
2553 /* create a CL buffer for eqaulize_map */
2554 length = (MaxMap+1);
2555 equalizeMapBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
2556 if (clStatus != CL_SUCCESS)
2558 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
2562 /* get the OpenCL kernel */
2563 equalizeKernel = AcquireOpenCLKernel(device,"Equalize");
2564 if (equalizeKernel == NULL)
2566 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
2570 /* set the kernel arguments */
2572 clStatus=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
2573 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(ChannelType),&image->channel_mask);
2574 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&equalizeMapBuffer);
2575 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_float4),&white);
2576 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_float4),&black);
2577 if (clStatus != CL_SUCCESS)
2579 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
2583 /* launch the kernel */
2584 global_work_size[0] = image->columns;
2585 global_work_size[1] = image->rows;
2587 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, equalizeKernel, 2, NULL, global_work_size, NULL, 0, NULL, &event);
2589 if (clStatus != CL_SUCCESS)
2591 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
2594 RecordProfileData(device,equalizeKernel,event);
2596 /* read the data back */
2597 if (ALIGNED(inputPixels,CLPixelPacket))
2599 length = image->columns * image->rows;
2600 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
2604 length = image->columns * image->rows;
2605 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
2607 if (clStatus != CL_SUCCESS)
2609 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
2613 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
2617 image_view=DestroyCacheView(image_view);
2619 if (imageBuffer!=NULL)
2620 clEnv->library->clReleaseMemObject(imageBuffer);
2622 map=(cl_float4 *) RelinquishMagickMemory(map);
2623 if (equalizeMapBuffer!=NULL)
2624 clEnv->library->clReleaseMemObject(equalizeMapBuffer);
2625 if (equalize_map!=NULL)
2626 equalize_map=(PixelPacket *) RelinquishMagickMemory(equalize_map);
2627 if (histogramBuffer!=NULL)
2628 clEnv->library->clReleaseMemObject(histogramBuffer);
2629 if (histogram!=NULL)
2630 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
2631 if (histogramKernel!=NULL)
2632 ReleaseOpenCLKernel(histogramKernel);
2633 if (equalizeKernel!=NULL)
2634 ReleaseOpenCLKernel(equalizeKernel);
2636 ReleaseOpenCLCommandQueue(device, queue);
2638 ReleaseOpenCLDevice(device);
2640 return(outputReady);
2643 MagickPrivate MagickBooleanType AccelerateEqualizeImage(Image *image,
2644 ExceptionInfo *exception)
2652 assert(image != NULL);
2653 assert(exception != (ExceptionInfo *) NULL);
2655 if ((checkAccelerateConditionRGBA(image) == MagickFalse) ||
2656 (checkHistogramCondition(image,image->intensity) == MagickFalse))
2657 return(MagickFalse);
2659 clEnv=getOpenCLEnvironment(exception);
2660 if (clEnv == (MagickCLEnv) NULL)
2661 return(MagickFalse);
2663 status=ComputeEqualizeImage(image,clEnv,exception);
2668 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2672 % A c c e l e r a t e F u n c t i o n I m a g e %
2676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2679 static MagickBooleanType ComputeFunctionImage(Image *image,MagickCLEnv clEnv,
2680 const MagickFunction function,const size_t number_parameters,
2681 const double *parameters,ExceptionInfo *exception)
2701 *parametersBufferPtr;
2713 outputReady=MagickFalse;
2715 functionKernel=NULL;
2716 parametersBuffer=NULL;
2718 device=RequestOpenCLDevice(clEnv);
2719 queue=AcquireOpenCLCommandQueue(device);
2720 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
2721 if (imageBuffer == (cl_mem) NULL)
2724 parametersBufferPtr=(float *) AcquireQuantumMemory(number_parameters,
2726 if (parametersBufferPtr == (float *) NULL)
2728 for (i=0; i<number_parameters; i++)
2729 parametersBufferPtr[i]=(float) parameters[i];
2730 parametersBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_ONLY |
2731 CL_MEM_COPY_HOST_PTR,number_parameters*sizeof(*parametersBufferPtr),
2732 parametersBufferPtr);
2733 parametersBufferPtr=RelinquishMagickMemory(parametersBufferPtr);
2734 if (parametersBuffer == (cl_mem) NULL)
2736 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
2737 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
2741 functionKernel=AcquireOpenCLKernel(device,"ComputeFunction");
2742 if (functionKernel == (cl_kernel) NULL)
2744 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
2745 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
2749 number_channels=(cl_uint) image->number_channels;
2750 number_params=(cl_uint) number_parameters;
2753 status =SetOpenCLKernelArg(functionKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
2754 status|=SetOpenCLKernelArg(functionKernel,i++,sizeof(cl_uint),(void *)&number_channels);
2755 status|=SetOpenCLKernelArg(functionKernel,i++,sizeof(ChannelType),(void *)&image->channel_mask);
2756 status|=SetOpenCLKernelArg(functionKernel,i++,sizeof(MagickFunction),(void *)&function);
2757 status|=SetOpenCLKernelArg(functionKernel,i++,sizeof(cl_uint),(void *)&number_params);
2758 status|=SetOpenCLKernelArg(functionKernel,i++,sizeof(cl_mem),(void *)¶metersBuffer);
2759 if (status != CL_SUCCESS)
2761 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
2762 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
2766 gsize[0]=image->columns;
2767 gsize[1]=image->rows;
2768 outputReady=EnqueueOpenCLKernel(queue,functionKernel,2,(const size_t *) NULL,
2769 gsize,(const size_t *) NULL,image,(const Image *) NULL,MagickFalse,
2774 if (parametersBuffer != (cl_mem) NULL)
2775 ReleaseOpenCLMemObject(parametersBuffer);
2776 if (functionKernel != (cl_kernel) NULL)
2777 ReleaseOpenCLKernel(functionKernel);
2778 if (queue != (cl_command_queue) NULL)
2779 ReleaseOpenCLCommandQueue(device,queue);
2780 if (device != (MagickCLDevice) NULL)
2781 ReleaseOpenCLDevice(device);
2782 return(outputReady);
2785 MagickPrivate MagickBooleanType AccelerateFunctionImage(Image *image,
2786 const MagickFunction function,const size_t number_parameters,
2787 const double *parameters,ExceptionInfo *exception)
2795 assert(image != NULL);
2796 assert(exception != (ExceptionInfo *) NULL);
2798 if (checkAccelerateCondition(image) == MagickFalse)
2799 return(MagickFalse);
2801 clEnv=getOpenCLEnvironment(exception);
2802 if (clEnv == (MagickCLEnv) NULL)
2803 return(MagickFalse);
2805 status=ComputeFunctionImage(image,clEnv,function,number_parameters,
2806 parameters,exception);
2811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815 % A c c e l e r a t e G r a y s c a l e I m a g e %
2819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822 static MagickBooleanType ComputeGrayscaleImage(Image *image,MagickCLEnv clEnv,
2823 const PixelIntensityMethod method,ExceptionInfo *exception)
2852 outputReady=MagickFalse;
2853 grayscaleKernel=NULL;
2855 assert(image != (Image *) NULL);
2856 assert(image->signature == MagickCoreSignature);
2857 device=RequestOpenCLDevice(clEnv);
2858 queue=AcquireOpenCLCommandQueue(device);
2859 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
2860 if (imageBuffer == (cl_mem) NULL)
2863 grayscaleKernel=AcquireOpenCLKernel(device,"Grayscale");
2864 if (grayscaleKernel == (cl_kernel) NULL)
2866 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
2867 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
2871 number_channels=(cl_uint) image->number_channels;
2872 intensityMethod=(cl_uint) method;
2873 colorspace=(cl_uint) image->colorspace;
2876 status =SetOpenCLKernelArg(grayscaleKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
2877 status|=SetOpenCLKernelArg(grayscaleKernel,i++,sizeof(cl_uint),&number_channels);
2878 status|=SetOpenCLKernelArg(grayscaleKernel,i++,sizeof(cl_uint),&colorspace);
2879 status|=SetOpenCLKernelArg(grayscaleKernel,i++,sizeof(cl_uint),&intensityMethod);
2880 if (status != CL_SUCCESS)
2882 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
2883 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
2887 gsize[0]=image->columns;
2888 gsize[1]=image->rows;
2889 outputReady=EnqueueOpenCLKernel(queue,grayscaleKernel,2,
2890 (const size_t *) NULL,gsize,(const size_t *) NULL,image,(Image *) NULL,
2891 MagickFalse,exception);
2895 if (grayscaleKernel != (cl_kernel) NULL)
2896 ReleaseOpenCLKernel(grayscaleKernel);
2897 if (queue != (cl_command_queue) NULL)
2898 ReleaseOpenCLCommandQueue(device,queue);
2899 if (device != (MagickCLDevice) NULL)
2900 ReleaseOpenCLDevice(device);
2902 return(outputReady);
2905 MagickPrivate MagickBooleanType AccelerateGrayscaleImage(Image* image,
2906 const PixelIntensityMethod method,ExceptionInfo *exception)
2914 assert(image != NULL);
2915 assert(exception != (ExceptionInfo *) NULL);
2917 if ((checkAccelerateCondition(image) == MagickFalse) ||
2918 (checkPixelIntensity(image,method) == MagickFalse))
2919 return(MagickFalse);
2921 if (image->number_channels < 3)
2922 return(MagickFalse);
2924 if ((GetPixelRedTraits(image) == UndefinedPixelTrait) ||
2925 (GetPixelGreenTraits(image) == UndefinedPixelTrait) ||
2926 (GetPixelBlueTraits(image) == UndefinedPixelTrait))
2927 return(MagickFalse);
2929 clEnv=getOpenCLEnvironment(exception);
2930 if (clEnv == (MagickCLEnv) NULL)
2931 return(MagickFalse);
2933 status=ComputeGrayscaleImage(image,clEnv,method,exception);
2938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2942 % 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 %
2946 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2949 static Image *ComputeLocalContrastImage(const Image *image,MagickCLEnv clEnv,
2950 const double radius,const double strength,ExceptionInfo *exception)
2953 *filteredImage_view,
2971 filteredImageBuffer,
3004 filteredImage = NULL;
3005 filteredImage_view = NULL;
3007 filteredImageBuffer = NULL;
3008 tempImageBuffer = NULL;
3009 imageKernelBuffer = NULL;
3010 blurRowKernel = NULL;
3011 blurColumnKernel = NULL;
3013 outputReady = MagickFalse;
3015 device = RequestOpenCLDevice(clEnv);
3016 queue = AcquireOpenCLCommandQueue(device);
3018 /* Create and initialize OpenCL buffers. */
3020 image_view=AcquireAuthenticCacheView(image,exception);
3021 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
3022 if (inputPixels == (const void *) NULL)
3024 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
3028 /* If the host pointer is aligned to the size of CLPixelPacket,
3029 then use the host buffer directly from the GPU; otherwise,
3030 create a buffer on the GPU and copy the data over */
3031 if (ALIGNED(inputPixels,CLPixelPacket))
3033 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
3037 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
3039 /* create a CL buffer from image pixel buffer */
3040 length = image->columns * image->rows;
3041 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3042 if (clStatus != CL_SUCCESS)
3044 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3051 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
3052 assert(filteredImage != NULL);
3053 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
3055 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", ".");
3058 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
3059 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
3060 if (filteredPixels == (void *) NULL)
3062 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
3066 if (ALIGNED(filteredPixels,CLPixelPacket))
3068 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
3069 hostPtr = filteredPixels;
3073 mem_flags = CL_MEM_WRITE_ONLY;
3077 /* create a CL buffer from image pixel buffer */
3078 length = image->columns * image->rows;
3079 filteredImageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
3080 if (clStatus != CL_SUCCESS)
3082 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3088 /* create temp buffer */
3090 length = image->columns * image->rows;
3091 tempImageBuffer = clEnv->library->clCreateBuffer(device->context, CL_MEM_READ_WRITE, length * sizeof(float), NULL, &clStatus);
3092 if (clStatus != CL_SUCCESS)
3094 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3099 /* get the opencl kernel */
3101 blurRowKernel = AcquireOpenCLKernel(device,"LocalContrastBlurRow");
3102 if (blurRowKernel == NULL)
3104 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
3108 blurColumnKernel = AcquireOpenCLKernel(device,"LocalContrastBlurApplyColumn");
3109 if (blurColumnKernel == NULL)
3111 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
3117 imageColumns = (unsigned int) image->columns;
3118 imageRows = (unsigned int) image->rows;
3119 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
3121 passes = (((1.0f * imageRows) * imageColumns * iRadius) + 3999999999) / 4000000000.0f;
3122 passes = (passes < 1) ? 1: passes;
3124 /* set the kernel arguments */
3126 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
3127 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
3128 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
3129 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_int),(void *)&iRadius);
3130 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
3131 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
3133 if (clStatus != CL_SUCCESS)
3135 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
3140 /* launch the kernel */
3143 for (x = 0; x < passes; ++x) {
3149 gsize[1] = (image->rows + passes - 1) / passes;
3153 goffset[1] = x * gsize[1];
3155 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, goffset, gsize, wsize, 0, NULL, &event);
3156 if (clStatus != CL_SUCCESS)
3158 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
3161 clEnv->library->clFlush(queue);
3162 RecordProfileData(device,blurRowKernel,event);
3167 cl_float FStrength = strength;
3169 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
3170 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
3171 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
3172 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&iRadius);
3173 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float),(void *)&FStrength);
3174 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
3175 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
3177 if (clStatus != CL_SUCCESS)
3179 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
3184 /* launch the kernel */
3187 for (x = 0; x < passes; ++x) {
3192 gsize[0] = ((image->columns + 3) / 4) * 4;
3193 gsize[1] = ((((image->rows + 63) / 64) + (passes + 1)) / passes) * 64;
3197 goffset[1] = x * gsize[1];
3199 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, goffset, gsize, wsize, 0, NULL, &event);
3200 if (clStatus != CL_SUCCESS)
3202 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
3205 clEnv->library->clFlush(queue);
3206 RecordProfileData(device,blurColumnKernel,event);
3212 if (ALIGNED(filteredPixels,CLPixelPacket))
3214 length = image->columns * image->rows;
3215 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3219 length = image->columns * image->rows;
3220 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
3222 if (clStatus != CL_SUCCESS)
3224 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
3228 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
3232 image_view=DestroyCacheView(image_view);
3233 if (filteredImage_view != NULL)
3234 filteredImage_view=DestroyCacheView(filteredImage_view);
3236 if (imageBuffer!=NULL)
3237 clEnv->library->clReleaseMemObject(imageBuffer);
3238 if (filteredImageBuffer!=NULL)
3239 clEnv->library->clReleaseMemObject(filteredImageBuffer);
3240 if (tempImageBuffer!=NULL)
3241 clEnv->library->clReleaseMemObject(tempImageBuffer);
3242 if (imageKernelBuffer!=NULL)
3243 clEnv->library->clReleaseMemObject(imageKernelBuffer);
3244 if (blurRowKernel!=NULL)
3245 ReleaseOpenCLKernel(blurRowKernel);
3246 if (blurColumnKernel!=NULL)
3247 ReleaseOpenCLKernel(blurColumnKernel);
3249 ReleaseOpenCLCommandQueue(device, queue);
3251 ReleaseOpenCLDevice(device);
3252 if (outputReady == MagickFalse)
3254 if (filteredImage != NULL)
3256 DestroyImage(filteredImage);
3257 filteredImage = NULL;
3261 return(filteredImage);
3264 MagickPrivate Image *AccelerateLocalContrastImage(const Image *image,
3265 const double radius,const double strength,ExceptionInfo *exception)
3273 assert(image != NULL);
3274 assert(exception != (ExceptionInfo *) NULL);
3276 if (checkAccelerateConditionRGBA(image) == MagickFalse)
3277 return((Image *) NULL);
3279 clEnv=getOpenCLEnvironment(exception);
3280 if (clEnv == (MagickCLEnv) NULL)
3281 return((Image *) NULL);
3283 filteredImage=ComputeLocalContrastImage(image,clEnv,radius,strength,
3285 return(filteredImage);
3289 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3293 % A c c e l e r a t e M o d u l a t e I m a g e %
3297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3300 static MagickBooleanType ComputeModulateImage(Image *image,MagickCLEnv clEnv,
3301 const double percent_brightness,const double percent_hue,
3302 const double percent_saturation,const ColorspaceType colorspace,
3303 ExceptionInfo *exception)
3349 modulateKernel = NULL;
3351 assert(image != (Image *) NULL);
3352 assert(image->signature == MagickCoreSignature);
3353 if (image->debug != MagickFalse)
3354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3357 * initialize opencl env
3359 device = RequestOpenCLDevice(clEnv);
3360 queue = AcquireOpenCLCommandQueue(device);
3362 outputReady = MagickFalse;
3364 /* Create and initialize OpenCL buffers.
3365 inputPixels = AcquirePixelCachePixels(image, &length, exception);
3366 assume this will get a writable image
3368 image_view=AcquireAuthenticCacheView(image,exception);
3369 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
3370 if (inputPixels == (void *) NULL)
3372 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
3376 /* If the host pointer is aligned to the size of CLPixelPacket,
3377 then use the host buffer directly from the GPU; otherwise,
3378 create a buffer on the GPU and copy the data over
3380 if (ALIGNED(inputPixels,CLPixelPacket))
3382 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3386 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3388 /* create a CL buffer from image pixel buffer */
3389 length = image->columns * image->rows;
3390 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3391 if (clStatus != CL_SUCCESS)
3393 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3397 modulateKernel = AcquireOpenCLKernel(device, "Modulate");
3398 if (modulateKernel == NULL)
3400 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", ".");
3404 bright=percent_brightness;
3406 saturation=percent_saturation;
3410 clStatus=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
3411 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&bright);
3412 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&hue);
3413 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&saturation);
3414 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&color);
3415 if (clStatus != CL_SUCCESS)
3417 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", ".");
3422 size_t global_work_size[2];
3423 global_work_size[0] = image->columns;
3424 global_work_size[1] = image->rows;
3425 /* launch the kernel */
3426 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, modulateKernel, 2, NULL, global_work_size, NULL, 0, NULL, &event);
3427 if (clStatus != CL_SUCCESS)
3429 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
3432 RecordProfileData(device,modulateKernel,event);
3435 if (ALIGNED(inputPixels,CLPixelPacket))
3437 length = image->columns * image->rows;
3438 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
3442 length = image->columns * image->rows;
3443 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
3445 if (clStatus != CL_SUCCESS)
3447 (void) OpenCLThrowMagickException(device,exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", ".");
3451 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
3455 image_view=DestroyCacheView(image_view);
3457 if (imageBuffer!=NULL)
3458 clEnv->library->clReleaseMemObject(imageBuffer);
3459 if (modulateKernel!=NULL)
3460 ReleaseOpenCLKernel(modulateKernel);
3462 ReleaseOpenCLCommandQueue(device,queue);
3464 ReleaseOpenCLDevice(device);
3470 MagickPrivate MagickBooleanType AccelerateModulateImage(Image *image,
3471 const double percent_brightness,const double percent_hue,
3472 const double percent_saturation,const ColorspaceType colorspace,
3473 ExceptionInfo *exception)
3481 assert(image != NULL);
3482 assert(exception != (ExceptionInfo *) NULL);
3484 if (checkAccelerateConditionRGBA(image) == MagickFalse)
3485 return(MagickFalse);
3487 if ((colorspace != HSLColorspace) && (colorspace != UndefinedColorspace))
3488 return(MagickFalse);
3490 clEnv=getOpenCLEnvironment(exception);
3491 if (clEnv == (MagickCLEnv) NULL)
3492 return(MagickFalse);
3494 status=ComputeModulateImage(image,clEnv,percent_brightness,percent_hue,
3495 percent_saturation,colorspace,exception);
3500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3504 % 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 %
3508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3511 static Image* ComputeMotionBlurImage(const Image *image,MagickCLEnv clEnv,
3512 const double *kernel,const size_t width,const OffsetInfo *offset,
3513 ExceptionInfo *exception)
3516 *filteredImage_view,
3535 filteredImageBuffer,
3568 global_work_size[2],
3581 outputReady = MagickFalse;
3582 filteredImage = NULL;
3583 filteredImage_view = NULL;
3585 filteredImageBuffer = NULL;
3586 imageKernelBuffer = NULL;
3587 motionBlurKernel = NULL;
3590 device = RequestOpenCLDevice(clEnv);
3592 /* Create and initialize OpenCL buffers. */
3594 image_view=AcquireAuthenticCacheView(image,exception);
3595 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
3596 if (inputPixels == (const void *) NULL)
3598 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3599 "UnableToReadPixelCache.","`%s'",image->filename);
3603 // If the host pointer is aligned to the size of CLPixelPacket,
3604 // then use the host buffer directly from the GPU; otherwise,
3605 // create a buffer on the GPU and copy the data over
3606 if (ALIGNED(inputPixels,CLPixelPacket))
3608 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
3612 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
3614 // create a CL buffer from image pixel buffer
3615 length = image->columns * image->rows;
3616 imageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags,
3617 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
3618 if (clStatus != CL_SUCCESS)
3620 (void) ThrowMagickException(exception, GetMagickModule(),
3621 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
3626 filteredImage = CloneImage(image,image->columns,image->rows,
3627 MagickTrue,exception);
3628 assert(filteredImage != NULL);
3629 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
3631 (void) ThrowMagickException(exception, GetMagickModule(),
3632 ResourceLimitError, "CloneImage failed.", ".");
3635 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
3636 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
3637 if (filteredPixels == (void *) NULL)
3639 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
3640 "UnableToReadPixelCache.","`%s'",filteredImage->filename);
3644 if (ALIGNED(filteredPixels,CLPixelPacket))
3646 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
3647 hostPtr = filteredPixels;
3651 mem_flags = CL_MEM_WRITE_ONLY;
3654 // create a CL buffer from image pixel buffer
3655 length = image->columns * image->rows;
3656 filteredImageBuffer = clEnv->library->clCreateBuffer(device->context, mem_flags,
3657 length * sizeof(CLPixelPacket), hostPtr, &clStatus);
3658 if (clStatus != CL_SUCCESS)
3660 (void) ThrowMagickException(exception, GetMagickModule(),
3661 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
3666 imageKernelBuffer = clEnv->library->clCreateBuffer(device->context,
3667 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(float), NULL,
3669 if (clStatus != CL_SUCCESS)
3671 (void) ThrowMagickException(exception, GetMagickModule(),
3672 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
3676 queue = AcquireOpenCLCommandQueue(device);
3677 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer,
3678 CL_TRUE, CL_MAP_WRITE, 0, width * sizeof(float), 0, NULL, NULL, &clStatus);
3679 if (clStatus != CL_SUCCESS)
3681 (void) ThrowMagickException(exception, GetMagickModule(),
3682 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
3685 for (i = 0; i < width; i++)
3687 kernelBufferPtr[i] = (float) kernel[i];
3689 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr,
3691 if (clStatus != CL_SUCCESS)
3693 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
3694 "clEnv->library->clEnqueueUnmapMemObject failed.", ".");
3698 offsetBuffer = clEnv->library->clCreateBuffer(device->context,
3699 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(cl_int2), NULL,
3701 if (clStatus != CL_SUCCESS)
3703 (void) ThrowMagickException(exception, GetMagickModule(),
3704 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
3708 offsetBufferPtr = (int*)clEnv->library->clEnqueueMapBuffer(queue, offsetBuffer, CL_TRUE,
3709 CL_MAP_WRITE, 0, width * sizeof(cl_int2), 0, NULL, NULL, &clStatus);
3710 if (clStatus != CL_SUCCESS)
3712 (void) ThrowMagickException(exception, GetMagickModule(),
3713 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
3716 for (i = 0; i < width; i++)
3718 offsetBufferPtr[2*i] = (int)offset[i].x;
3719 offsetBufferPtr[2*i+1] = (int)offset[i].y;
3721 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, offsetBuffer, offsetBufferPtr, 0,
3723 if (clStatus != CL_SUCCESS)
3725 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
3726 "clEnv->library->clEnqueueUnmapMemObject failed.", ".");
3731 // get the OpenCL kernel
3732 motionBlurKernel = AcquireOpenCLKernel(device,"MotionBlur");
3733 if (motionBlurKernel == NULL)
3735 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
3736 "AcquireOpenCLKernel failed.", ".");
3740 // set the kernel arguments
3742 clStatus=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
3743 (void *)&imageBuffer);
3744 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
3745 (void *)&filteredImageBuffer);
3746 imageWidth = (unsigned int) image->columns;
3747 imageHeight = (unsigned int) image->rows;
3748 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
3750 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
3752 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
3753 (void *)&imageKernelBuffer);
3754 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
3756 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
3757 (void *)&offsetBuffer);
3759 GetPixelInfo(image,&bias);
3760 biasPixel.s[0] = bias.red;
3761 biasPixel.s[1] = bias.green;
3762 biasPixel.s[2] = bias.blue;
3763 biasPixel.s[3] = bias.alpha;
3764 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_float4), &biasPixel);
3766 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(ChannelType), &image->channel_mask);
3767 matte = (image->alpha_trait > CopyPixelTrait)?1:0;
3768 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), &matte);
3769 if (clStatus != CL_SUCCESS)
3771 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
3772 "clEnv->library->clSetKernelArg failed.", ".");
3776 // launch the kernel
3777 local_work_size[0] = 16;
3778 local_work_size[1] = 16;
3779 global_work_size[0] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
3780 (unsigned int) image->columns,(unsigned int) local_work_size[0]);
3781 global_work_size[1] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
3782 (unsigned int) image->rows,(unsigned int) local_work_size[1]);
3783 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, motionBlurKernel, 2, NULL,
3784 global_work_size, local_work_size, 0, NULL, &event);
3786 if (clStatus != CL_SUCCESS)
3788 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
3789 "clEnv->library->clEnqueueNDRangeKernel failed.", ".");
3792 RecordProfileData(device,motionBlurKernel,event);
3794 if (ALIGNED(filteredPixels,CLPixelPacket))
3796 length = image->columns * image->rows;
3797 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE,
3798 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
3803 length = image->columns * image->rows;
3804 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0,
3805 length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
3807 if (clStatus != CL_SUCCESS)
3809 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
3810 "Reading output image from CL buffer failed.", ".");
3813 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
3817 image_view=DestroyCacheView(image_view);
3818 if (filteredImage_view != NULL)
3819 filteredImage_view=DestroyCacheView(filteredImage_view);
3821 if (filteredImageBuffer!=NULL)
3822 clEnv->library->clReleaseMemObject(filteredImageBuffer);
3823 if (imageBuffer!=NULL)
3824 clEnv->library->clReleaseMemObject(imageBuffer);
3825 if (imageKernelBuffer!=NULL)
3826 clEnv->library->clReleaseMemObject(imageKernelBuffer);
3827 if (motionBlurKernel!=NULL)
3828 ReleaseOpenCLKernel(motionBlurKernel);
3830 ReleaseOpenCLCommandQueue(device,queue);
3832 ReleaseOpenCLDevice(device);
3833 if (outputReady == MagickFalse && filteredImage != NULL)
3834 filteredImage=DestroyImage(filteredImage);
3836 return(filteredImage);
3839 MagickPrivate Image *AccelerateMotionBlurImage(const Image *image,
3840 const double* kernel,const size_t width,const OffsetInfo *offset,
3841 ExceptionInfo *exception)
3849 assert(image != NULL);
3850 assert(kernel != (double *) NULL);
3851 assert(offset != (OffsetInfo *) NULL);
3852 assert(exception != (ExceptionInfo *) NULL);
3854 if (checkAccelerateConditionRGBA(image) == MagickFalse)
3855 return((Image *) NULL);
3857 clEnv=getOpenCLEnvironment(exception);
3858 if (clEnv == (MagickCLEnv) NULL)
3859 return((Image *) NULL);
3861 filteredImage=ComputeMotionBlurImage(image,clEnv,kernel,width,offset,
3863 return(filteredImage);
3867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3871 % A c c e l e r a t e R e s i z e I m a g e %
3875 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3878 static MagickBooleanType resizeHorizontalFilter(MagickCLDevice device,
3879 cl_command_queue queue,const Image *image,Image *filteredImage,
3880 cl_mem imageBuffer,cl_uint number_channels,cl_uint columns,cl_uint rows,
3881 cl_mem resizedImageBuffer,cl_uint resizedColumns,cl_uint resizedRows,
3882 const ResizeFilter *resizeFilter,cl_mem resizeFilterCubicCoefficients,
3883 const float xFactor,ExceptionInfo *exception)
3892 workgroupSize = 256;
3896 resizeFilterSupport,
3897 resizeFilterWindowSupport,
3913 gammaAccumulatorLocalMemorySize,
3916 imageCacheLocalMemorySize,
3917 pixelAccumulatorLocalMemorySize,
3919 totalLocalMemorySize,
3920 weightAccumulatorLocalMemorySize;
3926 horizontalKernel=NULL;
3927 outputReady=MagickFalse;
3930 Apply filter to resize vertically from image to resize image.
3932 scale=MAGICK_MAX(1.0/xFactor+MagickEpsilon,1.0);
3933 support=scale*GetResizeFilterSupport(resizeFilter);
3937 Support too small even for nearest neighbour: Reduce to point
3940 support=(float) 0.5;
3943 scale=PerceptibleReciprocal(scale);
3945 if (resizedColumns < workgroupSize)
3948 pixelPerWorkgroup=32;
3952 chunkSize=workgroupSize;
3953 pixelPerWorkgroup=workgroupSize;
3956 DisableMSCWarning(4127)
3960 /* calculate the local memory size needed per workgroup */
3961 cacheRangeStart=(int) (((0 + 0.5)/xFactor+MagickEpsilon)-support+0.5);
3962 cacheRangeEnd=(int) ((((pixelPerWorkgroup-1) + 0.5)/xFactor+
3963 MagickEpsilon)+support+0.5);
3964 numCachedPixels=cacheRangeEnd-cacheRangeStart+1;
3965 imageCacheLocalMemorySize=numCachedPixels*sizeof(CLQuantum)*
3967 totalLocalMemorySize=imageCacheLocalMemorySize;
3969 /* local size for the pixel accumulator */
3970 pixelAccumulatorLocalMemorySize=chunkSize*sizeof(cl_float4);
3971 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
3973 /* local memory size for the weight accumulator */
3974 weightAccumulatorLocalMemorySize=chunkSize*sizeof(float);
3975 totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
3977 /* local memory size for the gamma accumulator */
3978 if ((number_channels == 4) || (number_channels == 2))
3979 gammaAccumulatorLocalMemorySize=chunkSize*sizeof(float);
3981 gammaAccumulatorLocalMemorySize=sizeof(float);
3982 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
3984 if (totalLocalMemorySize <= device->local_memory_size)
3988 pixelPerWorkgroup=pixelPerWorkgroup/2;
3989 chunkSize=chunkSize/2;
3990 if ((pixelPerWorkgroup == 0) || (chunkSize == 0))
3992 /* quit, fallback to CPU */
3998 resizeFilterType=(int)GetResizeFilterWeightingType(resizeFilter);
3999 resizeWindowType=(int)GetResizeFilterWindowWeightingType(resizeFilter);
4001 horizontalKernel=AcquireOpenCLKernel(device,"ResizeHorizontalFilter");
4002 if (horizontalKernel == (cl_kernel) NULL)
4004 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4005 ResourceLimitWarning,"AcquireOpenCLKernel failed.", ".");
4009 resizeFilterScale=(float) GetResizeFilterScale(resizeFilter);
4010 resizeFilterSupport=(float) GetResizeFilterSupport(resizeFilter);
4011 resizeFilterWindowSupport=(float) GetResizeFilterWindowSupport(resizeFilter);
4012 resizeFilterBlur=(float) GetResizeFilterBlur(resizeFilter);
4015 status =SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_mem),(void*)&imageBuffer);
4016 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_uint),(void*)&number_channels);
4017 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_uint),(void*)&columns);
4018 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_uint),(void*)&rows);
4019 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_mem),(void*)&resizedImageBuffer);
4020 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_uint),(void*)&resizedColumns);
4021 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_uint),(void*)&resizedRows);
4022 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(float),(void*)&xFactor);
4023 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(int),(void*)&resizeFilterType);
4024 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(int),(void*)&resizeWindowType);
4025 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(cl_mem),(void*)&resizeFilterCubicCoefficients);
4026 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(float),(void*)&resizeFilterScale);
4027 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(float),(void*)&resizeFilterSupport);
4028 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(float),(void*)&resizeFilterWindowSupport);
4029 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(float),(void*)&resizeFilterBlur);
4030 status|=SetOpenCLKernelArg(horizontalKernel,i++,imageCacheLocalMemorySize,NULL);
4031 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(int),&numCachedPixels);
4032 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(unsigned int),&pixelPerWorkgroup);
4033 status|=SetOpenCLKernelArg(horizontalKernel,i++,sizeof(unsigned int),&chunkSize);
4034 status|=SetOpenCLKernelArg(horizontalKernel,i++,pixelAccumulatorLocalMemorySize,NULL);
4035 status|=SetOpenCLKernelArg(horizontalKernel,i++,weightAccumulatorLocalMemorySize,NULL);
4036 status|=SetOpenCLKernelArg(horizontalKernel,i++,gammaAccumulatorLocalMemorySize,NULL);
4038 if (status != CL_SUCCESS)
4040 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4041 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
4045 gsize[0]=(resizedColumns+pixelPerWorkgroup-1)/pixelPerWorkgroup*
4047 gsize[1]=resizedRows;
4048 lsize[0]=workgroupSize;
4050 outputReady=EnqueueOpenCLKernel(queue,horizontalKernel,2,
4051 (const size_t *) NULL,gsize,lsize,image,filteredImage,MagickFalse,
4056 if (horizontalKernel != (cl_kernel) NULL)
4057 ReleaseOpenCLKernel(horizontalKernel);
4059 return(outputReady);
4062 static MagickBooleanType resizeVerticalFilter(MagickCLDevice device,
4063 cl_command_queue queue,const Image *image,Image * filteredImage,
4064 cl_mem imageBuffer,cl_uint number_channels,cl_uint columns,cl_uint rows,
4065 cl_mem resizedImageBuffer,cl_uint resizedColumns,cl_uint resizedRows,
4066 const ResizeFilter *resizeFilter,cl_mem resizeFilterCubicCoefficients,
4067 const float yFactor,ExceptionInfo *exception)
4076 workgroupSize = 256;
4080 resizeFilterSupport,
4081 resizeFilterWindowSupport,
4097 gammaAccumulatorLocalMemorySize,
4100 imageCacheLocalMemorySize,
4101 pixelAccumulatorLocalMemorySize,
4103 totalLocalMemorySize,
4104 weightAccumulatorLocalMemorySize;
4110 verticalKernel=NULL;
4111 outputReady=MagickFalse;
4114 Apply filter to resize vertically from image to resize image.
4116 scale=MAGICK_MAX(1.0/yFactor+MagickEpsilon,1.0);
4117 support=scale*GetResizeFilterSupport(resizeFilter);
4121 Support too small even for nearest neighbour: Reduce to point
4124 support=(float) 0.5;
4127 scale=PerceptibleReciprocal(scale);
4129 if (resizedRows < workgroupSize)
4132 pixelPerWorkgroup=32;
4136 chunkSize=workgroupSize;
4137 pixelPerWorkgroup=workgroupSize;
4140 DisableMSCWarning(4127)
4144 /* calculate the local memory size needed per workgroup */
4145 cacheRangeStart=(int) (((0 + 0.5)/yFactor+MagickEpsilon)-support+0.5);
4146 cacheRangeEnd=(int) ((((pixelPerWorkgroup-1) + 0.5)/yFactor+
4147 MagickEpsilon)+support+0.5);
4148 numCachedPixels=cacheRangeEnd-cacheRangeStart+1;
4149 imageCacheLocalMemorySize=numCachedPixels*sizeof(CLQuantum)*
4151 totalLocalMemorySize=imageCacheLocalMemorySize;
4153 /* local size for the pixel accumulator */
4154 pixelAccumulatorLocalMemorySize=chunkSize*sizeof(cl_float4);
4155 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
4157 /* local memory size for the weight accumulator */
4158 weightAccumulatorLocalMemorySize=chunkSize*sizeof(float);
4159 totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
4161 /* local memory size for the gamma accumulator */
4162 if ((number_channels == 4) || (number_channels == 2))
4163 gammaAccumulatorLocalMemorySize=chunkSize*sizeof(float);
4165 gammaAccumulatorLocalMemorySize=sizeof(float);
4166 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
4168 if (totalLocalMemorySize <= device->local_memory_size)
4172 pixelPerWorkgroup=pixelPerWorkgroup/2;
4173 chunkSize=chunkSize/2;
4174 if ((pixelPerWorkgroup == 0) || (chunkSize == 0))
4176 /* quit, fallback to CPU */
4182 resizeFilterType=(int)GetResizeFilterWeightingType(resizeFilter);
4183 resizeWindowType=(int)GetResizeFilterWindowWeightingType(resizeFilter);
4185 verticalKernel=AcquireOpenCLKernel(device,"ResizeVerticalFilter");
4186 if (verticalKernel == (cl_kernel) NULL)
4188 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4189 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
4193 resizeFilterScale=(float) GetResizeFilterScale(resizeFilter);
4194 resizeFilterSupport=(float) GetResizeFilterSupport(resizeFilter);
4195 resizeFilterBlur=(float) GetResizeFilterBlur(resizeFilter);
4196 resizeFilterWindowSupport=(float) GetResizeFilterWindowSupport(resizeFilter);
4199 status =SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_mem),(void*)&imageBuffer);
4200 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_uint),(void*)&number_channels);
4201 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_uint),(void*)&columns);
4202 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_uint),(void*)&rows);
4203 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_mem),(void*)&resizedImageBuffer);
4204 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_uint),(void*)&resizedColumns);
4205 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_uint),(void*)&resizedRows);
4206 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(float),(void*)&yFactor);
4207 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(int),(void*)&resizeFilterType);
4208 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(int),(void*)&resizeWindowType);
4209 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(cl_mem),(void*)&resizeFilterCubicCoefficients);
4210 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(float),(void*)&resizeFilterScale);
4211 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(float),(void*)&resizeFilterSupport);
4212 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(float),(void*)&resizeFilterWindowSupport);
4213 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(float),(void*)&resizeFilterBlur);
4214 status|=SetOpenCLKernelArg(verticalKernel,i++,imageCacheLocalMemorySize, NULL);
4215 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(int), &numCachedPixels);
4216 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(unsigned int), &pixelPerWorkgroup);
4217 status|=SetOpenCLKernelArg(verticalKernel,i++,sizeof(unsigned int), &chunkSize);
4218 status|=SetOpenCLKernelArg(verticalKernel,i++,pixelAccumulatorLocalMemorySize, NULL);
4219 status|=SetOpenCLKernelArg(verticalKernel,i++,weightAccumulatorLocalMemorySize, NULL);
4220 status|=SetOpenCLKernelArg(verticalKernel,i++,gammaAccumulatorLocalMemorySize, NULL);
4222 if (status != CL_SUCCESS)
4224 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4225 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
4229 gsize[0]=resizedColumns;
4230 gsize[1]=(resizedRows+pixelPerWorkgroup-1)/pixelPerWorkgroup*
4233 lsize[1]=workgroupSize;
4234 outputReady=EnqueueOpenCLKernel(queue,verticalKernel,2,(const size_t *) NULL,
4235 gsize,lsize,image,filteredImage,MagickFalse,exception);
4239 if (verticalKernel != (cl_kernel) NULL)
4240 ReleaseOpenCLKernel(verticalKernel);
4242 return(outputReady);
4245 static Image *ComputeResizeImage(const Image* image,MagickCLEnv clEnv,
4246 const size_t resizedColumns,const size_t resizedRows,
4247 const ResizeFilter *resizeFilter,ExceptionInfo *exception)
4253 cubicCoefficientsBuffer,
4254 filteredImageBuffer,
4262 *resizeFilterCoefficient;
4265 coefficientBuffer[7],
4285 tempImageBuffer=NULL;
4286 cubicCoefficientsBuffer=NULL;
4287 outputReady=MagickFalse;
4289 device=RequestOpenCLDevice(clEnv);
4290 queue=AcquireOpenCLCommandQueue(device);
4291 filteredImage=CloneImage(image,resizedColumns,resizedRows,MagickTrue,
4293 if (filteredImage == (Image *) NULL)
4295 if (filteredImage->number_channels != image->number_channels)
4297 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
4298 if (imageBuffer == (cl_mem) NULL)
4300 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
4301 if (filteredImageBuffer == (cl_mem) NULL)
4304 resizeFilterCoefficient=GetResizeFilterCoefficient(resizeFilter);
4305 for (i = 0; i < 7; i++)
4306 coefficientBuffer[i]=(float) resizeFilterCoefficient[i];
4307 cubicCoefficientsBuffer=CreateOpenCLBuffer(device,CL_MEM_COPY_HOST_PTR |
4308 CL_MEM_READ_ONLY,7*sizeof(*resizeFilterCoefficient),&coefficientBuffer);
4309 if (cubicCoefficientsBuffer == (cl_mem) NULL)
4311 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4312 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
4316 number_channels=(cl_uint) image->number_channels;
4317 xFactor=(float) resizedColumns/(float) image->columns;
4318 yFactor=(float) resizedRows/(float) image->rows;
4319 if (xFactor > yFactor)
4321 length=resizedColumns*image->rows*number_channels;
4322 tempImageBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_WRITE,length*
4323 sizeof(CLQuantum),(void *) NULL);
4324 if (tempImageBuffer == (cl_mem) NULL)
4326 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4327 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
4331 outputReady=resizeHorizontalFilter(device,queue,image,filteredImage,
4332 imageBuffer,number_channels,(cl_uint) image->columns,
4333 (cl_uint) image->rows,tempImageBuffer,(cl_uint) resizedColumns,
4334 (cl_uint) image->rows,resizeFilter,cubicCoefficientsBuffer,xFactor,
4336 if (outputReady == MagickFalse)
4339 outputReady=resizeVerticalFilter(device,queue,image,filteredImage,
4340 tempImageBuffer,number_channels,(cl_uint) resizedColumns,
4341 (cl_uint) image->rows,filteredImageBuffer,(cl_uint) resizedColumns,
4342 (cl_uint) resizedRows,resizeFilter,cubicCoefficientsBuffer,yFactor,
4344 if (outputReady == MagickFalse)
4349 length=image->columns*resizedRows*number_channels;
4350 tempImageBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_WRITE,length*
4351 sizeof(CLQuantum),(void *) NULL);
4352 if (tempImageBuffer == (cl_mem) NULL)
4354 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4355 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
4359 outputReady=resizeVerticalFilter(device,queue,image,filteredImage,
4360 imageBuffer,number_channels,(cl_uint) image->columns,
4361 (cl_int) image->rows,tempImageBuffer,(cl_uint) image->columns,
4362 (cl_uint) resizedRows,resizeFilter,cubicCoefficientsBuffer,yFactor,
4364 if (outputReady == MagickFalse)
4367 outputReady=resizeHorizontalFilter(device,queue,image,filteredImage,
4368 tempImageBuffer,number_channels,(cl_uint) image->columns,
4369 (cl_uint) resizedRows,filteredImageBuffer,(cl_uint) resizedColumns,
4370 (cl_uint) resizedRows,resizeFilter,cubicCoefficientsBuffer,xFactor,
4372 if (outputReady == MagickFalse)
4378 if (tempImageBuffer != (cl_mem) NULL)
4379 ReleaseOpenCLMemObject(tempImageBuffer);
4380 if (cubicCoefficientsBuffer != (cl_mem) NULL)
4381 ReleaseOpenCLMemObject(cubicCoefficientsBuffer);
4382 if (queue != (cl_command_queue) NULL)
4383 ReleaseOpenCLCommandQueue(device,queue);
4384 if (device != (MagickCLDevice) NULL)
4385 ReleaseOpenCLDevice(device);
4386 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
4387 filteredImage=DestroyImage(filteredImage);
4389 return(filteredImage);
4392 static MagickBooleanType gpuSupportedResizeWeighting(
4393 ResizeWeightingFunctionType f)
4400 if (supportedResizeWeighting[i] == LastWeightingFunction)
4402 if (supportedResizeWeighting[i] == f)
4405 return(MagickFalse);
4408 MagickPrivate Image *AccelerateResizeImage(const Image *image,
4409 const size_t resizedColumns,const size_t resizedRows,
4410 const ResizeFilter *resizeFilter,ExceptionInfo *exception)
4418 assert(image != NULL);
4419 assert(exception != (ExceptionInfo *) NULL);
4421 if (checkAccelerateCondition(image) == MagickFalse)
4422 return((Image *) NULL);
4424 if ((gpuSupportedResizeWeighting(GetResizeFilterWeightingType(
4425 resizeFilter)) == MagickFalse) ||
4426 (gpuSupportedResizeWeighting(GetResizeFilterWindowWeightingType(
4427 resizeFilter)) == MagickFalse))
4428 return((Image *) NULL);
4430 clEnv=getOpenCLEnvironment(exception);
4431 if (clEnv == (MagickCLEnv) NULL)
4432 return((Image *) NULL);
4434 filteredImage=ComputeResizeImage(image,clEnv,resizedColumns,resizedRows,
4435 resizeFilter,exception);
4436 return(filteredImage);
4440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4444 % 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 %
4448 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4451 static Image* ComputeRotationalBlurImage(const Image *image,MagickCLEnv clEnv,
4452 const double angle,ExceptionInfo *exception)
4465 filteredImageBuffer,
4470 rotationalBlurKernel;
4497 sinThetaBuffer=NULL;
4498 cosThetaBuffer=NULL;
4499 rotationalBlurKernel=NULL;
4500 outputReady=MagickFalse;
4502 device=RequestOpenCLDevice(clEnv);
4503 queue=AcquireOpenCLCommandQueue(device);
4504 filteredImage=cloneImage(image,exception);
4505 if (filteredImage == (Image *) NULL)
4507 if (filteredImage->number_channels != image->number_channels)
4509 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
4510 if (imageBuffer == (cl_mem) NULL)
4512 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
4513 if (filteredImageBuffer == (cl_mem) NULL)
4516 blurCenter.x=(float) (image->columns-1)/2.0;
4517 blurCenter.y=(float) (image->rows-1)/2.0;
4518 blurRadius=hypot(blurCenter.x,blurCenter.y);
4519 cossin_theta_size=(unsigned int) fabs(4.0*DegreesToRadians(angle)*sqrt(
4520 (double) blurRadius)+2UL);
4522 cosThetaPtr=AcquireQuantumMemory(cossin_theta_size,sizeof(float));
4523 if (cosThetaPtr == (float *) NULL)
4525 sinThetaPtr=AcquireQuantumMemory(cossin_theta_size,sizeof(float));
4526 if (sinThetaPtr == (float *) NULL)
4528 cosThetaPtr=RelinquishMagickMemory(cosThetaPtr);
4532 theta=DegreesToRadians(angle)/(double) (cossin_theta_size-1);
4533 offset=theta*(float) (cossin_theta_size-1)/2.0;
4534 for (i=0; i < (ssize_t) cossin_theta_size; i++)
4536 cosThetaPtr[i]=(float)cos((double) (theta*i-offset));
4537 sinThetaPtr[i]=(float)sin((double) (theta*i-offset));
4540 sinThetaBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_ONLY |
4541 CL_MEM_COPY_HOST_PTR,cossin_theta_size*sizeof(float),sinThetaPtr);
4542 sinThetaPtr=RelinquishMagickMemory(sinThetaPtr);
4543 cosThetaBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_ONLY |
4544 CL_MEM_COPY_HOST_PTR,cossin_theta_size*sizeof(float),cosThetaPtr);
4545 cosThetaPtr=RelinquishMagickMemory(cosThetaPtr);
4546 if ((sinThetaBuffer == (cl_mem) NULL) || (cosThetaBuffer == (cl_mem) NULL))
4548 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4549 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
4553 rotationalBlurKernel=AcquireOpenCLKernel(device,"RotationalBlur");
4554 if (rotationalBlurKernel == (cl_kernel) NULL)
4556 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4557 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
4561 number_channels=(cl_uint) image->number_channels;
4564 status =SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
4565 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_uint),&number_channels);
4566 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(ChannelType), &image->channel_mask);
4567 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_float2), &blurCenter);
4568 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&cosThetaBuffer);
4569 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&sinThetaBuffer);
4570 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_uint), &cossin_theta_size);
4571 status|=SetOpenCLKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
4572 if (status != CL_SUCCESS)
4574 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4575 ResourceLimitWarning,"clEnv->library->clSetKernelArg failed.",".");
4579 gsize[0]=image->columns;
4580 gsize[1]=image->rows;
4581 outputReady=EnqueueOpenCLKernel(queue,rotationalBlurKernel,2,
4582 (const size_t *) NULL,gsize,(const size_t *) NULL,image,filteredImage,
4583 MagickFalse,exception);
4587 if (sinThetaBuffer != (cl_mem) NULL)
4588 ReleaseOpenCLMemObject(sinThetaBuffer);
4589 if (cosThetaBuffer != (cl_mem) NULL)
4590 ReleaseOpenCLMemObject(cosThetaBuffer);
4591 if (rotationalBlurKernel != (cl_kernel) NULL)
4592 ReleaseOpenCLKernel(rotationalBlurKernel);
4593 if (queue != (cl_command_queue) NULL)
4594 ReleaseOpenCLCommandQueue(device,queue);
4595 if (device != (MagickCLDevice) NULL)
4596 ReleaseOpenCLDevice(device);
4597 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
4598 filteredImage=DestroyImage(filteredImage);
4600 return(filteredImage);
4603 MagickPrivate Image* AccelerateRotationalBlurImage(const Image *image,
4604 const double angle,ExceptionInfo *exception)
4612 assert(image != NULL);
4613 assert(exception != (ExceptionInfo *) NULL);
4615 if (checkAccelerateCondition(image) == MagickFalse)
4616 return((Image *) NULL);
4618 clEnv=getOpenCLEnvironment(exception);
4619 if (clEnv == (MagickCLEnv) NULL)
4620 return((Image *) NULL);
4622 filteredImage=ComputeRotationalBlurImage(image,clEnv,angle,exception);
4623 return filteredImage;
4627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4631 % 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 %
4635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4638 static Image *ComputeUnsharpMaskImage(const Image *image,MagickCLEnv clEnv,
4639 const double radius,const double sigma,const double gain,
4640 const double threshold,ExceptionInfo *exception)
4650 unsharpMaskBlurColumnKernel;
4653 filteredImageBuffer,
4689 tempImageBuffer=NULL;
4690 imageKernelBuffer=NULL;
4692 unsharpMaskBlurColumnKernel=NULL;
4693 outputReady=MagickFalse;
4695 device=RequestOpenCLDevice(clEnv);
4696 queue=AcquireOpenCLCommandQueue(device);
4697 filteredImage=cloneImage(image,exception);
4698 if (filteredImage == (Image *) NULL)
4700 if (filteredImage->number_channels != image->number_channels)
4702 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
4703 if (imageBuffer == (cl_mem) NULL)
4705 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
4706 if (filteredImageBuffer == (cl_mem) NULL)
4709 imageKernelBuffer=createKernelInfo(device,radius,sigma,&kernelWidth,
4712 length=image->columns*image->rows;
4713 tempImageBuffer=CreateOpenCLBuffer(device,CL_MEM_READ_WRITE,length*
4714 sizeof(cl_float4),NULL);
4715 if (tempImageBuffer == (cl_mem) NULL)
4717 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4718 ResourceLimitWarning,"CreateOpenCLBuffer failed.",".");
4722 blurRowKernel=AcquireOpenCLKernel(device,"BlurRow");
4723 if (blurRowKernel == (cl_kernel) NULL)
4725 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4726 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
4730 unsharpMaskBlurColumnKernel=AcquireOpenCLKernel(device,
4731 "UnsharpMaskBlurColumn");
4732 if (unsharpMaskBlurColumnKernel == (cl_kernel) NULL)
4734 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4735 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
4739 number_channels=(cl_uint) image->number_channels;
4740 imageColumns=(cl_uint) image->columns;
4741 imageRows=(cl_uint) image->rows;
4746 status =SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
4747 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),&number_channels);
4748 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(ChannelType),&image->channel_mask);
4749 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
4750 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),(void *)&kernelWidth);
4751 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),(void *)&imageColumns);
4752 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_uint),(void *)&imageRows);
4753 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_float4)*(chunkSize+kernelWidth),(void *) NULL);
4754 status|=SetOpenCLKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
4755 if (status != CL_SUCCESS)
4757 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4758 ResourceLimitWarning,"clEnv->library->clSetKernelArg failed.",".");
4762 gsize[0]=chunkSize*((image->columns+chunkSize-1)/chunkSize);
4763 gsize[1]=image->rows;
4766 outputReady=EnqueueOpenCLKernel(queue,blurRowKernel,2,
4767 (const size_t *) NULL,gsize,lsize,image,filteredImage,MagickFalse,
4772 fThreshold=(float) threshold;
4775 status =SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
4776 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
4777 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_uint),&number_channels);
4778 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&image->channel_mask);
4779 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_uint),(void *)&imageColumns);
4780 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_uint),(void *)&imageRows);
4781 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,(chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
4782 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,kernelWidth*sizeof(float),NULL);
4783 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
4784 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_uint),(void *)&kernelWidth);
4785 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
4786 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
4787 status|=SetOpenCLKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
4788 if (status != CL_SUCCESS)
4790 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4791 ResourceLimitWarning,"clEnv->library->clSetKernelArg failed.",".");
4795 gsize[0]=image->columns;
4796 gsize[1]=chunkSize*((image->rows+chunkSize-1)/chunkSize);
4799 outputReady=EnqueueOpenCLKernel(queue,unsharpMaskBlurColumnKernel,2,
4800 (const size_t *) NULL,gsize,lsize,image,filteredImage,MagickFalse,
4805 if (tempImageBuffer != (cl_mem) NULL)
4806 ReleaseOpenCLMemObject(tempImageBuffer);
4807 if (imageKernelBuffer != (cl_mem) NULL)
4808 ReleaseOpenCLMemObject(imageKernelBuffer);
4809 if (blurRowKernel != (cl_kernel) NULL)
4810 ReleaseOpenCLKernel(blurRowKernel);
4811 if (unsharpMaskBlurColumnKernel != (cl_kernel) NULL)
4812 ReleaseOpenCLKernel(unsharpMaskBlurColumnKernel);
4813 if (queue != (cl_command_queue) NULL)
4814 ReleaseOpenCLCommandQueue(device,queue);
4815 if (device != (MagickCLDevice) NULL)
4816 ReleaseOpenCLDevice(device);
4817 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
4818 filteredImage=DestroyImage(filteredImage);
4820 return(filteredImage);
4823 static Image *ComputeUnsharpMaskImageSingle(const Image *image,
4824 MagickCLEnv clEnv,const double radius,const double sigma,const double gain,
4825 const double threshold,ExceptionInfo *exception)
4837 filteredImageBuffer,
4866 imageKernelBuffer=NULL;
4867 unsharpMaskKernel=NULL;
4868 outputReady=MagickFalse;
4870 device=RequestOpenCLDevice(clEnv);
4871 queue=AcquireOpenCLCommandQueue(device);
4872 filteredImage=cloneImage(image,exception);
4873 if (filteredImage == (Image *) NULL)
4875 if (filteredImage->number_channels != image->number_channels)
4877 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
4878 if (imageBuffer == (cl_mem) NULL)
4880 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
4881 if (filteredImageBuffer == (cl_mem) NULL)
4884 imageKernelBuffer=createKernelInfo(device,radius,sigma,&kernelWidth,
4887 unsharpMaskKernel=AcquireOpenCLKernel(device,"UnsharpMask");
4888 if (unsharpMaskKernel == NULL)
4890 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4891 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
4895 imageColumns=(cl_uint) image->columns;
4896 imageRows=(cl_uint) image->rows;
4897 number_channels=(cl_uint) image->number_channels;
4899 fThreshold=(float) threshold;
4902 status =SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
4903 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_uint),(void *)&number_channels);
4904 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(ChannelType),(void *)&image->channel_mask);
4905 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
4906 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_uint),(void *)&kernelWidth);
4907 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_uint),(void *)&imageColumns);
4908 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_uint),(void *)&imageRows);
4909 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_float4)*(8 * (32 + kernelWidth)),(void *) NULL);
4910 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(float),(void *)&fGain);
4911 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(float),(void *)&fThreshold);
4912 status|=SetOpenCLKernelArg(unsharpMaskKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
4913 if (status != CL_SUCCESS)
4915 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
4916 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
4920 gsize[0]=((image->columns + 7) / 8)*8;
4921 gsize[1]=((image->rows + 31) / 32)*32;
4924 outputReady=EnqueueOpenCLKernel(queue,unsharpMaskKernel,2,(const size_t *) NULL,
4925 gsize,lsize,image,filteredImage,MagickFalse,exception);
4929 if (imageKernelBuffer != (cl_mem) NULL)
4930 ReleaseOpenCLMemObject(imageKernelBuffer);
4931 if (unsharpMaskKernel != (cl_kernel) NULL)
4932 ReleaseOpenCLKernel(unsharpMaskKernel);
4933 if (queue != (cl_command_queue) NULL)
4934 ReleaseOpenCLCommandQueue(device,queue);
4935 if (device != (MagickCLDevice) NULL)
4936 ReleaseOpenCLDevice(device);
4937 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
4938 filteredImage=DestroyImage(filteredImage);
4940 return(filteredImage);
4943 MagickPrivate Image *AccelerateUnsharpMaskImage(const Image *image,
4944 const double radius,const double sigma,const double gain,
4945 const double threshold,ExceptionInfo *exception)
4953 assert(image != NULL);
4954 assert(exception != (ExceptionInfo *) NULL);
4956 if (checkAccelerateCondition(image) == MagickFalse)
4957 return((Image *) NULL);
4959 clEnv=getOpenCLEnvironment(exception);
4960 if (clEnv == (MagickCLEnv) NULL)
4961 return((Image *) NULL);
4964 filteredImage=ComputeUnsharpMaskImageSingle(image,clEnv,radius,sigma,gain,
4965 threshold,exception);
4967 filteredImage=ComputeUnsharpMaskImage(image,clEnv,radius,sigma,gain,
4968 threshold,exception);
4969 return(filteredImage);
4972 static Image *ComputeWaveletDenoiseImage(const Image *image,MagickCLEnv clEnv,
4973 const double threshold,ExceptionInfo *exception)
4984 SIZE=TILESIZE-2*PAD;
4996 filteredImageBuffer,
5025 outputReady=MagickFalse;
5027 device=RequestOpenCLDevice(clEnv);
5028 /* Work around an issue on low end Intel devices */
5029 if (strcmp("Intel(R) HD Graphics",device->name) == 0)
5031 queue=AcquireOpenCLCommandQueue(device);
5032 filteredImage=CloneImage(image,image->columns,image->rows,MagickTrue,
5034 if (filteredImage == (Image *) NULL)
5036 if (filteredImage->number_channels != image->number_channels)
5038 imageBuffer=GetAuthenticOpenCLBuffer(image,device,exception);
5039 if (imageBuffer == (cl_mem) NULL)
5041 filteredImageBuffer=GetAuthenticOpenCLBuffer(filteredImage,device,exception);
5042 if (filteredImageBuffer == (cl_mem) NULL)
5045 denoiseKernel=AcquireOpenCLKernel(device,"WaveletDenoise");
5046 if (denoiseKernel == (cl_kernel) NULL)
5048 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
5049 ResourceLimitWarning,"AcquireOpenCLKernel failed.",".");
5053 number_channels=(cl_uint)image->number_channels;
5054 width=(cl_uint)image->columns;
5055 height=(cl_uint)image->rows;
5056 max_channels=number_channels;
5057 if ((max_channels == 4) || (max_channels == 2))
5058 max_channels=max_channels-1;
5060 passes=(((1.0f*image->columns)*image->rows)+1999999.0f)/2000000.0f;
5061 passes=(passes < 1) ? 1 : passes;
5064 status =SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
5065 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
5066 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_uint),(void *)&number_channels);
5067 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_uint),(void *)&max_channels);
5068 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_float),(void *)&thresh);
5069 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_int),(void *)&PASSES);
5070 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_uint),(void *)&width);
5071 status|=SetOpenCLKernelArg(denoiseKernel,i++,sizeof(cl_uint),(void *)&height);
5072 if (status != CL_SUCCESS)
5074 (void) OpenCLThrowMagickException(device,exception,GetMagickModule(),
5075 ResourceLimitWarning,"SetOpenCLKernelArg failed.",".");
5079 for (x = 0; x < passes; ++x)
5081 gsize[0]=((width+(SIZE-1))/SIZE)*TILESIZE;
5082 gsize[1]=((((height+(SIZE-1))/SIZE)+passes-1)/passes)*4;
5086 goffset[1]=x*gsize[1];
5088 outputReady=EnqueueOpenCLKernel(queue,denoiseKernel,2,goffset,gsize,lsize,
5089 image,filteredImage,MagickTrue,exception);
5090 if (outputReady == MagickFalse)
5096 if (denoiseKernel != (cl_kernel) NULL)
5097 ReleaseOpenCLKernel(denoiseKernel);
5098 if (queue != (cl_command_queue) NULL)
5099 ReleaseOpenCLCommandQueue(device,queue);
5100 if (device != (MagickCLDevice) NULL)
5101 ReleaseOpenCLDevice(device);
5102 if ((outputReady == MagickFalse) && (filteredImage != (Image *) NULL))
5103 filteredImage=DestroyImage(filteredImage);
5105 return(filteredImage);
5108 MagickPrivate Image *AccelerateWaveletDenoiseImage(const Image *image,
5109 const double threshold,ExceptionInfo *exception)
5117 assert(image != NULL);
5118 assert(exception != (ExceptionInfo *)NULL);
5120 if (checkAccelerateCondition(image) == MagickFalse)
5121 return((Image *) NULL);
5123 clEnv=getOpenCLEnvironment(exception);
5124 if (clEnv == (MagickCLEnv) NULL)
5125 return((Image *) NULL);
5127 filteredImage=ComputeWaveletDenoiseImage(image,clEnv,threshold,exception);
5129 return(filteredImage);
5131 #endif /* MAGICKCORE_OPENCL_SUPPORT */