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-2014 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/resample.h"
75 #include "MagickCore/resource_.h"
76 #include "MagickCore/splay-tree.h"
77 #include "MagickCore/semaphore.h"
78 #include "MagickCore/statistic.h"
79 #include "MagickCore/string_.h"
80 #include "MagickCore/token.h"
81 #include "MagickCore/utility.h"
83 #ifdef MAGICKCORE_CLPERFMARKER
84 #include "CLPerfMarker.h"
88 #if defined(MAGICKCORE_OPENCL_SUPPORT)
91 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
92 MagickBooleanType OpenCLDisabled; /* whether if OpenCL has been explicitely disabled. */
95 cl_platform_id platform;
96 cl_device_type deviceType;
100 MagickBooleanType disableProgramCache; /* disable the OpenCL program cache */
101 cl_program programs[MAGICK_OPENCL_NUM_PROGRAMS]; /* one program object maps one kernel source file */
103 MagickBooleanType regenerateProfile; /* re-run the microbenchmark in auto device selection mode */
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 + A c q u i r e M a g i c k O p e n C L E n v %
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119 % AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure
123 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
126 clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
129 memset(clEnv, 0, sizeof(struct _MagickCLEnv));
130 ActivateSemaphoreInfo(&clEnv->lock);
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
141 + 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 %
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147 % RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
149 % The format of the RelinquishMagickOpenCLEnv method is:
151 % MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
153 % A description of each parameter follows:
155 % o clEnv: MagickCLEnv structure to destroy
159 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
161 if (clEnv != (MagickCLEnv)NULL)
163 RelinquishSemaphoreInfo(clEnv->lock);
164 RelinquishMagickMemory(clEnv);
172 * Default OpenCL environment
174 MagickCLEnv defaultCLEnv;
175 SemaphoreInfo* defaultCLEnvLock;
179 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
183 + G e t D e f a u l t O p e n C L E n v %
187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189 % GetDefaultOpenCLEnv() returns the default OpenCL env
191 % The format of the GetDefaultOpenCLEnv method is:
193 % MagickCLEnv GetDefaultOpenCLEnv()
195 % A description of each parameter follows:
197 % o exception: return any errors or warnings.
201 MagickExport MagickCLEnv GetDefaultOpenCLEnv()
203 if (defaultCLEnv == NULL)
205 if (defaultCLEnvLock == NULL)
207 ActivateSemaphoreInfo(&defaultCLEnvLock);
209 LockSemaphoreInfo(defaultCLEnvLock);
210 defaultCLEnv = AcquireMagickOpenCLEnv();
211 UnlockSemaphoreInfo(defaultCLEnvLock);
216 static void LockDefaultOpenCLEnv() {
217 if (defaultCLEnvLock == NULL)
219 ActivateSemaphoreInfo(&defaultCLEnvLock);
221 LockSemaphoreInfo(defaultCLEnvLock);
224 static void UnlockDefaultOpenCLEnv() {
225 if (defaultCLEnvLock == NULL)
227 ActivateSemaphoreInfo(&defaultCLEnvLock);
230 UnlockSemaphoreInfo(defaultCLEnvLock);
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239 + S e t D e f a u l t O p e n C L E n v %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245 % SetDefaultOpenCLEnv() sets the new OpenCL environment as default
246 % and returns the old OpenCL environment
248 % The format of the SetDefaultOpenCLEnv() method is:
250 % MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
252 % A description of each parameter follows:
254 % o clEnv: the new default OpenCL environment.
257 MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
260 LockDefaultOpenCLEnv();
261 oldEnv = defaultCLEnv;
262 defaultCLEnv = clEnv;
263 UnlockDefaultOpenCLEnv();
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 + S e t M a g i c k O p e n C L E n v P a r a m %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 % SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
282 % The format of the SetMagickOpenCLEnvParam() method is:
284 % MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
285 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
286 % ExceptionInfo* exception)
288 % A description of each parameter follows:
290 % o clEnv: the OpenCL environment.
292 % o param: the parameter to be set.
294 % o dataSize: the data size of the parameter value.
296 % o data: the pointer to the new parameter value
298 % o exception: return any errors or warnings
302 static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
303 , size_t dataSize, void* data, ExceptionInfo* exception)
305 MagickBooleanType status = MagickFalse;
313 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
314 if (dataSize != sizeof(clEnv->device))
316 clEnv->device = *((cl_device_id*)data);
317 clEnv->OpenCLInitialized = MagickFalse;
321 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
322 if (dataSize != sizeof(clEnv->OpenCLDisabled))
324 clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
325 clEnv->OpenCLInitialized = MagickFalse;
329 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
330 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
333 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
334 if (dataSize != sizeof(clEnv->disableProgramCache))
336 clEnv->disableProgramCache = *((MagickBooleanType*)data);
337 clEnv->OpenCLInitialized = MagickFalse;
341 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
342 if (dataSize != sizeof(clEnv->regenerateProfile))
344 clEnv->regenerateProfile = *((MagickBooleanType*)data);
345 clEnv->OpenCLInitialized = MagickFalse;
358 MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
359 , size_t dataSize, void* data, ExceptionInfo* exception) {
360 MagickBooleanType status = MagickFalse;
362 LockSemaphoreInfo(clEnv->lock);
363 status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
364 UnlockSemaphoreInfo(clEnv->lock);
370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 + G e t M a g i c k O p e n C L E n v P a r a m %
378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
380 % GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
382 % The format of the GetMagickOpenCLEnvParam() method is:
384 % MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
385 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
386 % ExceptionInfo* exception)
388 % A description of each parameter follows:
390 % o clEnv: the OpenCL environment.
392 % o param: the parameter to be returned.
394 % o dataSize: the data size of the parameter value.
396 % o data: the location where the returned parameter value will be stored
398 % o exception: return any errors or warnings
403 MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
404 , size_t dataSize, void* data, ExceptionInfo* exception)
409 magick_unreferenced(exception);
411 status = MagickFalse;
419 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
420 if (dataSize != sizeof(cl_device_id))
422 *((cl_device_id*)data) = clEnv->device;
426 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
427 if (dataSize != sizeof(clEnv->OpenCLDisabled))
429 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
433 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
434 if (dataSize != sizeof(clEnv->OpenCLDisabled))
436 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
440 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
441 if (dataSize != sizeof(clEnv->disableProgramCache))
443 *((MagickBooleanType*)data) = clEnv->disableProgramCache;
447 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
448 if (dataSize != sizeof(clEnv->regenerateProfile))
450 *((MagickBooleanType*)data) = clEnv->regenerateProfile;
464 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
468 + G e t O p e n C L C o n t e x t %
472 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
474 % GetOpenCLContext() returns the OpenCL context
476 % The format of the GetOpenCLContext() method is:
478 % cl_context GetOpenCLContext(MagickCLEnv clEnv)
480 % A description of each parameter follows:
482 % o clEnv: OpenCL environment
487 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
491 return clEnv->context;
494 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
498 char path[MaxTextExtent];
499 char deviceName[MaxTextExtent];
500 const char* prefix = "magick_opencl";
501 clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
503 /* strip out illegal characters for file names */
506 if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
507 || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
513 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x_%.20g.bin",
514 GetOpenCLCachedFilesDirectory(),DirectorySeparator,prefix,deviceName,
515 (unsigned int) prog,signature,(double) sizeof(char*)*8);
516 name = (char*)AcquireMagickMemory(strlen(path)+1);
517 CopyMagickString(name,path,strlen(path)+1);
521 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
523 MagickBooleanType saveSuccessful;
525 size_t binaryProgramSize;
526 unsigned char* binaryProgram;
527 char* binaryFileName;
530 #ifdef MAGICKCORE_CLPERFMARKER
531 clBeginPerfMarkerAMD(__FUNCTION__,"");
534 binaryProgram = NULL;
535 binaryFileName = NULL;
537 saveSuccessful = MagickFalse;
539 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
540 if (clStatus != CL_SUCCESS)
542 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
546 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
547 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
548 if (clStatus != CL_SUCCESS)
550 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
554 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
555 fileHandle = fopen(binaryFileName, "wb");
556 if (fileHandle != NULL)
558 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
559 saveSuccessful = MagickTrue;
563 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
564 "Saving binary kernel failed.", "'%s'", ".");
568 if (fileHandle != NULL)
570 if (binaryProgram != NULL)
571 RelinquishMagickMemory(binaryProgram);
572 if (binaryFileName != NULL)
573 free(binaryFileName);
575 #ifdef MAGICKCORE_CLPERFMARKER
576 clEndPerfMarkerAMD();
579 return saveSuccessful;
582 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
584 MagickBooleanType loadSuccessful;
585 unsigned char* binaryProgram;
586 char* binaryFileName;
589 #ifdef MAGICKCORE_CLPERFMARKER
590 clBeginPerfMarkerAMD(__FUNCTION__,"");
593 binaryProgram = NULL;
594 binaryFileName = NULL;
596 loadSuccessful = MagickFalse;
598 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
599 fileHandle = fopen(binaryFileName, "rb");
600 if (fileHandle != NULL)
605 cl_int clBinaryStatus;
609 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
610 b_error |= ( length = ftell( fileHandle ) ) <= 0;
611 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
615 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
616 if (binaryProgram == NULL)
619 memset(binaryProgram, 0, length);
620 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
622 clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
623 if (clStatus != CL_SUCCESS
624 || clBinaryStatus != CL_SUCCESS)
627 loadSuccessful = MagickTrue;
631 if (fileHandle != NULL)
633 if (binaryFileName != NULL)
634 free(binaryFileName);
635 if (binaryProgram != NULL)
636 RelinquishMagickMemory(binaryProgram);
638 #ifdef MAGICKCORE_CLPERFMARKER
639 clEndPerfMarkerAMD();
642 return loadSuccessful;
645 static unsigned int stringSignature(const char* string)
647 unsigned int stringLength;
649 unsigned int signature;
653 const unsigned int* u;
656 #ifdef MAGICKCORE_CLPERFMARKER
657 clBeginPerfMarkerAMD(__FUNCTION__,"");
660 stringLength = strlen(string);
661 signature = stringLength;
662 n = stringLength/sizeof(unsigned int);
664 for (i = 0; i < n; i++)
668 if (n * sizeof(unsigned int) != stringLength)
671 j = n * sizeof(unsigned int);
672 for (i = 0; i < 4; i++,j++)
674 if (j < stringLength)
683 #ifdef MAGICKCORE_CLPERFMARKER
684 clEndPerfMarkerAMD();
690 /* OpenCL kernels for accelerate.c */
691 extern const char *accelerateKernels, *accelerateKernels2;
693 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
695 MagickBooleanType status = MagickFalse;
698 char* accelerateKernelsBuffer = NULL;
700 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
701 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
703 char options[MaxTextExtent];
704 unsigned int optionsSignature;
706 #ifdef MAGICKCORE_CLPERFMARKER
707 clBeginPerfMarkerAMD(__FUNCTION__,"");
710 /* Get additional options */
711 (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
712 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
715 if (getenv("MAGICK_OCL_DEF"))
718 strcat(options,getenv("MAGICK_OCL_DEF"));
723 if (getenv("MAGICK_OCL_BUILD"))
724 printf("options: %s\n", options);
727 optionsSignature = stringSignature(options);
729 /* get all the OpenCL program strings here */
730 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
731 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
732 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
734 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
736 MagickBooleanType loadSuccessful = MagickFalse;
737 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
739 /* try to load the binary first */
740 if (clEnv->disableProgramCache != MagickTrue
741 && !getenv("MAGICK_OCL_REC"))
742 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature);
744 if (loadSuccessful == MagickFalse)
746 /* Binary CL program unavailable, compile the program from source */
747 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
748 clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
749 if (clStatus!=CL_SUCCESS)
751 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
752 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
758 clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
759 if (clStatus!=CL_SUCCESS)
761 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
762 "clBuildProgram failed.", "(%d)", (int)clStatus);
764 if (loadSuccessful == MagickFalse)
766 char path[MaxTextExtent];
769 /* dump the source into a file */
770 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
771 ,GetOpenCLCachedFilesDirectory()
772 ,DirectorySeparator,"magick_badcl.cl");
773 fileHandle = fopen(path, "wb");
774 if (fileHandle != NULL)
776 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
780 /* dump the build log */
784 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
785 log = (char*)AcquireMagickMemory(logSize);
786 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
788 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
789 ,GetOpenCLCachedFilesDirectory()
790 ,DirectorySeparator,"magick_badcl_build.log");
791 fileHandle = fopen(path, "wb");
792 if (fileHandle != NULL)
794 const char* buildOptionsTitle = "build options: ";
795 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
796 fwrite(options, sizeof(char), strlen(options), fileHandle);
797 fwrite("\n",sizeof(char), 1, fileHandle);
798 fwrite(log, sizeof(char), logSize, fileHandle);
801 RelinquishMagickMemory(log);
807 if (loadSuccessful == MagickFalse)
809 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
810 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
818 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
820 #ifdef MAGICKCORE_CLPERFMARKER
821 clEndPerfMarkerAMD();
827 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
830 cl_uint numPlatforms = 0;
831 cl_platform_id *platforms = NULL;
832 char* MAGICK_OCL_DEVICE = NULL;
833 MagickBooleanType OpenCLAvailable = MagickFalse;
835 #ifdef MAGICKCORE_CLPERFMARKER
836 clBeginPerfMarkerAMD(__FUNCTION__,"");
839 /* check if there's an environment variable overriding the device selection */
840 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
841 if (MAGICK_OCL_DEVICE != NULL)
843 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
845 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
847 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
849 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
851 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
853 /* OpenCL disabled */
857 else if (clEnv->deviceType == 0) {
858 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
861 if (clEnv->device != NULL)
863 status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
864 if (status != CL_SUCCESS) {
865 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
866 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
870 else if (clEnv->platform != NULL)
873 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
874 if (platforms == (cl_platform_id *) NULL)
876 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
877 "AcquireMagickMemory failed.",".");
880 platforms[0] = clEnv->platform;
884 clEnv->device = NULL;
886 /* Get the number of OpenCL platforms available */
887 status = clGetPlatformIDs(0, NULL, &numPlatforms);
888 if (status != CL_SUCCESS)
890 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
891 "clGetplatformIDs failed.", "(%d)", status);
895 /* No OpenCL available, just leave */
896 if (numPlatforms == 0) {
900 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
901 if (platforms == (cl_platform_id *) NULL)
903 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
904 "AcquireMagickMemory failed.",".");
908 status = clGetPlatformIDs(numPlatforms, platforms, NULL);
909 if (status != CL_SUCCESS)
911 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
912 "clGetPlatformIDs failed.", "(%d)", status);
917 /* Device selection */
918 clEnv->device = NULL;
919 for (j = 0; j < 2; j++)
922 cl_device_type deviceType;
923 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
926 deviceType = CL_DEVICE_TYPE_GPU;
928 deviceType = CL_DEVICE_TYPE_CPU;
935 deviceType = clEnv->deviceType;
937 for (i = 0; i < numPlatforms; i++)
940 status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
941 if (status != CL_SUCCESS)
943 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
944 "clGetPlatformIDs failed.", "(%d)", status);
947 if (clEnv->device != NULL)
949 clEnv->platform = platforms[i];
957 RelinquishMagickMemory(platforms);
959 OpenCLAvailable = (clEnv->platform!=NULL
960 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
962 #ifdef MAGICKCORE_CLPERFMARKER
963 clEndPerfMarkerAMD();
966 return OpenCLAvailable;
969 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
970 if (clEnv->OpenCLInitialized != MagickFalse
971 && clEnv->platform != NULL
972 && clEnv->device != NULL) {
973 clEnv->OpenCLDisabled = MagickFalse;
976 clEnv->OpenCLDisabled = MagickTrue;
981 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
987 + I n i t O p e n C L E n v %
991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 % InitOpenCLEnv() initialize the OpenCL environment
995 % The format of the RelinquishMagickOpenCLEnv method is:
997 % MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
999 % A description of each parameter follows:
1001 % o clEnv: OpenCL environment structure
1003 % o exception: return any errors or warnings.
1008 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
1009 MagickBooleanType status = MagickTrue;
1011 cl_context_properties cps[3];
1014 clEnv->OpenCLInitialized = MagickTrue;
1015 if (clEnv->OpenCLDisabled != MagickFalse)
1018 clEnv->OpenCLDisabled = MagickTrue;
1019 /* setup the OpenCL platform and device */
1020 status = InitOpenCLPlatformDevice(clEnv, exception);
1021 if (status == MagickFalse) {
1022 /* No OpenCL device available */
1026 /* create an OpenCL context */
1027 cps[0] = CL_CONTEXT_PLATFORM;
1028 cps[1] = (cl_context_properties)clEnv->platform;
1030 clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
1031 if (clStatus != CL_SUCCESS)
1033 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1034 "clCreateContext failed.", "(%d)", clStatus);
1035 status = MagickFalse;
1039 status = CompileOpenCLKernels(clEnv, exception);
1040 if (status == MagickFalse) {
1041 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1042 "clCreateCommandQueue failed.", "(%d)", status);
1044 status = MagickFalse;
1048 status = EnableOpenCLInternal(clEnv);
1055 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1056 MagickBooleanType status = MagickFalse;
1061 #ifdef MAGICKCORE_CLPERFMARKER
1062 clBeginPerfMarkerAMD(__FUNCTION__,"");
1065 LockSemaphoreInfo(clEnv->lock);
1066 if (clEnv->OpenCLInitialized == MagickFalse) {
1067 if (clEnv->device==NULL
1068 && clEnv->OpenCLDisabled == MagickFalse)
1069 status = autoSelectDevice(clEnv, exception);
1071 status = InitOpenCLEnvInternal(clEnv, exception);
1073 UnlockSemaphoreInfo(clEnv->lock);
1075 #ifdef MAGICKCORE_CLPERFMARKER
1076 clEndPerfMarkerAMD();
1083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 + 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 %
1091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1093 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1095 % The format of the AcquireOpenCLCommandQueue method is:
1097 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1099 % A description of each parameter follows:
1101 % o clEnv: the OpenCL environment.
1106 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1109 return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1120 + 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 %
1124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 % RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1128 % The format of the RelinquishOpenCLCommandQueue method is:
1130 % MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1131 % cl_command_queue queue)
1133 % A description of each parameter follows:
1135 % o clEnv: the OpenCL environment.
1137 % o queue: the OpenCL queue to be released.
1142 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1146 return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159 + A c q u i r e O p e n C L K e r n e l %
1163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1165 % AcquireOpenCLKernel() acquires an OpenCL kernel
1167 % The format of the AcquireOpenCLKernel method is:
1169 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
1170 % MagickOpenCLProgram program, const char* kernelName)
1172 % A description of each parameter follows:
1174 % o clEnv: the OpenCL environment.
1176 % o program: the OpenCL program module that the kernel belongs to.
1178 % o kernelName: the name of the kernel
1183 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1186 cl_kernel kernel = NULL;
1187 if (clEnv != NULL && kernelName!=NULL)
1189 kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200 + R e l i n q u i s h O p e n C L K e r n e l %
1204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206 % RelinquishOpenCLKernel() releases an OpenCL kernel
1208 % The format of the RelinquishOpenCLKernel method is:
1210 % MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1213 % A description of each parameter follows:
1215 % o clEnv: the OpenCL environment.
1217 % o kernel: the OpenCL kernel object to be released.
1223 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1225 MagickBooleanType status = MagickFalse;
1226 if (clEnv != NULL && kernel != NULL)
1228 status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1238 + 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 %
1242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244 % GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1246 % The format of the GetOpenCLDeviceLocalMemorySize method is:
1248 % unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1250 % A description of each parameter follows:
1252 % o clEnv: the OpenCL environment.
1258 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1260 cl_ulong localMemorySize;
1261 clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1262 return (unsigned long)localMemorySize;
1266 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1268 cl_ulong maxMemAllocSize;
1269 clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1270 return (unsigned long)maxMemAllocSize;
1275 Beginning of the OpenCL device selection infrastructure
1281 ,DS_INVALID_PROFILE = 1000
1283 ,DS_INVALID_PERF_EVALUATOR_TYPE
1284 ,DS_INVALID_PERF_EVALUATOR
1285 ,DS_PERF_EVALUATOR_ERROR
1287 ,DS_UNKNOWN_DEVICE_TYPE
1288 ,DS_PROFILE_FILE_ERROR
1289 ,DS_SCORE_SERIALIZER_ERROR
1290 ,DS_SCORE_DESERIALIZER_ERROR
1295 DS_DEVICE_NATIVE_CPU = 0
1296 ,DS_DEVICE_OPENCL_DEVICE
1301 ds_device_type type;
1302 cl_device_id oclDeviceID;
1303 char* oclDeviceName;
1304 char* oclDriverVersion;
1305 cl_uint oclMaxClockFrequency;
1306 cl_uint oclMaxComputeUnits;
1307 void* score; /* a pointer to the score data, the content/format is application defined */
1311 unsigned int numDevices;
1313 const char* version;
1316 /* deallocate memory used by score */
1317 typedef ds_status (*ds_score_release)(void* score);
1319 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1320 ds_status status = DS_SUCCESS;
1322 if (device->oclDeviceName) free(device->oclDeviceName);
1323 if (device->oclDriverVersion) free(device->oclDriverVersion);
1324 if (device->score) status = sr(device->score);
1329 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1330 ds_status status = DS_SUCCESS;
1331 if (profile!=NULL) {
1332 if (profile->devices!=NULL && sr!=NULL) {
1334 for (i = 0; i < profile->numDevices; i++) {
1335 status = releaseDeviceResource(profile->devices+i,sr);
1336 if (status != DS_SUCCESS)
1339 free(profile->devices);
1347 static ds_status initDSProfile(ds_profile** p, const char* version) {
1349 cl_uint numPlatforms = 0;
1350 cl_platform_id* platforms = NULL;
1351 cl_device_id* devices = NULL;
1352 ds_status status = DS_SUCCESS;
1353 ds_profile* profile = NULL;
1354 unsigned int next = 0;
1358 return DS_INVALID_PROFILE;
1360 profile = (ds_profile*)malloc(sizeof(ds_profile));
1361 if (profile == NULL)
1362 return DS_MEMORY_ERROR;
1364 memset(profile, 0, sizeof(ds_profile));
1366 clGetPlatformIDs(0, NULL, &numPlatforms);
1367 if (numPlatforms > 0) {
1368 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1369 if (platforms == NULL) {
1370 status = DS_MEMORY_ERROR;
1373 clGetPlatformIDs(numPlatforms, platforms, NULL);
1374 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1376 if (clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num) == CL_SUCCESS)
1381 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1383 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1384 if (profile->devices == NULL) {
1385 profile->numDevices = 0;
1386 status = DS_MEMORY_ERROR;
1389 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1391 if (numDevices > 0) {
1392 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1393 if (devices == NULL) {
1394 status = DS_MEMORY_ERROR;
1397 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1401 for (d = 0; d < 2; d++) {
1403 cl_device_type deviceType;
1406 deviceType = CL_DEVICE_TYPE_GPU;
1409 deviceType = CL_DEVICE_TYPE_CPU;
1415 if (clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
1417 for (j = 0; j < num; j++, next++) {
1420 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1421 profile->devices[next].oclDeviceID = devices[j];
1423 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1424 , 0, NULL, &length);
1425 profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
1426 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1427 , length, profile->devices[next].oclDeviceName, NULL);
1429 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1430 , 0, NULL, &length);
1431 profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
1432 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1433 , length, profile->devices[next].oclDriverVersion, NULL);
1435 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1436 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1438 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1439 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1445 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1446 profile->version = version;
1449 if (platforms) free(platforms);
1450 if (devices) free(devices);
1451 if (status == DS_SUCCESS) {
1456 if (profile->devices)
1457 free(profile->devices);
1464 /* Pointer to a function that calculates the score of a device (ex: device->score)
1465 update the data size of score. The encoding and the format of the score data
1466 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1468 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1472 ,DS_EVALUATE_NEW_ONLY
1473 } ds_evaluation_type;
1475 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1476 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1477 ds_status status = DS_SUCCESS;
1479 unsigned int updates = 0;
1481 if (profile == NULL) {
1482 return DS_INVALID_PROFILE;
1484 if (evaluator == NULL) {
1485 return DS_INVALID_PERF_EVALUATOR;
1488 for (i = 0; i < profile->numDevices; i++) {
1489 ds_status evaluatorStatus;
1492 case DS_EVALUATE_NEW_ONLY:
1493 if (profile->devices[i].score != NULL)
1495 /* else fall through */
1496 case DS_EVALUATE_ALL:
1497 evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
1498 if (evaluatorStatus != DS_SUCCESS) {
1499 status = evaluatorStatus;
1505 return DS_INVALID_PERF_EVALUATOR_TYPE;
1510 *numUpdates = updates;
1515 #define DS_TAG_VERSION "<version>"
1516 #define DS_TAG_VERSION_END "</version>"
1517 #define DS_TAG_DEVICE "<device>"
1518 #define DS_TAG_DEVICE_END "</device>"
1519 #define DS_TAG_SCORE "<score>"
1520 #define DS_TAG_SCORE_END "</score>"
1521 #define DS_TAG_DEVICE_TYPE "<type>"
1522 #define DS_TAG_DEVICE_TYPE_END "</type>"
1523 #define DS_TAG_DEVICE_NAME "<name>"
1524 #define DS_TAG_DEVICE_NAME_END "</name>"
1525 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1526 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1527 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1528 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1529 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1530 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1532 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1536 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1537 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1538 ds_status status = DS_SUCCESS;
1539 FILE* profileFile = NULL;
1542 if (profile == NULL)
1543 return DS_INVALID_PROFILE;
1545 profileFile = fopen(file, "wb");
1546 if (profileFile==NULL) {
1547 status = DS_FILE_ERROR;
1552 /* write version string */
1553 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1554 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1555 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1556 fwrite("\n", sizeof(char), 1, profileFile);
1558 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1559 void* serializedScore;
1560 unsigned int serializedScoreSize;
1562 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1564 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1565 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1566 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1568 switch(profile->devices[i].type) {
1569 case DS_DEVICE_NATIVE_CPU:
1571 /* There's no need to emit a device name for the native CPU device. */
1573 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1574 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1575 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1579 case DS_DEVICE_OPENCL_DEVICE:
1583 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1584 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1585 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1587 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1588 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1589 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1591 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1592 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1593 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1594 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1596 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1597 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1598 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1599 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1603 status = DS_UNKNOWN_DEVICE_TYPE;
1607 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1608 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1609 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1610 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1611 free(serializedScore);
1613 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1614 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1615 fwrite("\n",sizeof(char),1,profileFile);
1617 fclose(profileFile);
1623 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1624 ds_status status = DS_SUCCESS;
1625 FILE * input = NULL;
1628 char* binary = NULL;
1633 input = fopen(fileName, "rb");
1635 return DS_FILE_ERROR;
1638 fseek(input, 0L, SEEK_END);
1639 size = ftell(input);
1641 binary = (char*)malloc(size);
1642 if(binary == NULL) {
1643 status = DS_FILE_ERROR;
1646 rsize = fread(binary, sizeof(char), size, input);
1649 status = DS_FILE_ERROR;
1652 *contentSize = size;
1656 if (input != NULL) fclose(input);
1657 if (status != DS_SUCCESS
1658 && binary != NULL) {
1667 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1668 size_t stringLength;
1669 const char* currentPosition;
1672 stringLength = strlen(string);
1673 currentPosition = contentStart;
1674 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1675 if (*currentPosition == string[0]) {
1676 if (currentPosition+stringLength < contentEnd) {
1677 if (strncmp(currentPosition, string, stringLength) == 0) {
1678 found = currentPosition;
1688 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1689 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1691 ds_status status = DS_SUCCESS;
1692 char* contentStart = NULL;
1693 const char* contentEnd = NULL;
1697 return DS_INVALID_PROFILE;
1699 status = readProFile(file, &contentStart, &contentSize);
1700 if (status == DS_SUCCESS) {
1701 const char* currentPosition;
1702 const char* dataStart;
1703 const char* dataEnd;
1704 size_t versionStringLength;
1706 contentEnd = contentStart + contentSize;
1707 currentPosition = contentStart;
1710 /* parse the version string */
1711 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1712 if (dataStart == NULL) {
1713 status = DS_PROFILE_FILE_ERROR;
1716 dataStart += strlen(DS_TAG_VERSION);
1718 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1719 if (dataEnd==NULL) {
1720 status = DS_PROFILE_FILE_ERROR;
1724 versionStringLength = strlen(profile->version);
1725 if (versionStringLength!=(size_t)(dataEnd-dataStart)
1726 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1727 /* version mismatch */
1728 status = DS_PROFILE_FILE_ERROR;
1731 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1733 /* parse the device information */
1734 DisableMSCWarning(4127)
1739 const char* deviceTypeStart;
1740 const char* deviceTypeEnd;
1741 ds_device_type deviceType;
1743 const char* deviceNameStart;
1744 const char* deviceNameEnd;
1746 const char* deviceScoreStart;
1747 const char* deviceScoreEnd;
1749 const char* deviceDriverStart;
1750 const char* deviceDriverEnd;
1752 const char* tmpStart;
1756 cl_uint maxClockFrequency;
1757 cl_uint maxComputeUnits;
1759 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1760 if (dataStart==NULL) {
1761 /* nothing useful remain, quit...*/
1764 dataStart+=strlen(DS_TAG_DEVICE);
1765 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1766 if (dataEnd==NULL) {
1767 status = DS_PROFILE_FILE_ERROR;
1771 /* parse the device type */
1772 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1773 if (deviceTypeStart==NULL) {
1774 status = DS_PROFILE_FILE_ERROR;
1777 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1778 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1779 if (deviceTypeEnd==NULL) {
1780 status = DS_PROFILE_FILE_ERROR;
1783 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1786 /* parse the device name */
1787 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1789 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1790 if (deviceNameStart==NULL) {
1791 status = DS_PROFILE_FILE_ERROR;
1794 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1795 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1796 if (deviceNameEnd==NULL) {
1797 status = DS_PROFILE_FILE_ERROR;
1802 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1803 if (deviceDriverStart==NULL) {
1804 status = DS_PROFILE_FILE_ERROR;
1807 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1808 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1809 if (deviceDriverEnd ==NULL) {
1810 status = DS_PROFILE_FILE_ERROR;
1815 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1816 if (tmpStart==NULL) {
1817 status = DS_PROFILE_FILE_ERROR;
1820 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1821 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1822 if (tmpEnd ==NULL) {
1823 status = DS_PROFILE_FILE_ERROR;
1826 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1827 tmp[tmpEnd-tmpStart] = '\0';
1828 maxComputeUnits = atoi(tmp);
1831 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1832 if (tmpStart==NULL) {
1833 status = DS_PROFILE_FILE_ERROR;
1836 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1837 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1838 if (tmpEnd ==NULL) {
1839 status = DS_PROFILE_FILE_ERROR;
1842 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1843 tmp[tmpEnd-tmpStart] = '\0';
1844 maxClockFrequency = atoi(tmp);
1847 /* check if this device is on the system */
1848 for (i = 0; i < profile->numDevices; i++) {
1849 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1850 size_t actualDeviceNameLength;
1851 size_t driverVersionLength;
1853 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1854 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1855 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
1856 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
1857 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1858 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1859 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1860 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1862 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1863 if (deviceNameStart==NULL) {
1864 status = DS_PROFILE_FILE_ERROR;
1867 deviceScoreStart+=strlen(DS_TAG_SCORE);
1868 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1869 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1870 if (status != DS_SUCCESS) {
1878 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1879 for (i = 0; i < profile->numDevices; i++) {
1880 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1881 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1882 if (deviceScoreStart==NULL) {
1883 status = DS_PROFILE_FILE_ERROR;
1886 deviceScoreStart+=strlen(DS_TAG_SCORE);
1887 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1888 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1889 if (status != DS_SUCCESS) {
1896 /* skip over the current one to find the next device */
1897 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1901 if (contentStart!=NULL) free(contentStart);
1907 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1909 if (profile == NULL || num==NULL)
1910 return DS_MEMORY_ERROR;
1912 for (i = 0; i < profile->numDevices; i++) {
1913 if (profile->devices[i].score == NULL) {
1922 End of the OpenCL device selection infrastructure
1927 typedef struct _AccelerateTimer {
1933 static void startAccelerateTimer(AccelerateTimer* timer) {
1935 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
1940 gettimeofday(&s, 0);
1941 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1945 static void stopAccelerateTimer(AccelerateTimer* timer) {
1948 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
1951 gettimeofday(&s, 0);
1952 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1956 timer->_clocks += n;
1959 static void resetAccelerateTimer(AccelerateTimer* timer) {
1965 static void initAccelerateTimer(AccelerateTimer* timer) {
1967 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1969 timer->_freq = (long long)1.0E3;
1971 resetAccelerateTimer(timer);
1974 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1977 typedef double AccelerateScoreType;
1979 static ds_status AcceleratePerfEvaluator(ds_device *device,
1980 void *magick_unused(data))
1982 #define ACCELERATE_PERF_DIMEN "2048x1536"
1984 #define ReturnStatus(status) \
1987 RelinquishMagickOpenCLEnv(clEnv); \
1988 if (oldClEnv!=NULL) \
1989 defaultCLEnv = oldClEnv; \
2003 magick_unreferenced(data);
2006 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2008 clEnv=AcquireMagickOpenCLEnv();
2009 exception=AcquireExceptionInfo();
2011 if (device->type == DS_DEVICE_NATIVE_CPU)
2014 MagickBooleanType flag=MagickTrue;
2015 SetMagickOpenCLEnvParamInternal(clEnv,
2016 MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
2019 else if (device->type == DS_DEVICE_OPENCL_DEVICE)
2022 SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
2023 sizeof(cl_device_id),&device->oclDeviceID,exception);
2026 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2028 /* recompile the OpenCL kernels if it needs to */
2029 clEnv->disableProgramCache = defaultCLEnv->disableProgramCache;
2031 InitOpenCLEnvInternal(clEnv,exception);
2032 oldClEnv=defaultCLEnv;
2035 /* microbenchmark */
2046 imageInfo=AcquireImageInfo();
2047 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
2048 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
2049 inputImage=ReadImage(imageInfo,exception);
2051 initAccelerateTimer(&timer);
2053 for (i=0; i<=NUM_ITER; i++)
2061 startAccelerateTimer(&timer);
2063 #ifdef MAGICKCORE_CLPERFMARKER
2064 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2067 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2068 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2070 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
2073 #ifdef MAGICKCORE_CLPERFMARKER
2074 clEndPerfMarkerAMD();
2078 stopAccelerateTimer(&timer);
2081 DestroyImage(bluredImage);
2083 DestroyImage(unsharpedImage);
2085 DestroyImage(resizedImage);
2087 DestroyImage(inputImage);
2089 /* end of microbenchmark */
2091 if (device->score == NULL)
2092 device->score=malloc(sizeof(AccelerateScoreType));
2093 *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
2095 ReturnStatus(DS_SUCCESS);
2098 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2101 /* generate a string from the score */
2102 char* s = (char*)malloc(sizeof(char)*256);
2103 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2104 *serializedScore = (void*)s;
2105 *serializedScoreSize = strlen(s);
2109 return DS_SCORE_SERIALIZER_ERROR;
2113 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2115 /* convert the string back to an int */
2116 char* s = (char*)malloc(serializedScoreSize+1);
2117 memcpy(s, serializedScore, serializedScoreSize);
2118 s[serializedScoreSize] = (char)'\0';
2119 device->score = malloc(sizeof(AccelerateScoreType));
2120 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2125 return DS_SCORE_DESERIALIZER_ERROR;
2129 ds_status AccelerateScoreRelease(void* score) {
2137 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2138 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2139 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2141 MagickBooleanType mStatus = MagickFalse;
2143 ds_profile* profile;
2144 unsigned int numDeviceProfiled = 0;
2146 unsigned int bestDeviceIndex;
2147 AccelerateScoreType bestScore;
2148 char path[MaxTextExtent];
2149 MagickBooleanType flag;
2150 ds_evaluation_type profileType;
2152 LockDefaultOpenCLEnv();
2154 /* Initially, just set OpenCL to off */
2156 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2157 , sizeof(MagickBooleanType), &flag, exception);
2159 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2160 if (status!=DS_SUCCESS) {
2161 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2165 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2166 ,GetOpenCLCachedFilesDirectory()
2167 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2169 if (clEnv->regenerateProfile != MagickFalse) {
2170 profileType = DS_EVALUATE_ALL;
2173 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2174 profileType = DS_EVALUATE_NEW_ONLY;
2176 status = profileDevices(profile, profileType, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2178 if (status!=DS_SUCCESS) {
2179 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2182 if (numDeviceProfiled > 0) {
2183 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2184 if (status!=DS_SUCCESS) {
2185 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2189 /* pick the best device */
2190 bestDeviceIndex = 0;
2191 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2192 for (i = 1; i < profile->numDevices; i++) {
2193 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2194 if (score < bestScore) {
2195 bestDeviceIndex = i;
2200 /* set up clEnv with the best device */
2201 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2204 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2205 , sizeof(MagickBooleanType), &flag, exception);
2207 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2210 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2211 , sizeof(MagickBooleanType), &flag, exception);
2212 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2213 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2216 status = DS_PERF_EVALUATOR_ERROR;
2219 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2221 status = releaseDSProfile(profile, AccelerateScoreRelease);
2222 if (status!=DS_SUCCESS) {
2223 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2228 UnlockDefaultOpenCLEnv();
2234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2238 + I n i t I m a g e M a g i c k O p e n C L %
2242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2244 % InitImageMagickOpenCL() provides a simplified interface to initialize
2245 % the OpenCL environtment in ImageMagick
2247 % The format of the InitImageMagickOpenCL() method is:
2249 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2250 % void* userSelectedDevice,
2251 % void* selectedDevice)
2253 % A description of each parameter follows:
2255 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2257 % o userSelectedDevice: when in user mode, a pointer to the selected
2260 % o selectedDevice: a pointer to cl_device_id where the selected
2261 % cl_device_id by ImageMagick could be returned
2263 % o exception: exception
2266 MagickExport MagickBooleanType InitImageMagickOpenCL(
2267 ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2268 ExceptionInfo *exception)
2270 MagickBooleanType status = MagickTrue;
2271 MagickCLEnv clEnv = NULL;
2272 MagickBooleanType flag;
2274 clEnv = GetDefaultOpenCLEnv();
2278 case MAGICK_OPENCL_OFF:
2280 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2281 , sizeof(MagickBooleanType), &flag, exception);
2282 status = InitOpenCLEnv(clEnv, exception);
2285 *(cl_device_id*)selectedDevice = NULL;
2288 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2290 if (userSelectedDevice == NULL)
2294 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2295 , sizeof(MagickBooleanType), &flag, exception);
2297 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2298 , sizeof(cl_device_id), userSelectedDevice,exception);
2300 status = InitOpenCLEnv(clEnv, exception);
2301 if (selectedDevice) {
2302 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2303 , sizeof(cl_device_id), selectedDevice, exception);
2307 case MAGICK_OPENCL_DEVICE_SELECT_AUTO_CLEAR_CACHE:
2309 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED
2310 , sizeof(MagickBooleanType), &flag, exception);
2312 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE
2313 , sizeof(MagickBooleanType), &flag, exception);
2315 /* fall through here!! */
2316 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2319 cl_device_id d = NULL;
2321 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2322 , sizeof(MagickBooleanType), &flag, exception);
2323 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2324 , sizeof(cl_device_id), &d,exception);
2325 status = InitOpenCLEnv(clEnv, exception);
2326 if (selectedDevice) {
2327 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2328 , sizeof(cl_device_id), selectedDevice, exception);
2339 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2340 const char *module,const char *function,const size_t line,
2341 const ExceptionType severity,const char *tag,const char *format,...) {
2347 status = MagickTrue;
2349 clEnv = GetDefaultOpenCLEnv();
2351 assert(exception != (ExceptionInfo *) NULL);
2352 assert(exception->signature == MagickSignature);
2355 cl_device_type dType;
2356 clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
2357 if (dType == CL_DEVICE_TYPE_CPU) {
2358 char buffer[MaxTextExtent];
2359 clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
2361 /* Workaround for Intel OpenCL CPU runtime bug */
2362 /* Turn off OpenCL when a problem is detected! */
2363 if (strncmp(buffer, "Intel",5) == 0) {
2365 InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2370 #ifdef OPENCLLOG_ENABLED
2374 va_start(operands,format);
2375 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2379 magick_unreferenced(module);
2380 magick_unreferenced(function);
2381 magick_unreferenced(line);
2382 magick_unreferenced(tag);
2383 magick_unreferenced(format);
2392 struct _MagickCLEnv {
2393 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2396 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2401 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2402 MagickCLEnv magick_unused(clEnv))
2404 magick_unreferenced(clEnv);
2410 * Return the OpenCL environment
2412 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2413 ExceptionInfo *magick_unused(exception))
2415 magick_unreferenced(exception);
2417 return (MagickCLEnv) NULL;
2420 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2421 MagickCLEnv magick_unused(clEnv))
2423 magick_unreferenced(clEnv);
2425 return (MagickCLEnv) NULL;
2428 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2429 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2430 size_t magick_unused(dataSize),void *magick_unused(data),
2431 ExceptionInfo *magick_unused(exception))
2433 magick_unreferenced(clEnv);
2434 magick_unreferenced(param);
2435 magick_unreferenced(dataSize);
2436 magick_unreferenced(data);
2437 magick_unreferenced(exception);
2442 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2443 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2444 size_t magick_unused(dataSize),void *magick_unused(data),
2445 ExceptionInfo *magick_unused(exception))
2447 magick_unreferenced(clEnv);
2448 magick_unreferenced(param);
2449 magick_unreferenced(dataSize);
2450 magick_unreferenced(data);
2451 magick_unreferenced(exception);
2456 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2457 ExceptionInfo *magick_unused(exception))
2459 magick_unreferenced(clEnv);
2460 magick_unreferenced(exception);
2465 MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(
2466 MagickCLEnv magick_unused(clEnv))
2468 magick_unreferenced(clEnv);
2470 return (cl_command_queue) NULL;
2473 MagickExport MagickBooleanType RelinquishCommandQueue(
2474 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2476 magick_unreferenced(clEnv);
2477 magick_unreferenced(queue);
2482 MagickPrivate cl_kernel AcquireOpenCLKernel(
2483 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2484 const char *magick_unused(kernelName))
2486 magick_unreferenced(clEnv);
2487 magick_unreferenced(program);
2488 magick_unreferenced(kernelName);
2490 return (cl_kernel)NULL;
2493 MagickPrivate MagickBooleanType RelinquishOpenCLKernel(
2494 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2496 magick_unreferenced(clEnv);
2497 magick_unreferenced(kernel);
2502 MagickPrivate unsigned long GetOpenCLDeviceLocalMemorySize(
2503 MagickCLEnv magick_unused(clEnv))
2505 magick_unreferenced(clEnv);
2510 MagickExport MagickBooleanType InitImageMagickOpenCL(
2511 ImageMagickOpenCLMode magick_unused(mode),
2512 void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2513 ExceptionInfo *magick_unused(exception))
2515 magick_unreferenced(mode);
2516 magick_unreferenced(userSelectedDevice);
2517 magick_unreferenced(selectedDevice);
2518 magick_unreferenced(exception);
2524 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2525 const char *module,const char *function,const size_t line,
2526 const ExceptionType severity,const char *tag,const char *format,...)
2528 magick_unreferenced(exception);
2529 magick_unreferenced(module);
2530 magick_unreferenced(function);
2531 magick_unreferenced(line);
2532 magick_unreferenced(severity);
2533 magick_unreferenced(tag);
2534 magick_unreferenced(format);
2535 return(MagickFalse);
2537 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2539 char* openclCachedFilesDirectory;
2540 SemaphoreInfo* openclCachedFilesDirectoryLock;
2543 const char* GetOpenCLCachedFilesDirectory() {
2544 if (openclCachedFilesDirectory == NULL) {
2545 if (openclCachedFilesDirectoryLock == NULL)
2547 ActivateSemaphoreInfo(&openclCachedFilesDirectoryLock);
2549 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2550 if (openclCachedFilesDirectory == NULL) {
2551 char path[MaxTextExtent];
2554 struct stat attributes;
2555 MagickBooleanType status;
2557 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2558 home=GetEnvironmentValue("LOCALAPPDATA");
2559 if (home == (char *) NULL)
2560 home=GetEnvironmentValue("APPDATA");
2561 if (home == (char *) NULL)
2562 home=GetEnvironmentValue("USERPROFILE");
2564 home=GetEnvironmentValue("HOME");
2566 if (home != (char *) NULL)
2569 Search $HOME/.config/ImageMagick.
2571 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.config",home,
2572 DirectorySeparator);
2573 status=GetPathAttributes(path,&attributes);
2574 if (status == MagickFalse) {
2575 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2581 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.config%sImageMagick",
2582 home,DirectorySeparator,DirectorySeparator);
2583 home=DestroyString(home);
2584 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2585 CopyMagickString(temp,path,strlen(path)+1);
2586 status=GetPathAttributes(path,&attributes);
2587 if (status == MagickFalse) {
2588 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2595 openclCachedFilesDirectory = temp;
2597 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2599 return openclCachedFilesDirectory;
2602 /* create a function for OpenCL log */
2604 void OpenCLLog(const char* message) {
2606 #ifdef OPENCLLOG_ENABLED
2607 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2610 if (getenv("MAGICK_OCL_LOG"))
2613 char path[MaxTextExtent];
2614 unsigned long allocSize;
2618 clEnv = GetDefaultOpenCLEnv();
2620 /* dump the source into a file */
2621 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2622 ,GetOpenCLCachedFilesDirectory()
2623 ,DirectorySeparator,OPENCL_LOG_FILE);
2626 log = fopen(path, "ab");
2627 fwrite(message, sizeof(char), strlen(message), log);
2628 fwrite("\n", sizeof(char), 1, log);
2630 if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
2632 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
2633 fprintf(log, "Devic Max Memory Alloc Size: %ld\n", allocSize);
2640 magick_unreferenced(message);