43#include "MagickCore/studio.h"
44#include "MagickCore/accelerate-kernels-private.h"
45#include "MagickCore/artifact.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/cache-private.h"
48#include "MagickCore/color.h"
49#include "MagickCore/compare.h"
50#include "MagickCore/constitute.h"
51#include "MagickCore/configure.h"
52#include "MagickCore/distort.h"
53#include "MagickCore/draw.h"
54#include "MagickCore/effect.h"
55#include "MagickCore/exception.h"
56#include "MagickCore/exception-private.h"
57#include "MagickCore/fx.h"
58#include "MagickCore/gem.h"
59#include "MagickCore/geometry.h"
60#include "MagickCore/image.h"
61#include "MagickCore/image-private.h"
62#include "MagickCore/layer.h"
63#include "MagickCore/locale_.h"
64#include "MagickCore/mime-private.h"
65#include "MagickCore/memory_.h"
66#include "MagickCore/memory-private.h"
67#include "MagickCore/monitor.h"
68#include "MagickCore/montage.h"
69#include "MagickCore/morphology.h"
70#include "MagickCore/nt-base.h"
71#include "MagickCore/nt-base-private.h"
72#include "MagickCore/opencl.h"
73#include "MagickCore/opencl-private.h"
74#include "MagickCore/option.h"
75#include "MagickCore/policy.h"
76#include "MagickCore/property.h"
77#include "MagickCore/quantize.h"
78#include "MagickCore/quantum.h"
79#include "MagickCore/random_.h"
80#include "MagickCore/random-private.h"
81#include "MagickCore/resample.h"
82#include "MagickCore/resource_.h"
83#include "MagickCore/splay-tree.h"
84#include "MagickCore/semaphore.h"
85#include "MagickCore/statistic.h"
86#include "MagickCore/string_.h"
87#include "MagickCore/string-private.h"
88#include "MagickCore/token.h"
89#include "MagickCore/utility.h"
90#include "MagickCore/utility-private.h"
91#include "MagickCore/xml-tree-private.h"
93#if defined(MAGICKCORE_OPENCL_SUPPORT)
94#if defined(MAGICKCORE_LTDL_DELEGATE)
101#define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile.xml"
127} MagickCLDeviceBenchmark;
133static MagickBooleanType
135 LoadOpenCLLibrary(
void);
138 RelinquishMagickCLDevice(MagickCLDevice);
141 RelinquishMagickCLEnv(MagickCLEnv);
144 BenchmarkOpenCLDevices(MagickCLEnv);
162 *cache_directory_lock;
164static inline MagickBooleanType IsSameOpenCLDevice(MagickCLDevice a,
167 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
168 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
169 (LocaleCompare(a->name,b->name) == 0) &&
170 (LocaleCompare(a->version,b->version) == 0) &&
171 (a->max_clock_frequency == b->max_clock_frequency) &&
172 (a->max_compute_units == b->max_compute_units))
178static inline MagickBooleanType IsBenchmarkedOpenCLDevice(MagickCLDevice a,
179 MagickCLDeviceBenchmark *b)
181 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
182 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
183 (LocaleCompare(a->name,b->name) == 0) &&
184 (LocaleCompare(a->version,b->version) == 0) &&
185 (a->max_clock_frequency == b->max_clock_frequency) &&
186 (a->max_compute_units == b->max_compute_units))
192static inline void RelinquishMagickCLDevices(MagickCLEnv clEnv)
197 if (clEnv->devices != (MagickCLDevice *) NULL)
199 for (i = 0; i < clEnv->number_devices; i++)
200 clEnv->devices[i]=RelinquishMagickCLDevice(clEnv->devices[i]);
201 clEnv->devices=(MagickCLDevice *) RelinquishMagickMemory(clEnv->devices);
203 clEnv->number_devices=0;
206static inline MagickBooleanType MagickCreateDirectory(
const char *path)
211#ifdef MAGICKCORE_WINDOWS_SUPPORT
214 status=mkdir(path,0777);
216 return(status == 0 ? MagickTrue : MagickFalse);
219static inline void InitAccelerateTimer(AccelerateTimer *timer)
222 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->freq);
224 timer->freq=(
long long)1.0E3;
230static inline double ReadAccelerateTimer(AccelerateTimer *timer)
232 return (
double)timer->clocks/(double)timer->freq;
235static inline void StartAccelerateTimer(AccelerateTimer* timer)
238 QueryPerformanceCounter((LARGE_INTEGER*)&timer->start);
243 timer->start=(
long long)s.tv_sec*(
long long)1.0E3+(
long long)s.tv_usec/
248static inline void StopAccelerateTimer(AccelerateTimer *timer)
255 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
260 n=(
long long)s.tv_sec*(
long long)1.0E3+(
long long)s.tv_usec/
268static const char *GetOpenCLCacheDirectory()
270 if (cache_directory == (
char *) NULL)
273 ActivateSemaphoreInfo(&cache_directory_lock);
274 LockSemaphoreInfo(cache_directory_lock);
275 if (cache_directory == (
char *) NULL)
279 path[MagickPathExtent],
289 home=GetEnvironmentValue(
"MAGICK_OPENCL_CACHE_DIR");
290 if (home == (
char *) NULL)
292 home=GetEnvironmentValue(
"XDG_CACHE_HOME");
293#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
294 if (home == (
char *) NULL)
295 home=GetEnvironmentValue(
"LOCALAPPDATA");
296 if (home == (
char *) NULL)
297 home=GetEnvironmentValue(
"APPDATA");
298 if (home == (
char *) NULL)
299 home=GetEnvironmentValue(
"USERPROFILE");
303 if (home != (
char *) NULL)
306 (void) FormatLocaleString(path,MagickPathExtent,
"%s",home);
307 status=GetPathAttributes(path,&attributes);
308 if (status == MagickFalse)
309 status=MagickCreateDirectory(path);
312 if (status != MagickFalse)
314 (void) FormatLocaleString(path,MagickPathExtent,
315 "%s%sImageMagick",home,DirectorySeparator);
317 status=GetPathAttributes(path,&attributes);
318 if (status == MagickFalse)
319 status=MagickCreateDirectory(path);
322 if (status != MagickFalse)
324 temp=(
char*) AcquireCriticalMemory(strlen(path)+1);
325 CopyMagickString(temp,path,strlen(path)+1);
327 home=DestroyString(home);
331 home=GetEnvironmentValue(
"HOME");
332 if (home != (
char *) NULL)
335 (void) FormatLocaleString(path,MagickPathExtent,
"%s%s.cache",
336 home,DirectorySeparator);
337 status=GetPathAttributes(path,&attributes);
338 if (status == MagickFalse)
339 status=MagickCreateDirectory(path);
342 if (status != MagickFalse)
344 (void) FormatLocaleString(path,MagickPathExtent,
345 "%s%s.cache%sImageMagick",home,DirectorySeparator,
347 status=GetPathAttributes(path,&attributes);
348 if (status == MagickFalse)
349 status=MagickCreateDirectory(path);
352 if (status != MagickFalse)
354 temp=(
char*) AcquireCriticalMemory(strlen(path)+1);
355 CopyMagickString(temp,path,strlen(path)+1);
357 home=DestroyString(home);
360 if (temp == (
char *) NULL)
362 temp=AcquireString(
"?");
363 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
364 "Cannot use cache directory: \"%s\"",path);
367 (
void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
368 "Using cache directory: \"%s\"",temp);
369 cache_directory=temp;
371 UnlockSemaphoreInfo(cache_directory_lock);
373 if (*cache_directory ==
'?')
374 return((
const char *) NULL);
375 return(cache_directory);
378static void SelectOpenCLDevice(MagickCLEnv clEnv,cl_device_type type)
387 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
388 "Selecting device for type: %d",(int) type);
389 for (i = 0; i < clEnv->number_devices; i++)
390 clEnv->devices[i]->enabled=MagickFalse;
392 for (i = 0; i < clEnv->number_devices; i++)
394 device=clEnv->devices[i];
395 if (device->type != type)
398 device->enabled=MagickTrue;
399 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
400 "Selected device: %s",device->name);
401 for (j = i+1; j < clEnv->number_devices; j++)
406 other_device=clEnv->devices[j];
407 if (IsSameOpenCLDevice(device,other_device))
408 other_device->enabled=MagickTrue;
413static size_t StringSignature(
const char*
string)
428 stringLength=(size_t) strlen(
string);
429 signature=stringLength;
430 n=stringLength/
sizeof(size_t);
432 for (i = 0; i < n; i++)
434 if (n *
sizeof(
size_t) != stringLength)
440 for (i = 0; i < 4; i++, j++)
442 if (j < stringLength)
453static void DestroyMagickCLCacheInfo(MagickCLCacheInfo info)
458 for (i=0; i < (ssize_t) info->event_count; i++)
459 openCL_library->clReleaseEvent(info->events[i]);
460 info->events=(cl_event *) RelinquishMagickMemory(info->events);
461 if (info->buffer != (cl_mem) NULL)
462 openCL_library->clReleaseMemObject(info->buffer);
463 RelinquishSemaphoreInfo(&info->events_semaphore);
464 ReleaseOpenCLDevice(info->device);
465 RelinquishMagickMemory(info);
472MagickPrivate cl_mem CreateOpenCLBuffer(MagickCLDevice device,
473 cl_mem_flags flags,
size_t size,
void *host_ptr)
475 return(openCL_library->clCreateBuffer(device->context,flags,size,host_ptr,
479MagickPrivate
void ReleaseOpenCLKernel(cl_kernel kernel)
481 (void) openCL_library->clReleaseKernel(kernel);
484MagickPrivate
void ReleaseOpenCLMemObject(cl_mem memobj)
486 (void) openCL_library->clReleaseMemObject(memobj);
489MagickPrivate
void RetainOpenCLMemObject(cl_mem memobj)
491 (void) openCL_library->clRetainMemObject(memobj);
494MagickPrivate cl_int SetOpenCLKernelArg(cl_kernel kernel,
size_t arg_index,
495 size_t arg_size,
const void *arg_value)
497 return(openCL_library->clSetKernelArg(kernel,(cl_uint) arg_index,arg_size,
529MagickPrivate MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
530 Quantum *pixels,
const MagickSizeType length)
538 info=(MagickCLCacheInfo) AcquireCriticalMemory(
sizeof(*info));
539 (void) memset(info,0,
sizeof(*info));
540 LockSemaphoreInfo(openCL_lock);
542 UnlockSemaphoreInfo(openCL_lock);
546 info->events_semaphore=AcquireSemaphoreInfo();
547 info->buffer=openCL_library->clCreateBuffer(device->context,
548 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,(
size_t) length,(
void *) pixels,
550 if (status == CL_SUCCESS)
552 DestroyMagickCLCacheInfo(info);
553 return((MagickCLCacheInfo) NULL);
575static MagickCLDevice AcquireMagickCLDevice()
580 device=(MagickCLDevice) AcquireMagickMemory(
sizeof(*device));
583 (void) memset(device,0,
sizeof(*device));
584 ActivateSemaphoreInfo(&device->lock);
585 device->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
586 device->command_queues_index=-1;
587 device->enabled=MagickTrue;
607static MagickCLEnv AcquireMagickCLEnv(
void)
615 clEnv=(MagickCLEnv) AcquireMagickMemory(
sizeof(*clEnv));
616 if (clEnv != (MagickCLEnv) NULL)
618 (void) memset(clEnv,0,
sizeof(*clEnv));
619 ActivateSemaphoreInfo(&clEnv->lock);
620 clEnv->cpu_score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
621 clEnv->enabled=MagickFalse;
622 option=getenv(
"MAGICK_OCL_DEVICE");
623 if (option != (
const char *) NULL)
625 if ((IsStringTrue(option) != MagickFalse) ||
626 (strcmp(option,
"GPU") == 0) ||
627 (strcmp(option,
"CPU") == 0))
628 clEnv->enabled=MagickTrue;
657MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
662 cl_command_queue_properties
665 assert(device != (MagickCLDevice) NULL);
666 LockSemaphoreInfo(device->lock);
667 if ((device->profile_kernels == MagickFalse) &&
668 (device->command_queues_index >= 0))
670 queue=device->command_queues[device->command_queues_index--];
671 UnlockSemaphoreInfo(device->lock);
675 UnlockSemaphoreInfo(device->lock);
677 if (device->profile_kernels != MagickFalse)
678 properties=CL_QUEUE_PROFILING_ENABLE;
679 queue=openCL_library->clCreateCommandQueue(device->context,
680 device->deviceID,properties,(cl_int *) NULL);
713MagickPrivate cl_kernel AcquireOpenCLKernel(MagickCLDevice device,
714 const char *kernel_name)
719 assert(device != (MagickCLDevice) NULL);
720 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
"Using kernel: %s",
722 kernel=openCL_library->clCreateKernel(device->program,kernel_name,
753#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
754static MagickCLDeviceBenchmark* RelinquishDeviceBenchmark(
755 MagickCLDeviceBenchmark *device_benchmark)
757 if (device_benchmark == (MagickCLDeviceBenchmark*) NULL)
758 return((MagickCLDeviceBenchmark *) NULL);
760 device_benchmark->platform_name=(
char *) RelinquishMagickMemory(
761 device_benchmark->platform_name);
762 device_benchmark->vendor_name=(
char *) RelinquishMagickMemory(
763 device_benchmark->vendor_name);
764 device_benchmark->name=(
char *) RelinquishMagickMemory(
765 device_benchmark->name);
766 device_benchmark->version=(
char *) RelinquishMagickMemory(
767 device_benchmark->version);
768 return((MagickCLDeviceBenchmark *) RelinquishMagickMemory(
772static void LoadOpenCLDeviceBenchmark(MagickCLEnv clEnv,
const char *xml)
775 keyword[MagickPathExtent],
781 MagickCLDeviceBenchmark
788 if (xml == (
char *) NULL)
790 device_benchmark=(MagickCLDeviceBenchmark *) NULL;
791 token=AcquireString(xml);
792 extent=strlen(token)+MagickPathExtent;
793 for (q=(
char *) xml; *q !=
'\0'; )
798 if (SkipXMLComment(&q) == MagickFalse)
800 (void) GetNextToken(q,&q,extent,token);
803 (void) CopyMagickString(keyword,token,MagickPathExtent);
804 if (LocaleNCompare(keyword,
"<!DOCTYPE",9) == 0)
806 if (SkipXMLDocType(&q) == MagickFalse)
810 if (LocaleCompare(keyword,
"<device") == 0)
815 device_benchmark=(MagickCLDeviceBenchmark *) AcquireQuantumMemory(1,
816 sizeof(*device_benchmark));
817 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
819 (void) memset(device_benchmark,0,
sizeof(*device_benchmark));
820 device_benchmark->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
823 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
825 if (LocaleCompare(keyword,
"/>") == 0)
827 if (device_benchmark->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
829 if (LocaleCompare(device_benchmark->name,
"CPU") == 0)
830 clEnv->cpu_score=device_benchmark->score;
839 for (i = 0; i < clEnv->number_devices; i++)
841 device=clEnv->devices[i];
842 if (IsBenchmarkedOpenCLDevice(device,device_benchmark))
843 device->score=device_benchmark->score;
847 device_benchmark=RelinquishDeviceBenchmark(device_benchmark);
850 (void) GetNextToken(q,(
const char **) NULL,extent,token);
853 (void) GetNextToken(q,&q,extent,token);
854 (void) GetNextToken(q,&q,extent,token);
860 if (LocaleCompare((
char *) keyword,
"maxClockFrequency") == 0)
862 device_benchmark->max_clock_frequency=StringToInteger(token);
865 if (LocaleCompare((
char *) keyword,
"maxComputeUnits") == 0)
867 device_benchmark->max_compute_units=StringToInteger(token);
875 if (LocaleCompare((
char *) keyword,
"name") == 0)
876 device_benchmark->name=ConstantString(token);
882 if (LocaleCompare((
char *) keyword,
"platform") == 0)
883 device_benchmark->platform_name=ConstantString(token);
889 if (LocaleCompare((
char *) keyword,
"score") == 0)
890 device_benchmark->score=StringToDouble(token,(
char **) NULL);
896 if (LocaleCompare((
char *) keyword,
"vendor") == 0)
897 device_benchmark->vendor_name=ConstantString(token);
898 if (LocaleCompare((
char *) keyword,
"version") == 0)
899 device_benchmark->version=ConstantString(token);
906 token=(
char *) RelinquishMagickMemory(token);
907 device_benchmark=RelinquishDeviceBenchmark(device_benchmark);
910static MagickBooleanType CanWriteProfileToFile(
const char *filename)
915 profileFile=fopen(filename,
"ab");
917 if (profileFile == (FILE *) NULL)
919 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
920 "Unable to save profile to: \"%s\"",filename);
929static MagickBooleanType LoadOpenCLBenchmarks(MagickCLEnv clEnv)
931#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
933 filename[MagickPathExtent];
938 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
939 GetOpenCLCacheDirectory(),DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
945 if (CanWriteProfileToFile(filename) == MagickFalse)
951 for (i = 0; i < clEnv->number_devices; i++)
952 clEnv->devices[i]->score=1.0;
954 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
957#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
958 option=ConfigureFileToStringInfo(filename);
959 LoadOpenCLDeviceBenchmark(clEnv,(
const char *) GetStringInfoDatum(option));
960 option=DestroyStringInfo(option);
965static void AutoSelectOpenCLDevices(MagickCLEnv clEnv)
979 option=getenv(
"MAGICK_OCL_DEVICE");
980 if (option != (
const char *) NULL)
982 if (strcmp(option,
"GPU") == 0)
983 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
984 else if (strcmp(option,
"CPU") == 0)
985 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_CPU);
988 if (LoadOpenCLBenchmarks(clEnv) == MagickFalse)
991 benchmark=MagickFalse;
992 if (clEnv->cpu_score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
993 benchmark=MagickTrue;
996 for (i = 0; i < clEnv->number_devices; i++)
998 if (clEnv->devices[i]->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1000 benchmark=MagickTrue;
1006 if (benchmark != MagickFalse)
1007 BenchmarkOpenCLDevices(clEnv);
1009 best_score=clEnv->cpu_score;
1010 for (i = 0; i < clEnv->number_devices; i++)
1011 best_score=MagickMin(clEnv->devices[i]->score,best_score);
1013 for (i = 0; i < clEnv->number_devices; i++)
1015 if (clEnv->devices[i]->score != best_score)
1016 clEnv->devices[i]->enabled=MagickFalse;
1045static double RunOpenCLBenchmark(MagickBooleanType is_cpu)
1062 exception=AcquireExceptionInfo();
1063 imageInfo=AcquireImageInfo();
1064 CloneString(&imageInfo->size,
"2048x1536");
1065 CopyMagickString(imageInfo->filename,
"xc:none",MagickPathExtent);
1066 inputImage=ReadImage(imageInfo,exception);
1067 if (inputImage == (
Image *) NULL)
1070 InitAccelerateTimer(&timer);
1072 for (i=0; i<=2; i++)
1080 StartAccelerateTimer(&timer);
1082 blurredImage=BlurImage(inputImage,10.0f,3.5f,exception);
1083 unsharpedImage=UnsharpMaskImage(blurredImage,2.0f,2.0f,50.0f,10.0f,
1085 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
1092 if (is_cpu == MagickFalse)
1097 cache_info=(
CacheInfo *) resizedImage->cache;
1098 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1099 openCL_library->clWaitForEvents(cache_info->opencl->event_count,
1100 cache_info->opencl->events);
1104 StopAccelerateTimer(&timer);
1106 if (blurredImage != (
Image *) NULL)
1107 DestroyImage(blurredImage);
1108 if (unsharpedImage != (
Image *) NULL)
1109 DestroyImage(unsharpedImage);
1110 if (resizedImage != (
Image *) NULL)
1111 DestroyImage(resizedImage);
1113 DestroyImage(inputImage);
1114 return(ReadAccelerateTimer(&timer));
1117static void RunDeviceBenchmark(MagickCLEnv clEnv,MagickCLEnv testEnv,
1118 MagickCLDevice device)
1120 testEnv->devices[0]=device;
1121 default_CLEnv=testEnv;
1122 device->score=RunOpenCLBenchmark(MagickFalse);
1123 default_CLEnv=clEnv;
1124 testEnv->devices[0]=(MagickCLDevice) NULL;
1127static void CacheOpenCLBenchmarks(MagickCLEnv clEnv)
1130 filename[MagickPathExtent];
1142 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1143 GetOpenCLCacheDirectory(),DirectorySeparator,
1144 IMAGEMAGICK_PROFILE_FILE);
1146 cache_file=fopen_utf8(filename,
"wb");
1147 if (cache_file == (FILE *) NULL)
1149 fwrite(
"<devices>\n",
sizeof(
char),10,cache_file);
1150 fprintf(cache_file,
" <device name=\"CPU\" score=\"%.4g\"/>\n",
1152 for (i = 0; i < clEnv->number_devices; i++)
1157 device=clEnv->devices[i];
1158 duplicate=MagickFalse;
1159 for (j = 0; j < i; j++)
1161 if (IsSameOpenCLDevice(clEnv->devices[j],device))
1163 duplicate=MagickTrue;
1171 if (device->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1172 fprintf(cache_file,
" <device platform=\"%s\" vendor=\"%s\" name=\"%s\"\
1173 version=\"%s\" maxClockFrequency=\"%d\" maxComputeUnits=\"%d\"\
1174 score=\"%.4g\"/>\n",
1175 device->platform_name,device->vendor_name,device->name,device->version,
1176 (
int)device->max_clock_frequency,(
int)device->max_compute_units,
1179 fwrite(
"</devices>",
sizeof(
char),10,cache_file);
1184static void BenchmarkOpenCLDevices(MagickCLEnv clEnv)
1196 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1197 "Starting benchmark");
1198 testEnv=AcquireMagickCLEnv();
1199 testEnv->library=openCL_library;
1200 testEnv->devices=(MagickCLDevice *) AcquireCriticalMemory(
1201 sizeof(MagickCLDevice));
1202 testEnv->number_devices=1;
1203 testEnv->benchmark_thread_id=GetMagickThreadId();
1204 testEnv->initialized=MagickTrue;
1206 for (i = 0; i < clEnv->number_devices; i++)
1207 clEnv->devices[i]->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
1209 for (i = 0; i < clEnv->number_devices; i++)
1211 device=clEnv->devices[i];
1212 if (device->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1213 RunDeviceBenchmark(clEnv,testEnv,device);
1216 for (j = i+1; j < clEnv->number_devices; j++)
1221 other_device=clEnv->devices[j];
1222 if (IsSameOpenCLDevice(device,other_device))
1223 other_device->score=device->score;
1227 testEnv->enabled=MagickFalse;
1228 default_CLEnv=testEnv;
1229 clEnv->cpu_score=RunOpenCLBenchmark(MagickTrue);
1230 default_CLEnv=clEnv;
1232 testEnv=RelinquishMagickCLEnv(testEnv);
1233 CacheOpenCLBenchmarks(clEnv);
1270static void CacheOpenCLKernel(MagickCLDevice device,
char *filename,
1282 status=openCL_library->clGetProgramInfo(device->program,
1283 CL_PROGRAM_BINARY_SIZES,
sizeof(
size_t),&binaryProgramSize,NULL);
1284 if (status != CL_SUCCESS)
1286 binaryProgram=(
unsigned char*) AcquireQuantumMemory(1,binaryProgramSize);
1287 if (binaryProgram == (
unsigned char *) NULL)
1289 (void) ThrowMagickException(exception,GetMagickModule(),
1290 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",filename);
1293 status=openCL_library->clGetProgramInfo(device->program,
1294 CL_PROGRAM_BINARIES,
sizeof(
unsigned char*),&binaryProgram,NULL);
1295 if (status == CL_SUCCESS)
1297 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1298 "Creating cache file: \"%s\"",filename);
1299 (void) BlobToFile(filename,binaryProgram,binaryProgramSize,exception);
1301 binaryProgram=(
unsigned char *) RelinquishMagickMemory(binaryProgram);
1304static MagickBooleanType LoadCachedOpenCLKernels(MagickCLDevice device,
1305 const char *filename)
1320 sans_exception=AcquireExceptionInfo();
1321 binaryProgram=(
unsigned char *) FileToBlob(filename,SIZE_MAX,&length,
1323 sans_exception=DestroyExceptionInfo(sans_exception);
1324 if (binaryProgram == (
unsigned char *) NULL)
1325 return(MagickFalse);
1326 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1327 "Loaded cached kernels: \"%s\"",filename);
1328 device->program=openCL_library->clCreateProgramWithBinary(device->context,1,
1329 &device->deviceID,&length,(
const unsigned char**)&binaryProgram,
1330 &binaryStatus,&status);
1331 binaryProgram=(
unsigned char *) RelinquishMagickMemory(binaryProgram);
1332 return((status != CL_SUCCESS) || (binaryStatus != CL_SUCCESS) ? MagickFalse :
1336static void LogOpenCLBuildFailure(MagickCLDevice device,
const char *kernel,
1340 filename[MagickPathExtent],
1346 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1347 GetOpenCLCacheDirectory(),DirectorySeparator,
"magick_badcl.cl");
1349 (void) remove_utf8(filename);
1350 (void) BlobToFile(filename,kernel,strlen(kernel),exception);
1352 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1353 CL_PROGRAM_BUILD_LOG,0,NULL,&log_size);
1354 log=(
char*)AcquireCriticalMemory(log_size);
1355 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1356 CL_PROGRAM_BUILD_LOG,log_size,log,&log_size);
1358 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1359 GetOpenCLCacheDirectory(),DirectorySeparator,
"magick_badcl.log");
1361 (void) remove_utf8(filename);
1362 (void) BlobToFile(filename,log,log_size,exception);
1363 log=(
char*)RelinquishMagickMemory(log);
1366static MagickBooleanType CompileOpenCLKernel(MagickCLDevice device,
1367 const char *kernel,
const char *options,
size_t signature,
1371 deviceName[MagickPathExtent],
1372 filename[MagickPathExtent],
1384 (void) CopyMagickString(deviceName,device->name,MagickPathExtent);
1387 while (*ptr !=
'\0')
1389 if ((*ptr ==
' ') || (*ptr ==
'\\') || (*ptr ==
'/') || (*ptr ==
':') ||
1390 (*ptr ==
'*') || (*ptr ==
'?') || (*ptr ==
'"') || (*ptr ==
'<') ||
1391 (*ptr ==
'>' || *ptr ==
'|'))
1395 (void) FormatLocaleString(filename,MagickPathExtent,
1396 "%s%s%s_%s_%08x_%.20g.bin",GetOpenCLCacheDirectory(),
1397 DirectorySeparator,
"magick_opencl",deviceName,(
unsigned int) signature,
1398 (
double)
sizeof(
char*)*8);
1399 loaded=LoadCachedOpenCLKernels(device,filename);
1400 if (loaded == MagickFalse)
1403 length=strlen(kernel);
1404 device->program=openCL_library->clCreateProgramWithSource(
1405 device->context,1,&kernel,&length,&status);
1406 if (status != CL_SUCCESS)
1407 return(MagickFalse);
1410 status=openCL_library->clBuildProgram(device->program,1,&device->deviceID,
1412 if (status != CL_SUCCESS)
1414 (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
1415 "clBuildProgram failed.",
"(%d)",(int)status);
1416 LogOpenCLBuildFailure(device,kernel,exception);
1417 return(MagickFalse);
1421 if (loaded == MagickFalse)
1422 CacheOpenCLKernel(device,filename,exception);
1427static cl_event* CopyOpenCLEvents(MagickCLCacheInfo first,
1428 MagickCLCacheInfo second,cl_uint *event_count)
1439 assert(first != (MagickCLCacheInfo) NULL);
1440 assert(event_count != (cl_uint *) NULL);
1441 events=(cl_event *) NULL;
1442 LockSemaphoreInfo(first->events_semaphore);
1443 if (second != (MagickCLCacheInfo) NULL)
1444 LockSemaphoreInfo(second->events_semaphore);
1445 *event_count=first->event_count;
1446 if (second != (MagickCLCacheInfo) NULL)
1447 *event_count+=second->event_count;
1448 if (*event_count > 0)
1450 events=(cl_event *) AcquireQuantumMemory(*event_count,
sizeof(*events));
1451 if (events == (cl_event *) NULL)
1456 for (i=0; i < first->event_count; i++, j++)
1457 events[j]=first->events[i];
1458 if (second != (MagickCLCacheInfo) NULL)
1460 for (i=0; i < second->event_count; i++, j++)
1461 events[j]=second->events[i];
1465 UnlockSemaphoreInfo(first->events_semaphore);
1466 if (second != (MagickCLCacheInfo) NULL)
1467 UnlockSemaphoreInfo(second->events_semaphore);
1493MagickPrivate MagickCLCacheInfo CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1507 if (info == (MagickCLCacheInfo) NULL)
1508 return((MagickCLCacheInfo) NULL);
1509 events=CopyOpenCLEvents(info,(MagickCLCacheInfo) NULL,&event_count);
1510 if (events != (cl_event *) NULL)
1512 queue=AcquireOpenCLCommandQueue(info->device);
1513 pixels=(Quantum *) openCL_library->clEnqueueMapBuffer(queue,info->buffer,
1514 CL_TRUE,CL_MAP_READ | CL_MAP_WRITE,0,info->length,event_count,events,
1515 (cl_event *) NULL,(cl_int *) NULL);
1516 assert(pixels == info->pixels);
1517 ReleaseOpenCLCommandQueue(info->device,queue);
1518 events=(cl_event *) RelinquishMagickMemory(events);
1520 return(RelinquishMagickCLCacheInfo(info,MagickFalse));
1542MagickPrivate
void DumpOpenCLProfileData()
1544#define OpenCLLog(message) \
1545 fwrite(message,sizeof(char),strlen(message),log); \
1546 fwrite("\n",sizeof(char),1,log);
1550 filename[MagickPathExtent],
1560 if (default_CLEnv == (MagickCLEnv) NULL)
1563 for (i = 0; i < default_CLEnv->number_devices; i++)
1564 if (default_CLEnv->devices[i]->profile_kernels != MagickFalse)
1566 if (i == default_CLEnv->number_devices)
1569 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1570 GetOpenCLCacheDirectory(),DirectorySeparator,
"ImageMagickOpenCL.log");
1572 log=fopen_utf8(filename,
"wb");
1573 if (log == (FILE *) NULL)
1575 for (i = 0; i < default_CLEnv->number_devices; i++)
1580 device=default_CLEnv->devices[i];
1581 if ((device->profile_kernels == MagickFalse) ||
1585 OpenCLLog(
"====================================================");
1586 fprintf(log,
"Device: %s\n",device->name);
1587 fprintf(log,
"Version: %s\n",device->version);
1588 OpenCLLog(
"====================================================");
1589 OpenCLLog(
" average calls min max");
1590 OpenCLLog(
" ------- ----- --- ---");
1597 profile=device->profile_records[j];
1598 (void) CopyMagickString(indent,
" ",
1600 CopyMagickString(indent,profile->kernel_name,MagickMin(strlen(
1601 profile->kernel_name),strlen(indent)));
1602 (void) FormatLocaleString(buf,
sizeof(buf),
"%s %7d %7d %7d %7d",indent,
1603 (int) (profile->total/profile->count),(int) profile->count,
1604 (
int) profile->min,(int) profile->max);
1608 OpenCLLog(
"====================================================");
1609 fwrite(
"\n\n",
sizeof(
char),2,log);
1661static MagickBooleanType RegisterCacheEvent(MagickCLCacheInfo info,
1664 assert(info != (MagickCLCacheInfo) NULL);
1665 assert(event != (cl_event) NULL);
1666 if (openCL_library->clRetainEvent(event) != CL_SUCCESS)
1668 openCL_library->clWaitForEvents(1,&event);
1669 return(MagickFalse);
1671 LockSemaphoreInfo(info->events_semaphore);
1672 if (info->events == (cl_event *) NULL)
1674 info->events=(cl_event *) AcquireMagickMemory(
sizeof(*info->events));
1675 info->event_count=1;
1678 info->events=(cl_event *) ResizeQuantumMemory(info->events,
1679 ++info->event_count,
sizeof(*info->events));
1680 if (info->events == (cl_event *) NULL)
1682 UnlockSemaphoreInfo(info->events_semaphore);
1683 return(MagickFalse);
1685 info->events[info->event_count-1]=event;
1686 UnlockSemaphoreInfo(info->events_semaphore);
1690MagickPrivate MagickBooleanType EnqueueOpenCLKernel(cl_command_queue queue,
1691 cl_kernel kernel,cl_uint work_dim,
const size_t *offset,
const size_t *gsize,
1692 const size_t *lsize,
const Image *input_image,
const Image *output_image,
1709 assert(input_image != (
const Image *) NULL);
1710 input_info=(
CacheInfo *) input_image->cache;
1711 assert(input_info != (
CacheInfo *) NULL);
1712 assert(input_info->opencl != (MagickCLCacheInfo) NULL);
1714 if (output_image == (
const Image *) NULL)
1715 events=CopyOpenCLEvents(input_info->opencl,(MagickCLCacheInfo) NULL,
1719 output_info=(
CacheInfo *) output_image->cache;
1720 assert(output_info != (
CacheInfo *) NULL);
1721 assert(output_info->opencl != (MagickCLCacheInfo) NULL);
1722 events=CopyOpenCLEvents(input_info->opencl,output_info->opencl,
1725 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,offset,
1726 gsize,lsize,event_count,events,&event);
1728 if ((status != CL_SUCCESS) && (event_count > 0))
1730 openCL_library->clFinish(queue);
1731 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,
1732 offset,gsize,lsize,event_count,events,&event);
1734 events=(cl_event *) RelinquishMagickMemory(events);
1735 if (status != CL_SUCCESS)
1737 (void) OpenCLThrowMagickException(input_info->opencl->device,exception,
1738 GetMagickModule(),ResourceLimitWarning,
1739 "clEnqueueNDRangeKernel failed.",
"'%s'",
".");
1740 return(MagickFalse);
1742 if (flush != MagickFalse)
1743 openCL_library->clFlush(queue);
1744 if (RecordProfileData(input_info->opencl->device,kernel,event) == MagickFalse)
1746 if (RegisterCacheEvent(input_info->opencl,event) != MagickFalse)
1749 (
void) RegisterCacheEvent(output_info->opencl,event);
1752 openCL_library->clReleaseEvent(event);
1775MagickPrivate MagickCLEnv GetCurrentOpenCLEnv(
void)
1777 if (default_CLEnv != (MagickCLEnv) NULL)
1779 if ((default_CLEnv->benchmark_thread_id != (MagickThreadType) 0) &&
1780 (default_CLEnv->benchmark_thread_id != GetMagickThreadId()))
1781 return((MagickCLEnv) NULL);
1783 return(default_CLEnv);
1786 if (GetOpenCLCacheDirectory() == (
char *) NULL)
1787 return((MagickCLEnv) NULL);
1790 ActivateSemaphoreInfo(&openCL_lock);
1792 LockSemaphoreInfo(openCL_lock);
1793 if (default_CLEnv == (MagickCLEnv) NULL)
1794 default_CLEnv=AcquireMagickCLEnv();
1795 UnlockSemaphoreInfo(openCL_lock);
1797 return(default_CLEnv);
1824MagickExport
double GetOpenCLDeviceBenchmarkScore(
1825 const MagickCLDevice device)
1827 if (device == (MagickCLDevice) NULL)
1828 return(MAGICKCORE_OPENCL_UNDEFINED_SCORE);
1829 return(device->score);
1854MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
1855 const MagickCLDevice device)
1857 if (device == (MagickCLDevice) NULL)
1858 return(MagickFalse);
1859 return(device->enabled);
1884MagickExport
const char *GetOpenCLDeviceName(
const MagickCLDevice device)
1886 if (device == (MagickCLDevice) NULL)
1887 return((
const char *) NULL);
1888 return(device->name);
1913MagickExport
const char *GetOpenCLDeviceVendorName(
const MagickCLDevice device)
1915 if (device == (MagickCLDevice) NULL)
1916 return((
const char *) NULL);
1917 return(device->vendor_name);
1947MagickExport MagickCLDevice *GetOpenCLDevices(
size_t *length,
1953 clEnv=GetCurrentOpenCLEnv();
1954 if (clEnv == (MagickCLEnv) NULL)
1956 if (length != (
size_t *) NULL)
1958 return((MagickCLDevice *) NULL);
1960 InitializeOpenCL(clEnv,exception);
1961 if (length != (
size_t *) NULL)
1962 *length=clEnv->number_devices;
1963 return(clEnv->devices);
1988MagickExport MagickCLDeviceType GetOpenCLDeviceType(
1989 const MagickCLDevice device)
1991 if (device == (MagickCLDevice) NULL)
1992 return(UndefinedCLDeviceType);
1993 if (device->type == CL_DEVICE_TYPE_GPU)
1994 return(GpuCLDeviceType);
1995 if (device->type == CL_DEVICE_TYPE_CPU)
1996 return(CpuCLDeviceType);
1997 return(UndefinedCLDeviceType);
2022MagickExport
const char *GetOpenCLDeviceVersion(
const MagickCLDevice device)
2024 if (device == (MagickCLDevice) NULL)
2025 return((
const char *) NULL);
2026 return(device->version);
2048MagickExport MagickBooleanType GetOpenCLEnabled(
void)
2053 clEnv=GetCurrentOpenCLEnv();
2054 if (clEnv == (MagickCLEnv) NULL)
2055 return(MagickFalse);
2056 return(clEnv->enabled);
2083 const MagickCLDevice device,
size_t *length)
2085 if ((device == (
const MagickCLDevice) NULL) || (device->profile_records ==
2088 if (length != (
size_t *) NULL)
2092 if (length != (
size_t *) NULL)
2095 LockSemaphoreInfo(device->lock);
2098 UnlockSemaphoreInfo(device->lock);
2100 return(device->profile_records);
2131static MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2135 *accelerateKernelsBuffer,
2136 options[MagickPathExtent];
2148 for (i = 0; i < clEnv->number_devices; i++)
2150 if ((clEnv->devices[i]->enabled != MagickFalse))
2153 if (i == clEnv->number_devices)
2154 return(MagickFalse);
2158 for (i = 0; i < clEnv->number_devices; i++)
2160 if ((clEnv->devices[i]->enabled != MagickFalse) &&
2161 (clEnv->devices[i]->program == (cl_program) NULL))
2167 if (status != MagickFalse)
2171 (void) FormatLocaleString(options,MagickPathExtent,CLOptions,
2172 (
float)QuantumRange,(float)QuantumScale,(
float)CLCharQuantumScale,
2173 (float)MagickEpsilon,(
float)MagickPI,(
unsigned int)MaxMap,
2174 (
unsigned int)MAGICKCORE_QUANTUM_DEPTH);
2176 signature=StringSignature(options);
2177 accelerateKernelsBuffer=(
char*) AcquireQuantumMemory(1,
2178 strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
2179 if (accelerateKernelsBuffer == (
char*) NULL)
2180 return(MagickFalse);
2181 (void) FormatLocaleString(accelerateKernelsBuffer,strlen(accelerateKernels)+
2182 strlen(accelerateKernels2)+1,
"%s%s",accelerateKernels,accelerateKernels2);
2183 signature^=StringSignature(accelerateKernelsBuffer);
2186 for (i = 0; i < clEnv->number_devices; i++)
2194 device=clEnv->devices[i];
2195 if ((device->enabled == MagickFalse) ||
2196 (device->program != (cl_program) NULL))
2199 LockSemaphoreInfo(device->lock);
2200 if (device->program != (cl_program) NULL)
2202 UnlockSemaphoreInfo(device->lock);
2205 device_signature=signature;
2206 device_signature^=StringSignature(device->platform_name);
2207 status=CompileOpenCLKernel(device,accelerateKernelsBuffer,options,
2208 device_signature,exception);
2209 UnlockSemaphoreInfo(device->lock);
2210 if (status == MagickFalse)
2213 accelerateKernelsBuffer=(
char *) RelinquishMagickMemory(
2214 accelerateKernelsBuffer);
2242static cl_uint GetOpenCLDeviceCount(MagickCLEnv clEnv,cl_platform_id platform)
2245 version[MagickPathExtent];
2250 if (clEnv->library->clGetPlatformInfo(platform,CL_PLATFORM_VERSION,
2251 MagickPathExtent,version,NULL) != CL_SUCCESS)
2253 if (strncmp(version,
"OpenCL 1.0 ",11) == 0)
2255 if (clEnv->library->clGetDeviceIDs(platform,
2256 CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU,0,NULL,&num) != CL_SUCCESS)
2261static inline char *GetOpenCLPlatformString(cl_platform_id platform,
2262 cl_platform_info param_name)
2270 openCL_library->clGetPlatformInfo(platform,param_name,0,NULL,&length);
2271 value=(
char *) AcquireCriticalMemory(length*
sizeof(*value));
2272 openCL_library->clGetPlatformInfo(platform,param_name,length,value,NULL);
2276static inline char *GetOpenCLDeviceString(cl_device_id device,
2277 cl_device_info param_name)
2285 openCL_library->clGetDeviceInfo(device,param_name,0,NULL,&length);
2286 value=(
char *) AcquireCriticalMemory(length*
sizeof(*value));
2287 openCL_library->clGetDeviceInfo(device,param_name,length,value,NULL);
2291static void LoadOpenCLDevices(MagickCLEnv clEnv)
2293 cl_context_properties
2313 if (openCL_library->clGetPlatformIDs(0,NULL,&number_platforms) != CL_SUCCESS)
2315 if (number_platforms == 0)
2317 platforms=(cl_platform_id *) AcquireQuantumMemory(1,number_platforms*
2318 sizeof(cl_platform_id));
2319 if (platforms == (cl_platform_id *) NULL)
2321 if (openCL_library->clGetPlatformIDs(number_platforms,platforms,NULL) != CL_SUCCESS)
2323 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2326 for (i = 0; i < number_platforms; i++)
2328 number_devices=GetOpenCLDeviceCount(clEnv,platforms[i]);
2329 if (number_devices == 0)
2330 platforms[i]=(cl_platform_id) NULL;
2332 clEnv->number_devices+=number_devices;
2334 if (clEnv->number_devices == 0)
2336 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2339 clEnv->devices=(MagickCLDevice *) AcquireQuantumMemory(clEnv->number_devices,
2340 sizeof(MagickCLDevice));
2341 if (clEnv->devices == (MagickCLDevice *) NULL)
2343 RelinquishMagickCLDevices(clEnv);
2344 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2347 (void) memset(clEnv->devices,0,clEnv->number_devices*
sizeof(MagickCLDevice));
2348 devices=(cl_device_id *) AcquireQuantumMemory(clEnv->number_devices,
2349 sizeof(cl_device_id));
2350 if (devices == (cl_device_id *) NULL)
2352 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2353 RelinquishMagickCLDevices(clEnv);
2356 (void) memset(devices,0,clEnv->number_devices*
sizeof(cl_device_id));
2357 clEnv->number_contexts=(size_t) number_platforms;
2358 clEnv->contexts=(cl_context *) AcquireQuantumMemory(clEnv->number_contexts,
2359 sizeof(cl_context));
2360 if (clEnv->contexts == (cl_context *) NULL)
2362 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2363 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2364 RelinquishMagickCLDevices(clEnv);
2367 (void) memset(clEnv->contexts,0,clEnv->number_contexts*
sizeof(cl_context));
2369 for (i = 0; i < number_platforms; i++)
2371 if (platforms[i] == (cl_platform_id) NULL)
2374 status=clEnv->library->clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_CPU |
2375 CL_DEVICE_TYPE_GPU,(cl_uint) clEnv->number_devices,devices,&number_devices);
2376 if (status != CL_SUCCESS)
2379 properties[0]=CL_CONTEXT_PLATFORM;
2380 properties[1]=(cl_context_properties) platforms[i];
2382 clEnv->contexts[i]=openCL_library->clCreateContext(properties,number_devices,
2383 devices,NULL,NULL,&status);
2384 if (status != CL_SUCCESS)
2387 for (j = 0; j < number_devices; j++,next++)
2392 device=AcquireMagickCLDevice();
2393 if (device == (MagickCLDevice) NULL)
2396 device->context=clEnv->contexts[i];
2397 device->deviceID=devices[j];
2399 device->platform_name=GetOpenCLPlatformString(platforms[i],
2402 device->vendor_name=GetOpenCLPlatformString(platforms[i],
2403 CL_PLATFORM_VENDOR);
2405 device->name=GetOpenCLDeviceString(devices[j],CL_DEVICE_NAME);
2407 device->version=GetOpenCLDeviceString(devices[j],CL_DRIVER_VERSION);
2409 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_CLOCK_FREQUENCY,
2410 sizeof(cl_uint),&device->max_clock_frequency,NULL);
2412 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,
2413 sizeof(cl_uint),&device->max_compute_units,NULL);
2415 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_TYPE,
2416 sizeof(cl_device_type),&device->type,NULL);
2418 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_LOCAL_MEM_SIZE,
2419 sizeof(cl_ulong),&device->local_memory_size,NULL);
2421 clEnv->devices[next]=device;
2422 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
2423 "Found device: %s (%s)",device->name,device->platform_name);
2426 if (next != clEnv->number_devices)
2427 RelinquishMagickCLDevices(clEnv);
2428 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2429 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2432MagickPrivate MagickBooleanType InitializeOpenCL(MagickCLEnv clEnv,
2435 LockSemaphoreInfo(clEnv->lock);
2436 if (clEnv->initialized != MagickFalse)
2438 UnlockSemaphoreInfo(clEnv->lock);
2439 return(HasOpenCLDevices(clEnv,exception));
2441 if (LoadOpenCLLibrary() != MagickFalse)
2443 clEnv->library=openCL_library;
2444 LoadOpenCLDevices(clEnv);
2445 if (clEnv->number_devices > 0)
2446 AutoSelectOpenCLDevices(clEnv);
2448 clEnv->initialized=MagickTrue;
2449 UnlockSemaphoreInfo(clEnv->lock);
2450 return(HasOpenCLDevices(clEnv,exception));
2472void *OsLibraryGetFunctionAddress(
void *library,
const char *functionName)
2474 if ((library == (
void *) NULL) || (functionName == (
const char *) NULL))
2475 return (
void *) NULL;
2476 return lt_dlsym(library,functionName);
2479static MagickBooleanType BindOpenCLFunctions()
2481#ifdef MAGICKCORE_HAVE_OPENCL_CL_H
2482#define BIND(X) openCL_library->X= &X;
2484 (void) memset(openCL_library,0,
sizeof(MagickLibrary));
2485#ifdef MAGICKCORE_WINDOWS_SUPPORT
2486 openCL_library->library=(
void *)lt_dlopen(
"OpenCL.dll");
2488 openCL_library->library=(
void *)lt_dlopen(
"libOpenCL.so");
2491 if ((openCL_library->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(openCL_library->library,#X)) == NULL) \
2492 return(MagickFalse);
2495 if (openCL_library->library == (
void*) NULL)
2496 return(MagickFalse);
2498 BIND(clGetPlatformIDs);
2499 BIND(clGetPlatformInfo);
2501 BIND(clGetDeviceIDs);
2502 BIND(clGetDeviceInfo);
2504 BIND(clCreateBuffer);
2505 BIND(clReleaseMemObject);
2506 BIND(clRetainMemObject);
2508 BIND(clCreateContext);
2509 BIND(clReleaseContext);
2511 BIND(clCreateCommandQueue);
2512 BIND(clReleaseCommandQueue);
2516 BIND(clCreateProgramWithSource);
2517 BIND(clCreateProgramWithBinary);
2518 BIND(clReleaseProgram);
2519 BIND(clBuildProgram);
2520 BIND(clGetProgramBuildInfo);
2521 BIND(clGetProgramInfo);
2523 BIND(clCreateKernel);
2524 BIND(clReleaseKernel);
2525 BIND(clSetKernelArg);
2526 BIND(clGetKernelInfo);
2528 BIND(clEnqueueReadBuffer);
2529 BIND(clEnqueueMapBuffer);
2530 BIND(clEnqueueUnmapMemObject);
2531 BIND(clEnqueueNDRangeKernel);
2533 BIND(clGetEventInfo);
2534 BIND(clWaitForEvents);
2535 BIND(clReleaseEvent);
2536 BIND(clRetainEvent);
2537 BIND(clSetEventCallback);
2539 BIND(clGetEventProfilingInfo);
2544static MagickBooleanType LoadOpenCLLibrary(
void)
2546 openCL_library=(MagickLibrary *) AcquireMagickMemory(
sizeof(MagickLibrary));
2547 if (openCL_library == (MagickLibrary *) NULL)
2548 return(MagickFalse);
2550 if (BindOpenCLFunctions() == MagickFalse)
2552 openCL_library=(MagickLibrary *)RelinquishMagickMemory(openCL_library);
2553 return(MagickFalse);
2578MagickPrivate
void OpenCLTerminus()
2580 DumpOpenCLProfileData();
2581 if (cache_directory != (
char *) NULL)
2582 cache_directory=DestroyString(cache_directory);
2584 RelinquishSemaphoreInfo(&cache_directory_lock);
2585 if (default_CLEnv != (MagickCLEnv) NULL)
2586 default_CLEnv=RelinquishMagickCLEnv(default_CLEnv);
2588 RelinquishSemaphoreInfo(&openCL_lock);
2589 if (openCL_library != (MagickLibrary *) NULL)
2591 if (openCL_library->library != (
void *) NULL)
2592 (void) lt_dlclose(openCL_library->library);
2593 openCL_library=(MagickLibrary *) RelinquishMagickMemory(openCL_library);
2636MagickPrivate MagickBooleanType OpenCLThrowMagickException(
2637 MagickCLDevice device,
ExceptionInfo *exception,
const char *module,
2638 const char *function,
const size_t line,
const ExceptionType severity,
2639 const char *tag,
const char *format,...)
2644 assert(device != (MagickCLDevice) NULL);
2646 assert(exception->signature == MagickCoreSignature);
2651 if (device->type == CL_DEVICE_TYPE_CPU)
2655 if (strncmp(device->platform_name,
"Intel",5) == 0)
2656 default_CLEnv->enabled=MagickFalse;
2660#ifdef OPENCLLOG_ENABLED
2664 va_start(operands,format);
2665 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
2670 magick_unreferenced(module);
2671 magick_unreferenced(function);
2672 magick_unreferenced(line);
2673 magick_unreferenced(tag);
2674 magick_unreferenced(format);
2706MagickPrivate MagickBooleanType RecordProfileData(MagickCLDevice device,
2707 cl_kernel kernel,cl_event event)
2727 if (device->profile_kernels == MagickFalse)
2728 return(MagickFalse);
2729 status=openCL_library->clWaitForEvents(1,&event);
2730 if (status != CL_SUCCESS)
2731 return(MagickFalse);
2732 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,0,NULL,
2734 if (status != CL_SUCCESS)
2736 name=(
char *) AcquireQuantumMemory(length,
sizeof(*name));
2737 if (name == (
char *) NULL)
2739 start=end=elapsed=0;
2740 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,length,
2741 name,(
size_t *) NULL);
2742 status|=openCL_library->clGetEventProfilingInfo(event,
2743 CL_PROFILING_COMMAND_START,
sizeof(cl_ulong),&start,NULL);
2744 status|=openCL_library->clGetEventProfilingInfo(event,
2745 CL_PROFILING_COMMAND_END,
sizeof(cl_ulong),&end,NULL);
2746 if (status != CL_SUCCESS)
2748 name=DestroyString(name);
2754 LockSemaphoreInfo(device->lock);
2761 if (LocaleCompare(device->profile_records[i]->kernel_name,name) == 0)
2763 profile_record=device->profile_records[i];
2770 name=DestroyString(name);
2774 sizeof(*profile_record));
2775 (void) memset(profile_record,0,
sizeof(*profile_record));
2776 profile_record->kernel_name=name;
2778 device->profile_records,(i+2),
sizeof(*device->profile_records));
2781 UnlockSemaphoreInfo(device->lock);
2784 name=DestroyString(name);
2785 return(MagickFalse);
2787 device->profile_records[i]=profile_record;
2790 if ((elapsed < profile_record->min) || (profile_record->count == 0))
2791 profile_record->min=elapsed;
2792 if (elapsed > profile_record->max)
2793 profile_record->max=elapsed;
2794 profile_record->total+=elapsed;
2795 profile_record->count+=1;
2796 UnlockSemaphoreInfo(device->lock);
2825MagickPrivate
void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2826 cl_command_queue queue)
2828 if (queue == (cl_command_queue) NULL)
2831 assert(device != (MagickCLDevice) NULL);
2832 LockSemaphoreInfo(device->lock);
2833 if ((device->profile_kernels != MagickFalse) ||
2834 (device->command_queues_index >= MAGICKCORE_OPENCL_COMMAND_QUEUES-1))
2836 UnlockSemaphoreInfo(device->lock);
2837 openCL_library->clFinish(queue);
2838 (void) openCL_library->clReleaseCommandQueue(queue);
2842 openCL_library->clFlush(queue);
2843 device->command_queues[++device->command_queues_index]=queue;
2844 UnlockSemaphoreInfo(device->lock);
2871MagickPrivate
void ReleaseOpenCLDevice(MagickCLDevice device)
2873 assert(device != (MagickCLDevice) NULL);
2874 LockSemaphoreInfo(openCL_lock);
2875 device->requested--;
2876 UnlockSemaphoreInfo(openCL_lock);
2906static void CL_API_CALL DestroyMagickCLCacheInfoAndPixels(
2907 cl_event magick_unused(event),
2908 cl_int magick_unused(event_command_exec_status),
void *user_data)
2919 magick_unreferenced(event);
2920 magick_unreferenced(event_command_exec_status);
2921 info=(MagickCLCacheInfo) user_data;
2922 for (i=(ssize_t)info->event_count-1; i >= 0; i--)
2930 status=openCL_library->clGetEventInfo(info->events[i],
2931 CL_EVENT_COMMAND_EXECUTION_STATUS,
sizeof(event_status),&event_status,
2933 if ((status == CL_SUCCESS) && (event_status > CL_COMPLETE))
2935 openCL_library->clSetEventCallback(info->events[i],CL_COMPLETE,
2936 &DestroyMagickCLCacheInfoAndPixels,info);
2940 pixels=info->pixels;
2941 RelinquishMagickResource(MemoryResource,info->length);
2942 DestroyMagickCLCacheInfo(info);
2943 (void) RelinquishAlignedMemory(pixels);
2946MagickPrivate MagickCLCacheInfo RelinquishMagickCLCacheInfo(
2947 MagickCLCacheInfo info,
const MagickBooleanType relinquish_pixels)
2949 if (info == (MagickCLCacheInfo) NULL)
2950 return((MagickCLCacheInfo) NULL);
2951 if (relinquish_pixels != MagickFalse)
2952 DestroyMagickCLCacheInfoAndPixels((cl_event) NULL,0,info);
2954 DestroyMagickCLCacheInfo(info);
2955 return((MagickCLCacheInfo) NULL);
2981static MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2983 if (device == (MagickCLDevice) NULL)
2984 return((MagickCLDevice) NULL);
2986 device->platform_name=(
char *) RelinquishMagickMemory(device->platform_name);
2987 device->vendor_name=(
char *) RelinquishMagickMemory(device->vendor_name);
2988 device->name=(
char *) RelinquishMagickMemory(device->name);
2989 device->version=(
char *) RelinquishMagickMemory(device->version);
2990 if (device->program != (cl_program) NULL)
2991 (
void) openCL_library->clReleaseProgram(device->program);
2992 while (device->command_queues_index >= 0)
2993 (void) openCL_library->clReleaseCommandQueue(
2994 device->command_queues[device->command_queues_index--]);
2995 RelinquishSemaphoreInfo(&device->lock);
2996 return((MagickCLDevice) RelinquishMagickMemory(device));
3022static MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv clEnv)
3024 if (clEnv == (MagickCLEnv) NULL)
3025 return((MagickCLEnv) NULL);
3027 RelinquishSemaphoreInfo(&clEnv->lock);
3028 RelinquishMagickCLDevices(clEnv);
3029 if (clEnv->contexts != (cl_context *) NULL)
3034 for (i=0; i < clEnv->number_contexts; i++)
3035 if (clEnv->contexts[i] != (cl_context) NULL)
3036 (void) openCL_library->clReleaseContext(clEnv->contexts[i]);
3037 clEnv->contexts=(cl_context *) RelinquishMagickMemory(clEnv->contexts);
3039 return((MagickCLEnv) RelinquishMagickMemory(clEnv));
3064MagickPrivate MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
3076 if (clEnv == (MagickCLEnv) NULL)
3077 return((MagickCLDevice) NULL);
3079 if (clEnv->number_devices == 1)
3081 if (clEnv->devices[0]->enabled)
3082 return(clEnv->devices[0]);
3084 return((MagickCLDevice) NULL);
3087 device=(MagickCLDevice) NULL;
3089 LockSemaphoreInfo(openCL_lock);
3090 for (i = 0; i < clEnv->number_devices; i++)
3092 if (clEnv->devices[i]->enabled == MagickFalse)
3095 score=clEnv->devices[i]->score+(clEnv->devices[i]->score*
3096 clEnv->devices[i]->requested);
3097 if ((device == (MagickCLDevice) NULL) || (score < best_score))
3099 device=clEnv->devices[i];
3103 if (device != (MagickCLDevice)NULL)
3104 device->requested++;
3105 UnlockSemaphoreInfo(openCL_lock);
3135MagickExport
void SetOpenCLDeviceEnabled(MagickCLDevice device,
3136 const MagickBooleanType value)
3138 if (device == (MagickCLDevice) NULL)
3140 device->enabled=value;
3170MagickExport
void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3171 const MagickBooleanType value)
3173 if (device == (MagickCLDevice) NULL)
3175 device->profile_kernels=value;
3200MagickExport MagickBooleanType SetOpenCLEnabled(
const MagickBooleanType value)
3205 clEnv=GetCurrentOpenCLEnv();
3206 if (clEnv == (MagickCLEnv) NULL)
3207 return(MagickFalse);
3208 clEnv->enabled=value;
3209 return(clEnv->enabled);
3214MagickExport
double GetOpenCLDeviceBenchmarkScore(
3215 const MagickCLDevice magick_unused(device))
3217 magick_unreferenced(device);
3221MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
3222 const MagickCLDevice magick_unused(device))
3224 magick_unreferenced(device);
3225 return(MagickFalse);
3228MagickExport
const char *GetOpenCLDeviceName(
3229 const MagickCLDevice magick_unused(device))
3231 magick_unreferenced(device);
3232 return((
const char *) NULL);
3235MagickExport MagickCLDevice *GetOpenCLDevices(
size_t *length,
3238 magick_unreferenced(exception);
3239 if (length != (
size_t *) NULL)
3241 return((MagickCLDevice *) NULL);
3244MagickExport MagickCLDeviceType GetOpenCLDeviceType(
3245 const MagickCLDevice magick_unused(device))
3247 magick_unreferenced(device);
3248 return(UndefinedCLDeviceType);
3252 const MagickCLDevice magick_unused(device),
size_t *length)
3254 magick_unreferenced(device);
3255 if (length != (
size_t *) NULL)
3260MagickExport
const char *GetOpenCLDeviceVersion(
3261 const MagickCLDevice magick_unused(device))
3263 magick_unreferenced(device);
3264 return((
const char *) NULL);
3267MagickExport MagickBooleanType GetOpenCLEnabled(
void)
3269 return(MagickFalse);
3272MagickExport
void SetOpenCLDeviceEnabled(
3273 MagickCLDevice magick_unused(device),
3274 const MagickBooleanType magick_unused(value))
3276 magick_unreferenced(device);
3277 magick_unreferenced(value);
3280MagickExport MagickBooleanType SetOpenCLEnabled(
3281 const MagickBooleanType magick_unused(value))
3283 magick_unreferenced(value);
3284 return(MagickFalse);
3287MagickExport
void SetOpenCLKernelProfileEnabled(
3288 MagickCLDevice magick_unused(device),
3289 const MagickBooleanType magick_unused(value))
3291 magick_unreferenced(device);
3292 magick_unreferenced(value);