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/memory-private.h"
65 #include "MagickCore/monitor.h"
66 #include "MagickCore/montage.h"
67 #include "MagickCore/morphology.h"
68 #include "MagickCore/nt-base.h"
69 #include "MagickCore/nt-base-private.h"
70 #include "MagickCore/opencl.h"
71 #include "MagickCore/opencl-private.h"
72 #include "MagickCore/option.h"
73 #include "MagickCore/policy.h"
74 #include "MagickCore/property.h"
75 #include "MagickCore/quantize.h"
76 #include "MagickCore/quantum.h"
77 #include "MagickCore/random_.h"
78 #include "MagickCore/random-private.h"
79 #include "MagickCore/resample.h"
80 #include "MagickCore/resource_.h"
81 #include "MagickCore/splay-tree.h"
82 #include "MagickCore/semaphore.h"
83 #include "MagickCore/statistic.h"
84 #include "MagickCore/string_.h"
85 #include "MagickCore/string-private.h"
86 #include "MagickCore/token.h"
87 #include "MagickCore/utility.h"
88 #include "MagickCore/utility-private.h"
90 #if defined(MAGICKCORE_OPENCL_SUPPORT)
91 #if defined(MAGICKCORE_LTDL_DELEGATE)
95 #ifndef MAGICKCORE_WINDOWS_SUPPORT
99 #ifdef MAGICKCORE_HAVE_OPENCL_CL_H
100 #define MAGICKCORE_OPENCL_MACOSX 1
106 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile.xml"
109 Typedef declarations.
132 } MagickCLDeviceBenchmark;
135 Forward declarations.
138 static MagickBooleanType
139 HasOpenCLDevices(MagickCLEnv,ExceptionInfo *),
140 LoadOpenCLLibrary(void);
142 static MagickCLDevice
143 RelinquishMagickCLDevice(MagickCLDevice);
146 RelinquishMagickCLEnv(MagickCLEnv);
149 BenchmarkOpenCLDevices(MagickCLEnv);
152 *accelerateKernels, *accelerateKernels2;
158 /* Default OpenCL environment */
166 /* Cached location of the OpenCL cache files */
170 *cache_directory_lock;
172 static inline MagickBooleanType IsSameOpenCLDevice(MagickCLDevice a,
175 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
176 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
177 (LocaleCompare(a->name,b->name) == 0) &&
178 (LocaleCompare(a->version,b->version) == 0) &&
179 (a->max_clock_frequency == b->max_clock_frequency) &&
180 (a->max_compute_units == b->max_compute_units))
186 static inline MagickBooleanType IsBenchmarkedOpenCLDevice(MagickCLDevice a,
187 MagickCLDeviceBenchmark *b)
189 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
190 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
191 (LocaleCompare(a->name,b->name) == 0) &&
192 (LocaleCompare(a->version,b->version) == 0) &&
193 (a->max_clock_frequency == b->max_clock_frequency) &&
194 (a->max_compute_units == b->max_compute_units))
200 static inline void RelinquishMagickCLDevices(MagickCLEnv clEnv)
205 if (clEnv->devices != (MagickCLDevice *) NULL)
207 for (i = 0; i < clEnv->number_devices; i++)
208 clEnv->devices[i]=RelinquishMagickCLDevice(clEnv->devices[i]);
209 clEnv->devices=(MagickCLDevice *) RelinquishMagickMemory(clEnv->devices);
211 clEnv->number_devices=0;
214 static inline MagickBooleanType MagickCreateDirectory(const char *path)
219 #ifdef MAGICKCORE_WINDOWS_SUPPORT
222 status=mkdir(path, 0777);
224 return(status == 0 ? MagickTrue : MagickFalse);
227 static inline void InitAccelerateTimer(AccelerateTimer *timer)
230 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->freq);
232 timer->freq=(long long)1.0E3;
238 static inline double ReadAccelerateTimer(AccelerateTimer *timer)
240 return (double)timer->clocks/(double)timer->freq;
243 static inline void StartAccelerateTimer(AccelerateTimer* timer)
246 QueryPerformanceCounter((LARGE_INTEGER*)&timer->start);
251 timer->start=(long long)s.tv_sec*(long long)1.0E3+(long long)s.tv_usec/
256 static inline void StopAccelerateTimer(AccelerateTimer *timer)
263 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
268 n=(long long)s.tv_sec*(long long)1.0E3+(long long)s.tv_usec/
276 static const char *GetOpenCLCacheDirectory()
278 if (cache_directory == (char *) NULL)
280 if (cache_directory_lock == (SemaphoreInfo *) NULL)
281 ActivateSemaphoreInfo(&cache_directory_lock);
282 LockSemaphoreInfo(cache_directory_lock);
283 if (cache_directory == (char *) NULL)
287 path[MagickPathExtent],
297 home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
298 if (home == (char *) NULL)
300 home=GetEnvironmentValue("XDG_CACHE_HOME");
301 if (home == (char *) NULL)
302 home=GetEnvironmentValue("LOCALAPPDATA");
303 if (home == (char *) NULL)
304 home=GetEnvironmentValue("APPDATA");
305 if (home == (char *) NULL)
306 home=GetEnvironmentValue("USERPROFILE");
309 if (home != (char *) NULL)
311 /* first check if $HOME exists */
312 (void) FormatLocaleString(path,MagickPathExtent,"%s",home);
313 status=GetPathAttributes(path,&attributes);
314 if (status == MagickFalse)
315 status=MagickCreateDirectory(path);
317 /* first check if $HOME/ImageMagick exists */
318 if (status != MagickFalse)
320 (void) FormatLocaleString(path,MagickPathExtent,
321 "%s%sImageMagick",home,DirectorySeparator);
323 status=GetPathAttributes(path,&attributes);
324 if (status == MagickFalse)
325 status=MagickCreateDirectory(path);
328 if (status != MagickFalse)
330 temp=(char*) AcquireCriticalMemory(strlen(path)+1);
331 CopyMagickString(temp,path,strlen(path)+1);
333 home=DestroyString(home);
337 home=GetEnvironmentValue("HOME");
338 if (home != (char *) NULL)
340 /* first check if $HOME/.cache exists */
341 (void) FormatLocaleString(path,MagickPathExtent,"%s%s.cache",
342 home,DirectorySeparator);
343 status=GetPathAttributes(path,&attributes);
344 if (status == MagickFalse)
345 status=MagickCreateDirectory(path);
347 /* first check if $HOME/.cache/ImageMagick exists */
348 if (status != MagickFalse)
350 (void) FormatLocaleString(path,MagickPathExtent,
351 "%s%s.cache%sImageMagick",home,DirectorySeparator,
353 status=GetPathAttributes(path,&attributes);
354 if (status == MagickFalse)
355 status=MagickCreateDirectory(path);
358 if (status != MagickFalse)
360 temp=(char*) AcquireCriticalMemory(strlen(path)+1);
361 CopyMagickString(temp,path,strlen(path)+1);
363 home=DestroyString(home);
366 if (temp == (char *) NULL)
367 temp=AcquireString("?");
368 cache_directory=temp;
370 UnlockSemaphoreInfo(cache_directory_lock);
372 if (*cache_directory == '?')
373 return((const char *) NULL);
374 return(cache_directory);
377 static void SelectOpenCLDevice(MagickCLEnv clEnv,cl_device_type type)
386 for (i = 0; i < clEnv->number_devices; i++)
387 clEnv->devices[i]->enabled=MagickFalse;
389 for (i = 0; i < clEnv->number_devices; i++)
391 device=clEnv->devices[i];
392 if (device->type != type)
395 device->enabled=MagickTrue;
396 for (j = i+1; j < clEnv->number_devices; j++)
401 other_device=clEnv->devices[j];
402 if (IsSameOpenCLDevice(device,other_device))
403 other_device->enabled=MagickTrue;
408 static size_t StringSignature(const char* string)
423 stringLength=(size_t) strlen(string);
424 signature=stringLength;
425 n=stringLength/sizeof(size_t);
427 for (i = 0; i < n; i++)
429 if (n * sizeof(size_t) != stringLength)
435 for (i = 0; i < 4; i++, j++)
437 if (j < stringLength)
448 static void DestroyMagickCLCacheInfo(MagickCLCacheInfo info)
453 for (i=0; i < (ssize_t) info->event_count; i++)
454 openCL_library->clReleaseEvent(info->events[i]);
455 info->events=(cl_event *) RelinquishMagickMemory(info->events);
456 if (info->buffer != (cl_mem) NULL)
457 openCL_library->clReleaseMemObject(info->buffer);
458 RelinquishSemaphoreInfo(&info->events_semaphore);
459 ReleaseOpenCLDevice(info->device);
460 RelinquishMagickMemory(info);
464 Provide call to OpenCL library methods
467 MagickPrivate cl_mem CreateOpenCLBuffer(MagickCLDevice device,
468 cl_mem_flags flags,size_t size,void *host_ptr)
470 return(openCL_library->clCreateBuffer(device->context,flags,size,host_ptr,
474 MagickPrivate void ReleaseOpenCLKernel(cl_kernel kernel)
476 (void) openCL_library->clReleaseKernel(kernel);
479 MagickPrivate void ReleaseOpenCLMemObject(cl_mem memobj)
481 (void) openCL_library->clReleaseMemObject(memobj);
484 MagickPrivate void RetainOpenCLMemObject(cl_mem memobj)
486 (void) openCL_library->clRetainMemObject(memobj);
489 MagickPrivate cl_int SetOpenCLKernelArg(cl_kernel kernel,size_t arg_index,
490 size_t arg_size,const void *arg_value)
492 return(openCL_library->clSetKernelArg(kernel,(cl_uint) arg_index,arg_size,
497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
501 + A c q u i r e M a g i c k C L C a c h e I n f o %
505 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 % AcquireMagickCLCacheInfo() acquires an OpenCL cache info structure.
509 % The format of the AcquireMagickCLCacheInfo method is:
511 % MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
512 % Quantum *pixels,const MagickSizeType length)
514 % A description of each parameter follows:
516 % o device: the OpenCL device.
518 % o pixels: the pixel buffer of the image.
520 % o length: the length of the pixel buffer.
524 MagickPrivate MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
525 Quantum *pixels,const MagickSizeType length)
533 info=(MagickCLCacheInfo) AcquireCriticalMemory(sizeof(*info));
534 (void) ResetMagickMemory(info,0,sizeof(*info));
535 LockSemaphoreInfo(openCL_lock);
537 UnlockSemaphoreInfo(openCL_lock);
541 info->events_semaphore=AcquireSemaphoreInfo();
542 info->buffer=openCL_library->clCreateBuffer(device->context,
543 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,(size_t) length,(void *) pixels,
545 if (status == CL_SUCCESS)
547 DestroyMagickCLCacheInfo(info);
548 return((MagickCLCacheInfo) NULL);
552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
556 % A c q u i r e M a g i c k C L D e v i c e %
560 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 % AcquireMagickCLDevice() acquires an OpenCL device
564 % The format of the AcquireMagickCLDevice method is:
566 % MagickCLDevice AcquireMagickCLDevice()
570 static MagickCLDevice AcquireMagickCLDevice()
575 device=(MagickCLDevice) AcquireMagickMemory(sizeof(*device));
578 (void) ResetMagickMemory(device,0,sizeof(*device));
579 ActivateSemaphoreInfo(&device->lock);
580 device->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
581 device->command_queues_index=-1;
582 device->enabled=MagickTrue;
588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
592 % A c q u i r e M a g i c k C L E n v %
596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 % AcquireMagickCLEnv() allocates the MagickCLEnv structure
602 static MagickCLEnv AcquireMagickCLEnv(void)
610 clEnv=(MagickCLEnv) AcquireMagickMemory(sizeof(*clEnv));
611 if (clEnv != (MagickCLEnv) NULL)
613 (void) ResetMagickMemory(clEnv,0,sizeof(*clEnv));
614 ActivateSemaphoreInfo(&clEnv->lock);
615 clEnv->cpu_score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
616 clEnv->enabled=MagickTrue;
617 option=getenv("MAGICK_OCL_DEVICE");
618 if ((option != (const char *) NULL) && (strcmp(option,"OFF") == 0))
619 clEnv->enabled=MagickFalse;
625 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 + 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 %
633 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
635 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
637 % The format of the AcquireOpenCLCommandQueue method is:
639 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
641 % A description of each parameter follows:
643 % o device: the OpenCL device.
647 MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
652 cl_command_queue_properties
655 assert(device != (MagickCLDevice) NULL);
656 LockSemaphoreInfo(device->lock);
657 if ((device->profile_kernels == MagickFalse) &&
658 (device->command_queues_index >= 0))
660 queue=device->command_queues[device->command_queues_index--];
661 UnlockSemaphoreInfo(device->lock);
665 UnlockSemaphoreInfo(device->lock);
666 properties=(cl_command_queue_properties) NULL;
667 if (device->profile_kernels != MagickFalse)
668 properties=CL_QUEUE_PROFILING_ENABLE;
669 queue=openCL_library->clCreateCommandQueue(device->context,
670 device->deviceID,properties,(cl_int *) NULL);
676 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 + A c q u i r e O p e n C L K e r n e l %
684 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 % AcquireOpenCLKernel() acquires an OpenCL kernel
688 % The format of the AcquireOpenCLKernel method is:
690 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
691 % MagickOpenCLProgram program, const char* kernelName)
693 % A description of each parameter follows:
695 % o clEnv: the OpenCL environment.
697 % o program: the OpenCL program module that the kernel belongs to.
699 % o kernelName: the name of the kernel
703 MagickPrivate cl_kernel AcquireOpenCLKernel(MagickCLDevice device,
704 const char *kernel_name)
709 assert(device != (MagickCLDevice) NULL);
710 kernel=openCL_library->clCreateKernel(device->program,kernel_name,
716 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
720 % A u t o S e l e c t O p e n C L D e v i c e s %
724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726 % AutoSelectOpenCLDevices() determines the best device based on the
727 % information from the micro-benchmark.
729 % The format of the AutoSelectOpenCLDevices method is:
731 % void AcquireOpenCLKernel(MagickCLEnv clEnv,ExceptionInfo *exception)
733 % A description of each parameter follows:
735 % o clEnv: the OpenCL environment.
737 % o exception: return any errors or warnings in this structure.
741 static void LoadOpenCLDeviceBenchmark(MagickCLEnv clEnv,const char *xml)
744 keyword[MagickPathExtent],
750 MagickCLDeviceBenchmark
757 if (xml == (char *) NULL)
759 device_benchmark=(MagickCLDeviceBenchmark *) NULL;
760 token=AcquireString(xml);
761 extent=strlen(token)+MagickPathExtent;
762 for (q=(char *) xml; *q != '\0'; )
767 GetNextToken(q,&q,extent,token);
770 (void) CopyMagickString(keyword,token,MagickPathExtent);
771 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
776 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
777 GetNextToken(q,&q,extent,token);
780 if (LocaleNCompare(keyword,"<!--",4) == 0)
785 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
786 GetNextToken(q,&q,extent,token);
789 if (LocaleCompare(keyword,"<device") == 0)
794 device_benchmark=(MagickCLDeviceBenchmark *) AcquireMagickMemory(
795 sizeof(*device_benchmark));
796 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
798 (void) ResetMagickMemory(device_benchmark,0,sizeof(*device_benchmark));
799 device_benchmark->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
802 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
804 if (LocaleCompare(keyword,"/>") == 0)
806 if (device_benchmark->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
808 if (LocaleCompare(device_benchmark->name, "CPU") == 0)
809 clEnv->cpu_score=device_benchmark->score;
816 Set the score for all devices that match this device.
818 for (i = 0; i < clEnv->number_devices; i++)
820 device=clEnv->devices[i];
821 if (IsBenchmarkedOpenCLDevice(device,device_benchmark))
822 device->score=device_benchmark->score;
827 device_benchmark->platform_name=RelinquishMagickMemory(
828 device_benchmark->platform_name);
829 device_benchmark->vendor_name=RelinquishMagickMemory(
830 device_benchmark->vendor_name);
831 device_benchmark->name=RelinquishMagickMemory(device_benchmark->name);
832 device_benchmark->version=RelinquishMagickMemory(
833 device_benchmark->version);
834 device_benchmark=(MagickCLDeviceBenchmark *) RelinquishMagickMemory(
838 GetNextToken(q,(const char **) NULL,extent,token);
841 GetNextToken(q,&q,extent,token);
842 GetNextToken(q,&q,extent,token);
848 if (LocaleCompare((char *) keyword,"maxClockFrequency") == 0)
850 device_benchmark->max_clock_frequency=StringToInteger(token);
853 if (LocaleCompare((char *) keyword,"maxComputeUnits") == 0)
855 device_benchmark->max_compute_units=StringToInteger(token);
863 if (LocaleCompare((char *) keyword,"name") == 0)
864 device_benchmark->name=ConstantString(token);
870 if (LocaleCompare((char *) keyword,"platform") == 0)
871 device_benchmark->platform_name=ConstantString(token);
877 if (LocaleCompare((char *) keyword,"score") == 0)
878 device_benchmark->score=StringToDouble(token,(char **) NULL);
884 if (LocaleCompare((char *) keyword,"vendor") == 0)
885 device_benchmark->vendor_name=ConstantString(token);
886 if (LocaleCompare((char *) keyword,"version") == 0)
887 device_benchmark->version=ConstantString(token);
894 token=(char *) RelinquishMagickMemory(token);
895 device_benchmark=(MagickCLDeviceBenchmark *) RelinquishMagickMemory(
899 static MagickBooleanType CanWriteProfileToFile(const char *filename)
904 profileFile=fopen(filename,"ab");
906 if (profileFile == (FILE *)NULL)
913 static MagickBooleanType LoadOpenCLBenchmarks(MagickCLEnv clEnv)
916 filename[MagickPathExtent];
924 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
925 GetOpenCLCacheDirectory(),DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
928 We don't run the benchmark when we can not write out a device profile. The
929 first GPU device will be used.
931 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
932 if (CanWriteProfileToFile(filename) == MagickFalse)
935 for (i = 0; i < clEnv->number_devices; i++)
936 clEnv->devices[i]->score=1.0;
938 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
942 option=ConfigureFileToStringInfo(filename);
943 LoadOpenCLDeviceBenchmark(clEnv,(const char *) GetStringInfoDatum(option));
944 option=DestroyStringInfo(option);
948 static void AutoSelectOpenCLDevices(MagickCLEnv clEnv)
962 option=getenv("MAGICK_OCL_DEVICE");
963 if (option != (const char *) NULL)
965 if (strcmp(option,"GPU") == 0)
966 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
967 else if (strcmp(option,"CPU") == 0)
968 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_CPU);
969 else if (strcmp(option,"OFF") == 0)
971 for (i = 0; i < clEnv->number_devices; i++)
972 clEnv->devices[i]->enabled=MagickFalse;
973 clEnv->enabled=MagickFalse;
977 if (LoadOpenCLBenchmarks(clEnv) == MagickFalse)
980 benchmark=MagickFalse;
981 if (clEnv->cpu_score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
982 benchmark=MagickTrue;
985 for (i = 0; i < clEnv->number_devices; i++)
987 if (clEnv->devices[i]->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
989 benchmark=MagickTrue;
995 if (benchmark != MagickFalse)
996 BenchmarkOpenCLDevices(clEnv);
998 best_score=clEnv->cpu_score;
999 for (i = 0; i < clEnv->number_devices; i++)
1000 best_score=MagickMin(clEnv->devices[i]->score,best_score);
1002 for (i = 0; i < clEnv->number_devices; i++)
1004 if (clEnv->devices[i]->score != best_score)
1005 clEnv->devices[i]->enabled=MagickFalse;
1010 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1014 % B e n c h m a r k O p e n C L D e v i c e s %
1018 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020 % BenchmarkOpenCLDevices() benchmarks the OpenCL devices and the CPU to help
1021 % the automatic selection of the best device.
1023 % The format of the BenchmarkOpenCLDevices method is:
1025 % void BenchmarkOpenCLDevices(MagickCLEnv clEnv,ExceptionInfo *exception)
1027 % A description of each parameter follows:
1029 % o clEnv: the OpenCL environment.
1031 % o exception: return any errors or warnings
1034 static double RunOpenCLBenchmark(MagickBooleanType is_cpu)
1051 exception=AcquireExceptionInfo();
1052 imageInfo=AcquireImageInfo();
1053 CloneString(&imageInfo->size,"2048x1536");
1054 CopyMagickString(imageInfo->filename,"xc:none",MagickPathExtent);
1055 inputImage=ReadImage(imageInfo,exception);
1057 InitAccelerateTimer(&timer);
1059 for (i=0; i<=2; i++)
1067 StartAccelerateTimer(&timer);
1069 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
1070 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
1072 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
1076 We need this to get a proper performance benchmark, the operations
1077 are executed asynchronous.
1079 if (is_cpu == MagickFalse)
1084 cache_info=(CacheInfo *) resizedImage->cache;
1085 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1086 openCL_library->clWaitForEvents(cache_info->opencl->event_count,
1087 cache_info->opencl->events);
1091 StopAccelerateTimer(&timer);
1093 if (bluredImage != (Image *) NULL)
1094 DestroyImage(bluredImage);
1095 if (unsharpedImage != (Image *) NULL)
1096 DestroyImage(unsharpedImage);
1097 if (resizedImage != (Image *) NULL)
1098 DestroyImage(resizedImage);
1100 DestroyImage(inputImage);
1101 return(ReadAccelerateTimer(&timer));
1104 static void RunDeviceBenckmark(MagickCLEnv clEnv,MagickCLEnv testEnv,
1105 MagickCLDevice device)
1107 testEnv->devices[0]=device;
1108 default_CLEnv=testEnv;
1109 device->score=RunOpenCLBenchmark(MagickFalse);
1110 default_CLEnv=clEnv;
1111 testEnv->devices[0]=(MagickCLDevice) NULL;
1114 static void CacheOpenCLBenchmarks(MagickCLEnv clEnv)
1117 filename[MagickPathExtent];
1129 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1130 GetOpenCLCacheDirectory(),DirectorySeparator,
1131 IMAGEMAGICK_PROFILE_FILE);
1133 cache_file=fopen_utf8(filename,"wb");
1134 if (cache_file == (FILE *) NULL)
1136 fwrite("<devices>\n",sizeof(char),10,cache_file);
1137 fprintf(cache_file," <device name=\"CPU\" score=\"%.4g\"/>\n",
1139 for (i = 0; i < clEnv->number_devices; i++)
1144 device=clEnv->devices[i];
1145 duplicate=MagickFalse;
1146 for (j = 0; j < i; j++)
1148 if (IsSameOpenCLDevice(clEnv->devices[j],device))
1150 duplicate=MagickTrue;
1158 if (device->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1159 fprintf(cache_file," <device platform=\"%s\" vendor=\"%s\" name=\"%s\"\
1160 version=\"%s\" maxClockFrequency=\"%d\" maxComputeUnits=\"%d\"\
1161 score=\"%.4g\"/>\n",
1162 device->platform_name,device->vendor_name,device->name,device->version,
1163 (int)device->max_clock_frequency,(int)device->max_compute_units,
1166 fwrite("</devices>",sizeof(char),10,cache_file);
1171 static void BenchmarkOpenCLDevices(MagickCLEnv clEnv)
1183 testEnv=AcquireMagickCLEnv();
1184 testEnv->library=openCL_library;
1185 testEnv->devices=(MagickCLDevice *) AcquireCriticalMemory(
1186 sizeof(MagickCLDevice));
1187 testEnv->number_devices=1;
1188 testEnv->benchmark_thread_id=GetMagickThreadId();
1189 testEnv->initialized=MagickTrue;
1191 for (i = 0; i < clEnv->number_devices; i++)
1192 clEnv->devices[i]->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
1194 for (i = 0; i < clEnv->number_devices; i++)
1196 device=clEnv->devices[i];
1197 if (device->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1198 RunDeviceBenckmark(clEnv,testEnv,device);
1200 /* Set the score on all the other devices that are the same */
1201 for (j = i+1; j < clEnv->number_devices; j++)
1206 other_device=clEnv->devices[j];
1207 if (IsSameOpenCLDevice(device,other_device))
1208 other_device->score=device->score;
1212 testEnv->enabled=MagickFalse;
1213 default_CLEnv=testEnv;
1214 clEnv->cpu_score=RunOpenCLBenchmark(MagickTrue);
1215 default_CLEnv=clEnv;
1217 testEnv=RelinquishMagickCLEnv(testEnv);
1218 CacheOpenCLBenchmarks(clEnv);
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1226 % C o m p i l e O p e n C L K e r n e l %
1230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1232 % CompileOpenCLKernel() compiles the kernel for the specified device. The
1233 % kernel will be cached on disk to reduce the compilation time.
1235 % The format of the CompileOpenCLKernel method is:
1237 % MagickBooleanType AcquireOpenCLKernel(MagickCLDevice clEnv,
1238 % unsigned int signature,const char *kernel,const char *options,
1239 % ExceptionInfo *exception)
1241 % A description of each parameter follows:
1243 % o device: the OpenCL device.
1245 % o kernel: the source code of the kernel.
1247 % o options: options for the compiler.
1249 % o signature: a number to uniquely identify the kernel
1251 % o exception: return any errors or warnings in this structure.
1255 static void CacheOpenCLKernel(MagickCLDevice device,char *filename,
1256 ExceptionInfo *exception)
1267 status=openCL_library->clGetProgramInfo(device->program,
1268 CL_PROGRAM_BINARY_SIZES,sizeof(size_t),&binaryProgramSize,NULL);
1269 if (status != CL_SUCCESS)
1271 binaryProgram=(unsigned char*) AcquireMagickMemory(binaryProgramSize);
1272 if (binaryProgram == (unsigned char *) NULL)
1274 (void) ThrowMagickException(exception,GetMagickModule(),
1275 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1278 status=openCL_library->clGetProgramInfo(device->program,
1279 CL_PROGRAM_BINARIES,sizeof(unsigned char*),&binaryProgram,NULL);
1280 if (status == CL_SUCCESS)
1281 (void) BlobToFile(filename,binaryProgram,binaryProgramSize,exception);
1282 binaryProgram=(unsigned char *) RelinquishMagickMemory(binaryProgram);
1285 static MagickBooleanType LoadCachedOpenCLKernel(MagickCLDevice device,
1286 const char *filename)
1301 exception=AcquireExceptionInfo();
1302 binaryProgram=(unsigned char *) FileToBlob(filename,~0UL,&length,exception);
1303 exception=DestroyExceptionInfo(exception);
1304 if (binaryProgram == (unsigned char *) NULL)
1305 return(MagickFalse);
1306 device->program=openCL_library->clCreateProgramWithBinary(device->context,1,
1307 &device->deviceID,&length,(const unsigned char**)&binaryProgram,
1308 &binaryStatus,&status);
1309 binaryProgram=(unsigned char *) RelinquishMagickMemory(binaryProgram);
1310 return((status != CL_SUCCESS) || (binaryStatus != CL_SUCCESS) ? MagickFalse :
1314 static void LogOpenCLBuildFailure(MagickCLDevice device,const char *kernel,
1315 ExceptionInfo *exception)
1318 filename[MagickPathExtent],
1324 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1325 GetOpenCLCacheDirectory(),DirectorySeparator,"magick_badcl.cl");
1327 (void) remove_utf8(filename);
1328 (void) BlobToFile(filename,kernel,strlen(kernel),exception);
1330 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1331 CL_PROGRAM_BUILD_LOG,0,NULL,&log_size);
1332 log=(char*)AcquireCriticalMemory(log_size);
1333 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1334 CL_PROGRAM_BUILD_LOG,log_size,log,&log_size);
1336 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1337 GetOpenCLCacheDirectory(),DirectorySeparator,"magick_badcl.log");
1339 (void) remove_utf8(filename);
1340 (void) BlobToFile(filename,log,log_size,exception);
1341 log=(char*)RelinquishMagickMemory(log);
1344 static MagickBooleanType CompileOpenCLKernel(MagickCLDevice device,
1345 const char *kernel,const char *options,size_t signature,
1346 ExceptionInfo *exception)
1349 deviceName[MagickPathExtent],
1350 filename[MagickPathExtent],
1362 (void) CopyMagickString(deviceName,device->name,MagickPathExtent);
1364 /* Strip out illegal characters for file names */
1365 while (*ptr != '\0')
1367 if ((*ptr == ' ') || (*ptr == '\\') || (*ptr == '/') || (*ptr == ':') ||
1368 (*ptr == '*') || (*ptr == '?') || (*ptr == '"') || (*ptr == '<') ||
1369 (*ptr == '>' || *ptr == '|'))
1373 (void) FormatLocaleString(filename,MagickPathExtent,
1374 "%s%s%s_%s_%08x_%.20g.bin",GetOpenCLCacheDirectory(),
1375 DirectorySeparator,"magick_opencl",deviceName,(unsigned int) signature,
1376 (double) sizeof(char*)*8);
1377 loaded=LoadCachedOpenCLKernel(device,filename);
1378 if (loaded == MagickFalse)
1380 /* Binary CL program unavailable, compile the program from source */
1381 length=strlen(kernel);
1382 device->program=openCL_library->clCreateProgramWithSource(
1383 device->context,1,&kernel,&length,&status);
1384 if (status != CL_SUCCESS)
1385 return(MagickFalse);
1388 status=openCL_library->clBuildProgram(device->program,1,&device->deviceID,
1390 if (status != CL_SUCCESS)
1392 (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
1393 "clBuildProgram failed.","(%d)",(int)status);
1394 LogOpenCLBuildFailure(device,kernel,exception);
1395 return(MagickFalse);
1398 /* Save the binary to a file to avoid re-compilation of the kernels */
1399 if (loaded == MagickFalse)
1400 CacheOpenCLKernel(device,filename,exception);
1405 static cl_event* CopyOpenCLEvents(MagickCLCacheInfo first,
1406 MagickCLCacheInfo second,cl_uint *event_count)
1417 assert(first != (MagickCLCacheInfo) NULL);
1418 assert(event_count != (cl_uint *) NULL);
1419 events=(cl_event *) NULL;
1420 LockSemaphoreInfo(first->events_semaphore);
1421 if (second != (MagickCLCacheInfo) NULL)
1422 LockSemaphoreInfo(second->events_semaphore);
1423 *event_count=first->event_count;
1424 if (second != (MagickCLCacheInfo) NULL)
1425 *event_count+=second->event_count;
1426 if (*event_count > 0)
1428 events=AcquireQuantumMemory(*event_count,sizeof(*events));
1429 if (events == (cl_event *) NULL)
1434 for (i=0; i < first->event_count; i++, j++)
1435 events[j]=first->events[i];
1436 if (second != (MagickCLCacheInfo) NULL)
1438 for (i=0; i < second->event_count; i++, j++)
1439 events[j]=second->events[i];
1443 UnlockSemaphoreInfo(first->events_semaphore);
1444 if (second != (MagickCLCacheInfo) NULL)
1445 UnlockSemaphoreInfo(second->events_semaphore);
1450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454 + C o p y M a g i c k C L C a c h e I n f o %
1458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460 % CopyMagickCLCacheInfo() copies the memory from the device into host memory.
1462 % The format of the CopyMagickCLCacheInfo method is:
1464 % void CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1466 % A description of each parameter follows:
1468 % o info: the OpenCL cache info.
1471 MagickPrivate MagickCLCacheInfo CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1485 if (info == (MagickCLCacheInfo) NULL)
1486 return((MagickCLCacheInfo) NULL);
1487 events=CopyOpenCLEvents(info,(MagickCLCacheInfo) NULL,&event_count);
1488 if (events != (cl_event *) NULL)
1490 queue=AcquireOpenCLCommandQueue(info->device);
1491 pixels=openCL_library->clEnqueueMapBuffer(queue,info->buffer,CL_TRUE,
1492 CL_MAP_READ | CL_MAP_WRITE,0,info->length,event_count,events,
1493 (cl_event *) NULL,(cl_int *) NULL);
1494 assert(pixels == info->pixels);
1495 ReleaseOpenCLCommandQueue(info->device,queue);
1496 events=(cl_event *) RelinquishMagickMemory(events);
1498 return(RelinquishMagickCLCacheInfo(info,MagickFalse));
1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1506 + D u m p O p e n C L P r o f i l e D a t a %
1510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 % DumpOpenCLProfileData() dumps the kernel profile data.
1514 % The format of the DumpProfileData method is:
1516 % void DumpProfileData()
1520 MagickPrivate void DumpOpenCLProfileData()
1522 #define OpenCLLog(message) \
1523 fwrite(message,sizeof(char),strlen(message),log); \
1524 fwrite("\n",sizeof(char),1,log);
1528 filename[MagickPathExtent],
1541 clEnv=GetCurrentOpenCLEnv();
1542 if (clEnv == (MagickCLEnv) NULL)
1545 for (i = 0; i < clEnv->number_devices; i++)
1546 if (clEnv->devices[i]->profile_kernels != MagickFalse)
1548 if (i == clEnv->number_devices)
1551 (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1552 GetOpenCLCacheDirectory(),DirectorySeparator,"ImageMagickOpenCL.log");
1554 log=fopen_utf8(filename,"wb");
1556 for (i = 0; i < clEnv->number_devices; i++)
1561 device=clEnv->devices[i];
1562 if ((device->profile_kernels == MagickFalse) ||
1563 (device->profile_records == (KernelProfileRecord *) NULL))
1566 OpenCLLog("====================================================");
1567 fprintf(log,"Device: %s\n",device->name);
1568 fprintf(log,"Version: %s\n",device->version);
1569 OpenCLLog("====================================================");
1570 OpenCLLog(" average calls min max");
1571 OpenCLLog(" ------- ----- --- ---");
1573 while (device->profile_records[j] != (KernelProfileRecord) NULL)
1578 profile=device->profile_records[j];
1580 strncpy(indent,profile->kernel_name,MagickMin(strlen(
1581 profile->kernel_name),strlen(indent)-1));
1582 sprintf(buf,"%s %7d %7d %7d %7d",indent,(int) (profile->total/
1583 profile->count),(int) profile->count,(int) profile->min,
1584 (int) profile->max);
1588 OpenCLLog("====================================================");
1589 fwrite("\n\n",sizeof(char),2,log);
1594 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1598 + E n q u e u e O p e n C L K e r n e l %
1602 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1604 % EnqueueOpenCLKernel() enques the specified kernel and registers the OpenCL
1605 % events with the images.
1607 % The format of the EnqueueOpenCLKernel method is:
1609 % MagickBooleanType EnqueueOpenCLKernel(cl_kernel kernel,cl_uint work_dim,
1610 % const size_t *global_work_offset,const size_t *global_work_size,
1611 % const size_t *local_work_size,const Image *input_image,
1612 % const Image *output_image,ExceptionInfo *exception)
1614 % A description of each parameter follows:
1616 % o kernel: the OpenCL kernel.
1618 % o work_dim: the number of dimensions used to specify the global work-items
1619 % and work-items in the work-group.
1621 % o offset: can be used to specify an array of work_dim unsigned values
1622 % that describe the offset used to calculate the global ID of a
1625 % o gsize: points to an array of work_dim unsigned values that describe the
1626 % number of global work-items in work_dim dimensions that will
1627 % execute the kernel function.
1629 % o lsize: points to an array of work_dim unsigned values that describe the
1630 % number of work-items that make up a work-group that will execute
1631 % the kernel specified by kernel.
1633 % o input_image: the input image of the operation.
1635 % o output_image: the output or secondairy image of the operation.
1637 % o exception: return any errors or warnings in this structure.
1641 static MagickBooleanType RegisterCacheEvent(MagickCLCacheInfo info,
1644 assert(info != (MagickCLCacheInfo) NULL);
1645 assert(event != (cl_event) NULL);
1646 if (openCL_library->clRetainEvent(event) != CL_SUCCESS)
1648 openCL_library->clWaitForEvents(1,&event);
1649 return(MagickFalse);
1651 LockSemaphoreInfo(info->events_semaphore);
1652 if (info->events == (cl_event *) NULL)
1654 info->events=AcquireMagickMemory(sizeof(*info->events));
1655 info->event_count=1;
1658 info->events=ResizeQuantumMemory(info->events,++info->event_count,
1659 sizeof(*info->events));
1660 if (info->events == (cl_event *) NULL)
1661 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1662 info->events[info->event_count-1]=event;
1663 UnlockSemaphoreInfo(info->events_semaphore);
1667 MagickPrivate MagickBooleanType EnqueueOpenCLKernel(cl_command_queue queue,
1668 cl_kernel kernel,cl_uint work_dim,const size_t *offset,const size_t *gsize,
1669 const size_t *lsize,const Image *input_image,const Image *output_image,
1670 MagickBooleanType flush,ExceptionInfo *exception)
1686 assert(input_image != (const Image *) NULL);
1687 input_info=(CacheInfo *) input_image->cache;
1688 assert(input_info != (CacheInfo *) NULL);
1689 assert(input_info->opencl != (MagickCLCacheInfo) NULL);
1690 output_info=(CacheInfo *) NULL;
1691 if (output_image == (const Image *) NULL)
1692 events=CopyOpenCLEvents(input_info->opencl,(MagickCLCacheInfo) NULL,
1696 output_info=(CacheInfo *) output_image->cache;
1697 assert(output_info != (CacheInfo *) NULL);
1698 assert(output_info->opencl != (MagickCLCacheInfo) NULL);
1699 events=CopyOpenCLEvents(input_info->opencl,output_info->opencl,
1702 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,offset,
1703 gsize,lsize,event_count,events,&event);
1704 /* This can fail due to memory issues and calling clFinish might help. */
1705 if ((status != CL_SUCCESS) && (event_count > 0))
1707 openCL_library->clFinish(queue);
1708 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,
1709 offset,gsize,lsize,event_count,events,&event);
1711 events=(cl_event *) RelinquishMagickMemory(events);
1712 if (status != CL_SUCCESS)
1714 (void) OpenCLThrowMagickException(input_info->opencl->device,exception,
1715 GetMagickModule(),ResourceLimitWarning,
1716 "clEnqueueNDRangeKernel failed.","'%s'",".");
1717 return(MagickFalse);
1719 if (flush != MagickFalse)
1720 openCL_library->clFlush(queue);
1721 if (RecordProfileData(input_info->opencl->device,kernel,event) == MagickFalse)
1723 if (RegisterCacheEvent(input_info->opencl,event) != MagickFalse)
1725 if (output_info != (CacheInfo *) NULL)
1726 (void) RegisterCacheEvent(output_info->opencl,event);
1729 openCL_library->clReleaseEvent(event);
1734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1738 + G e t C u r r u n t O p e n C L E n v %
1742 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1744 % GetCurrentOpenCLEnv() returns the current OpenCL env
1746 % The format of the GetCurrentOpenCLEnv method is:
1748 % MagickCLEnv GetCurrentOpenCLEnv()
1752 MagickPrivate MagickCLEnv GetCurrentOpenCLEnv(void)
1754 if (default_CLEnv != (MagickCLEnv) NULL)
1756 if ((default_CLEnv->benchmark_thread_id != (MagickThreadType) 0) &&
1757 (default_CLEnv->benchmark_thread_id != GetMagickThreadId()))
1758 return((MagickCLEnv) NULL);
1760 return(default_CLEnv);
1763 if (GetOpenCLCacheDirectory() == (char *) NULL)
1764 return((MagickCLEnv) NULL);
1766 if (openCL_lock == (SemaphoreInfo *) NULL)
1767 ActivateSemaphoreInfo(&openCL_lock);
1769 LockSemaphoreInfo(openCL_lock);
1770 if (default_CLEnv == (MagickCLEnv) NULL)
1771 default_CLEnv=AcquireMagickCLEnv();
1772 UnlockSemaphoreInfo(openCL_lock);
1774 return(default_CLEnv);
1778 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1782 % 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 %
1786 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1788 % GetOpenCLDeviceBenchmarkScore() returns the score of the benchmark for the
1789 % device. The score is determined by the duration of the micro benchmark so
1790 % that means a lower score is better than a higher score.
1792 % The format of the GetOpenCLDeviceBenchmarkScore method is:
1794 % double GetOpenCLDeviceBenchmarkScore(const MagickCLDevice device)
1796 % A description of each parameter follows:
1798 % o device: the OpenCL device.
1801 MagickExport double GetOpenCLDeviceBenchmarkScore(
1802 const MagickCLDevice device)
1804 if (device == (MagickCLDevice) NULL)
1805 return(MAGICKCORE_OPENCL_UNDEFINED_SCORE);
1806 return(device->score);
1810 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1814 % G e t O p e n C L D e v i c e E n a b l e d %
1818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1820 % GetOpenCLDeviceEnabled() returns true if the device is enabled.
1822 % The format of the GetOpenCLDeviceEnabled method is:
1824 % MagickBooleanType GetOpenCLDeviceEnabled(const MagickCLDevice device)
1826 % A description of each parameter follows:
1828 % o device: the OpenCL device.
1831 MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
1832 const MagickCLDevice device)
1834 if (device == (MagickCLDevice) NULL)
1835 return(MagickFalse);
1836 return(device->enabled);
1840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1844 % G e t O p e n C L D e v i c e N a m e %
1848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1850 % GetOpenCLDeviceName() returns the name of the device.
1852 % The format of the GetOpenCLDeviceName method is:
1854 % const char *GetOpenCLDeviceName(const MagickCLDevice device)
1856 % A description of each parameter follows:
1858 % o device: the OpenCL device.
1861 MagickExport const char *GetOpenCLDeviceName(const MagickCLDevice device)
1863 if (device == (MagickCLDevice) NULL)
1864 return((const char *) NULL);
1865 return(device->name);
1869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1873 % 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 %
1877 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1879 % GetOpenCLDeviceVendorName() returns the vendor name of the device.
1881 % The format of the GetOpenCLDeviceVendorName method is:
1883 % const char *GetOpenCLDeviceVendorName(const MagickCLDevice device)
1885 % A description of each parameter follows:
1887 % o device: the OpenCL device.
1890 MagickExport const char *GetOpenCLDeviceVendorName(const MagickCLDevice device)
1892 if (device == (MagickCLDevice) NULL)
1893 return((const char *) NULL);
1894 return(device->vendor_name);
1898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1902 % G e t O p e n C L D e v i c e s %
1906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1908 % GetOpenCLDevices() returns the devices of the OpenCL environment at sets the
1909 % value of length to the number of devices that are available.
1911 % The format of the GetOpenCLDevices method is:
1913 % const MagickCLDevice *GetOpenCLDevices(size_t *length,
1914 % ExceptionInfo *exception)
1916 % A description of each parameter follows:
1918 % o length: the number of device.
1920 % o exception: return any errors or warnings in this structure.
1924 MagickExport MagickCLDevice *GetOpenCLDevices(size_t *length,
1925 ExceptionInfo *exception)
1930 clEnv=GetCurrentOpenCLEnv();
1931 if (clEnv == (MagickCLEnv) NULL)
1933 if (length != (size_t *) NULL)
1935 return((MagickCLDevice *) NULL);
1937 InitializeOpenCL(clEnv,exception);
1938 if (length != (size_t *) NULL)
1939 *length=clEnv->number_devices;
1940 return(clEnv->devices);
1944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1948 % G e t O p e n C L D e v i c e T y p e %
1952 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1954 % GetOpenCLDeviceType() returns the type of the device.
1956 % The format of the GetOpenCLDeviceType method is:
1958 % MagickCLDeviceType GetOpenCLDeviceType(const MagickCLDevice device)
1960 % A description of each parameter follows:
1962 % o device: the OpenCL device.
1965 MagickExport MagickCLDeviceType GetOpenCLDeviceType(
1966 const MagickCLDevice device)
1968 if (device == (MagickCLDevice) NULL)
1969 return(UndefinedCLDeviceType);
1970 if (device->type == CL_DEVICE_TYPE_GPU)
1971 return(GpuCLDeviceType);
1972 if (device->type == CL_DEVICE_TYPE_CPU)
1973 return(CpuCLDeviceType);
1974 return(UndefinedCLDeviceType);
1978 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1982 % G e t O p e n C L D e v i c e V e r s i o n %
1986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 % GetOpenCLDeviceVersion() returns the version of the device.
1990 % The format of the GetOpenCLDeviceName method is:
1992 % const char *GetOpenCLDeviceVersion(MagickCLDevice device)
1994 % A description of each parameter follows:
1996 % o device: the OpenCL device.
1999 MagickExport const char *GetOpenCLDeviceVersion(const MagickCLDevice device)
2001 if (device == (MagickCLDevice) NULL)
2002 return((const char *) NULL);
2003 return(device->version);
2007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2011 % G e t O p e n C L E n a b l e d %
2015 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017 % GetOpenCLEnabled() returns true if OpenCL acceleration is enabled.
2019 % The format of the GetOpenCLEnabled method is:
2021 % MagickBooleanType GetOpenCLEnabled()
2025 MagickExport MagickBooleanType GetOpenCLEnabled(void)
2030 clEnv=GetCurrentOpenCLEnv();
2031 if (clEnv == (MagickCLEnv) NULL)
2032 return(MagickFalse);
2033 return(clEnv->enabled);
2037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2041 % 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 %
2045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2047 % GetOpenCLKernelProfileRecords() returns the profile records for the
2048 % specified device and sets length to the number of profile records.
2050 % The format of the GetOpenCLKernelProfileRecords method is:
2052 % const KernelProfileRecord *GetOpenCLKernelProfileRecords(size *length)
2054 % A description of each parameter follows:
2056 % o length: the number of profiles records.
2059 MagickExport const KernelProfileRecord *GetOpenCLKernelProfileRecords(
2060 const MagickCLDevice device,size_t *length)
2062 if ((device == (const MagickCLDevice) NULL) || (device->profile_records ==
2063 (KernelProfileRecord *) NULL))
2065 if (length != (size_t *) NULL)
2067 return((const KernelProfileRecord *) NULL);
2069 if (length != (size_t *) NULL)
2072 LockSemaphoreInfo(device->lock);
2073 while (device->profile_records[*length] != (KernelProfileRecord) NULL)
2075 UnlockSemaphoreInfo(device->lock);
2077 return(device->profile_records);
2081 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2085 % H a s O p e n C L D e v i c e s %
2089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2091 % HasOpenCLDevices() checks if the OpenCL environment has devices that are
2092 % enabled and compiles the kernel for the device when necessary. False will be
2093 % returned if no enabled devices could be found
2095 % The format of the HasOpenCLDevices method is:
2097 % MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2098 % ExceptionInfo exception)
2100 % A description of each parameter follows:
2102 % o clEnv: the OpenCL environment.
2104 % o exception: return any errors or warnings in this structure.
2108 static MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2109 ExceptionInfo *exception)
2112 *accelerateKernelsBuffer,
2113 options[MagickPathExtent];
2124 /* Check if there are enabled devices */
2125 for (i = 0; i < clEnv->number_devices; i++)
2127 if ((clEnv->devices[i]->enabled != MagickFalse))
2130 if (i == clEnv->number_devices)
2131 return(MagickFalse);
2133 /* Check if we need to compile a kernel for one of the devices */
2135 for (i = 0; i < clEnv->number_devices; i++)
2137 if ((clEnv->devices[i]->enabled != MagickFalse) &&
2138 (clEnv->devices[i]->program == (cl_program) NULL))
2144 if (status != MagickFalse)
2147 /* Get additional options */
2148 (void) FormatLocaleString(options,MaxTextExtent,CLOptions,
2149 (float)QuantumRange,(float)QuantumScale,(float)CLCharQuantumScale,
2150 (float)MagickEpsilon,(float)MagickPI,(unsigned int)MaxMap,
2151 (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
2153 signature=StringSignature(options);
2154 accelerateKernelsBuffer=(char*) AcquireMagickMemory(
2155 strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
2156 if (accelerateKernelsBuffer == (char*) NULL)
2157 return(MagickFalse);
2158 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
2159 signature^=StringSignature(accelerateKernelsBuffer);
2162 for (i = 0; i < clEnv->number_devices; i++)
2170 device=clEnv->devices[i];
2171 if ((device->enabled == MagickFalse) ||
2172 (device->program != (cl_program) NULL))
2175 LockSemaphoreInfo(device->lock);
2176 if (device->program != (cl_program) NULL)
2178 UnlockSemaphoreInfo(device->lock);
2181 device_signature=signature;
2182 device_signature^=StringSignature(device->platform_name);
2183 status=CompileOpenCLKernel(device,accelerateKernelsBuffer,options,
2184 device_signature,exception);
2185 UnlockSemaphoreInfo(device->lock);
2186 if (status == MagickFalse)
2189 accelerateKernelsBuffer=RelinquishMagickMemory(accelerateKernelsBuffer);
2194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198 + I n i t i a l i z e O p e n C L %
2202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2204 % InitializeOpenCL() is used to initialize the OpenCL environment. This method
2205 % makes sure the devices are propertly initialized and benchmarked.
2207 % The format of the InitializeOpenCL method is:
2209 % MagickBooleanType InitializeOpenCL(ExceptionInfo exception)
2211 % A description of each parameter follows:
2213 % o exception: return any errors or warnings in this structure.
2217 static cl_uint GetOpenCLDeviceCount(MagickCLEnv clEnv,cl_platform_id platform)
2220 version[MagickPathExtent];
2225 if (clEnv->library->clGetPlatformInfo(platform,CL_PLATFORM_VERSION,
2226 MagickPathExtent,version,NULL) != CL_SUCCESS)
2228 if (strncmp(version, "OpenCL 1.0 ", 11) == 0)
2230 if (clEnv->library->clGetDeviceIDs(platform,
2231 CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU,0,NULL,&num) != CL_SUCCESS)
2236 static void LoadOpenCLDevices(MagickCLEnv clEnv)
2238 cl_context_properties
2261 if (openCL_library->clGetPlatformIDs(0,NULL,&number_platforms) != CL_SUCCESS)
2263 if (number_platforms == 0)
2265 platforms=(cl_platform_id *) AcquireMagickMemory(number_platforms*
2266 sizeof(cl_platform_id));
2267 if (platforms == (cl_platform_id *) NULL)
2269 if (openCL_library->clGetPlatformIDs(number_platforms,platforms,NULL) != CL_SUCCESS)
2271 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2274 for (i = 0; i < number_platforms; i++)
2276 number_devices=GetOpenCLDeviceCount(clEnv,platforms[i]);
2277 if (number_devices == 0)
2278 platforms[i]=(cl_platform_id) NULL;
2280 clEnv->number_devices+=number_devices;
2282 if (clEnv->number_devices == 0)
2284 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2287 clEnv->devices=(MagickCLDevice *) AcquireQuantumMemory(clEnv->number_devices,
2288 sizeof(MagickCLDevice));
2289 if (clEnv->devices == (MagickCLDevice *) NULL)
2291 RelinquishMagickCLDevices(clEnv);
2292 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2295 (void) ResetMagickMemory(clEnv->devices,0,clEnv->number_devices*
2296 sizeof(MagickCLDevice));
2297 devices=(cl_device_id *) AcquireQuantumMemory(clEnv->number_devices,
2298 sizeof(cl_device_id));
2299 if (devices == (cl_device_id *) NULL)
2301 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2302 RelinquishMagickCLDevices(clEnv);
2305 clEnv->number_contexts=(size_t) number_platforms;
2306 clEnv->contexts=(cl_context *) AcquireQuantumMemory(clEnv->number_contexts,
2307 sizeof(cl_context));
2308 if (clEnv->contexts == (cl_context *) NULL)
2310 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2311 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2312 RelinquishMagickCLDevices(clEnv);
2316 for (i = 0; i < number_platforms; i++)
2318 if (platforms[i] == (cl_platform_id) NULL)
2321 status=clEnv->library->clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_CPU |
2322 CL_DEVICE_TYPE_GPU,(cl_uint) clEnv->number_devices,devices,&number_devices);
2323 if (status != CL_SUCCESS)
2326 properties[0]=CL_CONTEXT_PLATFORM;
2327 properties[1]=(cl_context_properties) platforms[i];
2329 clEnv->contexts[i]=openCL_library->clCreateContext(properties,number_devices,
2330 devices,NULL,NULL,&status);
2331 if (status != CL_SUCCESS)
2334 for (j = 0; j < number_devices; j++,next++)
2339 device=AcquireMagickCLDevice();
2340 if (device == (MagickCLDevice) NULL)
2343 device->context=clEnv->contexts[i];
2344 device->deviceID=devices[j];
2346 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_NAME,0,NULL,
2348 device->platform_name=AcquireCriticalMemory(length*
2349 sizeof(*device->platform_name));
2350 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_NAME,length,
2351 device->platform_name,NULL);
2353 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_VENDOR,0,NULL,
2355 device->vendor_name=AcquireCriticalMemory(length*
2356 sizeof(*device->vendor_name));
2357 openCL_library->clGetPlatformInfo(platforms[i],CL_PLATFORM_VENDOR,length,
2358 device->vendor_name,NULL);
2360 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_NAME,0,NULL,
2362 device->name=AcquireCriticalMemory(length*sizeof(*device->name));
2363 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_NAME,length,
2366 openCL_library->clGetDeviceInfo(devices[j],CL_DRIVER_VERSION,0,NULL,
2368 device->version=AcquireCriticalMemory(length*sizeof(*device->version));
2369 openCL_library->clGetDeviceInfo(devices[j],CL_DRIVER_VERSION,length,
2370 device->version,NULL);
2372 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_CLOCK_FREQUENCY,
2373 sizeof(cl_uint),&device->max_clock_frequency,NULL);
2375 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,
2376 sizeof(cl_uint),&device->max_compute_units,NULL);
2378 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_TYPE,
2379 sizeof(cl_device_type),&device->type,NULL);
2381 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_LOCAL_MEM_SIZE,
2382 sizeof(cl_ulong),&device->local_memory_size,NULL);
2384 clEnv->devices[next]=device;
2387 if (next != clEnv->number_devices)
2388 RelinquishMagickCLDevices(clEnv);
2389 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2390 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2393 MagickPrivate MagickBooleanType InitializeOpenCL(MagickCLEnv clEnv,
2394 ExceptionInfo *exception)
2396 LockSemaphoreInfo(clEnv->lock);
2397 if (clEnv->initialized != MagickFalse)
2399 UnlockSemaphoreInfo(clEnv->lock);
2400 return(HasOpenCLDevices(clEnv,exception));
2402 if (LoadOpenCLLibrary() != MagickFalse)
2404 clEnv->library=openCL_library;
2405 LoadOpenCLDevices(clEnv);
2406 if (clEnv->number_devices > 0)
2407 AutoSelectOpenCLDevices(clEnv);
2409 clEnv->initialized=MagickTrue;
2410 UnlockSemaphoreInfo(clEnv->lock);
2411 return(HasOpenCLDevices(clEnv,exception));
2415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419 % L o a d O p e n C L L i b r a r y %
2423 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2425 % LoadOpenCLLibrary() load and binds the OpenCL library.
2427 % The format of the LoadOpenCLLibrary method is:
2429 % MagickBooleanType LoadOpenCLLibrary(void)
2433 void *OsLibraryGetFunctionAddress(void *library,const char *functionName)
2435 if ((library == (void *) NULL) || (functionName == (const char *) NULL))
2436 return (void *) NULL;
2437 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2438 return (void *) GetProcAddress((HMODULE)library,functionName);
2440 return (void *) dlsym(library,functionName);
2444 static MagickBooleanType BindOpenCLFunctions()
2446 #ifdef MAGICKCORE_OPENCL_MACOSX
2447 #define BIND(X) openCL_library->X= &X;
2449 (void) ResetMagickMemory(openCL_library,0,sizeof(MagickLibrary));
2450 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2451 openCL_library->library=(void *)LoadLibraryA("OpenCL.dll");
2453 openCL_library->library=(void *)dlopen("libOpenCL.so", RTLD_NOW);
2456 if ((openCL_library->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(openCL_library->library,#X)) == NULL) \
2457 return(MagickFalse);
2460 if (openCL_library->library == (void*) NULL)
2461 return(MagickFalse);
2463 BIND(clGetPlatformIDs);
2464 BIND(clGetPlatformInfo);
2466 BIND(clGetDeviceIDs);
2467 BIND(clGetDeviceInfo);
2469 BIND(clCreateBuffer);
2470 BIND(clReleaseMemObject);
2471 BIND(clRetainMemObject);
2473 BIND(clCreateContext);
2474 BIND(clReleaseContext);
2476 BIND(clCreateCommandQueue);
2477 BIND(clReleaseCommandQueue);
2481 BIND(clCreateProgramWithSource);
2482 BIND(clCreateProgramWithBinary);
2483 BIND(clReleaseProgram);
2484 BIND(clBuildProgram);
2485 BIND(clGetProgramBuildInfo);
2486 BIND(clGetProgramInfo);
2488 BIND(clCreateKernel);
2489 BIND(clReleaseKernel);
2490 BIND(clSetKernelArg);
2491 BIND(clGetKernelInfo);
2493 BIND(clEnqueueReadBuffer);
2494 BIND(clEnqueueMapBuffer);
2495 BIND(clEnqueueUnmapMemObject);
2496 BIND(clEnqueueNDRangeKernel);
2498 BIND(clGetEventInfo);
2499 BIND(clWaitForEvents);
2500 BIND(clReleaseEvent);
2501 BIND(clRetainEvent);
2502 BIND(clSetEventCallback);
2504 BIND(clGetEventProfilingInfo);
2509 static MagickBooleanType LoadOpenCLLibrary(void)
2511 openCL_library=(MagickLibrary *) AcquireMagickMemory(sizeof(MagickLibrary));
2512 if (openCL_library == (MagickLibrary *) NULL)
2513 return(MagickFalse);
2515 if (BindOpenCLFunctions() == MagickFalse)
2517 openCL_library=(MagickLibrary *)RelinquishMagickMemory(openCL_library);
2518 return(MagickFalse);
2525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2529 + O p e n C L T e r m i n u s %
2533 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2535 % OpenCLTerminus() destroys the OpenCL component.
2537 % The format of the OpenCLTerminus method is:
2539 % OpenCLTerminus(void)
2543 MagickPrivate void OpenCLTerminus()
2545 DumpOpenCLProfileData();
2546 if (cache_directory != (char *) NULL)
2547 cache_directory=DestroyString(cache_directory);
2548 if (cache_directory_lock != (SemaphoreInfo *) NULL)
2549 RelinquishSemaphoreInfo(&cache_directory_lock);
2550 if (default_CLEnv != (MagickCLEnv) NULL)
2551 default_CLEnv=RelinquishMagickCLEnv(default_CLEnv);
2552 if (openCL_lock != (SemaphoreInfo *) NULL)
2553 RelinquishSemaphoreInfo(&openCL_lock);
2554 if (openCL_library != (MagickLibrary *) NULL)
2556 if (openCL_library->library != (void *) NULL)
2557 (void) lt_dlclose(openCL_library->library);
2558 openCL_library=(MagickLibrary *) RelinquishMagickMemory(openCL_library);
2563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2567 + 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 %
2571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2573 % OpenCLThrowMagickException logs an OpenCL exception as determined by the log
2574 % configuration file. If an error occurs, MagickFalse is returned
2575 % otherwise MagickTrue.
2577 % The format of the OpenCLThrowMagickException method is:
2579 % MagickBooleanType ThrowFileException(ExceptionInfo *exception,
2580 % const char *module,const char *function,const size_t line,
2581 % const ExceptionType severity,const char *tag,const char *format,...)
2583 % A description of each parameter follows:
2585 % o exception: the exception info.
2587 % o filename: the source module filename.
2589 % o function: the function name.
2591 % o line: the line number of the source module.
2593 % o severity: Specifies the numeric error category.
2595 % o tag: the locale tag.
2597 % o format: the output format.
2601 MagickPrivate MagickBooleanType OpenCLThrowMagickException(
2602 MagickCLDevice device,ExceptionInfo *exception,const char *module,
2603 const char *function,const size_t line,const ExceptionType severity,
2604 const char *tag,const char *format,...)
2609 assert(device != (MagickCLDevice) NULL);
2610 assert(exception != (ExceptionInfo *) NULL);
2611 assert(exception->signature == MagickCoreSignature);
2616 if (device->type == CL_DEVICE_TYPE_CPU)
2618 /* Workaround for Intel OpenCL CPU runtime bug */
2619 /* Turn off OpenCL when a problem is detected! */
2620 if (strncmp(device->platform_name, "Intel",5) == 0)
2621 default_CLEnv->enabled=MagickFalse;
2625 #ifdef OPENCLLOG_ENABLED
2629 va_start(operands,format);
2630 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
2635 magick_unreferenced(module);
2636 magick_unreferenced(function);
2637 magick_unreferenced(line);
2638 magick_unreferenced(tag);
2639 magick_unreferenced(format);
2646 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2650 + R e c o r d P r o f i l e D a t a %
2654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2656 % RecordProfileData() records profile data.
2658 % The format of the RecordProfileData method is:
2660 % void RecordProfileData(MagickCLDevice device,ProfiledKernels kernel,
2663 % A description of each parameter follows:
2665 % o device: the OpenCL device that did the operation.
2667 % o event: the event that contains the profiling data.
2671 MagickPrivate MagickBooleanType RecordProfileData(MagickCLDevice device,
2672 cl_kernel kernel,cl_event event)
2692 if (device->profile_kernels == MagickFalse)
2693 return(MagickFalse);
2694 status=openCL_library->clWaitForEvents(1,&event);
2695 if (status != CL_SUCCESS)
2696 return(MagickFalse);
2697 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,0,NULL,
2699 if (status != CL_SUCCESS)
2701 name=AcquireQuantumMemory(length,sizeof(*name));
2702 if (name == (char *) NULL)
2704 start=end=elapsed=0;
2705 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,length,
2706 name,(size_t *) NULL);
2707 status|=openCL_library->clGetEventProfilingInfo(event,
2708 CL_PROFILING_COMMAND_START,sizeof(cl_ulong),&start,NULL);
2709 status|=openCL_library->clGetEventProfilingInfo(event,
2710 CL_PROFILING_COMMAND_END,sizeof(cl_ulong),&end,NULL);
2711 if (status != CL_SUCCESS)
2713 name=DestroyString(name);
2716 start/=1000; // usecs
2719 LockSemaphoreInfo(device->lock);
2721 profile_record=(KernelProfileRecord) NULL;
2722 if (device->profile_records != (KernelProfileRecord *) NULL)
2724 while (device->profile_records[i] != (KernelProfileRecord) NULL)
2726 if (LocaleCompare(device->profile_records[i]->kernel_name,name) == 0)
2728 profile_record=device->profile_records[i];
2734 if (profile_record != (KernelProfileRecord) NULL)
2735 name=DestroyString(name);
2738 profile_record=AcquireMagickMemory(sizeof(*profile_record));
2739 (void) ResetMagickMemory(profile_record,0,sizeof(*profile_record));
2740 profile_record->kernel_name=name;
2741 device->profile_records=ResizeMagickMemory(device->profile_records,(i+2)*
2742 sizeof(*device->profile_records));
2743 device->profile_records[i]=profile_record;
2744 device->profile_records[i+1]=(KernelProfileRecord) NULL;
2746 if ((elapsed < profile_record->min) || (profile_record->count == 0))
2747 profile_record->min=elapsed;
2748 if (elapsed > profile_record->max)
2749 profile_record->max=elapsed;
2750 profile_record->total+=elapsed;
2751 profile_record->count+=1;
2752 UnlockSemaphoreInfo(device->lock);
2757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2761 + 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 %
2765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2767 % ReleaseOpenCLCommandQueue() releases the OpenCL command queue
2769 % The format of the ReleaseOpenCLCommandQueue method is:
2771 % void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2772 % cl_command_queue queue)
2774 % A description of each parameter follows:
2776 % o device: the OpenCL device.
2778 % o queue: the OpenCL queue to be released.
2781 MagickPrivate void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2782 cl_command_queue queue)
2784 if (queue == (cl_command_queue) NULL)
2787 assert(device != (MagickCLDevice) NULL);
2788 LockSemaphoreInfo(device->lock);
2789 if ((device->profile_kernels != MagickFalse) ||
2790 (device->command_queues_index >= MAGICKCORE_OPENCL_COMMAND_QUEUES-1))
2792 UnlockSemaphoreInfo(device->lock);
2793 openCL_library->clFinish(queue);
2794 (void) openCL_library->clReleaseCommandQueue(queue);
2798 openCL_library->clFlush(queue);
2799 device->command_queues[++device->command_queues_index]=queue;
2800 UnlockSemaphoreInfo(device->lock);
2805 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2809 + R e l e a s e M a g i c k C L D e v i c e %
2813 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2815 % ReleaseOpenCLDevice() returns the OpenCL device to the environment
2817 % The format of the ReleaseOpenCLDevice method is:
2819 % void ReleaseOpenCLDevice(MagickCLDevice device)
2821 % A description of each parameter follows:
2823 % o device: the OpenCL device to be released.
2827 MagickPrivate void ReleaseOpenCLDevice(MagickCLDevice device)
2829 assert(device != (MagickCLDevice) NULL);
2830 LockSemaphoreInfo(openCL_lock);
2831 device->requested--;
2832 UnlockSemaphoreInfo(openCL_lock);
2836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2840 + 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 %
2844 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2846 % RelinquishMagickCLCacheInfo() frees memory acquired with
2847 % AcquireMagickCLCacheInfo()
2849 % The format of the RelinquishMagickCLCacheInfo method is:
2851 % MagickCLCacheInfo RelinquishMagickCLCacheInfo(MagickCLCacheInfo info,
2852 % const MagickBooleanType relinquish_pixels)
2854 % A description of each parameter follows:
2856 % o info: the OpenCL cache info.
2858 % o relinquish_pixels: the pixels will be relinquish when set to true.
2862 static void CL_API_CALL DestroyMagickCLCacheInfoAndPixels(
2863 cl_event magick_unused(event),
2864 cl_int magick_unused(event_command_exec_status),void *user_data)
2875 magick_unreferenced(event);
2876 magick_unreferenced(event_command_exec_status);
2877 info=(MagickCLCacheInfo) user_data;
2878 for (i=(ssize_t)info->event_count-1; i >= 0; i--)
2886 status=openCL_library->clGetEventInfo(info->events[i],
2887 CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof(event_status),&event_status,
2889 if ((status == CL_SUCCESS) && (event_status != CL_COMPLETE))
2891 openCL_library->clSetEventCallback(info->events[i],CL_COMPLETE,
2892 &DestroyMagickCLCacheInfoAndPixels,info);
2896 pixels=info->pixels;
2897 DestroyMagickCLCacheInfo(info);
2898 (void) RelinquishAlignedMemory(pixels);
2901 MagickPrivate MagickCLCacheInfo RelinquishMagickCLCacheInfo(
2902 MagickCLCacheInfo info,const MagickBooleanType relinquish_pixels)
2904 if (info == (MagickCLCacheInfo) NULL)
2905 return((MagickCLCacheInfo) NULL);
2906 if (relinquish_pixels != MagickFalse)
2907 DestroyMagickCLCacheInfoAndPixels((cl_event) NULL,0,info);
2909 DestroyMagickCLCacheInfo(info);
2910 return((MagickCLCacheInfo) NULL);
2914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2918 % R e l i n q u i s h M a g i c k C L D e v i c e %
2922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2924 % RelinquishMagickCLDevice() releases the OpenCL device
2926 % The format of the RelinquishMagickCLDevice method is:
2928 % MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2930 % A description of each parameter follows:
2932 % o device: the OpenCL device to be released.
2936 static MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2938 if (device == (MagickCLDevice) NULL)
2939 return((MagickCLDevice) NULL);
2941 device->platform_name=RelinquishMagickMemory(device->platform_name);
2942 device->vendor_name=RelinquishMagickMemory(device->vendor_name);
2943 device->name=RelinquishMagickMemory(device->name);
2944 device->version=RelinquishMagickMemory(device->version);
2945 if (device->program != (cl_program) NULL)
2946 (void) openCL_library->clReleaseProgram(device->program);
2947 while (device->command_queues_index >= 0)
2948 (void) openCL_library->clReleaseCommandQueue(
2949 device->command_queues[device->command_queues_index--]);
2950 RelinquishSemaphoreInfo(&device->lock);
2951 return((MagickCLDevice) RelinquishMagickMemory(device));
2955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2959 % R e l i n q u i s h M a g i c k C L E n v %
2963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2965 % RelinquishMagickCLEnv() releases the OpenCL environment
2967 % The format of the RelinquishMagickCLEnv method is:
2969 % MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv device)
2971 % A description of each parameter follows:
2973 % o clEnv: the OpenCL environment to be released.
2977 static MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv clEnv)
2979 if (clEnv == (MagickCLEnv) NULL)
2980 return((MagickCLEnv) NULL);
2982 RelinquishSemaphoreInfo(&clEnv->lock);
2983 RelinquishMagickCLDevices(clEnv);
2984 if (clEnv->contexts != (cl_context *) NULL)
2989 for (i=0; i < clEnv->number_contexts; i++)
2990 (void) openCL_library->clReleaseContext(clEnv->contexts[i]);
2991 clEnv->contexts=(cl_context *) RelinquishMagickMemory(clEnv->contexts);
2993 return((MagickCLEnv) RelinquishMagickMemory(clEnv));
2997 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3001 + R e q u e s t O p e n C L D e v i c e %
3005 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3007 % RequestOpenCLDevice() returns one of the enabled OpenCL devices.
3009 % The format of the RequestOpenCLDevice method is:
3011 % MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
3013 % A description of each parameter follows:
3015 % o clEnv: the OpenCL environment.
3018 MagickPrivate MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
3030 if (clEnv == (MagickCLEnv) NULL)
3031 return((MagickCLDevice) NULL);
3033 if (clEnv->number_devices == 1)
3035 if (clEnv->devices[0]->enabled)
3036 return(clEnv->devices[0]);
3038 return((MagickCLDevice) NULL);
3041 device=(MagickCLDevice) NULL;
3043 LockSemaphoreInfo(openCL_lock);
3044 for (i = 0; i < clEnv->number_devices; i++)
3046 if (clEnv->devices[i]->enabled == MagickFalse)
3049 score=clEnv->devices[i]->score+(clEnv->devices[i]->score*
3050 clEnv->devices[i]->requested);
3051 if ((device == (MagickCLDevice) NULL) || (score < best_score))
3053 device=clEnv->devices[i];
3057 if (device != (MagickCLDevice)NULL)
3058 device->requested++;
3059 UnlockSemaphoreInfo(openCL_lock);
3065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3069 % S e t O p e n C L D e v i c e E n a b l e d %
3073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3075 % SetOpenCLDeviceEnabled() can be used to enable or disabled the device.
3077 % The format of the SetOpenCLDeviceEnabled method is:
3079 % void SetOpenCLDeviceEnabled(MagickCLDevice device,
3080 % MagickBooleanType value)
3082 % A description of each parameter follows:
3084 % o device: the OpenCL device.
3086 % o value: determines if the device should be enabled or disabled.
3089 MagickExport void SetOpenCLDeviceEnabled(MagickCLDevice device,
3090 const MagickBooleanType value)
3092 if (device == (MagickCLDevice) NULL)
3094 device->enabled=value;
3098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3102 % 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 %
3106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3108 % SetOpenCLKernelProfileEnabled() can be used to enable or disabled the
3109 % kernel profiling of a device.
3111 % The format of the SetOpenCLKernelProfileEnabled method is:
3113 % void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3114 % MagickBooleanType value)
3116 % A description of each parameter follows:
3118 % o device: the OpenCL device.
3120 % o value: determines if kernel profiling for the device should be enabled
3124 MagickExport void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3125 const MagickBooleanType value)
3127 if (device == (MagickCLDevice) NULL)
3129 device->profile_kernels=value;
3133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3137 % S e t O p e n C L E n a b l e d %
3141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3143 % SetOpenCLEnabled() can be used to enable or disable OpenCL acceleration.
3145 % The format of the SetOpenCLEnabled method is:
3147 % void SetOpenCLEnabled(MagickBooleanType)
3149 % A description of each parameter follows:
3151 % o value: specify true to enable OpenCL acceleration
3154 MagickExport MagickBooleanType SetOpenCLEnabled(const MagickBooleanType value)
3159 clEnv=GetCurrentOpenCLEnv();
3160 if (clEnv == (MagickCLEnv) NULL)
3161 return(MagickFalse);
3162 clEnv->enabled=value;
3163 return(clEnv->enabled);
3168 MagickExport double GetOpenCLDeviceBenchmarkScore(
3169 const MagickCLDevice magick_unused(device))
3171 magick_unreferenced(device);
3175 MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
3176 const MagickCLDevice magick_unused(device))
3178 magick_unreferenced(device);
3179 return(MagickFalse);
3182 MagickExport const char *GetOpenCLDeviceName(
3183 const MagickCLDevice magick_unused(device))
3185 magick_unreferenced(device);
3186 return((const char *) NULL);
3189 MagickExport MagickCLDevice *GetOpenCLDevices(size_t *length,
3190 ExceptionInfo *magick_unused(exception))
3192 magick_unreferenced(exception);
3193 if (length != (size_t *) NULL)
3195 return((MagickCLDevice *) NULL);
3198 MagickExport MagickCLDeviceType GetOpenCLDeviceType(
3199 const MagickCLDevice magick_unused(device))
3201 magick_unreferenced(device);
3202 return(UndefinedCLDeviceType);
3205 MagickExport const KernelProfileRecord *GetOpenCLKernelProfileRecords(
3206 const MagickCLDevice magick_unused(device),size_t *length)
3208 magick_unreferenced(device);
3209 if (length != (size_t *) NULL)
3211 return((const KernelProfileRecord *) NULL);
3214 MagickExport const char *GetOpenCLDeviceVersion(
3215 const MagickCLDevice magick_unused(device))
3217 magick_unreferenced(device);
3218 return((const char *) NULL);
3221 MagickExport MagickBooleanType GetOpenCLEnabled(void)
3223 return(MagickFalse);
3226 MagickExport void SetOpenCLDeviceEnabled(
3227 MagickCLDevice magick_unused(device),
3228 const MagickBooleanType magick_unused(value))
3230 magick_unreferenced(device);
3231 magick_unreferenced(value);
3234 MagickExport MagickBooleanType SetOpenCLEnabled(
3235 const MagickBooleanType magick_unused(value))
3237 magick_unreferenced(value);
3238 return(MagickFalse);
3241 MagickExport void SetOpenCLKernelProfileEnabled(
3242 MagickCLDevice magick_unused(device),
3243 const MagickBooleanType magick_unused(value))
3245 magick_unreferenced(device);
3246 magick_unreferenced(value);