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_ALL, 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 clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num);
1382 for (j = 0; j < num; j++, next++) {
1385 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1386 profile->devices[next].oclDeviceID = devices[j];
1388 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
\r
1389 , 0, NULL, &length);
\r
1390 profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
\r
1391 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
\r
1392 , length, profile->devices[next].oclDeviceName, NULL);
\r
1394 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
\r
1395 , 0, NULL, &length);
\r
1396 profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
\r
1397 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
\r
1398 , length, profile->devices[next].oclDriverVersion, NULL);
1400 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1401 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1403 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1404 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1410 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1411 profile->version = version;
1414 if (platforms) free(platforms);
1415 if (devices) free(devices);
1416 if (status == DS_SUCCESS) {
1421 if (profile->devices)
1422 free(profile->devices);
1429 /* Pointer to a function that calculates the score of a device (ex: device->score)
1430 update the data size of score. The encoding and the format of the score data
1431 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1433 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1437 ,DS_EVALUATE_NEW_ONLY
1438 } ds_evaluation_type;
1440 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1441 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1442 ds_status status = DS_SUCCESS;
1444 unsigned int updates = 0;
1446 if (profile == NULL) {
1447 return DS_INVALID_PROFILE;
1449 if (evaluator == NULL) {
1450 return DS_INVALID_PERF_EVALUATOR;
1453 for (i = 0; i < profile->numDevices; i++) {
1454 ds_status evaluatorStatus;
1457 case DS_EVALUATE_NEW_ONLY:
1458 if (profile->devices[i].score != NULL)
1460 /* else fall through */
1461 case DS_EVALUATE_ALL:
1462 evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
1463 if (evaluatorStatus != DS_SUCCESS) {
1464 status = evaluatorStatus;
1470 return DS_INVALID_PERF_EVALUATOR_TYPE;
1475 *numUpdates = updates;
1480 #define DS_TAG_VERSION "<version>"
1481 #define DS_TAG_VERSION_END "</version>"
1482 #define DS_TAG_DEVICE "<device>"
1483 #define DS_TAG_DEVICE_END "</device>"
1484 #define DS_TAG_SCORE "<score>"
1485 #define DS_TAG_SCORE_END "</score>"
1486 #define DS_TAG_DEVICE_TYPE "<type>"
1487 #define DS_TAG_DEVICE_TYPE_END "</type>"
1488 #define DS_TAG_DEVICE_NAME "<name>"
1489 #define DS_TAG_DEVICE_NAME_END "</name>"
1490 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1491 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1492 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1493 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1494 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1495 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1497 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1501 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1502 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1503 ds_status status = DS_SUCCESS;
1504 FILE* profileFile = NULL;
1507 if (profile == NULL)
1508 return DS_INVALID_PROFILE;
1510 profileFile = fopen(file, "wb");
1511 if (profileFile==NULL) {
1512 status = DS_FILE_ERROR;
1517 /* write version string */
1518 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1519 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1520 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1521 fwrite("\n", sizeof(char), 1, profileFile);
1523 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1524 void* serializedScore;
1525 unsigned int serializedScoreSize;
1527 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1529 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1530 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1531 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1533 switch(profile->devices[i].type) {
1534 case DS_DEVICE_NATIVE_CPU:
1536 /* There's no need to emit a device name for the native CPU device. */
1538 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1539 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1540 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1544 case DS_DEVICE_OPENCL_DEVICE:
1548 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1549 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1550 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1552 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1553 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1554 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1556 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1557 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1558 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1559 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1561 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1562 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1563 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1564 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1568 status = DS_UNKNOWN_DEVICE_TYPE;
1572 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1573 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1574 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1575 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1576 free(serializedScore);
1578 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1579 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1580 fwrite("\n",sizeof(char),1,profileFile);
1582 fclose(profileFile);
1588 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1589 ds_status status = DS_SUCCESS;
1590 FILE * input = NULL;
1593 char* binary = NULL;
1598 input = fopen(fileName, "rb");
1600 return DS_FILE_ERROR;
1603 fseek(input, 0L, SEEK_END);
1604 size = ftell(input);
1606 binary = (char*)malloc(size);
1607 if(binary == NULL) {
1608 status = DS_FILE_ERROR;
1611 rsize = fread(binary, sizeof(char), size, input);
1614 status = DS_FILE_ERROR;
1617 *contentSize = size;
1621 if (input != NULL) fclose(input);
1622 if (status != DS_SUCCESS
1623 && binary != NULL) {
1632 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1633 size_t stringLength;
1634 const char* currentPosition;
1637 stringLength = strlen(string);
1638 currentPosition = contentStart;
1639 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1640 if (*currentPosition == string[0]) {
1641 if (currentPosition+stringLength < contentEnd) {
1642 if (strncmp(currentPosition, string, stringLength) == 0) {
1643 found = currentPosition;
1653 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1654 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1656 ds_status status = DS_SUCCESS;
1657 char* contentStart = NULL;
1658 const char* contentEnd = NULL;
1662 return DS_INVALID_PROFILE;
1664 status = readProFile(file, &contentStart, &contentSize);
1665 if (status == DS_SUCCESS) {
1666 const char* currentPosition;
1667 const char* dataStart;
1668 const char* dataEnd;
1669 size_t versionStringLength;
1671 contentEnd = contentStart + contentSize;
1672 currentPosition = contentStart;
1675 /* parse the version string */
1676 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1677 if (dataStart == NULL) {
1678 status = DS_PROFILE_FILE_ERROR;
1681 dataStart += strlen(DS_TAG_VERSION);
1683 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1684 if (dataEnd==NULL) {
1685 status = DS_PROFILE_FILE_ERROR;
1689 versionStringLength = strlen(profile->version);
1690 if (versionStringLength!=(size_t)(dataEnd-dataStart)
1691 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1692 /* version mismatch */
1693 status = DS_PROFILE_FILE_ERROR;
1696 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1698 /* parse the device information */
1699 DisableMSCWarning(4127)
1704 const char* deviceTypeStart;
1705 const char* deviceTypeEnd;
1706 ds_device_type deviceType;
1708 const char* deviceNameStart;
1709 const char* deviceNameEnd;
1711 const char* deviceScoreStart;
1712 const char* deviceScoreEnd;
1714 const char* deviceDriverStart;
1715 const char* deviceDriverEnd;
1717 const char* tmpStart;
1721 cl_uint maxClockFrequency;
1722 cl_uint maxComputeUnits;
1724 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1725 if (dataStart==NULL) {
1726 /* nothing useful remain, quit...*/
1729 dataStart+=strlen(DS_TAG_DEVICE);
1730 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1731 if (dataEnd==NULL) {
1732 status = DS_PROFILE_FILE_ERROR;
1736 /* parse the device type */
1737 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1738 if (deviceTypeStart==NULL) {
1739 status = DS_PROFILE_FILE_ERROR;
1742 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1743 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1744 if (deviceTypeEnd==NULL) {
1745 status = DS_PROFILE_FILE_ERROR;
1748 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1751 /* parse the device name */
1752 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1754 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1755 if (deviceNameStart==NULL) {
1756 status = DS_PROFILE_FILE_ERROR;
1759 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1760 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1761 if (deviceNameEnd==NULL) {
1762 status = DS_PROFILE_FILE_ERROR;
1767 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1768 if (deviceDriverStart==NULL) {
1769 status = DS_PROFILE_FILE_ERROR;
1772 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1773 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1774 if (deviceDriverEnd ==NULL) {
1775 status = DS_PROFILE_FILE_ERROR;
1780 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1781 if (tmpStart==NULL) {
1782 status = DS_PROFILE_FILE_ERROR;
1785 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1786 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1787 if (tmpEnd ==NULL) {
1788 status = DS_PROFILE_FILE_ERROR;
1791 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1792 tmp[tmpEnd-tmpStart] = '\0';
1793 maxComputeUnits = atoi(tmp);
1796 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1797 if (tmpStart==NULL) {
1798 status = DS_PROFILE_FILE_ERROR;
1801 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1802 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1803 if (tmpEnd ==NULL) {
1804 status = DS_PROFILE_FILE_ERROR;
1807 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1808 tmp[tmpEnd-tmpStart] = '\0';
1809 maxClockFrequency = atoi(tmp);
1812 /* check if this device is on the system */
1813 for (i = 0; i < profile->numDevices; i++) {
1814 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1815 size_t actualDeviceNameLength;
1816 size_t driverVersionLength;
1818 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1819 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1820 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
1821 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
1822 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1823 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1824 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1825 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1827 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1828 if (deviceNameStart==NULL) {
1829 status = DS_PROFILE_FILE_ERROR;
1832 deviceScoreStart+=strlen(DS_TAG_SCORE);
1833 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1834 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1835 if (status != DS_SUCCESS) {
1843 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1844 for (i = 0; i < profile->numDevices; i++) {
1845 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1846 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1847 if (deviceScoreStart==NULL) {
1848 status = DS_PROFILE_FILE_ERROR;
1851 deviceScoreStart+=strlen(DS_TAG_SCORE);
1852 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1853 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1854 if (status != DS_SUCCESS) {
1861 /* skip over the current one to find the next device */
1862 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1866 if (contentStart!=NULL) free(contentStart);
1872 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1874 if (profile == NULL || num==NULL)
1875 return DS_MEMORY_ERROR;
1877 for (i = 0; i < profile->numDevices; i++) {
1878 if (profile->devices[i].score == NULL) {
1887 End of the OpenCL device selection infrastructure
1892 typedef struct _AccelerateTimer {
1898 static void startAccelerateTimer(AccelerateTimer* timer) {
1900 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
1905 gettimeofday(&s, 0);
1906 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1910 static void stopAccelerateTimer(AccelerateTimer* timer) {
1913 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
1916 gettimeofday(&s, 0);
1917 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1921 timer->_clocks += n;
1924 static void resetAccelerateTimer(AccelerateTimer* timer) {
1930 static void initAccelerateTimer(AccelerateTimer* timer) {
1932 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1934 timer->_freq = (long long)1.0E3;
1936 resetAccelerateTimer(timer);
1939 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1942 typedef double AccelerateScoreType;
1944 static ds_status AcceleratePerfEvaluator(ds_device *device,
1945 void *magick_unused(data))
1947 #define ACCELERATE_PERF_DIMEN "2048x1536"
1949 #define ReturnStatus(status) \
1952 RelinquishMagickOpenCLEnv(clEnv); \
1953 if (oldClEnv!=NULL) \
1954 defaultCLEnv = oldClEnv; \
1968 magick_unreferenced(data);
1971 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
1973 clEnv=AcquireMagickOpenCLEnv();
1974 exception=AcquireExceptionInfo();
1976 if (device->type == DS_DEVICE_NATIVE_CPU)
1979 MagickBooleanType flag=MagickTrue;
1980 SetMagickOpenCLEnvParamInternal(clEnv,
1981 MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
1984 else if (device->type == DS_DEVICE_OPENCL_DEVICE)
1987 SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
1988 sizeof(cl_device_id),&device->oclDeviceID,exception);
1991 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
1993 InitOpenCLEnvInternal(clEnv,exception);
1994 oldClEnv=defaultCLEnv;
1997 /* microbenchmark */
2008 imageInfo=AcquireImageInfo();
2009 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
2010 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
2011 inputImage=ReadImage(imageInfo,exception);
2013 initAccelerateTimer(&timer);
2015 for (i=0; i<=NUM_ITER; i++)
2023 startAccelerateTimer(&timer);
2025 #ifdef MAGICKCORE_CLPERFMARKER
2026 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2029 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2030 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2032 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
2035 #ifdef MAGICKCORE_CLPERFMARKER
2036 clEndPerfMarkerAMD();
2040 stopAccelerateTimer(&timer);
2043 DestroyImage(bluredImage);
2045 DestroyImage(unsharpedImage);
2047 DestroyImage(resizedImage);
2049 DestroyImage(inputImage);
2051 /* end of microbenchmark */
2053 if (device->score == NULL)
2054 device->score=malloc(sizeof(AccelerateScoreType));
2055 *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
2057 ReturnStatus(DS_SUCCESS);
2060 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2063 /* generate a string from the score */
2064 char* s = (char*)malloc(sizeof(char)*256);
2065 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2066 *serializedScore = (void*)s;
2067 *serializedScoreSize = strlen(s);
2071 return DS_SCORE_SERIALIZER_ERROR;
2075 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2077 /* convert the string back to an int */
2078 char* s = (char*)malloc(serializedScoreSize+1);
2079 memcpy(s, serializedScore, serializedScoreSize);
2080 s[serializedScoreSize] = (char)'\0';
2081 device->score = malloc(sizeof(AccelerateScoreType));
2082 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2087 return DS_SCORE_DESERIALIZER_ERROR;
2091 ds_status AccelerateScoreRelease(void* score) {
2099 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2100 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2101 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2103 MagickBooleanType mStatus = MagickFalse;
2105 ds_profile* profile;
2106 unsigned int numDeviceProfiled = 0;
2108 unsigned int bestDeviceIndex;
2109 AccelerateScoreType bestScore;
2110 char path[MaxTextExtent];
2111 MagickBooleanType flag;
2113 LockDefaultOpenCLEnv();
2115 /* Initially, just set OpenCL to off */
2117 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2118 , sizeof(MagickBooleanType), &flag, exception);
2120 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2121 if (status!=DS_SUCCESS) {
2122 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2126 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2127 ,GetOpenCLCachedFilesDirectory()
2128 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2130 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2131 status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2132 if (status!=DS_SUCCESS) {
2133 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2136 if (numDeviceProfiled > 0) {
2137 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2138 if (status!=DS_SUCCESS) {
2139 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2143 /* pick the best device */
2144 bestDeviceIndex = 0;
2145 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2146 for (i = 1; i < profile->numDevices; i++) {
2147 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2148 if (score < bestScore) {
2149 bestDeviceIndex = i;
2154 /* set up clEnv with the best device */
2155 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2158 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2159 , sizeof(MagickBooleanType), &flag, exception);
2161 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2164 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2165 , sizeof(MagickBooleanType), &flag, exception);
2166 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2167 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2170 status = DS_PERF_EVALUATOR_ERROR;
2173 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2175 status = releaseDSProfile(profile, AccelerateScoreRelease);
2176 if (status!=DS_SUCCESS) {
2177 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2182 UnlockDefaultOpenCLEnv();
2188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2192 + I n i t I m a g e M a g i c k O p e n C L %
2196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2198 % InitImageMagickOpenCL() provides a simplified interface to initialize
2199 % the OpenCL environtment in ImageMagick
2201 % The format of the InitImageMagickOpenCL() method is:
2203 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2204 % void* userSelectedDevice,
2205 % void* selectedDevice)
2207 % A description of each parameter follows:
2209 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2211 % o userSelectedDevice: when in user mode, a pointer to the selected
2214 % o selectedDevice: a pointer to cl_device_id where the selected
2215 % cl_device_id by ImageMagick could be returned
2217 % o exception: exception
2220 MagickExport MagickBooleanType InitImageMagickOpenCL(
2221 ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2222 ExceptionInfo *exception)
2224 MagickBooleanType status = MagickTrue;
2225 MagickCLEnv clEnv = NULL;
2226 MagickBooleanType flag;
2228 clEnv = GetDefaultOpenCLEnv();
2232 case MAGICK_OPENCL_OFF:
2234 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2235 , sizeof(MagickBooleanType), &flag, exception);
2236 status = InitOpenCLEnv(clEnv, exception);
2239 *(cl_device_id*)selectedDevice = NULL;
2242 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2244 if (userSelectedDevice == NULL)
2248 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2249 , sizeof(MagickBooleanType), &flag, exception);
2251 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2252 , sizeof(cl_device_id), userSelectedDevice,exception);
2254 status = InitOpenCLEnv(clEnv, exception);
2255 if (selectedDevice) {
2256 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2257 , sizeof(cl_device_id), selectedDevice, exception);
2261 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2264 cl_device_id d = NULL;
2266 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2267 , sizeof(MagickBooleanType), &flag, exception);
2268 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2269 , sizeof(cl_device_id), &d,exception);
2270 status = InitOpenCLEnv(clEnv, exception);
2271 if (selectedDevice) {
2272 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2273 , sizeof(cl_device_id), selectedDevice, exception);
2284 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2285 const char *module,const char *function,const size_t line,
2286 const ExceptionType severity,const char *tag,const char *format,...) {
2292 status = MagickTrue;
2294 clEnv = GetDefaultOpenCLEnv();
2296 assert(exception != (ExceptionInfo *) NULL);
2297 assert(exception->signature == MagickSignature);
2300 cl_device_type dType;
2301 clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
2302 if (dType == CL_DEVICE_TYPE_CPU) {
2303 char buffer[MaxTextExtent];
2304 clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
2306 /* Workaround for Intel OpenCL CPU runtime bug */
2307 /* Turn off OpenCL when a problem is detected! */
2308 if (strncmp(buffer, "Intel",5) == 0) {
2310 InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2315 #ifdef OPENCLLOG_ENABLED
2319 va_start(operands,format);
2320 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2324 magick_unreferenced(module);
2325 magick_unreferenced(function);
2326 magick_unreferenced(line);
2327 magick_unreferenced(tag);
2328 magick_unreferenced(format);
2337 struct _MagickCLEnv {
2338 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2341 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2346 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2347 MagickCLEnv magick_unused(clEnv))
2349 magick_unreferenced(clEnv);
2355 * Return the OpenCL environment
2357 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2358 ExceptionInfo *magick_unused(exception))
2360 magick_unreferenced(exception);
2362 return (MagickCLEnv) NULL;
2365 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2366 MagickCLEnv magick_unused(clEnv))
2368 magick_unreferenced(clEnv);
2370 return (MagickCLEnv) NULL;
2373 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2374 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2375 size_t magick_unused(dataSize),void *magick_unused(data),
2376 ExceptionInfo *magick_unused(exception))
2378 magick_unreferenced(clEnv);
2379 magick_unreferenced(param);
2380 magick_unreferenced(dataSize);
2381 magick_unreferenced(data);
2382 magick_unreferenced(exception);
2387 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2388 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2389 size_t magick_unused(dataSize),void *magick_unused(data),
2390 ExceptionInfo *magick_unused(exception))
2392 magick_unreferenced(clEnv);
2393 magick_unreferenced(param);
2394 magick_unreferenced(dataSize);
2395 magick_unreferenced(data);
2396 magick_unreferenced(exception);
2401 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2402 ExceptionInfo *magick_unused(exception))
2404 magick_unreferenced(clEnv);
2405 magick_unreferenced(exception);
2410 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2411 MagickCLEnv magick_unused(clEnv))
2413 magick_unreferenced(clEnv);
2415 return (cl_command_queue) NULL;
2418 MagickExport MagickBooleanType RelinquishCommandQueue(
2419 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2421 magick_unreferenced(clEnv);
2422 magick_unreferenced(queue);
2427 MagickExport cl_kernel AcquireOpenCLKernel(
2428 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2429 const char *magick_unused(kernelName))
2431 magick_unreferenced(clEnv);
2432 magick_unreferenced(program);
2433 magick_unreferenced(kernelName);
2435 return (cl_kernel)NULL;
2438 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2439 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2441 magick_unreferenced(clEnv);
2442 magick_unreferenced(kernel);
2447 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2448 MagickCLEnv magick_unused(clEnv))
2450 magick_unreferenced(clEnv);
2455 MagickExport MagickBooleanType InitImageMagickOpenCL(
2456 ImageMagickOpenCLMode magick_unused(mode),
2457 void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2458 ExceptionInfo *magick_unused(exception))
2460 magick_unreferenced(mode);
2461 magick_unreferenced(userSelectedDevice);
2462 magick_unreferenced(selectedDevice);
2463 magick_unreferenced(exception);
2469 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2470 const char *module,const char *function,const size_t line,
2471 const ExceptionType severity,const char *tag,const char *format,...)
2473 magick_unreferenced(exception);
2474 magick_unreferenced(module);
2475 magick_unreferenced(function);
2476 magick_unreferenced(line);
2477 magick_unreferenced(severity);
2478 magick_unreferenced(tag);
2479 magick_unreferenced(format);
2480 return(MagickFalse);
2482 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2484 char* openclCachedFilesDirectory;
2485 SemaphoreInfo* openclCachedFilesDirectoryLock;
2488 const char* GetOpenCLCachedFilesDirectory() {
2489 if (openclCachedFilesDirectory == NULL) {
2490 if (openclCachedFilesDirectoryLock == NULL)
2492 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2494 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2495 if (openclCachedFilesDirectory == NULL) {
2496 char path[MaxTextExtent];
2499 struct stat attributes;
2500 MagickBooleanType status;
2502 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2503 home=GetEnvironmentValue("LOCALAPPDATA");
2504 if (home == (char *) NULL)
2505 home=GetEnvironmentValue("APPDATA");
2506 if (home == (char *) NULL)
2507 home=GetEnvironmentValue("USERPROFILE");
2509 home=GetEnvironmentValue("HOME");
2511 if (home != (char *) NULL)
2514 Search $HOME/.magick.
2516 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2517 DirectorySeparator);
2518 home=DestroyString(home);
2519 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2520 CopyMagickString(temp,path,strlen(path)+1);
2521 status=GetPathAttributes(path,&attributes);
2522 if (status == MagickFalse) {
2523 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2530 openclCachedFilesDirectory = temp;
2532 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2534 return openclCachedFilesDirectory;
2537 /* create a function for OpenCL log */
2539 void OpenCLLog(const char* message) {
2541 #ifdef OPENCLLOG_ENABLED
2542 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2545 if (getenv("MAGICK_OCL_LOG"))
2548 char path[MaxTextExtent];
2549 unsigned long allocSize;
2553 clEnv = GetDefaultOpenCLEnv();
2555 /* dump the source into a file */
2556 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2557 ,GetOpenCLCachedFilesDirectory()
2558 ,DirectorySeparator,OPENCL_LOG_FILE);
2561 log = fopen(path, "ab");
2562 fwrite(message, sizeof(char), strlen(message), log);
2563 fwrite("\n", sizeof(char), 1, log);
2565 if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
2567 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
2568 fprintf(log, "Devic Max Memory Alloc Size: %ld\n", allocSize);
2575 magick_unreferenced(message);