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/opencl.h"
67 #include "MagickCore/opencl-private.h"
68 #include "MagickCore/option.h"
69 #include "MagickCore/policy.h"
70 #include "MagickCore/property.h"
71 #include "MagickCore/quantize.h"
72 #include "MagickCore/quantum.h"
73 #include "MagickCore/resample.h"
74 #include "MagickCore/resource_.h"
75 #include "MagickCore/splay-tree.h"
76 #include "MagickCore/semaphore.h"
77 #include "MagickCore/statistic.h"
78 #include "MagickCore/string_.h"
79 #include "MagickCore/token.h"
80 #include "MagickCore/utility.h"
82 #ifdef MAGICKCORE_CLPERFMARKER
83 #include "CLPerfMarker.h"
87 #if defined(MAGICKCORE_OPENCL_SUPPORT)
90 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
91 MagickBooleanType OpenCLDisabled; /* whether if OpenCL has been explicitely disabled. */
94 cl_platform_id platform;
95 cl_device_type deviceType;
99 cl_program programs[MAGICK_OPENCL_NUM_PROGRAMS]; /* one program object maps one kernel source file */
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 + A c q u i r e M a g i c k O p e n C L E n v %
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 % AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure
120 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
123 clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
126 memset(clEnv, 0, sizeof(struct _MagickCLEnv));
127 AcquireSemaphoreInfo(&clEnv->lock);
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138 + 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 %
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144 % RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
146 % The format of the RelinquishMagickOpenCLEnv method is:
148 % MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
150 % A description of each parameter follows:
152 % o clEnv: MagickCLEnv structure to destroy
156 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
158 if (clEnv != (MagickCLEnv)NULL)
160 RelinquishSemaphoreInfo(clEnv->lock);
161 RelinquishMagickMemory(clEnv);
169 * Default OpenCL environment
171 MagickCLEnv defaultCLEnv;
172 SemaphoreInfo* defaultCLEnvLock;
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
180 + G e t D e f a u l t O p e n C L E n v %
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 % GetDefaultOpenCLEnv() returns the default OpenCL env
188 % The format of the GetDefaultOpenCLEnv method is:
190 % MagickCLEnv GetDefaultOpenCLEnv()
192 % A description of each parameter follows:
194 % o exception: return any errors or warnings.
198 MagickExport MagickCLEnv GetDefaultOpenCLEnv()
200 if (defaultCLEnv == NULL)
202 if (defaultCLEnvLock == NULL)
204 AcquireSemaphoreInfo(&defaultCLEnvLock);
206 LockSemaphoreInfo(defaultCLEnvLock);
207 defaultCLEnv = AcquireMagickOpenCLEnv();
208 UnlockSemaphoreInfo(defaultCLEnvLock);
213 static void LockDefaultOpenCLEnv() {
214 if (defaultCLEnvLock == NULL)
216 AcquireSemaphoreInfo(&defaultCLEnvLock);
218 LockSemaphoreInfo(defaultCLEnvLock);
221 static void UnlockDefaultOpenCLEnv() {
222 if (defaultCLEnvLock == NULL)
224 AcquireSemaphoreInfo(&defaultCLEnvLock);
227 UnlockSemaphoreInfo(defaultCLEnvLock);
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 + S e t D e f a u l t O p e n C L E n v %
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 % SetDefaultOpenCLEnv() sets the new OpenCL environment as default
243 % and returns the old OpenCL environment
245 % The format of the SetDefaultOpenCLEnv() method is:
247 % MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
249 % A description of each parameter follows:
251 % o clEnv: the new default OpenCL environment.
254 MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
257 LockDefaultOpenCLEnv();
258 oldEnv = defaultCLEnv;
259 defaultCLEnv = clEnv;
260 UnlockDefaultOpenCLEnv();
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271 + S e t M a g i c k O p e n C L E n v P a r a m %
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 % SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
279 % The format of the SetMagickOpenCLEnvParam() method is:
281 % MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
282 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
283 % ExceptionInfo* exception)
285 % A description of each parameter follows:
287 % o clEnv: the OpenCL environment.
289 % o param: the parameter to be set.
291 % o dataSize: the data size of the parameter value.
293 % o data: the pointer to the new parameter value
295 % o exception: return any errors or warnings
299 static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
300 , size_t dataSize, void* data, ExceptionInfo* exception)
302 MagickBooleanType status = MagickFalse;
310 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
311 if (dataSize != sizeof(clEnv->device))
313 clEnv->device = *((cl_device_id*)data);
314 clEnv->OpenCLInitialized = MagickFalse;
318 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
319 if (dataSize != sizeof(clEnv->OpenCLDisabled))
321 clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
322 clEnv->OpenCLInitialized = MagickFalse;
326 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
327 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
339 MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
340 , size_t dataSize, void* data, ExceptionInfo* exception) {
341 MagickBooleanType status = MagickFalse;
343 LockSemaphoreInfo(clEnv->lock);
344 status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
345 UnlockSemaphoreInfo(clEnv->lock);
351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 + G e t M a g i c k O p e n C L E n v P a r a m %
359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361 % GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
363 % The format of the GetMagickOpenCLEnvParam() method is:
365 % MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
366 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
367 % ExceptionInfo* exception)
369 % A description of each parameter follows:
371 % o clEnv: the OpenCL environment.
373 % o param: the parameter to be returned.
375 % o dataSize: the data size of the parameter value.
377 % o data: the location where the returned parameter value will be stored
379 % o exception: return any errors or warnings
384 MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
385 , size_t dataSize, void* data, ExceptionInfo* exception)
390 magick_unreferenced(exception);
392 status = MagickFalse;
400 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
401 if (dataSize != sizeof(cl_device_id))
403 *((cl_device_id*)data) = clEnv->device;
407 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
408 if (dataSize != sizeof(clEnv->OpenCLDisabled))
410 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
414 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
415 if (dataSize != sizeof(clEnv->OpenCLDisabled))
417 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
431 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
435 + G e t O p e n C L C o n t e x t %
439 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 % GetOpenCLContext() returns the OpenCL context
443 % The format of the GetOpenCLContext() method is:
445 % cl_context GetOpenCLContext(MagickCLEnv clEnv)
447 % A description of each parameter follows:
449 % o clEnv: OpenCL environment
454 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
458 return clEnv->context;
461 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
465 char path[MaxTextExtent];
466 char deviceName[MaxTextExtent];
467 const char* prefix = "magick_opencl";
468 clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
470 /* strip out illegal characters for file names */
473 if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
474 || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
480 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x.bin"
481 ,GetOpenCLCachedFilesDirectory()
482 ,DirectorySeparator,prefix,deviceName, (unsigned int)prog, signature);
483 name = (char*)AcquireMagickMemory(strlen(path)+1);
484 CopyMagickString(name,path,strlen(path)+1);
488 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
490 MagickBooleanType saveSuccessful;
492 size_t binaryProgramSize;
493 unsigned char* binaryProgram;
494 char* binaryFileName;
497 #ifdef MAGICKCORE_CLPERFMARKER
498 clBeginPerfMarkerAMD(__FUNCTION__,"");
501 binaryProgram = NULL;
502 binaryFileName = NULL;
504 saveSuccessful = MagickFalse;
506 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
507 if (clStatus != CL_SUCCESS)
509 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
513 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
514 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
515 if (clStatus != CL_SUCCESS)
517 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
521 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
522 fileHandle = fopen(binaryFileName, "wb");
523 if (fileHandle != NULL)
525 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
526 saveSuccessful = MagickTrue;
530 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
531 "Saving binary kernel failed.", "'%s'", ".");
535 if (fileHandle != NULL)
537 if (binaryProgram != NULL)
538 RelinquishMagickMemory(binaryProgram);
539 if (binaryFileName != NULL)
540 free(binaryFileName);
542 #ifdef MAGICKCORE_CLPERFMARKER
543 clEndPerfMarkerAMD();
546 return saveSuccessful;
549 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
551 MagickBooleanType loadSuccessful;
552 unsigned char* binaryProgram;
553 char* binaryFileName;
556 #ifdef MAGICKCORE_CLPERFMARKER
557 clBeginPerfMarkerAMD(__FUNCTION__,"");
560 binaryProgram = NULL;
561 binaryFileName = NULL;
563 loadSuccessful = MagickFalse;
565 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
566 fileHandle = fopen(binaryFileName, "rb");
567 if (fileHandle != NULL)
572 cl_int clBinaryStatus;
576 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
577 b_error |= ( length = ftell( fileHandle ) ) <= 0;
578 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
582 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
583 if (binaryProgram == NULL)
586 memset(binaryProgram, 0, length);
587 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
589 clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
590 if (clStatus != CL_SUCCESS
591 || clBinaryStatus != CL_SUCCESS)
594 loadSuccessful = MagickTrue;
598 if (fileHandle != NULL)
600 if (binaryFileName != NULL)
601 free(binaryFileName);
602 if (binaryProgram != NULL)
603 RelinquishMagickMemory(binaryProgram);
605 #ifdef MAGICKCORE_CLPERFMARKER
606 clEndPerfMarkerAMD();
609 return loadSuccessful;
612 static unsigned int stringSignature(const char* string)
614 unsigned int stringLength;
616 unsigned int signature;
620 const unsigned int* u;
623 #ifdef MAGICKCORE_CLPERFMARKER
624 clBeginPerfMarkerAMD(__FUNCTION__,"");
627 stringLength = strlen(string);
628 signature = stringLength;
629 n = stringLength/sizeof(unsigned int);
631 for (i = 0; i < n; i++)
635 if (n * sizeof(unsigned int) != stringLength)
638 j = n * sizeof(unsigned int);
639 for (i = 0; i < 4; i++,j++)
641 if (j < stringLength)
650 #ifdef MAGICKCORE_CLPERFMARKER
651 clEndPerfMarkerAMD();
657 /* OpenCL kernels for accelerate.c */
658 extern const char *accelerateKernels, *accelerateKernels2;
660 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
662 MagickBooleanType status = MagickFalse;
665 char* accelerateKernelsBuffer = NULL;
667 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
668 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
670 char options[MaxTextExtent];
671 unsigned int optionsSignature;
673 #ifdef MAGICKCORE_CLPERFMARKER
674 clBeginPerfMarkerAMD(__FUNCTION__,"");
677 /* Get additional options */
678 (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
679 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
682 if (getenv("MAGICK_OCL_DEF"))
685 strcat(options,getenv("MAGICK_OCL_DEF"));
690 if (getenv("MAGICK_OCL_BUILD"))
691 printf("options: %s\n", options);
694 optionsSignature = stringSignature(options);
696 /* get all the OpenCL program strings here */
697 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
698 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
699 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
701 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
703 MagickBooleanType loadSuccessful = MagickFalse;
704 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
706 /* try to load the binary first */
707 if (!getenv("MAGICK_OCL_REC"))
708 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature);
710 if (loadSuccessful == MagickFalse)
712 /* Binary CL program unavailable, compile the program from source */
713 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
714 clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
715 if (clStatus!=CL_SUCCESS)
717 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
718 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
724 clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
725 if (clStatus!=CL_SUCCESS)
727 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
728 "clBuildProgram failed.", "(%d)", (int)clStatus);
730 if (loadSuccessful == MagickFalse)
732 char path[MaxTextExtent];
735 /* dump the source into a file */
736 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
737 ,GetOpenCLCachedFilesDirectory()
738 ,DirectorySeparator,"magick_badcl.cl");
739 fileHandle = fopen(path, "wb");
740 if (fileHandle != NULL)
742 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
746 /* dump the build log */
750 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
751 log = (char*)AcquireMagickMemory(logSize);
752 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
754 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
755 ,GetOpenCLCachedFilesDirectory()
756 ,DirectorySeparator,"magick_badcl_build.log");
757 fileHandle = fopen(path, "wb");
758 if (fileHandle != NULL)
760 const char* buildOptionsTitle = "build options: ";
761 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
762 fwrite(options, sizeof(char), strlen(options), fileHandle);
763 fwrite("\n",sizeof(char), 1, fileHandle);
764 fwrite(log, sizeof(char), logSize, fileHandle);
767 RelinquishMagickMemory(log);
773 if (loadSuccessful == MagickFalse)
775 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
776 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
784 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
786 #ifdef MAGICKCORE_CLPERFMARKER
787 clEndPerfMarkerAMD();
793 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
796 cl_uint numPlatforms = 0;
797 cl_platform_id *platforms = NULL;
798 char* MAGICK_OCL_DEVICE = NULL;
799 MagickBooleanType OpenCLAvailable = MagickFalse;
801 #ifdef MAGICKCORE_CLPERFMARKER
802 clBeginPerfMarkerAMD(__FUNCTION__,"");
805 /* check if there's an environment variable overriding the device selection */
806 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
807 if (MAGICK_OCL_DEVICE != NULL)
809 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
811 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
813 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
815 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
817 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
819 /* OpenCL disabled */
823 else if (clEnv->deviceType == 0) {
824 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
827 if (clEnv->device != NULL)
829 status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
830 if (status != CL_SUCCESS) {
831 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
832 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
836 else if (clEnv->platform != NULL)
839 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
840 if (platforms == (cl_platform_id *) NULL)
842 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
843 "AcquireMagickMemory failed.",".");
846 platforms[0] = clEnv->platform;
850 clEnv->device = NULL;
852 /* Get the number of OpenCL platforms available */
853 status = clGetPlatformIDs(0, NULL, &numPlatforms);
854 if (status != CL_SUCCESS)
856 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
857 "clGetplatformIDs failed.", "(%d)", status);
861 /* No OpenCL available, just leave */
862 if (numPlatforms == 0) {
866 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
867 if (platforms == (cl_platform_id *) NULL)
869 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
870 "AcquireMagickMemory failed.",".");
874 status = clGetPlatformIDs(numPlatforms, platforms, NULL);
875 if (status != CL_SUCCESS)
877 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
878 "clGetPlatformIDs failed.", "(%d)", status);
883 /* Device selection */
884 clEnv->device = NULL;
885 for (j = 0; j < 2; j++)
888 cl_device_type deviceType;
889 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
892 deviceType = CL_DEVICE_TYPE_GPU;
894 deviceType = CL_DEVICE_TYPE_CPU;
901 deviceType = clEnv->deviceType;
903 for (i = 0; i < numPlatforms; i++)
906 status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
907 if (status != CL_SUCCESS)
909 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
910 "clGetPlatformIDs failed.", "(%d)", status);
913 if (clEnv->device != NULL)
915 clEnv->platform = platforms[i];
923 RelinquishMagickMemory(platforms);
925 OpenCLAvailable = (clEnv->platform!=NULL
926 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
928 #ifdef MAGICKCORE_CLPERFMARKER
929 clEndPerfMarkerAMD();
932 return OpenCLAvailable;
935 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
936 if (clEnv->OpenCLInitialized == MagickTrue
937 && clEnv->platform != NULL
938 && clEnv->device != NULL) {
939 clEnv->OpenCLDisabled = MagickFalse;
942 clEnv->OpenCLDisabled = MagickTrue;
947 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
949 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953 + I n i t O p e n C L E n v %
957 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
959 % InitOpenCLEnv() initialize the OpenCL environment
961 % The format of the RelinquishMagickOpenCLEnv method is:
963 % MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
965 % A description of each parameter follows:
967 % o clEnv: OpenCL environment structure
969 % o exception: return any errors or warnings.
974 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
975 MagickBooleanType status = MagickTrue;
977 cl_context_properties cps[3];
980 clEnv->OpenCLInitialized = MagickTrue;
981 if (clEnv->OpenCLDisabled == MagickTrue)
984 clEnv->OpenCLDisabled = MagickTrue;
985 /* setup the OpenCL platform and device */
986 status = InitOpenCLPlatformDevice(clEnv, exception);
987 if (status == MagickFalse) {
988 /* No OpenCL device available */
992 /* create an OpenCL context */
993 cps[0] = CL_CONTEXT_PLATFORM;
994 cps[1] = (cl_context_properties)clEnv->platform;
996 clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
997 if (clStatus != CL_SUCCESS)
999 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1000 "clCreateContext failed.", "(%d)", clStatus);
1001 status = MagickFalse;
1005 status = CompileOpenCLKernels(clEnv, exception);
1006 if (status == MagickFalse) {
1007 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1008 "clCreateCommandQueue failed.", "(%d)", status);
1010 status = MagickFalse;
1014 status = EnableOpenCLInternal(clEnv);
1021 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1022 MagickBooleanType status = MagickFalse;
1027 #ifdef MAGICKCORE_CLPERFMARKER
1028 clBeginPerfMarkerAMD(__FUNCTION__,"");
1031 LockSemaphoreInfo(clEnv->lock);
1032 if (clEnv->OpenCLInitialized == MagickFalse) {
1033 if (clEnv->device==NULL
1034 && clEnv->OpenCLDisabled == MagickFalse)
1035 status = autoSelectDevice(clEnv, exception);
1037 status = InitOpenCLEnvInternal(clEnv, exception);
1039 UnlockSemaphoreInfo(clEnv->lock);
1041 #ifdef MAGICKCORE_CLPERFMARKER
1042 clEndPerfMarkerAMD();
1049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 + 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 %
1057 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1059 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1061 % The format of the AcquireOpenCLCommandQueue method is:
1063 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1065 % A description of each parameter follows:
1067 % o clEnv: the OpenCL environment.
1072 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1075 return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 + 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 %
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092 % RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1094 % The format of the RelinquishOpenCLCommandQueue method is:
1096 % MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1097 % cl_command_queue queue)
1099 % A description of each parameter follows:
1101 % o clEnv: the OpenCL environment.
1103 % o queue: the OpenCL queue to be released.
1108 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1112 return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1121 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125 + A c q u i r e O p e n C L K e r n e l %
1129 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1131 % AcquireOpenCLKernel() acquires an OpenCL kernel
1133 % The format of the AcquireOpenCLKernel method is:
1135 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
1136 % MagickOpenCLProgram program, const char* kernelName)
1138 % A description of each parameter follows:
1140 % o clEnv: the OpenCL environment.
1142 % o program: the OpenCL program module that the kernel belongs to.
1144 % o kernelName: the name of the kernel
1149 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1152 cl_kernel kernel = NULL;
1153 if (clEnv != NULL && kernelName!=NULL)
1155 kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166 + R e l i n q u i s h O p e n C L K e r n e l %
1170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1172 % RelinquishOpenCLKernel() releases an OpenCL kernel
1174 % The format of the RelinquishOpenCLKernel method is:
1176 % MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1179 % A description of each parameter follows:
1181 % o clEnv: the OpenCL environment.
1183 % o kernel: the OpenCL kernel object to be released.
1189 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1191 MagickBooleanType status = MagickFalse;
1192 if (clEnv != NULL && kernel != NULL)
1194 status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204 + 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 %
1208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1210 % GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1212 % The format of the GetOpenCLDeviceLocalMemorySize method is:
1214 % unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1216 % A description of each parameter follows:
1218 % o clEnv: the OpenCL environment.
1224 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1226 cl_ulong localMemorySize;
1227 clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1228 return (unsigned long)localMemorySize;
1232 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1234 cl_ulong maxMemAllocSize;
1235 clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1236 return (unsigned long)maxMemAllocSize;
1241 Beginning of the OpenCL device selection infrastructure
1247 ,DS_INVALID_PROFILE = 1000
1249 ,DS_INVALID_PERF_EVALUATOR_TYPE
1250 ,DS_INVALID_PERF_EVALUATOR
1251 ,DS_PERF_EVALUATOR_ERROR
1253 ,DS_UNKNOWN_DEVICE_TYPE
1254 ,DS_PROFILE_FILE_ERROR
1255 ,DS_SCORE_SERIALIZER_ERROR
1256 ,DS_SCORE_DESERIALIZER_ERROR
1261 DS_DEVICE_NATIVE_CPU = 0
1262 ,DS_DEVICE_OPENCL_DEVICE
1267 ds_device_type type;
1268 cl_device_id oclDeviceID;
1269 char* oclDeviceName;
1270 char* oclDriverVersion;
1271 cl_uint oclMaxClockFrequency;
1272 cl_uint oclMaxComputeUnits;
1273 void* score; /* a pointer to the score data, the content/format is application defined */
1277 unsigned int numDevices;
1279 const char* version;
1282 /* deallocate memory used by score */
1283 typedef ds_status (*ds_score_release)(void* score);
1285 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1286 ds_status status = DS_SUCCESS;
1288 if (device->oclDeviceName) free(device->oclDeviceName);
1289 if (device->oclDriverVersion) free(device->oclDriverVersion);
1290 if (device->score) status = sr(device->score);
1295 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1296 ds_status status = DS_SUCCESS;
1297 if (profile!=NULL) {
1298 if (profile->devices!=NULL && sr!=NULL) {
1300 for (i = 0; i < profile->numDevices; i++) {
1301 status = releaseDeviceResource(profile->devices+i,sr);
1302 if (status != DS_SUCCESS)
1305 free(profile->devices);
1313 static ds_status initDSProfile(ds_profile** p, const char* version) {
1315 cl_uint numPlatforms = 0;
1316 cl_platform_id* platforms = NULL;
1317 cl_device_id* devices = NULL;
1318 ds_status status = DS_SUCCESS;
1319 ds_profile* profile = NULL;
1320 unsigned int next = 0;
1324 return DS_INVALID_PROFILE;
1326 profile = (ds_profile*)malloc(sizeof(ds_profile));
1327 if (profile == NULL)
1328 return DS_MEMORY_ERROR;
1330 memset(profile, 0, sizeof(ds_profile));
1332 clGetPlatformIDs(0, NULL, &numPlatforms);
1333 if (numPlatforms > 0) {
1334 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1335 if (platforms == NULL) {
1336 status = DS_MEMORY_ERROR;
1339 clGetPlatformIDs(numPlatforms, platforms, NULL);
1340 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1342 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num);
1347 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1349 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1350 if (profile->devices == NULL) {
1351 profile->numDevices = 0;
1352 status = DS_MEMORY_ERROR;
1355 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1357 if (numDevices > 0) {
1358 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1359 if (devices == NULL) {
1360 status = DS_MEMORY_ERROR;
1363 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1367 for (d = 0; d < 2; d++) {
1369 cl_device_type deviceType;
1372 deviceType = CL_DEVICE_TYPE_GPU;
1375 deviceType = CL_DEVICE_TYPE_CPU;
1381 if (clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
1383 for (j = 0; j < num; j++, next++) {
1386 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1387 profile->devices[next].oclDeviceID = devices[j];
1389 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1390 , 0, NULL, &length);
1391 profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
1392 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1393 , length, profile->devices[next].oclDeviceName, NULL);
1395 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1396 , 0, NULL, &length);
1397 profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
1398 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1399 , length, profile->devices[next].oclDriverVersion, NULL);
1401 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1402 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1404 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1405 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1411 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1412 profile->version = version;
1415 if (platforms) free(platforms);
1416 if (devices) free(devices);
1417 if (status == DS_SUCCESS) {
1422 if (profile->devices)
1423 free(profile->devices);
1430 /* Pointer to a function that calculates the score of a device (ex: device->score)
1431 update the data size of score. The encoding and the format of the score data
1432 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1434 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1438 ,DS_EVALUATE_NEW_ONLY
1439 } ds_evaluation_type;
1441 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1442 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1443 ds_status status = DS_SUCCESS;
1445 unsigned int updates = 0;
1447 if (profile == NULL) {
1448 return DS_INVALID_PROFILE;
1450 if (evaluator == NULL) {
1451 return DS_INVALID_PERF_EVALUATOR;
1454 for (i = 0; i < profile->numDevices; i++) {
1455 ds_status evaluatorStatus;
1458 case DS_EVALUATE_NEW_ONLY:
1459 if (profile->devices[i].score != NULL)
1461 /* else fall through */
1462 case DS_EVALUATE_ALL:
1463 evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
1464 if (evaluatorStatus != DS_SUCCESS) {
1465 status = evaluatorStatus;
1471 return DS_INVALID_PERF_EVALUATOR_TYPE;
1476 *numUpdates = updates;
1481 #define DS_TAG_VERSION "<version>"
1482 #define DS_TAG_VERSION_END "</version>"
1483 #define DS_TAG_DEVICE "<device>"
1484 #define DS_TAG_DEVICE_END "</device>"
1485 #define DS_TAG_SCORE "<score>"
1486 #define DS_TAG_SCORE_END "</score>"
1487 #define DS_TAG_DEVICE_TYPE "<type>"
1488 #define DS_TAG_DEVICE_TYPE_END "</type>"
1489 #define DS_TAG_DEVICE_NAME "<name>"
1490 #define DS_TAG_DEVICE_NAME_END "</name>"
1491 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1492 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1493 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1494 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1495 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1496 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1498 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1502 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1503 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1504 ds_status status = DS_SUCCESS;
1505 FILE* profileFile = NULL;
1508 if (profile == NULL)
1509 return DS_INVALID_PROFILE;
1511 profileFile = fopen(file, "wb");
1512 if (profileFile==NULL) {
1513 status = DS_FILE_ERROR;
1518 /* write version string */
1519 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1520 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1521 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1522 fwrite("\n", sizeof(char), 1, profileFile);
1524 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1525 void* serializedScore;
1526 unsigned int serializedScoreSize;
1528 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1530 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1531 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1532 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1534 switch(profile->devices[i].type) {
1535 case DS_DEVICE_NATIVE_CPU:
1537 /* There's no need to emit a device name for the native CPU device. */
1539 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1540 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1541 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1545 case DS_DEVICE_OPENCL_DEVICE:
1549 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1550 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1551 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1553 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1554 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1555 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1557 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1558 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1559 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1560 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1562 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1563 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1564 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1565 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1569 status = DS_UNKNOWN_DEVICE_TYPE;
1573 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1574 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1575 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1576 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1577 free(serializedScore);
1579 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1580 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1581 fwrite("\n",sizeof(char),1,profileFile);
1583 fclose(profileFile);
1589 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1590 ds_status status = DS_SUCCESS;
1591 FILE * input = NULL;
1594 char* binary = NULL;
1599 input = fopen(fileName, "rb");
1601 return DS_FILE_ERROR;
1604 fseek(input, 0L, SEEK_END);
1605 size = ftell(input);
1607 binary = (char*)malloc(size);
1608 if(binary == NULL) {
1609 status = DS_FILE_ERROR;
1612 rsize = fread(binary, sizeof(char), size, input);
1615 status = DS_FILE_ERROR;
1618 *contentSize = size;
1622 if (input != NULL) fclose(input);
1623 if (status != DS_SUCCESS
1624 && binary != NULL) {
1633 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1634 size_t stringLength;
1635 const char* currentPosition;
1638 stringLength = strlen(string);
1639 currentPosition = contentStart;
1640 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1641 if (*currentPosition == string[0]) {
1642 if (currentPosition+stringLength < contentEnd) {
1643 if (strncmp(currentPosition, string, stringLength) == 0) {
1644 found = currentPosition;
1654 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1655 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1657 ds_status status = DS_SUCCESS;
1658 char* contentStart = NULL;
1659 const char* contentEnd = NULL;
1663 return DS_INVALID_PROFILE;
1665 status = readProFile(file, &contentStart, &contentSize);
1666 if (status == DS_SUCCESS) {
1667 const char* currentPosition;
1668 const char* dataStart;
1669 const char* dataEnd;
1670 size_t versionStringLength;
1672 contentEnd = contentStart + contentSize;
1673 currentPosition = contentStart;
1676 /* parse the version string */
1677 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1678 if (dataStart == NULL) {
1679 status = DS_PROFILE_FILE_ERROR;
1682 dataStart += strlen(DS_TAG_VERSION);
1684 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1685 if (dataEnd==NULL) {
1686 status = DS_PROFILE_FILE_ERROR;
1690 versionStringLength = strlen(profile->version);
1691 if (versionStringLength!=(size_t)(dataEnd-dataStart)
1692 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1693 /* version mismatch */
1694 status = DS_PROFILE_FILE_ERROR;
1697 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1699 /* parse the device information */
1700 DisableMSCWarning(4127)
1705 const char* deviceTypeStart;
1706 const char* deviceTypeEnd;
1707 ds_device_type deviceType;
1709 const char* deviceNameStart;
1710 const char* deviceNameEnd;
1712 const char* deviceScoreStart;
1713 const char* deviceScoreEnd;
1715 const char* deviceDriverStart;
1716 const char* deviceDriverEnd;
1718 const char* tmpStart;
1722 cl_uint maxClockFrequency;
1723 cl_uint maxComputeUnits;
1725 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1726 if (dataStart==NULL) {
1727 /* nothing useful remain, quit...*/
1730 dataStart+=strlen(DS_TAG_DEVICE);
1731 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1732 if (dataEnd==NULL) {
1733 status = DS_PROFILE_FILE_ERROR;
1737 /* parse the device type */
1738 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1739 if (deviceTypeStart==NULL) {
1740 status = DS_PROFILE_FILE_ERROR;
1743 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1744 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1745 if (deviceTypeEnd==NULL) {
1746 status = DS_PROFILE_FILE_ERROR;
1749 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1752 /* parse the device name */
1753 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1755 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1756 if (deviceNameStart==NULL) {
1757 status = DS_PROFILE_FILE_ERROR;
1760 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1761 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1762 if (deviceNameEnd==NULL) {
1763 status = DS_PROFILE_FILE_ERROR;
1768 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1769 if (deviceDriverStart==NULL) {
1770 status = DS_PROFILE_FILE_ERROR;
1773 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1774 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1775 if (deviceDriverEnd ==NULL) {
1776 status = DS_PROFILE_FILE_ERROR;
1781 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1782 if (tmpStart==NULL) {
1783 status = DS_PROFILE_FILE_ERROR;
1786 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1787 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1788 if (tmpEnd ==NULL) {
1789 status = DS_PROFILE_FILE_ERROR;
1792 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1793 tmp[tmpEnd-tmpStart] = '\0';
1794 maxComputeUnits = atoi(tmp);
1797 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1798 if (tmpStart==NULL) {
1799 status = DS_PROFILE_FILE_ERROR;
1802 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1803 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1804 if (tmpEnd ==NULL) {
1805 status = DS_PROFILE_FILE_ERROR;
1808 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1809 tmp[tmpEnd-tmpStart] = '\0';
1810 maxClockFrequency = atoi(tmp);
1813 /* check if this device is on the system */
1814 for (i = 0; i < profile->numDevices; i++) {
1815 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1816 size_t actualDeviceNameLength;
1817 size_t driverVersionLength;
1819 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1820 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1821 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
1822 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
1823 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1824 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1825 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1826 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1828 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1829 if (deviceNameStart==NULL) {
1830 status = DS_PROFILE_FILE_ERROR;
1833 deviceScoreStart+=strlen(DS_TAG_SCORE);
1834 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1835 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1836 if (status != DS_SUCCESS) {
1844 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1845 for (i = 0; i < profile->numDevices; i++) {
1846 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1847 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1848 if (deviceScoreStart==NULL) {
1849 status = DS_PROFILE_FILE_ERROR;
1852 deviceScoreStart+=strlen(DS_TAG_SCORE);
1853 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1854 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1855 if (status != DS_SUCCESS) {
1862 /* skip over the current one to find the next device */
1863 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1867 if (contentStart!=NULL) free(contentStart);
1873 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1875 if (profile == NULL || num==NULL)
1876 return DS_MEMORY_ERROR;
1878 for (i = 0; i < profile->numDevices; i++) {
1879 if (profile->devices[i].score == NULL) {
1888 End of the OpenCL device selection infrastructure
1893 typedef struct _AccelerateTimer {
1899 static void startAccelerateTimer(AccelerateTimer* timer) {
1901 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
1906 gettimeofday(&s, 0);
1907 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1911 static void stopAccelerateTimer(AccelerateTimer* timer) {
1914 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
1917 gettimeofday(&s, 0);
1918 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1922 timer->_clocks += n;
1925 static void resetAccelerateTimer(AccelerateTimer* timer) {
1931 static void initAccelerateTimer(AccelerateTimer* timer) {
1933 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1935 timer->_freq = (long long)1.0E3;
1937 resetAccelerateTimer(timer);
1940 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1943 typedef double AccelerateScoreType;
1945 static ds_status AcceleratePerfEvaluator(ds_device *device,
1946 void *magick_unused(data))
1948 #define ACCELERATE_PERF_DIMEN "2048x1536"
1950 #define ReturnStatus(status) \
1953 RelinquishMagickOpenCLEnv(clEnv); \
1954 if (oldClEnv!=NULL) \
1955 defaultCLEnv = oldClEnv; \
1969 magick_unreferenced(data);
1972 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
1974 clEnv=AcquireMagickOpenCLEnv();
1975 exception=AcquireExceptionInfo();
1977 if (device->type == DS_DEVICE_NATIVE_CPU)
1980 MagickBooleanType flag=MagickTrue;
1981 SetMagickOpenCLEnvParamInternal(clEnv,
1982 MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
1985 else if (device->type == DS_DEVICE_OPENCL_DEVICE)
1988 SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
1989 sizeof(cl_device_id),&device->oclDeviceID,exception);
1992 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
1994 InitOpenCLEnvInternal(clEnv,exception);
1995 oldClEnv=defaultCLEnv;
1998 /* microbenchmark */
2009 imageInfo=AcquireImageInfo();
2010 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
2011 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
2012 inputImage=ReadImage(imageInfo,exception);
2014 initAccelerateTimer(&timer);
2016 for (i=0; i<=NUM_ITER; i++)
2024 startAccelerateTimer(&timer);
2026 #ifdef MAGICKCORE_CLPERFMARKER
2027 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2030 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2031 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2033 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
2036 #ifdef MAGICKCORE_CLPERFMARKER
2037 clEndPerfMarkerAMD();
2041 stopAccelerateTimer(&timer);
2044 DestroyImage(bluredImage);
2046 DestroyImage(unsharpedImage);
2048 DestroyImage(resizedImage);
2050 DestroyImage(inputImage);
2052 /* end of microbenchmark */
2054 if (device->score == NULL)
2055 device->score=malloc(sizeof(AccelerateScoreType));
2056 *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
2058 ReturnStatus(DS_SUCCESS);
2061 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2064 /* generate a string from the score */
2065 char* s = (char*)malloc(sizeof(char)*256);
2066 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2067 *serializedScore = (void*)s;
2068 *serializedScoreSize = strlen(s);
2072 return DS_SCORE_SERIALIZER_ERROR;
2076 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2078 /* convert the string back to an int */
2079 char* s = (char*)malloc(serializedScoreSize+1);
2080 memcpy(s, serializedScore, serializedScoreSize);
2081 s[serializedScoreSize] = (char)'\0';
2082 device->score = malloc(sizeof(AccelerateScoreType));
2083 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2088 return DS_SCORE_DESERIALIZER_ERROR;
2092 ds_status AccelerateScoreRelease(void* score) {
2100 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2101 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2102 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2104 MagickBooleanType mStatus = MagickFalse;
2106 ds_profile* profile;
2107 unsigned int numDeviceProfiled = 0;
2109 unsigned int bestDeviceIndex;
2110 AccelerateScoreType bestScore;
2111 char path[MaxTextExtent];
2112 MagickBooleanType flag;
2114 LockDefaultOpenCLEnv();
2116 /* Initially, just set OpenCL to off */
2118 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2119 , sizeof(MagickBooleanType), &flag, exception);
2121 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2122 if (status!=DS_SUCCESS) {
2123 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2127 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2128 ,GetOpenCLCachedFilesDirectory()
2129 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2131 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2132 status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2133 if (status!=DS_SUCCESS) {
2134 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2137 if (numDeviceProfiled > 0) {
2138 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2139 if (status!=DS_SUCCESS) {
2140 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2144 /* pick the best device */
2145 bestDeviceIndex = 0;
2146 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2147 for (i = 1; i < profile->numDevices; i++) {
2148 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2149 if (score < bestScore) {
2150 bestDeviceIndex = i;
2155 /* set up clEnv with the best device */
2156 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2159 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2160 , sizeof(MagickBooleanType), &flag, exception);
2162 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2165 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2166 , sizeof(MagickBooleanType), &flag, exception);
2167 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2168 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2171 status = DS_PERF_EVALUATOR_ERROR;
2174 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2176 status = releaseDSProfile(profile, AccelerateScoreRelease);
2177 if (status!=DS_SUCCESS) {
2178 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2183 UnlockDefaultOpenCLEnv();
2189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2193 + I n i t I m a g e M a g i c k O p e n C L %
2197 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2199 % InitImageMagickOpenCL() provides a simplified interface to initialize
2200 % the OpenCL environtment in ImageMagick
2202 % The format of the InitImageMagickOpenCL() method is:
2204 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2205 % void* userSelectedDevice,
2206 % void* selectedDevice)
2208 % A description of each parameter follows:
2210 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2212 % o userSelectedDevice: when in user mode, a pointer to the selected
2215 % o selectedDevice: a pointer to cl_device_id where the selected
2216 % cl_device_id by ImageMagick could be returned
2218 % o exception: exception
2221 MagickExport MagickBooleanType InitImageMagickOpenCL(
2222 ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2223 ExceptionInfo *exception)
2225 MagickBooleanType status = MagickTrue;
2226 MagickCLEnv clEnv = NULL;
2227 MagickBooleanType flag;
2229 clEnv = GetDefaultOpenCLEnv();
2233 case MAGICK_OPENCL_OFF:
2235 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2236 , sizeof(MagickBooleanType), &flag, exception);
2237 status = InitOpenCLEnv(clEnv, exception);
2240 *(cl_device_id*)selectedDevice = NULL;
2243 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2245 if (userSelectedDevice == NULL)
2249 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2250 , sizeof(MagickBooleanType), &flag, exception);
2252 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2253 , sizeof(cl_device_id), userSelectedDevice,exception);
2255 status = InitOpenCLEnv(clEnv, exception);
2256 if (selectedDevice) {
2257 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2258 , sizeof(cl_device_id), selectedDevice, exception);
2262 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2265 cl_device_id d = NULL;
2267 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2268 , sizeof(MagickBooleanType), &flag, exception);
2269 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2270 , sizeof(cl_device_id), &d,exception);
2271 status = InitOpenCLEnv(clEnv, exception);
2272 if (selectedDevice) {
2273 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2274 , sizeof(cl_device_id), selectedDevice, exception);
2285 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2286 const char *module,const char *function,const size_t line,
2287 const ExceptionType severity,const char *tag,const char *format,...) {
2293 status = MagickTrue;
2295 clEnv = GetDefaultOpenCLEnv();
2297 assert(exception != (ExceptionInfo *) NULL);
2298 assert(exception->signature == MagickSignature);
2301 cl_device_type dType;
2302 clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
2303 if (dType == CL_DEVICE_TYPE_CPU) {
2304 char buffer[MaxTextExtent];
2305 clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
2307 /* Workaround for Intel OpenCL CPU runtime bug */
2308 /* Turn off OpenCL when a problem is detected! */
2309 if (strncmp(buffer, "Intel",5) == 0) {
2311 InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2316 #ifdef OPENCLLOG_ENABLED
2320 va_start(operands,format);
2321 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2325 magick_unreferenced(module);
2326 magick_unreferenced(function);
2327 magick_unreferenced(line);
2328 magick_unreferenced(tag);
2329 magick_unreferenced(format);
2338 struct _MagickCLEnv {
2339 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2342 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2347 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2348 MagickCLEnv magick_unused(clEnv))
2350 magick_unreferenced(clEnv);
2356 * Return the OpenCL environment
2358 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2359 ExceptionInfo *magick_unused(exception))
2361 magick_unreferenced(exception);
2363 return (MagickCLEnv) NULL;
2366 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2367 MagickCLEnv magick_unused(clEnv))
2369 magick_unreferenced(clEnv);
2371 return (MagickCLEnv) NULL;
2374 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2375 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2376 size_t magick_unused(dataSize),void *magick_unused(data),
2377 ExceptionInfo *magick_unused(exception))
2379 magick_unreferenced(clEnv);
2380 magick_unreferenced(param);
2381 magick_unreferenced(dataSize);
2382 magick_unreferenced(data);
2383 magick_unreferenced(exception);
2388 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2389 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2390 size_t magick_unused(dataSize),void *magick_unused(data),
2391 ExceptionInfo *magick_unused(exception))
2393 magick_unreferenced(clEnv);
2394 magick_unreferenced(param);
2395 magick_unreferenced(dataSize);
2396 magick_unreferenced(data);
2397 magick_unreferenced(exception);
2402 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2403 ExceptionInfo *magick_unused(exception))
2405 magick_unreferenced(clEnv);
2406 magick_unreferenced(exception);
2411 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2412 MagickCLEnv magick_unused(clEnv))
2414 magick_unreferenced(clEnv);
2416 return (cl_command_queue) NULL;
2419 MagickExport MagickBooleanType RelinquishCommandQueue(
2420 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2422 magick_unreferenced(clEnv);
2423 magick_unreferenced(queue);
2428 MagickExport cl_kernel AcquireOpenCLKernel(
2429 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2430 const char *magick_unused(kernelName))
2432 magick_unreferenced(clEnv);
2433 magick_unreferenced(program);
2434 magick_unreferenced(kernelName);
2436 return (cl_kernel)NULL;
2439 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2440 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2442 magick_unreferenced(clEnv);
2443 magick_unreferenced(kernel);
2448 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2449 MagickCLEnv magick_unused(clEnv))
2451 magick_unreferenced(clEnv);
2456 MagickExport MagickBooleanType InitImageMagickOpenCL(
2457 ImageMagickOpenCLMode magick_unused(mode),
2458 void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2459 ExceptionInfo *magick_unused(exception))
2461 magick_unreferenced(mode);
2462 magick_unreferenced(userSelectedDevice);
2463 magick_unreferenced(selectedDevice);
2464 magick_unreferenced(exception);
2470 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2471 const char *module,const char *function,const size_t line,
2472 const ExceptionType severity,const char *tag,const char *format,...)
2474 magick_unreferenced(exception);
2475 magick_unreferenced(module);
2476 magick_unreferenced(function);
2477 magick_unreferenced(line);
2478 magick_unreferenced(severity);
2479 magick_unreferenced(tag);
2480 magick_unreferenced(format);
2481 return(MagickFalse);
2483 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2485 char* openclCachedFilesDirectory;
2486 SemaphoreInfo* openclCachedFilesDirectoryLock;
2489 const char* GetOpenCLCachedFilesDirectory() {
2490 if (openclCachedFilesDirectory == NULL) {
2491 if (openclCachedFilesDirectoryLock == NULL)
2493 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2495 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2496 if (openclCachedFilesDirectory == NULL) {
2497 char path[MaxTextExtent];
2500 struct stat attributes;
2501 MagickBooleanType status;
2503 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2504 home=GetEnvironmentValue("LOCALAPPDATA");
2505 if (home == (char *) NULL)
2506 home=GetEnvironmentValue("APPDATA");
2507 if (home == (char *) NULL)
2508 home=GetEnvironmentValue("USERPROFILE");
2510 home=GetEnvironmentValue("HOME");
2512 if (home != (char *) NULL)
2515 Search $HOME/.magick.
2517 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2518 DirectorySeparator);
2519 home=DestroyString(home);
2520 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2521 CopyMagickString(temp,path,strlen(path)+1);
2522 status=GetPathAttributes(path,&attributes);
2523 if (status == MagickFalse) {
2524 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2531 openclCachedFilesDirectory = temp;
2533 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2535 return openclCachedFilesDirectory;
2538 /* create a function for OpenCL log */
2540 void OpenCLLog(const char* message) {
2542 #ifdef OPENCLLOG_ENABLED
2543 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2546 if (getenv("MAGICK_OCL_LOG"))
2549 char path[MaxTextExtent];
2550 unsigned long allocSize;
2554 clEnv = GetDefaultOpenCLEnv();
2556 /* dump the source into a file */
2557 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2558 ,GetOpenCLCachedFilesDirectory()
2559 ,DirectorySeparator,OPENCL_LOG_FILE);
2562 log = fopen(path, "ab");
2563 fwrite(message, sizeof(char), strlen(message), log);
2564 fwrite("\n", sizeof(char), 1, log);
2566 if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
2568 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
2569 fprintf(log, "Devic Max Memory Alloc Size: %ld\n", allocSize);
2576 magick_unreferenced(message);