2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % OOO PPPP EEEEE N N CCCC L %
8 % O O PPPP EEE N N N C L %
10 % OOO P EEEEE N N CCCC LLLLL %
13 % MagickCore OpenCL Methods %
20 % Copyright 1999-2017 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % https://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/cache-private.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/compare.h"
49 #include "MagickCore/constitute.h"
50 #include "MagickCore/configure.h"
51 #include "MagickCore/distort.h"
52 #include "MagickCore/draw.h"
53 #include "MagickCore/effect.h"
54 #include "MagickCore/exception.h"
55 #include "MagickCore/exception-private.h"
56 #include "MagickCore/fx.h"
57 #include "MagickCore/gem.h"
58 #include "MagickCore/geometry.h"
59 #include "MagickCore/image.h"
60 #include "MagickCore/image-private.h"
61 #include "MagickCore/layer.h"
62 #include "MagickCore/mime-private.h"
63 #include "MagickCore/memory_.h"
64 #include "MagickCore/monitor.h"
65 #include "MagickCore/montage.h"
66 #include "MagickCore/morphology.h"
67 #include "MagickCore/nt-base.h"
68 #include "MagickCore/nt-base-private.h"
69 #include "MagickCore/opencl.h"
70 #include "MagickCore/opencl-private.h"
71 #include "MagickCore/option.h"
72 #include "MagickCore/policy.h"
73 #include "MagickCore/property.h"
74 #include "MagickCore/quantize.h"
75 #include "MagickCore/quantum.h"
76 #include "MagickCore/random_.h"
77 #include "MagickCore/random-private.h"
78 #include "MagickCore/resample.h"
79 #include "MagickCore/resource_.h"
80 #include "MagickCore/splay-tree.h"
81 #include "MagickCore/semaphore.h"
82 #include "MagickCore/statistic.h"
83 #include "MagickCore/string_.h"
84 #include "MagickCore/string-private.h"
85 #include "MagickCore/token.h"
86 #include "MagickCore/utility.h"
87 #include "MagickCore/utility-private.h"
89 #if defined(MAGICKCORE_OPENCL_SUPPORT)
91 #ifndef MAGICKCORE_WINDOWS_SUPPORT
95 #ifdef MAGICKCORE_HAVE_OPENCL_CL_H
96 #define MAGICKCORE_OPENCL_MACOSX 1
102 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile.xml"
105 Typedef declarations.
128 } MagickCLDeviceBenchmark;
131 Forward declarations.
134 static MagickBooleanType
135 HasOpenCLDevices(MagickCLEnv,ExceptionInfo *),
136 LoadOpenCLLibrary(void);
138 static MagickCLDevice
139 RelinquishMagickCLDevice(MagickCLDevice);
142 RelinquishMagickCLEnv(MagickCLEnv);
145 BenchmarkOpenCLDevices(MagickCLEnv);
148 *accelerateKernels, *accelerateKernels2;
154 /* Default OpenCL environment */
162 /* Cached location of the OpenCL cache files */
166 *cache_directory_lock;
168 static inline MagickBooleanType IsSameOpenCLDevice(MagickCLDevice a,
171 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
172 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
173 (LocaleCompare(a->name,b->name) == 0) &&
174 (LocaleCompare(a->version,b->version) == 0) &&
175 (a->max_clock_frequency == b->max_clock_frequency) &&
176 (a->max_compute_units == b->max_compute_units))
182 static inline MagickBooleanType IsBenchmarkedOpenCLDevice(MagickCLDevice a,
183 MagickCLDeviceBenchmark *b)
185 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
186 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
187 (LocaleCompare(a->name,b->name) == 0) &&
188 (LocaleCompare(a->version,b->version) == 0) &&
189 (a->max_clock_frequency == b->max_clock_frequency) &&
190 (a->max_compute_units == b->max_compute_units))
196 static inline void RelinquishMagickCLDevices(MagickCLEnv clEnv)
201 if (clEnv->devices != (MagickCLDevice *) NULL)
203 for (i = 0; i < clEnv->number_devices; i++)
204 clEnv->devices[i]=RelinquishMagickCLDevice(clEnv->devices[i]);
205 clEnv->devices=(MagickCLDevice *) RelinquishMagickMemory(clEnv->devices);
207 clEnv->number_devices=0;
210 static inline MagickBooleanType MagickCreateDirectory(const char *path)
215 #ifdef MAGICKCORE_WINDOWS_SUPPORT
218 status=mkdir(path, 0777);
220 return(status == 0 ? MagickTrue : MagickFalse);
223 static inline void InitAccelerateTimer(AccelerateTimer *timer)
226 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->freq);
228 timer->freq=(long long)1.0E3;
234 static inline double ReadAccelerateTimer(AccelerateTimer *timer)
236 return (double)timer->clocks/(double)timer->freq;
239 static inline void StartAccelerateTimer(AccelerateTimer* timer)
242 QueryPerformanceCounter((LARGE_INTEGER*)&timer->start);
247 timer->start=(long long)s.tv_sec*(long long)1.0E3+(long long)s.tv_usec/
252 static inline void StopAccelerateTimer(AccelerateTimer *timer)
259 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
264 n=(long long)s.tv_sec*(long long)1.0E3+(long long)s.tv_usec/
272 static const char *GetOpenCLCacheDirectory()
274 if (cache_directory == (char *) NULL)
276 if (cache_directory_lock == (SemaphoreInfo *) NULL)
277 ActivateSemaphoreInfo(&cache_directory_lock);
278 LockSemaphoreInfo(cache_directory_lock);
279 if (cache_directory == (char *) NULL)
283 path[MagickPathExtent],
293 home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
294 if (home == (char *) NULL)
296 home=GetEnvironmentValue("XDG_CACHE_HOME");
297 if (home == (char *) NULL)
298 home=GetEnvironmentValue("LOCALAPPDATA");
299 if (home == (char *) NULL)
300 home=GetEnvironmentValue("APPDATA");
301 if (home == (char *) NULL)
302 home=GetEnvironmentValue("USERPROFILE");
305 if (home != (char *) NULL)
307 /* first check if $HOME exists */
308 (void) FormatLocaleString(path,MagickPathExtent,"%s",home);
309 status=GetPathAttributes(path,&attributes);
310 if (status == MagickFalse)
311 status=MagickCreateDirectory(path);
313 /* first check if $HOME/ImageMagick exists */
314 if (status != MagickFalse)
316 (void) FormatLocaleString(path,MagickPathExtent,
317 "%s%sImageMagick",home,DirectorySeparator);
319 status=GetPathAttributes(path,&attributes);
320 if (status == MagickFalse)
321 status=MagickCreateDirectory(path);
324 if (status != MagickFalse)
326 temp=(char*) AcquireMagickMemory(strlen(path)+1);
327 CopyMagickString(temp,path,strlen(path)+1);
329 home=DestroyString(home);
333 home=GetEnvironmentValue("HOME");
334 if (home != (char *) NULL)
336 /* first check if $HOME/.cache exists */
337 (void) FormatLocaleString(path,MagickPathExtent,"%s%s.cache",
338 home,DirectorySeparator);
339 status=GetPathAttributes(path,&attributes);
340 if (status == MagickFalse)
341 status=MagickCreateDirectory(path);
343 /* first check if $HOME/.cache/ImageMagick exists */
344 if (status != MagickFalse)
346 (void) FormatLocaleString(path,MagickPathExtent,
347 "%s%s.cache%sImageMagick",home,DirectorySeparator,
349 status=GetPathAttributes(path,&attributes);
350 if (status == MagickFalse)
351 status=MagickCreateDirectory(path);
354 if (status != MagickFalse)
356 temp=(char*) AcquireMagickMemory(strlen(path)+1);
357 CopyMagickString(temp,path,strlen(path)+1);
359 home=DestroyString(home);
362 if (temp == (char *) NULL)
363 temp=AcquireString("?");
364 cache_directory=temp;
366 UnlockSemaphoreInfo(cache_directory_lock);
368 if (*cache_directory == '?')
369 return((const char *) NULL);
370 return(cache_directory);
373 static void SelectOpenCLDevice(MagickCLEnv clEnv,cl_device_type type)
382 for (i = 0; i < clEnv->number_devices; i++)
383 clEnv->devices[i]->enabled=MagickFalse;
385 for (i = 0; i < clEnv->number_devices; i++)
387 device=clEnv->devices[i];
388 if (device->type != type)
391 device->enabled=MagickTrue;
392 for (j = i+1; j < clEnv->number_devices; j++)
397 other_device=clEnv->devices[j];
398 if (IsSameOpenCLDevice(device,other_device))
399 other_device->enabled=MagickTrue;
404 static size_t StringSignature(const char* string)
419 stringLength=(size_t) strlen(string);
420 signature=stringLength;
421 n=stringLength/sizeof(size_t);
423 for (i = 0; i < n; i++)
425 if (n * sizeof(size_t) != stringLength)
431 for (i = 0; i < 4; i++, j++)
433 if (j < stringLength)
445 Provide call to OpenCL library methods
448 MagickPrivate cl_mem CreateOpenCLBuffer(MagickCLDevice device,
449 cl_mem_flags flags,size_t size,void *host_ptr)
451 return(openCL_library->clCreateBuffer(device->context,flags,size,host_ptr,
455 MagickPrivate void ReleaseOpenCLKernel(cl_kernel kernel)
457 (void) openCL_library->clReleaseKernel(kernel);
460 MagickPrivate void ReleaseOpenCLMemObject(cl_mem memobj)
462 (void) openCL_library->clReleaseMemObject(memobj);
465 MagickPrivate cl_int SetOpenCLKernelArg(cl_kernel kernel,size_t arg_index,
466 size_t arg_size,const void *arg_value)
468 return(openCL_library->clSetKernelArg(kernel,(cl_uint) arg_index,arg_size,
473 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 + A c q u i r e M a g i c k C L C a c h e I n f o %
481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 % AcquireMagickCLCacheInfo() acquires an OpenCL cache info structure.
485 % The format of the AcquireMagickCLCacheInfo method is:
487 % MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
488 % Quantum *pixels,const MagickSizeType length)
490 % A description of each parameter follows:
492 % o device: the OpenCL device.
494 % o pixels: the pixel buffer of the image.
496 % o length: the length of the pixel buffer.
500 MagickPrivate MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
501 Quantum *pixels,const MagickSizeType length)
509 info=(MagickCLCacheInfo) AcquireMagickMemory(sizeof(*info));
510 if (info == (MagickCLCacheInfo) NULL)
511 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
512 (void) ResetMagickMemory(info,0,sizeof(*info));
513 LockSemaphoreInfo(openCL_lock);
515 UnlockSemaphoreInfo(openCL_lock);
519 info->buffer=openCL_library->clCreateBuffer(device->context,
520 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,(size_t) length,(void *) pixels,
522 if (status == CL_SUCCESS)
524 LockSemaphoreInfo(openCL_lock);
526 UnlockSemaphoreInfo(openCL_lock);
527 return((MagickCLCacheInfo) RelinquishMagickMemory(info));
531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535 % A c q u i r e M a g i c k C L D e v i c e %
539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 % AcquireMagickCLDevice() acquires an OpenCL device
543 % The format of the AcquireMagickCLDevice method is:
545 % MagickCLDevice AcquireMagickCLDevice()
549 static MagickCLDevice AcquireMagickCLDevice()
554 device=(MagickCLDevice) AcquireMagickMemory(sizeof(*device));
557 (void) ResetMagickMemory(device,0,sizeof(*device));
558 ActivateSemaphoreInfo(&device->lock);
559 device->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
560 device->command_queues_index=-1;
561 device->enabled=MagickTrue;
567 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
571 % A c q u i r e M a g i c k C L E n v %
575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577 % AcquireMagickCLEnv() allocates the MagickCLEnv structure
581 static MagickCLEnv AcquireMagickCLEnv(void)
589 clEnv=(MagickCLEnv) AcquireMagickMemory(sizeof(*clEnv));
590 if (clEnv != (MagickCLEnv) NULL)
592 (void) ResetMagickMemory(clEnv,0,sizeof(*clEnv));
593 ActivateSemaphoreInfo(&clEnv->lock);
594 clEnv->cpu_score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
595 clEnv->enabled=MagickTrue;
596 option=getenv("MAGICK_OCL_DEVICE");
597 if ((option != (const char *) NULL) && (strcmp(option,"OFF") == 0))
598 clEnv->enabled=MagickFalse;
604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608 + A c q u i r e O p e n C L C o m m a n d Q u e u e %
612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
616 % The format of the AcquireOpenCLCommandQueue method is:
618 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
620 % A description of each parameter follows:
622 % o device: the OpenCL device.
626 MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
631 cl_command_queue_properties
634 assert(device != (MagickCLDevice) NULL);
635 LockSemaphoreInfo(device->lock);
636 if ((device->profile_kernels == MagickFalse) &&
637 (device->command_queues_index >= 0))
639 queue=device->command_queues[device->command_queues_index--];
640 UnlockSemaphoreInfo(device->lock);
644 UnlockSemaphoreInfo(device->lock);
645 properties=(cl_command_queue_properties) NULL;
646 if (device->profile_kernels != MagickFalse)
647 properties=CL_QUEUE_PROFILING_ENABLE;
648 queue=openCL_library->clCreateCommandQueue(device->context,
649 device->deviceID,properties,(cl_int *) NULL);
655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659 + A c q u i r e O p e n C L K e r n e l %
663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 % AcquireOpenCLKernel() acquires an OpenCL kernel
667 % The format of the AcquireOpenCLKernel method is:
669 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
670 % MagickOpenCLProgram program, const char* kernelName)
672 % A description of each parameter follows:
674 % o clEnv: the OpenCL environment.
676 % o program: the OpenCL program module that the kernel belongs to.
678 % o kernelName: the name of the kernel
682 MagickPrivate cl_kernel AcquireOpenCLKernel(MagickCLDevice device,
683 const char *kernel_name)
688 assert(device != (MagickCLDevice) NULL);
689 kernel=openCL_library->clCreateKernel(device->program,kernel_name,
695 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
699 % A u t o S e l e c t O p e n C L D e v i c e s %
703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
705 % AutoSelectOpenCLDevices() determines the best device based on the
706 % information from the micro-benchmark.
708 % The format of the AutoSelectOpenCLDevices method is:
710 % void AcquireOpenCLKernel(MagickCLEnv clEnv,ExceptionInfo *exception)
712 % A description of each parameter follows:
714 % o clEnv: the OpenCL environment.
716 % o exception: return any errors or warnings in this structure.
720 static void LoadOpenCLDeviceBenchmark(MagickCLEnv clEnv,const char *xml)
723 keyword[MagickPathExtent],
729 MagickCLDeviceBenchmark
736 if (xml == (char *) NULL)
738 device_benchmark=(MagickCLDeviceBenchmark *) NULL;
739 token=AcquireString(xml);
740 extent=strlen(token)+MagickPathExtent;
741 for (q=(char *) xml; *q != '\0'; )
746 GetNextToken(q,&q,extent,token);
749 (void) CopyMagickString(keyword,token,MagickPathExtent);
750 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
755 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
756 GetNextToken(q,&q,extent,token);
759 if (LocaleNCompare(keyword,"<!--",4) == 0)
764 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
765 GetNextToken(q,&q,extent,token);
768 if (LocaleCompare(keyword,"<device") == 0)
773 device_benchmark=(MagickCLDeviceBenchmark *) AcquireMagickMemory(
774 sizeof(*device_benchmark));
775 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
777 (void) ResetMagickMemory(device_benchmark,0,sizeof(*device_benchmark));
778 device_benchmark->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
781 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
783 if (LocaleCompare(keyword,"/>") == 0)
785 if (device_benchmark->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
787 if (LocaleCompare(device_benchmark->name, "CPU") == 0)
788 clEnv->cpu_score=device_benchmark->score;
795 Set the score for all devices that match this device.
797 for (i = 0; i < clEnv->number_devices; i++)
799 device=clEnv->devices[i];
800 if (IsBenchmarkedOpenCLDevice(device,device_benchmark))
801 device->score=device_benchmark->score;
806 device_benchmark->platform_name=RelinquishMagickMemory(
807 device_benchmark->platform_name);
808 device_benchmark->vendor_name=RelinquishMagickMemory(
809 device_benchmark->vendor_name);
810 device_benchmark->name=RelinquishMagickMemory(device_benchmark->name);
811 device_benchmark->version=RelinquishMagickMemory(
812 device_benchmark->version);
813 device_benchmark=(MagickCLDeviceBenchmark *) RelinquishMagickMemory(
817 GetNextToken(q,(const char **) NULL,extent,token);
820 GetNextToken(q,&q,extent,token);
821 GetNextToken(q,&q,extent,token);
827 if (LocaleCompare((char *) keyword,"maxClockFrequency") == 0)
829 device_benchmark->max_clock_frequency=StringToInteger(token);
832 if (LocaleCompare((char *) keyword,"maxComputeUnits") == 0)
834 device_benchmark->max_compute_units=StringToInteger(token);
842 if (LocaleCompare((char *) keyword,"name") == 0)
843 device_benchmark->name=ConstantString(token);
849 if (LocaleCompare((char *) keyword,"platform") == 0)
850 device_benchmark->platform_name=ConstantString(token);
856 if (LocaleCompare((char *) keyword,"score") == 0)
857 device_benchmark->score=StringToDouble(token,(char **) NULL);
863 if (LocaleCompare((char *) keyword,"vendor") == 0)
864 device_benchmark->vendor_name=ConstantString(token);
865 if (LocaleCompare((char *) keyword,"version") == 0)
866 device_benchmark->version=ConstantString(token);
873 token=(char *) RelinquishMagickMemory(token);
874 device_benchmark=(MagickCLDeviceBenchmark *) RelinquishMagickMemory(
878 static MagickBooleanType CanWriteProfileToFile(const char *filename)
883 profileFile=fopen(filename,"ab");
885 if (profileFile == (FILE *)NULL)
892 static MagickBooleanType LoadOpenCLBenchmarks(MagickCLEnv clEnv)
895 filename[MagickPathExtent];
903 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
904 GetOpenCLCacheDirectory(),DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
907 We don't run the benchmark when we can not write out a device profile. The
908 first GPU device will be used.
910 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
911 if (CanWriteProfileToFile(filename) == MagickFalse)
914 for (i = 0; i < clEnv->number_devices; i++)
915 clEnv->devices[i]->score=1.0;
917 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
921 option=ConfigureFileToStringInfo(filename);
922 LoadOpenCLDeviceBenchmark(clEnv,(const char *) GetStringInfoDatum(option));
923 option=DestroyStringInfo(option);
927 static void AutoSelectOpenCLDevices(MagickCLEnv clEnv)
941 option=getenv("MAGICK_OCL_DEVICE");
942 if (option != (const char *) NULL)
944 if (strcmp(option,"GPU") == 0)
945 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
946 else if (strcmp(option,"CPU") == 0)
947 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_CPU);
948 else if (strcmp(option,"OFF") == 0)
950 for (i = 0; i < clEnv->number_devices; i++)
951 clEnv->devices[i]->enabled=MagickFalse;
952 clEnv->enabled=MagickFalse;
956 if (LoadOpenCLBenchmarks(clEnv) == MagickFalse)
959 benchmark=MagickFalse;
960 if (clEnv->cpu_score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
961 benchmark=MagickTrue;
964 for (i = 0; i < clEnv->number_devices; i++)
966 if (clEnv->devices[i]->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
968 benchmark=MagickTrue;
974 if (benchmark != MagickFalse)
975 BenchmarkOpenCLDevices(clEnv);
977 best_score=clEnv->cpu_score;
978 for (i = 0; i < clEnv->number_devices; i++)
979 best_score=MagickMin(clEnv->devices[i]->score,best_score);
981 for (i = 0; i < clEnv->number_devices; i++)
983 if (clEnv->devices[i]->score != best_score)
984 clEnv->devices[i]->enabled=MagickFalse;
989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 % B e n c h m a r k O p e n C L D e v i c e s %
997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
999 % BenchmarkOpenCLDevices() benchmarks the OpenCL devices and the CPU to help
1000 % the automatic selection of the best device.
1002 % The format of the BenchmarkOpenCLDevices method is:
1004 % void BenchmarkOpenCLDevices(MagickCLEnv clEnv,ExceptionInfo *exception)
1006 % A description of each parameter follows:
1008 % o clEnv: the OpenCL environment.
1010 % o exception: return any errors or warnings
1013 static double RunOpenCLBenchmark(MagickBooleanType is_cpu)
1030 exception=AcquireExceptionInfo();
1031 imageInfo=AcquireImageInfo();
1032 CloneString(&imageInfo->size,"2048x1536");
1033 CopyMagickString(imageInfo->filename,"xc:none",MagickPathExtent);
1034 inputImage=ReadImage(imageInfo,exception);
1036 InitAccelerateTimer(&timer);
1038 for (i=0; i<=2; i++)
1046 StartAccelerateTimer(&timer);
1048 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
1049 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
1051 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
1055 We need this to get a proper performance benchmark, the operations
1056 are executed asynchronous.
1058 if (is_cpu == MagickFalse)
1063 cache_info=(CacheInfo *) resizedImage->cache;
1064 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1065 openCL_library->clWaitForEvents(cache_info->opencl->event_count,
1066 cache_info->opencl->events);
1070 StopAccelerateTimer(&timer);
1072 if (bluredImage != (Image *) NULL)
1073 DestroyImage(bluredImage);
1074 if (unsharpedImage != (Image *) NULL)
1075 DestroyImage(unsharpedImage);
1076 if (resizedImage != (Image *) NULL)
1077 DestroyImage(resizedImage);
1079 DestroyImage(inputImage);
1080 return(ReadAccelerateTimer(&timer));
1083 static void RunDeviceBenckmark(MagickCLEnv clEnv,MagickCLEnv testEnv,
1084 MagickCLDevice device)
1086 testEnv->devices[0]=device;
1087 default_CLEnv=testEnv;
1088 device->score=RunOpenCLBenchmark(MagickFalse);
1089 default_CLEnv=clEnv;
1090 testEnv->devices[0]=(MagickCLDevice) NULL;
1093 static void CacheOpenCLBenchmarks(MagickCLEnv clEnv)
1096 filename[MagickPathExtent];
1108 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1109 GetOpenCLCacheDirectory(),DirectorySeparator,
1110 IMAGEMAGICK_PROFILE_FILE);
1112 cache_file=fopen_utf8(filename,"wb");
1113 if (cache_file == (FILE *) NULL)
1115 fwrite("<devices>\n",sizeof(char),10,cache_file);
1116 fprintf(cache_file," <device name=\"CPU\" score=\"%.4g\"/>\n",
1118 for (i = 0; i < clEnv->number_devices; i++)
1123 device=clEnv->devices[i];
1124 duplicate=MagickFalse;
1125 for (j = 0; j < i; j++)
1127 if (IsSameOpenCLDevice(clEnv->devices[j],device))
1129 duplicate=MagickTrue;
1137 if (device->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1138 fprintf(cache_file," <device platform=\"%s\" vendor=\"%s\" name=\"%s\"\
1139 version=\"%s\" maxClockFrequency=\"%d\" maxComputeUnits=\"%d\"\
1140 score=\"%.4g\"/>\n",
1141 device->platform_name,device->vendor_name,device->name,device->version,
1142 (int)device->max_clock_frequency,(int)device->max_compute_units,
1145 fwrite("</devices>",sizeof(char),10,cache_file);
1150 static void BenchmarkOpenCLDevices(MagickCLEnv clEnv)
1162 testEnv=AcquireMagickCLEnv();
1163 testEnv->library=openCL_library;
1164 testEnv->devices=(MagickCLDevice *) AcquireMagickMemory(
1165 sizeof(MagickCLDevice));
1166 testEnv->number_devices=1;
1167 testEnv->benchmark_thread_id=GetMagickThreadId();
1168 testEnv->initialized=MagickTrue;
1170 for (i = 0; i < clEnv->number_devices; i++)
1171 clEnv->devices[i]->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
1173 for (i = 0; i < clEnv->number_devices; i++)
1175 device=clEnv->devices[i];
1176 if (device->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1177 RunDeviceBenckmark(clEnv,testEnv,device);
1179 /* Set the score on all the other devices that are the same */
1180 for (j = i+1; j < clEnv->number_devices; j++)
1185 other_device=clEnv->devices[j];
1186 if (IsSameOpenCLDevice(device,other_device))
1187 other_device->score=device->score;
1191 testEnv->enabled=MagickFalse;
1192 default_CLEnv=testEnv;
1193 clEnv->cpu_score=RunOpenCLBenchmark(MagickTrue);
1194 default_CLEnv=clEnv;
1196 testEnv=RelinquishMagickCLEnv(testEnv);
1197 CacheOpenCLBenchmarks(clEnv);
1201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % C o m p i l e O p e n C L K e r n e l %
1209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1211 % CompileOpenCLKernel() compiles the kernel for the specified device. The
1212 % kernel will be cached on disk to reduce the compilation time.
1214 % The format of the CompileOpenCLKernel method is:
1216 % MagickBooleanType AcquireOpenCLKernel(MagickCLDevice clEnv,
1217 % unsigned int signature,const char *kernel,const char *options,
1218 % ExceptionInfo *exception)
1220 % A description of each parameter follows:
1222 % o device: the OpenCL device.
1224 % o kernel: the source code of the kernel.
1226 % o options: options for the compiler.
1228 % o signature: a number to uniquely identify the kernel
1230 % o exception: return any errors or warnings in this structure.
1234 static void CacheOpenCLKernel(MagickCLDevice device,char *filename,
1235 ExceptionInfo *exception)
1246 status=openCL_library->clGetProgramInfo(device->program,
1247 CL_PROGRAM_BINARY_SIZES,sizeof(size_t),&binaryProgramSize,NULL);
1248 if (status != CL_SUCCESS)
1251 binaryProgram=(unsigned char*) AcquireMagickMemory(binaryProgramSize);
1252 status=openCL_library->clGetProgramInfo(device->program,
1253 CL_PROGRAM_BINARIES,sizeof(unsigned char*),&binaryProgram,NULL);
1254 if (status == CL_SUCCESS)
1255 (void) BlobToFile(filename,binaryProgram,binaryProgramSize,exception);
1256 binaryProgram=(unsigned char *) RelinquishMagickMemory(binaryProgram);
1259 static MagickBooleanType LoadCachedOpenCLKernel(MagickCLDevice device,
1260 const char *filename)
1275 exception=AcquireExceptionInfo();
1276 binaryProgram=(unsigned char *) FileToBlob(filename,~0UL,&length,exception);
1277 exception=DestroyExceptionInfo(exception);
1278 if (binaryProgram == (unsigned char *) NULL)
1279 return(MagickFalse);
1280 device->program=openCL_library->clCreateProgramWithBinary(device->context,1,
1281 &device->deviceID,&length,(const unsigned char**)&binaryProgram,
1282 &binaryStatus,&status);
1283 binaryProgram=(unsigned char *) RelinquishMagickMemory(binaryProgram);
1284 return((status != CL_SUCCESS) || (binaryStatus != CL_SUCCESS) ? MagickFalse :
1288 static void LogOpenCLBuildFailure(MagickCLDevice device,const char *kernel,
1289 ExceptionInfo *exception)
1292 filename[MagickPathExtent],
1298 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1299 GetOpenCLCacheDirectory(),DirectorySeparator,"magick_badcl.cl");
1301 (void) remove_utf8(filename);
1302 (void) BlobToFile(filename,kernel,strlen(kernel),exception);
1304 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1305 CL_PROGRAM_BUILD_LOG,0,NULL,&log_size);
1306 log=(char*)AcquireMagickMemory(log_size);
1307 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1308 CL_PROGRAM_BUILD_LOG,log_size,log,&log_size);
1310 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1311 GetOpenCLCacheDirectory(),DirectorySeparator,"magick_badcl.log");
1313 (void) remove_utf8(filename);
1314 (void) BlobToFile(filename,log,log_size,exception);
1315 log=(char*)RelinquishMagickMemory(log);
1318 static MagickBooleanType CompileOpenCLKernel(MagickCLDevice device,
1319 const char *kernel,const char *options,size_t signature,
1320 ExceptionInfo *exception)
1323 deviceName[MagickPathExtent],
1324 filename[MagickPathExtent],
1336 (void) CopyMagickString(deviceName,device->name,MagickPathExtent);
1338 /* Strip out illegal characters for file names */
1339 while (*ptr != '\0')
1341 if ((*ptr == ' ') || (*ptr == '\\') || (*ptr == '/') || (*ptr == ':') ||
1342 (*ptr == '*') || (*ptr == '?') || (*ptr == '"') || (*ptr == '<') ||
1343 (*ptr == '>' || *ptr == '|'))
1347 (void) FormatLocaleString(filename,MagickPathExtent,
1348 "%s%s%s_%s_%08x_%.20g.bin",GetOpenCLCacheDirectory(),
1349 DirectorySeparator,"magick_opencl",deviceName,signature,
1350 (double) sizeof(char*)*8);
1351 loaded=LoadCachedOpenCLKernel(device,filename);
1352 if (loaded == MagickFalse)
1354 /* Binary CL program unavailable, compile the program from source */
1355 length=strlen(kernel);
1356 device->program=openCL_library->clCreateProgramWithSource(
1357 device->context,1,&kernel,&length,&status);
1358 if (status != CL_SUCCESS)
1359 return(MagickFalse);
1362 status=openCL_library->clBuildProgram(device->program,1,&device->deviceID,
1364 if (status != CL_SUCCESS)
1366 (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
1367 "clBuildProgram failed.","(%d)",(int)status);
1368 LogOpenCLBuildFailure(device,kernel,exception);
1369 return(MagickFalse);
1372 /* Save the binary to a file to avoid re-compilation of the kernels */
1373 if (loaded == MagickFalse)
1374 CacheOpenCLKernel(device,filename,exception);
1380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1384 + C o p y M a g i c k C L C a c h e I n f o %
1388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1390 % CopyMagickCLCacheInfo() copies the memory from the device into host memory.
1392 % The format of the CopyMagickCLCacheInfo method is:
1394 % void CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1396 % A description of each parameter follows:
1398 % o info: the OpenCL cache info.
1401 MagickPrivate MagickCLCacheInfo CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1409 if (info == (MagickCLCacheInfo) NULL)
1410 return((MagickCLCacheInfo) NULL);
1411 if (info->event_count > 0)
1413 queue=AcquireOpenCLCommandQueue(info->device);
1414 pixels=openCL_library->clEnqueueMapBuffer(queue,info->buffer,CL_TRUE,
1415 CL_MAP_READ | CL_MAP_WRITE,0,info->length,info->event_count,
1416 info->events,(cl_event *) NULL,(cl_int *) NULL);
1417 assert(pixels == info->pixels);
1418 ReleaseOpenCLCommandQueue(info->device,queue);
1420 return(RelinquishMagickCLCacheInfo(info,MagickFalse));
1424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1428 + D u m p O p e n C L P r o f i l e D a t a %
1432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434 % DumpOpenCLProfileData() dumps the kernel profile data.
1436 % The format of the DumpProfileData method is:
1438 % void DumpProfileData()
1442 MagickPrivate void DumpOpenCLProfileData()
1444 #define OpenCLLog(message) \
1445 fwrite(message,sizeof(char),strlen(message),log); \
1446 fwrite("\n",sizeof(char),1,log);
1450 filename[MagickPathExtent],
1463 clEnv=GetCurrentOpenCLEnv();
1464 if (clEnv == (MagickCLEnv) NULL)
1467 for (i = 0; i < clEnv->number_devices; i++)
1468 if (clEnv->devices[i]->profile_kernels != MagickFalse)
1470 if (i == clEnv->number_devices)
1473 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1474 GetOpenCLCacheDirectory(),DirectorySeparator,"ImageMagickOpenCL.log");
1476 log=fopen_utf8(filename,"wb");
1478 for (i = 0; i < clEnv->number_devices; i++)
1483 device=clEnv->devices[i];
1484 if ((device->profile_kernels == MagickFalse) ||
1485 (device->profile_records == (KernelProfileRecord *) NULL))
1488 OpenCLLog("====================================================");
1489 fprintf(log,"Device: %s\n",device->name);
1490 fprintf(log,"Version: %s\n",device->version);
1491 OpenCLLog("====================================================");
1492 OpenCLLog(" average calls min max");
1493 OpenCLLog(" ------- ----- --- ---");
1495 while (device->profile_records[j] != (KernelProfileRecord) NULL)
1500 profile=device->profile_records[j];
1502 strncpy(indent,profile->kernel_name,MagickMin(strlen(
1503 profile->kernel_name),strlen(indent)-1));
1504 sprintf(buf,"%s %7d %7d %7d %7d",indent,(int) (profile->total/
1505 profile->count),(int) profile->count,(int) profile->min,
1506 (int) profile->max);
1510 OpenCLLog("====================================================");
1511 fwrite("\n\n",sizeof(char),2,log);
1516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1520 + E n q u e u e O p e n C L K e r n e l %
1524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526 % EnqueueOpenCLKernel() enques the specified kernel and registers the OpenCL
1527 % events with the images.
1529 % The format of the EnqueueOpenCLKernel method is:
1531 % MagickBooleanType EnqueueOpenCLKernel(cl_kernel kernel,cl_uint work_dim,
1532 % const size_t *global_work_offset,const size_t *global_work_size,
1533 % const size_t *local_work_size,const Image *input_image,
1534 % const Image *output_image,ExceptionInfo *exception)
1536 % A description of each parameter follows:
1538 % o kernel: the OpenCL kernel.
1540 % o work_dim: the number of dimensions used to specify the global work-items
1541 % and work-items in the work-group.
1543 % o offset: can be used to specify an array of work_dim unsigned values
1544 % that describe the offset used to calculate the global ID of a
1547 % o gsize: points to an array of work_dim unsigned values that describe the
1548 % number of global work-items in work_dim dimensions that will
1549 % execute the kernel function.
1551 % o lsize: points to an array of work_dim unsigned values that describe the
1552 % number of work-items that make up a work-group that will execute
1553 % the kernel specified by kernel.
1555 % o input_image: the input image of the operation.
1557 % o output_image: the output or secondairy image of the operation.
1559 % o exception: return any errors or warnings in this structure.
1563 static void RegisterCacheEvent(MagickCLCacheInfo info,cl_event event)
1565 assert(info != (MagickCLCacheInfo) NULL);
1566 assert(event != (cl_event) NULL);
1567 if (info->events == (cl_event *) NULL)
1569 info->events=AcquireMagickMemory(sizeof(*info->events));
1570 info->event_count=1;
1573 info->events=ResizeQuantumMemory(info->events,++info->event_count,
1574 sizeof(*info->events));
1575 if (info->events == (cl_event *) NULL)
1576 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1577 info->events[info->event_count-1]=event;
1578 openCL_library->clRetainEvent(event);
1581 MagickPrivate MagickBooleanType EnqueueOpenCLKernel(cl_command_queue queue,
1582 cl_kernel kernel,cl_uint work_dim,const size_t *offset,const size_t *gsize,
1583 const size_t *lsize,const Image *input_image,const Image *output_image,
1584 MagickBooleanType flush,ExceptionInfo *exception)
1600 assert(input_image != (const Image *) NULL);
1601 input_info=(CacheInfo *) input_image->cache;
1602 assert(input_info != (CacheInfo *) NULL);
1603 assert(input_info->opencl != (MagickCLCacheInfo) NULL);
1604 event_count=input_info->opencl->event_count;
1605 events=input_info->opencl->events;
1606 output_info=(CacheInfo *) NULL;
1607 if (output_image != (const Image *) NULL)
1609 output_info=(CacheInfo *) output_image->cache;
1610 assert(output_info != (CacheInfo *) NULL);
1611 assert(output_info->opencl != (MagickCLCacheInfo) NULL);
1612 if (output_info->opencl->event_count > 0)
1617 event_count+=output_info->opencl->event_count;
1618 events=AcquireQuantumMemory(event_count,sizeof(*events));
1619 if (events == (cl_event *) NULL)
1620 return(MagickFalse);
1621 for (i=0; i < (ssize_t) event_count; i++)
1623 if (i < (ssize_t) input_info->opencl->event_count)
1624 events[i]=input_info->opencl->events[i];
1626 events[i]=output_info->opencl->events[i-
1627 input_info->opencl->event_count];
1631 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,offset,
1632 gsize,lsize,event_count,events,&event);
1633 /* This can fail due to memory issues and calling clFinish might help. */
1634 if ((status != CL_SUCCESS) && (event_count > 0))
1636 openCL_library->clFinish(queue);
1637 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,
1638 offset,gsize,lsize,event_count,events,&event);
1640 if ((output_info != (CacheInfo *) NULL) &&
1641 (output_info->opencl->event_count > 0))
1642 events=(cl_event *) RelinquishMagickMemory(events);
1643 if (status != CL_SUCCESS)
1645 (void) OpenCLThrowMagickException(input_info->opencl->device,exception,
1646 GetMagickModule(),ResourceLimitWarning,
1647 "clEnqueueNDRangeKernel failed.","'%s'",".");
1648 return(MagickFalse);
1650 if (flush != MagickFalse)
1651 openCL_library->clFlush(queue);
1652 if (RecordProfileData(input_info->opencl->device,kernel,event) == MagickFalse)
1654 RegisterCacheEvent(input_info->opencl,event);
1655 if (output_info != (CacheInfo *) NULL)
1656 RegisterCacheEvent(output_info->opencl,event);
1658 openCL_library->clReleaseEvent(event);
1663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 + G e t C u r r u n t O p e n C L E n v %
1671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673 % GetCurrentOpenCLEnv() returns the current OpenCL env
1675 % The format of the GetCurrentOpenCLEnv method is:
1677 % MagickCLEnv GetCurrentOpenCLEnv()
1681 MagickPrivate MagickCLEnv GetCurrentOpenCLEnv(void)
1683 if (default_CLEnv != (MagickCLEnv) NULL)
1685 if ((default_CLEnv->benchmark_thread_id != (MagickThreadType) 0) &&
1686 (default_CLEnv->benchmark_thread_id != GetMagickThreadId()))
1687 return((MagickCLEnv) NULL);
1689 return(default_CLEnv);
1692 if (GetOpenCLCacheDirectory() == (char *) NULL)
1693 return((MagickCLEnv) NULL);
1695 if (openCL_lock == (SemaphoreInfo *) NULL)
1696 ActivateSemaphoreInfo(&openCL_lock);
1698 LockSemaphoreInfo(openCL_lock);
1699 if (default_CLEnv == (MagickCLEnv) NULL)
1700 default_CLEnv=AcquireMagickCLEnv();
1701 UnlockSemaphoreInfo(openCL_lock);
1703 return(default_CLEnv);
1707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1711 % G e t O p e n C L D e v i c e B e n c h m a r k D u r a t i o n %
1715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1717 % GetOpenCLDeviceBenchmarkScore() returns the score of the benchmark for the
1718 % device. The score is determined by the duration of the micro benchmark so
1719 % that means a lower score is better than a higher score.
1721 % The format of the GetOpenCLDeviceBenchmarkScore method is:
1723 % double GetOpenCLDeviceBenchmarkScore(const MagickCLDevice device)
1725 % A description of each parameter follows:
1727 % o device: the OpenCL device.
1730 MagickExport double GetOpenCLDeviceBenchmarkScore(
1731 const MagickCLDevice device)
1733 if (device == (MagickCLDevice) NULL)
1734 return(MAGICKCORE_OPENCL_UNDEFINED_SCORE);
1735 return(device->score);
1739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1743 % G e t O p e n C L D e v i c e E n a b l e d %
1747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1749 % GetOpenCLDeviceEnabled() returns true if the device is enabled.
1751 % The format of the GetOpenCLDeviceEnabled method is:
1753 % MagickBooleanType GetOpenCLDeviceEnabled(const MagickCLDevice device)
1755 % A description of each parameter follows:
1757 % o device: the OpenCL device.
1760 MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
1761 const MagickCLDevice device)
1763 if (device == (MagickCLDevice) NULL)
1764 return(MagickFalse);
1765 return(device->enabled);
1769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773 % G e t O p e n C L D e v i c e N a m e %
1777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1779 % GetOpenCLDeviceName() returns the name of the device.
1781 % The format of the GetOpenCLDeviceName method is:
1783 % const char *GetOpenCLDeviceName(const MagickCLDevice device)
1785 % A description of each parameter follows:
1787 % o device: the OpenCL device.
1790 MagickExport const char *GetOpenCLDeviceName(const MagickCLDevice device)
1792 if (device == (MagickCLDevice) NULL)
1793 return((const char *) NULL);
1794 return(device->name);
1798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 % G e t O p e n C L D e v i c e V e n d o r N a m e %
1806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1808 % GetOpenCLDeviceVendorName() returns the vendor name of the device.
1810 % The format of the GetOpenCLDeviceVendorName method is:
1812 % const char *GetOpenCLDeviceVendorName(const MagickCLDevice device)
1814 % A description of each parameter follows:
1816 % o device: the OpenCL device.
1819 MagickExport const char *GetOpenCLDeviceVendorName(const MagickCLDevice device)
1821 if (device == (MagickCLDevice) NULL)
1822 return((const char *) NULL);
1823 return(device->vendor_name);
1827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1831 % G e t O p e n C L D e v i c e s %
1835 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837 % GetOpenCLDevices() returns the devices of the OpenCL environment at sets the
1838 % value of length to the number of devices that are available.
1840 % The format of the GetOpenCLDevices method is:
1842 % const MagickCLDevice *GetOpenCLDevices(size_t *length,
1843 % ExceptionInfo *exception)
1845 % A description of each parameter follows:
1847 % o length: the number of device.
1849 % o exception: return any errors or warnings in this structure.
1853 MagickExport MagickCLDevice *GetOpenCLDevices(size_t *length,
1854 ExceptionInfo *exception)
1859 clEnv=GetCurrentOpenCLEnv();
1860 if (clEnv == (MagickCLEnv) NULL)
1862 if (length != (size_t *) NULL)
1864 return((MagickCLDevice *) NULL);
1866 InitializeOpenCL(clEnv,exception);
1867 if (length != (size_t *) NULL)
1868 *length=clEnv->number_devices;
1869 return(clEnv->devices);
1873 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1877 % G e t O p e n C L D e v i c e T y p e %
1881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1883 % GetOpenCLDeviceType() returns the type of the device.
1885 % The format of the GetOpenCLDeviceType method is:
1887 % MagickCLDeviceType GetOpenCLDeviceType(const MagickCLDevice device)
1889 % A description of each parameter follows:
1891 % o device: the OpenCL device.
1894 MagickExport MagickCLDeviceType GetOpenCLDeviceType(
1895 const MagickCLDevice device)
1897 if (device == (MagickCLDevice) NULL)
1898 return(UndefinedCLDeviceType);
1899 if (device->type == CL_DEVICE_TYPE_GPU)
1900 return(GpuCLDeviceType);
1901 if (device->type == CL_DEVICE_TYPE_CPU)
1902 return(CpuCLDeviceType);
1903 return(UndefinedCLDeviceType);
1907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1911 % G e t O p e n C L D e v i c e V e r s i o n %
1915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1917 % GetOpenCLDeviceVersion() returns the version of the device.
1919 % The format of the GetOpenCLDeviceName method is:
1921 % const char *GetOpenCLDeviceVersion(MagickCLDevice device)
1923 % A description of each parameter follows:
1925 % o device: the OpenCL device.
1928 MagickExport const char *GetOpenCLDeviceVersion(const MagickCLDevice device)
1930 if (device == (MagickCLDevice) NULL)
1931 return((const char *) NULL);
1932 return(device->version);
1936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1940 % G e t O p e n C L E n a b l e d %
1944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946 % GetOpenCLEnabled() returns true if OpenCL acceleration is enabled.
1948 % The format of the GetOpenCLEnabled method is:
1950 % MagickBooleanType GetOpenCLEnabled()
1954 MagickExport MagickBooleanType GetOpenCLEnabled(void)
1959 clEnv=GetCurrentOpenCLEnv();
1960 if (clEnv == (MagickCLEnv) NULL)
1961 return(MagickFalse);
1962 return(clEnv->enabled);
1966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1970 % G e t O p e n C L K e r n e l P r o f i l e R e c o r d s %
1974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1976 % GetOpenCLKernelProfileRecords() returns the profile records for the
1977 % specified device and sets length to the number of profile records.
1979 % The format of the GetOpenCLKernelProfileRecords method is:
1981 % const KernelProfileRecord *GetOpenCLKernelProfileRecords(size *length)
1983 % A description of each parameter follows:
1985 % o length: the number of profiles records.
1988 MagickExport const KernelProfileRecord *GetOpenCLKernelProfileRecords(
1989 const MagickCLDevice device,size_t *length)
1991 if ((device == (const MagickCLDevice) NULL) || (device->profile_records ==
1992 (KernelProfileRecord *) NULL))
1994 if (length != (size_t *) NULL)
1996 return((const KernelProfileRecord *) NULL);
1998 if (length != (size_t *) NULL)
2001 LockSemaphoreInfo(device->lock);
2002 while (device->profile_records[*length] != (KernelProfileRecord) NULL)
2004 UnlockSemaphoreInfo(device->lock);
2006 return(device->profile_records);
2010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2014 % H a s O p e n C L D e v i c e s %
2018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2020 % HasOpenCLDevices() checks if the OpenCL environment has devices that are
2021 % enabled and compiles the kernel for the device when necessary. False will be
2022 % returned if no enabled devices could be found
2024 % The format of the HasOpenCLDevices method is:
2026 % MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2027 % ExceptionInfo exception)
2029 % A description of each parameter follows:
2031 % o clEnv: the OpenCL environment.
2033 % o exception: return any errors or warnings in this structure.
2037 static MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2038 ExceptionInfo *exception)
2041 *accelerateKernelsBuffer,
2042 options[MagickPathExtent];
2053 /* Check if there are enabled devices */
2054 for (i = 0; i < clEnv->number_devices; i++)
2056 if ((clEnv->devices[i]->enabled != MagickFalse))
2059 if (i == clEnv->number_devices)
2060 return(MagickFalse);
2062 /* Check if we need to compile a kernel for one of the devices */
2064 for (i = 0; i < clEnv->number_devices; i++)
2066 if ((clEnv->devices[i]->enabled != MagickFalse) &&
2067 (clEnv->devices[i]->program == (cl_program) NULL))
2073 if (status != MagickFalse)
2076 /* Get additional options */
2077 (void) FormatLocaleString(options,MaxTextExtent,CLOptions,
2078 (float)QuantumRange,(float)QuantumScale,(float)CLCharQuantumScale,
2079 (float)MagickEpsilon,(float)MagickPI,(unsigned int)MaxMap,
2080 (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
2082 signature=StringSignature(options);
2083 accelerateKernelsBuffer=(char*) AcquireMagickMemory(
2084 strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
2085 if (accelerateKernelsBuffer == (char*) NULL)
2086 return(MagickFalse);
2087 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
2088 signature^=StringSignature(accelerateKernelsBuffer);
2091 for (i = 0; i < clEnv->number_devices; i++)
2099 device=clEnv->devices[i];
2100 if ((device->enabled == MagickFalse) ||
2101 (device->program != (cl_program) NULL))
2104 LockSemaphoreInfo(device->lock);
2105 if (device->program != (cl_program) NULL)
2107 UnlockSemaphoreInfo(device->lock);
2110 device_signature=signature;
2111 device_signature^=StringSignature(device->platform_name);
2112 status=CompileOpenCLKernel(device,accelerateKernelsBuffer,options,
2113 device_signature,exception);
2114 UnlockSemaphoreInfo(device->lock);
2115 if (status == MagickFalse)
2118 accelerateKernelsBuffer=RelinquishMagickMemory(accelerateKernelsBuffer);
2123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2127 + I n i t i a l i z e O p e n C L %
2131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2133 % InitializeOpenCL() is used to initialize the OpenCL environment. This method
2134 % makes sure the devices are propertly initialized and benchmarked.
2136 % The format of the InitializeOpenCL method is:
2138 % MagickBooleanType InitializeOpenCL(ExceptionInfo exception)
2140 % A description of each parameter follows:
2142 % o exception: return any errors or warnings in this structure.
2146 static cl_uint GetOpenCLDeviceCount(MagickCLEnv clEnv,cl_platform_id platform)
2149 version[MagickPathExtent];
2154 if (clEnv->library->clGetPlatformInfo(platform,CL_PLATFORM_VERSION,
2155 MagickPathExtent,version,NULL) != CL_SUCCESS)
2157 if (strncmp(version, "OpenCL 1.0 ", 11) == 0)
2159 if (clEnv->library->clGetDeviceIDs(platform,
2160 CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU,0,NULL,&num) != CL_SUCCESS)
2165 static void LoadOpenCLDevices(MagickCLEnv clEnv)
2167 cl_context_properties
2190 if (openCL_library->clGetPlatformIDs(0,NULL,&number_platforms) != CL_SUCCESS)
2192 if (number_platforms == 0)
2194 platforms=(cl_platform_id *) AcquireMagickMemory(number_platforms*
2195 sizeof(cl_platform_id));
2196 if (platforms == (cl_platform_id *) NULL)
2198 if (openCL_library->clGetPlatformIDs(number_platforms,platforms,NULL) != CL_SUCCESS)
2200 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2203 for (i = 0; i < number_platforms; i++)
2205 number_devices=GetOpenCLDeviceCount(clEnv,platforms[i]);
2206 if (number_devices == 0)
2207 platforms[i]=(cl_platform_id) NULL;
2209 clEnv->number_devices+=number_devices;
2211 if (clEnv->number_devices == 0)
2213 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2216 clEnv->devices=(MagickCLDevice *) AcquireQuantumMemory(clEnv->number_devices,
2217 sizeof(MagickCLDevice));
2218 if (clEnv->devices == (MagickCLDevice *) NULL)
2220 RelinquishMagickCLDevices(clEnv);
2221 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2224 (void) ResetMagickMemory(clEnv->devices,0,clEnv->number_devices*
2225 sizeof(MagickCLDevice));
2226 devices=(cl_device_id *) AcquireQuantumMemory(clEnv->number_devices,
2227 sizeof(cl_device_id));
2228 if (devices == (cl_device_id *) NULL)
2230 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2231 RelinquishMagickCLDevices(clEnv);
2234 clEnv->number_contexts=(size_t) number_platforms;
2235 clEnv->contexts=(cl_context *) AcquireQuantumMemory(clEnv->number_contexts,
2236 sizeof(cl_context));
2237 if (clEnv->contexts == (cl_context *) NULL)
2239 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2240 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2241 RelinquishMagickCLDevices(clEnv);
2245 for (i = 0; i < number_platforms; i++)
2247 if (platforms[i] == (cl_platform_id) NULL)
2250 status=clEnv->library->clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_CPU |
2251 CL_DEVICE_TYPE_GPU,(cl_uint) clEnv->number_devices,devices,&number_devices);
2252 if (status != CL_SUCCESS)
2255 properties[0]=CL_CONTEXT_PLATFORM;
2256 properties[1]=(cl_context_properties) platforms[i];
2258 clEnv->contexts[i]=openCL_library->clCreateContext(properties,number_devices,
2259 devices,NULL,NULL,&status);
2260 if (status != CL_SUCCESS)
2263 for (j = 0; j < number_devices; j++,next++)
2268 device=AcquireMagickCLDevice();
2269 if (device == (MagickCLDevice) NULL)
2272 device->context=clEnv->contexts[i];
2273 device->deviceID=devices[j];
2275 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_NAME,0,NULL,
2277 device->platform_name=AcquireQuantumMemory(length,
2278 sizeof(*device->platform_name));
2279 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_NAME,length,
2280 device->platform_name,NULL);
2282 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_VENDOR,0,NULL,
2284 device->vendor_name=AcquireQuantumMemory(length,
2285 sizeof(*device->vendor_name));
2286 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_VENDOR,length,
2287 device->vendor_name,NULL);
2289 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_NAME,0,NULL,
2291 device->name=AcquireQuantumMemory(length,sizeof(*device->name));
2292 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_NAME,length,
2295 openCL_library->clGetDeviceInfo(devices[j],CL_DRIVER_VERSION,0,NULL,
2297 device->version=AcquireQuantumMemory(length,sizeof(*device->version));
2298 openCL_library->clGetDeviceInfo(devices[j],CL_DRIVER_VERSION,length,
2299 device->version,NULL);
2301 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_CLOCK_FREQUENCY,
2302 sizeof(cl_uint),&device->max_clock_frequency,NULL);
2304 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,
2305 sizeof(cl_uint),&device->max_compute_units,NULL);
2307 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_TYPE,
2308 sizeof(cl_device_type),&device->type,NULL);
2310 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_LOCAL_MEM_SIZE,
2311 sizeof(cl_ulong),&device->local_memory_size,NULL);
2313 clEnv->devices[next]=device;
2316 if (next != clEnv->number_devices)
2317 RelinquishMagickCLDevices(clEnv);
2318 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2319 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2322 MagickPrivate MagickBooleanType InitializeOpenCL(MagickCLEnv clEnv,
2323 ExceptionInfo *exception)
2325 LockSemaphoreInfo(clEnv->lock);
2326 if (clEnv->initialized != MagickFalse)
2328 UnlockSemaphoreInfo(clEnv->lock);
2329 return(HasOpenCLDevices(clEnv,exception));
2331 if (LoadOpenCLLibrary() != MagickFalse)
2333 clEnv->library=openCL_library;
2334 LoadOpenCLDevices(clEnv);
2335 if (clEnv->number_devices > 0)
2336 AutoSelectOpenCLDevices(clEnv);
2338 clEnv->initialized=MagickTrue;
2339 UnlockSemaphoreInfo(clEnv->lock);
2340 return(HasOpenCLDevices(clEnv,exception));
2344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2348 % L o a d O p e n C L L i b r a r y %
2352 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354 % LoadOpenCLLibrary() load and binds the OpenCL library.
2356 % The format of the LoadOpenCLLibrary method is:
2358 % MagickBooleanType LoadOpenCLLibrary(void)
2362 void *OsLibraryGetFunctionAddress(void *library,const char *functionName)
2364 if ((library == (void *) NULL) || (functionName == (const char *) NULL))
2365 return (void *) NULL;
2366 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2367 return (void *) GetProcAddress((HMODULE)library,functionName);
2369 return (void *) dlsym(library,functionName);
2373 static MagickBooleanType BindOpenCLFunctions()
2375 #ifdef MAGICKCORE_OPENCL_MACOSX
2376 #define BIND(X) openCL_library->X= &X;
2378 (void) ResetMagickMemory(openCL_library,0,sizeof(MagickLibrary));
2379 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2380 openCL_library->library=(void *)LoadLibraryA("OpenCL.dll");
2382 openCL_library->library=(void *)dlopen("libOpenCL.so", RTLD_NOW);
2385 if ((openCL_library->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(openCL_library->library,#X)) == NULL) \
2386 return(MagickFalse);
2389 if (openCL_library->library == (void*) NULL)
2390 return(MagickFalse);
2392 BIND(clGetPlatformIDs);
2393 BIND(clGetPlatformInfo);
2395 BIND(clGetDeviceIDs);
2396 BIND(clGetDeviceInfo);
2398 BIND(clCreateBuffer);
2399 BIND(clReleaseMemObject);
2401 BIND(clCreateContext);
2402 BIND(clReleaseContext);
2404 BIND(clCreateCommandQueue);
2405 BIND(clReleaseCommandQueue);
2409 BIND(clCreateProgramWithSource);
2410 BIND(clCreateProgramWithBinary);
2411 BIND(clReleaseProgram);
2412 BIND(clBuildProgram);
2413 BIND(clGetProgramBuildInfo);
2414 BIND(clGetProgramInfo);
2416 BIND(clCreateKernel);
2417 BIND(clReleaseKernel);
2418 BIND(clSetKernelArg);
2419 BIND(clGetKernelInfo);
2421 BIND(clEnqueueReadBuffer);
2422 BIND(clEnqueueMapBuffer);
2423 BIND(clEnqueueUnmapMemObject);
2424 BIND(clEnqueueNDRangeKernel);
2426 BIND(clGetEventInfo);
2427 BIND(clWaitForEvents);
2428 BIND(clReleaseEvent);
2429 BIND(clRetainEvent);
2430 BIND(clSetEventCallback);
2432 BIND(clGetEventProfilingInfo);
2437 static MagickBooleanType LoadOpenCLLibrary(void)
2439 openCL_library=(MagickLibrary *) AcquireMagickMemory(sizeof(MagickLibrary));
2440 if (openCL_library == (MagickLibrary *) NULL)
2441 return(MagickFalse);
2443 if (BindOpenCLFunctions() == MagickFalse)
2445 openCL_library=(MagickLibrary *)RelinquishMagickMemory(openCL_library);
2446 return(MagickFalse);
2453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457 + O p e n C L T e r m i n u s %
2461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2463 % OpenCLTerminus() destroys the OpenCL component.
2465 % The format of the OpenCLTerminus method is:
2467 % OpenCLTerminus(void)
2471 MagickPrivate void OpenCLTerminus()
2473 DumpOpenCLProfileData();
2474 if (cache_directory != (char *) NULL)
2475 cache_directory=DestroyString(cache_directory);
2476 if (cache_directory_lock != (SemaphoreInfo *) NULL)
2477 RelinquishSemaphoreInfo(&cache_directory_lock);
2478 if (default_CLEnv != (MagickCLEnv) NULL)
2479 default_CLEnv=RelinquishMagickCLEnv(default_CLEnv);
2480 if (openCL_lock != (SemaphoreInfo *) NULL)
2481 RelinquishSemaphoreInfo(&openCL_lock);
2482 if (openCL_library != (MagickLibrary *) NULL)
2484 if (openCL_library->library != (void *) NULL)
2485 (void) lt_dlclose(openCL_library->library);
2486 openCL_library=(MagickLibrary *) RelinquishMagickMemory(openCL_library);
2491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2495 + O p e n C L T h r o w M a g i c k E x c e p t i o n %
2499 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501 % OpenCLThrowMagickException logs an OpenCL exception as determined by the log
2502 % configuration file. If an error occurs, MagickFalse is returned
2503 % otherwise MagickTrue.
2505 % The format of the OpenCLThrowMagickException method is:
2507 % MagickBooleanType ThrowFileException(ExceptionInfo *exception,
2508 % const char *module,const char *function,const size_t line,
2509 % const ExceptionType severity,const char *tag,const char *format,...)
2511 % A description of each parameter follows:
2513 % o exception: the exception info.
2515 % o filename: the source module filename.
2517 % o function: the function name.
2519 % o line: the line number of the source module.
2521 % o severity: Specifies the numeric error category.
2523 % o tag: the locale tag.
2525 % o format: the output format.
2529 MagickPrivate MagickBooleanType OpenCLThrowMagickException(
2530 MagickCLDevice device,ExceptionInfo *exception,const char *module,
2531 const char *function,const size_t line,const ExceptionType severity,
2532 const char *tag,const char *format,...)
2537 assert(device != (MagickCLDevice) NULL);
2538 assert(exception != (ExceptionInfo *) NULL);
2539 assert(exception->signature == MagickCoreSignature);
2544 if (device->type == CL_DEVICE_TYPE_CPU)
2546 /* Workaround for Intel OpenCL CPU runtime bug */
2547 /* Turn off OpenCL when a problem is detected! */
2548 if (strncmp(device->platform_name, "Intel",5) == 0)
2549 default_CLEnv->enabled=MagickFalse;
2553 #ifdef OPENCLLOG_ENABLED
2557 va_start(operands,format);
2558 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
2563 magick_unreferenced(module);
2564 magick_unreferenced(function);
2565 magick_unreferenced(line);
2566 magick_unreferenced(tag);
2567 magick_unreferenced(format);
2574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2578 + R e c o r d P r o f i l e D a t a %
2582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2584 % RecordProfileData() records profile data.
2586 % The format of the RecordProfileData method is:
2588 % void RecordProfileData(MagickCLDevice device,ProfiledKernels kernel,
2591 % A description of each parameter follows:
2593 % o device: the OpenCL device that did the operation.
2595 % o event: the event that contains the profiling data.
2599 MagickPrivate MagickBooleanType RecordProfileData(MagickCLDevice device,
2600 cl_kernel kernel,cl_event event)
2620 if (device->profile_kernels == MagickFalse)
2621 return(MagickFalse);
2622 status=openCL_library->clWaitForEvents(1,&event);
2623 if (status != CL_SUCCESS)
2624 return(MagickFalse);
2625 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,0,NULL,
2627 if (status != CL_SUCCESS)
2629 name=AcquireQuantumMemory(length,sizeof(*name));
2630 if (name == (char *) NULL)
2632 start=end=elapsed=0;
2633 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,length,
2634 name,(size_t *) NULL);
2635 status|=openCL_library->clGetEventProfilingInfo(event,
2636 CL_PROFILING_COMMAND_START,sizeof(cl_ulong),&start,NULL);
2637 status|=openCL_library->clGetEventProfilingInfo(event,
2638 CL_PROFILING_COMMAND_END,sizeof(cl_ulong),&end,NULL);
2639 if (status != CL_SUCCESS)
2641 name=DestroyString(name);
2644 start/=1000; // usecs
2647 LockSemaphoreInfo(device->lock);
2649 profile_record=(KernelProfileRecord) NULL;
2650 if (device->profile_records != (KernelProfileRecord *) NULL)
2652 while (device->profile_records[i] != (KernelProfileRecord) NULL)
2654 if (LocaleCompare(device->profile_records[i]->kernel_name,name) == 0)
2656 profile_record=device->profile_records[i];
2662 if (profile_record != (KernelProfileRecord) NULL)
2663 name=DestroyString(name);
2666 profile_record=AcquireMagickMemory(sizeof(*profile_record));
2667 (void) ResetMagickMemory(profile_record,0,sizeof(*profile_record));
2668 profile_record->kernel_name=name;
2669 device->profile_records=ResizeMagickMemory(device->profile_records,(i+2)*
2670 sizeof(*device->profile_records));
2671 device->profile_records[i]=profile_record;
2672 device->profile_records[i+1]=(KernelProfileRecord) NULL;
2674 if ((elapsed < profile_record->min) || (profile_record->count == 0))
2675 profile_record->min=elapsed;
2676 if (elapsed > profile_record->max)
2677 profile_record->max=elapsed;
2678 profile_record->total+=elapsed;
2679 profile_record->count+=1;
2680 UnlockSemaphoreInfo(device->lock);
2685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2689 + R e l e a s e O p e n C L C o m m a n d Q u e u e %
2693 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695 % ReleaseOpenCLCommandQueue() releases the OpenCL command queue
2697 % The format of the ReleaseOpenCLCommandQueue method is:
2699 % void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2700 % cl_command_queue queue)
2702 % A description of each parameter follows:
2704 % o device: the OpenCL device.
2706 % o queue: the OpenCL queue to be released.
2709 MagickPrivate void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2710 cl_command_queue queue)
2712 if (queue == (cl_command_queue) NULL)
2715 assert(device != (MagickCLDevice) NULL);
2716 LockSemaphoreInfo(device->lock);
2717 if ((device->profile_kernels != MagickFalse) ||
2718 (device->command_queues_index >= MAGICKCORE_OPENCL_COMMAND_QUEUES-1))
2720 UnlockSemaphoreInfo(device->lock);
2721 openCL_library->clFinish(queue);
2722 (void) openCL_library->clReleaseCommandQueue(queue);
2726 openCL_library->clFlush(queue);
2727 device->command_queues[++device->command_queues_index]=queue;
2728 UnlockSemaphoreInfo(device->lock);
2733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2737 + R e l e a s e M a g i c k C L D e v i c e %
2741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2743 % ReleaseOpenCLDevice() returns the OpenCL device to the environment
2745 % The format of the ReleaseOpenCLDevice method is:
2747 % void ReleaseOpenCLDevice(MagickCLDevice device)
2749 % A description of each parameter follows:
2751 % o device: the OpenCL device to be released.
2755 MagickPrivate void ReleaseOpenCLDevice(MagickCLDevice device)
2757 assert(device != (MagickCLDevice) NULL);
2758 LockSemaphoreInfo(openCL_lock);
2759 device->requested--;
2760 UnlockSemaphoreInfo(openCL_lock);
2764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768 + R e l i n q u i s h M a g i c k C L C a c h e I n f o %
2772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2774 % RelinquishMagickCLCacheInfo() frees memory acquired with
2775 % AcquireMagickCLCacheInfo()
2777 % The format of the RelinquishMagickCLCacheInfo method is:
2779 % MagickCLCacheInfo RelinquishMagickCLCacheInfo(MagickCLCacheInfo info,
2780 % const MagickBooleanType relinquish_pixels)
2782 % A description of each parameter follows:
2784 % o info: the OpenCL cache info.
2786 % o relinquish_pixels: the pixels will be relinquish when set to true.
2789 static void DestroyMagickCLCacheInfo(MagickCLCacheInfo info)
2794 for (i=0; i < (ssize_t) info->event_count; i++)
2795 openCL_library->clReleaseEvent(info->events[i]);
2796 info->events=(cl_event *) RelinquishMagickMemory(info->events);
2797 if (info->buffer != (cl_mem) NULL)
2798 openCL_library->clReleaseMemObject(info->buffer);
2799 ReleaseOpenCLDevice(info->device);
2800 RelinquishMagickMemory(info);
2803 static void CL_API_CALL DestroyMagickCLCacheInfoAndPixels(
2804 cl_event magick_unused(event),
2805 cl_int magick_unused(event_command_exec_status),void *user_data)
2813 magick_unreferenced(event);
2814 magick_unreferenced(event_command_exec_status);
2815 info=(MagickCLCacheInfo) user_data;
2816 pixels=info->pixels;
2817 RelinquishMagickResource(MemoryResource,info->length);
2818 DestroyMagickCLCacheInfo(info);
2819 (void) RelinquishAlignedMemory(pixels);
2822 MagickPrivate MagickCLCacheInfo RelinquishMagickCLCacheInfo(
2823 MagickCLCacheInfo info,const MagickBooleanType relinquish_pixels)
2825 if (info == (MagickCLCacheInfo) NULL)
2826 return((MagickCLCacheInfo) NULL);
2827 if (relinquish_pixels != MagickFalse)
2835 events_completed=MagickTrue;
2836 for (i=0; i < (ssize_t)info->event_count; i++)
2844 status=openCL_library->clGetEventInfo(info->events[i],
2845 CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof(cl_int),&event_status,NULL);
2846 if ((status == CL_SUCCESS) && (event_status != CL_COMPLETE))
2848 events_completed=MagickFalse;
2852 if (events_completed == MagickFalse)
2853 openCL_library->clSetEventCallback(info->events[info->event_count-1],
2854 CL_COMPLETE,&DestroyMagickCLCacheInfoAndPixels,info);
2856 DestroyMagickCLCacheInfoAndPixels((cl_event) NULL,0,info);
2859 DestroyMagickCLCacheInfo(info);
2860 return((MagickCLCacheInfo) NULL);
2864 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2868 % R e l i n q u i s h M a g i c k C L D e v i c e %
2872 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2874 % RelinquishMagickCLDevice() releases the OpenCL device
2876 % The format of the RelinquishMagickCLDevice method is:
2878 % MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2880 % A description of each parameter follows:
2882 % o device: the OpenCL device to be released.
2886 static MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2888 if (device == (MagickCLDevice) NULL)
2889 return((MagickCLDevice) NULL);
2891 device->platform_name=RelinquishMagickMemory(device->platform_name);
2892 device->vendor_name=RelinquishMagickMemory(device->vendor_name);
2893 device->name=RelinquishMagickMemory(device->name);
2894 device->version=RelinquishMagickMemory(device->version);
2895 if (device->program != (cl_program) NULL)
2896 (void) openCL_library->clReleaseProgram(device->program);
2897 while (device->command_queues_index >= 0)
2898 (void) openCL_library->clReleaseCommandQueue(
2899 device->command_queues[device->command_queues_index--]);
2900 RelinquishSemaphoreInfo(&device->lock);
2901 return((MagickCLDevice) RelinquishMagickMemory(device));
2905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2909 % R e l i n q u i s h M a g i c k C L E n v %
2913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2915 % RelinquishMagickCLEnv() releases the OpenCL environment
2917 % The format of the RelinquishMagickCLEnv method is:
2919 % MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv device)
2921 % A description of each parameter follows:
2923 % o clEnv: the OpenCL environment to be released.
2927 static MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv clEnv)
2929 if (clEnv == (MagickCLEnv) NULL)
2930 return((MagickCLEnv) NULL);
2932 RelinquishSemaphoreInfo(&clEnv->lock);
2933 RelinquishMagickCLDevices(clEnv);
2934 if (clEnv->contexts != (cl_context *) NULL)
2939 for (i=0; i < clEnv->number_contexts; i++)
2940 (void) openCL_library->clReleaseContext(clEnv->contexts[i]);
2941 clEnv->contexts=(cl_context *) RelinquishMagickMemory(clEnv->contexts);
2943 return((MagickCLEnv) RelinquishMagickMemory(clEnv));
2947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2951 + R e q u e s t O p e n C L D e v i c e %
2955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2957 % RequestOpenCLDevice() returns one of the enabled OpenCL devices.
2959 % The format of the RequestOpenCLDevice method is:
2961 % MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
2963 % A description of each parameter follows:
2965 % o clEnv: the OpenCL environment.
2968 MagickPrivate MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
2980 if (clEnv == (MagickCLEnv) NULL)
2981 return((MagickCLDevice) NULL);
2983 if (clEnv->number_devices == 1)
2985 if (clEnv->devices[0]->enabled)
2986 return(clEnv->devices[0]);
2988 return((MagickCLDevice) NULL);
2991 device=(MagickCLDevice) NULL;
2993 LockSemaphoreInfo(openCL_lock);
2994 for (i = 0; i < clEnv->number_devices; i++)
2996 if (clEnv->devices[i]->enabled == MagickFalse)
2999 score=clEnv->devices[i]->score+(clEnv->devices[i]->score*
3000 clEnv->devices[i]->requested);
3001 if ((device == (MagickCLDevice) NULL) || (score < best_score))
3003 device=clEnv->devices[i];
3007 if (device != (MagickCLDevice)NULL)
3008 device->requested++;
3009 UnlockSemaphoreInfo(openCL_lock);
3015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3019 % S e t O p e n C L D e v i c e E n a b l e d %
3023 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3025 % SetOpenCLDeviceEnabled() can be used to enable or disabled the device.
3027 % The format of the SetOpenCLDeviceEnabled method is:
3029 % void SetOpenCLDeviceEnabled(MagickCLDevice device,
3030 % MagickBooleanType value)
3032 % A description of each parameter follows:
3034 % o device: the OpenCL device.
3036 % o value: determines if the device should be enabled or disabled.
3039 MagickExport void SetOpenCLDeviceEnabled(MagickCLDevice device,
3040 const MagickBooleanType value)
3042 if (device == (MagickCLDevice) NULL)
3044 device->enabled=value;
3048 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3052 % S e t O p e n C L K e r n e l P r o f i l e E n a b l e d %
3056 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3058 % SetOpenCLKernelProfileEnabled() can be used to enable or disabled the
3059 % kernel profiling of a device.
3061 % The format of the SetOpenCLKernelProfileEnabled method is:
3063 % void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3064 % MagickBooleanType value)
3066 % A description of each parameter follows:
3068 % o device: the OpenCL device.
3070 % o value: determines if kernel profiling for the device should be enabled
3074 MagickExport void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3075 const MagickBooleanType value)
3077 if (device == (MagickCLDevice) NULL)
3079 device->profile_kernels=value;
3083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3087 % S e t O p e n C L E n a b l e d %
3091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3093 % SetOpenCLEnabled() can be used to enable or disable OpenCL acceleration.
3095 % The format of the SetOpenCLEnabled method is:
3097 % void SetOpenCLEnabled(MagickBooleanType)
3099 % A description of each parameter follows:
3101 % o value: specify true to enable OpenCL acceleration
3104 MagickExport MagickBooleanType SetOpenCLEnabled(const MagickBooleanType value)
3109 clEnv=GetCurrentOpenCLEnv();
3110 if (clEnv == (MagickCLEnv) NULL)
3111 return(MagickFalse);
3112 clEnv->enabled=value;
3113 return(clEnv->enabled);
3118 MagickExport double GetOpenCLDeviceBenchmarkScore(
3119 const MagickCLDevice magick_unused(device))
3121 magick_unreferenced(device);
3125 MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
3126 const MagickCLDevice magick_unused(device))
3128 magick_unreferenced(device);
3129 return(MagickFalse);
3132 MagickExport const char *GetOpenCLDeviceName(
3133 const MagickCLDevice magick_unused(device))
3135 magick_unreferenced(device);
3136 return((const char *) NULL);
3139 MagickExport MagickCLDevice *GetOpenCLDevices(size_t *length,
3140 ExceptionInfo *magick_unused(exception))
3142 magick_unreferenced(exception);
3143 if (length != (size_t *) NULL)
3145 return((MagickCLDevice *) NULL);
3148 MagickExport MagickCLDeviceType GetOpenCLDeviceType(
3149 const MagickCLDevice magick_unused(device))
3151 magick_unreferenced(device);
3152 return(UndefinedCLDeviceType);
3155 MagickExport const KernelProfileRecord *GetOpenCLKernelProfileRecords(
3156 const MagickCLDevice magick_unused(device),size_t *length)
3158 magick_unreferenced(device);
3159 if (length != (size_t *) NULL)
3161 return((const KernelProfileRecord *) NULL);
3164 MagickExport const char *GetOpenCLDeviceVersion(
3165 const MagickCLDevice magick_unused(device))
3167 magick_unreferenced(device);
3168 return((const char *) NULL);
3171 MagickExport MagickBooleanType GetOpenCLEnabled(void)
3173 return(MagickFalse);
3176 MagickExport void SetOpenCLDeviceEnabled(
3177 MagickCLDevice magick_unused(device),
3178 const MagickBooleanType magick_unused(value))
3180 magick_unreferenced(device);
3181 magick_unreferenced(value);
3184 MagickExport MagickBooleanType SetOpenCLEnabled(
3185 const MagickBooleanType magick_unused(value))
3187 magick_unreferenced(value);
3188 return(MagickFalse);
3191 MagickExport void SetOpenCLKernelProfileEnabled(
3192 MagickCLDevice magick_unused(device),
3193 const MagickBooleanType magick_unused(value))
3195 magick_unreferenced(device);
3196 magick_unreferenced(value);