2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % OOO PPPP EEEEE N N CCCC L %
8 % O O PPPP EEE N N N C L %
10 % OOO P EEEEE N N CCCC LLLLL %
13 % MagickCore OpenCL Methods %
20 % Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/artifact.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/color.h"
47 #include "MagickCore/compare.h"
48 #include "MagickCore/constitute.h"
49 #include "MagickCore/distort.h"
50 #include "MagickCore/draw.h"
51 #include "MagickCore/effect.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/fx.h"
55 #include "MagickCore/gem.h"
56 #include "MagickCore/geometry.h"
57 #include "MagickCore/image.h"
58 #include "MagickCore/image-private.h"
59 #include "MagickCore/layer.h"
60 #include "MagickCore/mime-private.h"
61 #include "MagickCore/memory_.h"
62 #include "MagickCore/monitor.h"
63 #include "MagickCore/montage.h"
64 #include "MagickCore/morphology.h"
65 #include "MagickCore/nt-base.h"
66 #include "MagickCore/nt-base-private.h"
67 #include "MagickCore/opencl.h"
68 #include "MagickCore/opencl-private.h"
69 #include "MagickCore/option.h"
70 #include "MagickCore/policy.h"
71 #include "MagickCore/property.h"
72 #include "MagickCore/quantize.h"
73 #include "MagickCore/quantum.h"
74 #include "MagickCore/random_.h"
75 #include "MagickCore/random-private.h"
76 #include "MagickCore/resample.h"
77 #include "MagickCore/resource_.h"
78 #include "MagickCore/splay-tree.h"
79 #include "MagickCore/semaphore.h"
80 #include "MagickCore/statistic.h"
81 #include "MagickCore/string_.h"
82 #include "MagickCore/token.h"
83 #include "MagickCore/utility.h"
85 #ifdef MAGICKCORE_CLPERFMARKER
86 #include "CLPerfMarker.h"
90 #if defined(MAGICKCORE_OPENCL_SUPPORT)
92 #ifdef MAGICKCORE_HAVE_OPENCL_CL_H
93 #define MAGICKCORE_OPENCL_MACOSX 1
97 #define NUM_CL_RAND_GENERATORS 1024 /* number of random number generators running in parallel */
101 * Dynamic library loading functions
104 #ifdef MAGICKCORE_WINDOWS_SUPPORT
109 // dynamically load a library. returns NULL on failure
110 void *OsLibraryLoad(const char *libraryName)
112 #ifdef MAGICKCORE_WINDOWS_SUPPORT
113 return (void *)LoadLibraryA(libraryName);
115 return (void *)dlopen(libraryName, RTLD_NOW);
119 // get a function pointer from a loaded library. returns NULL on failure.
120 void *OsLibraryGetFunctionAddress(void *library, const char *functionName)
122 #ifdef MAGICKCORE_WINDOWS_SUPPORT
123 if (!library || !functionName)
127 return (void *) GetProcAddress( (HMODULE)library, functionName);
129 if (!library || !functionName)
133 return (void *)dlsym(library, functionName);
138 void OsLibraryUnload(void *library)
140 #ifdef MAGICKCORE_WINDOWS_SUPPORT
141 FreeLibrary( (HMODULE)library);
149 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
153 + A c q u i r e M a g i c k O p e n C L E n v %
157 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 % AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure
163 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
166 clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
169 memset(clEnv, 0, sizeof(struct _MagickCLEnv));
170 ActivateSemaphoreInfo(&clEnv->lock);
177 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
181 + R e l i n q u i s h M a g i c k O p e n C L E n v %
185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 % RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
189 % The format of the RelinquishMagickOpenCLEnv method is:
191 % MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
193 % A description of each parameter follows:
195 % o clEnv: MagickCLEnv structure to destroy
199 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
201 if (clEnv != (MagickCLEnv)NULL)
203 RelinquishSemaphoreInfo(&clEnv->lock);
204 RelinquishMagickMemory(clEnv);
212 * Default OpenCL environment
214 MagickCLEnv defaultCLEnv;
215 SemaphoreInfo* defaultCLEnvLock;
220 MagickLibrary * OpenCLLib;
221 SemaphoreInfo* OpenCLLibLock;
224 static MagickBooleanType bindOpenCLFunctions(void* library)
226 #ifdef MAGICKCORE_OPENCL_MACOSX
227 #define BIND(X) OpenCLLib->X= &X;
230 if ((OpenCLLib->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(library,#X)) == NULL)\
234 BIND(clGetPlatformIDs);
235 BIND(clGetPlatformInfo);
237 BIND(clGetDeviceIDs);
238 BIND(clGetDeviceInfo);
240 BIND(clCreateContext);
242 BIND(clCreateBuffer);
243 BIND(clReleaseMemObject);
245 BIND(clCreateProgramWithSource);
246 BIND(clCreateProgramWithBinary);
247 BIND(clBuildProgram);
248 BIND(clGetProgramInfo);
249 BIND(clGetProgramBuildInfo);
251 BIND(clCreateKernel);
252 BIND(clReleaseKernel);
253 BIND(clSetKernelArg);
258 BIND(clEnqueueNDRangeKernel);
259 BIND(clEnqueueReadBuffer);
260 BIND(clEnqueueMapBuffer);
261 BIND(clEnqueueUnmapMemObject);
263 BIND(clCreateCommandQueue);
264 BIND(clReleaseCommandQueue);
269 MagickLibrary * GetOpenCLLib()
271 if (OpenCLLib == NULL)
273 if (OpenCLLibLock == NULL)
275 ActivateSemaphoreInfo(&OpenCLLibLock);
278 LockSemaphoreInfo(OpenCLLibLock);
280 OpenCLLib = (MagickLibrary *) AcquireMagickMemory (sizeof (MagickLibrary));
282 if (OpenCLLib != NULL)
284 MagickBooleanType status = MagickFalse;
285 void * library = NULL;
287 #ifdef MAGICKCORE_OPENCL_MACOSX
288 status = bindOpenCLFunctions(library);
291 memset(OpenCLLib, 0, sizeof(MagickLibrary));
292 #ifdef MAGICKCORE_WINDOWS_SUPPORT
293 library = OsLibraryLoad("OpenCL.dll");
295 library = OsLibraryLoad("libOpenCL.so");
298 status = bindOpenCLFunctions(library);
300 if (status==MagickTrue)
301 OpenCLLib->base=library;
303 OpenCLLib=(MagickLibrary *)RelinquishMagickMemory(OpenCLLib);
307 UnlockSemaphoreInfo(OpenCLLibLock);
316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320 + G e t D e f a u l t O p e n C L E n v %
324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 % GetDefaultOpenCLEnv() returns the default OpenCL env
328 % The format of the GetDefaultOpenCLEnv method is:
330 % MagickCLEnv GetDefaultOpenCLEnv()
332 % A description of each parameter follows:
334 % o exception: return any errors or warnings.
338 MagickExport MagickCLEnv GetDefaultOpenCLEnv()
340 if (defaultCLEnv == NULL)
342 if (defaultCLEnvLock == NULL)
344 ActivateSemaphoreInfo(&defaultCLEnvLock);
346 LockSemaphoreInfo(defaultCLEnvLock);
347 defaultCLEnv = AcquireMagickOpenCLEnv();
348 UnlockSemaphoreInfo(defaultCLEnvLock);
353 static void LockDefaultOpenCLEnv() {
354 if (defaultCLEnvLock == NULL)
356 ActivateSemaphoreInfo(&defaultCLEnvLock);
358 LockSemaphoreInfo(defaultCLEnvLock);
361 static void UnlockDefaultOpenCLEnv() {
362 if (defaultCLEnvLock == NULL)
364 ActivateSemaphoreInfo(&defaultCLEnvLock);
367 UnlockSemaphoreInfo(defaultCLEnvLock);
372 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 + S e t D e f a u l t O p e n C L E n v %
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382 % SetDefaultOpenCLEnv() sets the new OpenCL environment as default
383 % and returns the old OpenCL environment
385 % The format of the SetDefaultOpenCLEnv() method is:
387 % MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
389 % A description of each parameter follows:
391 % o clEnv: the new default OpenCL environment.
394 MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
397 LockDefaultOpenCLEnv();
398 oldEnv = defaultCLEnv;
399 defaultCLEnv = clEnv;
400 UnlockDefaultOpenCLEnv();
407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 + S e t M a g i c k O p e n C L E n v P a r a m %
415 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 % SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
419 % The format of the SetMagickOpenCLEnvParam() method is:
421 % MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
422 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
423 % ExceptionInfo* exception)
425 % A description of each parameter follows:
427 % o clEnv: the OpenCL environment.
429 % o param: the parameter to be set.
431 % o dataSize: the data size of the parameter value.
433 % o data: the pointer to the new parameter value
435 % o exception: return any errors or warnings
439 static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
440 , size_t dataSize, void* data, ExceptionInfo* exception)
442 MagickBooleanType status = MagickFalse;
450 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
451 if (dataSize != sizeof(clEnv->device))
453 clEnv->device = *((cl_device_id*)data);
454 clEnv->OpenCLInitialized = MagickFalse;
458 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
459 if (dataSize != sizeof(clEnv->OpenCLDisabled))
461 clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
462 clEnv->OpenCLInitialized = MagickFalse;
466 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
467 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
470 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
471 if (dataSize != sizeof(clEnv->disableProgramCache))
473 clEnv->disableProgramCache = *((MagickBooleanType*)data);
474 clEnv->OpenCLInitialized = MagickFalse;
478 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
479 if (dataSize != sizeof(clEnv->regenerateProfile))
481 clEnv->regenerateProfile = *((MagickBooleanType*)data);
482 clEnv->OpenCLInitialized = MagickFalse;
495 MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
496 , size_t dataSize, void* data, ExceptionInfo* exception) {
497 MagickBooleanType status = MagickFalse;
499 LockSemaphoreInfo(clEnv->lock);
500 status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
501 UnlockSemaphoreInfo(clEnv->lock);
507 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511 + G e t M a g i c k O p e n C L E n v P a r a m %
515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
517 % GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
519 % The format of the GetMagickOpenCLEnvParam() method is:
521 % MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
522 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
523 % ExceptionInfo* exception)
525 % A description of each parameter follows:
527 % o clEnv: the OpenCL environment.
529 % o param: the parameter to be returned.
531 % o dataSize: the data size of the parameter value.
533 % o data: the location where the returned parameter value will be stored
535 % o exception: return any errors or warnings
540 MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
541 , size_t dataSize, void* data, ExceptionInfo* exception)
546 magick_unreferenced(exception);
548 status = MagickFalse;
556 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
557 if (dataSize != sizeof(cl_device_id))
559 *((cl_device_id*)data) = clEnv->device;
563 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
564 if (dataSize != sizeof(clEnv->OpenCLDisabled))
566 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
570 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
571 if (dataSize != sizeof(clEnv->OpenCLDisabled))
573 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
577 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
578 if (dataSize != sizeof(clEnv->disableProgramCache))
580 *((MagickBooleanType*)data) = clEnv->disableProgramCache;
584 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
585 if (dataSize != sizeof(clEnv->regenerateProfile))
587 *((MagickBooleanType*)data) = clEnv->regenerateProfile;
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605 + G e t O p e n C L C o n t e x t %
609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611 % GetOpenCLContext() returns the OpenCL context
613 % The format of the GetOpenCLContext() method is:
615 % cl_context GetOpenCLContext(MagickCLEnv clEnv)
617 % A description of each parameter follows:
619 % o clEnv: OpenCL environment
624 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
628 return clEnv->context;
631 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
635 char path[MaxTextExtent];
636 char deviceName[MaxTextExtent];
637 const char* prefix = "magick_opencl";
638 clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
640 /* strip out illegal characters for file names */
643 if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
644 || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
650 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x_%.20g.bin",
651 GetOpenCLCachedFilesDirectory(),DirectorySeparator,prefix,deviceName,
652 (unsigned int) prog,signature,(double) sizeof(char*)*8);
653 name = (char*)AcquireMagickMemory(strlen(path)+1);
654 CopyMagickString(name,path,strlen(path)+1);
658 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
660 MagickBooleanType saveSuccessful;
662 size_t binaryProgramSize;
663 unsigned char* binaryProgram;
664 char* binaryFileName;
667 #ifdef MAGICKCORE_CLPERFMARKER
668 clBeginPerfMarkerAMD(__FUNCTION__,"");
671 binaryProgram = NULL;
672 binaryFileName = NULL;
674 saveSuccessful = MagickFalse;
676 clStatus = clEnv->library->clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
677 if (clStatus != CL_SUCCESS)
679 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
683 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
684 clStatus = clEnv->library->clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
685 if (clStatus != CL_SUCCESS)
687 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
691 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
692 fileHandle = fopen(binaryFileName, "wb");
693 if (fileHandle != NULL)
695 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
696 saveSuccessful = MagickTrue;
700 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
701 "Saving binary kernel failed.", "'%s'", ".");
705 if (fileHandle != NULL)
707 if (binaryProgram != NULL)
708 RelinquishMagickMemory(binaryProgram);
709 if (binaryFileName != NULL)
710 free(binaryFileName);
712 #ifdef MAGICKCORE_CLPERFMARKER
713 clEndPerfMarkerAMD();
716 return saveSuccessful;
719 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
721 MagickBooleanType loadSuccessful;
722 unsigned char* binaryProgram;
723 char* binaryFileName;
726 #ifdef MAGICKCORE_CLPERFMARKER
727 clBeginPerfMarkerAMD(__FUNCTION__,"");
730 binaryProgram = NULL;
731 binaryFileName = NULL;
733 loadSuccessful = MagickFalse;
735 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
736 fileHandle = fopen(binaryFileName, "rb");
737 if (fileHandle != NULL)
742 cl_int clBinaryStatus;
746 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
747 b_error |= ( length = ftell( fileHandle ) ) <= 0;
748 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
752 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
753 if (binaryProgram == NULL)
756 memset(binaryProgram, 0, length);
757 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
759 clEnv->programs[prog] = clEnv->library->clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
760 if (clStatus != CL_SUCCESS
761 || clBinaryStatus != CL_SUCCESS)
764 loadSuccessful = MagickTrue;
768 if (fileHandle != NULL)
770 if (binaryFileName != NULL)
771 free(binaryFileName);
772 if (binaryProgram != NULL)
773 RelinquishMagickMemory(binaryProgram);
775 #ifdef MAGICKCORE_CLPERFMARKER
776 clEndPerfMarkerAMD();
779 return loadSuccessful;
782 static unsigned int stringSignature(const char* string)
784 unsigned int stringLength;
786 unsigned int signature;
790 const unsigned int* u;
793 #ifdef MAGICKCORE_CLPERFMARKER
794 clBeginPerfMarkerAMD(__FUNCTION__,"");
797 stringLength = (unsigned int) strlen(string);
798 signature = stringLength;
799 n = stringLength/sizeof(unsigned int);
801 for (i = 0; i < n; i++)
805 if (n * sizeof(unsigned int) != stringLength)
808 j = n * sizeof(unsigned int);
809 for (i = 0; i < 4; i++,j++)
811 if (j < stringLength)
820 #ifdef MAGICKCORE_CLPERFMARKER
821 clEndPerfMarkerAMD();
827 /* OpenCL kernels for accelerate.c */
828 extern const char *accelerateKernels, *accelerateKernels2;
830 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
832 MagickBooleanType status = MagickFalse;
835 char* accelerateKernelsBuffer = NULL;
837 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
838 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
840 char options[MaxTextExtent];
841 unsigned int optionsSignature;
843 #ifdef MAGICKCORE_CLPERFMARKER
844 clBeginPerfMarkerAMD(__FUNCTION__,"");
847 /* Get additional options */
848 (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
849 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
852 if (getenv("MAGICK_OCL_DEF"))
855 strcat(options,getenv("MAGICK_OCL_DEF"));
860 if (getenv("MAGICK_OCL_BUILD"))
861 printf("options: %s\n", options);
864 optionsSignature = stringSignature(options);
866 /* get all the OpenCL program strings here */
867 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
868 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
869 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
871 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
873 MagickBooleanType loadSuccessful = MagickFalse;
874 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
876 /* try to load the binary first */
877 if (clEnv->disableProgramCache != MagickTrue
878 && !getenv("MAGICK_OCL_REC"))
879 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature);
881 if (loadSuccessful == MagickFalse)
883 /* Binary CL program unavailable, compile the program from source */
884 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
885 clEnv->programs[i] = clEnv->library->clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
886 if (clStatus!=CL_SUCCESS)
888 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
889 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
895 clStatus = clEnv->library->clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
896 if (clStatus!=CL_SUCCESS)
898 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
899 "clBuildProgram failed.", "(%d)", (int)clStatus);
901 if (loadSuccessful == MagickFalse)
903 char path[MaxTextExtent];
906 /* dump the source into a file */
907 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
908 ,GetOpenCLCachedFilesDirectory()
909 ,DirectorySeparator,"magick_badcl.cl");
910 fileHandle = fopen(path, "wb");
911 if (fileHandle != NULL)
913 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
917 /* dump the build log */
921 clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
922 log = (char*)AcquireMagickMemory(logSize);
923 clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
925 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
926 ,GetOpenCLCachedFilesDirectory()
927 ,DirectorySeparator,"magick_badcl_build.log");
928 fileHandle = fopen(path, "wb");
929 if (fileHandle != NULL)
931 const char* buildOptionsTitle = "build options: ";
932 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
933 fwrite(options, sizeof(char), strlen(options), fileHandle);
934 fwrite("\n",sizeof(char), 1, fileHandle);
935 fwrite(log, sizeof(char), logSize, fileHandle);
938 RelinquishMagickMemory(log);
944 if (loadSuccessful == MagickFalse)
946 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
947 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
955 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
957 #ifdef MAGICKCORE_CLPERFMARKER
958 clEndPerfMarkerAMD();
964 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
967 cl_uint numPlatforms = 0;
968 cl_platform_id *platforms = NULL;
969 char* MAGICK_OCL_DEVICE = NULL;
970 MagickBooleanType OpenCLAvailable = MagickFalse;
972 #ifdef MAGICKCORE_CLPERFMARKER
973 clBeginPerfMarkerAMD(__FUNCTION__,"");
976 /* check if there's an environment variable overriding the device selection */
977 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
978 if (MAGICK_OCL_DEVICE != NULL)
980 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
982 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
984 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
986 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
988 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
990 /* OpenCL disabled */
994 else if (clEnv->deviceType == 0) {
995 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
998 if (clEnv->device != NULL)
1000 status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
1001 if (status != CL_SUCCESS) {
1002 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1003 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
1007 else if (clEnv->platform != NULL)
1010 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
1011 if (platforms == (cl_platform_id *) NULL)
1013 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
1014 "AcquireMagickMemory failed.",".");
1017 platforms[0] = clEnv->platform;
1021 clEnv->device = NULL;
1023 /* Get the number of OpenCL platforms available */
1024 status = clEnv->library->clGetPlatformIDs(0, NULL, &numPlatforms);
1025 if (status != CL_SUCCESS)
1027 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1028 "clGetplatformIDs failed.", "(%d)", status);
1032 /* No OpenCL available, just leave */
1033 if (numPlatforms == 0) {
1037 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
1038 if (platforms == (cl_platform_id *) NULL)
1040 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
1041 "AcquireMagickMemory failed.",".");
1045 status = clEnv->library->clGetPlatformIDs(numPlatforms, platforms, NULL);
1046 if (status != CL_SUCCESS)
1048 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1049 "clGetPlatformIDs failed.", "(%d)", status);
1054 /* Device selection */
1055 clEnv->device = NULL;
1056 for (j = 0; j < 2; j++)
1059 cl_device_type deviceType;
1060 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
1063 deviceType = CL_DEVICE_TYPE_GPU;
1065 deviceType = CL_DEVICE_TYPE_CPU;
1072 deviceType = clEnv->deviceType;
1074 for (i = 0; i < numPlatforms; i++)
1076 char version[MaxTextExtent];
1078 status = clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_VERSION, MaxTextExtent, version, NULL);
1079 if (status != CL_SUCCESS)
1081 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1082 "clGetPlatformInfo failed.", "(%d)", status);
1085 if (strncmp(version,"OpenCL 1.0 ",11) == 0)
1087 status = clEnv->library->clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
1088 if (status != CL_SUCCESS)
1090 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1091 "clGetDeviceIDs failed.", "(%d)", status);
1094 if (clEnv->device != NULL)
1096 clEnv->platform = platforms[i];
1103 if (platforms!=NULL)
1104 RelinquishMagickMemory(platforms);
1106 OpenCLAvailable = (clEnv->platform!=NULL
1107 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
1109 #ifdef MAGICKCORE_CLPERFMARKER
1110 clEndPerfMarkerAMD();
1113 return OpenCLAvailable;
1116 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
1117 if (clEnv->OpenCLInitialized != MagickFalse
1118 && clEnv->platform != NULL
1119 && clEnv->device != NULL) {
1120 clEnv->OpenCLDisabled = MagickFalse;
1123 clEnv->OpenCLDisabled = MagickTrue;
1128 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
1130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1134 + I n i t O p e n C L E n v %
1138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1140 % InitOpenCLEnv() initialize the OpenCL environment
1142 % The format of the RelinquishMagickOpenCLEnv method is:
1144 % MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
1146 % A description of each parameter follows:
1148 % o clEnv: OpenCL environment structure
1150 % o exception: return any errors or warnings.
1155 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
1156 MagickBooleanType status = MagickTrue;
1158 cl_context_properties cps[3];
1160 #ifdef MAGICKCORE_CLPERFMARKER
1162 int status = clInitializePerfMarkerAMD();
1163 if (status == AP_SUCCESS) {
1164 //printf("PerfMarker successfully initialized\n");
1168 clEnv->OpenCLInitialized = MagickTrue;
1170 /* check and init the global lib */
1171 OpenCLLib=GetOpenCLLib();
1174 clEnv->library=OpenCLLib;
1178 /* turn off opencl */
1179 MagickBooleanType flag;
1181 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
1182 , sizeof(MagickBooleanType), &flag, exception);
1185 if (clEnv->OpenCLDisabled != MagickFalse)
1188 clEnv->OpenCLDisabled = MagickTrue;
1189 /* setup the OpenCL platform and device */
1190 status = InitOpenCLPlatformDevice(clEnv, exception);
1191 if (status == MagickFalse) {
1192 /* No OpenCL device available */
1196 /* create an OpenCL context */
1197 cps[0] = CL_CONTEXT_PLATFORM;
1198 cps[1] = (cl_context_properties)clEnv->platform;
1200 clEnv->context = clEnv->library->clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
1201 if (clStatus != CL_SUCCESS)
1203 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1204 "clCreateContext failed.", "(%d)", clStatus);
1205 status = MagickFalse;
1209 status = CompileOpenCLKernels(clEnv, exception);
1210 if (status == MagickFalse) {
1211 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1212 "clCreateCommandQueue failed.", "(%d)", status);
1214 status = MagickFalse;
1218 status = EnableOpenCLInternal(clEnv);
1226 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1227 MagickBooleanType status = MagickFalse;
1232 #ifdef MAGICKCORE_CLPERFMARKER
1233 clBeginPerfMarkerAMD(__FUNCTION__,"");
1236 LockSemaphoreInfo(clEnv->lock);
1237 if (clEnv->OpenCLInitialized == MagickFalse) {
1238 if (clEnv->device==NULL
1239 && clEnv->OpenCLDisabled == MagickFalse)
1240 status = autoSelectDevice(clEnv, exception);
1242 status = InitOpenCLEnvInternal(clEnv, exception);
1244 UnlockSemaphoreInfo(clEnv->lock);
1246 #ifdef MAGICKCORE_CLPERFMARKER
1247 clEndPerfMarkerAMD();
1254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1258 + A c q u i r e O p e n C L C o m m a n d Q u e u e %
1262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1266 % The format of the AcquireOpenCLCommandQueue method is:
1268 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1270 % A description of each parameter follows:
1272 % o clEnv: the OpenCL environment.
1277 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1280 return clEnv->library->clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1291 + R e l i n q u i s h O p e n C L C o m m a n d Q u e u e %
1295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1297 % RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1299 % The format of the RelinquishOpenCLCommandQueue method is:
1301 % MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1302 % cl_command_queue queue)
1304 % A description of each parameter follows:
1306 % o clEnv: the OpenCL environment.
1308 % o queue: the OpenCL queue to be released.
1313 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1317 return ((clEnv->library->clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1330 + A c q u i r e O p e n C L K e r n e l %
1334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336 % AcquireOpenCLKernel() acquires an OpenCL kernel
1338 % The format of the AcquireOpenCLKernel method is:
1340 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
1341 % MagickOpenCLProgram program, const char* kernelName)
1343 % A description of each parameter follows:
1345 % o clEnv: the OpenCL environment.
1347 % o program: the OpenCL program module that the kernel belongs to.
1349 % o kernelName: the name of the kernel
1354 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1357 cl_kernel kernel = NULL;
1358 if (clEnv != NULL && kernelName!=NULL)
1360 kernel = clEnv->library->clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1367 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371 + R e l i n q u i s h O p e n C L K e r n e l %
1375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1377 % RelinquishOpenCLKernel() releases an OpenCL kernel
1379 % The format of the RelinquishOpenCLKernel method is:
1381 % MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1384 % A description of each parameter follows:
1386 % o clEnv: the OpenCL environment.
1388 % o kernel: the OpenCL kernel object to be released.
1394 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1396 MagickBooleanType status = MagickFalse;
1397 if (clEnv != NULL && kernel != NULL)
1399 status = ((clEnv->library->clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409 + G e t O p e n C L D e v i c e L o c a l M e m o r y S i z e %
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415 % GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1417 % The format of the GetOpenCLDeviceLocalMemorySize method is:
1419 % unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1421 % A description of each parameter follows:
1423 % o clEnv: the OpenCL environment.
1429 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1431 cl_ulong localMemorySize;
1432 clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1433 return (unsigned long)localMemorySize;
1437 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1439 cl_ulong maxMemAllocSize;
1440 clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1441 return (unsigned long)maxMemAllocSize;
1446 Beginning of the OpenCL device selection infrastructure
1452 ,DS_INVALID_PROFILE = 1000
1454 ,DS_INVALID_PERF_EVALUATOR_TYPE
1455 ,DS_INVALID_PERF_EVALUATOR
1456 ,DS_PERF_EVALUATOR_ERROR
1458 ,DS_UNKNOWN_DEVICE_TYPE
1459 ,DS_PROFILE_FILE_ERROR
1460 ,DS_SCORE_SERIALIZER_ERROR
1461 ,DS_SCORE_DESERIALIZER_ERROR
1466 DS_DEVICE_NATIVE_CPU = 0
1467 ,DS_DEVICE_OPENCL_DEVICE
1472 ds_device_type type;
1473 cl_device_type oclDeviceType;
1474 cl_device_id oclDeviceID;
1475 char* oclDeviceName;
1476 char* oclDriverVersion;
1477 cl_uint oclMaxClockFrequency;
1478 cl_uint oclMaxComputeUnits;
1479 void* score; /* a pointer to the score data, the content/format is application defined */
1483 unsigned int numDevices;
1485 const char* version;
1488 /* deallocate memory used by score */
1489 typedef ds_status (*ds_score_release)(void* score);
1491 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1492 ds_status status = DS_SUCCESS;
1494 if (device->oclDeviceName) free(device->oclDeviceName);
1495 if (device->oclDriverVersion) free(device->oclDriverVersion);
1496 if (device->score) status = sr(device->score);
1501 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1502 ds_status status = DS_SUCCESS;
1503 if (profile!=NULL) {
1504 if (profile->devices!=NULL && sr!=NULL) {
1506 for (i = 0; i < profile->numDevices; i++) {
1507 status = releaseDeviceResource(profile->devices+i,sr);
1508 if (status != DS_SUCCESS)
1511 free(profile->devices);
1519 static ds_status initDSProfile(ds_profile** p, const char* version) {
1521 cl_uint numPlatforms = 0;
1522 cl_platform_id* platforms = NULL;
1523 cl_device_id* devices = NULL;
1524 ds_status status = DS_SUCCESS;
1525 ds_profile* profile = NULL;
1526 unsigned int next = 0;
1530 return DS_INVALID_PROFILE;
1532 profile = (ds_profile*)malloc(sizeof(ds_profile));
1533 if (profile == NULL)
1534 return DS_MEMORY_ERROR;
1536 memset(profile, 0, sizeof(ds_profile));
1538 OpenCLLib->clGetPlatformIDs(0, NULL, &numPlatforms);
1539 if (numPlatforms > 0) {
1540 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1541 if (platforms == NULL) {
1542 status = DS_MEMORY_ERROR;
1545 OpenCLLib->clGetPlatformIDs(numPlatforms, platforms, NULL);
1546 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1548 if (OpenCLLib->clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num) == CL_SUCCESS)
1553 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1555 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1556 if (profile->devices == NULL) {
1557 profile->numDevices = 0;
1558 status = DS_MEMORY_ERROR;
1561 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1563 if (numDevices > 0) {
1564 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1565 if (devices == NULL) {
1566 status = DS_MEMORY_ERROR;
1569 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1573 for (d = 0; d < 2; d++) {
1575 cl_device_type deviceType;
1578 deviceType = CL_DEVICE_TYPE_GPU;
1581 deviceType = CL_DEVICE_TYPE_CPU;
1587 if (OpenCLLib->clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
1589 for (j = 0; j < num; j++, next++) {
1592 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1593 profile->devices[next].oclDeviceID = devices[j];
1595 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1596 , 0, NULL, &length);
1597 profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
1598 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1599 , length, profile->devices[next].oclDeviceName, NULL);
1601 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1602 , 0, NULL, &length);
1603 profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
1604 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1605 , length, profile->devices[next].oclDriverVersion, NULL);
1607 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1608 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1610 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1611 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1613 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_TYPE
1614 , sizeof(cl_device_type), &profile->devices[next].oclDeviceType, NULL);
1620 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1621 profile->version = version;
1624 if (platforms) free(platforms);
1625 if (devices) free(devices);
1626 if (status == DS_SUCCESS) {
1631 if (profile->devices)
1632 free(profile->devices);
1639 /* Pointer to a function that calculates the score of a device (ex: device->score)
1640 update the data size of score. The encoding and the format of the score data
1641 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1643 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1647 ,DS_EVALUATE_NEW_ONLY
1648 } ds_evaluation_type;
1650 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1651 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1652 ds_status status = DS_SUCCESS;
1654 unsigned int updates = 0;
1656 if (profile == NULL) {
1657 return DS_INVALID_PROFILE;
1659 if (evaluator == NULL) {
1660 return DS_INVALID_PERF_EVALUATOR;
1663 for (i = 0; i < profile->numDevices; i++) {
1664 ds_status evaluatorStatus;
1667 case DS_EVALUATE_NEW_ONLY:
1668 if (profile->devices[i].score != NULL)
1670 /* else fall through */
1671 case DS_EVALUATE_ALL:
1672 evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
1673 if (evaluatorStatus != DS_SUCCESS) {
1674 status = evaluatorStatus;
1680 return DS_INVALID_PERF_EVALUATOR_TYPE;
1685 *numUpdates = updates;
1690 #define DS_TAG_VERSION "<version>"
1691 #define DS_TAG_VERSION_END "</version>"
1692 #define DS_TAG_DEVICE "<device>"
1693 #define DS_TAG_DEVICE_END "</device>"
1694 #define DS_TAG_SCORE "<score>"
1695 #define DS_TAG_SCORE_END "</score>"
1696 #define DS_TAG_DEVICE_TYPE "<type>"
1697 #define DS_TAG_DEVICE_TYPE_END "</type>"
1698 #define DS_TAG_DEVICE_NAME "<name>"
1699 #define DS_TAG_DEVICE_NAME_END "</name>"
1700 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1701 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1702 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1703 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1704 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1705 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1707 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1711 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1712 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1713 ds_status status = DS_SUCCESS;
1714 FILE* profileFile = NULL;
1717 if (profile == NULL)
1718 return DS_INVALID_PROFILE;
1720 profileFile = fopen(file, "wb");
1721 if (profileFile==NULL) {
1722 status = DS_FILE_ERROR;
1727 /* write version string */
1728 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1729 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1730 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1731 fwrite("\n", sizeof(char), 1, profileFile);
1733 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1734 void* serializedScore;
1735 unsigned int serializedScoreSize;
1737 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1739 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1740 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1741 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1743 switch(profile->devices[i].type) {
1744 case DS_DEVICE_NATIVE_CPU:
1746 /* There's no need to emit a device name for the native CPU device. */
1748 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1749 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1750 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1754 case DS_DEVICE_OPENCL_DEVICE:
1758 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1759 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1760 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1762 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1763 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1764 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1766 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1767 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1768 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1769 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1771 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1772 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1773 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1774 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1778 status = DS_UNKNOWN_DEVICE_TYPE;
1782 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1783 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1784 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1785 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1786 free(serializedScore);
1788 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1789 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1790 fwrite("\n",sizeof(char),1,profileFile);
1792 fclose(profileFile);
1798 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1799 ds_status status = DS_SUCCESS;
1800 FILE * input = NULL;
1803 char* binary = NULL;
1808 input = fopen(fileName, "rb");
1810 return DS_FILE_ERROR;
1813 fseek(input, 0L, SEEK_END);
1814 size = ftell(input);
1816 binary = (char*)malloc(size);
1817 if(binary == NULL) {
1818 status = DS_FILE_ERROR;
1821 rsize = fread(binary, sizeof(char), size, input);
1824 status = DS_FILE_ERROR;
1827 *contentSize = size;
1831 if (input != NULL) fclose(input);
1832 if (status != DS_SUCCESS
1833 && binary != NULL) {
1842 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1843 size_t stringLength;
1844 const char* currentPosition;
1847 stringLength = strlen(string);
1848 currentPosition = contentStart;
1849 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1850 if (*currentPosition == string[0]) {
1851 if (currentPosition+stringLength < contentEnd) {
1852 if (strncmp(currentPosition, string, stringLength) == 0) {
1853 found = currentPosition;
1863 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1864 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1866 ds_status status = DS_SUCCESS;
1867 char* contentStart = NULL;
1868 const char* contentEnd = NULL;
1872 return DS_INVALID_PROFILE;
1874 status = readProFile(file, &contentStart, &contentSize);
1875 if (status == DS_SUCCESS) {
1876 const char* currentPosition;
1877 const char* dataStart;
1878 const char* dataEnd;
1879 size_t versionStringLength;
1881 contentEnd = contentStart + contentSize;
1882 currentPosition = contentStart;
1885 /* parse the version string */
1886 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1887 if (dataStart == NULL) {
1888 status = DS_PROFILE_FILE_ERROR;
1891 dataStart += strlen(DS_TAG_VERSION);
1893 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1894 if (dataEnd==NULL) {
1895 status = DS_PROFILE_FILE_ERROR;
1899 versionStringLength = strlen(profile->version);
1900 if (versionStringLength!=(size_t)(dataEnd-dataStart)
1901 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1902 /* version mismatch */
1903 status = DS_PROFILE_FILE_ERROR;
1906 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1908 /* parse the device information */
1909 DisableMSCWarning(4127)
1914 const char* deviceTypeStart;
1915 const char* deviceTypeEnd;
1916 ds_device_type deviceType;
1918 const char* deviceNameStart;
1919 const char* deviceNameEnd;
1921 const char* deviceScoreStart;
1922 const char* deviceScoreEnd;
1924 const char* deviceDriverStart;
1925 const char* deviceDriverEnd;
1927 const char* tmpStart;
1931 cl_uint maxClockFrequency;
1932 cl_uint maxComputeUnits;
1934 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1935 if (dataStart==NULL) {
1936 /* nothing useful remain, quit...*/
1939 dataStart+=strlen(DS_TAG_DEVICE);
1940 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1941 if (dataEnd==NULL) {
1942 status = DS_PROFILE_FILE_ERROR;
1946 /* parse the device type */
1947 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1948 if (deviceTypeStart==NULL) {
1949 status = DS_PROFILE_FILE_ERROR;
1952 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1953 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1954 if (deviceTypeEnd==NULL) {
1955 status = DS_PROFILE_FILE_ERROR;
1958 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1961 /* parse the device name */
1962 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1964 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1965 if (deviceNameStart==NULL) {
1966 status = DS_PROFILE_FILE_ERROR;
1969 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1970 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1971 if (deviceNameEnd==NULL) {
1972 status = DS_PROFILE_FILE_ERROR;
1977 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1978 if (deviceDriverStart==NULL) {
1979 status = DS_PROFILE_FILE_ERROR;
1982 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1983 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1984 if (deviceDriverEnd ==NULL) {
1985 status = DS_PROFILE_FILE_ERROR;
1990 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1991 if (tmpStart==NULL) {
1992 status = DS_PROFILE_FILE_ERROR;
1995 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1996 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1997 if (tmpEnd ==NULL) {
1998 status = DS_PROFILE_FILE_ERROR;
2001 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
2002 tmp[tmpEnd-tmpStart] = '\0';
2003 maxComputeUnits = atoi(tmp);
2006 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
2007 if (tmpStart==NULL) {
2008 status = DS_PROFILE_FILE_ERROR;
2011 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
2012 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
2013 if (tmpEnd ==NULL) {
2014 status = DS_PROFILE_FILE_ERROR;
2017 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
2018 tmp[tmpEnd-tmpStart] = '\0';
2019 maxClockFrequency = atoi(tmp);
2022 /* check if this device is on the system */
2023 for (i = 0; i < profile->numDevices; i++) {
2024 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
2025 size_t actualDeviceNameLength;
2026 size_t driverVersionLength;
2028 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
2029 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
2030 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
2031 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
2032 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
2033 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
2034 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
2035 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
2037 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
2038 if (deviceNameStart==NULL) {
2039 status = DS_PROFILE_FILE_ERROR;
2042 deviceScoreStart+=strlen(DS_TAG_SCORE);
2043 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
2044 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
2045 if (status != DS_SUCCESS) {
2053 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
2054 for (i = 0; i < profile->numDevices; i++) {
2055 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
2056 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
2057 if (deviceScoreStart==NULL) {
2058 status = DS_PROFILE_FILE_ERROR;
2061 deviceScoreStart+=strlen(DS_TAG_SCORE);
2062 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
2063 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
2064 if (status != DS_SUCCESS) {
2071 /* skip over the current one to find the next device */
2072 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
2076 if (contentStart!=NULL) free(contentStart);
2082 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
2084 if (profile == NULL || num==NULL)
2085 return DS_MEMORY_ERROR;
2087 for (i = 0; i < profile->numDevices; i++) {
2088 if (profile->devices[i].score == NULL) {
2097 End of the OpenCL device selection infrastructure
2101 typedef double AccelerateScoreType;
2103 static ds_status AcceleratePerfEvaluator(ds_device *device,
2104 void *magick_unused(data))
2106 #define ACCELERATE_PERF_DIMEN "2048x1536"
2108 #define ReturnStatus(status) \
2111 RelinquishMagickOpenCLEnv(clEnv); \
2112 if (oldClEnv!=NULL) \
2113 defaultCLEnv = oldClEnv; \
2127 magick_unreferenced(data);
2130 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2132 clEnv=AcquireMagickOpenCLEnv();
2133 exception=AcquireExceptionInfo();
2135 if (device->type == DS_DEVICE_NATIVE_CPU)
2138 MagickBooleanType flag=MagickTrue;
2139 SetMagickOpenCLEnvParamInternal(clEnv,
2140 MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
2143 else if (device->type == DS_DEVICE_OPENCL_DEVICE)
2146 SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
2147 sizeof(cl_device_id),&device->oclDeviceID,exception);
2150 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2152 /* recompile the OpenCL kernels if it needs to */
2153 clEnv->disableProgramCache = defaultCLEnv->disableProgramCache;
2155 InitOpenCLEnvInternal(clEnv,exception);
2156 oldClEnv=defaultCLEnv;
2159 /* microbenchmark */
2170 imageInfo=AcquireImageInfo();
2171 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
2172 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
2173 inputImage=ReadImage(imageInfo,exception);
2175 initAccelerateTimer(&timer);
2177 for (i=0; i<=NUM_ITER; i++)
2185 startAccelerateTimer(&timer);
2187 #ifdef MAGICKCORE_CLPERFMARKER
2188 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2191 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2192 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2194 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
2197 #ifdef MAGICKCORE_CLPERFMARKER
2198 clEndPerfMarkerAMD();
2202 stopAccelerateTimer(&timer);
2205 DestroyImage(bluredImage);
2207 DestroyImage(unsharpedImage);
2209 DestroyImage(resizedImage);
2211 DestroyImage(inputImage);
2213 /* end of microbenchmark */
2215 if (device->score == NULL)
2216 device->score=malloc(sizeof(AccelerateScoreType));
2217 *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
2219 ReturnStatus(DS_SUCCESS);
2222 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2225 /* generate a string from the score */
2226 char* s = (char*)malloc(sizeof(char)*256);
2227 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2228 *serializedScore = (void*)s;
2229 *serializedScoreSize = (unsigned int) strlen(s);
2233 return DS_SCORE_SERIALIZER_ERROR;
2237 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2239 /* convert the string back to an int */
2240 char* s = (char*)malloc(serializedScoreSize+1);
2241 memcpy(s, serializedScore, serializedScoreSize);
2242 s[serializedScoreSize] = (char)'\0';
2243 device->score = malloc(sizeof(AccelerateScoreType));
2244 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2249 return DS_SCORE_DESERIALIZER_ERROR;
2253 ds_status AccelerateScoreRelease(void* score) {
2260 ds_status canWriteProfileToFile(const char *path)
2262 FILE* profileFile = fopen(path, "ab");
2264 if (profileFile==NULL)
2265 return DS_FILE_ERROR;
2267 fclose(profileFile);
2271 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2272 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2273 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2275 MagickBooleanType mStatus = MagickFalse;
2277 ds_profile* profile;
2278 unsigned int numDeviceProfiled = 0;
2280 unsigned int bestDeviceIndex;
2281 AccelerateScoreType bestScore;
2282 char path[MaxTextExtent];
2283 MagickBooleanType flag;
2284 ds_evaluation_type profileType;
2286 LockDefaultOpenCLEnv();
2288 /* Initially, just set OpenCL to off */
2290 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2291 , sizeof(MagickBooleanType), &flag, exception);
2293 /* check and init the global lib */
2294 OpenCLLib=GetOpenCLLib();
2295 if (OpenCLLib==NULL)
2297 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2301 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2302 if (status!=DS_SUCCESS) {
2303 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2307 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2308 ,GetOpenCLCachedFilesDirectory()
2309 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2311 if (canWriteProfileToFile(path) != DS_SUCCESS) {
2312 /* We can not write out a device profile, so don't run the benchmark */
2313 /* select the first GPU device */
2315 bestDeviceIndex = 0;
2316 for (i = 1; i < profile->numDevices; i++) {
2317 if ((profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) && (profile->devices[i].oclDeviceType == CL_DEVICE_TYPE_GPU)) {
2318 bestDeviceIndex = i;
2324 if (clEnv->regenerateProfile != MagickFalse) {
2325 profileType = DS_EVALUATE_ALL;
2328 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2329 profileType = DS_EVALUATE_NEW_ONLY;
2331 status = profileDevices(profile, profileType, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2333 if (status!=DS_SUCCESS) {
2334 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2337 if (numDeviceProfiled > 0) {
2338 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2339 if (status!=DS_SUCCESS) {
2340 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2344 /* pick the best device */
2345 bestDeviceIndex = 0;
2346 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2347 for (i = 1; i < profile->numDevices; i++) {
2348 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2349 if (score < bestScore) {
2350 bestDeviceIndex = i;
2356 /* set up clEnv with the best device */
2357 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2360 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2361 , sizeof(MagickBooleanType), &flag, exception);
2363 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2366 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2367 , sizeof(MagickBooleanType), &flag, exception);
2368 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2369 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2372 status = DS_PERF_EVALUATOR_ERROR;
2375 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2377 status = releaseDSProfile(profile, AccelerateScoreRelease);
2378 if (status!=DS_SUCCESS) {
2379 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2384 UnlockDefaultOpenCLEnv();
2390 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2394 + I n i t I m a g e M a g i c k O p e n C L %
2398 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2400 % InitImageMagickOpenCL() provides a simplified interface to initialize
2401 % the OpenCL environtment in ImageMagick
2403 % The format of the InitImageMagickOpenCL() method is:
2405 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2406 % void* userSelectedDevice,
2407 % void* selectedDevice)
2409 % A description of each parameter follows:
2411 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2413 % o userSelectedDevice: when in user mode, a pointer to the selected
2416 % o selectedDevice: a pointer to cl_device_id where the selected
2417 % cl_device_id by ImageMagick could be returned
2419 % o exception: exception
2422 MagickExport MagickBooleanType InitImageMagickOpenCL(
2423 ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2424 ExceptionInfo *exception)
2426 MagickBooleanType status = MagickFalse;
2427 MagickCLEnv clEnv = NULL;
2428 MagickBooleanType flag;
2430 clEnv = GetDefaultOpenCLEnv();
2434 case MAGICK_OPENCL_OFF:
2436 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2437 , sizeof(MagickBooleanType), &flag, exception);
2438 status = InitOpenCLEnv(clEnv, exception);
2441 *(cl_device_id*)selectedDevice = NULL;
2444 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2446 if (userSelectedDevice == NULL)
2450 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2451 , sizeof(MagickBooleanType), &flag, exception);
2453 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2454 , sizeof(cl_device_id), userSelectedDevice,exception);
2456 status = InitOpenCLEnv(clEnv, exception);
2457 if (selectedDevice) {
2458 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2459 , sizeof(cl_device_id), selectedDevice, exception);
2463 case MAGICK_OPENCL_DEVICE_SELECT_AUTO_CLEAR_CACHE:
2465 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED
2466 , sizeof(MagickBooleanType), &flag, exception);
2468 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE
2469 , sizeof(MagickBooleanType), &flag, exception);
2471 /* fall through here!! */
2472 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2475 cl_device_id d = NULL;
2477 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2478 , sizeof(MagickBooleanType), &flag, exception);
2479 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2480 , sizeof(cl_device_id), &d,exception);
2481 status = InitOpenCLEnv(clEnv, exception);
2482 if (selectedDevice) {
2483 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2484 , sizeof(cl_device_id), selectedDevice, exception);
2495 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2496 const char *module,const char *function,const size_t line,
2497 const ExceptionType severity,const char *tag,const char *format,...) {
2503 status = MagickTrue;
2505 clEnv = GetDefaultOpenCLEnv();
2507 assert(exception != (ExceptionInfo *) NULL);
2508 assert(exception->signature == MagickSignature);
2511 cl_device_type dType;
2512 clEnv->library->clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
2513 if (dType == CL_DEVICE_TYPE_CPU) {
2514 char buffer[MaxTextExtent];
2515 clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
2517 /* Workaround for Intel OpenCL CPU runtime bug */
2518 /* Turn off OpenCL when a problem is detected! */
2519 if (strncmp(buffer, "Intel",5) == 0) {
2521 InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2526 #ifdef OPENCLLOG_ENABLED
2530 va_start(operands,format);
2531 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2535 magick_unreferenced(module);
2536 magick_unreferenced(function);
2537 magick_unreferenced(line);
2538 magick_unreferenced(tag);
2539 magick_unreferenced(format);
2545 MagickPrivate cl_mem GetAndLockRandSeedBuffer(MagickCLEnv clEnv)
2547 LockSemaphoreInfo(clEnv->lock);
2548 if (clEnv->seedsLock == NULL)
2550 ActivateSemaphoreInfo(&clEnv->seedsLock);
2552 LockSemaphoreInfo(clEnv->seedsLock);
2554 if (clEnv->seeds == NULL)
2557 clEnv->numGenerators = NUM_CL_RAND_GENERATORS;
2558 clEnv->seeds = clEnv->library->clCreateBuffer(clEnv->context, CL_MEM_READ_WRITE,
2559 clEnv->numGenerators*4*sizeof(unsigned int),
2561 if (clStatus != CL_SUCCESS)
2563 clEnv->seeds = NULL;
2568 cl_command_queue queue = NULL;
2569 unsigned int *seeds;
2571 queue = AcquireOpenCLCommandQueue(clEnv);
2572 seeds = (unsigned int*) clEnv->library->clEnqueueMapBuffer(queue, clEnv->seeds, CL_TRUE,
2574 clEnv->numGenerators*4
2575 *sizeof(unsigned int),
2576 0, NULL, NULL, &clStatus);
2577 if (clStatus!=CL_SUCCESS)
2579 clEnv->library->clReleaseMemObject(clEnv->seeds);
2583 for (i = 0; i < clEnv->numGenerators; i++) {
2584 RandomInfo* randomInfo = AcquireRandomInfo();
2585 const unsigned long* s = GetRandomInfoSeed(randomInfo);
2587 clEnv->randNormalize = GetRandomInfoNormalize(randomInfo);
2589 seeds[i*4] = (unsigned int) s[0];
2590 seeds[i*4+1] = (unsigned int) 0x50a7f451;
2591 seeds[i*4+2] = (unsigned int) 0x5365417e;
2592 seeds[i*4+3] = (unsigned int) 0xc3a4171a;
2594 randomInfo = DestroyRandomInfo(randomInfo);
2596 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, clEnv->seeds, seeds, 0,
2598 clEnv->library->clFinish(queue);
2601 RelinquishOpenCLCommandQueue(clEnv, queue);
2604 UnlockSemaphoreInfo(clEnv->lock);
2605 return clEnv->seeds;
2608 MagickPrivate void UnlockRandSeedBuffer(MagickCLEnv clEnv) {
2609 if (clEnv->seedsLock == NULL)
2611 ActivateSemaphoreInfo(&clEnv->seedsLock);
2614 UnlockSemaphoreInfo(clEnv->seedsLock);
2617 MagickPrivate unsigned int GetNumRandGenerators(MagickCLEnv clEnv)
2619 return clEnv->numGenerators;
2623 MagickPrivate float GetRandNormalize(MagickCLEnv clEnv)
2625 return clEnv->randNormalize;
2630 struct _MagickCLEnv {
2631 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2634 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2639 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2640 MagickCLEnv magick_unused(clEnv))
2642 magick_unreferenced(clEnv);
2648 * Return the OpenCL environment
2650 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2651 ExceptionInfo *magick_unused(exception))
2653 magick_unreferenced(exception);
2655 return (MagickCLEnv) NULL;
2658 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2659 MagickCLEnv magick_unused(clEnv))
2661 magick_unreferenced(clEnv);
2663 return (MagickCLEnv) NULL;
2666 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2667 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2668 size_t magick_unused(dataSize),void *magick_unused(data),
2669 ExceptionInfo *magick_unused(exception))
2671 magick_unreferenced(clEnv);
2672 magick_unreferenced(param);
2673 magick_unreferenced(dataSize);
2674 magick_unreferenced(data);
2675 magick_unreferenced(exception);
2680 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2681 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2682 size_t magick_unused(dataSize),void *magick_unused(data),
2683 ExceptionInfo *magick_unused(exception))
2685 magick_unreferenced(clEnv);
2686 magick_unreferenced(param);
2687 magick_unreferenced(dataSize);
2688 magick_unreferenced(data);
2689 magick_unreferenced(exception);
2694 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2695 ExceptionInfo *magick_unused(exception))
2697 magick_unreferenced(clEnv);
2698 magick_unreferenced(exception);
2703 MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(
2704 MagickCLEnv magick_unused(clEnv))
2706 magick_unreferenced(clEnv);
2708 return (cl_command_queue) NULL;
2711 MagickPrivate MagickBooleanType RelinquishCommandQueue(
2712 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2714 magick_unreferenced(clEnv);
2715 magick_unreferenced(queue);
2720 MagickPrivate cl_kernel AcquireOpenCLKernel(
2721 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2722 const char *magick_unused(kernelName))
2724 magick_unreferenced(clEnv);
2725 magick_unreferenced(program);
2726 magick_unreferenced(kernelName);
2728 return (cl_kernel)NULL;
2731 MagickPrivate MagickBooleanType RelinquishOpenCLKernel(
2732 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2734 magick_unreferenced(clEnv);
2735 magick_unreferenced(kernel);
2740 MagickPrivate unsigned long GetOpenCLDeviceLocalMemorySize(
2741 MagickCLEnv magick_unused(clEnv))
2743 magick_unreferenced(clEnv);
2748 MagickExport MagickBooleanType InitImageMagickOpenCL(
2749 ImageMagickOpenCLMode magick_unused(mode),
2750 void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2751 ExceptionInfo *magick_unused(exception))
2753 magick_unreferenced(mode);
2754 magick_unreferenced(userSelectedDevice);
2755 magick_unreferenced(selectedDevice);
2756 magick_unreferenced(exception);
2762 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2763 const char *module,const char *function,const size_t line,
2764 const ExceptionType severity,const char *tag,const char *format,...)
2766 magick_unreferenced(exception);
2767 magick_unreferenced(module);
2768 magick_unreferenced(function);
2769 magick_unreferenced(line);
2770 magick_unreferenced(severity);
2771 magick_unreferenced(tag);
2772 magick_unreferenced(format);
2773 return(MagickFalse);
2777 MagickPrivate cl_mem GetAndLockRandSeedBuffer(MagickCLEnv clEnv)
2779 magick_unreferenced(clEnv);
2784 MagickPrivate void UnlockRandSeedBuffer(MagickCLEnv clEnv)
2786 magick_unreferenced(clEnv);
2789 MagickPrivate unsigned int GetNumRandGenerators(MagickCLEnv clEnv)
2791 magick_unreferenced(clEnv);
2795 MagickPrivate float GetRandNormalize(MagickCLEnv clEnv)
2797 magick_unreferenced(clEnv);
2801 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2803 char* openclCachedFilesDirectory;
2804 SemaphoreInfo* openclCachedFilesDirectoryLock;
2807 const char* GetOpenCLCachedFilesDirectory() {
2808 if (openclCachedFilesDirectory == NULL) {
2809 if (openclCachedFilesDirectoryLock == NULL)
2811 ActivateSemaphoreInfo(&openclCachedFilesDirectoryLock);
2813 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2814 if (openclCachedFilesDirectory == NULL) {
2815 char path[MaxTextExtent];
2818 struct stat attributes;
2819 MagickBooleanType status;
2823 home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
2824 if (home == (char *) NULL)
2826 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2827 home=GetEnvironmentValue("LOCALAPPDATA");
2828 if (home == (char *) NULL)
2829 home=GetEnvironmentValue("APPDATA");
2830 if (home == (char *) NULL)
2831 home=GetEnvironmentValue("USERPROFILE");
2833 home=GetEnvironmentValue("HOME");
2837 if (home != (char *) NULL)
2839 int mkdirStatus = 0;
2843 /* first check if $HOME/.config exists */
2844 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.config",
2845 home,DirectorySeparator);
2846 status=GetPathAttributes(path,&attributes);
2847 if (status == MagickFalse)
2850 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2851 mkdirStatus = mkdir(path);
2853 mkdirStatus = mkdir(path, 0777);
2857 /* first check if $HOME/.config/ImageMagick exists */
2860 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.config%sImageMagick",
2861 home,DirectorySeparator,DirectorySeparator);
2863 status=GetPathAttributes(path,&attributes);
2864 if (status == MagickFalse)
2866 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2867 mkdirStatus = mkdir(path);
2869 mkdirStatus = mkdir(path, 0777);
2876 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2877 CopyMagickString(temp,path,strlen(path)+1);
2879 home=DestroyString(home);
2881 openclCachedFilesDirectory = temp;
2883 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2885 return openclCachedFilesDirectory;
2888 void startAccelerateTimer(AccelerateTimer* timer) {
2890 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
2895 gettimeofday(&s, 0);
2896 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
2900 void stopAccelerateTimer(AccelerateTimer* timer) {
2903 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
2906 gettimeofday(&s, 0);
2907 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
2911 timer->_clocks += n;
2914 void resetAccelerateTimer(AccelerateTimer* timer) {
2920 void initAccelerateTimer(AccelerateTimer* timer) {
2922 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
2924 timer->_freq = (long long)1.0E3;
2926 resetAccelerateTimer(timer);
2929 double readAccelerateTimer(AccelerateTimer* timer) {
2930 return (double)timer->_clocks/(double)timer->_freq;
2934 /* create a function for OpenCL log */
2936 void OpenCLLog(const char* message) {
2938 #ifdef OPENCLLOG_ENABLED
2939 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2942 if (getenv("MAGICK_OCL_LOG"))
2945 char path[MaxTextExtent];
2946 unsigned long allocSize;
2950 clEnv = GetDefaultOpenCLEnv();
2952 /* dump the source into a file */
2953 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2954 ,GetOpenCLCachedFilesDirectory()
2955 ,DirectorySeparator,OPENCL_LOG_FILE);
2958 log = fopen(path, "ab");
2959 fwrite(message, sizeof(char), strlen(message), log);
2960 fwrite("\n", sizeof(char), 1, log);
2962 if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
2964 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
2965 fprintf(log, "Devic Max Memory Alloc Size: %ld\n", allocSize);
2972 magick_unreferenced(message);