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 MagickBooleanType disableProgramCache; /* disable the OpenCL program cache */
100 cl_program programs[MAGICK_OPENCL_NUM_PROGRAMS]; /* one program object maps one kernel source file */
102 MagickBooleanType regenerateProfile; /* re-run the microbenchmark in auto device selection mode */
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112 + A c q u i r e M a g i c k O p e n C L E n v %
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 % AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure
122 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
125 clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
128 memset(clEnv, 0, sizeof(struct _MagickCLEnv));
129 AcquireSemaphoreInfo(&clEnv->lock);
136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 + 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 %
144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 % RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
148 % The format of the RelinquishMagickOpenCLEnv method is:
150 % MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
152 % A description of each parameter follows:
154 % o clEnv: MagickCLEnv structure to destroy
158 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
160 if (clEnv != (MagickCLEnv)NULL)
162 RelinquishSemaphoreInfo(clEnv->lock);
163 RelinquishMagickMemory(clEnv);
171 * Default OpenCL environment
173 MagickCLEnv defaultCLEnv;
174 SemaphoreInfo* defaultCLEnvLock;
178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 + G e t D e f a u l t O p e n C L E n v %
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188 % GetDefaultOpenCLEnv() returns the default OpenCL env
190 % The format of the GetDefaultOpenCLEnv method is:
192 % MagickCLEnv GetDefaultOpenCLEnv()
194 % A description of each parameter follows:
196 % o exception: return any errors or warnings.
200 MagickExport MagickCLEnv GetDefaultOpenCLEnv()
202 if (defaultCLEnv == NULL)
204 if (defaultCLEnvLock == NULL)
206 AcquireSemaphoreInfo(&defaultCLEnvLock);
208 LockSemaphoreInfo(defaultCLEnvLock);
209 defaultCLEnv = AcquireMagickOpenCLEnv();
210 UnlockSemaphoreInfo(defaultCLEnvLock);
215 static void LockDefaultOpenCLEnv() {
216 if (defaultCLEnvLock == NULL)
218 AcquireSemaphoreInfo(&defaultCLEnvLock);
220 LockSemaphoreInfo(defaultCLEnvLock);
223 static void UnlockDefaultOpenCLEnv() {
224 if (defaultCLEnvLock == NULL)
226 AcquireSemaphoreInfo(&defaultCLEnvLock);
229 UnlockSemaphoreInfo(defaultCLEnvLock);
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 + S e t D e f a u l t O p e n C L E n v %
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 % SetDefaultOpenCLEnv() sets the new OpenCL environment as default
245 % and returns the old OpenCL environment
247 % The format of the SetDefaultOpenCLEnv() method is:
249 % MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
251 % A description of each parameter follows:
253 % o clEnv: the new default OpenCL environment.
256 MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
259 LockDefaultOpenCLEnv();
260 oldEnv = defaultCLEnv;
261 defaultCLEnv = clEnv;
262 UnlockDefaultOpenCLEnv();
269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273 + S e t M a g i c k O p e n C L E n v P a r a m %
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 % SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
281 % The format of the SetMagickOpenCLEnvParam() method is:
283 % MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
284 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
285 % ExceptionInfo* exception)
287 % A description of each parameter follows:
289 % o clEnv: the OpenCL environment.
291 % o param: the parameter to be set.
293 % o dataSize: the data size of the parameter value.
295 % o data: the pointer to the new parameter value
297 % o exception: return any errors or warnings
301 static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
302 , size_t dataSize, void* data, ExceptionInfo* exception)
304 MagickBooleanType status = MagickFalse;
312 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
313 if (dataSize != sizeof(clEnv->device))
315 clEnv->device = *((cl_device_id*)data);
316 clEnv->OpenCLInitialized = MagickFalse;
320 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
321 if (dataSize != sizeof(clEnv->OpenCLDisabled))
323 clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
324 clEnv->OpenCLInitialized = MagickFalse;
328 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
329 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
332 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
333 if (dataSize != sizeof(clEnv->disableProgramCache))
335 clEnv->disableProgramCache = *((MagickBooleanType*)data);
336 clEnv->OpenCLInitialized = MagickFalse;
340 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
341 if (dataSize != sizeof(clEnv->regenerateProfile))
343 clEnv->regenerateProfile = *((MagickBooleanType*)data);
344 clEnv->OpenCLInitialized = MagickFalse;
357 MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
358 , size_t dataSize, void* data, ExceptionInfo* exception) {
359 MagickBooleanType status = MagickFalse;
361 LockSemaphoreInfo(clEnv->lock);
362 status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
363 UnlockSemaphoreInfo(clEnv->lock);
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 + G e t M a g i c k O p e n C L E n v P a r a m %
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 % GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
381 % The format of the GetMagickOpenCLEnvParam() method is:
383 % MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
384 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
385 % ExceptionInfo* exception)
387 % A description of each parameter follows:
389 % o clEnv: the OpenCL environment.
391 % o param: the parameter to be returned.
393 % o dataSize: the data size of the parameter value.
395 % o data: the location where the returned parameter value will be stored
397 % o exception: return any errors or warnings
402 MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
403 , size_t dataSize, void* data, ExceptionInfo* exception)
408 magick_unreferenced(exception);
410 status = MagickFalse;
418 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
419 if (dataSize != sizeof(cl_device_id))
421 *((cl_device_id*)data) = clEnv->device;
425 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
426 if (dataSize != sizeof(clEnv->OpenCLDisabled))
428 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
432 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
433 if (dataSize != sizeof(clEnv->OpenCLDisabled))
435 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
439 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
440 if (dataSize != sizeof(clEnv->disableProgramCache))
442 *((MagickBooleanType*)data) = clEnv->disableProgramCache;
446 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
447 if (dataSize != sizeof(clEnv->regenerateProfile))
449 *((MagickBooleanType*)data) = clEnv->regenerateProfile;
463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 + G e t O p e n C L C o n t e x t %
471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 % GetOpenCLContext() returns the OpenCL context
475 % The format of the GetOpenCLContext() method is:
477 % cl_context GetOpenCLContext(MagickCLEnv clEnv)
479 % A description of each parameter follows:
481 % o clEnv: OpenCL environment
486 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
490 return clEnv->context;
493 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
497 char path[MaxTextExtent];
498 char deviceName[MaxTextExtent];
499 const char* prefix = "magick_opencl";
500 clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
502 /* strip out illegal characters for file names */
505 if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
506 || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
512 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x_%.20g.bin",
513 GetOpenCLCachedFilesDirectory(),DirectorySeparator,prefix,deviceName,
514 (unsigned int) prog,signature,(double) sizeof(char*)*8);
515 name = (char*)AcquireMagickMemory(strlen(path)+1);
516 CopyMagickString(name,path,strlen(path)+1);
520 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
522 MagickBooleanType saveSuccessful;
524 size_t binaryProgramSize;
525 unsigned char* binaryProgram;
526 char* binaryFileName;
529 #ifdef MAGICKCORE_CLPERFMARKER
530 clBeginPerfMarkerAMD(__FUNCTION__,"");
533 binaryProgram = NULL;
534 binaryFileName = NULL;
536 saveSuccessful = MagickFalse;
538 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
539 if (clStatus != CL_SUCCESS)
541 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
545 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
546 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
547 if (clStatus != CL_SUCCESS)
549 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
553 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
554 fileHandle = fopen(binaryFileName, "wb");
555 if (fileHandle != NULL)
557 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
558 saveSuccessful = MagickTrue;
562 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
563 "Saving binary kernel failed.", "'%s'", ".");
567 if (fileHandle != NULL)
569 if (binaryProgram != NULL)
570 RelinquishMagickMemory(binaryProgram);
571 if (binaryFileName != NULL)
572 free(binaryFileName);
574 #ifdef MAGICKCORE_CLPERFMARKER
575 clEndPerfMarkerAMD();
578 return saveSuccessful;
581 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
583 MagickBooleanType loadSuccessful;
584 unsigned char* binaryProgram;
585 char* binaryFileName;
588 #ifdef MAGICKCORE_CLPERFMARKER
589 clBeginPerfMarkerAMD(__FUNCTION__,"");
592 binaryProgram = NULL;
593 binaryFileName = NULL;
595 loadSuccessful = MagickFalse;
597 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
598 fileHandle = fopen(binaryFileName, "rb");
599 if (fileHandle != NULL)
604 cl_int clBinaryStatus;
608 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
609 b_error |= ( length = ftell( fileHandle ) ) <= 0;
610 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
614 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
615 if (binaryProgram == NULL)
618 memset(binaryProgram, 0, length);
619 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
621 clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
622 if (clStatus != CL_SUCCESS
623 || clBinaryStatus != CL_SUCCESS)
626 loadSuccessful = MagickTrue;
630 if (fileHandle != NULL)
632 if (binaryFileName != NULL)
633 free(binaryFileName);
634 if (binaryProgram != NULL)
635 RelinquishMagickMemory(binaryProgram);
637 #ifdef MAGICKCORE_CLPERFMARKER
638 clEndPerfMarkerAMD();
641 return loadSuccessful;
644 static unsigned int stringSignature(const char* string)
646 unsigned int stringLength;
648 unsigned int signature;
652 const unsigned int* u;
655 #ifdef MAGICKCORE_CLPERFMARKER
656 clBeginPerfMarkerAMD(__FUNCTION__,"");
659 stringLength = strlen(string);
660 signature = stringLength;
661 n = stringLength/sizeof(unsigned int);
663 for (i = 0; i < n; i++)
667 if (n * sizeof(unsigned int) != stringLength)
670 j = n * sizeof(unsigned int);
671 for (i = 0; i < 4; i++,j++)
673 if (j < stringLength)
682 #ifdef MAGICKCORE_CLPERFMARKER
683 clEndPerfMarkerAMD();
689 /* OpenCL kernels for accelerate.c */
690 extern const char *accelerateKernels, *accelerateKernels2;
692 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
694 MagickBooleanType status = MagickFalse;
697 char* accelerateKernelsBuffer = NULL;
699 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
700 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
702 char options[MaxTextExtent];
703 unsigned int optionsSignature;
705 #ifdef MAGICKCORE_CLPERFMARKER
706 clBeginPerfMarkerAMD(__FUNCTION__,"");
709 /* Get additional options */
710 (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
711 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
714 if (getenv("MAGICK_OCL_DEF"))
717 strcat(options,getenv("MAGICK_OCL_DEF"));
722 if (getenv("MAGICK_OCL_BUILD"))
723 printf("options: %s\n", options);
726 optionsSignature = stringSignature(options);
728 /* get all the OpenCL program strings here */
729 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
730 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
731 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
733 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
735 MagickBooleanType loadSuccessful = MagickFalse;
736 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
738 /* try to load the binary first */
739 if (clEnv->disableProgramCache != MagickTrue
740 && !getenv("MAGICK_OCL_REC"))
741 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature);
743 if (loadSuccessful == MagickFalse)
745 /* Binary CL program unavailable, compile the program from source */
746 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
747 clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
748 if (clStatus!=CL_SUCCESS)
750 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
751 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
757 clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
758 if (clStatus!=CL_SUCCESS)
760 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
761 "clBuildProgram failed.", "(%d)", (int)clStatus);
763 if (loadSuccessful == MagickFalse)
765 char path[MaxTextExtent];
768 /* dump the source into a file */
769 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
770 ,GetOpenCLCachedFilesDirectory()
771 ,DirectorySeparator,"magick_badcl.cl");
772 fileHandle = fopen(path, "wb");
773 if (fileHandle != NULL)
775 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
779 /* dump the build log */
783 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
784 log = (char*)AcquireMagickMemory(logSize);
785 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
787 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
788 ,GetOpenCLCachedFilesDirectory()
789 ,DirectorySeparator,"magick_badcl_build.log");
790 fileHandle = fopen(path, "wb");
791 if (fileHandle != NULL)
793 const char* buildOptionsTitle = "build options: ";
794 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
795 fwrite(options, sizeof(char), strlen(options), fileHandle);
796 fwrite("\n",sizeof(char), 1, fileHandle);
797 fwrite(log, sizeof(char), logSize, fileHandle);
800 RelinquishMagickMemory(log);
806 if (loadSuccessful == MagickFalse)
808 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
809 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
817 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
819 #ifdef MAGICKCORE_CLPERFMARKER
820 clEndPerfMarkerAMD();
826 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
829 cl_uint numPlatforms = 0;
830 cl_platform_id *platforms = NULL;
831 char* MAGICK_OCL_DEVICE = NULL;
832 MagickBooleanType OpenCLAvailable = MagickFalse;
834 #ifdef MAGICKCORE_CLPERFMARKER
835 clBeginPerfMarkerAMD(__FUNCTION__,"");
838 /* check if there's an environment variable overriding the device selection */
839 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
840 if (MAGICK_OCL_DEVICE != NULL)
842 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
844 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
846 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
848 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
850 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
852 /* OpenCL disabled */
856 else if (clEnv->deviceType == 0) {
857 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
860 if (clEnv->device != NULL)
862 status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
863 if (status != CL_SUCCESS) {
864 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
865 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
869 else if (clEnv->platform != NULL)
872 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
873 if (platforms == (cl_platform_id *) NULL)
875 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
876 "AcquireMagickMemory failed.",".");
879 platforms[0] = clEnv->platform;
883 clEnv->device = NULL;
885 /* Get the number of OpenCL platforms available */
886 status = clGetPlatformIDs(0, NULL, &numPlatforms);
887 if (status != CL_SUCCESS)
889 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
890 "clGetplatformIDs failed.", "(%d)", status);
894 /* No OpenCL available, just leave */
895 if (numPlatforms == 0) {
899 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
900 if (platforms == (cl_platform_id *) NULL)
902 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
903 "AcquireMagickMemory failed.",".");
907 status = clGetPlatformIDs(numPlatforms, platforms, NULL);
908 if (status != CL_SUCCESS)
910 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
911 "clGetPlatformIDs failed.", "(%d)", status);
916 /* Device selection */
917 clEnv->device = NULL;
918 for (j = 0; j < 2; j++)
921 cl_device_type deviceType;
922 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
925 deviceType = CL_DEVICE_TYPE_GPU;
927 deviceType = CL_DEVICE_TYPE_CPU;
934 deviceType = clEnv->deviceType;
936 for (i = 0; i < numPlatforms; i++)
939 status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
940 if (status != CL_SUCCESS)
942 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
943 "clGetPlatformIDs failed.", "(%d)", status);
946 if (clEnv->device != NULL)
948 clEnv->platform = platforms[i];
956 RelinquishMagickMemory(platforms);
958 OpenCLAvailable = (clEnv->platform!=NULL
959 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
961 #ifdef MAGICKCORE_CLPERFMARKER
962 clEndPerfMarkerAMD();
965 return OpenCLAvailable;
968 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
969 if (clEnv->OpenCLInitialized != MagickFalse
970 && clEnv->platform != NULL
971 && clEnv->device != NULL) {
972 clEnv->OpenCLDisabled = MagickFalse;
975 clEnv->OpenCLDisabled = MagickTrue;
980 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
986 + I n i t O p e n C L E n v %
990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
992 % InitOpenCLEnv() initialize the OpenCL environment
994 % The format of the RelinquishMagickOpenCLEnv method is:
996 % MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
998 % A description of each parameter follows:
1000 % o clEnv: OpenCL environment structure
1002 % o exception: return any errors or warnings.
1007 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
1008 MagickBooleanType status = MagickTrue;
1010 cl_context_properties cps[3];
1013 clEnv->OpenCLInitialized = MagickTrue;
1014 if (clEnv->OpenCLDisabled != MagickFalse)
1017 clEnv->OpenCLDisabled = MagickTrue;
1018 /* setup the OpenCL platform and device */
1019 status = InitOpenCLPlatformDevice(clEnv, exception);
1020 if (status == MagickFalse) {
1021 /* No OpenCL device available */
1025 /* create an OpenCL context */
1026 cps[0] = CL_CONTEXT_PLATFORM;
1027 cps[1] = (cl_context_properties)clEnv->platform;
1029 clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
1030 if (clStatus != CL_SUCCESS)
1032 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1033 "clCreateContext failed.", "(%d)", clStatus);
1034 status = MagickFalse;
1038 status = CompileOpenCLKernels(clEnv, exception);
1039 if (status == MagickFalse) {
1040 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1041 "clCreateCommandQueue failed.", "(%d)", status);
1043 status = MagickFalse;
1047 status = EnableOpenCLInternal(clEnv);
1054 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1055 MagickBooleanType status = MagickFalse;
1060 #ifdef MAGICKCORE_CLPERFMARKER
1061 clBeginPerfMarkerAMD(__FUNCTION__,"");
1064 LockSemaphoreInfo(clEnv->lock);
1065 if (clEnv->OpenCLInitialized == MagickFalse) {
1066 if (clEnv->device==NULL
1067 && clEnv->OpenCLDisabled == MagickFalse)
1068 status = autoSelectDevice(clEnv, exception);
1070 status = InitOpenCLEnvInternal(clEnv, exception);
1072 UnlockSemaphoreInfo(clEnv->lock);
1074 #ifdef MAGICKCORE_CLPERFMARKER
1075 clEndPerfMarkerAMD();
1082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 + 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 %
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1092 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1094 % The format of the AcquireOpenCLCommandQueue method is:
1096 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1098 % A description of each parameter follows:
1100 % o clEnv: the OpenCL environment.
1105 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1108 return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 + 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 %
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125 % RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1127 % The format of the RelinquishOpenCLCommandQueue method is:
1129 % MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1130 % cl_command_queue queue)
1132 % A description of each parameter follows:
1134 % o clEnv: the OpenCL environment.
1136 % o queue: the OpenCL queue to be released.
1141 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1145 return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1154 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 + A c q u i r e O p e n C L K e r n e l %
1162 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1164 % AcquireOpenCLKernel() acquires an OpenCL kernel
1166 % The format of the AcquireOpenCLKernel method is:
1168 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
1169 % MagickOpenCLProgram program, const char* kernelName)
1171 % A description of each parameter follows:
1173 % o clEnv: the OpenCL environment.
1175 % o program: the OpenCL program module that the kernel belongs to.
1177 % o kernelName: the name of the kernel
1182 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1185 cl_kernel kernel = NULL;
1186 if (clEnv != NULL && kernelName!=NULL)
1188 kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199 + R e l i n q u i s h O p e n C L K e r n e l %
1203 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 % RelinquishOpenCLKernel() releases an OpenCL kernel
1207 % The format of the RelinquishOpenCLKernel method is:
1209 % MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1212 % A description of each parameter follows:
1214 % o clEnv: the OpenCL environment.
1216 % o kernel: the OpenCL kernel object to be released.
1222 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1224 MagickBooleanType status = MagickFalse;
1225 if (clEnv != NULL && kernel != NULL)
1227 status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1237 + 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 %
1241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1243 % GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1245 % The format of the GetOpenCLDeviceLocalMemorySize method is:
1247 % unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1249 % A description of each parameter follows:
1251 % o clEnv: the OpenCL environment.
1257 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1259 cl_ulong localMemorySize;
1260 clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1261 return (unsigned long)localMemorySize;
1265 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1267 cl_ulong maxMemAllocSize;
1268 clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1269 return (unsigned long)maxMemAllocSize;
1274 Beginning of the OpenCL device selection infrastructure
1280 ,DS_INVALID_PROFILE = 1000
1282 ,DS_INVALID_PERF_EVALUATOR_TYPE
1283 ,DS_INVALID_PERF_EVALUATOR
1284 ,DS_PERF_EVALUATOR_ERROR
1286 ,DS_UNKNOWN_DEVICE_TYPE
1287 ,DS_PROFILE_FILE_ERROR
1288 ,DS_SCORE_SERIALIZER_ERROR
1289 ,DS_SCORE_DESERIALIZER_ERROR
1294 DS_DEVICE_NATIVE_CPU = 0
1295 ,DS_DEVICE_OPENCL_DEVICE
1300 ds_device_type type;
1301 cl_device_id oclDeviceID;
1302 char* oclDeviceName;
1303 char* oclDriverVersion;
1304 cl_uint oclMaxClockFrequency;
1305 cl_uint oclMaxComputeUnits;
1306 void* score; /* a pointer to the score data, the content/format is application defined */
1310 unsigned int numDevices;
1312 const char* version;
1315 /* deallocate memory used by score */
1316 typedef ds_status (*ds_score_release)(void* score);
1318 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1319 ds_status status = DS_SUCCESS;
1321 if (device->oclDeviceName) free(device->oclDeviceName);
1322 if (device->oclDriverVersion) free(device->oclDriverVersion);
1323 if (device->score) status = sr(device->score);
1328 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1329 ds_status status = DS_SUCCESS;
1330 if (profile!=NULL) {
1331 if (profile->devices!=NULL && sr!=NULL) {
1333 for (i = 0; i < profile->numDevices; i++) {
1334 status = releaseDeviceResource(profile->devices+i,sr);
1335 if (status != DS_SUCCESS)
1338 free(profile->devices);
1346 static ds_status initDSProfile(ds_profile** p, const char* version) {
1348 cl_uint numPlatforms = 0;
1349 cl_platform_id* platforms = NULL;
1350 cl_device_id* devices = NULL;
1351 ds_status status = DS_SUCCESS;
1352 ds_profile* profile = NULL;
1353 unsigned int next = 0;
1357 return DS_INVALID_PROFILE;
1359 profile = (ds_profile*)malloc(sizeof(ds_profile));
1360 if (profile == NULL)
1361 return DS_MEMORY_ERROR;
1363 memset(profile, 0, sizeof(ds_profile));
1365 clGetPlatformIDs(0, NULL, &numPlatforms);
1366 if (numPlatforms > 0) {
1367 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1368 if (platforms == NULL) {
1369 status = DS_MEMORY_ERROR;
1372 clGetPlatformIDs(numPlatforms, platforms, NULL);
1373 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1375 if (clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num) == CL_SUCCESS)
1380 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1382 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1383 if (profile->devices == NULL) {
1384 profile->numDevices = 0;
1385 status = DS_MEMORY_ERROR;
1388 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1390 if (numDevices > 0) {
1391 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1392 if (devices == NULL) {
1393 status = DS_MEMORY_ERROR;
1396 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1400 for (d = 0; d < 2; d++) {
1402 cl_device_type deviceType;
1405 deviceType = CL_DEVICE_TYPE_GPU;
1408 deviceType = CL_DEVICE_TYPE_CPU;
1414 if (clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
1416 for (j = 0; j < num; j++, next++) {
1419 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1420 profile->devices[next].oclDeviceID = devices[j];
1422 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1423 , 0, NULL, &length);
1424 profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
1425 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1426 , length, profile->devices[next].oclDeviceName, NULL);
1428 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1429 , 0, NULL, &length);
1430 profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
1431 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1432 , length, profile->devices[next].oclDriverVersion, NULL);
1434 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1435 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1437 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1438 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1444 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1445 profile->version = version;
1448 if (platforms) free(platforms);
1449 if (devices) free(devices);
1450 if (status == DS_SUCCESS) {
1455 if (profile->devices)
1456 free(profile->devices);
1463 /* Pointer to a function that calculates the score of a device (ex: device->score)
1464 update the data size of score. The encoding and the format of the score data
1465 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1467 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1471 ,DS_EVALUATE_NEW_ONLY
1472 } ds_evaluation_type;
1474 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1475 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1476 ds_status status = DS_SUCCESS;
1478 unsigned int updates = 0;
1480 if (profile == NULL) {
1481 return DS_INVALID_PROFILE;
1483 if (evaluator == NULL) {
1484 return DS_INVALID_PERF_EVALUATOR;
1487 for (i = 0; i < profile->numDevices; i++) {
1488 ds_status evaluatorStatus;
1491 case DS_EVALUATE_NEW_ONLY:
1492 if (profile->devices[i].score != NULL)
1494 /* else fall through */
1495 case DS_EVALUATE_ALL:
1496 evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
1497 if (evaluatorStatus != DS_SUCCESS) {
1498 status = evaluatorStatus;
1504 return DS_INVALID_PERF_EVALUATOR_TYPE;
1509 *numUpdates = updates;
1514 #define DS_TAG_VERSION "<version>"
1515 #define DS_TAG_VERSION_END "</version>"
1516 #define DS_TAG_DEVICE "<device>"
1517 #define DS_TAG_DEVICE_END "</device>"
1518 #define DS_TAG_SCORE "<score>"
1519 #define DS_TAG_SCORE_END "</score>"
1520 #define DS_TAG_DEVICE_TYPE "<type>"
1521 #define DS_TAG_DEVICE_TYPE_END "</type>"
1522 #define DS_TAG_DEVICE_NAME "<name>"
1523 #define DS_TAG_DEVICE_NAME_END "</name>"
1524 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1525 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1526 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1527 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1528 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1529 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1531 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1535 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1536 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1537 ds_status status = DS_SUCCESS;
1538 FILE* profileFile = NULL;
1541 if (profile == NULL)
1542 return DS_INVALID_PROFILE;
1544 profileFile = fopen(file, "wb");
1545 if (profileFile==NULL) {
1546 status = DS_FILE_ERROR;
1551 /* write version string */
1552 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1553 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1554 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1555 fwrite("\n", sizeof(char), 1, profileFile);
1557 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1558 void* serializedScore;
1559 unsigned int serializedScoreSize;
1561 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1563 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1564 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1565 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1567 switch(profile->devices[i].type) {
1568 case DS_DEVICE_NATIVE_CPU:
1570 /* There's no need to emit a device name for the native CPU device. */
1572 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1573 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1574 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1578 case DS_DEVICE_OPENCL_DEVICE:
1582 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1583 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1584 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1586 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1587 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1588 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1590 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1591 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1592 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1593 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1595 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1596 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1597 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1598 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1602 status = DS_UNKNOWN_DEVICE_TYPE;
1606 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1607 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1608 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1609 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1610 free(serializedScore);
1612 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1613 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1614 fwrite("\n",sizeof(char),1,profileFile);
1616 fclose(profileFile);
1622 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1623 ds_status status = DS_SUCCESS;
1624 FILE * input = NULL;
1627 char* binary = NULL;
1632 input = fopen(fileName, "rb");
1634 return DS_FILE_ERROR;
1637 fseek(input, 0L, SEEK_END);
1638 size = ftell(input);
1640 binary = (char*)malloc(size);
1641 if(binary == NULL) {
1642 status = DS_FILE_ERROR;
1645 rsize = fread(binary, sizeof(char), size, input);
1648 status = DS_FILE_ERROR;
1651 *contentSize = size;
1655 if (input != NULL) fclose(input);
1656 if (status != DS_SUCCESS
1657 && binary != NULL) {
1666 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1667 size_t stringLength;
1668 const char* currentPosition;
1671 stringLength = strlen(string);
1672 currentPosition = contentStart;
1673 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1674 if (*currentPosition == string[0]) {
1675 if (currentPosition+stringLength < contentEnd) {
1676 if (strncmp(currentPosition, string, stringLength) == 0) {
1677 found = currentPosition;
1687 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1688 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1690 ds_status status = DS_SUCCESS;
1691 char* contentStart = NULL;
1692 const char* contentEnd = NULL;
1696 return DS_INVALID_PROFILE;
1698 status = readProFile(file, &contentStart, &contentSize);
1699 if (status == DS_SUCCESS) {
1700 const char* currentPosition;
1701 const char* dataStart;
1702 const char* dataEnd;
1703 size_t versionStringLength;
1705 contentEnd = contentStart + contentSize;
1706 currentPosition = contentStart;
1709 /* parse the version string */
1710 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1711 if (dataStart == NULL) {
1712 status = DS_PROFILE_FILE_ERROR;
1715 dataStart += strlen(DS_TAG_VERSION);
1717 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1718 if (dataEnd==NULL) {
1719 status = DS_PROFILE_FILE_ERROR;
1723 versionStringLength = strlen(profile->version);
1724 if (versionStringLength!=(size_t)(dataEnd-dataStart)
1725 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1726 /* version mismatch */
1727 status = DS_PROFILE_FILE_ERROR;
1730 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1732 /* parse the device information */
1733 DisableMSCWarning(4127)
1738 const char* deviceTypeStart;
1739 const char* deviceTypeEnd;
1740 ds_device_type deviceType;
1742 const char* deviceNameStart;
1743 const char* deviceNameEnd;
1745 const char* deviceScoreStart;
1746 const char* deviceScoreEnd;
1748 const char* deviceDriverStart;
1749 const char* deviceDriverEnd;
1751 const char* tmpStart;
1755 cl_uint maxClockFrequency;
1756 cl_uint maxComputeUnits;
1758 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1759 if (dataStart==NULL) {
1760 /* nothing useful remain, quit...*/
1763 dataStart+=strlen(DS_TAG_DEVICE);
1764 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1765 if (dataEnd==NULL) {
1766 status = DS_PROFILE_FILE_ERROR;
1770 /* parse the device type */
1771 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1772 if (deviceTypeStart==NULL) {
1773 status = DS_PROFILE_FILE_ERROR;
1776 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1777 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1778 if (deviceTypeEnd==NULL) {
1779 status = DS_PROFILE_FILE_ERROR;
1782 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1785 /* parse the device name */
1786 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1788 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1789 if (deviceNameStart==NULL) {
1790 status = DS_PROFILE_FILE_ERROR;
1793 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1794 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1795 if (deviceNameEnd==NULL) {
1796 status = DS_PROFILE_FILE_ERROR;
1801 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1802 if (deviceDriverStart==NULL) {
1803 status = DS_PROFILE_FILE_ERROR;
1806 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1807 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1808 if (deviceDriverEnd ==NULL) {
1809 status = DS_PROFILE_FILE_ERROR;
1814 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1815 if (tmpStart==NULL) {
1816 status = DS_PROFILE_FILE_ERROR;
1819 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1820 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1821 if (tmpEnd ==NULL) {
1822 status = DS_PROFILE_FILE_ERROR;
1825 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1826 tmp[tmpEnd-tmpStart] = '\0';
1827 maxComputeUnits = atoi(tmp);
1830 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1831 if (tmpStart==NULL) {
1832 status = DS_PROFILE_FILE_ERROR;
1835 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1836 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1837 if (tmpEnd ==NULL) {
1838 status = DS_PROFILE_FILE_ERROR;
1841 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1842 tmp[tmpEnd-tmpStart] = '\0';
1843 maxClockFrequency = atoi(tmp);
1846 /* check if this device is on the system */
1847 for (i = 0; i < profile->numDevices; i++) {
1848 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1849 size_t actualDeviceNameLength;
1850 size_t driverVersionLength;
1852 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1853 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1854 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
1855 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
1856 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1857 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1858 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1859 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1861 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1862 if (deviceNameStart==NULL) {
1863 status = DS_PROFILE_FILE_ERROR;
1866 deviceScoreStart+=strlen(DS_TAG_SCORE);
1867 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1868 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1869 if (status != DS_SUCCESS) {
1877 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1878 for (i = 0; i < profile->numDevices; i++) {
1879 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1880 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1881 if (deviceScoreStart==NULL) {
1882 status = DS_PROFILE_FILE_ERROR;
1885 deviceScoreStart+=strlen(DS_TAG_SCORE);
1886 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1887 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1888 if (status != DS_SUCCESS) {
1895 /* skip over the current one to find the next device */
1896 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1900 if (contentStart!=NULL) free(contentStart);
1906 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1908 if (profile == NULL || num==NULL)
1909 return DS_MEMORY_ERROR;
1911 for (i = 0; i < profile->numDevices; i++) {
1912 if (profile->devices[i].score == NULL) {
1921 End of the OpenCL device selection infrastructure
1926 typedef struct _AccelerateTimer {
1932 static void startAccelerateTimer(AccelerateTimer* timer) {
1934 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
1939 gettimeofday(&s, 0);
1940 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1944 static void stopAccelerateTimer(AccelerateTimer* timer) {
1947 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
1950 gettimeofday(&s, 0);
1951 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1955 timer->_clocks += n;
1958 static void resetAccelerateTimer(AccelerateTimer* timer) {
1964 static void initAccelerateTimer(AccelerateTimer* timer) {
1966 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1968 timer->_freq = (long long)1.0E3;
1970 resetAccelerateTimer(timer);
1973 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1976 typedef double AccelerateScoreType;
1978 static ds_status AcceleratePerfEvaluator(ds_device *device,
1979 void *magick_unused(data))
1981 #define ACCELERATE_PERF_DIMEN "2048x1536"
1983 #define ReturnStatus(status) \
1986 RelinquishMagickOpenCLEnv(clEnv); \
1987 if (oldClEnv!=NULL) \
1988 defaultCLEnv = oldClEnv; \
2002 magick_unreferenced(data);
2005 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2007 clEnv=AcquireMagickOpenCLEnv();
2008 exception=AcquireExceptionInfo();
2010 if (device->type == DS_DEVICE_NATIVE_CPU)
2013 MagickBooleanType flag=MagickTrue;
2014 SetMagickOpenCLEnvParamInternal(clEnv,
2015 MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
2018 else if (device->type == DS_DEVICE_OPENCL_DEVICE)
2021 SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
2022 sizeof(cl_device_id),&device->oclDeviceID,exception);
2025 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2027 /* recompile the OpenCL kernels if it needs to */
2028 clEnv->disableProgramCache = defaultCLEnv->disableProgramCache;
2030 InitOpenCLEnvInternal(clEnv,exception);
2031 oldClEnv=defaultCLEnv;
2034 /* microbenchmark */
2045 imageInfo=AcquireImageInfo();
2046 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
2047 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
2048 inputImage=ReadImage(imageInfo,exception);
2050 initAccelerateTimer(&timer);
2052 for (i=0; i<=NUM_ITER; i++)
2060 startAccelerateTimer(&timer);
2062 #ifdef MAGICKCORE_CLPERFMARKER
2063 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2066 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2067 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2069 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
2072 #ifdef MAGICKCORE_CLPERFMARKER
2073 clEndPerfMarkerAMD();
2077 stopAccelerateTimer(&timer);
2080 DestroyImage(bluredImage);
2082 DestroyImage(unsharpedImage);
2084 DestroyImage(resizedImage);
2086 DestroyImage(inputImage);
2088 /* end of microbenchmark */
2090 if (device->score == NULL)
2091 device->score=malloc(sizeof(AccelerateScoreType));
2092 *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
2094 ReturnStatus(DS_SUCCESS);
2097 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2100 /* generate a string from the score */
2101 char* s = (char*)malloc(sizeof(char)*256);
2102 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2103 *serializedScore = (void*)s;
2104 *serializedScoreSize = strlen(s);
2108 return DS_SCORE_SERIALIZER_ERROR;
2112 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2114 /* convert the string back to an int */
2115 char* s = (char*)malloc(serializedScoreSize+1);
2116 memcpy(s, serializedScore, serializedScoreSize);
2117 s[serializedScoreSize] = (char)'\0';
2118 device->score = malloc(sizeof(AccelerateScoreType));
2119 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2124 return DS_SCORE_DESERIALIZER_ERROR;
2128 ds_status AccelerateScoreRelease(void* score) {
2136 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2137 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2138 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2140 MagickBooleanType mStatus = MagickFalse;
2142 ds_profile* profile;
2143 unsigned int numDeviceProfiled = 0;
2145 unsigned int bestDeviceIndex;
2146 AccelerateScoreType bestScore;
2147 char path[MaxTextExtent];
2148 MagickBooleanType flag;
2149 ds_evaluation_type profileType;
2151 LockDefaultOpenCLEnv();
2153 /* Initially, just set OpenCL to off */
2155 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2156 , sizeof(MagickBooleanType), &flag, exception);
2158 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2159 if (status!=DS_SUCCESS) {
2160 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2164 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2165 ,GetOpenCLCachedFilesDirectory()
2166 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2168 if (clEnv->regenerateProfile != MagickFalse) {
2169 profileType = DS_EVALUATE_ALL;
2172 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2173 profileType = DS_EVALUATE_NEW_ONLY;
2175 status = profileDevices(profile, profileType, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2177 if (status!=DS_SUCCESS) {
2178 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2181 if (numDeviceProfiled > 0) {
2182 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2183 if (status!=DS_SUCCESS) {
2184 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2188 /* pick the best device */
2189 bestDeviceIndex = 0;
2190 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2191 for (i = 1; i < profile->numDevices; i++) {
2192 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2193 if (score < bestScore) {
2194 bestDeviceIndex = i;
2199 /* set up clEnv with the best device */
2200 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2203 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2204 , sizeof(MagickBooleanType), &flag, exception);
2206 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2209 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2210 , sizeof(MagickBooleanType), &flag, exception);
2211 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2212 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2215 status = DS_PERF_EVALUATOR_ERROR;
2218 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2220 status = releaseDSProfile(profile, AccelerateScoreRelease);
2221 if (status!=DS_SUCCESS) {
2222 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2227 UnlockDefaultOpenCLEnv();
2233 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2237 + I n i t I m a g e M a g i c k O p e n C L %
2241 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2243 % InitImageMagickOpenCL() provides a simplified interface to initialize
2244 % the OpenCL environtment in ImageMagick
2246 % The format of the InitImageMagickOpenCL() method is:
2248 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2249 % void* userSelectedDevice,
2250 % void* selectedDevice)
2252 % A description of each parameter follows:
2254 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2256 % o userSelectedDevice: when in user mode, a pointer to the selected
2259 % o selectedDevice: a pointer to cl_device_id where the selected
2260 % cl_device_id by ImageMagick could be returned
2262 % o exception: exception
2265 MagickExport MagickBooleanType InitImageMagickOpenCL(
2266 ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2267 ExceptionInfo *exception)
2269 MagickBooleanType status = MagickTrue;
2270 MagickCLEnv clEnv = NULL;
2271 MagickBooleanType flag;
2273 clEnv = GetDefaultOpenCLEnv();
2277 case MAGICK_OPENCL_OFF:
2279 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2280 , sizeof(MagickBooleanType), &flag, exception);
2281 status = InitOpenCLEnv(clEnv, exception);
2284 *(cl_device_id*)selectedDevice = NULL;
2287 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2289 if (userSelectedDevice == NULL)
2293 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2294 , sizeof(MagickBooleanType), &flag, exception);
2296 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2297 , sizeof(cl_device_id), userSelectedDevice,exception);
2299 status = InitOpenCLEnv(clEnv, exception);
2300 if (selectedDevice) {
2301 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2302 , sizeof(cl_device_id), selectedDevice, exception);
2306 case MAGICK_OPENCL_DEVICE_SELECT_AUTO_CLEAR_CACHE:
2308 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED
2309 , sizeof(MagickBooleanType), &flag, exception);
2311 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE
2312 , sizeof(MagickBooleanType), &flag, exception);
2314 /* fall through here!! */
2315 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2318 cl_device_id d = NULL;
2320 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2321 , sizeof(MagickBooleanType), &flag, exception);
2322 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2323 , sizeof(cl_device_id), &d,exception);
2324 status = InitOpenCLEnv(clEnv, exception);
2325 if (selectedDevice) {
2326 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2327 , sizeof(cl_device_id), selectedDevice, exception);
2338 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2339 const char *module,const char *function,const size_t line,
2340 const ExceptionType severity,const char *tag,const char *format,...) {
2346 status = MagickTrue;
2348 clEnv = GetDefaultOpenCLEnv();
2350 assert(exception != (ExceptionInfo *) NULL);
2351 assert(exception->signature == MagickSignature);
2354 cl_device_type dType;
2355 clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
2356 if (dType == CL_DEVICE_TYPE_CPU) {
2357 char buffer[MaxTextExtent];
2358 clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
2360 /* Workaround for Intel OpenCL CPU runtime bug */
2361 /* Turn off OpenCL when a problem is detected! */
2362 if (strncmp(buffer, "Intel",5) == 0) {
2364 InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2369 #ifdef OPENCLLOG_ENABLED
2373 va_start(operands,format);
2374 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2378 magick_unreferenced(module);
2379 magick_unreferenced(function);
2380 magick_unreferenced(line);
2381 magick_unreferenced(tag);
2382 magick_unreferenced(format);
2391 struct _MagickCLEnv {
2392 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2395 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2400 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2401 MagickCLEnv magick_unused(clEnv))
2403 magick_unreferenced(clEnv);
2409 * Return the OpenCL environment
2411 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2412 ExceptionInfo *magick_unused(exception))
2414 magick_unreferenced(exception);
2416 return (MagickCLEnv) NULL;
2419 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2420 MagickCLEnv magick_unused(clEnv))
2422 magick_unreferenced(clEnv);
2424 return (MagickCLEnv) NULL;
2427 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2428 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2429 size_t magick_unused(dataSize),void *magick_unused(data),
2430 ExceptionInfo *magick_unused(exception))
2432 magick_unreferenced(clEnv);
2433 magick_unreferenced(param);
2434 magick_unreferenced(dataSize);
2435 magick_unreferenced(data);
2436 magick_unreferenced(exception);
2441 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2442 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2443 size_t magick_unused(dataSize),void *magick_unused(data),
2444 ExceptionInfo *magick_unused(exception))
2446 magick_unreferenced(clEnv);
2447 magick_unreferenced(param);
2448 magick_unreferenced(dataSize);
2449 magick_unreferenced(data);
2450 magick_unreferenced(exception);
2455 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2456 ExceptionInfo *magick_unused(exception))
2458 magick_unreferenced(clEnv);
2459 magick_unreferenced(exception);
2464 MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(
2465 MagickCLEnv magick_unused(clEnv))
2467 magick_unreferenced(clEnv);
2469 return (cl_command_queue) NULL;
2472 MagickExport MagickBooleanType RelinquishCommandQueue(
2473 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2475 magick_unreferenced(clEnv);
2476 magick_unreferenced(queue);
2481 MagickPrivate cl_kernel AcquireOpenCLKernel(
2482 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2483 const char *magick_unused(kernelName))
2485 magick_unreferenced(clEnv);
2486 magick_unreferenced(program);
2487 magick_unreferenced(kernelName);
2489 return (cl_kernel)NULL;
2492 MagickPrivate MagickBooleanType RelinquishOpenCLKernel(
2493 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2495 magick_unreferenced(clEnv);
2496 magick_unreferenced(kernel);
2501 MagickPrivate unsigned long GetOpenCLDeviceLocalMemorySize(
2502 MagickCLEnv magick_unused(clEnv))
2504 magick_unreferenced(clEnv);
2509 MagickExport MagickBooleanType InitImageMagickOpenCL(
2510 ImageMagickOpenCLMode magick_unused(mode),
2511 void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2512 ExceptionInfo *magick_unused(exception))
2514 magick_unreferenced(mode);
2515 magick_unreferenced(userSelectedDevice);
2516 magick_unreferenced(selectedDevice);
2517 magick_unreferenced(exception);
2523 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2524 const char *module,const char *function,const size_t line,
2525 const ExceptionType severity,const char *tag,const char *format,...)
2527 magick_unreferenced(exception);
2528 magick_unreferenced(module);
2529 magick_unreferenced(function);
2530 magick_unreferenced(line);
2531 magick_unreferenced(severity);
2532 magick_unreferenced(tag);
2533 magick_unreferenced(format);
2534 return(MagickFalse);
2536 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2538 char* openclCachedFilesDirectory;
2539 SemaphoreInfo* openclCachedFilesDirectoryLock;
2542 const char* GetOpenCLCachedFilesDirectory() {
2543 if (openclCachedFilesDirectory == NULL) {
2544 if (openclCachedFilesDirectoryLock == NULL)
2546 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2548 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2549 if (openclCachedFilesDirectory == NULL) {
2550 char path[MaxTextExtent];
2553 struct stat attributes;
2554 MagickBooleanType status;
2556 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2557 home=GetEnvironmentValue("LOCALAPPDATA");
2558 if (home == (char *) NULL)
2559 home=GetEnvironmentValue("APPDATA");
2560 if (home == (char *) NULL)
2561 home=GetEnvironmentValue("USERPROFILE");
2563 home=GetEnvironmentValue("HOME");
2565 if (home != (char *) NULL)
2568 Search $HOME/.magick.
2570 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2571 DirectorySeparator);
2572 home=DestroyString(home);
2573 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2574 CopyMagickString(temp,path,strlen(path)+1);
2575 status=GetPathAttributes(path,&attributes);
2576 if (status == MagickFalse) {
2577 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2584 openclCachedFilesDirectory = temp;
2586 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2588 return openclCachedFilesDirectory;
2591 /* create a function for OpenCL log */
2593 void OpenCLLog(const char* message) {
2595 #ifdef OPENCLLOG_ENABLED
2596 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2599 if (getenv("MAGICK_OCL_LOG"))
2602 char path[MaxTextExtent];
2603 unsigned long allocSize;
2607 clEnv = GetDefaultOpenCLEnv();
2609 /* dump the source into a file */
2610 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2611 ,GetOpenCLCachedFilesDirectory()
2612 ,DirectorySeparator,OPENCL_LOG_FILE);
2615 log = fopen(path, "ab");
2616 fwrite(message, sizeof(char), strlen(message), log);
2617 fwrite("\n", sizeof(char), 1, log);
2619 if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
2621 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
2622 fprintf(log, "Devic Max Memory Alloc Size: %ld\n", allocSize);
2629 magick_unreferenced(message);