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)
387 MagickBooleanType status;
388 status = MagickFalse;
396 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
397 if (dataSize != sizeof(cl_device_id))
399 *((cl_device_id*)data) = clEnv->device;
403 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
404 if (dataSize != sizeof(clEnv->OpenCLDisabled))
406 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
410 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
411 if (dataSize != sizeof(clEnv->OpenCLDisabled))
413 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
431 + G e t O p e n C L C o n t e x t %
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437 % GetOpenCLContext() returns the OpenCL context
439 % The format of the GetOpenCLContext() method is:
441 % cl_context GetOpenCLContext(MagickCLEnv clEnv)
443 % A description of each parameter follows:
445 % o clEnv: OpenCL environment
450 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
454 return clEnv->context;
457 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
461 char path[MaxTextExtent];
462 char deviceName[MaxTextExtent];
463 const char* prefix = "magick_opencl";
464 clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
466 /* strip out illegal characters for file names */
469 if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
470 || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
476 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x.bin"
477 ,GetOpenCLCachedFilesDirectory()
478 ,DirectorySeparator,prefix,deviceName, (unsigned int)prog, signature);
479 name = (char*)AcquireMagickMemory(strlen(path)+1);
480 CopyMagickString(name,path,strlen(path)+1);
484 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
486 MagickBooleanType saveSuccessful;
488 size_t binaryProgramSize;
489 unsigned char* binaryProgram;
490 char* binaryFileName;
493 #ifdef MAGICKCORE_CLPERFMARKER
494 clBeginPerfMarkerAMD(__FUNCTION__,"");
497 binaryProgram = NULL;
498 binaryFileName = NULL;
500 saveSuccessful = MagickFalse;
502 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
503 if (clStatus != CL_SUCCESS)
505 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
509 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
510 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
511 if (clStatus != CL_SUCCESS)
513 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
517 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
518 fileHandle = fopen(binaryFileName, "wb");
519 if (fileHandle != NULL)
521 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
522 saveSuccessful = MagickTrue;
526 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
527 "Saving binary kernel failed.", "'%s'", ".");
531 if (fileHandle != NULL)
533 if (binaryProgram != NULL)
534 RelinquishMagickMemory(binaryProgram);
535 if (binaryFileName != NULL)
536 free(binaryFileName);
538 #ifdef MAGICKCORE_CLPERFMARKER
539 clEndPerfMarkerAMD();
542 return saveSuccessful;
545 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
547 MagickBooleanType loadSuccessful;
548 unsigned char* binaryProgram;
549 char* binaryFileName;
552 #ifdef MAGICKCORE_CLPERFMARKER
553 clBeginPerfMarkerAMD(__FUNCTION__,"");
556 binaryProgram = NULL;
557 binaryFileName = NULL;
559 loadSuccessful = MagickFalse;
561 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
562 fileHandle = fopen(binaryFileName, "rb");
563 if (fileHandle != NULL)
568 cl_int clBinaryStatus;
572 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
573 b_error |= ( length = ftell( fileHandle ) ) <= 0;
574 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
578 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
579 if (binaryProgram == NULL)
582 memset(binaryProgram, 0, length);
583 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
585 clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
586 if (clStatus != CL_SUCCESS
587 || clBinaryStatus != CL_SUCCESS)
590 loadSuccessful = MagickTrue;
594 if (fileHandle != NULL)
596 if (binaryFileName != NULL)
597 free(binaryFileName);
598 if (binaryProgram != NULL)
599 RelinquishMagickMemory(binaryProgram);
601 #ifdef MAGICKCORE_CLPERFMARKER
602 clEndPerfMarkerAMD();
605 return loadSuccessful;
608 static unsigned int stringSignature(const char* string)
610 unsigned int stringLength;
612 unsigned int signature;
616 const unsigned int* u;
619 #ifdef MAGICKCORE_CLPERFMARKER
620 clBeginPerfMarkerAMD(__FUNCTION__,"");
623 stringLength = strlen(string);
624 signature = stringLength;
625 n = stringLength/sizeof(unsigned int);
627 for (i = 0; i < n; i++)
631 if (n * sizeof(unsigned int) != stringLength)
634 j = n * sizeof(unsigned int);
635 for (i = 0; i < 4; i++,j++)
637 if (j < stringLength)
646 #ifdef MAGICKCORE_CLPERFMARKER
647 clEndPerfMarkerAMD();
653 /* OpenCL kernels for accelerate.c */
654 extern const char *accelerateKernels, *accelerateKernels2;
656 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
658 MagickBooleanType status = MagickFalse;
661 char* accelerateKernelsBuffer = NULL;
663 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
664 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
666 char options[MaxTextExtent];
667 unsigned int optionsSignature;
669 #ifdef MAGICKCORE_CLPERFMARKER
670 clBeginPerfMarkerAMD(__FUNCTION__,"");
673 /* Get additional options */
674 (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
675 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
678 if (getenv("MAGICK_OCL_DEF"))
681 strcat(options,getenv("MAGICK_OCL_DEF"));
686 if (getenv("MAGICK_OCL_BUILD"))
687 printf("options: %s\n", options);
690 optionsSignature = stringSignature(options);
692 /* get all the OpenCL program strings here */
693 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
694 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
695 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
697 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
699 MagickBooleanType loadSuccessful = MagickFalse;
700 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
702 /* try to load the binary first */
703 if (!getenv("MAGICK_OCL_REC"))
704 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
706 if (loadSuccessful == MagickFalse)
708 /* Binary CL program unavailable, compile the program from source */
709 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
710 clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
711 if (clStatus!=CL_SUCCESS)
713 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
714 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
720 clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
721 if (clStatus!=CL_SUCCESS)
723 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
724 "clBuildProgram failed.", "(%d)", (int)clStatus);
726 if (loadSuccessful == MagickFalse)
728 char path[MaxTextExtent];
731 /* dump the source into a file */
732 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
733 ,GetOpenCLCachedFilesDirectory()
734 ,DirectorySeparator,"magick_badcl.cl");
735 fileHandle = fopen(path, "wb");
736 if (fileHandle != NULL)
738 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
742 /* dump the build log */
746 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
747 log = (char*)AcquireMagickMemory(logSize);
748 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
750 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
751 ,GetOpenCLCachedFilesDirectory()
752 ,DirectorySeparator,"magick_badcl_build.log");
753 fileHandle = fopen(path, "wb");
754 if (fileHandle != NULL)
756 const char* buildOptionsTitle = "build options: ";
757 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
758 fwrite(options, sizeof(char), strlen(options), fileHandle);
759 fwrite("\n",sizeof(char), 1, fileHandle);
760 fwrite(log, sizeof(char), logSize, fileHandle);
763 RelinquishMagickMemory(log);
769 if (loadSuccessful == MagickFalse)
771 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
772 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
780 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
782 #ifdef MAGICKCORE_CLPERFMARKER
783 clEndPerfMarkerAMD();
789 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
792 cl_uint numPlatforms = 0;
793 cl_platform_id *platforms = NULL;
794 char* MAGICK_OCL_DEVICE = NULL;
795 MagickBooleanType OpenCLAvailable = MagickFalse;
797 #ifdef MAGICKCORE_CLPERFMARKER
798 clBeginPerfMarkerAMD(__FUNCTION__,"");
801 /* check if there's an environment variable overriding the device selection */
802 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
803 if (MAGICK_OCL_DEVICE != NULL)
805 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
807 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
809 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
811 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
813 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
815 /* OpenCL disabled */
819 else if (clEnv->deviceType == 0) {
820 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
823 if (clEnv->device != NULL)
825 status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
826 if (status != CL_SUCCESS) {
827 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
828 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
832 else if (clEnv->platform != NULL)
835 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
836 if (platforms == (cl_platform_id *) NULL)
838 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
839 "AcquireMagickMemory failed.",".");
842 platforms[0] = clEnv->platform;
846 clEnv->device = NULL;
848 /* Get the number of OpenCL platforms available */
849 status = clGetPlatformIDs(0, NULL, &numPlatforms);
850 if (status != CL_SUCCESS)
852 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
853 "clGetplatformIDs failed.", "(%d)", status);
857 /* No OpenCL available, just leave */
858 if (numPlatforms == 0) {
862 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
863 if (platforms == (cl_platform_id *) NULL)
865 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
866 "AcquireMagickMemory failed.",".");
870 status = clGetPlatformIDs(numPlatforms, platforms, NULL);
871 if (status != CL_SUCCESS)
873 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
874 "clGetPlatformIDs failed.", "(%d)", status);
879 /* Device selection */
880 clEnv->device = NULL;
881 for (j = 0; j < 2; j++)
884 cl_device_type deviceType;
885 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
888 deviceType = CL_DEVICE_TYPE_GPU;
890 deviceType = CL_DEVICE_TYPE_CPU;
897 deviceType = clEnv->deviceType;
899 for (i = 0; i < numPlatforms; i++)
902 status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
903 if (status != CL_SUCCESS)
905 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
906 "clGetPlatformIDs failed.", "(%d)", status);
909 if (clEnv->device != NULL)
911 clEnv->platform = platforms[i];
919 RelinquishMagickMemory(platforms);
921 OpenCLAvailable = (clEnv->platform!=NULL
922 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
924 #ifdef MAGICKCORE_CLPERFMARKER
925 clEndPerfMarkerAMD();
928 return OpenCLAvailable;
931 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
932 if (clEnv->OpenCLInitialized == MagickTrue
933 && clEnv->platform != NULL
934 && clEnv->device != NULL) {
935 clEnv->OpenCLDisabled = MagickFalse;
938 clEnv->OpenCLDisabled = MagickTrue;
943 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
949 + I n i t O p e n C L E n v %
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
955 % InitOpenCLEnv() initialize the OpenCL environment
957 % The format of the RelinquishMagickOpenCLEnv method is:
959 % MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
961 % A description of each parameter follows:
963 % o clEnv: OpenCL environment structure
965 % o exception: return any errors or warnings.
970 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
971 MagickBooleanType status = MagickTrue;
973 cl_context_properties cps[3];
976 clEnv->OpenCLInitialized = MagickTrue;
977 if (clEnv->OpenCLDisabled == MagickTrue)
980 clEnv->OpenCLDisabled = MagickTrue;
981 /* setup the OpenCL platform and device */
982 status = InitOpenCLPlatformDevice(clEnv, exception);
983 if (status == MagickFalse) {
984 /* No OpenCL device available */
988 /* create an OpenCL context */
989 cps[0] = CL_CONTEXT_PLATFORM;
990 cps[1] = (cl_context_properties)clEnv->platform;
992 clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
993 if (clStatus != CL_SUCCESS)
995 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
996 "clCreateContext failed.", "(%d)", clStatus);
997 status = MagickFalse;
1001 status = CompileOpenCLKernels(clEnv, exception);
1002 if (status == MagickFalse) {
1003 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1004 "clCreateCommandQueue failed.", "(%d)", status);
1006 status = MagickFalse;
1010 status = EnableOpenCLInternal(clEnv);
1017 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1018 MagickBooleanType status = MagickFalse;
1023 #ifdef MAGICKCORE_CLPERFMARKER
1024 clBeginPerfMarkerAMD(__FUNCTION__,"");
1027 LockSemaphoreInfo(clEnv->lock);
1028 if (clEnv->OpenCLInitialized == MagickFalse) {
1029 if (clEnv->device==NULL
1030 && clEnv->OpenCLDisabled == MagickFalse)
1031 status = autoSelectDevice(clEnv, exception);
1033 status = InitOpenCLEnvInternal(clEnv, exception);
1035 UnlockSemaphoreInfo(clEnv->lock);
1037 #ifdef MAGICKCORE_CLPERFMARKER
1038 clEndPerfMarkerAMD();
1045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1049 + 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 %
1053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1055 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1057 % The format of the AcquireOpenCLCommandQueue method is:
1059 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1061 % A description of each parameter follows:
1063 % o clEnv: the OpenCL environment.
1068 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1071 return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1082 + 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 %
1086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088 % RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1090 % The format of the RelinquishOpenCLCommandQueue method is:
1092 % MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1093 % cl_command_queue queue)
1095 % A description of each parameter follows:
1097 % o clEnv: the OpenCL environment.
1099 % o queue: the OpenCL queue to be released.
1104 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1108 return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1121 + A c q u i r e O p e n C L K e r n e l %
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 % AcquireOpenCLKernel() acquires an OpenCL kernel
1129 % The format of the AcquireOpenCLKernel method is:
1131 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
1132 % MagickOpenCLProgram program, const char* kernelName)
1134 % A description of each parameter follows:
1136 % o clEnv: the OpenCL environment.
1138 % o program: the OpenCL program module that the kernel belongs to.
1140 % o kernelName: the name of the kernel
1145 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1148 cl_kernel kernel = NULL;
1149 if (clEnv != NULL && kernelName!=NULL)
1151 kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 + R e l i n q u i s h O p e n C L K e r n e l %
1166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168 % RelinquishOpenCLKernel() releases an OpenCL kernel
1170 % The format of the RelinquishOpenCLKernel method is:
1172 % MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1175 % A description of each parameter follows:
1177 % o clEnv: the OpenCL environment.
1179 % o kernel: the OpenCL kernel object to be released.
1185 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1187 MagickBooleanType status = MagickFalse;
1188 if (clEnv != NULL && kernel != NULL)
1190 status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1200 + 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 %
1204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206 % GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1208 % The format of the GetOpenCLDeviceLocalMemorySize method is:
1210 % unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1212 % A description of each parameter follows:
1214 % o clEnv: the OpenCL environment.
1220 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1222 cl_ulong localMemorySize;
1223 clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1224 return (unsigned long)localMemorySize;
1228 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1230 cl_ulong maxMemAllocSize;
1231 clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1232 return (unsigned long)maxMemAllocSize;
1237 Beginning of the OpenCL device selection infrastructure
1241 #define DS_DEVICE_NAME_LENGTH 256
1245 ,DS_INVALID_PROFILE = 1000
1247 ,DS_INVALID_PERF_EVALUATOR_TYPE
1248 ,DS_INVALID_PERF_EVALUATOR
1249 ,DS_PERF_EVALUATOR_ERROR
1251 ,DS_UNKNOWN_DEVICE_TYPE
1252 ,DS_PROFILE_FILE_ERROR
1253 ,DS_SCORE_SERIALIZER_ERROR
1254 ,DS_SCORE_DESERIALIZER_ERROR
1259 DS_DEVICE_NATIVE_CPU = 0
1260 ,DS_DEVICE_OPENCL_DEVICE
1265 ds_device_type type;
1266 cl_device_id oclDeviceID;
1267 char* oclDeviceName;
1268 char* oclDriverVersion;
1269 cl_uint oclMaxClockFrequency;
1270 cl_uint oclMaxComputeUnits;
1271 void* score; /* a pointer to the score data, the content/format is application defined */
1275 unsigned int numDevices;
1277 const char* version;
1280 /* deallocate memory used by score */
1281 typedef ds_status (*ds_score_release)(void* score);
1283 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1284 ds_status status = DS_SUCCESS;
1286 if (device->oclDeviceName) free(device->oclDeviceName);
1287 if (device->oclDriverVersion) free(device->oclDriverVersion);
1288 if (device->score) status = sr(device->score);
1293 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1294 ds_status status = DS_SUCCESS;
1295 if (profile!=NULL) {
1296 if (profile->devices!=NULL && sr!=NULL) {
1298 for (i = 0; i < profile->numDevices; i++) {
1299 status = releaseDeviceResource(profile->devices+i,sr);
1300 if (status != DS_SUCCESS)
1303 free(profile->devices);
1311 static ds_status initDSProfile(ds_profile** p, const char* version) {
1313 cl_uint numPlatforms = 0;
1314 cl_platform_id* platforms = NULL;
1315 cl_device_id* devices = NULL;
1316 ds_status status = DS_SUCCESS;
1317 ds_profile* profile = NULL;
1318 unsigned int next = 0;
1322 return DS_INVALID_PROFILE;
1324 profile = (ds_profile*)malloc(sizeof(ds_profile));
1325 if (profile == NULL)
1326 return DS_MEMORY_ERROR;
1328 memset(profile, 0, sizeof(ds_profile));
1330 clGetPlatformIDs(0, NULL, &numPlatforms);
1331 if (numPlatforms > 0) {
1332 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1333 if (platforms == NULL) {
1334 status = DS_MEMORY_ERROR;
1337 clGetPlatformIDs(numPlatforms, platforms, NULL);
1338 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1340 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
1345 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1347 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1348 if (profile->devices == NULL) {
1349 profile->numDevices = 0;
1350 status = DS_MEMORY_ERROR;
1353 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1355 if (numDevices > 0) {
1356 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1357 if (devices == NULL) {
1358 status = DS_MEMORY_ERROR;
1361 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1365 for (d = 0; d < 2; d++) {
1367 cl_device_type deviceType;
1370 deviceType = CL_DEVICE_TYPE_GPU;
1373 deviceType = CL_DEVICE_TYPE_CPU;
1379 clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num);
1380 for (j = 0; j < num; j++, next++) {
1381 char buffer[DS_DEVICE_NAME_LENGTH];
1384 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1385 profile->devices[next].oclDeviceID = devices[j];
1387 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1388 , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1389 length = strlen(buffer);
1390 profile->devices[next].oclDeviceName = (char*)malloc(length+1);
1391 memcpy(profile->devices[next].oclDeviceName, buffer, length+1);
1393 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1394 , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1395 length = strlen(buffer);
1396 profile->devices[next].oclDriverVersion = (char*)malloc(length+1);
1397 memcpy(profile->devices[next].oclDriverVersion, buffer, length+1);
1399 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1400 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1402 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1403 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1409 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1410 profile->version = version;
1413 if (platforms) free(platforms);
1414 if (devices) free(devices);
1415 if (status == DS_SUCCESS) {
1420 if (profile->devices)
1421 free(profile->devices);
1428 /* Pointer to a function that calculates the score of a device (ex: device->score)
1429 update the data size of score. The encoding and the format of the score data
1430 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1432 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1436 ,DS_EVALUATE_NEW_ONLY
1437 } ds_evaluation_type;
1439 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1440 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1441 ds_status status = DS_SUCCESS;
1443 unsigned int updates = 0;
1445 if (profile == NULL) {
1446 return DS_INVALID_PROFILE;
1448 if (evaluator == NULL) {
1449 return DS_INVALID_PERF_EVALUATOR;
1452 for (i = 0; i < profile->numDevices; i++) {
1453 ds_status evaluatorStatus;
1456 case DS_EVALUATE_NEW_ONLY:
1457 if (profile->devices[i].score != NULL)
1459 /* else fall through */
1460 case DS_EVALUATE_ALL:
1461 evaluatorStatus = evaluator(profile->devices+i, evaluatorData);
1462 if (evaluatorStatus != DS_SUCCESS) {
1463 status = evaluatorStatus;
1469 return DS_INVALID_PERF_EVALUATOR_TYPE;
1474 *numUpdates = updates;
1479 #define DS_TAG_VERSION "<version>"
1480 #define DS_TAG_VERSION_END "</version>"
1481 #define DS_TAG_DEVICE "<device>"
1482 #define DS_TAG_DEVICE_END "</device>"
1483 #define DS_TAG_SCORE "<score>"
1484 #define DS_TAG_SCORE_END "</score>"
1485 #define DS_TAG_DEVICE_TYPE "<type>"
1486 #define DS_TAG_DEVICE_TYPE_END "</type>"
1487 #define DS_TAG_DEVICE_NAME "<name>"
1488 #define DS_TAG_DEVICE_NAME_END "</name>"
1489 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1490 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1491 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1492 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1493 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1494 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1496 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1500 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1501 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1502 ds_status status = DS_SUCCESS;
1503 FILE* profileFile = NULL;
1506 if (profile == NULL)
1507 return DS_INVALID_PROFILE;
1509 profileFile = fopen(file, "wb");
1510 if (profileFile==NULL) {
1511 status = DS_FILE_ERROR;
1516 /* write version string */
1517 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1518 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1519 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1520 fwrite("\n", sizeof(char), 1, profileFile);
1522 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1523 void* serializedScore;
1524 unsigned int serializedScoreSize;
1526 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1528 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1529 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1530 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1532 switch(profile->devices[i].type) {
1533 case DS_DEVICE_NATIVE_CPU:
1535 /* There's no need to emit a device name for the native CPU device. */
1537 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1538 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1539 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1543 case DS_DEVICE_OPENCL_DEVICE:
1547 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1548 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1549 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1551 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1552 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1553 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1555 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1556 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1557 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1558 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1560 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1561 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1562 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1563 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1567 status = DS_UNKNOWN_DEVICE_TYPE;
1571 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1572 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1573 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1574 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1575 free(serializedScore);
1577 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1578 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1579 fwrite("\n",sizeof(char),1,profileFile);
1581 fclose(profileFile);
1587 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1588 ds_status status = DS_SUCCESS;
1589 FILE * input = NULL;
1592 char* binary = NULL;
1597 input = fopen(fileName, "rb");
1599 return DS_FILE_ERROR;
1602 fseek(input, 0L, SEEK_END);
1603 size = ftell(input);
1605 binary = (char*)malloc(size);
1606 if(binary == NULL) {
1607 status = DS_FILE_ERROR;
1610 rsize = fread(binary, sizeof(char), size, input);
1613 status = DS_FILE_ERROR;
1616 *contentSize = size;
1620 if (input != NULL) fclose(input);
1621 if (status != DS_SUCCESS
1622 && binary != NULL) {
1631 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1632 size_t stringLength;
1633 const char* currentPosition;
1636 stringLength = strlen(string);
1637 currentPosition = contentStart;
1638 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1639 if (*currentPosition == string[0]) {
1640 if (currentPosition+stringLength < contentEnd) {
1641 if (strncmp(currentPosition, string, stringLength) == 0) {
1642 found = currentPosition;
1652 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1653 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1655 ds_status status = DS_SUCCESS;
1656 char* contentStart = NULL;
1657 const char* contentEnd = NULL;
1661 return DS_INVALID_PROFILE;
1663 status = readProFile(file, &contentStart, &contentSize);
1664 if (status == DS_SUCCESS) {
1665 const char* currentPosition;
1666 const char* dataStart;
1667 const char* dataEnd;
1668 size_t versionStringLength;
1670 contentEnd = contentStart + contentSize;
1671 currentPosition = contentStart;
1674 /* parse the version string */
1675 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1676 if (dataStart == NULL) {
1677 status = DS_PROFILE_FILE_ERROR;
1680 dataStart += strlen(DS_TAG_VERSION);
1682 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1683 if (dataEnd==NULL) {
1684 status = DS_PROFILE_FILE_ERROR;
1688 versionStringLength = strlen(profile->version);
1689 if (versionStringLength!=(dataEnd-dataStart)
1690 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1691 /* version mismatch */
1692 status = DS_PROFILE_FILE_ERROR;
1695 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1697 /* parse the device information */
1701 const char* deviceTypeStart;
1702 const char* deviceTypeEnd;
1703 ds_device_type deviceType;
1705 const char* deviceNameStart;
1706 const char* deviceNameEnd;
1708 const char* deviceScoreStart;
1709 const char* deviceScoreEnd;
1711 const char* deviceDriverStart;
1712 const char* deviceDriverEnd;
1714 const char* tmpStart;
1718 cl_uint maxClockFrequency;
1719 cl_uint maxComputeUnits;
1721 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1722 if (dataStart==NULL) {
1723 /* nothing useful remain, quit...*/
1726 dataStart+=strlen(DS_TAG_DEVICE);
1727 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1728 if (dataEnd==NULL) {
1729 status = DS_PROFILE_FILE_ERROR;
1733 /* parse the device type */
1734 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1735 if (deviceTypeStart==NULL) {
1736 status = DS_PROFILE_FILE_ERROR;
1739 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1740 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1741 if (deviceTypeEnd==NULL) {
1742 status = DS_PROFILE_FILE_ERROR;
1745 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1748 /* parse the device name */
1749 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1751 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1752 if (deviceNameStart==NULL) {
1753 status = DS_PROFILE_FILE_ERROR;
1756 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1757 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1758 if (deviceNameEnd==NULL) {
1759 status = DS_PROFILE_FILE_ERROR;
1764 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1765 if (deviceDriverStart==NULL) {
1766 status = DS_PROFILE_FILE_ERROR;
1769 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1770 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1771 if (deviceDriverEnd ==NULL) {
1772 status = DS_PROFILE_FILE_ERROR;
1777 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1778 if (tmpStart==NULL) {
1779 status = DS_PROFILE_FILE_ERROR;
1782 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1783 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1784 if (tmpEnd ==NULL) {
1785 status = DS_PROFILE_FILE_ERROR;
1788 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1789 tmp[tmpEnd-tmpStart] = '\0';
1790 maxComputeUnits = atoi(tmp);
1793 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1794 if (tmpStart==NULL) {
1795 status = DS_PROFILE_FILE_ERROR;
1798 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1799 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1800 if (tmpEnd ==NULL) {
1801 status = DS_PROFILE_FILE_ERROR;
1804 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1805 tmp[tmpEnd-tmpStart] = '\0';
1806 maxClockFrequency = atoi(tmp);
1809 /* check if this device is on the system */
1810 for (i = 0; i < profile->numDevices; i++) {
1811 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1812 size_t actualDeviceNameLength;
1813 size_t driverVersionLength;
1815 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1816 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1817 if (actualDeviceNameLength == (deviceNameEnd - deviceNameStart)
1818 && driverVersionLength == (deviceDriverEnd - deviceDriverStart)
1819 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1820 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1821 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1822 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1824 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1825 if (deviceNameStart==NULL) {
1826 status = DS_PROFILE_FILE_ERROR;
1829 deviceScoreStart+=strlen(DS_TAG_SCORE);
1830 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1831 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1832 if (status != DS_SUCCESS) {
1840 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1841 for (i = 0; i < profile->numDevices; i++) {
1842 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1843 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1844 if (deviceScoreStart==NULL) {
1845 status = DS_PROFILE_FILE_ERROR;
1848 deviceScoreStart+=strlen(DS_TAG_SCORE);
1849 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1850 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1851 if (status != DS_SUCCESS) {
1858 /* skip over the current one to find the next device */
1859 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1863 if (contentStart!=NULL) free(contentStart);
1867 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1869 if (profile == NULL || num==NULL)
1870 return DS_MEMORY_ERROR;
1872 for (i = 0; i < profile->numDevices; i++) {
1873 if (profile->devices[i].score == NULL) {
1881 End of the OpenCL device selection infrastructure
1886 typedef struct _AccelerateTimer {
1892 static void startAccelerateTimer(AccelerateTimer* timer) {
1894 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
1899 gettimeofday(&s, 0);
1900 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1904 static void stopAccelerateTimer(AccelerateTimer* timer) {
1907 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
1910 gettimeofday(&s, 0);
1911 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1915 timer->_clocks += n;
1918 static void resetAccelerateTimer(AccelerateTimer* timer) {
1924 static void initAccelerateTimer(AccelerateTimer* timer) {
1926 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1928 timer->_freq = (long long)1.0E3;
1930 resetAccelerateTimer(timer);
1933 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1936 typedef double AccelerateScoreType;
1938 static ds_status AcceleratePerfEvaluator(ds_device* device, void* data) {
1940 ds_status status = DS_SUCCESS;
1941 MagickCLEnv clEnv = NULL;
1942 MagickCLEnv oldClEnv = NULL;
1943 ExceptionInfo* exception = NULL;
1944 AccelerateTimer timer;
1946 if (device == NULL) {
1947 status = DS_PERF_EVALUATOR_ERROR;
1951 clEnv = AcquireMagickOpenCLEnv();
1952 exception = AcquireExceptionInfo();
1954 if (device->type == DS_DEVICE_NATIVE_CPU) {
1956 MagickBooleanType flag = MagickTrue;
1957 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
1958 , sizeof(MagickBooleanType), &flag, exception);
1960 else if (device->type == DS_DEVICE_OPENCL_DEVICE) {
1962 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
1963 , sizeof(cl_device_id), &device->oclDeviceID,exception);
1966 status = DS_PERF_EVALUATOR_ERROR;
1969 InitOpenCLEnvInternal(clEnv, exception);
1970 oldClEnv = defaultCLEnv;
1971 defaultCLEnv = clEnv;
1973 /* microbenchmark */
1975 #define ACCELERATE_PERF_DIMEN "2048x1536"
1979 ImageInfo* imageInfo;
1982 imageInfo = AcquireImageInfo();
1983 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
1984 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
1985 inputImage = ReadImage(imageInfo,exception);
1987 initAccelerateTimer(&timer);
1989 for (i = 0; i <=NUM_ITER; i++) {
1992 Image* unsharpedImage;
1993 Image* resizedImage;
1996 startAccelerateTimer(&timer);
1998 #ifdef MAGICKCORE_CLPERFMARKER
1999 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2002 bluredImage = BlurImage(inputImage, 10.0f, 3.5f, exception);
2003 unsharpedImage = UnsharpMaskImage(bluredImage, 2.0f,2.0f,50.0f,10.0f,exception);
2004 resizedImage = ResizeImage(unsharpedImage,640,480,LanczosFilter,1.0,exception);
2006 #ifdef MAGICKCORE_CLPERFMARKER
2007 clEndPerfMarkerAMD();
2011 stopAccelerateTimer(&timer);
2013 if (bluredImage) DestroyImage(bluredImage);
2014 if (unsharpedImage) DestroyImage(unsharpedImage);
2015 if (resizedImage) DestroyImage(resizedImage);
2017 DestroyImage(inputImage);
2019 /* end of microbenchmark */
2021 if (device->score == NULL) {
2022 device->score = malloc(sizeof(AccelerateScoreType));
2024 *(AccelerateScoreType*)device->score = readAccelerateTimer(&timer);
2028 RelinquishMagickOpenCLEnv(clEnv);
2030 defaultCLEnv = oldClEnv;
2036 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2039 /* generate a string from the score */
2040 char* s = (char*)malloc(sizeof(char)*256);
2041 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2042 *serializedScore = (void*)s;
2043 *serializedScoreSize = strlen(s);
2047 return DS_SCORE_SERIALIZER_ERROR;
2051 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2053 /* convert the string back to an int */
2054 char* s = (char*)malloc(serializedScoreSize+1);
2055 memcpy(s, serializedScore, serializedScoreSize);
2056 s[serializedScoreSize] = (char)'\0';
2057 device->score = malloc(sizeof(AccelerateScoreType));
2058 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2063 return DS_SCORE_DESERIALIZER_ERROR;
2067 ds_status AccelerateScoreRelease(void* score) {
2075 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2076 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2077 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2079 MagickBooleanType mStatus = MagickFalse;
2081 ds_profile* profile;
2082 unsigned int numDeviceProfiled = 0;
2084 unsigned int bestDeviceIndex;
2085 AccelerateScoreType bestScore;
2086 char path[MaxTextExtent];
2089 LockDefaultOpenCLEnv();
2091 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2092 if (status!=DS_SUCCESS) {
2093 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2097 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2098 ,GetOpenCLCachedFilesDirectory()
2099 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2101 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2102 status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2103 if (status!=DS_SUCCESS) {
2104 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2107 if (numDeviceProfiled > 0) {
2108 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2109 if (status!=DS_SUCCESS) {
2110 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2114 /* pick the best device */
2115 bestDeviceIndex = 0;
2116 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2117 for (i = 1; i < profile->numDevices; i++) {
2118 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2119 if (score < bestScore) {
2120 bestDeviceIndex = i;
2125 /* set up clEnv with the best device */
2126 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2128 MagickBooleanType flag = MagickTrue;
2129 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2130 , sizeof(MagickBooleanType), &flag, exception);
2132 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2134 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2135 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2138 status = DS_PERF_EVALUATOR_ERROR;
2141 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2143 status = releaseDSProfile(profile, AccelerateScoreRelease);
2144 if (status!=DS_SUCCESS) {
2145 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2150 UnlockDefaultOpenCLEnv();
2156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2160 + I n i t I m a g e M a g i c k O p e n C L %
2164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 % InitImageMagickOpenCL() provides a simplified interface to initialize
2167 % the OpenCL environtment in ImageMagick
2169 % The format of the InitImageMagickOpenCL() method is:
2171 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2172 % void* userSelectedDevice,
2173 % void* selectedDevice)
2175 % A description of each parameter follows:
2177 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2179 % o userSelectedDevice: when in user mode, a pointer to the selected
2182 % o selectedDevice: a pointer to cl_device_id where the selected
2183 % cl_device_id by ImageMagick could be returned
2185 % o exception: exception
2188 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2189 void* userSelectedDevice,
2190 void* selectedDevice,
2191 ExceptionInfo* exception) {
2193 MagickBooleanType status = MagickTrue;
2194 MagickCLEnv clEnv = NULL;
2195 MagickBooleanType flag;
2197 exception = AcquireExceptionInfo();
2198 clEnv = GetDefaultOpenCLEnv();
2202 case MAGICK_OPENCL_OFF:
2204 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2205 , sizeof(MagickBooleanType), &flag, exception);
2206 status = InitOpenCLEnv(clEnv, exception);
2209 *(cl_device_id*)selectedDevice = NULL;
2212 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2214 if (userSelectedDevice == NULL)
2218 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2219 , sizeof(MagickBooleanType), &flag, exception);
2221 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2222 , sizeof(cl_device_id), userSelectedDevice,exception);
2224 status = InitOpenCLEnv(clEnv, exception);
2225 if (selectedDevice) {
2226 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2227 , sizeof(cl_device_id), selectedDevice, exception);
2231 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2234 cl_device_id d = NULL;
2236 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2237 , sizeof(MagickBooleanType), &flag, exception);
2238 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2239 , sizeof(cl_device_id), &d,exception);
2240 status = InitOpenCLEnv(clEnv, exception);
2241 if (selectedDevice) {
2242 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2243 , sizeof(cl_device_id), selectedDevice, exception);
2255 struct _MagickCLEnv {
2256 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2259 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2264 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2265 MagickCLEnv magick_unused(clEnv))
2267 magick_unreferenced(clEnv);
2273 * Return the OpenCL environment
2275 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2276 ExceptionInfo *magick_unused(exception))
2278 magick_unreferenced(exception);
2280 return (MagickCLEnv) NULL;
2283 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2284 MagickCLEnv magick_unused(clEnv))
2286 magick_unreferenced(clEnv);
2288 return (MagickCLEnv) NULL;
2291 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2292 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2293 size_t magick_unused(dataSize),void *magick_unused(data),
2294 ExceptionInfo *magick_unused(exception))
2296 magick_unreferenced(clEnv);
2297 magick_unreferenced(param);
2298 magick_unreferenced(dataSize);
2299 magick_unreferenced(data);
2300 magick_unreferenced(exception);
2305 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2306 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2307 size_t magick_unused(dataSize),void *magick_unused(data),
2308 ExceptionInfo *magick_unused(exception))
2310 magick_unreferenced(clEnv);
2311 magick_unreferenced(param);
2312 magick_unreferenced(dataSize);
2313 magick_unreferenced(data);
2314 magick_unreferenced(exception);
2319 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2320 ExceptionInfo *magick_unused(exception))
2322 magick_unreferenced(clEnv);
2323 magick_unreferenced(exception);
2328 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2329 MagickCLEnv magick_unused(clEnv))
2331 magick_unreferenced(clEnv);
2333 return (cl_command_queue) NULL;
2336 MagickExport MagickBooleanType RelinquishCommandQueue(
2337 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2339 magick_unreferenced(clEnv);
2340 magick_unreferenced(queue);
2345 MagickExport cl_kernel AcquireOpenCLKernel(
2346 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2347 const char *magick_unused(kernelName))
2349 magick_unreferenced(clEnv);
2350 magick_unreferenced(program);
2351 magick_unreferenced(kernelName);
2353 return (cl_kernel)NULL;
2356 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2357 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2359 magick_unreferenced(clEnv);
2360 magick_unreferenced(kernel);
2365 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2366 MagickCLEnv magick_unused(clEnv))
2368 magick_unreferenced(clEnv);
2373 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2374 void* userSelectedDevice,
2375 void* selectedDevice,
2376 ExceptionInfo* exception)
2378 magick_unreferenced(mode);
2379 magick_unreferenced(userSelectedDevice);
2380 magick_unreferenced(selectedDevice);
2381 magick_unreferenced(exception);
2385 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2387 char* openclCachedFilesDirectory;
2388 SemaphoreInfo* openclCachedFilesDirectoryLock;
2391 const char* GetOpenCLCachedFilesDirectory() {
2392 if (openclCachedFilesDirectory == NULL) {
2393 if (openclCachedFilesDirectoryLock == NULL)
2395 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2397 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2398 if (openclCachedFilesDirectory == NULL) {
2399 char path[MaxTextExtent];
2402 struct stat attributes;
2403 MagickBooleanType status;
2405 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2406 home=GetEnvironmentValue("LOCALAPPDATA");
2407 if (home == (char *) NULL)
2408 home=GetEnvironmentValue("APPDATA");
2409 if (home == (char *) NULL)
2410 home=GetEnvironmentValue("USERPROFILE");
2412 home=GetEnvironmentValue("HOME");
2414 if (home != (char *) NULL)
2417 Search $HOME/.magick.
2419 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2420 DirectorySeparator);
2421 home=DestroyString(home);
2422 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2423 CopyMagickString(temp,path,strlen(path)+1);
2424 status=GetPathAttributes(path,&attributes);
2425 if (status == MagickFalse) {
2426 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2433 openclCachedFilesDirectory = temp;
2435 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2437 return openclCachedFilesDirectory;
2440 /* create a function for OpenCL log */
2442 void OpenCLLog(const char* message) {
2444 #ifdef OPENCLLOG_ENABLED
2445 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2448 if (getenv("MAGICK_OCL_LOG"))
2451 char path[MaxTextExtent];
2453 /* dump the source into a file */
2454 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2455 ,GetOpenCLCachedFilesDirectory()
2456 ,DirectorySeparator,OPENCL_LOG_FILE);
2459 log = fopen(path, "ab");
2460 fwrite(message, sizeof(char), strlen(message), log);
2461 fwrite("\n", sizeof(char), 1, log);
2466 magick_unreferenced(message);