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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 #include "MagickCore/studio.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/cache.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/compare.h"
49 #include "MagickCore/constitute.h"
50 #include "MagickCore/distort.h"
51 #include "MagickCore/draw.h"
52 #include "MagickCore/effect.h"
53 #include "MagickCore/exception.h"
54 #include "MagickCore/exception-private.h"
55 #include "MagickCore/fx.h"
56 #include "MagickCore/gem.h"
57 #include "MagickCore/geometry.h"
58 #include "MagickCore/image.h"
59 #include "MagickCore/image-private.h"
60 #include "MagickCore/layer.h"
61 #include "MagickCore/mime-private.h"
62 #include "MagickCore/memory_.h"
63 #include "MagickCore/monitor.h"
64 #include "MagickCore/montage.h"
65 #include "MagickCore/morphology.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"
92 #ifdef MAGICKCORE_CLPERFMARKER
93 #include "CLPerfMarker.h"
97 #if defined(MAGICKCORE_OPENCL_SUPPORT)
100 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
101 MagickBooleanType OpenCLDisabled; /* whether if OpenCL has been explicitely disabled. */
104 cl_platform_id platform;
105 cl_device_type deviceType;
109 cl_program programs[MAGICK_OPENCL_NUM_PROGRAMS]; /* one program object maps one kernel source file */
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 + A c q u i r e M a g i c k O p e n C L E n v %
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 % AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure
130 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
133 clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
136 memset(clEnv, 0, sizeof(struct _MagickCLEnv));
137 AcquireSemaphoreInfo(&clEnv->lock);
144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 + 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 %
152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 % RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
156 % The format of the RelinquishMagickOpenCLEnv method is:
158 % MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
160 % A description of each parameter follows:
162 % o clEnv: MagickCLEnv structure to destroy
166 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
168 if (clEnv != (MagickCLEnv)NULL)
170 RelinquishSemaphoreInfo(clEnv->lock);
171 RelinquishMagickMemory(clEnv);
179 * Default OpenCL environment
181 MagickCLEnv defaultCLEnv;
182 SemaphoreInfo* defaultCLEnvLock;
186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
190 + G e t D e f a u l t O p e n C L E n v %
194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 % GetDefaultOpenCLEnv() returns the default OpenCL env
198 % The format of the GetDefaultOpenCLEnv method is:
200 % MagickCLEnv GetDefaultOpenCLEnv()
202 % A description of each parameter follows:
204 % o exception: return any errors or warnings.
208 MagickExport MagickCLEnv GetDefaultOpenCLEnv()
210 if (defaultCLEnv == NULL)
212 if (defaultCLEnvLock == NULL)
214 AcquireSemaphoreInfo(&defaultCLEnvLock);
216 LockSemaphoreInfo(defaultCLEnvLock);
217 defaultCLEnv = AcquireMagickOpenCLEnv();
218 UnlockSemaphoreInfo(defaultCLEnvLock);
223 static void LockDefaultOpenCLEnv() {
224 if (defaultCLEnvLock == NULL)
226 AcquireSemaphoreInfo(&defaultCLEnvLock);
228 LockSemaphoreInfo(defaultCLEnvLock);
231 static void UnlockDefaultOpenCLEnv() {
232 if (defaultCLEnvLock == NULL)
234 AcquireSemaphoreInfo(&defaultCLEnvLock);
237 UnlockSemaphoreInfo(defaultCLEnvLock);
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246 + S e t D e f a u l t O p e n C L E n v %
250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252 % SetDefaultOpenCLEnv() sets the new OpenCL environment as default
253 % and returns the old OpenCL environment
255 % The format of the SetDefaultOpenCLEnv() method is:
257 % MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
259 % A description of each parameter follows:
261 % o clEnv: the new default OpenCL environment.
264 MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
267 LockDefaultOpenCLEnv();
268 oldEnv = defaultCLEnv;
269 defaultCLEnv = clEnv;
270 UnlockDefaultOpenCLEnv();
277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281 + S e t M a g i c k O p e n C L E n v P a r a m %
285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 % SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
289 % The format of the SetMagickOpenCLEnvParam() method is:
291 % MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
292 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
293 % ExceptionInfo* exception)
295 % A description of each parameter follows:
297 % o clEnv: the OpenCL environment.
299 % o param: the parameter to be set.
301 % o dataSize: the data size of the parameter value.
303 % o data: the pointer to the new parameter value
305 % o exception: return any errors or warnings
309 static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
310 , size_t dataSize, void* data, ExceptionInfo* exception)
312 MagickBooleanType status = MagickFalse;
320 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
321 if (dataSize != sizeof(clEnv->device))
323 clEnv->device = *((cl_device_id*)data);
324 clEnv->OpenCLInitialized = MagickFalse;
328 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
329 if (dataSize != sizeof(clEnv->OpenCLDisabled))
331 clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
332 clEnv->OpenCLInitialized = MagickFalse;
336 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
337 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
349 MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
350 , size_t dataSize, void* data, ExceptionInfo* exception) {
351 MagickBooleanType status = MagickFalse;
353 LockSemaphoreInfo(clEnv->lock);
354 status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
355 UnlockSemaphoreInfo(clEnv->lock);
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 + G e t M a g i c k O p e n C L E n v P a r a m %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 % GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
373 % The format of the GetMagickOpenCLEnvParam() method is:
375 % MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
376 % MagickOpenCLEnvParam param, size_t dataSize, void* data,
377 % ExceptionInfo* exception)
379 % A description of each parameter follows:
381 % o clEnv: the OpenCL environment.
383 % o param: the parameter to be returned.
385 % o dataSize: the data size of the parameter value.
387 % o data: the location where the returned parameter value will be stored
389 % o exception: return any errors or warnings
394 MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
395 , size_t dataSize, void* data, ExceptionInfo* exception)
397 MagickBooleanType status;
398 status = MagickFalse;
406 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
407 if (dataSize != sizeof(cl_device_id))
409 *((cl_device_id*)data) = clEnv->device;
413 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
414 if (dataSize != sizeof(clEnv->OpenCLDisabled))
416 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
420 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
421 if (dataSize != sizeof(clEnv->OpenCLDisabled))
423 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 + G e t O p e n C L C o n t e x t %
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447 % GetOpenCLContext() returns the OpenCL context
449 % The format of the GetOpenCLContext() method is:
451 % cl_context GetOpenCLContext(MagickCLEnv clEnv)
453 % A description of each parameter follows:
455 % o clEnv: OpenCL environment
460 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
464 return clEnv->context;
467 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
470 char path[MaxTextExtent];
471 char deviceName[MaxTextExtent];
472 const char* prefix = "magick_opencl";
473 clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
474 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x.bin"
475 ,GetOpenCLCachedFilesDirectory()
476 ,DirectorySeparator,prefix,deviceName, (unsigned int)prog, signature);
477 name = (char*)AcquireMagickMemory(strlen(path)+1);
478 CopyMagickString(name,path,strlen(path)+1);
482 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
484 MagickBooleanType saveSuccessful;
486 size_t binaryProgramSize;
487 unsigned char* binaryProgram;
488 char* binaryFileName;
491 #ifdef MAGICKCORE_CLPERFMARKER
492 clBeginPerfMarkerAMD(__FUNCTION__,"");
495 binaryProgram = NULL;
496 binaryFileName = NULL;
498 saveSuccessful = MagickFalse;
500 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
501 if (clStatus != CL_SUCCESS)
503 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
507 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
508 clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
509 if (clStatus != CL_SUCCESS)
511 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
515 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
516 fileHandle = fopen(binaryFileName, "wb");
517 if (fileHandle != NULL)
519 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
520 saveSuccessful = MagickTrue;
524 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
525 "Saving binary kernel failed.", "'%s'", ".");
529 if (fileHandle != NULL)
531 if (binaryProgram != NULL)
532 RelinquishMagickMemory(binaryProgram);
533 if (binaryFileName != NULL)
534 free(binaryFileName);
536 #ifdef MAGICKCORE_CLPERFMARKER
537 clEndPerfMarkerAMD();
540 return saveSuccessful;
543 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
545 MagickBooleanType loadSuccessful;
546 unsigned char* binaryProgram;
547 char* binaryFileName;
550 #ifdef MAGICKCORE_CLPERFMARKER
551 clBeginPerfMarkerAMD(__FUNCTION__,"");
554 binaryProgram = NULL;
555 binaryFileName = NULL;
557 loadSuccessful = MagickFalse;
559 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
560 fileHandle = fopen(binaryFileName, "rb");
561 if (fileHandle != NULL)
566 cl_int clBinaryStatus;
570 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
571 b_error |= ( length = ftell( fileHandle ) ) <= 0;
572 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
576 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
577 if (binaryProgram == NULL)
580 memset(binaryProgram, 0, length);
581 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
583 clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
584 if (clStatus != CL_SUCCESS
585 || clBinaryStatus != CL_SUCCESS)
588 loadSuccessful = MagickTrue;
592 if (fileHandle != NULL)
594 if (binaryFileName != NULL)
595 free(binaryFileName);
596 if (binaryProgram != NULL)
597 RelinquishMagickMemory(binaryProgram);
599 #ifdef MAGICKCORE_CLPERFMARKER
600 clEndPerfMarkerAMD();
603 return loadSuccessful;
606 static unsigned int stringSignature(const char* string)
608 unsigned int stringLength;
610 unsigned int signature;
614 const unsigned int* u;
617 #ifdef MAGICKCORE_CLPERFMARKER
618 clBeginPerfMarkerAMD(__FUNCTION__,"");
621 stringLength = strlen(string);
622 signature = stringLength;
623 n = stringLength/sizeof(unsigned int);
625 for (i = 0; i < n; i++)
629 if (n * sizeof(unsigned int) != stringLength)
632 j = n * sizeof(unsigned int);
633 for (i = 0; i < 4; i++,j++)
635 if (j < stringLength)
644 #ifdef MAGICKCORE_CLPERFMARKER
645 clEndPerfMarkerAMD();
651 /* OpenCL kernels for accelerate.c */
652 extern const char *accelerateKernels, *accelerateKernels2;
654 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
656 MagickBooleanType status = MagickFalse;
659 char* accelerateKernelsBuffer = NULL;
661 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
662 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
664 char options[MaxTextExtent];
665 unsigned int optionsSignature;
667 #ifdef MAGICKCORE_CLPERFMARKER
668 clBeginPerfMarkerAMD(__FUNCTION__,"");
671 /* Get additional options */
672 (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
673 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
676 if (getenv("MAGICK_OCL_DEF"))
679 strcat(options,getenv("MAGICK_OCL_DEF"));
684 if (getenv("MAGICK_OCL_BUILD"))
685 printf("options: %s\n", options);
688 optionsSignature = stringSignature(options);
690 /* get all the OpenCL program strings here */
691 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
692 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
693 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
695 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
697 MagickBooleanType loadSuccessful = MagickFalse;
698 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
700 /* try to load the binary first */
701 if (!getenv("MAGICK_OCL_REC"))
702 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
704 if (loadSuccessful == MagickFalse)
706 /* Binary CL program unavailable, compile the program from source */
707 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
708 clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
709 if (clStatus!=CL_SUCCESS)
711 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
712 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
718 clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
719 if (clStatus!=CL_SUCCESS)
721 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
722 "clBuildProgram failed.", "(%d)", (int)clStatus);
724 if (loadSuccessful == MagickFalse)
726 char path[MaxTextExtent];
729 /* dump the source into a file */
730 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
731 ,GetOpenCLCachedFilesDirectory()
732 ,DirectorySeparator,"magick_badcl.cl");
733 fileHandle = fopen(path, "wb");
734 if (fileHandle != NULL)
736 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
740 /* dump the build log */
744 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
745 log = (char*)AcquireMagickMemory(logSize);
746 clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
748 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
749 ,GetOpenCLCachedFilesDirectory()
750 ,DirectorySeparator,"magick_badcl_build.log");
751 fileHandle = fopen(path, "wb");
752 if (fileHandle != NULL)
754 const char* buildOptionsTitle = "build options: ";
755 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
756 fwrite(options, sizeof(char), strlen(options), fileHandle);
757 fwrite("\n",sizeof(char), 1, fileHandle);
758 fwrite(log, sizeof(char), logSize, fileHandle);
761 RelinquishMagickMemory(log);
767 if (loadSuccessful == MagickFalse)
769 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
770 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
778 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
780 #ifdef MAGICKCORE_CLPERFMARKER
781 clEndPerfMarkerAMD();
787 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
790 cl_uint numPlatforms = 0;
791 cl_platform_id *platforms = NULL;
792 char* MAGICK_OCL_DEVICE = NULL;
793 MagickBooleanType OpenCLAvailable = MagickFalse;
795 #ifdef MAGICKCORE_CLPERFMARKER
796 clBeginPerfMarkerAMD(__FUNCTION__,"");
799 /* check if there's an environment variable overriding the device selection */
800 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
801 if (MAGICK_OCL_DEVICE != NULL)
803 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
805 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
807 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
809 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
811 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
813 /* OpenCL disabled */
817 else if (clEnv->deviceType == 0) {
818 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
821 if (clEnv->device != NULL)
823 status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
824 if (status != CL_SUCCESS) {
825 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
826 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
830 else if (clEnv->platform != NULL)
833 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
834 if (platforms == (cl_platform_id *) NULL)
836 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
837 "AcquireMagickMemory failed.",".");
840 platforms[0] = clEnv->platform;
844 clEnv->device = NULL;
846 /* Get the number of OpenCL platforms available */
847 status = clGetPlatformIDs(0, NULL, &numPlatforms);
848 if (status != CL_SUCCESS)
850 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
851 "clGetplatformIDs failed.", "(%d)", status);
855 /* No OpenCL available, just leave */
856 if (numPlatforms == 0) {
860 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
861 if (platforms == (cl_platform_id *) NULL)
863 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
864 "AcquireMagickMemory failed.",".");
868 status = clGetPlatformIDs(numPlatforms, platforms, NULL);
869 if (status != CL_SUCCESS)
871 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
872 "clGetPlatformIDs failed.", "(%d)", status);
877 /* Device selection */
878 clEnv->device = NULL;
879 for (j = 0; j < 2; j++)
882 cl_device_type deviceType;
883 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
886 deviceType = CL_DEVICE_TYPE_GPU;
888 deviceType = CL_DEVICE_TYPE_CPU;
895 deviceType = clEnv->deviceType;
897 for (i = 0; i < numPlatforms; i++)
900 status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
901 if (status != CL_SUCCESS)
903 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
904 "clGetPlatformIDs failed.", "(%d)", status);
907 if (clEnv->device != NULL)
909 clEnv->platform = platforms[i];
917 RelinquishMagickMemory(platforms);
919 OpenCLAvailable = (clEnv->platform!=NULL
920 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
922 #ifdef MAGICKCORE_CLPERFMARKER
923 clEndPerfMarkerAMD();
926 return OpenCLAvailable;
929 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
930 if (clEnv->OpenCLInitialized == MagickTrue
931 && clEnv->platform != NULL
932 && clEnv->device != NULL) {
933 clEnv->OpenCLDisabled = MagickFalse;
936 clEnv->OpenCLDisabled = MagickTrue;
941 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
943 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
947 + I n i t O p e n C L E n v %
951 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
953 % InitOpenCLEnv() initialize the OpenCL environment
955 % The format of the RelinquishMagickOpenCLEnv method is:
957 % MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
959 % A description of each parameter follows:
961 % o clEnv: OpenCL environment structure
963 % o exception: return any errors or warnings.
968 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
969 MagickBooleanType status = MagickTrue;
971 cl_context_properties cps[3];
974 clEnv->OpenCLInitialized = MagickTrue;
975 if (clEnv->OpenCLDisabled == MagickTrue)
978 clEnv->OpenCLDisabled = MagickTrue;
979 /* setup the OpenCL platform and device */
980 status = InitOpenCLPlatformDevice(clEnv, exception);
981 if (status == MagickFalse) {
982 /* No OpenCL device available */
986 /* create an OpenCL context */
987 cps[0] = CL_CONTEXT_PLATFORM;
988 cps[1] = (cl_context_properties)clEnv->platform;
990 clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
991 if (clStatus != CL_SUCCESS)
993 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
994 "clCreateContext failed.", "(%d)", clStatus);
995 status = MagickFalse;
999 status = CompileOpenCLKernels(clEnv, exception);
1000 if (status == MagickFalse) {
1001 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1002 "clCreateCommandQueue failed.", "(%d)", status);
1004 status = MagickFalse;
1008 status = EnableOpenCLInternal(clEnv);
1015 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1016 MagickBooleanType status = MagickFalse;
1021 #ifdef MAGICKCORE_CLPERFMARKER
1022 clBeginPerfMarkerAMD(__FUNCTION__,"");
1025 LockSemaphoreInfo(clEnv->lock);
1026 if (clEnv->OpenCLInitialized == MagickFalse) {
1027 if (clEnv->device==NULL
1028 && clEnv->OpenCLDisabled == MagickFalse)
1029 status = autoSelectDevice(clEnv, exception);
1031 status = InitOpenCLEnvInternal(clEnv, exception);
1033 UnlockSemaphoreInfo(clEnv->lock);
1035 #ifdef MAGICKCORE_CLPERFMARKER
1036 clEndPerfMarkerAMD();
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1047 + 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 %
1051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053 % AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1055 % The format of the AcquireOpenCLCommandQueue method is:
1057 % cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1059 % A description of each parameter follows:
1061 % o clEnv: the OpenCL environment.
1066 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1069 return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1080 + 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 %
1084 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1086 % RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1088 % The format of the RelinquishOpenCLCommandQueue method is:
1090 % MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1091 % cl_command_queue queue)
1093 % A description of each parameter follows:
1095 % o clEnv: the OpenCL environment.
1097 % o queue: the OpenCL queue to be released.
1102 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1106 return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 + A c q u i r e O p e n C L K e r n e l %
1123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1125 % AcquireOpenCLKernel() acquires an OpenCL kernel
1127 % The format of the AcquireOpenCLKernel method is:
1129 % cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
1130 % MagickOpenCLProgram program, const char* kernelName)
1132 % A description of each parameter follows:
1134 % o clEnv: the OpenCL environment.
1136 % o program: the OpenCL program module that the kernel belongs to.
1138 % o kernelName: the name of the kernel
1143 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1146 cl_kernel kernel = NULL;
1147 if (clEnv != NULL && kernelName!=NULL)
1149 kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160 + R e l i n q u i s h O p e n C L K e r n e l %
1164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1166 % RelinquishOpenCLKernel() releases an OpenCL kernel
1168 % The format of the RelinquishOpenCLKernel method is:
1170 % MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1173 % A description of each parameter follows:
1175 % o clEnv: the OpenCL environment.
1177 % o kernel: the OpenCL kernel object to be released.
1183 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1185 MagickBooleanType status = MagickFalse;
1186 if (clEnv != NULL && kernel != NULL)
1188 status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198 + 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 %
1202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1204 % GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1206 % The format of the GetOpenCLDeviceLocalMemorySize method is:
1208 % unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1210 % A description of each parameter follows:
1212 % o clEnv: the OpenCL environment.
1218 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1220 cl_ulong localMemorySize;
1221 clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1222 return (unsigned long)localMemorySize;
1226 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1228 cl_ulong maxMemAllocSize;
1229 clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1230 return (unsigned long)maxMemAllocSize;
1235 Beginning of the OpenCL device selection infrastructure
1239 #define DS_DEVICE_NAME_LENGTH 256
1243 ,DS_INVALID_PROFILE = 1000
1245 ,DS_INVALID_PERF_EVALUATOR_TYPE
1246 ,DS_INVALID_PERF_EVALUATOR
1247 ,DS_PERF_EVALUATOR_ERROR
1249 ,DS_UNKNOWN_DEVICE_TYPE
1250 ,DS_PROFILE_FILE_ERROR
1251 ,DS_SCORE_SERIALIZER_ERROR
1252 ,DS_SCORE_DESERIALIZER_ERROR
1257 DS_DEVICE_NATIVE_CPU = 0
1258 ,DS_DEVICE_OPENCL_DEVICE
1263 ds_device_type type;
1264 cl_device_id oclDeviceID;
1265 char* oclDeviceName;
1266 char* oclDriverVersion;
1267 cl_uint oclMaxClockFrequency;
1268 cl_uint oclMaxComputeUnits;
1269 void* score; /* a pointer to the score data, the content/format is application defined */
1273 unsigned int numDevices;
1275 const char* version;
1278 /* deallocate memory used by score */
1279 typedef ds_status (*ds_score_release)(void* score);
1281 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1282 ds_status status = DS_SUCCESS;
1284 if (device->oclDeviceName) free(device->oclDeviceName);
1285 if (device->oclDriverVersion) free(device->oclDriverVersion);
1286 if (device->score) status = sr(device->score);
1291 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1292 ds_status status = DS_SUCCESS;
1293 if (profile!=NULL) {
1294 if (profile->devices!=NULL && sr!=NULL) {
1296 for (i = 0; i < profile->numDevices; i++) {
1297 status = releaseDeviceResource(profile->devices+i,sr);
1298 if (status != DS_SUCCESS)
1301 free(profile->devices);
1309 static ds_status initDSProfile(ds_profile** p, const char* version) {
1311 cl_uint numPlatforms = 0;
1312 cl_platform_id* platforms = NULL;
1313 cl_device_id* devices = NULL;
1314 ds_status status = DS_SUCCESS;
1315 ds_profile* profile = NULL;
1316 unsigned int next = 0;
1320 return DS_INVALID_PROFILE;
1322 profile = (ds_profile*)malloc(sizeof(ds_profile));
1323 if (profile == NULL)
1324 return DS_MEMORY_ERROR;
1326 memset(profile, 0, sizeof(ds_profile));
1328 clGetPlatformIDs(0, NULL, &numPlatforms);
1329 if (numPlatforms > 0) {
1330 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1331 if (platforms == NULL) {
1332 status = DS_MEMORY_ERROR;
1335 clGetPlatformIDs(numPlatforms, platforms, NULL);
1336 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1338 clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
1343 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1345 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
1346 if (profile->devices == NULL) {
1347 profile->numDevices = 0;
1348 status = DS_MEMORY_ERROR;
1351 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1353 if (numDevices > 0) {
1354 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1355 if (devices == NULL) {
1356 status = DS_MEMORY_ERROR;
1359 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1363 for (d = 0; d < 2; d++) {
1365 cl_device_type deviceType;
1368 deviceType = CL_DEVICE_TYPE_GPU;
1371 deviceType = CL_DEVICE_TYPE_CPU;
1377 clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num);
1378 for (j = 0; j < num; j++, next++) {
1379 char buffer[DS_DEVICE_NAME_LENGTH];
1382 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1383 profile->devices[next].oclDeviceID = devices[j];
1385 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1386 , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1387 length = strlen(buffer);
1388 profile->devices[next].oclDeviceName = (char*)malloc(length+1);
1389 memcpy(profile->devices[next].oclDeviceName, buffer, length+1);
1391 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1392 , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1393 length = strlen(buffer);
1394 profile->devices[next].oclDriverVersion = (char*)malloc(length+1);
1395 memcpy(profile->devices[next].oclDriverVersion, buffer, length+1);
1397 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1398 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1400 clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1401 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1407 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1408 profile->version = version;
1411 if (platforms) free(platforms);
1412 if (devices) free(devices);
1413 if (status == DS_SUCCESS) {
1418 if (profile->devices)
1419 free(profile->devices);
1426 /* Pointer to a function that calculates the score of a device (ex: device->score)
1427 update the data size of score. The encoding and the format of the score data
1428 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1430 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1434 ,DS_EVALUATE_NEW_ONLY
1435 } ds_evaluation_type;
1437 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1438 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1439 ds_status status = DS_SUCCESS;
1441 unsigned int updates = 0;
1443 if (profile == NULL) {
1444 return DS_INVALID_PROFILE;
1446 if (evaluator == NULL) {
1447 return DS_INVALID_PERF_EVALUATOR;
1450 for (i = 0; i < profile->numDevices; i++) {
1451 ds_status evaluatorStatus;
1454 case DS_EVALUATE_NEW_ONLY:
1455 if (profile->devices[i].score != NULL)
1457 /* else fall through */
1458 case DS_EVALUATE_ALL:
1459 evaluatorStatus = evaluator(profile->devices+i, evaluatorData);
1460 if (evaluatorStatus != DS_SUCCESS) {
1461 status = evaluatorStatus;
1467 return DS_INVALID_PERF_EVALUATOR_TYPE;
1472 *numUpdates = updates;
1477 #define DS_TAG_VERSION "<version>"
1478 #define DS_TAG_VERSION_END "</version>"
1479 #define DS_TAG_DEVICE "<device>"
1480 #define DS_TAG_DEVICE_END "</device>"
1481 #define DS_TAG_SCORE "<score>"
1482 #define DS_TAG_SCORE_END "</score>"
1483 #define DS_TAG_DEVICE_TYPE "<type>"
1484 #define DS_TAG_DEVICE_TYPE_END "</type>"
1485 #define DS_TAG_DEVICE_NAME "<name>"
1486 #define DS_TAG_DEVICE_NAME_END "</name>"
1487 #define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1488 #define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1489 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1490 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1491 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1492 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1494 #define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1498 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1499 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1500 ds_status status = DS_SUCCESS;
1501 FILE* profileFile = NULL;
1504 if (profile == NULL)
1505 return DS_INVALID_PROFILE;
1507 profileFile = fopen(file, "wb");
1508 if (profileFile==NULL) {
1509 status = DS_FILE_ERROR;
1514 /* write version string */
1515 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1516 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1517 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1518 fwrite("\n", sizeof(char), 1, profileFile);
1520 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1521 void* serializedScore;
1522 unsigned int serializedScoreSize;
1524 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1526 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1527 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1528 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1530 switch(profile->devices[i].type) {
1531 case DS_DEVICE_NATIVE_CPU:
1533 /* There's no need to emit a device name for the native CPU device. */
1535 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1536 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1537 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1541 case DS_DEVICE_OPENCL_DEVICE:
1545 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1546 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1547 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1549 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1550 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1551 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1553 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1554 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1555 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1556 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1558 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1559 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1560 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1561 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1565 status = DS_UNKNOWN_DEVICE_TYPE;
1569 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1570 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1571 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1572 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1573 free(serializedScore);
1575 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1576 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1577 fwrite("\n",sizeof(char),1,profileFile);
1579 fclose(profileFile);
1585 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1586 ds_status status = DS_SUCCESS;
1587 FILE * input = NULL;
1590 char* binary = NULL;
1595 input = fopen(fileName, "rb");
1597 return DS_FILE_ERROR;
1600 fseek(input, 0L, SEEK_END);
1601 size = ftell(input);
1603 binary = (char*)malloc(size);
1604 if(binary == NULL) {
1605 status = DS_FILE_ERROR;
1608 rsize = fread(binary, sizeof(char), size, input);
1611 status = DS_FILE_ERROR;
1614 *contentSize = size;
1618 if (input != NULL) fclose(input);
1619 if (status != DS_SUCCESS
1620 && binary != NULL) {
1629 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1630 size_t stringLength;
1631 const char* currentPosition;
1634 stringLength = strlen(string);
1635 currentPosition = contentStart;
1636 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1637 if (*currentPosition == string[0]) {
1638 if (currentPosition+stringLength < contentEnd) {
1639 if (strncmp(currentPosition, string, stringLength) == 0) {
1640 found = currentPosition;
1650 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
1651 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1653 ds_status status = DS_SUCCESS;
1654 char* contentStart = NULL;
1655 const char* contentEnd = NULL;
1659 return DS_INVALID_PROFILE;
1661 status = readProFile(file, &contentStart, &contentSize);
1662 if (status == DS_SUCCESS) {
1663 const char* currentPosition;
1664 const char* dataStart;
1665 const char* dataEnd;
1666 size_t versionStringLength;
1668 contentEnd = contentStart + contentSize;
1669 currentPosition = contentStart;
1672 /* parse the version string */
1673 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1674 if (dataStart == NULL) {
1675 status = DS_PROFILE_FILE_ERROR;
1678 dataStart += strlen(DS_TAG_VERSION);
1680 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1681 if (dataEnd==NULL) {
1682 status = DS_PROFILE_FILE_ERROR;
1686 versionStringLength = strlen(profile->version);
1687 if (versionStringLength!=(dataEnd-dataStart)
1688 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1689 /* version mismatch */
1690 status = DS_PROFILE_FILE_ERROR;
1693 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1695 /* parse the device information */
1699 const char* deviceTypeStart;
1700 const char* deviceTypeEnd;
1701 ds_device_type deviceType;
1703 const char* deviceNameStart;
1704 const char* deviceNameEnd;
1706 const char* deviceScoreStart;
1707 const char* deviceScoreEnd;
1709 const char* deviceDriverStart;
1710 const char* deviceDriverEnd;
1712 const char* tmpStart;
1716 cl_uint maxClockFrequency;
1717 cl_uint maxComputeUnits;
1719 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1720 if (dataStart==NULL) {
1721 /* nothing useful remain, quit...*/
1724 dataStart+=strlen(DS_TAG_DEVICE);
1725 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1726 if (dataEnd==NULL) {
1727 status = DS_PROFILE_FILE_ERROR;
1731 /* parse the device type */
1732 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1733 if (deviceTypeStart==NULL) {
1734 status = DS_PROFILE_FILE_ERROR;
1737 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1738 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1739 if (deviceTypeEnd==NULL) {
1740 status = DS_PROFILE_FILE_ERROR;
1743 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1746 /* parse the device name */
1747 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1749 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1750 if (deviceNameStart==NULL) {
1751 status = DS_PROFILE_FILE_ERROR;
1754 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1755 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1756 if (deviceNameEnd==NULL) {
1757 status = DS_PROFILE_FILE_ERROR;
1762 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1763 if (deviceDriverStart==NULL) {
1764 status = DS_PROFILE_FILE_ERROR;
1767 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1768 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1769 if (deviceDriverEnd ==NULL) {
1770 status = DS_PROFILE_FILE_ERROR;
1775 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1776 if (tmpStart==NULL) {
1777 status = DS_PROFILE_FILE_ERROR;
1780 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1781 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1782 if (tmpEnd ==NULL) {
1783 status = DS_PROFILE_FILE_ERROR;
1786 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1787 tmp[tmpEnd-tmpStart] = '\0';
1788 maxComputeUnits = atoi(tmp);
1791 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1792 if (tmpStart==NULL) {
1793 status = DS_PROFILE_FILE_ERROR;
1796 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1797 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1798 if (tmpEnd ==NULL) {
1799 status = DS_PROFILE_FILE_ERROR;
1802 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1803 tmp[tmpEnd-tmpStart] = '\0';
1804 maxClockFrequency = atoi(tmp);
1807 /* check if this device is on the system */
1808 for (i = 0; i < profile->numDevices; i++) {
1809 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1810 size_t actualDeviceNameLength;
1811 size_t driverVersionLength;
1813 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1814 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1815 if (actualDeviceNameLength == (deviceNameEnd - deviceNameStart)
1816 && driverVersionLength == (deviceDriverEnd - deviceDriverStart)
1817 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1818 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1819 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1820 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1822 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1823 if (deviceNameStart==NULL) {
1824 status = DS_PROFILE_FILE_ERROR;
1827 deviceScoreStart+=strlen(DS_TAG_SCORE);
1828 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1829 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1830 if (status != DS_SUCCESS) {
1838 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1839 for (i = 0; i < profile->numDevices; i++) {
1840 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1841 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1842 if (deviceScoreStart==NULL) {
1843 status = DS_PROFILE_FILE_ERROR;
1846 deviceScoreStart+=strlen(DS_TAG_SCORE);
1847 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1848 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1849 if (status != DS_SUCCESS) {
1856 /* skip over the current one to find the next device */
1857 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1861 if (contentStart!=NULL) free(contentStart);
1865 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1867 if (profile == NULL || num==NULL)
1868 return DS_MEMORY_ERROR;
1870 for (i = 0; i < profile->numDevices; i++) {
1871 if (profile->devices[i].score == NULL) {
1879 End of the OpenCL device selection infrastructure
1884 typedef struct _AccelerateTimer {
1890 static void startAccelerateTimer(AccelerateTimer* timer) {
1892 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
1897 gettimeofday(&s, 0);
1898 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1902 static void stopAccelerateTimer(AccelerateTimer* timer) {
1905 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
1908 gettimeofday(&s, 0);
1909 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1913 timer->_clocks += n;
1916 static void resetAccelerateTimer(AccelerateTimer* timer) {
1922 static void initAccelerateTimer(AccelerateTimer* timer) {
1924 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1926 timer->_freq = (long long)1.0E3;
1928 resetAccelerateTimer(timer);
1931 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1934 typedef double AccelerateScoreType;
1936 static ds_status AcceleratePerfEvaluator(ds_device* device, void* data) {
1938 ds_status status = DS_SUCCESS;
1939 MagickCLEnv clEnv = NULL;
1940 MagickCLEnv oldClEnv = NULL;
1941 ExceptionInfo* exception = NULL;
1942 AccelerateTimer timer;
1944 if (device == NULL) {
1945 status = DS_PERF_EVALUATOR_ERROR;
1949 clEnv = AcquireMagickOpenCLEnv();
1950 exception = AcquireExceptionInfo();
1952 if (device->type == DS_DEVICE_NATIVE_CPU) {
1954 MagickBooleanType flag = MagickTrue;
1955 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
1956 , sizeof(MagickBooleanType), &flag, exception);
1958 else if (device->type == DS_DEVICE_OPENCL_DEVICE) {
1960 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
1961 , sizeof(cl_device_id), &device->oclDeviceID,exception);
1964 status = DS_PERF_EVALUATOR_ERROR;
1967 InitOpenCLEnvInternal(clEnv, exception);
1968 oldClEnv = defaultCLEnv;
1969 defaultCLEnv = clEnv;
1971 /* microbenchmark */
1973 #define ACCELERATE_PERF_DIMEN "2048x1536"
1977 ImageInfo* imageInfo;
1980 imageInfo = AcquireImageInfo();
1981 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
1982 CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
1983 inputImage = ReadImage(imageInfo,exception);
1985 initAccelerateTimer(&timer);
1987 for (i = 0; i <=NUM_ITER; i++) {
1990 Image* unsharpedImage;
1991 Image* resizedImage;
1994 startAccelerateTimer(&timer);
1996 #ifdef MAGICKCORE_CLPERFMARKER
1997 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2000 bluredImage = BlurImage(inputImage, 10.0f, 3.5f, exception);
2001 unsharpedImage = UnsharpMaskImage(bluredImage, 2.0f,2.0f,50.0f,10.0f,exception);
2002 resizedImage = ResizeImage(unsharpedImage,640,480,LanczosFilter,1.0,exception);
2004 #ifdef MAGICKCORE_CLPERFMARKER
2005 clEndPerfMarkerAMD();
2009 stopAccelerateTimer(&timer);
2011 if (bluredImage) DestroyImage(bluredImage);
2012 if (unsharpedImage) DestroyImage(unsharpedImage);
2013 if (resizedImage) DestroyImage(resizedImage);
2015 DestroyImage(inputImage);
2017 /* end of microbenchmark */
2019 if (device->score == NULL) {
2020 device->score = malloc(sizeof(AccelerateScoreType));
2022 *(AccelerateScoreType*)device->score = readAccelerateTimer(&timer);
2026 RelinquishMagickOpenCLEnv(clEnv);
2028 defaultCLEnv = oldClEnv;
2034 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2037 /* generate a string from the score */
2038 char* s = (char*)malloc(sizeof(char)*256);
2039 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2040 *serializedScore = (void*)s;
2041 *serializedScoreSize = strlen(s);
2045 return DS_SCORE_SERIALIZER_ERROR;
2049 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2051 /* convert the string back to an int */
2052 char* s = (char*)malloc(serializedScoreSize+1);
2053 memcpy(s, serializedScore, serializedScoreSize);
2054 s[serializedScoreSize] = (char)'\0';
2055 device->score = malloc(sizeof(AccelerateScoreType));
2056 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2061 return DS_SCORE_DESERIALIZER_ERROR;
2065 ds_status AccelerateScoreRelease(void* score) {
2073 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2074 #define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2075 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2077 MagickBooleanType mStatus = MagickFalse;
2079 ds_profile* profile;
2080 unsigned int numDeviceProfiled = 0;
2082 unsigned int bestDeviceIndex;
2083 AccelerateScoreType bestScore;
2084 char path[MaxTextExtent];
2087 LockDefaultOpenCLEnv();
2089 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2090 if (status!=DS_SUCCESS) {
2091 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2095 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2096 ,GetOpenCLCachedFilesDirectory()
2097 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2099 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2100 status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2101 if (status!=DS_SUCCESS) {
2102 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2105 if (numDeviceProfiled > 0) {
2106 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2107 if (status!=DS_SUCCESS) {
2108 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2112 /* pick the best device */
2113 bestDeviceIndex = 0;
2114 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2115 for (i = 1; i < profile->numDevices; i++) {
2116 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2117 if (score < bestScore) {
2118 bestDeviceIndex = i;
2123 /* set up clEnv with the best device */
2124 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2126 MagickBooleanType flag = MagickTrue;
2127 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2128 , sizeof(MagickBooleanType), &flag, exception);
2130 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2132 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2133 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2136 status = DS_PERF_EVALUATOR_ERROR;
2139 InitOpenCLEnvInternal(clEnv, exception);
2141 status = releaseDSProfile(profile, AccelerateScoreRelease);
2142 if (status!=DS_SUCCESS) {
2143 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2145 mStatus = MagickTrue;
2149 UnlockDefaultOpenCLEnv();
2155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2159 + I n i t I m a g e M a g i c k O p e n C L %
2163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165 % InitImageMagickOpenCL() provides a simplified interface to initialize
2166 % the OpenCL environtment in ImageMagick
2168 % The format of the InitImageMagickOpenCL() method is:
2170 % MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2171 % void* userSelectedDevice,
2172 % void* selectedDevice)
2174 % A description of each parameter follows:
2176 % o mode: OpenCL mode in ImageMagick, could be off,auto,user
2178 % o userSelectedDevice: when in user mode, a pointer to the selected
2181 % o selectedDevice: a pointer to cl_device_id where the selected
2182 % cl_device_id by ImageMagick could be returned
2184 % o exception: exception
2187 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2188 void* userSelectedDevice,
2189 void* selectedDevice,
2190 ExceptionInfo* exception) {
2192 MagickBooleanType status = MagickTrue;
2193 MagickCLEnv clEnv = NULL;
2194 MagickBooleanType flag;
2196 exception = AcquireExceptionInfo();
2197 clEnv = GetDefaultOpenCLEnv();
2201 case MAGICK_OPENCL_OFF:
2203 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2204 , sizeof(MagickBooleanType), &flag, exception);
2205 status = InitOpenCLEnv(clEnv, exception);
2208 *(cl_device_id*)selectedDevice = NULL;
2211 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2213 if (userSelectedDevice == NULL)
2217 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2218 , sizeof(MagickBooleanType), &flag, exception);
2220 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2221 , sizeof(cl_device_id), userSelectedDevice,exception);
2223 status = InitOpenCLEnv(clEnv, exception);
2224 if (selectedDevice) {
2225 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2226 , sizeof(cl_device_id), selectedDevice, exception);
2230 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2233 cl_device_id d = NULL;
2235 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2236 , sizeof(MagickBooleanType), &flag, exception);
2237 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2238 , sizeof(cl_device_id), &d,exception);
2239 status = InitOpenCLEnv(clEnv, exception);
2240 if (selectedDevice) {
2241 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2242 , sizeof(cl_device_id), selectedDevice, exception);
2254 struct _MagickCLEnv {
2255 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2258 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2263 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2264 MagickCLEnv magick_unused(clEnv))
2266 magick_unreferenced(clEnv);
2272 * Return the OpenCL environment
2274 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2275 ExceptionInfo *magick_unused(exception))
2277 magick_unreferenced(exception);
2279 return (MagickCLEnv) NULL;
2282 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2283 MagickCLEnv magick_unused(clEnv))
2285 magick_unreferenced(clEnv);
2287 return (MagickCLEnv) NULL;
2290 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2291 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2292 size_t magick_unused(dataSize),void *magick_unused(data),
2293 ExceptionInfo *magick_unused(exception))
2295 magick_unreferenced(clEnv);
2296 magick_unreferenced(param);
2297 magick_unreferenced(dataSize);
2298 magick_unreferenced(data);
2299 magick_unreferenced(exception);
2304 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2305 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2306 size_t magick_unused(dataSize),void *magick_unused(data),
2307 ExceptionInfo *magick_unused(exception))
2309 magick_unreferenced(clEnv);
2310 magick_unreferenced(param);
2311 magick_unreferenced(dataSize);
2312 magick_unreferenced(data);
2313 magick_unreferenced(exception);
2318 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2319 ExceptionInfo *magick_unused(exception))
2321 magick_unreferenced(clEnv);
2322 magick_unreferenced(exception);
2327 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2328 MagickCLEnv magick_unused(clEnv))
2330 magick_unreferenced(clEnv);
2332 return (cl_command_queue) NULL;
2335 MagickExport MagickBooleanType RelinquishCommandQueue(
2336 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2338 magick_unreferenced(clEnv);
2339 magick_unreferenced(queue);
2344 MagickExport cl_kernel AcquireOpenCLKernel(
2345 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2346 const char *magick_unused(kernelName))
2348 magick_unreferenced(clEnv);
2349 magick_unreferenced(program);
2350 magick_unreferenced(kernelName);
2352 return (cl_kernel)NULL;
2355 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2356 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2358 magick_unreferenced(clEnv);
2359 magick_unreferenced(kernel);
2364 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2365 MagickCLEnv magick_unused(clEnv))
2367 magick_unreferenced(clEnv);
2372 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2373 void* userSelectedDevice,
2374 void* selectedDevice,
2375 ExceptionInfo* exception)
2377 magick_unreferenced(mode);
2378 magick_unreferenced(userSelectedDevice);
2379 magick_unreferenced(selectedDevice);
2380 magick_unreferenced(exception);
2384 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2386 char* openclCachedFilesDirectory;
2387 SemaphoreInfo* openclCachedFilesDirectoryLock;
2390 const char* GetOpenCLCachedFilesDirectory() {
2391 if (openclCachedFilesDirectory == NULL) {
2392 if (openclCachedFilesDirectoryLock == NULL)
2394 AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2396 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2397 if (openclCachedFilesDirectory == NULL) {
2398 char path[MaxTextExtent];
2401 struct stat attributes;
2402 MagickBooleanType status;
2404 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2405 home=GetEnvironmentValue("LOCALAPPDATA");
2406 if (home == (char *) NULL)
2407 home=GetEnvironmentValue("APPDATA");
2408 if (home == (char *) NULL)
2409 home=GetEnvironmentValue("USERPROFILE");
2411 home=GetEnvironmentValue("HOME");
2413 if (home != (char *) NULL)
2416 Search $HOME/.magick.
2418 (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2419 DirectorySeparator);
2420 home=DestroyString(home);
2421 temp = (char*)AcquireMagickMemory(strlen(path)+1);
2422 CopyMagickString(temp,path,strlen(path)+1);
2423 status=GetPathAttributes(path,&attributes);
2424 if (status == MagickFalse) {
2425 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2432 openclCachedFilesDirectory = temp;
2434 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
2436 return openclCachedFilesDirectory;
2440 /* create a loggin function */
2442 void OpenCLLog(const char* message) {
2444 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2448 char path[MaxTextExtent];
2450 /* dump the source into a file */
2451 (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2452 ,GetOpenCLCachedFilesDirectory()
2453 ,DirectorySeparator,OPENCL_LOG_FILE);
2456 log = fopen(path, "ab");
2457 fwrite(message, sizeof(char), strlen(message), log);
2458 fwrite("\n", sizeof(char), 1, log);