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);
1432 /* Pointer to a function that calculates the score of a device (ex: device->score)
1433 update the data size of score. The encoding and the format of the score data
1434 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1436 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
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, void* evaluatorData, 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,evaluatorData);
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,
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];
2113 LockDefaultOpenCLEnv();
2115 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2116 if (status!=DS_SUCCESS) {
2117 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2121 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2122 ,GetOpenCLCachedFilesDirectory()
2123 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2125 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2126 status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2127 if (status!=DS_SUCCESS) {
2128 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2131 if (numDeviceProfiled > 0) {
2132 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2133 if (status!=DS_SUCCESS) {
2134 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2138 /* pick the best device */
2139 bestDeviceIndex = 0;
2140 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2141 for (i = 1; i < profile->numDevices; i++) {
2142 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2143 if (score < bestScore) {
2144 bestDeviceIndex = i;
2149 /* set up clEnv with the best device */
2150 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2152 MagickBooleanType flag = MagickTrue;
2153 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2154 , sizeof(MagickBooleanType), &flag, exception);
2156 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2158 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2159 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2162 status = DS_PERF_EVALUATOR_ERROR;
2165 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2167 status = releaseDSProfile(profile, AccelerateScoreRelease);
2168 if (status!=DS_SUCCESS) {
2169 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2174 UnlockDefaultOpenCLEnv();
2180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2184 + I n i t I m a g e M a g i c k O p e n C L %
2188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2190 % InitImageMagickOpenCL() provides a simplified interface to initialize
2191 % the OpenCL environtment in ImageMagick
2193 % The format of the InitImageMagickOpenCL() method is:
2195 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2196 % void* userSelectedDevice,
2197 % void* selectedDevice)
2199 % A description of each parameter follows:
2201 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2203 % o userSelectedDevice: when in user mode, a pointer to the selected
2206 % o selectedDevice: a pointer to cl_device_id where the selected
2207 % cl_device_id by ImageMagick could be returned
2209 % o exception: exception
2212 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2213 void* userSelectedDevice,
2214 void* selectedDevice,
2215 ExceptionInfo* exception) {
2217 MagickBooleanType status = MagickTrue;
2218 MagickCLEnv clEnv = NULL;
2219 MagickBooleanType flag;
2221 exception = AcquireExceptionInfo();
2222 clEnv = GetDefaultOpenCLEnv();
2226 case MAGICK_OPENCL_OFF:
2228 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2229 , sizeof(MagickBooleanType), &flag, exception);
2230 status = InitOpenCLEnv(clEnv, exception);
2233 *(cl_device_id*)selectedDevice = NULL;
2236 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2238 if (userSelectedDevice == NULL)
2242 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2243 , sizeof(MagickBooleanType), &flag, exception);
2245 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2246 , sizeof(cl_device_id), userSelectedDevice,exception);
2248 status = InitOpenCLEnv(clEnv, exception);
2249 if (selectedDevice) {
2250 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2251 , sizeof(cl_device_id), selectedDevice, exception);
2255 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2258 cl_device_id d = NULL;
2260 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2261 , sizeof(MagickBooleanType), &flag, exception);
2262 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2263 , sizeof(cl_device_id), &d,exception);
2264 status = InitOpenCLEnv(clEnv, exception);
2265 if (selectedDevice) {
2266 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2267 , sizeof(cl_device_id), selectedDevice, exception);
2279 struct _MagickCLEnv {
2280 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2283 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2288 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2289 MagickCLEnv magick_unused(clEnv))
2291 magick_unreferenced(clEnv);
2297 * Return the OpenCL environment
2299 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2300 ExceptionInfo *magick_unused(exception))
2302 magick_unreferenced(exception);
2304 return (MagickCLEnv) NULL;
2307 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2308 MagickCLEnv magick_unused(clEnv))
2310 magick_unreferenced(clEnv);
2312 return (MagickCLEnv) NULL;
2315 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2316 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2317 size_t magick_unused(dataSize),void *magick_unused(data),
2318 ExceptionInfo *magick_unused(exception))
2320 magick_unreferenced(clEnv);
2321 magick_unreferenced(param);
2322 magick_unreferenced(dataSize);
2323 magick_unreferenced(data);
2324 magick_unreferenced(exception);
2329 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2330 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2331 size_t magick_unused(dataSize),void *magick_unused(data),
2332 ExceptionInfo *magick_unused(exception))
2334 magick_unreferenced(clEnv);
2335 magick_unreferenced(param);
2336 magick_unreferenced(dataSize);
2337 magick_unreferenced(data);
2338 magick_unreferenced(exception);
2343 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2344 ExceptionInfo *magick_unused(exception))
2346 magick_unreferenced(clEnv);
2347 magick_unreferenced(exception);
2352 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2353 MagickCLEnv magick_unused(clEnv))
2355 magick_unreferenced(clEnv);
2357 return (cl_command_queue) NULL;
2360 MagickExport MagickBooleanType RelinquishCommandQueue(
2361 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2363 magick_unreferenced(clEnv);
2364 magick_unreferenced(queue);
2369 MagickExport cl_kernel AcquireOpenCLKernel(
2370 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2371 const char *magick_unused(kernelName))
2373 magick_unreferenced(clEnv);
2374 magick_unreferenced(program);
2375 magick_unreferenced(kernelName);
2377 return (cl_kernel)NULL;
2380 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2381 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2383 magick_unreferenced(clEnv);
2384 magick_unreferenced(kernel);
2389 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2390 MagickCLEnv magick_unused(clEnv))
2392 magick_unreferenced(clEnv);
2397 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2398 void* userSelectedDevice,
2399 void* selectedDevice,
2400 ExceptionInfo* exception)
2402 magick_unreferenced(mode);
2403 magick_unreferenced(userSelectedDevice);
2404 magick_unreferenced(selectedDevice);
2405 magick_unreferenced(exception);
2409 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2411 char* openclCachedFilesDirectory;
2412 SemaphoreInfo* openclCachedFilesDirectoryLock;
2415 const char* GetOpenCLCachedFilesDirectory() {
2416 if (openclCachedFilesDirectory == NULL) {
2417 if (openclCachedFilesDirectoryLock == NULL)
2419 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2421 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2422 if (openclCachedFilesDirectory == NULL) {
2423 char path[MaxTextExtent];
2426 struct stat attributes;
2427 MagickBooleanType status;
2429 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2430 home=GetEnvironmentValue("LOCALAPPDATA");
2431 if (home == (char *) NULL)
2432 home=GetEnvironmentValue("APPDATA");
2433 if (home == (char *) NULL)
2434 home=GetEnvironmentValue("USERPROFILE");
2436 home=GetEnvironmentValue("HOME");
2438 if (home != (char *) NULL)
2441 Search $HOME/.magick.
2443 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2444 DirectorySeparator);
2445 home=DestroyString(home);
2446 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2447 CopyMagickString(temp,path,strlen(path)+1);
2448 status=GetPathAttributes(path,&attributes);
2449 if (status == MagickFalse) {
2450 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2457 openclCachedFilesDirectory = temp;
2459 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2461 return openclCachedFilesDirectory;
2464 /* create a function for OpenCL log */
2466 void OpenCLLog(const char* message) {
2468 #ifdef OPENCLLOG_ENABLED
2469 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2472 if (getenv("MAGICK_OCL_LOG"))
2475 char path[MaxTextExtent];
2477 /* dump the source into a file */
2478 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2479 ,GetOpenCLCachedFilesDirectory()
2480 ,DirectorySeparator,OPENCL_LOG_FILE);
2483 log = fopen(path, "ab");
2484 fwrite(message, sizeof(char), strlen(message), log);
2485 fwrite("\n", sizeof(char), 1, log);
2490 magick_unreferenced(message);