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"
92#if defined(MAGICKCORE_OPENCL_SUPPORT)
93#if defined(MAGICKCORE_LTDL_DELEGATE)
100#define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile.xml"
126} MagickCLDeviceBenchmark;
132static MagickBooleanType
133 HasOpenCLDevices(MagickCLEnv,ExceptionInfo *),
134 LoadOpenCLLibrary(
void);
137 RelinquishMagickCLDevice(MagickCLDevice);
140 RelinquishMagickCLEnv(MagickCLEnv);
143 BenchmarkOpenCLDevices(MagickCLEnv);
161 *cache_directory_lock;
163static inline MagickBooleanType IsSameOpenCLDevice(MagickCLDevice a,
166 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
167 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
168 (LocaleCompare(a->name,b->name) == 0) &&
169 (LocaleCompare(a->version,b->version) == 0) &&
170 (a->max_clock_frequency == b->max_clock_frequency) &&
171 (a->max_compute_units == b->max_compute_units))
177static inline MagickBooleanType IsBenchmarkedOpenCLDevice(MagickCLDevice a,
178 MagickCLDeviceBenchmark *b)
180 if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
181 (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
182 (LocaleCompare(a->name,b->name) == 0) &&
183 (LocaleCompare(a->version,b->version) == 0) &&
184 (a->max_clock_frequency == b->max_clock_frequency) &&
185 (a->max_compute_units == b->max_compute_units))
191static inline void RelinquishMagickCLDevices(MagickCLEnv clEnv)
196 if (clEnv->devices != (MagickCLDevice *) NULL)
198 for (i = 0; i < clEnv->number_devices; i++)
199 clEnv->devices[i]=RelinquishMagickCLDevice(clEnv->devices[i]);
200 clEnv->devices=(MagickCLDevice *) RelinquishMagickMemory(clEnv->devices);
202 clEnv->number_devices=0;
205static inline MagickBooleanType MagickCreateDirectory(
const char *path)
210#ifdef MAGICKCORE_WINDOWS_SUPPORT
213 status=mkdir(path,0777);
215 return(status == 0 ? MagickTrue : MagickFalse);
218static inline void InitAccelerateTimer(AccelerateTimer *timer)
221 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->freq);
223 timer->freq=(
long long)1.0E3;
229static inline double ReadAccelerateTimer(AccelerateTimer *timer)
231 return (
double)timer->clocks/(double)timer->freq;
234static inline void StartAccelerateTimer(AccelerateTimer* timer)
237 QueryPerformanceCounter((LARGE_INTEGER*)&timer->start);
242 timer->start=(
long long)s.tv_sec*(
long long)1.0E3+(
long long)s.tv_usec/
247static inline void StopAccelerateTimer(AccelerateTimer *timer)
254 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
259 n=(
long long)s.tv_sec*(
long long)1.0E3+(
long long)s.tv_usec/
267static const char *GetOpenCLCacheDirectory()
269 if (cache_directory == (
char *) NULL)
272 ActivateSemaphoreInfo(&cache_directory_lock);
273 LockSemaphoreInfo(cache_directory_lock);
274 if (cache_directory == (
char *) NULL)
278 path[MagickPathExtent],
288 home=GetEnvironmentValue(
"MAGICK_OPENCL_CACHE_DIR");
289 if (home == (
char *) NULL)
291 home=GetEnvironmentValue(
"XDG_CACHE_HOME");
292#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
293 if (home == (
char *) NULL)
294 home=GetEnvironmentValue(
"LOCALAPPDATA");
295 if (home == (
char *) NULL)
296 home=GetEnvironmentValue(
"APPDATA");
297 if (home == (
char *) NULL)
298 home=GetEnvironmentValue(
"USERPROFILE");
302 if (home != (
char *) NULL)
305 (void) FormatLocaleString(path,MagickPathExtent,
"%s",home);
306 status=GetPathAttributes(path,&attributes);
307 if (status == MagickFalse)
308 status=MagickCreateDirectory(path);
311 if (status != MagickFalse)
313 (void) FormatLocaleString(path,MagickPathExtent,
314 "%s%sImageMagick",home,DirectorySeparator);
316 status=GetPathAttributes(path,&attributes);
317 if (status == MagickFalse)
318 status=MagickCreateDirectory(path);
321 if (status != MagickFalse)
323 temp=(
char*) AcquireCriticalMemory(strlen(path)+1);
324 (void) CopyMagickString(temp,path,strlen(path)+1);
326 home=DestroyString(home);
330 home=GetEnvironmentValue(
"HOME");
331 if (home != (
char *) NULL)
334 (void) FormatLocaleString(path,MagickPathExtent,
"%s%s.cache",
335 home,DirectorySeparator);
336 status=GetPathAttributes(path,&attributes);
337 if (status == MagickFalse)
338 status=MagickCreateDirectory(path);
341 if (status != MagickFalse)
343 (void) FormatLocaleString(path,MagickPathExtent,
344 "%s%s.cache%sImageMagick",home,DirectorySeparator,
346 status=GetPathAttributes(path,&attributes);
347 if (status == MagickFalse)
348 status=MagickCreateDirectory(path);
351 if (status != MagickFalse)
353 temp=(
char*) AcquireCriticalMemory(strlen(path)+1);
354 (void) CopyMagickString(temp,path,strlen(path)+1);
356 home=DestroyString(home);
359 if (temp == (
char *) NULL)
361 temp=AcquireString(
"?");
362 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
363 "Cannot use cache directory: \"%s\"",path);
366 (
void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
367 "Using cache directory: \"%s\"",temp);
368 cache_directory=temp;
370 UnlockSemaphoreInfo(cache_directory_lock);
372 if (*cache_directory ==
'?')
373 return((
const char *) NULL);
374 return(cache_directory);
377static void SelectOpenCLDevice(MagickCLEnv clEnv,cl_device_type type)
386 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
387 "Selecting device for type: %d",(
int) type);
388 for (i = 0; i < clEnv->number_devices; i++)
389 clEnv->devices[i]->enabled=MagickFalse;
391 for (i = 0; i < clEnv->number_devices; i++)
393 device=clEnv->devices[i];
394 if (device->type != type)
397 device->enabled=MagickTrue;
398 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
399 "Selected device: %s",device->name);
400 for (j = i+1; j < clEnv->number_devices; j++)
405 other_device=clEnv->devices[j];
406 if (IsSameOpenCLDevice(device,other_device))
407 other_device->enabled=MagickTrue;
412static size_t StringSignature(
const char*
string)
427 stringLength=(size_t) strlen(
string);
428 signature=stringLength;
429 n=stringLength/
sizeof(size_t);
431 for (i = 0; i < n; i++)
433 if (n *
sizeof(
size_t) != stringLength)
439 for (i = 0; i < 4; i++, j++)
441 if (j < stringLength)
452static void DestroyMagickCLCacheInfo(MagickCLCacheInfo info)
457 for (i=0; i < (ssize_t) info->event_count; i++)
458 openCL_library->clReleaseEvent(info->events[i]);
459 info->events=(cl_event *) RelinquishMagickMemory(info->events);
460 if (info->buffer != (cl_mem) NULL)
461 openCL_library->clReleaseMemObject(info->buffer);
462 RelinquishSemaphoreInfo(&info->events_semaphore);
463 ReleaseOpenCLDevice(info->device);
464 RelinquishMagickMemory(info);
471MagickPrivate cl_mem CreateOpenCLBuffer(MagickCLDevice device,
472 cl_mem_flags flags,
size_t size,
void *host_ptr)
474 return(openCL_library->clCreateBuffer(device->context,flags,size,host_ptr,
478MagickPrivate
void ReleaseOpenCLKernel(cl_kernel kernel)
480 (void) openCL_library->clReleaseKernel(kernel);
483MagickPrivate
void ReleaseOpenCLMemObject(cl_mem memobj)
485 (void) openCL_library->clReleaseMemObject(memobj);
488MagickPrivate
void RetainOpenCLMemObject(cl_mem memobj)
490 (void) openCL_library->clRetainMemObject(memobj);
493MagickPrivate cl_int SetOpenCLKernelArg(cl_kernel kernel,
size_t arg_index,
494 size_t arg_size,
const void *arg_value)
496 return(openCL_library->clSetKernelArg(kernel,(cl_uint) arg_index,arg_size,
528MagickPrivate MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
529 Quantum *pixels,
const MagickSizeType length)
537 info=(MagickCLCacheInfo) AcquireCriticalMemory(
sizeof(*info));
538 (void) memset(info,0,
sizeof(*info));
539 LockSemaphoreInfo(openCL_lock);
541 UnlockSemaphoreInfo(openCL_lock);
545 info->events_semaphore=AcquireSemaphoreInfo();
546 info->buffer=openCL_library->clCreateBuffer(device->context,
547 CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,(
size_t) length,(
void *) pixels,
549 if (status == CL_SUCCESS)
551 DestroyMagickCLCacheInfo(info);
552 return((MagickCLCacheInfo) NULL);
574static MagickCLDevice AcquireMagickCLDevice()
579 device=(MagickCLDevice) AcquireMagickMemory(
sizeof(*device));
582 (void) memset(device,0,
sizeof(*device));
583 ActivateSemaphoreInfo(&device->lock);
584 device->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
585 device->command_queues_index=-1;
586 device->enabled=MagickTrue;
606static MagickCLEnv AcquireMagickCLEnv(
void)
614 clEnv=(MagickCLEnv) AcquireMagickMemory(
sizeof(*clEnv));
615 if (clEnv != (MagickCLEnv) NULL)
617 (void) memset(clEnv,0,
sizeof(*clEnv));
618 ActivateSemaphoreInfo(&clEnv->lock);
619 clEnv->cpu_score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
620 clEnv->enabled=MagickFalse;
621 option=GetEnvironmentValue(
"MAGICK_OCL_DEVICE");
622 if (option != (
const char *) NULL)
624 if ((IsStringTrue(option) != MagickFalse) ||
625 (strcmp(option,
"GPU") == 0) ||
626 (strcmp(option,
"CPU") == 0))
627 clEnv->enabled=MagickTrue;
628 option=DestroyString(option);
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 (void) GetNextToken(q,&q,extent,token);
801 (void) CopyMagickString(keyword,token,MagickPathExtent);
802 if (LocaleNCompare(keyword,
"<!DOCTYPE",9) == 0)
811 for ( ; *q !=
'\0'; q++)
820 if ((*q ==
'"') || (*q ==
'\''))
828 if (bracket_depth > 0)
832 if ((*q ==
'>') && (bracket_depth == 0))
840 if (LocaleNCompare(keyword,
"<!--",4) == 0)
845 while ((LocaleNCompare(q,
"->",2) != 0) && (*q !=
'\0'))
846 (void) GetNextToken(q,&q,extent,token);
849 if (LocaleCompare(keyword,
"<device") == 0)
854 device_benchmark=(MagickCLDeviceBenchmark *) AcquireQuantumMemory(1,
855 sizeof(*device_benchmark));
856 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
858 (void) memset(device_benchmark,0,
sizeof(*device_benchmark));
859 device_benchmark->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
862 if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
864 if (LocaleCompare(keyword,
"/>") == 0)
866 if (device_benchmark->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
868 if (LocaleCompare(device_benchmark->name,
"CPU") == 0)
869 clEnv->cpu_score=device_benchmark->score;
878 for (i = 0; i < clEnv->number_devices; i++)
880 device=clEnv->devices[i];
881 if (IsBenchmarkedOpenCLDevice(device,device_benchmark))
882 device->score=device_benchmark->score;
886 device_benchmark=RelinquishDeviceBenchmark(device_benchmark);
889 (void) GetNextToken(q,(
const char **) NULL,extent,token);
892 (void) GetNextToken(q,&q,extent,token);
893 (void) GetNextToken(q,&q,extent,token);
899 if (LocaleCompare((
char *) keyword,
"maxClockFrequency") == 0)
901 device_benchmark->max_clock_frequency=StringToInteger(token);
904 if (LocaleCompare((
char *) keyword,
"maxComputeUnits") == 0)
906 device_benchmark->max_compute_units=StringToInteger(token);
914 if (LocaleCompare((
char *) keyword,
"name") == 0)
915 device_benchmark->name=ConstantString(token);
921 if (LocaleCompare((
char *) keyword,
"platform") == 0)
922 device_benchmark->platform_name=ConstantString(token);
928 if (LocaleCompare((
char *) keyword,
"score") == 0)
929 device_benchmark->score=StringToDouble(token,(
char **) NULL);
935 if (LocaleCompare((
char *) keyword,
"vendor") == 0)
936 device_benchmark->vendor_name=ConstantString(token);
937 if (LocaleCompare((
char *) keyword,
"version") == 0)
938 device_benchmark->version=ConstantString(token);
945 token=(
char *) RelinquishMagickMemory(token);
946 device_benchmark=RelinquishDeviceBenchmark(device_benchmark);
949static MagickBooleanType CanWriteProfileToFile(
const char *filename)
954 profileFile=fopen_utf8(filename,
"ab");
956 if (profileFile == (FILE *) NULL)
958 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
959 "Unable to save profile to: \"%s\"",filename);
968static MagickBooleanType LoadOpenCLBenchmarks(MagickCLEnv clEnv)
970#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
972 filename[MagickPathExtent];
977 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
978 GetOpenCLCacheDirectory(),DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
984 if (CanWriteProfileToFile(filename) == MagickFalse)
990 for (i = 0; i < clEnv->number_devices; i++)
991 clEnv->devices[i]->score=1.0;
993 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
996#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
997 option=ConfigureFileToStringInfo(filename);
998 LoadOpenCLDeviceBenchmark(clEnv,(
const char *) GetStringInfoDatum(option));
999 option=DestroyStringInfo(option);
1004static void AutoSelectOpenCLDevices(MagickCLEnv clEnv)
1018 option=GetEnvironmentValue(
"MAGICK_OCL_DEVICE");
1019 if (option != (
const char *) NULL)
1021 if (strcmp(option,
"GPU") == 0)
1022 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
1023 else if (strcmp(option,
"CPU") == 0)
1024 SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_CPU);
1025 option=DestroyString(option);
1028 if (LoadOpenCLBenchmarks(clEnv) == MagickFalse)
1031 benchmark=MagickFalse;
1032 if (clEnv->cpu_score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1033 benchmark=MagickTrue;
1036 for (i = 0; i < clEnv->number_devices; i++)
1038 if (clEnv->devices[i]->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1040 benchmark=MagickTrue;
1046 if (benchmark != MagickFalse)
1047 BenchmarkOpenCLDevices(clEnv);
1049 best_score=clEnv->cpu_score;
1050 for (i = 0; i < clEnv->number_devices; i++)
1051 best_score=MagickMin(clEnv->devices[i]->score,best_score);
1053 for (i = 0; i < clEnv->number_devices; i++)
1055 if (clEnv->devices[i]->score != best_score)
1056 clEnv->devices[i]->enabled=MagickFalse;
1085static double RunOpenCLBenchmark(MagickBooleanType is_cpu)
1102 exception=AcquireExceptionInfo();
1103 imageInfo=AcquireImageInfo();
1104 CloneString(&imageInfo->size,
"2048x1536");
1105 (void) CopyMagickString(imageInfo->filename,
"xc:none",MagickPathExtent);
1106 inputImage=ReadImage(imageInfo,exception);
1107 if (inputImage == (Image *) NULL)
1110 InitAccelerateTimer(&timer);
1112 for (i=0; i<=2; i++)
1120 StartAccelerateTimer(&timer);
1122 blurredImage=BlurImage(inputImage,10.0f,3.5f,exception);
1123 unsharpedImage=UnsharpMaskImage(blurredImage,2.0f,2.0f,50.0f,10.0f,
1125 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
1132 if (is_cpu == MagickFalse)
1137 cache_info=(CacheInfo *) resizedImage->cache;
1138 if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1139 openCL_library->clWaitForEvents(cache_info->opencl->event_count,
1140 cache_info->opencl->events);
1144 StopAccelerateTimer(&timer);
1146 if (blurredImage != (Image *) NULL)
1147 DestroyImage(blurredImage);
1148 if (unsharpedImage != (Image *) NULL)
1149 DestroyImage(unsharpedImage);
1150 if (resizedImage != (Image *) NULL)
1151 DestroyImage(resizedImage);
1153 DestroyImage(inputImage);
1154 return(ReadAccelerateTimer(&timer));
1157static void RunDeviceBenchmark(MagickCLEnv clEnv,MagickCLEnv testEnv,
1158 MagickCLDevice device)
1160 testEnv->devices[0]=device;
1161 default_CLEnv=testEnv;
1162 device->score=RunOpenCLBenchmark(MagickFalse);
1163 default_CLEnv=clEnv;
1164 testEnv->devices[0]=(MagickCLDevice) NULL;
1167static void CacheOpenCLBenchmarks(MagickCLEnv clEnv)
1170 filename[MagickPathExtent];
1182 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1183 GetOpenCLCacheDirectory(),DirectorySeparator,
1184 IMAGEMAGICK_PROFILE_FILE);
1186 cache_file=fopen_utf8(filename,
"wb");
1187 if (cache_file == (FILE *) NULL)
1189 fwrite(
"<devices>\n",
sizeof(
char),10,cache_file);
1190 fprintf(cache_file,
" <device name=\"CPU\" score=\"%.4g\"/>\n",
1192 for (i = 0; i < clEnv->number_devices; i++)
1197 device=clEnv->devices[i];
1198 duplicate=MagickFalse;
1199 for (j = 0; j < i; j++)
1201 if (IsSameOpenCLDevice(clEnv->devices[j],device))
1203 duplicate=MagickTrue;
1211 if (device->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1212 fprintf(cache_file,
" <device platform=\"%s\" vendor=\"%s\" name=\"%s\"\
1213 version=\"%s\" maxClockFrequency=\"%d\" maxComputeUnits=\"%d\"\
1214 score=\"%.4g\"/>\n",
1215 device->platform_name,device->vendor_name,device->name,device->version,
1216 (
int)device->max_clock_frequency,(
int)device->max_compute_units,
1219 fwrite(
"</devices>",
sizeof(
char),10,cache_file);
1224static void BenchmarkOpenCLDevices(MagickCLEnv clEnv)
1236 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1237 "Starting benchmark");
1238 testEnv=AcquireMagickCLEnv();
1239 testEnv->library=openCL_library;
1240 testEnv->devices=(MagickCLDevice *) AcquireCriticalMemory(
1241 sizeof(MagickCLDevice));
1242 testEnv->number_devices=1;
1243 testEnv->benchmark_thread_id=GetMagickThreadId();
1244 testEnv->initialized=MagickTrue;
1246 for (i = 0; i < clEnv->number_devices; i++)
1247 clEnv->devices[i]->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
1249 for (i = 0; i < clEnv->number_devices; i++)
1251 device=clEnv->devices[i];
1252 if (device->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1253 RunDeviceBenchmark(clEnv,testEnv,device);
1256 for (j = i+1; j < clEnv->number_devices; j++)
1261 other_device=clEnv->devices[j];
1262 if (IsSameOpenCLDevice(device,other_device))
1263 other_device->score=device->score;
1267 testEnv->enabled=MagickFalse;
1268 default_CLEnv=testEnv;
1269 clEnv->cpu_score=RunOpenCLBenchmark(MagickTrue);
1270 default_CLEnv=clEnv;
1272 testEnv=RelinquishMagickCLEnv(testEnv);
1273 CacheOpenCLBenchmarks(clEnv);
1310static void CacheOpenCLKernel(MagickCLDevice device,
char *filename,
1311 ExceptionInfo *exception)
1322 status=openCL_library->clGetProgramInfo(device->program,
1323 CL_PROGRAM_BINARY_SIZES,
sizeof(
size_t),&binaryProgramSize,NULL);
1324 if (status != CL_SUCCESS)
1326 binaryProgram=(
unsigned char*) AcquireQuantumMemory(1,binaryProgramSize);
1327 if (binaryProgram == (
unsigned char *) NULL)
1329 (void) ThrowMagickException(exception,GetMagickModule(),
1330 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",filename);
1333 status=openCL_library->clGetProgramInfo(device->program,
1334 CL_PROGRAM_BINARIES,
sizeof(
unsigned char*),&binaryProgram,NULL);
1335 if (status == CL_SUCCESS)
1337 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1338 "Creating cache file: \"%s\"",filename);
1339 (void) BlobToFile(filename,binaryProgram,binaryProgramSize,exception);
1341 binaryProgram=(
unsigned char *) RelinquishMagickMemory(binaryProgram);
1344static MagickBooleanType LoadCachedOpenCLKernels(MagickCLDevice device,
1345 const char *filename)
1360 sans_exception=AcquireExceptionInfo();
1361 binaryProgram=(
unsigned char *) FileToBlob(filename,SIZE_MAX,&length,
1363 sans_exception=DestroyExceptionInfo(sans_exception);
1364 if (binaryProgram == (
unsigned char *) NULL)
1365 return(MagickFalse);
1366 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1367 "Loaded cached kernels: \"%s\"",filename);
1368 device->program=openCL_library->clCreateProgramWithBinary(device->context,1,
1369 &device->deviceID,&length,(
const unsigned char**)&binaryProgram,
1370 &binaryStatus,&status);
1371 binaryProgram=(
unsigned char *) RelinquishMagickMemory(binaryProgram);
1372 return((status != CL_SUCCESS) || (binaryStatus != CL_SUCCESS) ? MagickFalse :
1376static void LogOpenCLBuildFailure(MagickCLDevice device,
const char *kernel,
1377 ExceptionInfo *exception)
1380 filename[MagickPathExtent],
1386 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1387 GetOpenCLCacheDirectory(),DirectorySeparator,
"magick_badcl.cl");
1389 (void) remove_utf8(filename);
1390 (void) BlobToFile(filename,kernel,strlen(kernel),exception);
1392 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1393 CL_PROGRAM_BUILD_LOG,0,NULL,&log_size);
1394 log=(
char*)AcquireCriticalMemory(log_size);
1395 openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1396 CL_PROGRAM_BUILD_LOG,log_size,log,&log_size);
1398 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1399 GetOpenCLCacheDirectory(),DirectorySeparator,
"magick_badcl.log");
1401 (void) remove_utf8(filename);
1402 (void) BlobToFile(filename,log,log_size,exception);
1403 log=(
char*)RelinquishMagickMemory(log);
1406static MagickBooleanType CompileOpenCLKernel(MagickCLDevice device,
1407 const char *kernel,
const char *options,
size_t signature,
1408 ExceptionInfo *exception)
1411 deviceName[MagickPathExtent],
1412 filename[MagickPathExtent],
1424 (void) CopyMagickString(deviceName,device->name,MagickPathExtent);
1427 while (*ptr !=
'\0')
1429 if ((*ptr ==
' ') || (*ptr ==
'\\') || (*ptr ==
'/') || (*ptr ==
':') ||
1430 (*ptr ==
'*') || (*ptr ==
'?') || (*ptr ==
'"') || (*ptr ==
'<') ||
1431 (*ptr ==
'>' || *ptr ==
'|'))
1435 (void) FormatLocaleString(filename,MagickPathExtent,
1436 "%s%s%s_%s_%08x_%.17g.bin",GetOpenCLCacheDirectory(),
1437 DirectorySeparator,
"magick_opencl",deviceName,(
unsigned int) signature,
1438 (
double)
sizeof(
char*)*8);
1439 loaded=LoadCachedOpenCLKernels(device,filename);
1440 if (loaded == MagickFalse)
1443 length=strlen(kernel);
1444 device->program=openCL_library->clCreateProgramWithSource(
1445 device->context,1,&kernel,&length,&status);
1446 if (status != CL_SUCCESS)
1447 return(MagickFalse);
1450 status=openCL_library->clBuildProgram(device->program,1,&device->deviceID,
1452 if (status != CL_SUCCESS)
1454 (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
1455 "clBuildProgram failed.",
"(%d)",(
int)status);
1456 LogOpenCLBuildFailure(device,kernel,exception);
1457 return(MagickFalse);
1461 if (loaded == MagickFalse)
1462 CacheOpenCLKernel(device,filename,exception);
1467static cl_event* CopyOpenCLEvents(MagickCLCacheInfo first,
1468 MagickCLCacheInfo second,cl_uint *event_count)
1479 assert(first != (MagickCLCacheInfo) NULL);
1480 assert(event_count != (cl_uint *) NULL);
1481 events=(cl_event *) NULL;
1482 LockSemaphoreInfo(first->events_semaphore);
1483 if (second != (MagickCLCacheInfo) NULL)
1484 LockSemaphoreInfo(second->events_semaphore);
1485 *event_count=first->event_count;
1486 if (second != (MagickCLCacheInfo) NULL)
1487 *event_count+=second->event_count;
1488 if (*event_count > 0)
1490 events=(cl_event *) AcquireQuantumMemory(*event_count,
sizeof(*events));
1491 if (events == (cl_event *) NULL)
1496 for (i=0; i < first->event_count; i++, j++)
1497 events[j]=first->events[i];
1498 if (second != (MagickCLCacheInfo) NULL)
1500 for (i=0; i < second->event_count; i++, j++)
1501 events[j]=second->events[i];
1505 UnlockSemaphoreInfo(first->events_semaphore);
1506 if (second != (MagickCLCacheInfo) NULL)
1507 UnlockSemaphoreInfo(second->events_semaphore);
1533MagickPrivate MagickCLCacheInfo CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1547 if (info == (MagickCLCacheInfo) NULL)
1548 return((MagickCLCacheInfo) NULL);
1549 events=CopyOpenCLEvents(info,(MagickCLCacheInfo) NULL,&event_count);
1550 if (events != (cl_event *) NULL)
1552 queue=AcquireOpenCLCommandQueue(info->device);
1553 pixels=(Quantum *) openCL_library->clEnqueueMapBuffer(queue,info->buffer,
1554 CL_TRUE,CL_MAP_READ | CL_MAP_WRITE,0,(
size_t) info->length,event_count,
1556 (cl_event *) NULL,(cl_int *) NULL);
1557 assert(pixels == info->pixels);
1558 ReleaseOpenCLCommandQueue(info->device,queue);
1559 events=(cl_event *) RelinquishMagickMemory(events);
1561 return(RelinquishMagickCLCacheInfo(info,MagickFalse));
1583MagickPrivate
void DumpOpenCLProfileData()
1585#define OpenCLLog(message) \
1586 fwrite(message,sizeof(char),strlen(message),log); \
1587 fwrite("\n",sizeof(char),1,log);
1591 filename[MagickPathExtent],
1601 if (default_CLEnv == (MagickCLEnv) NULL)
1604 for (i = 0; i < default_CLEnv->number_devices; i++)
1605 if (default_CLEnv->devices[i]->profile_kernels != MagickFalse)
1607 if (i == default_CLEnv->number_devices)
1610 (void) FormatLocaleString(filename,MagickPathExtent,
"%s%s%s",
1611 GetOpenCLCacheDirectory(),DirectorySeparator,
"ImageMagickOpenCL.log");
1613 log=fopen_utf8(filename,
"wb");
1614 if (log == (FILE *) NULL)
1616 for (i = 0; i < default_CLEnv->number_devices; i++)
1621 device=default_CLEnv->devices[i];
1622 if ((device->profile_kernels == MagickFalse) ||
1623 (device->profile_records == (KernelProfileRecord *) NULL))
1626 OpenCLLog(
"====================================================");
1627 fprintf(log,
"Device: %s\n",device->name);
1628 fprintf(log,
"Version: %s\n",device->version);
1629 OpenCLLog(
"====================================================");
1630 OpenCLLog(
" average calls min max");
1631 OpenCLLog(
" ------- ----- --- ---");
1633 while (device->profile_records[j] != (KernelProfileRecord) NULL)
1638 profile=device->profile_records[j];
1639 (void) CopyMagickString(indent,
" ",
1641 (void) CopyMagickString(indent,profile->kernel_name,MagickMin(strlen(
1642 profile->kernel_name),strlen(indent)));
1643 (void) FormatLocaleString(buf,
sizeof(buf),
"%s %7d %7d %7d %7d",indent,
1644 (
int) (profile->total/profile->count),(
int) profile->count,
1645 (
int) profile->min,(
int) profile->max);
1649 OpenCLLog(
"====================================================");
1650 fwrite(
"\n\n",
sizeof(
char),2,log);
1702static MagickBooleanType RegisterCacheEvent(MagickCLCacheInfo info,
1705 assert(info != (MagickCLCacheInfo) NULL);
1706 assert(event != (cl_event) NULL);
1707 if (openCL_library->clRetainEvent(event) != CL_SUCCESS)
1709 openCL_library->clWaitForEvents(1,&event);
1710 return(MagickFalse);
1712 LockSemaphoreInfo(info->events_semaphore);
1713 if (info->events == (cl_event *) NULL)
1715 info->events=(cl_event *) AcquireMagickMemory(
sizeof(*info->events));
1716 info->event_count=1;
1719 info->events=(cl_event *) ResizeQuantumMemory(info->events,
1720 ++info->event_count,
sizeof(*info->events));
1721 if (info->events == (cl_event *) NULL)
1723 UnlockSemaphoreInfo(info->events_semaphore);
1724 return(MagickFalse);
1726 info->events[info->event_count-1]=event;
1727 UnlockSemaphoreInfo(info->events_semaphore);
1731MagickPrivate MagickBooleanType EnqueueOpenCLKernel(cl_command_queue queue,
1732 cl_kernel kernel,cl_uint work_dim,
const size_t *offset,
const size_t *gsize,
1733 const size_t *lsize,
const Image *input_image,
const Image *output_image,
1734 MagickBooleanType flush,ExceptionInfo *exception)
1750 assert(input_image != (
const Image *) NULL);
1751 input_info=(CacheInfo *) input_image->cache;
1752 assert(input_info != (CacheInfo *) NULL);
1753 assert(input_info->opencl != (MagickCLCacheInfo) NULL);
1754 output_info=(CacheInfo *) NULL;
1755 if (output_image == (
const Image *) NULL)
1756 events=CopyOpenCLEvents(input_info->opencl,(MagickCLCacheInfo) NULL,
1760 output_info=(CacheInfo *) output_image->cache;
1761 assert(output_info != (CacheInfo *) NULL);
1762 assert(output_info->opencl != (MagickCLCacheInfo) NULL);
1763 events=CopyOpenCLEvents(input_info->opencl,output_info->opencl,
1766 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,offset,
1767 gsize,lsize,event_count,events,&event);
1769 if ((status != CL_SUCCESS) && (event_count > 0))
1771 openCL_library->clFinish(queue);
1772 status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,
1773 offset,gsize,lsize,event_count,events,&event);
1775 events=(cl_event *) RelinquishMagickMemory(events);
1776 if (status != CL_SUCCESS)
1778 (void) OpenCLThrowMagickException(input_info->opencl->device,exception,
1779 GetMagickModule(),ResourceLimitWarning,
1780 "clEnqueueNDRangeKernel failed.",
"'%s'",
".");
1781 return(MagickFalse);
1783 if (flush != MagickFalse)
1784 openCL_library->clFlush(queue);
1785 if (RecordProfileData(input_info->opencl->device,kernel,event) == MagickFalse)
1787 if (RegisterCacheEvent(input_info->opencl,event) != MagickFalse)
1789 if (output_info != (CacheInfo *) NULL)
1790 (void) RegisterCacheEvent(output_info->opencl,event);
1793 openCL_library->clReleaseEvent(event);
1816MagickPrivate MagickCLEnv GetCurrentOpenCLEnv(
void)
1818 if (default_CLEnv != (MagickCLEnv) NULL)
1820 if ((default_CLEnv->benchmark_thread_id != (MagickThreadType) 0) &&
1821 (default_CLEnv->benchmark_thread_id != GetMagickThreadId()))
1822 return((MagickCLEnv) NULL);
1824 return(default_CLEnv);
1827 if (GetOpenCLCacheDirectory() == (
char *) NULL)
1828 return((MagickCLEnv) NULL);
1831 ActivateSemaphoreInfo(&openCL_lock);
1833 LockSemaphoreInfo(openCL_lock);
1834 if (default_CLEnv == (MagickCLEnv) NULL)
1835 default_CLEnv=AcquireMagickCLEnv();
1836 UnlockSemaphoreInfo(openCL_lock);
1838 return(default_CLEnv);
1865MagickExport
double GetOpenCLDeviceBenchmarkScore(
1866 const MagickCLDevice device)
1868 if (device == (MagickCLDevice) NULL)
1869 return(MAGICKCORE_OPENCL_UNDEFINED_SCORE);
1870 return(device->score);
1895MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
1896 const MagickCLDevice device)
1898 if (device == (MagickCLDevice) NULL)
1899 return(MagickFalse);
1900 return(device->enabled);
1925MagickExport
const char *GetOpenCLDeviceName(
const MagickCLDevice device)
1927 if (device == (MagickCLDevice) NULL)
1928 return((
const char *) NULL);
1929 return(device->name);
1954MagickExport
const char *GetOpenCLDeviceVendorName(
const MagickCLDevice device)
1956 if (device == (MagickCLDevice) NULL)
1957 return((
const char *) NULL);
1958 return(device->vendor_name);
1988MagickExport MagickCLDevice *GetOpenCLDevices(
size_t *length,
1989 ExceptionInfo *exception)
1994 clEnv=GetCurrentOpenCLEnv();
1995 if (clEnv == (MagickCLEnv) NULL)
1997 if (length != (
size_t *) NULL)
1999 return((MagickCLDevice *) NULL);
2001 InitializeOpenCL(clEnv,exception);
2002 if (length != (
size_t *) NULL)
2003 *length=clEnv->number_devices;
2004 return(clEnv->devices);
2029MagickExport MagickCLDeviceType GetOpenCLDeviceType(
2030 const MagickCLDevice device)
2032 if (device == (MagickCLDevice) NULL)
2033 return(UndefinedCLDeviceType);
2034 if (device->type == CL_DEVICE_TYPE_GPU)
2035 return(GpuCLDeviceType);
2036 if (device->type == CL_DEVICE_TYPE_CPU)
2037 return(CpuCLDeviceType);
2038 return(UndefinedCLDeviceType);
2063MagickExport
const char *GetOpenCLDeviceVersion(
const MagickCLDevice device)
2065 if (device == (MagickCLDevice) NULL)
2066 return((
const char *) NULL);
2067 return(device->version);
2089MagickExport MagickBooleanType GetOpenCLEnabled(
void)
2094 clEnv=GetCurrentOpenCLEnv();
2095 if (clEnv == (MagickCLEnv) NULL)
2096 return(MagickFalse);
2097 return(clEnv->enabled);
2123MagickExport
const KernelProfileRecord *GetOpenCLKernelProfileRecords(
2124 const MagickCLDevice device,
size_t *length)
2126 if ((device == (
const MagickCLDevice) NULL) || (device->profile_records ==
2127 (KernelProfileRecord *) NULL))
2129 if (length != (
size_t *) NULL)
2131 return((
const KernelProfileRecord *) NULL);
2133 if (length != (
size_t *) NULL)
2136 LockSemaphoreInfo(device->lock);
2137 while (device->profile_records[*length] != (KernelProfileRecord) NULL)
2139 UnlockSemaphoreInfo(device->lock);
2141 return(device->profile_records);
2172static MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2173 ExceptionInfo *exception)
2176 *accelerateKernelsBuffer,
2177 options[MagickPathExtent];
2189 for (i = 0; i < clEnv->number_devices; i++)
2191 if ((clEnv->devices[i]->enabled != MagickFalse))
2194 if (i == clEnv->number_devices)
2195 return(MagickFalse);
2199 for (i = 0; i < clEnv->number_devices; i++)
2201 if ((clEnv->devices[i]->enabled != MagickFalse) &&
2202 (clEnv->devices[i]->program == (cl_program) NULL))
2208 if (status != MagickFalse)
2212 (void) FormatLocaleString(options,MagickPathExtent,CLOptions,
2213 (
float)QuantumRange,(
float)CLCharQuantumScale,(
float)MagickEpsilon,
2214 (
float)MagickPI,(
unsigned int)MaxMap,(
unsigned int)MAGICKCORE_QUANTUM_DEPTH);
2216 signature=StringSignature(options);
2217 accelerateKernelsBuffer=(
char*) AcquireQuantumMemory(1,
2218 strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
2219 if (accelerateKernelsBuffer == (
char*) NULL)
2220 return(MagickFalse);
2221 (void) FormatLocaleString(accelerateKernelsBuffer,strlen(accelerateKernels)+
2222 strlen(accelerateKernels2)+1,
"%s%s",accelerateKernels,accelerateKernels2);
2223 signature^=StringSignature(accelerateKernelsBuffer);
2226 for (i = 0; i < clEnv->number_devices; i++)
2234 device=clEnv->devices[i];
2235 if ((device->enabled == MagickFalse) ||
2236 (device->program != (cl_program) NULL))
2239 LockSemaphoreInfo(device->lock);
2240 if (device->program != (cl_program) NULL)
2242 UnlockSemaphoreInfo(device->lock);
2245 device_signature=signature;
2246 device_signature^=StringSignature(device->platform_name);
2247 status=CompileOpenCLKernel(device,accelerateKernelsBuffer,options,
2248 device_signature,exception);
2249 UnlockSemaphoreInfo(device->lock);
2250 if (status == MagickFalse)
2253 accelerateKernelsBuffer=(
char *) RelinquishMagickMemory(
2254 accelerateKernelsBuffer);
2282static cl_uint GetOpenCLDeviceCount(MagickCLEnv clEnv,cl_platform_id platform)
2285 version[MagickPathExtent];
2290 if (clEnv->library->clGetPlatformInfo(platform,CL_PLATFORM_VERSION,
2291 MagickPathExtent,version,NULL) != CL_SUCCESS)
2293 if (strncmp(version,
"OpenCL 1.0 ",11) == 0)
2295 if (clEnv->library->clGetDeviceIDs(platform,
2296 CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU,0,NULL,&num) != CL_SUCCESS)
2301static inline char *GetOpenCLPlatformString(cl_platform_id platform,
2302 cl_platform_info param_name)
2310 openCL_library->clGetPlatformInfo(platform,param_name,0,NULL,&length);
2311 value=(
char *) AcquireCriticalMemory(length*
sizeof(*value));
2312 openCL_library->clGetPlatformInfo(platform,param_name,length,value,NULL);
2316static inline char *GetOpenCLDeviceString(cl_device_id device,
2317 cl_device_info param_name)
2325 openCL_library->clGetDeviceInfo(device,param_name,0,NULL,&length);
2326 value=(
char *) AcquireCriticalMemory(length*
sizeof(*value));
2327 openCL_library->clGetDeviceInfo(device,param_name,length,value,NULL);
2331static void LoadOpenCLDevices(MagickCLEnv clEnv)
2333 cl_context_properties
2353 if (openCL_library->clGetPlatformIDs(0,NULL,&number_platforms) != CL_SUCCESS)
2355 if (number_platforms == 0)
2357 platforms=(cl_platform_id *) AcquireQuantumMemory(1,number_platforms*
2358 sizeof(cl_platform_id));
2359 if (platforms == (cl_platform_id *) NULL)
2361 if (openCL_library->clGetPlatformIDs(number_platforms,platforms,NULL) != CL_SUCCESS)
2363 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2366 for (i = 0; i < number_platforms; i++)
2368 number_devices=GetOpenCLDeviceCount(clEnv,platforms[i]);
2369 if (number_devices == 0)
2370 platforms[i]=(cl_platform_id) NULL;
2372 clEnv->number_devices+=number_devices;
2374 if (clEnv->number_devices == 0)
2376 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2379 clEnv->devices=(MagickCLDevice *) AcquireQuantumMemory(clEnv->number_devices,
2380 sizeof(MagickCLDevice));
2381 if (clEnv->devices == (MagickCLDevice *) NULL)
2383 RelinquishMagickCLDevices(clEnv);
2384 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2387 (void) memset(clEnv->devices,0,clEnv->number_devices*
sizeof(MagickCLDevice));
2388 devices=(cl_device_id *) AcquireQuantumMemory(clEnv->number_devices,
2389 sizeof(cl_device_id));
2390 if (devices == (cl_device_id *) NULL)
2392 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2393 RelinquishMagickCLDevices(clEnv);
2396 (void) memset(devices,0,clEnv->number_devices*
sizeof(cl_device_id));
2397 clEnv->number_contexts=(size_t) number_platforms;
2398 clEnv->contexts=(cl_context *) AcquireQuantumMemory(clEnv->number_contexts,
2399 sizeof(cl_context));
2400 if (clEnv->contexts == (cl_context *) NULL)
2402 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2403 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2404 RelinquishMagickCLDevices(clEnv);
2407 (void) memset(clEnv->contexts,0,clEnv->number_contexts*
sizeof(cl_context));
2409 for (i = 0; i < number_platforms; i++)
2411 if (platforms[i] == (cl_platform_id) NULL)
2414 status=clEnv->library->clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_CPU |
2415 CL_DEVICE_TYPE_GPU,(cl_uint) clEnv->number_devices,devices,&number_devices);
2416 if (status != CL_SUCCESS)
2419 properties[0]=CL_CONTEXT_PLATFORM;
2420 properties[1]=(cl_context_properties) platforms[i];
2422 clEnv->contexts[i]=openCL_library->clCreateContext(properties,number_devices,
2423 devices,NULL,NULL,&status);
2424 if (status != CL_SUCCESS)
2427 for (j = 0; j < number_devices; j++,next++)
2432 device=AcquireMagickCLDevice();
2433 if (device == (MagickCLDevice) NULL)
2436 device->context=clEnv->contexts[i];
2437 device->deviceID=devices[j];
2439 device->platform_name=GetOpenCLPlatformString(platforms[i],
2442 device->vendor_name=GetOpenCLPlatformString(platforms[i],
2443 CL_PLATFORM_VENDOR);
2445 device->name=GetOpenCLDeviceString(devices[j],CL_DEVICE_NAME);
2447 device->version=GetOpenCLDeviceString(devices[j],CL_DRIVER_VERSION);
2449 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_CLOCK_FREQUENCY,
2450 sizeof(cl_uint),&device->max_clock_frequency,NULL);
2452 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,
2453 sizeof(cl_uint),&device->max_compute_units,NULL);
2455 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_TYPE,
2456 sizeof(cl_device_type),&device->type,NULL);
2458 openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_LOCAL_MEM_SIZE,
2459 sizeof(cl_ulong),&device->local_memory_size,NULL);
2461 clEnv->devices[next]=device;
2462 (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
2463 "Found device: %s (%s)",device->name,device->platform_name);
2466 if (next != clEnv->number_devices)
2467 RelinquishMagickCLDevices(clEnv);
2468 platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2469 devices=(cl_device_id *) RelinquishMagickMemory(devices);
2472MagickPrivate MagickBooleanType InitializeOpenCL(MagickCLEnv clEnv,
2473 ExceptionInfo *exception)
2475 LockSemaphoreInfo(clEnv->lock);
2476 if (clEnv->initialized != MagickFalse)
2478 UnlockSemaphoreInfo(clEnv->lock);
2479 return(HasOpenCLDevices(clEnv,exception));
2481 if (LoadOpenCLLibrary() != MagickFalse)
2483 clEnv->library=openCL_library;
2484 LoadOpenCLDevices(clEnv);
2485 if (clEnv->number_devices > 0)
2486 AutoSelectOpenCLDevices(clEnv);
2488 clEnv->initialized=MagickTrue;
2489 UnlockSemaphoreInfo(clEnv->lock);
2490 return(HasOpenCLDevices(clEnv,exception));
2512void *OsLibraryGetFunctionAddress(
void *library,
const char *functionName)
2514 if ((library == (
void *) NULL) || (functionName == (
const char *) NULL))
2515 return (
void *) NULL;
2516 return lt_dlsym(library,functionName);
2519static MagickBooleanType BindOpenCLFunctions()
2521#ifdef MAGICKCORE_HAVE_OPENCL_CL_H
2522#define BIND(X) openCL_library->X= &X;
2524 (void) memset(openCL_library,0,
sizeof(MagickLibrary));
2525#ifdef MAGICKCORE_WINDOWS_SUPPORT
2526 openCL_library->library=(
void *)lt_dlopen(
"OpenCL.dll");
2528 openCL_library->library=(
void *)lt_dlopen(
"libOpenCL.so");
2531 if ((openCL_library->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(openCL_library->library,#X)) == NULL) \
2532 return(MagickFalse);
2535 if (openCL_library->library == (
void*) NULL)
2536 return(MagickFalse);
2538 BIND(clGetPlatformIDs);
2539 BIND(clGetPlatformInfo);
2541 BIND(clGetDeviceIDs);
2542 BIND(clGetDeviceInfo);
2544 BIND(clCreateBuffer);
2545 BIND(clReleaseMemObject);
2546 BIND(clRetainMemObject);
2548 BIND(clCreateContext);
2549 BIND(clReleaseContext);
2551 BIND(clCreateCommandQueue);
2552 BIND(clReleaseCommandQueue);
2556 BIND(clCreateProgramWithSource);
2557 BIND(clCreateProgramWithBinary);
2558 BIND(clReleaseProgram);
2559 BIND(clBuildProgram);
2560 BIND(clGetProgramBuildInfo);
2561 BIND(clGetProgramInfo);
2563 BIND(clCreateKernel);
2564 BIND(clReleaseKernel);
2565 BIND(clSetKernelArg);
2566 BIND(clGetKernelInfo);
2568 BIND(clEnqueueReadBuffer);
2569 BIND(clEnqueueMapBuffer);
2570 BIND(clEnqueueUnmapMemObject);
2571 BIND(clEnqueueNDRangeKernel);
2573 BIND(clGetEventInfo);
2574 BIND(clWaitForEvents);
2575 BIND(clReleaseEvent);
2576 BIND(clRetainEvent);
2577 BIND(clSetEventCallback);
2579 BIND(clGetEventProfilingInfo);
2584static MagickBooleanType LoadOpenCLLibrary(
void)
2586 openCL_library=(MagickLibrary *) AcquireMagickMemory(
sizeof(MagickLibrary));
2587 if (openCL_library == (MagickLibrary *) NULL)
2588 return(MagickFalse);
2590 if (BindOpenCLFunctions() == MagickFalse)
2592 openCL_library=(MagickLibrary *)RelinquishMagickMemory(openCL_library);
2593 return(MagickFalse);
2618MagickPrivate
void OpenCLTerminus()
2620 DumpOpenCLProfileData();
2621 if (cache_directory != (
char *) NULL)
2622 cache_directory=DestroyString(cache_directory);
2624 RelinquishSemaphoreInfo(&cache_directory_lock);
2625 if (default_CLEnv != (MagickCLEnv) NULL)
2626 default_CLEnv=RelinquishMagickCLEnv(default_CLEnv);
2628 RelinquishSemaphoreInfo(&openCL_lock);
2629 if (openCL_library != (MagickLibrary *) NULL)
2631 if (openCL_library->library != (
void *) NULL)
2632 (void) lt_dlclose(openCL_library->library);
2633 openCL_library=(MagickLibrary *) RelinquishMagickMemory(openCL_library);
2676MagickPrivate MagickBooleanType OpenCLThrowMagickException(
2677 MagickCLDevice device,ExceptionInfo *exception,
const char *module,
2678 const char *function,
const size_t line,
const ExceptionType severity,
2679 const char *tag,
const char *format,...)
2684 assert(device != (MagickCLDevice) NULL);
2685 assert(exception != (ExceptionInfo *) NULL);
2686 assert(exception->signature == MagickCoreSignature);
2691 if (device->type == CL_DEVICE_TYPE_CPU)
2695 if (strncmp(device->platform_name,
"Intel",5) == 0)
2696 default_CLEnv->enabled=MagickFalse;
2700#ifdef OPENCLLOG_ENABLED
2704 va_start(operands,format);
2705 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
2710 magick_unreferenced(module);
2711 magick_unreferenced(function);
2712 magick_unreferenced(line);
2713 magick_unreferenced(tag);
2714 magick_unreferenced(format);
2746MagickPrivate MagickBooleanType RecordProfileData(MagickCLDevice device,
2747 cl_kernel kernel,cl_event event)
2767 if (device->profile_kernels == MagickFalse)
2768 return(MagickFalse);
2769 status=openCL_library->clWaitForEvents(1,&event);
2770 if (status != CL_SUCCESS)
2771 return(MagickFalse);
2772 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,0,NULL,
2774 if (status != CL_SUCCESS)
2776 name=(
char *) AcquireQuantumMemory(length,
sizeof(*name));
2777 if (name == (
char *) NULL)
2779 start=end=elapsed=0;
2780 status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,length,
2781 name,(
size_t *) NULL);
2782 status|=openCL_library->clGetEventProfilingInfo(event,
2783 CL_PROFILING_COMMAND_START,
sizeof(cl_ulong),&start,NULL);
2784 status|=openCL_library->clGetEventProfilingInfo(event,
2785 CL_PROFILING_COMMAND_END,
sizeof(cl_ulong),&end,NULL);
2786 if (status != CL_SUCCESS)
2788 name=DestroyString(name);
2794 LockSemaphoreInfo(device->lock);
2796 profile_record=(KernelProfileRecord) NULL;
2797 if (device->profile_records != (KernelProfileRecord *) NULL)
2799 while (device->profile_records[i] != (KernelProfileRecord) NULL)
2801 if (LocaleCompare(device->profile_records[i]->kernel_name,name) == 0)
2803 profile_record=device->profile_records[i];
2809 if (profile_record != (KernelProfileRecord) NULL)
2810 name=DestroyString(name);
2813 profile_record=(KernelProfileRecord) AcquireCriticalMemory(
2814 sizeof(*profile_record));
2815 (void) memset(profile_record,0,
sizeof(*profile_record));
2816 profile_record->kernel_name=name;
2817 device->profile_records=(KernelProfileRecord *) ResizeQuantumMemory(
2818 device->profile_records,(i+2),
sizeof(*device->profile_records));
2819 if (device->profile_records == (KernelProfileRecord *) NULL)
2821 UnlockSemaphoreInfo(device->lock);
2822 profile_record=(KernelProfileRecord) RelinquishMagickMemory(
2824 name=DestroyString(name);
2825 return(MagickFalse);
2827 device->profile_records[i]=profile_record;
2828 device->profile_records[i+1]=(KernelProfileRecord) NULL;
2830 if ((elapsed < profile_record->min) || (profile_record->count == 0))
2831 profile_record->min=(
unsigned long) elapsed;
2832 if (elapsed > profile_record->max)
2833 profile_record->max=(
unsigned long) elapsed;
2834 profile_record->total+=(
unsigned long) elapsed;
2835 profile_record->count+=1;
2836 UnlockSemaphoreInfo(device->lock);
2865MagickPrivate
void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2866 cl_command_queue queue)
2868 if (queue == (cl_command_queue) NULL)
2871 assert(device != (MagickCLDevice) NULL);
2872 LockSemaphoreInfo(device->lock);
2873 if ((device->profile_kernels != MagickFalse) ||
2874 (device->command_queues_index >= MAGICKCORE_OPENCL_COMMAND_QUEUES-1))
2876 UnlockSemaphoreInfo(device->lock);
2877 openCL_library->clFinish(queue);
2878 (void) openCL_library->clReleaseCommandQueue(queue);
2882 openCL_library->clFlush(queue);
2883 device->command_queues[++device->command_queues_index]=queue;
2884 UnlockSemaphoreInfo(device->lock);
2911MagickPrivate
void ReleaseOpenCLDevice(MagickCLDevice device)
2913 assert(device != (MagickCLDevice) NULL);
2914 LockSemaphoreInfo(openCL_lock);
2915 device->requested--;
2916 UnlockSemaphoreInfo(openCL_lock);
2946static void CL_API_CALL DestroyMagickCLCacheInfoAndPixels(
2947 cl_event magick_unused(event),
2948 cl_int magick_unused(event_command_exec_status),
void *user_data)
2959 magick_unreferenced(event);
2960 magick_unreferenced(event_command_exec_status);
2961 info=(MagickCLCacheInfo) user_data;
2962 for (i=(ssize_t)info->event_count-1; i >= 0; i--)
2970 status=openCL_library->clGetEventInfo(info->events[i],
2971 CL_EVENT_COMMAND_EXECUTION_STATUS,
sizeof(event_status),&event_status,
2973 if ((status == CL_SUCCESS) && (event_status > CL_COMPLETE))
2975 openCL_library->clSetEventCallback(info->events[i],CL_COMPLETE,
2976 &DestroyMagickCLCacheInfoAndPixels,info);
2980 pixels=info->pixels;
2981 RelinquishMagickResource(MemoryResource,info->length);
2982 DestroyMagickCLCacheInfo(info);
2983 (void) RelinquishAlignedMemory(pixels);
2986MagickPrivate MagickCLCacheInfo RelinquishMagickCLCacheInfo(
2987 MagickCLCacheInfo info,
const MagickBooleanType relinquish_pixels)
2989 if (info == (MagickCLCacheInfo) NULL)
2990 return((MagickCLCacheInfo) NULL);
2991 if (relinquish_pixels != MagickFalse)
2992 DestroyMagickCLCacheInfoAndPixels((cl_event) NULL,0,info);
2994 DestroyMagickCLCacheInfo(info);
2995 return((MagickCLCacheInfo) NULL);
3021static MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
3023 if (device == (MagickCLDevice) NULL)
3024 return((MagickCLDevice) NULL);
3026 device->platform_name=(
char *) RelinquishMagickMemory(device->platform_name);
3027 device->vendor_name=(
char *) RelinquishMagickMemory(device->vendor_name);
3028 device->name=(
char *) RelinquishMagickMemory(device->name);
3029 device->version=(
char *) RelinquishMagickMemory(device->version);
3030 if (device->program != (cl_program) NULL)
3031 (void) openCL_library->clReleaseProgram(device->program);
3032 while (device->command_queues_index >= 0)
3033 (void) openCL_library->clReleaseCommandQueue(
3034 device->command_queues[device->command_queues_index--]);
3035 RelinquishSemaphoreInfo(&device->lock);
3036 return((MagickCLDevice) RelinquishMagickMemory(device));
3062static MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv clEnv)
3064 if (clEnv == (MagickCLEnv) NULL)
3065 return((MagickCLEnv) NULL);
3067 RelinquishSemaphoreInfo(&clEnv->lock);
3068 RelinquishMagickCLDevices(clEnv);
3069 if (clEnv->contexts != (cl_context *) NULL)
3074 for (i=0; i < (ssize_t) clEnv->number_contexts; i++)
3075 if (clEnv->contexts[i] != (cl_context) NULL)
3076 (void) openCL_library->clReleaseContext(clEnv->contexts[i]);
3077 clEnv->contexts=(cl_context *) RelinquishMagickMemory(clEnv->contexts);
3079 return((MagickCLEnv) RelinquishMagickMemory(clEnv));
3104MagickPrivate MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
3116 if (clEnv == (MagickCLEnv) NULL)
3117 return((MagickCLDevice) NULL);
3119 if (clEnv->number_devices == 1)
3121 if (clEnv->devices[0]->enabled)
3122 return(clEnv->devices[0]);
3124 return((MagickCLDevice) NULL);
3127 device=(MagickCLDevice) NULL;
3129 LockSemaphoreInfo(openCL_lock);
3130 for (i = 0; i < clEnv->number_devices; i++)
3132 if (clEnv->devices[i]->enabled == MagickFalse)
3135 score=clEnv->devices[i]->score+(clEnv->devices[i]->score*
3136 clEnv->devices[i]->requested);
3137 if ((device == (MagickCLDevice) NULL) || (score < best_score))
3139 device=clEnv->devices[i];
3143 if (device != (MagickCLDevice)NULL)
3144 device->requested++;
3145 UnlockSemaphoreInfo(openCL_lock);
3175MagickExport
void SetOpenCLDeviceEnabled(MagickCLDevice device,
3176 const MagickBooleanType value)
3178 if (device == (MagickCLDevice) NULL)
3180 device->enabled=value;
3210MagickExport
void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3211 const MagickBooleanType value)
3213 if (device == (MagickCLDevice) NULL)
3215 device->profile_kernels=value;
3240MagickExport MagickBooleanType SetOpenCLEnabled(
const MagickBooleanType value)
3245 clEnv=GetCurrentOpenCLEnv();
3246 if (clEnv == (MagickCLEnv) NULL)
3247 return(MagickFalse);
3248 clEnv->enabled=value;
3249 return(clEnv->enabled);
3254MagickExport
double GetOpenCLDeviceBenchmarkScore(
3255 const MagickCLDevice magick_unused(device))
3257 magick_unreferenced(device);
3261MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
3262 const MagickCLDevice magick_unused(device))
3264 magick_unreferenced(device);
3265 return(MagickFalse);
3268MagickExport
const char *GetOpenCLDeviceName(
3269 const MagickCLDevice magick_unused(device))
3271 magick_unreferenced(device);
3272 return((
const char *) NULL);
3275MagickExport MagickCLDevice *GetOpenCLDevices(
size_t *length,
3276 ExceptionInfo *magick_unused(exception))
3278 magick_unreferenced(exception);
3279 if (length != (
size_t *) NULL)
3281 return((MagickCLDevice *) NULL);
3284MagickExport MagickCLDeviceType GetOpenCLDeviceType(
3285 const MagickCLDevice magick_unused(device))
3287 magick_unreferenced(device);
3288 return(UndefinedCLDeviceType);
3291MagickExport
const KernelProfileRecord *GetOpenCLKernelProfileRecords(
3292 const MagickCLDevice magick_unused(device),
size_t *length)
3294 magick_unreferenced(device);
3295 if (length != (
size_t *) NULL)
3297 return((
const KernelProfileRecord *) NULL);
3300MagickExport
const char *GetOpenCLDeviceVersion(
3301 const MagickCLDevice magick_unused(device))
3303 magick_unreferenced(device);
3304 return((
const char *) NULL);
3307MagickExport MagickBooleanType GetOpenCLEnabled(
void)
3309 return(MagickFalse);
3312MagickExport
void SetOpenCLDeviceEnabled(
3313 MagickCLDevice magick_unused(device),
3314 const MagickBooleanType magick_unused(value))
3316 magick_unreferenced(device);
3317 magick_unreferenced(value);
3320MagickExport MagickBooleanType SetOpenCLEnabled(
3321 const MagickBooleanType magick_unused(value))
3323 magick_unreferenced(value);
3324 return(MagickFalse);
3327MagickExport
void SetOpenCLKernelProfileEnabled(
3328 MagickCLDevice magick_unused(device),
3329 const MagickBooleanType magick_unused(value))
3331 magick_unreferenced(device);
3332 magick_unreferenced(value);