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
1245 #define DS_DEVICE_NAME_LENGTH 256
1249 ,DS_INVALID_PROFILE = 1000
1251 ,DS_INVALID_PERF_EVALUATOR_TYPE
1252 ,DS_INVALID_PERF_EVALUATOR
1253 ,DS_PERF_EVALUATOR_ERROR
1255 ,DS_UNKNOWN_DEVICE_TYPE
1256 ,DS_PROFILE_FILE_ERROR
1257 ,DS_SCORE_SERIALIZER_ERROR
1258 ,DS_SCORE_DESERIALIZER_ERROR
1263 DS_DEVICE_NATIVE_CPU = 0
1264 ,DS_DEVICE_OPENCL_DEVICE
1269 ds_device_type type;
1270 cl_device_id oclDeviceID;
1271 char* oclDeviceName;
1272 char* oclDriverVersion;
1273 cl_uint oclMaxClockFrequency;
1274 cl_uint oclMaxComputeUnits;
1275 void* score; /* a pointer to the score data, the content/format is application defined */
1279 unsigned int numDevices;
1281 const char* version;
1284 /* deallocate memory used by score */
1285 typedef ds_status (*ds_score_release)(void* score);
1287 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1288 ds_status status = DS_SUCCESS;
1290 if (device->oclDeviceName) free(device->oclDeviceName);
1291 if (device->oclDriverVersion) free(device->oclDriverVersion);
1292 if (device->score) status = sr(device->score);
1297 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1298 ds_status status = DS_SUCCESS;
1299 if (profile!=NULL) {
1300 if (profile->devices!=NULL && sr!=NULL) {
1302 for (i = 0; i < profile->numDevices; i++) {
1303 status = releaseDeviceResource(profile->devices+i,sr);
1304 if (status != DS_SUCCESS)
1307 free(profile->devices);
1315 static ds_status initDSProfile(ds_profile** p, const char* version) {
1317 cl_uint numPlatforms = 0;
1318 cl_platform_id* platforms = NULL;
1319 cl_device_id* devices = NULL;
1320 ds_status status = DS_SUCCESS;
1321 ds_profile* profile = NULL;
1322 unsigned int next = 0;
1326 return DS_INVALID_PROFILE;
1328 profile = (ds_profile*)malloc(sizeof(ds_profile));
1329 if (profile == NULL)
1330 return DS_MEMORY_ERROR;
1332 memset(profile, 0, sizeof(ds_profile));
1334 clGetPlatformIDs(0, NULL, &numPlatforms);
1335 if (numPlatforms > 0) {
1336 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1337 if (platforms == NULL) {
1338 status = DS_MEMORY_ERROR;
1341 clGetPlatformIDs(numPlatforms, platforms, NULL);
1342 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1344 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
1349 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1351 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1352 if (profile->devices == NULL) {
1353 profile->numDevices = 0;
1354 status = DS_MEMORY_ERROR;
1357 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1359 if (numDevices > 0) {
1360 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1361 if (devices == NULL) {
1362 status = DS_MEMORY_ERROR;
1365 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1369 for (d = 0; d < 2; d++) {
1371 cl_device_type deviceType;
1374 deviceType = CL_DEVICE_TYPE_GPU;
1377 deviceType = CL_DEVICE_TYPE_CPU;
1383 clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num);
1384 for (j = 0; j < num; j++, next++) {
1385 char buffer[DS_DEVICE_NAME_LENGTH];
1388 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1389 profile->devices[next].oclDeviceID = devices[j];
1391 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1392 , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1393 length = strlen(buffer);
1394 profile->devices[next].oclDeviceName = (char*)malloc(length+1);
1395 memcpy(profile->devices[next].oclDeviceName, buffer, length+1);
1397 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1398 , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1399 length = strlen(buffer);
1400 profile->devices[next].oclDriverVersion = (char*)malloc(length+1);
1401 memcpy(profile->devices[next].oclDriverVersion, buffer, length+1);
1403 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1404 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1406 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1407 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1413 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1414 profile->version = version;
1417 if (platforms) free(platforms);
1418 if (devices) free(devices);
1419 if (status == DS_SUCCESS) {
1424 if (profile->devices)
1425 free(profile->devices);
1433 Pointer to a function that updates the score of a device (ex: device->score)
\r
1434 The function should return DS_SUCCESS if there's no error to be reported.
\r
1436 typedef ds_status (*ds_perf_evaluator)(ds_device* device);
1440 ,DS_EVALUATE_NEW_ONLY
1441 } ds_evaluation_type;
1443 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1444 ,ds_perf_evaluator evaluator, unsigned int* numUpdates) {
1445 ds_status status = DS_SUCCESS;
1447 unsigned int updates = 0;
1449 if (profile == NULL) {
1450 return DS_INVALID_PROFILE;
1452 if (evaluator == NULL) {
1453 return DS_INVALID_PERF_EVALUATOR;
1456 for (i = 0; i < profile->numDevices; i++) {
1457 ds_status evaluatorStatus;
1460 case DS_EVALUATE_NEW_ONLY:
1461 if (profile->devices[i].score != NULL)
1463 /* else fall through */
1464 case DS_EVALUATE_ALL:
1465 evaluatorStatus = evaluator(profile->devices+i);
1466 if (evaluatorStatus != DS_SUCCESS) {
1467 status = evaluatorStatus;
1473 return DS_INVALID_PERF_EVALUATOR_TYPE;
1478 *numUpdates = updates;
1483 #define DS_TAG_VERSION "<version>"
1484 #define DS_TAG_VERSION_END "</version>"
1485 #define DS_TAG_DEVICE "<device>"
1486 #define DS_TAG_DEVICE_END "</device>"
1487 #define DS_TAG_SCORE "<score>"
1488 #define DS_TAG_SCORE_END "</score>"
1489 #define DS_TAG_DEVICE_TYPE "<type>"
1490 #define DS_TAG_DEVICE_TYPE_END "</type>"
1491 #define DS_TAG_DEVICE_NAME "<name>"
1492 #define DS_TAG_DEVICE_NAME_END "</name>"
1493 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1494 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1495 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1496 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1497 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1498 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1500 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1504 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1505 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1506 ds_status status = DS_SUCCESS;
1507 FILE* profileFile = NULL;
1510 if (profile == NULL)
1511 return DS_INVALID_PROFILE;
1513 profileFile = fopen(file, "wb");
1514 if (profileFile==NULL) {
1515 status = DS_FILE_ERROR;
1520 /* write version string */
1521 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1522 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1523 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1524 fwrite("\n", sizeof(char), 1, profileFile);
1526 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1527 void* serializedScore;
1528 unsigned int serializedScoreSize;
1530 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1532 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1533 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1534 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1536 switch(profile->devices[i].type) {
1537 case DS_DEVICE_NATIVE_CPU:
1539 /* There's no need to emit a device name for the native CPU device. */
1541 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1542 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1543 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1547 case DS_DEVICE_OPENCL_DEVICE:
1551 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1552 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1553 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1555 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1556 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1557 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1559 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1560 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1561 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1562 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1564 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1565 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1566 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1567 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1571 status = DS_UNKNOWN_DEVICE_TYPE;
1575 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1576 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1577 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1578 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1579 free(serializedScore);
1581 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1582 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1583 fwrite("\n",sizeof(char),1,profileFile);
1585 fclose(profileFile);
1591 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1592 ds_status status = DS_SUCCESS;
1593 FILE * input = NULL;
1596 char* binary = NULL;
1601 input = fopen(fileName, "rb");
1603 return DS_FILE_ERROR;
1606 fseek(input, 0L, SEEK_END);
1607 size = ftell(input);
1609 binary = (char*)malloc(size);
1610 if(binary == NULL) {
1611 status = DS_FILE_ERROR;
1614 rsize = fread(binary, sizeof(char), size, input);
1617 status = DS_FILE_ERROR;
1620 *contentSize = size;
1624 if (input != NULL) fclose(input);
1625 if (status != DS_SUCCESS
1626 && binary != NULL) {
1635 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1636 size_t stringLength;
1637 const char* currentPosition;
1640 stringLength = strlen(string);
1641 currentPosition = contentStart;
1642 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1643 if (*currentPosition == string[0]) {
1644 if (currentPosition+stringLength < contentEnd) {
1645 if (strncmp(currentPosition, string, stringLength) == 0) {
1646 found = currentPosition;
1656 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1657 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1659 ds_status status = DS_SUCCESS;
1660 char* contentStart = NULL;
1661 const char* contentEnd = NULL;
1665 return DS_INVALID_PROFILE;
1667 status = readProFile(file, &contentStart, &contentSize);
1668 if (status == DS_SUCCESS) {
1669 const char* currentPosition;
1670 const char* dataStart;
1671 const char* dataEnd;
1672 size_t versionStringLength;
1674 contentEnd = contentStart + contentSize;
1675 currentPosition = contentStart;
1678 /* parse the version string */
1679 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1680 if (dataStart == NULL) {
1681 status = DS_PROFILE_FILE_ERROR;
1684 dataStart += strlen(DS_TAG_VERSION);
1686 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1687 if (dataEnd==NULL) {
1688 status = DS_PROFILE_FILE_ERROR;
1692 versionStringLength = strlen(profile->version);
1693 if (versionStringLength!=(size_t)(dataEnd-dataStart)
1694 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1695 /* version mismatch */
1696 status = DS_PROFILE_FILE_ERROR;
1699 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1701 /* parse the device information */
1702 DisableMSCWarning(4127)
1707 const char* deviceTypeStart;
1708 const char* deviceTypeEnd;
1709 ds_device_type deviceType;
1711 const char* deviceNameStart;
1712 const char* deviceNameEnd;
1714 const char* deviceScoreStart;
1715 const char* deviceScoreEnd;
1717 const char* deviceDriverStart;
1718 const char* deviceDriverEnd;
1720 const char* tmpStart;
1724 cl_uint maxClockFrequency;
1725 cl_uint maxComputeUnits;
1727 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1728 if (dataStart==NULL) {
1729 /* nothing useful remain, quit...*/
1732 dataStart+=strlen(DS_TAG_DEVICE);
1733 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1734 if (dataEnd==NULL) {
1735 status = DS_PROFILE_FILE_ERROR;
1739 /* parse the device type */
1740 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1741 if (deviceTypeStart==NULL) {
1742 status = DS_PROFILE_FILE_ERROR;
1745 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1746 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1747 if (deviceTypeEnd==NULL) {
1748 status = DS_PROFILE_FILE_ERROR;
1751 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1754 /* parse the device name */
1755 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1757 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1758 if (deviceNameStart==NULL) {
1759 status = DS_PROFILE_FILE_ERROR;
1762 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1763 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1764 if (deviceNameEnd==NULL) {
1765 status = DS_PROFILE_FILE_ERROR;
1770 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1771 if (deviceDriverStart==NULL) {
1772 status = DS_PROFILE_FILE_ERROR;
1775 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1776 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1777 if (deviceDriverEnd ==NULL) {
1778 status = DS_PROFILE_FILE_ERROR;
1783 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1784 if (tmpStart==NULL) {
1785 status = DS_PROFILE_FILE_ERROR;
1788 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1789 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1790 if (tmpEnd ==NULL) {
1791 status = DS_PROFILE_FILE_ERROR;
1794 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1795 tmp[tmpEnd-tmpStart] = '\0';
1796 maxComputeUnits = atoi(tmp);
1799 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1800 if (tmpStart==NULL) {
1801 status = DS_PROFILE_FILE_ERROR;
1804 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1805 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1806 if (tmpEnd ==NULL) {
1807 status = DS_PROFILE_FILE_ERROR;
1810 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1811 tmp[tmpEnd-tmpStart] = '\0';
1812 maxClockFrequency = atoi(tmp);
1815 /* check if this device is on the system */
1816 for (i = 0; i < profile->numDevices; i++) {
1817 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1818 size_t actualDeviceNameLength;
1819 size_t driverVersionLength;
1821 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1822 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1823 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
1824 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
1825 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1826 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1827 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1828 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1830 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1831 if (deviceNameStart==NULL) {
1832 status = DS_PROFILE_FILE_ERROR;
1835 deviceScoreStart+=strlen(DS_TAG_SCORE);
1836 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1837 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1838 if (status != DS_SUCCESS) {
1846 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1847 for (i = 0; i < profile->numDevices; i++) {
1848 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1849 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1850 if (deviceScoreStart==NULL) {
1851 status = DS_PROFILE_FILE_ERROR;
1854 deviceScoreStart+=strlen(DS_TAG_SCORE);
1855 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1856 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1857 if (status != DS_SUCCESS) {
1864 /* skip over the current one to find the next device */
1865 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1869 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) {
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) {
1946 ds_status status = DS_SUCCESS;
1947 MagickCLEnv clEnv = NULL;
1948 MagickCLEnv oldClEnv = NULL;
1949 ExceptionInfo* exception = NULL;
1950 AccelerateTimer timer;
1952 if (device == NULL) {
1953 status = DS_PERF_EVALUATOR_ERROR;
1957 clEnv = AcquireMagickOpenCLEnv();
1958 exception = AcquireExceptionInfo();
1960 if (device->type == DS_DEVICE_NATIVE_CPU) {
1962 MagickBooleanType flag = MagickTrue;
1963 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
1964 , sizeof(MagickBooleanType), &flag, exception);
1966 else if (device->type == DS_DEVICE_OPENCL_DEVICE) {
1968 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
1969 , sizeof(cl_device_id), &device->oclDeviceID,exception);
1972 status = DS_PERF_EVALUATOR_ERROR;
1975 InitOpenCLEnvInternal(clEnv, exception);
1976 oldClEnv = defaultCLEnv;
1977 defaultCLEnv = clEnv;
1979 /* microbenchmark */
1981 #define ACCELERATE_PERF_DIMEN "2048x1536"
1985 ImageInfo* imageInfo;
1988 imageInfo = AcquireImageInfo();
1989 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
1990 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
1991 inputImage = ReadImage(imageInfo,exception);
1993 initAccelerateTimer(&timer);
1995 for (i = 0; i <=NUM_ITER; i++) {
1998 Image* unsharpedImage;
1999 Image* resizedImage;
2002 startAccelerateTimer(&timer);
2004 #ifdef MAGICKCORE_CLPERFMARKER
2005 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2008 bluredImage = BlurImage(inputImage, 10.0f, 3.5f, exception);
2009 unsharpedImage = UnsharpMaskImage(bluredImage, 2.0f,2.0f,50.0f,10.0f,exception);
2010 resizedImage = ResizeImage(unsharpedImage,640,480,LanczosFilter,exception);
2012 #ifdef MAGICKCORE_CLPERFMARKER
2013 clEndPerfMarkerAMD();
2017 stopAccelerateTimer(&timer);
2019 if (bluredImage) DestroyImage(bluredImage);
2020 if (unsharpedImage) DestroyImage(unsharpedImage);
2021 if (resizedImage) DestroyImage(resizedImage);
2023 DestroyImage(inputImage);
2025 /* end of microbenchmark */
2027 if (device->score == NULL) {
2028 device->score = malloc(sizeof(AccelerateScoreType));
2030 *(AccelerateScoreType*)device->score = readAccelerateTimer(&timer);
2034 RelinquishMagickOpenCLEnv(clEnv);
2036 defaultCLEnv = oldClEnv;
2042 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2045 /* generate a string from the score */
2046 char* s = (char*)malloc(sizeof(char)*256);
2047 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2048 *serializedScore = (void*)s;
2049 *serializedScoreSize = strlen(s);
2053 return DS_SCORE_SERIALIZER_ERROR;
2057 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2059 /* convert the string back to an int */
2060 char* s = (char*)malloc(serializedScoreSize+1);
2061 memcpy(s, serializedScore, serializedScoreSize);
2062 s[serializedScoreSize] = (char)'\0';
2063 device->score = malloc(sizeof(AccelerateScoreType));
2064 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2069 return DS_SCORE_DESERIALIZER_ERROR;
2073 ds_status AccelerateScoreRelease(void* score) {
2081 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2082 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2083 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2085 MagickBooleanType mStatus = MagickFalse;
2087 ds_profile* profile;
2088 unsigned int numDeviceProfiled = 0;
2090 unsigned int bestDeviceIndex;
2091 AccelerateScoreType bestScore;
2092 char path[MaxTextExtent];
2095 LockDefaultOpenCLEnv();
2097 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2098 if (status!=DS_SUCCESS) {
2099 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2103 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2104 ,GetOpenCLCachedFilesDirectory()
2105 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2107 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2108 status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, &numDeviceProfiled);
2109 if (status!=DS_SUCCESS) {
2110 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2113 if (numDeviceProfiled > 0) {
2114 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2115 if (status!=DS_SUCCESS) {
2116 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2120 /* pick the best device */
2121 bestDeviceIndex = 0;
2122 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2123 for (i = 1; i < profile->numDevices; i++) {
2124 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2125 if (score < bestScore) {
2126 bestDeviceIndex = i;
2131 /* set up clEnv with the best device */
2132 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2134 MagickBooleanType flag = MagickTrue;
2135 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2136 , sizeof(MagickBooleanType), &flag, exception);
2138 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2140 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2141 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2144 status = DS_PERF_EVALUATOR_ERROR;
2147 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2149 status = releaseDSProfile(profile, AccelerateScoreRelease);
2150 if (status!=DS_SUCCESS) {
2151 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2156 UnlockDefaultOpenCLEnv();
2162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 + I n i t I m a g e M a g i c k O p e n C L %
2170 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2172 % InitImageMagickOpenCL() provides a simplified interface to initialize
2173 % the OpenCL environtment in ImageMagick
2175 % The format of the InitImageMagickOpenCL() method is:
2177 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2178 % void* userSelectedDevice,
2179 % void* selectedDevice)
2181 % A description of each parameter follows:
2183 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2185 % o userSelectedDevice: when in user mode, a pointer to the selected
2188 % o selectedDevice: a pointer to cl_device_id where the selected
2189 % cl_device_id by ImageMagick could be returned
2191 % o exception: exception
2194 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2195 void* userSelectedDevice,
2196 void* selectedDevice,
2197 ExceptionInfo* exception) {
2199 MagickBooleanType status = MagickTrue;
2200 MagickCLEnv clEnv = NULL;
2201 MagickBooleanType flag;
2203 exception = AcquireExceptionInfo();
2204 clEnv = GetDefaultOpenCLEnv();
2208 case MAGICK_OPENCL_OFF:
2210 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2211 , sizeof(MagickBooleanType), &flag, exception);
2212 status = InitOpenCLEnv(clEnv, exception);
2215 *(cl_device_id*)selectedDevice = NULL;
2218 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2220 if (userSelectedDevice == NULL)
2224 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2225 , sizeof(MagickBooleanType), &flag, exception);
2227 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2228 , sizeof(cl_device_id), userSelectedDevice,exception);
2230 status = InitOpenCLEnv(clEnv, exception);
2231 if (selectedDevice) {
2232 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2233 , sizeof(cl_device_id), selectedDevice, exception);
2237 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2240 cl_device_id d = NULL;
2242 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2243 , sizeof(MagickBooleanType), &flag, exception);
2244 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2245 , sizeof(cl_device_id), &d,exception);
2246 status = InitOpenCLEnv(clEnv, exception);
2247 if (selectedDevice) {
2248 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2249 , sizeof(cl_device_id), selectedDevice, exception);
2261 struct _MagickCLEnv {
2262 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2265 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2270 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2271 MagickCLEnv magick_unused(clEnv))
2273 magick_unreferenced(clEnv);
2279 * Return the OpenCL environment
2281 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2282 ExceptionInfo *magick_unused(exception))
2284 magick_unreferenced(exception);
2286 return (MagickCLEnv) NULL;
2289 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2290 MagickCLEnv magick_unused(clEnv))
2292 magick_unreferenced(clEnv);
2294 return (MagickCLEnv) NULL;
2297 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2298 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2299 size_t magick_unused(dataSize),void *magick_unused(data),
2300 ExceptionInfo *magick_unused(exception))
2302 magick_unreferenced(clEnv);
2303 magick_unreferenced(param);
2304 magick_unreferenced(dataSize);
2305 magick_unreferenced(data);
2306 magick_unreferenced(exception);
2311 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2312 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2313 size_t magick_unused(dataSize),void *magick_unused(data),
2314 ExceptionInfo *magick_unused(exception))
2316 magick_unreferenced(clEnv);
2317 magick_unreferenced(param);
2318 magick_unreferenced(dataSize);
2319 magick_unreferenced(data);
2320 magick_unreferenced(exception);
2325 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2326 ExceptionInfo *magick_unused(exception))
2328 magick_unreferenced(clEnv);
2329 magick_unreferenced(exception);
2334 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2335 MagickCLEnv magick_unused(clEnv))
2337 magick_unreferenced(clEnv);
2339 return (cl_command_queue) NULL;
2342 MagickExport MagickBooleanType RelinquishCommandQueue(
2343 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2345 magick_unreferenced(clEnv);
2346 magick_unreferenced(queue);
2351 MagickExport cl_kernel AcquireOpenCLKernel(
2352 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2353 const char *magick_unused(kernelName))
2355 magick_unreferenced(clEnv);
2356 magick_unreferenced(program);
2357 magick_unreferenced(kernelName);
2359 return (cl_kernel)NULL;
2362 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2363 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2365 magick_unreferenced(clEnv);
2366 magick_unreferenced(kernel);
2371 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2372 MagickCLEnv magick_unused(clEnv))
2374 magick_unreferenced(clEnv);
2379 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2380 void* userSelectedDevice,
2381 void* selectedDevice,
2382 ExceptionInfo* exception)
2384 magick_unreferenced(mode);
2385 magick_unreferenced(userSelectedDevice);
2386 magick_unreferenced(selectedDevice);
2387 magick_unreferenced(exception);
2391 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2393 char* openclCachedFilesDirectory;
2394 SemaphoreInfo* openclCachedFilesDirectoryLock;
2397 const char* GetOpenCLCachedFilesDirectory() {
2398 if (openclCachedFilesDirectory == NULL) {
2399 if (openclCachedFilesDirectoryLock == NULL)
2401 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2403 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2404 if (openclCachedFilesDirectory == NULL) {
2405 char path[MaxTextExtent];
2408 struct stat attributes;
2409 MagickBooleanType status;
2411 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2412 home=GetEnvironmentValue("LOCALAPPDATA");
2413 if (home == (char *) NULL)
2414 home=GetEnvironmentValue("APPDATA");
2415 if (home == (char *) NULL)
2416 home=GetEnvironmentValue("USERPROFILE");
2418 home=GetEnvironmentValue("HOME");
2420 if (home != (char *) NULL)
2423 Search $HOME/.magick.
2425 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2426 DirectorySeparator);
2427 home=DestroyString(home);
2428 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2429 CopyMagickString(temp,path,strlen(path)+1);
2430 status=GetPathAttributes(path,&attributes);
2431 if (status == MagickFalse) {
2432 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2439 openclCachedFilesDirectory = temp;
2441 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2443 return openclCachedFilesDirectory;
2446 /* create a function for OpenCL log */
2448 void OpenCLLog(const char* message) {
2450 #ifdef OPENCLLOG_ENABLED
2451 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2454 if (getenv("MAGICK_OCL_LOG"))
2457 char path[MaxTextExtent];
2459 /* dump the source into a file */
2460 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2461 ,GetOpenCLCachedFilesDirectory()
2462 ,DirectorySeparator,OPENCL_LOG_FILE);
2465 log = fopen(path, "ab");
2466 fwrite(message, sizeof(char), strlen(message), log);
2467 fwrite("\n", sizeof(char), 1, log);
2472 magick_unreferenced(message);