]> granicus.if.org Git - imagemagick/blob - MagickCore/opencl.c
Fixed bug in automatic selection of OpenCL device.
[imagemagick] / MagickCore / opencl.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                   OOO   PPPP   EEEEE  N   N   CCCC  L                       %
7 %                  O   O  P   P  E      NN  N  C      L                       %
8 %                  O   O  PPPP   EEE    N N N  C      L                       %
9 %                  O   O  P      E      N  NN  C      L                       %
10 %                   OOO   P      EEEEE  N   N   CCCC  LLLLL                   %
11 %                                                                             %
12 %                                                                             %
13 %                         MagickCore OpenCL Methods                           %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 March 2000                                  %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
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.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39  
40 /*
41 Include declarations.
42 */
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"
81
82 #ifdef MAGICKCORE_CLPERFMARKER
83 #include "CLPerfMarker.h"
84 #endif
85
86
87 #if defined(MAGICKCORE_OPENCL_SUPPORT)
88
89 struct _MagickCLEnv {
90   MagickBooleanType OpenCLInitialized;  /* whether OpenCL environment is initialized. */
91   MagickBooleanType OpenCLDisabled;     /* whether if OpenCL has been explicitely disabled. */
92
93   /*OpenCL objects */
94   cl_platform_id platform;
95   cl_device_type deviceType;
96   cl_device_id device;
97   cl_context context;
98
99   cl_program programs[MAGICK_OPENCL_NUM_PROGRAMS]; /* one program object maps one kernel source file */
100
101   SemaphoreInfo* lock;
102 };
103
104
105 /*
106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107 %                                                                             %
108 %                                                                             %
109 %                                                                             %
110 +   A c q u i r e M a g i c k O p e n C L E n v                               %
111 %                                                                             %
112 %                                                                             %
113 %                                                                             %
114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115 %
116 % AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure 
117 %
118 */
119
120 MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
121 {
122   MagickCLEnv clEnv;
123   clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
124   if (clEnv != NULL)
125   {
126     memset(clEnv, 0, sizeof(struct _MagickCLEnv));
127     AcquireSemaphoreInfo(&clEnv->lock);
128   }
129   return clEnv;
130 }
131
132
133 /*
134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135 %                                                                             %
136 %                                                                             %
137 %                                                                             %
138 +   R e l i n q u i s h M a g i c k O p e n C L E n v                         %
139 %                                                                             %
140 %                                                                             %
141 %                                                                             %
142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143 %
144 %  RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
145 %
146 %  The format of the RelinquishMagickOpenCLEnv method is:
147 %
148 %      MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
149 %
150 %  A description of each parameter follows:
151 %
152 %    o clEnv: MagickCLEnv structure to destroy
153 %
154 */
155
156 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
157 {
158   if (clEnv != (MagickCLEnv)NULL)
159   {
160     RelinquishSemaphoreInfo(clEnv->lock);
161     RelinquishMagickMemory(clEnv);
162     return MagickTrue;
163   }
164   return MagickFalse;
165 }
166
167
168 /*
169 * Default OpenCL environment
170 */
171 MagickCLEnv defaultCLEnv;
172 SemaphoreInfo* defaultCLEnvLock;
173
174
175 /*
176 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177 %                                                                             %
178 %                                                                             %
179 %                                                                             %
180 +   G e t D e f a u l t O p e n C L E n v                                     %
181 %                                                                             %
182 %                                                                             %
183 %                                                                             %
184 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
185 %
186 %  GetDefaultOpenCLEnv() returns the default OpenCL env
187 %
188 %  The format of the GetDefaultOpenCLEnv method is:
189 %
190 %      MagickCLEnv GetDefaultOpenCLEnv()
191 %
192 %  A description of each parameter follows:
193 %
194 %    o exception: return any errors or warnings.
195 %
196 */
197
198 MagickExport MagickCLEnv GetDefaultOpenCLEnv()
199
200   if (defaultCLEnv == NULL)
201   {
202     if (defaultCLEnvLock == NULL)
203     {
204       AcquireSemaphoreInfo(&defaultCLEnvLock);
205     }
206     LockSemaphoreInfo(defaultCLEnvLock);
207     defaultCLEnv = AcquireMagickOpenCLEnv();
208     UnlockSemaphoreInfo(defaultCLEnvLock); 
209   }
210   return defaultCLEnv; 
211 }
212
213 static void LockDefaultOpenCLEnv() {
214   if (defaultCLEnvLock == NULL)
215   {
216     AcquireSemaphoreInfo(&defaultCLEnvLock);
217   }
218   LockSemaphoreInfo(defaultCLEnvLock);
219 }
220
221 static void UnlockDefaultOpenCLEnv() {
222   if (defaultCLEnvLock == NULL)
223   {
224     AcquireSemaphoreInfo(&defaultCLEnvLock);
225   }
226   else
227     UnlockSemaphoreInfo(defaultCLEnvLock);
228 }
229
230
231 /*
232 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233 %                                                                             %
234 %                                                                             %
235 %                                                                             %
236 +   S e t D e f a u l t O p e n C L E n v                                     %
237 %                                                                             %
238 %                                                                             %
239 %                                                                             %
240 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241 %
242 %  SetDefaultOpenCLEnv() sets the new OpenCL environment as default 
243 %  and returns the old OpenCL environment
244 %  
245 %  The format of the SetDefaultOpenCLEnv() method is:
246 %
247 %      MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
248 %
249 %  A description of each parameter follows:
250 %
251 %    o clEnv: the new default OpenCL environment.
252 %
253 */
254 MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)     
255 {
256   MagickCLEnv oldEnv;
257   LockDefaultOpenCLEnv();
258   oldEnv = defaultCLEnv;
259   defaultCLEnv = clEnv;
260   UnlockDefaultOpenCLEnv();
261   return oldEnv;
262
263
264
265
266 /*
267 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268 %                                                                             %
269 %                                                                             %
270 %                                                                             %
271 +   S e t M a g i c k O p e n C L E n v P a r a m                             %
272 %                                                                             %
273 %                                                                             %
274 %                                                                             %
275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
276 %
277 %  SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment  
278 %  
279 %  The format of the SetMagickOpenCLEnvParam() method is:
280 %
281 %      MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, 
282 %        MagickOpenCLEnvParam param, size_t dataSize, void* data, 
283 %        ExceptionInfo* exception)
284 %
285 %  A description of each parameter follows:
286 %
287 %    o clEnv: the OpenCL environment.
288 %    
289 %    o param: the parameter to be set.
290 %
291 %    o dataSize: the data size of the parameter value.
292 %
293 %    o data:  the pointer to the new parameter value
294 %
295 %    o exception: return any errors or warnings
296 %
297 */
298
299 static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
300                                           , size_t dataSize, void* data, ExceptionInfo* exception)
301 {
302   MagickBooleanType status = MagickFalse;
303
304   if (clEnv == NULL
305     || data == NULL)
306     goto cleanup;
307
308   switch(param)
309   {
310   case MAGICK_OPENCL_ENV_PARAM_DEVICE:
311     if (dataSize != sizeof(clEnv->device))
312       goto cleanup;
313     clEnv->device = *((cl_device_id*)data);
314     clEnv->OpenCLInitialized = MagickFalse;
315     status = MagickTrue;
316     break;
317
318   case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
319     if (dataSize != sizeof(clEnv->OpenCLDisabled))
320       goto cleanup;
321     clEnv->OpenCLDisabled =  *((MagickBooleanType*)data);
322     clEnv->OpenCLInitialized = MagickFalse;
323     status = MagickTrue;
324     break;
325
326   case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
327     (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
328     break;
329
330   default:
331     goto cleanup;
332   };
333
334 cleanup:
335   return status;
336 }
337
338 MagickExport
339   MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
340                                           , size_t dataSize, void* data, ExceptionInfo* exception) {
341   MagickBooleanType status = MagickFalse;
342   if (clEnv!=NULL) {
343     LockSemaphoreInfo(clEnv->lock);
344     status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
345     UnlockSemaphoreInfo(clEnv->lock);
346   }
347   return status;
348 }
349
350 /*
351 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 %                                                                             %
353 %                                                                             %
354 %                                                                             %
355 +   G e t M a g i c k O p e n C L E n v P a r a m                             %
356 %                                                                             %
357 %                                                                             %
358 %                                                                             %
359 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360 %
361 %  GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment  
362 %  
363 %  The format of the GetMagickOpenCLEnvParam() method is:
364 %
365 %      MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, 
366 %        MagickOpenCLEnvParam param, size_t dataSize, void* data, 
367 %        ExceptionInfo* exception)
368 %
369 %  A description of each parameter follows:
370 %
371 %    o clEnv: the OpenCL environment.
372 %    
373 %    o param: the parameter to be returned.
374 %
375 %    o dataSize: the data size of the parameter value.
376 %
377 %    o data:  the location where the returned parameter value will be stored 
378 %
379 %    o exception: return any errors or warnings
380 %
381 */
382
383 MagickExport
384   MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
385                                           , size_t dataSize, void* data, ExceptionInfo* exception)
386 {
387   MagickBooleanType status;
388   status = MagickFalse;
389
390   if (clEnv == NULL
391     || data == NULL)
392     goto cleanup;
393
394   switch(param)
395   {
396   case MAGICK_OPENCL_ENV_PARAM_DEVICE:
397     if (dataSize != sizeof(cl_device_id))
398       goto cleanup;
399     *((cl_device_id*)data) = clEnv->device;
400     status = MagickTrue;
401     break;
402
403   case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
404     if (dataSize != sizeof(clEnv->OpenCLDisabled))
405       goto cleanup;
406     *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
407     status = MagickTrue;
408     break;
409
410   case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
411     if (dataSize != sizeof(clEnv->OpenCLDisabled))
412       goto cleanup;
413     *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
414     status = MagickTrue;
415     break;
416
417   default:
418     goto cleanup;
419   };
420
421 cleanup:
422   return status;
423 }
424
425
426 /*
427 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 %                                                                             %
429 %                                                                             %
430 %                                                                             %
431 +   G e t O p e n C L C o n t e x t                                           %
432 %                                                                             %
433 %                                                                             %
434 %                                                                             %
435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436 %
437 %  GetOpenCLContext() returns the OpenCL context  
438 %  
439 %  The format of the GetOpenCLContext() method is:
440 %
441 %      cl_context GetOpenCLContext(MagickCLEnv clEnv) 
442 %
443 %  A description of each parameter follows:
444 %
445 %    o clEnv: OpenCL environment
446 %
447 */
448
449 MagickExport
450 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
451   if (clEnv == NULL)
452     return NULL;
453   else
454     return clEnv->context;
455 }
456
457 static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
458 {
459   char* name;
460   char* ptr;
461   char path[MaxTextExtent];
462   char deviceName[MaxTextExtent];
463   const char* prefix = "magick_opencl";
464   clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
465   ptr=deviceName;
466   /* strip out illegal characters for file names */
467   while (*ptr != '\0')
468   {
469     if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*' 
470         || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
471     {
472       *ptr = '_';
473     }
474     ptr++;
475   }
476   (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x.bin"
477          ,GetOpenCLCachedFilesDirectory()
478          ,DirectorySeparator,prefix,deviceName, (unsigned int)prog, signature);
479   name = (char*)AcquireMagickMemory(strlen(path)+1);
480   CopyMagickString(name,path,strlen(path)+1);
481   return name;
482 }
483
484 static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
485 {
486   MagickBooleanType saveSuccessful;
487   cl_int clStatus;
488   size_t binaryProgramSize;
489   unsigned char* binaryProgram;
490   char* binaryFileName;
491   FILE* fileHandle;
492
493 #ifdef MAGICKCORE_CLPERFMARKER
494   clBeginPerfMarkerAMD(__FUNCTION__,"");
495 #endif
496
497   binaryProgram = NULL;
498   binaryFileName = NULL;
499   fileHandle = NULL;
500   saveSuccessful = MagickFalse;
501
502   clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
503   if (clStatus != CL_SUCCESS)
504   {
505     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
506     goto cleanup;
507   }
508
509   binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
510   clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
511   if (clStatus != CL_SUCCESS)
512   {
513     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
514     goto cleanup;
515   }
516
517   binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
518   fileHandle = fopen(binaryFileName, "wb");
519   if (fileHandle != NULL)
520   {
521     fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
522     saveSuccessful = MagickTrue;
523   }
524   else
525   {
526     (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
527       "Saving binary kernel failed.", "'%s'", ".");
528   }
529
530 cleanup:
531   if (fileHandle != NULL)
532     fclose(fileHandle);
533   if (binaryProgram != NULL)
534     RelinquishMagickMemory(binaryProgram);
535   if (binaryFileName != NULL)
536     free(binaryFileName);
537
538 #ifdef MAGICKCORE_CLPERFMARKER
539   clEndPerfMarkerAMD();
540 #endif
541
542   return saveSuccessful;
543 }
544
545 static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
546 {
547   MagickBooleanType loadSuccessful;
548   unsigned char* binaryProgram;
549   char* binaryFileName;
550   FILE* fileHandle;
551
552 #ifdef MAGICKCORE_CLPERFMARKER
553   clBeginPerfMarkerAMD(__FUNCTION__,"");
554 #endif
555
556   binaryProgram = NULL;
557   binaryFileName = NULL;
558   fileHandle = NULL;
559   loadSuccessful = MagickFalse;
560
561   binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
562   fileHandle = fopen(binaryFileName, "rb");
563   if (fileHandle != NULL)
564   {
565     int b_error;
566     size_t length;
567     cl_int clStatus;
568     cl_int clBinaryStatus;
569
570     b_error = 0 ;
571     length = 0;
572     b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
573     b_error |= ( length = ftell( fileHandle ) ) <= 0;
574     b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
575     if( b_error )
576       goto cleanup;
577
578     binaryProgram = (unsigned char*)AcquireMagickMemory(length);
579     if (binaryProgram == NULL)
580       goto cleanup;
581
582     memset(binaryProgram, 0, length);
583     b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
584
585     clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
586     if (clStatus != CL_SUCCESS
587         || clBinaryStatus != CL_SUCCESS)
588       goto cleanup;
589
590     loadSuccessful = MagickTrue;
591   }
592
593 cleanup:
594   if (fileHandle != NULL)
595     fclose(fileHandle);
596   if (binaryFileName != NULL)
597     free(binaryFileName);
598   if (binaryProgram != NULL)
599     RelinquishMagickMemory(binaryProgram);
600
601 #ifdef MAGICKCORE_CLPERFMARKER
602   clEndPerfMarkerAMD();
603 #endif
604
605   return loadSuccessful;
606 }
607
608 static unsigned int stringSignature(const char* string)
609 {
610   unsigned int stringLength;
611   unsigned int n,i,j;
612   unsigned int signature;
613   union
614   {
615     const char* s;
616     const unsigned int* u;
617   }p;
618
619 #ifdef MAGICKCORE_CLPERFMARKER
620   clBeginPerfMarkerAMD(__FUNCTION__,"");
621 #endif
622
623   stringLength = strlen(string);
624   signature = stringLength;
625   n = stringLength/sizeof(unsigned int);
626   p.s = string;
627   for (i = 0; i < n; i++)
628   {
629     signature^=p.u[i];
630   }
631   if (n * sizeof(unsigned int) != stringLength)
632   {
633     char padded[4];
634     j = n * sizeof(unsigned int);
635     for (i = 0; i < 4; i++,j++)
636     {
637       if (j < stringLength)
638         padded[i] = p.s[j];
639       else
640         padded[i] = 0;
641     }
642     p.s = padded;
643     signature^=p.u[0];
644   }
645
646 #ifdef MAGICKCORE_CLPERFMARKER
647   clEndPerfMarkerAMD();
648 #endif
649
650   return signature;
651 }
652
653 /* OpenCL kernels for accelerate.c */
654 extern const char *accelerateKernels, *accelerateKernels2;
655
656 static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception) 
657 {
658   MagickBooleanType status = MagickFalse;
659   cl_int clStatus;
660   unsigned int i;
661   char* accelerateKernelsBuffer = NULL;
662
663   /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
664   const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS]; 
665
666   char options[MaxTextExtent];
667   unsigned int optionsSignature;
668
669 #ifdef MAGICKCORE_CLPERFMARKER
670   clBeginPerfMarkerAMD(__FUNCTION__,"");
671 #endif
672
673   /* Get additional options */
674   (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
675     (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
676
677   /*
678   if (getenv("MAGICK_OCL_DEF"))
679   {
680     strcat(options," ");
681     strcat(options,getenv("MAGICK_OCL_DEF"));
682   }
683   */
684
685   /*
686   if (getenv("MAGICK_OCL_BUILD"))
687     printf("options: %s\n", options);
688   */
689
690   optionsSignature = stringSignature(options);
691
692   /* get all the OpenCL program strings here */
693   accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
694   sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
695   MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
696
697   for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++) 
698   {
699     MagickBooleanType loadSuccessful = MagickFalse;
700     unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
701
702     /* try to load the binary first */
703     if (!getenv("MAGICK_OCL_REC"))
704       loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
705
706     if (loadSuccessful == MagickFalse)
707     {
708       /* Binary CL program unavailable, compile the program from source */
709       size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
710       clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
711       if (clStatus!=CL_SUCCESS)
712       {
713         (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
714           "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
715
716         goto cleanup;
717       }
718     }
719
720     clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
721     if (clStatus!=CL_SUCCESS)
722     {
723       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
724         "clBuildProgram failed.", "(%d)", (int)clStatus);
725
726       if (loadSuccessful == MagickFalse)
727       {
728         char path[MaxTextExtent];
729         FILE* fileHandle;
730
731         /*  dump the source into a file */
732         (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
733          ,GetOpenCLCachedFilesDirectory()
734          ,DirectorySeparator,"magick_badcl.cl");
735         fileHandle = fopen(path, "wb"); 
736         if (fileHandle != NULL)
737         {
738           fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
739           fclose(fileHandle);
740         }
741
742         /* dump the build log */
743         {
744           char* log;
745           size_t logSize;
746           clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
747           log = (char*)AcquireMagickMemory(logSize);
748           clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
749
750           (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
751            ,GetOpenCLCachedFilesDirectory()
752            ,DirectorySeparator,"magick_badcl_build.log");
753           fileHandle = fopen(path, "wb");       
754           if (fileHandle != NULL)
755           {
756             const char* buildOptionsTitle = "build options: ";
757             fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
758             fwrite(options, sizeof(char), strlen(options), fileHandle);
759             fwrite("\n",sizeof(char), 1, fileHandle);
760             fwrite(log, sizeof(char), logSize, fileHandle);
761             fclose(fileHandle);
762           }
763           RelinquishMagickMemory(log);
764         }
765       }
766       goto cleanup;
767     }
768
769     if (loadSuccessful == MagickFalse)
770     {
771       /* Save the binary to a file to avoid re-compilation of the kernels in the future */
772       saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
773     }
774
775   }
776   status = MagickTrue;
777
778 cleanup:
779
780   if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
781
782 #ifdef MAGICKCORE_CLPERFMARKER
783   clEndPerfMarkerAMD();
784 #endif
785
786   return status;
787 }
788
789 static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
790   int i,j;
791   cl_int status;
792   cl_uint numPlatforms = 0;
793   cl_platform_id *platforms = NULL;
794   char* MAGICK_OCL_DEVICE = NULL;
795   MagickBooleanType OpenCLAvailable = MagickFalse;
796
797 #ifdef MAGICKCORE_CLPERFMARKER
798   clBeginPerfMarkerAMD(__FUNCTION__,"");
799 #endif
800
801   /* check if there's an environment variable overriding the device selection */
802   MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
803   if (MAGICK_OCL_DEVICE != NULL)
804   {
805     if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
806     {
807       clEnv->deviceType = CL_DEVICE_TYPE_CPU;
808     }
809     else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
810     {
811       clEnv->deviceType = CL_DEVICE_TYPE_GPU;
812     }
813     else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
814     {
815       /* OpenCL disabled */
816       goto cleanup;
817     }
818   }
819   else if (clEnv->deviceType == 0) {
820     clEnv->deviceType = CL_DEVICE_TYPE_ALL;
821   }
822
823   if (clEnv->device != NULL)
824   {
825     status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
826     if (status != CL_SUCCESS) {
827       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
828           "Failed to get OpenCL platform from the selected device.", "(%d)", status);
829     }
830     goto cleanup;
831   }
832   else if (clEnv->platform != NULL)
833   {
834     numPlatforms = 1;
835     platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
836     if (platforms == (cl_platform_id *) NULL)
837     {
838       (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
839         "AcquireMagickMemory failed.",".");
840       goto cleanup;
841     }
842     platforms[0] = clEnv->platform;
843   }
844   else
845   {
846     clEnv->device = NULL;
847
848     /* Get the number of OpenCL platforms available */
849     status = clGetPlatformIDs(0, NULL, &numPlatforms);
850     if (status != CL_SUCCESS)
851     {
852       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning, 
853         "clGetplatformIDs failed.", "(%d)", status);
854       goto cleanup;
855     }
856
857     /* No OpenCL available, just leave */
858     if (numPlatforms == 0) {
859       goto cleanup;
860     }
861
862     platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
863     if (platforms == (cl_platform_id *) NULL)
864     {
865       (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
866         "AcquireMagickMemory failed.",".");
867       goto cleanup;
868     }
869
870     status = clGetPlatformIDs(numPlatforms, platforms, NULL);
871     if (status != CL_SUCCESS)
872     {
873       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
874         "clGetPlatformIDs failed.", "(%d)", status);
875       goto cleanup;
876     }
877   }
878
879   /* Device selection */
880   clEnv->device = NULL;
881   for (j = 0; j < 2; j++) 
882   {
883
884     cl_device_type deviceType;
885     if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
886     {
887       if (j == 0)
888         deviceType = CL_DEVICE_TYPE_GPU;
889       else
890         deviceType = CL_DEVICE_TYPE_CPU;
891     }
892     else if (j == 1)
893     {
894       break;
895     }
896     else
897       deviceType = clEnv->deviceType;
898
899     for (i = 0; i < numPlatforms; i++)
900     {
901       cl_uint numDevices;
902       status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
903       if (status != CL_SUCCESS)
904       {
905         (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
906           "clGetPlatformIDs failed.", "(%d)", status);
907         goto cleanup;
908       }
909       if (clEnv->device != NULL)
910       {
911         clEnv->platform = platforms[i];
912   goto cleanup;
913       }
914     }
915   }
916
917 cleanup:
918   if (platforms!=NULL)
919     RelinquishMagickMemory(platforms);
920
921   OpenCLAvailable = (clEnv->platform!=NULL
922           && clEnv->device!=NULL)?MagickTrue:MagickFalse;
923
924 #ifdef MAGICKCORE_CLPERFMARKER
925   clEndPerfMarkerAMD();
926 #endif
927
928   return OpenCLAvailable;
929 }
930
931 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
932   if (clEnv->OpenCLInitialized == MagickTrue
933     && clEnv->platform != NULL
934     && clEnv->device != NULL) {
935       clEnv->OpenCLDisabled = MagickFalse;
936       return MagickTrue;
937   }
938   clEnv->OpenCLDisabled = MagickTrue;
939   return MagickFalse;
940 }
941
942
943 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
944 /*
945 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
946 %                                                                             %
947 %                                                                             %
948 %                                                                             %
949 +   I n i t O p e n C L E n v                                                 %
950 %                                                                             %
951 %                                                                             %
952 %                                                                             %
953 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954 %
955 %  InitOpenCLEnv() initialize the OpenCL environment
956 %
957 %  The format of the RelinquishMagickOpenCLEnv method is:
958 %
959 %      MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
960 %
961 %  A description of each parameter follows:
962 %
963 %    o clEnv: OpenCL environment structure
964 %
965 %    o exception: return any errors or warnings.
966 %
967 */
968
969 MagickExport
970 MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
971   MagickBooleanType status = MagickTrue;
972   cl_int clStatus;
973   cl_context_properties cps[3];
974
975
976   clEnv->OpenCLInitialized = MagickTrue;
977   if (clEnv->OpenCLDisabled == MagickTrue)
978     goto cleanup;
979
980   clEnv->OpenCLDisabled = MagickTrue;
981   /* setup the OpenCL platform and device */
982   status = InitOpenCLPlatformDevice(clEnv, exception);
983   if (status == MagickFalse) {
984     /* No OpenCL device available */
985     goto cleanup;
986   }
987
988   /* create an OpenCL context */
989   cps[0] = CL_CONTEXT_PLATFORM;
990   cps[1] = (cl_context_properties)clEnv->platform;
991   cps[2] = 0;
992   clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
993   if (clStatus != CL_SUCCESS)
994   {
995     (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
996         "clCreateContext failed.", "(%d)", clStatus);
997     status = MagickFalse;
998     goto cleanup;
999   }
1000
1001   status = CompileOpenCLKernels(clEnv, exception);
1002   if (status == MagickFalse) {
1003    (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1004         "clCreateCommandQueue failed.", "(%d)", status);
1005
1006     status = MagickFalse;
1007     goto cleanup;
1008   }
1009
1010   status = EnableOpenCLInternal(clEnv);
1011 cleanup:
1012   return status;
1013 }
1014
1015
1016 MagickExport
1017 MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1018   MagickBooleanType status = MagickFalse;
1019
1020   if (clEnv == NULL)
1021     return MagickFalse;
1022
1023 #ifdef MAGICKCORE_CLPERFMARKER
1024   clBeginPerfMarkerAMD(__FUNCTION__,"");
1025 #endif
1026
1027   LockSemaphoreInfo(clEnv->lock);
1028   if (clEnv->OpenCLInitialized == MagickFalse) {
1029     if (clEnv->device==NULL
1030         && clEnv->OpenCLDisabled == MagickFalse)
1031       status = autoSelectDevice(clEnv, exception);
1032     else
1033       status = InitOpenCLEnvInternal(clEnv, exception);
1034   }
1035   UnlockSemaphoreInfo(clEnv->lock);
1036
1037 #ifdef MAGICKCORE_CLPERFMARKER
1038   clEndPerfMarkerAMD();
1039 #endif
1040   return status;
1041 }
1042
1043
1044 /*
1045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1046 %                                                                             %
1047 %                                                                             %
1048 %                                                                             %
1049 +   A c q u i r e O p e n C L C o m m a n d Q u e u e                         %
1050 %                                                                             %
1051 %                                                                             %
1052 %                                                                             %
1053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1054 %
1055 %  AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1056 %
1057 %  The format of the AcquireOpenCLCommandQueue method is:
1058 %
1059 %      cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1060 %
1061 %  A description of each parameter follows:
1062 %
1063 %    o clEnv: the OpenCL environment.
1064 %
1065 */
1066
1067 MagickExport
1068 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1069 {
1070   if (clEnv != NULL)
1071     return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
1072   else
1073     return NULL;
1074 }
1075
1076
1077 /*
1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079 %                                                                             %
1080 %                                                                             %
1081 %                                                                             %
1082 +   R e l i n q u i s h O p e n C L C o m m a n d Q u e u e                   %
1083 %                                                                             %
1084 %                                                                             %
1085 %                                                                             %
1086 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1087 %
1088 %  RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1089 %
1090 %  The format of the RelinquishOpenCLCommandQueue method is:
1091 %
1092 %      MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1093 %        cl_command_queue queue)
1094 %
1095 %  A description of each parameter follows:
1096 %
1097 %    o clEnv: the OpenCL environment.
1098 %
1099 %    o queue: the OpenCL queue to be released.
1100 %
1101 %
1102 */
1103 MagickExport
1104 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
1105 {
1106   if (clEnv != NULL)
1107   {
1108     return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
1109   }
1110   else
1111     return MagickFalse;
1112 }
1113
1114
1115
1116 /*
1117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1118 %                                                                             %
1119 %                                                                             %
1120 %                                                                             %
1121 +   A c q u i r e O p e n C L K e r n e l                                     %
1122 %                                                                             %
1123 %                                                                             %
1124 %                                                                             %
1125 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1126 %
1127 %  AcquireOpenCLKernel() acquires an OpenCL kernel
1128 %
1129 %  The format of the AcquireOpenCLKernel method is:
1130 %
1131 %      cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, 
1132 %        MagickOpenCLProgram program, const char* kernelName)
1133 %
1134 %  A description of each parameter follows:
1135 %
1136 %    o clEnv: the OpenCL environment.
1137 %
1138 %    o program: the OpenCL program module that the kernel belongs to.
1139 %
1140 %    o kernelName:  the name of the kernel
1141 %
1142 */
1143
1144 MagickExport
1145   cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1146 {
1147   cl_int clStatus;
1148   cl_kernel kernel = NULL;
1149   if (clEnv != NULL && kernelName!=NULL)
1150   {
1151     kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
1152   }
1153   return kernel;
1154 }
1155
1156
1157 /*
1158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1159 %                                                                             %
1160 %                                                                             %
1161 %                                                                             %
1162 +   R e l i n q u i s h O p e n C L K e r n e l                               %
1163 %                                                                             %
1164 %                                                                             %
1165 %                                                                             %
1166 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1167 %
1168 %  RelinquishOpenCLKernel() releases an OpenCL kernel
1169 %
1170 %  The format of the RelinquishOpenCLKernel method is:
1171 %
1172 %    MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1173 %      cl_kernel kernel)
1174 %
1175 %  A description of each parameter follows:
1176 %
1177 %    o clEnv: the OpenCL environment.
1178 %
1179 %    o kernel: the OpenCL kernel object to be released.
1180 %
1181 %
1182 */
1183
1184 MagickExport
1185   MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1186 {
1187   MagickBooleanType status = MagickFalse;
1188   if (clEnv != NULL && kernel != NULL)
1189   {
1190     status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
1191   }
1192   return status;
1193 }
1194
1195 /*
1196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1197 %                                                                             %
1198 %                                                                             %
1199 %                                                                             %
1200 +   G e t O p e n C L D e v i c e L o c a l M e m o r y S i z e               %
1201 %                                                                             %
1202 %                                                                             %
1203 %                                                                             %
1204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1205 %
1206 %  GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1207 %
1208 %  The format of the GetOpenCLDeviceLocalMemorySize method is:
1209 %
1210 %    unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1211 %
1212 %  A description of each parameter follows:
1213 %
1214 %    o clEnv: the OpenCL environment.
1215 %
1216 %
1217 */
1218
1219 MagickExport
1220  unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1221 {
1222   cl_ulong localMemorySize;
1223   clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
1224   return (unsigned long)localMemorySize;
1225 }
1226
1227 MagickExport
1228   unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1229 {
1230   cl_ulong maxMemAllocSize;
1231   clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
1232   return (unsigned long)maxMemAllocSize;
1233 }
1234
1235
1236 /*
1237  Beginning of the OpenCL device selection infrastructure
1238 */
1239
1240
1241 #define DS_DEVICE_NAME_LENGTH 256
1242
1243 typedef enum {
1244   DS_SUCCESS = 0
1245  ,DS_INVALID_PROFILE = 1000
1246  ,DS_MEMORY_ERROR
1247  ,DS_INVALID_PERF_EVALUATOR_TYPE
1248  ,DS_INVALID_PERF_EVALUATOR
1249  ,DS_PERF_EVALUATOR_ERROR
1250  ,DS_FILE_ERROR
1251  ,DS_UNKNOWN_DEVICE_TYPE
1252  ,DS_PROFILE_FILE_ERROR
1253  ,DS_SCORE_SERIALIZER_ERROR
1254  ,DS_SCORE_DESERIALIZER_ERROR
1255 } ds_status;
1256
1257 /* device type */
1258 typedef enum {
1259   DS_DEVICE_NATIVE_CPU = 0
1260  ,DS_DEVICE_OPENCL_DEVICE 
1261 } ds_device_type;
1262
1263
1264 typedef struct {
1265   ds_device_type  type;
1266   cl_device_id    oclDeviceID;
1267   char*           oclDeviceName;
1268   char*           oclDriverVersion;
1269   cl_uint         oclMaxClockFrequency;
1270   cl_uint         oclMaxComputeUnits;
1271   void*           score;            /* a pointer to the score data, the content/format is application defined */
1272 } ds_device;
1273
1274 typedef struct {
1275   unsigned int  numDevices;
1276   ds_device*    devices;
1277   const char*   version;
1278 } ds_profile;
1279
1280 /* deallocate memory used by score */
1281 typedef ds_status (*ds_score_release)(void* score);
1282
1283 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1284   ds_status status = DS_SUCCESS;
1285   if (device) {
1286     if (device->oclDeviceName)      free(device->oclDeviceName);
1287     if (device->oclDriverVersion)   free(device->oclDriverVersion);
1288     if (device->score)              status = sr(device->score);
1289   }
1290   return status;
1291 }
1292
1293 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1294   ds_status status = DS_SUCCESS;
1295   if (profile!=NULL) {
1296     if (profile->devices!=NULL && sr!=NULL) {
1297       unsigned int i;
1298       for (i = 0; i < profile->numDevices; i++) {
1299         status = releaseDeviceResource(profile->devices+i,sr);
1300         if (status != DS_SUCCESS)
1301           break;
1302       }
1303       free(profile->devices);
1304     }
1305     free(profile);
1306   }
1307   return status;
1308 }
1309
1310
1311 static ds_status initDSProfile(ds_profile** p, const char* version) {
1312   int numDevices = 0;
1313   cl_uint numPlatforms = 0;
1314   cl_platform_id* platforms = NULL;
1315   cl_device_id*   devices = NULL;
1316   ds_status status = DS_SUCCESS;
1317   ds_profile* profile = NULL;
1318   unsigned int next = 0;
1319   unsigned int i;
1320
1321   if (p == NULL)
1322     return DS_INVALID_PROFILE;
1323
1324   profile = (ds_profile*)malloc(sizeof(ds_profile));
1325   if (profile == NULL)
1326     return DS_MEMORY_ERROR;
1327   
1328   memset(profile, 0, sizeof(ds_profile));
1329
1330   clGetPlatformIDs(0, NULL, &numPlatforms);
1331   if (numPlatforms > 0) {
1332     platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1333     if (platforms == NULL) {
1334       status = DS_MEMORY_ERROR;
1335       goto cleanup;
1336     }
1337     clGetPlatformIDs(numPlatforms, platforms, NULL);
1338     for (i = 0; i < (unsigned int)numPlatforms; i++) {
1339       cl_uint num;
1340       clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
1341       numDevices+=num;
1342     }
1343   }
1344
1345   profile->numDevices = numDevices+1;     /* +1 to numDevices to include the native CPU */
1346
1347   profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));    
1348   if (profile->devices == NULL) {
1349     profile->numDevices = 0;
1350     status = DS_MEMORY_ERROR;
1351     goto cleanup;    
1352   }
1353   memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1354
1355   if (numDevices > 0) {
1356     devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1357     if (devices == NULL) {
1358       status = DS_MEMORY_ERROR;
1359       goto cleanup;
1360     }
1361     for (i = 0; i < (unsigned int)numPlatforms; i++) {
1362       cl_uint num;
1363
1364       int d;
1365       for (d = 0; d < 2; d++) { 
1366         unsigned int j;
1367         cl_device_type deviceType;
1368         switch(d) {
1369         case 0:
1370           deviceType = CL_DEVICE_TYPE_GPU;
1371           break;
1372         case 1:
1373           deviceType = CL_DEVICE_TYPE_CPU;
1374           break;
1375         default:
1376           continue;
1377           break;
1378         }
1379         clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num);
1380         for (j = 0; j < num; j++, next++) {
1381           char buffer[DS_DEVICE_NAME_LENGTH];
1382           size_t length;
1383
1384           profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1385           profile->devices[next].oclDeviceID = devices[j];
1386
1387           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
1388             , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1389           length = strlen(buffer);
1390           profile->devices[next].oclDeviceName = (char*)malloc(length+1);
1391           memcpy(profile->devices[next].oclDeviceName, buffer, length+1);
1392
1393           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
1394             , DS_DEVICE_NAME_LENGTH, &buffer, NULL);
1395           length = strlen(buffer);
1396           profile->devices[next].oclDriverVersion = (char*)malloc(length+1);
1397           memcpy(profile->devices[next].oclDriverVersion, buffer, length+1);
1398
1399           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1400             , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1401
1402           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1403             , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1404         }
1405       }
1406     }
1407   }
1408
1409   profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1410   profile->version = version;
1411
1412 cleanup:
1413   if (platforms)  free(platforms);
1414   if (devices)    free(devices);
1415   if (status == DS_SUCCESS) {
1416     *p = profile;
1417   }
1418   else {
1419     if (profile) {
1420       if (profile->devices)
1421         free(profile->devices);
1422       free(profile);
1423     }
1424   }
1425   return status;
1426 }
1427
1428 /* Pointer to a function that calculates the score of a device (ex: device->score) 
1429  update the data size of score. The encoding and the format of the score data 
1430  is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1431  */
1432 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1433
1434 typedef enum {
1435   DS_EVALUATE_ALL
1436   ,DS_EVALUATE_NEW_ONLY
1437 } ds_evaluation_type;
1438
1439 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1440                          ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1441   ds_status status = DS_SUCCESS;
1442   unsigned int i;
1443   unsigned int updates = 0;
1444
1445   if (profile == NULL) {
1446     return DS_INVALID_PROFILE;
1447   }
1448   if (evaluator == NULL) {
1449     return DS_INVALID_PERF_EVALUATOR;
1450   }
1451
1452   for (i = 0; i < profile->numDevices; i++) {
1453     ds_status evaluatorStatus;
1454     
1455     switch (type) {
1456     case DS_EVALUATE_NEW_ONLY:
1457       if (profile->devices[i].score != NULL)
1458         break;
1459       /*  else fall through */
1460     case DS_EVALUATE_ALL:
1461       evaluatorStatus = evaluator(profile->devices+i, evaluatorData);
1462       if (evaluatorStatus != DS_SUCCESS) {
1463         status = evaluatorStatus;
1464         return status;
1465       }
1466       updates++;
1467       break;
1468     default:
1469       return DS_INVALID_PERF_EVALUATOR_TYPE;
1470       break;
1471     };
1472   }
1473   if (numUpdates)
1474     *numUpdates = updates;
1475   return status;
1476 }
1477
1478
1479 #define DS_TAG_VERSION                      "<version>"
1480 #define DS_TAG_VERSION_END                  "</version>"
1481 #define DS_TAG_DEVICE                       "<device>"
1482 #define DS_TAG_DEVICE_END                   "</device>"
1483 #define DS_TAG_SCORE                        "<score>"
1484 #define DS_TAG_SCORE_END                    "</score>"
1485 #define DS_TAG_DEVICE_TYPE                  "<type>"
1486 #define DS_TAG_DEVICE_TYPE_END              "</type>"
1487 #define DS_TAG_DEVICE_NAME                  "<name>"
1488 #define DS_TAG_DEVICE_NAME_END              "</name>"
1489 #define DS_TAG_DEVICE_DRIVER_VERSION        "<driver>"
1490 #define DS_TAG_DEVICE_DRIVER_VERSION_END    "</driver>"
1491 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS     "<max cu>"
1492 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1493 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ        "<max clock>"
1494 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END    "</max clock>"
1495
1496 #define DS_DEVICE_NATIVE_CPU_STRING  "native_cpu"
1497
1498
1499
1500 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1501 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1502   ds_status status = DS_SUCCESS;
1503   FILE* profileFile = NULL;
1504
1505
1506   if (profile == NULL)
1507     return DS_INVALID_PROFILE;
1508
1509   profileFile = fopen(file, "wb");
1510   if (profileFile==NULL) {
1511     status = DS_FILE_ERROR;
1512   }
1513   else {
1514     unsigned int i;
1515
1516     /* write version string */
1517     fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1518     fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1519     fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1520     fwrite("\n", sizeof(char), 1, profileFile);
1521
1522     for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1523       void* serializedScore;
1524       unsigned int serializedScoreSize;
1525
1526       fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1527
1528       fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1529       fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1530       fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1531
1532       switch(profile->devices[i].type) {
1533       case DS_DEVICE_NATIVE_CPU:
1534         { 
1535           /* There's no need to emit a device name for the native CPU device. */
1536           /*
1537           fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1538           fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1539           fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1540           */
1541         }
1542         break;
1543       case DS_DEVICE_OPENCL_DEVICE: 
1544         {
1545           char tmp[16];
1546
1547           fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1548           fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1549           fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1550
1551           fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1552           fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1553           fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1554
1555           fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1556           sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1557           fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1558           fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1559
1560           fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1561           sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1562           fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1563           fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1564         }
1565         break;
1566       default:
1567         status = DS_UNKNOWN_DEVICE_TYPE;
1568         break;
1569       };
1570
1571       fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1572       status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1573       if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1574         fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1575         free(serializedScore);
1576       }
1577       fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1578       fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1579       fwrite("\n",sizeof(char),1,profileFile);
1580     }
1581     fclose(profileFile);
1582   }
1583   return status;
1584 }
1585
1586
1587 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1588   ds_status status = DS_SUCCESS;
1589   FILE * input = NULL;
1590   size_t size = 0;
1591   size_t rsize = 0;
1592   char* binary = NULL;
1593
1594   *contentSize = 0;
1595   *content = NULL;
1596
1597   input = fopen(fileName, "rb");
1598   if(input == NULL) {
1599     return DS_FILE_ERROR;
1600   }
1601
1602   fseek(input, 0L, SEEK_END); 
1603   size = ftell(input);
1604   rewind(input);
1605   binary = (char*)malloc(size);
1606   if(binary == NULL) {
1607     status = DS_FILE_ERROR;
1608     goto cleanup;
1609   }
1610   rsize = fread(binary, sizeof(char), size, input);
1611   if (rsize!=size
1612       || ferror(input)) {
1613     status = DS_FILE_ERROR;
1614     goto cleanup;
1615   }
1616   *contentSize = size;
1617   *content = binary;
1618
1619 cleanup:
1620   if (input != NULL) fclose(input);
1621   if (status != DS_SUCCESS
1622       && binary != NULL) {
1623       free(binary);
1624       *content = NULL;
1625       *contentSize = 0;
1626   }
1627   return status;
1628 }
1629
1630
1631 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1632   size_t stringLength;
1633   const char* currentPosition;
1634   const char* found;
1635   found = NULL;
1636   stringLength = strlen(string);
1637   currentPosition = contentStart;
1638   for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1639     if (*currentPosition == string[0]) {
1640       if (currentPosition+stringLength < contentEnd) {
1641         if (strncmp(currentPosition, string, stringLength) == 0) {
1642           found = currentPosition;
1643           break;
1644         }
1645       }
1646     }
1647   }
1648   return found;
1649 }
1650
1651
1652 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize); 
1653 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1654
1655   ds_status status = DS_SUCCESS;
1656   char* contentStart = NULL;
1657   const char* contentEnd = NULL;
1658   size_t contentSize;
1659
1660   if (profile==NULL)
1661     return DS_INVALID_PROFILE;
1662
1663   status = readProFile(file, &contentStart, &contentSize);
1664   if (status == DS_SUCCESS) {
1665     const char* currentPosition;
1666     const char* dataStart;
1667     const char* dataEnd;
1668     size_t versionStringLength;
1669
1670     contentEnd = contentStart + contentSize;
1671     currentPosition = contentStart;
1672
1673
1674     /* parse the version string */
1675     dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1676     if (dataStart == NULL) {
1677       status = DS_PROFILE_FILE_ERROR;
1678       goto cleanup;
1679     }
1680     dataStart += strlen(DS_TAG_VERSION);
1681
1682     dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1683     if (dataEnd==NULL) {
1684       status = DS_PROFILE_FILE_ERROR;
1685       goto cleanup;
1686     }
1687
1688     versionStringLength = strlen(profile->version);
1689     if (versionStringLength!=(dataEnd-dataStart)   
1690         || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1691       /* version mismatch */
1692       status = DS_PROFILE_FILE_ERROR;
1693       goto cleanup;
1694     }
1695     currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1696
1697     /* parse the device information */
1698     while (1) {
1699       unsigned int i;
1700
1701       const char* deviceTypeStart;
1702       const char* deviceTypeEnd;
1703       ds_device_type deviceType;
1704
1705       const char* deviceNameStart;
1706       const char* deviceNameEnd;
1707
1708       const char* deviceScoreStart;
1709       const char* deviceScoreEnd;
1710
1711       const char* deviceDriverStart;
1712       const char* deviceDriverEnd;
1713
1714       const char* tmpStart;
1715       const char* tmpEnd;
1716       char tmp[16];
1717
1718       cl_uint maxClockFrequency;
1719       cl_uint maxComputeUnits;
1720
1721       dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1722       if (dataStart==NULL) {
1723         /* nothing useful remain, quit...*/
1724         break;
1725       }
1726       dataStart+=strlen(DS_TAG_DEVICE);
1727       dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1728       if (dataEnd==NULL) {
1729         status = DS_PROFILE_FILE_ERROR;
1730         goto cleanup;
1731       }
1732
1733       /* parse the device type */
1734       deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1735       if (deviceTypeStart==NULL) {
1736         status = DS_PROFILE_FILE_ERROR;
1737         goto cleanup;       
1738       }
1739       deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1740       deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1741       if (deviceTypeEnd==NULL) {
1742         status = DS_PROFILE_FILE_ERROR;
1743         goto cleanup;
1744       }
1745       memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1746
1747
1748       /* parse the device name */
1749       if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1750
1751         deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1752         if (deviceNameStart==NULL) {
1753           status = DS_PROFILE_FILE_ERROR;
1754           goto cleanup;       
1755         }
1756         deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1757         deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1758         if (deviceNameEnd==NULL) {
1759           status = DS_PROFILE_FILE_ERROR;
1760           goto cleanup;       
1761         }
1762
1763
1764         deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1765         if (deviceDriverStart==NULL) {
1766           status = DS_PROFILE_FILE_ERROR;
1767           goto cleanup;       
1768         }
1769         deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1770         deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1771         if (deviceDriverEnd ==NULL) {
1772           status = DS_PROFILE_FILE_ERROR;
1773           goto cleanup;       
1774         }
1775
1776
1777         tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1778         if (tmpStart==NULL) {
1779           status = DS_PROFILE_FILE_ERROR;
1780           goto cleanup;       
1781         }
1782         tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1783         tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1784         if (tmpEnd ==NULL) {
1785           status = DS_PROFILE_FILE_ERROR;
1786           goto cleanup;       
1787         }
1788         memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1789         tmp[tmpEnd-tmpStart] = '\0';
1790         maxComputeUnits = atoi(tmp);
1791
1792
1793         tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1794         if (tmpStart==NULL) {
1795           status = DS_PROFILE_FILE_ERROR;
1796           goto cleanup;       
1797         }
1798         tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1799         tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1800         if (tmpEnd ==NULL) {
1801           status = DS_PROFILE_FILE_ERROR;
1802           goto cleanup;       
1803         }
1804         memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1805         tmp[tmpEnd-tmpStart] = '\0';
1806         maxClockFrequency = atoi(tmp);
1807
1808
1809         /* check if this device is on the system */
1810         for (i = 0; i < profile->numDevices; i++) {
1811           if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1812             size_t actualDeviceNameLength;
1813             size_t driverVersionLength;
1814             
1815             actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1816             driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1817             if (actualDeviceNameLength == (deviceNameEnd - deviceNameStart)
1818                && driverVersionLength == (deviceDriverEnd - deviceDriverStart)
1819                && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1820                && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1821                && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1822                && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1823
1824               deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1825               if (deviceNameStart==NULL) {
1826                 status = DS_PROFILE_FILE_ERROR;
1827                 goto cleanup;       
1828               }
1829               deviceScoreStart+=strlen(DS_TAG_SCORE);
1830               deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1831               status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1832               if (status != DS_SUCCESS) {
1833                 goto cleanup;
1834               }
1835             }
1836           }
1837         }
1838
1839       }
1840       else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1841         for (i = 0; i < profile->numDevices; i++) {
1842           if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1843             deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1844             if (deviceScoreStart==NULL) {
1845               status = DS_PROFILE_FILE_ERROR;
1846               goto cleanup;       
1847             }
1848             deviceScoreStart+=strlen(DS_TAG_SCORE);
1849             deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1850             status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1851             if (status != DS_SUCCESS) {
1852               goto cleanup;
1853             }
1854           }
1855         }
1856       }
1857
1858       /* skip over the current one to find the next device */
1859       currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1860     }
1861   }
1862 cleanup:
1863   if (contentStart!=NULL) free(contentStart);
1864   return status;
1865 }
1866
1867 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1868   unsigned int i;
1869   if (profile == NULL || num==NULL)
1870     return DS_MEMORY_ERROR;
1871   *num=0;
1872   for (i = 0; i < profile->numDevices; i++) {
1873     if (profile->devices[i].score == NULL) {
1874       *num++;
1875     }
1876   }
1877   return DS_SUCCESS;
1878 }
1879
1880 /*
1881  End of the OpenCL device selection infrastructure
1882 */
1883
1884
1885
1886 typedef struct _AccelerateTimer {
1887   long long _freq;      
1888   long long _clocks;
1889   long long _start;
1890 } AccelerateTimer;
1891
1892 static void startAccelerateTimer(AccelerateTimer* timer) {
1893 #ifdef _WIN32
1894       QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);  
1895
1896
1897 #else
1898       struct timeval s;
1899       gettimeofday(&s, 0);
1900       timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
1901 #endif  
1902 }
1903
1904 static void stopAccelerateTimer(AccelerateTimer* timer) {
1905       long long n=0;
1906 #ifdef _WIN32
1907       QueryPerformanceCounter((LARGE_INTEGER*)&(n));    
1908 #else
1909       struct timeval s;
1910       gettimeofday(&s, 0);
1911       n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
1912 #endif
1913       n -= timer->_start;
1914       timer->_start = 0;
1915       timer->_clocks += n;
1916 }
1917
1918 static void resetAccelerateTimer(AccelerateTimer* timer) {
1919    timer->_clocks = 0; 
1920    timer->_start = 0;
1921 }
1922
1923
1924 static void initAccelerateTimer(AccelerateTimer* timer) {
1925 #ifdef _WIN32
1926     QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
1927 #else
1928     timer->_freq = (long long)1.0E3;
1929 #endif
1930    resetAccelerateTimer(timer);
1931 }
1932
1933 double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
1934
1935
1936 typedef double AccelerateScoreType;
1937
1938 static ds_status AcceleratePerfEvaluator(ds_device* device, void* data) {
1939
1940   ds_status status = DS_SUCCESS;
1941   MagickCLEnv clEnv = NULL;
1942   MagickCLEnv oldClEnv = NULL;
1943   ExceptionInfo* exception = NULL;
1944   AccelerateTimer timer;
1945
1946   if (device == NULL) {
1947     status = DS_PERF_EVALUATOR_ERROR;
1948     goto cleanup;
1949   }
1950
1951   clEnv = AcquireMagickOpenCLEnv();
1952   exception = AcquireExceptionInfo();
1953
1954   if (device->type == DS_DEVICE_NATIVE_CPU) {
1955     /* CPU device */
1956     MagickBooleanType flag = MagickTrue;
1957     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
1958                                   , sizeof(MagickBooleanType), &flag, exception);
1959   }
1960   else if (device->type == DS_DEVICE_OPENCL_DEVICE) {
1961     /* OpenCL device */
1962     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
1963       , sizeof(cl_device_id), &device->oclDeviceID,exception);
1964   }
1965   else {
1966     status = DS_PERF_EVALUATOR_ERROR;
1967     goto cleanup;
1968   }
1969   InitOpenCLEnvInternal(clEnv, exception);
1970   oldClEnv = defaultCLEnv;
1971   defaultCLEnv = clEnv;
1972
1973   /* microbenchmark */
1974   {
1975 #define ACCELERATE_PERF_DIMEN       "2048x1536"
1976 #define NUM_ITER                      2
1977
1978     Image* inputImage;
1979     ImageInfo* imageInfo;
1980     int i;
1981
1982     imageInfo = AcquireImageInfo();
1983     CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
1984     CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
1985     inputImage = ReadImage(imageInfo,exception);
1986
1987     initAccelerateTimer(&timer);
1988
1989     for (i = 0; i <=NUM_ITER; i++) {
1990
1991       Image* bluredImage;
1992       Image* unsharpedImage;
1993       Image* resizedImage;
1994
1995       if (i > 0)
1996         startAccelerateTimer(&timer);
1997
1998 #ifdef MAGICKCORE_CLPERFMARKER
1999   clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2000 #endif
2001
2002       bluredImage = BlurImage(inputImage, 10.0f, 3.5f, exception);
2003       unsharpedImage = UnsharpMaskImage(bluredImage, 2.0f,2.0f,50.0f,10.0f,exception);
2004       resizedImage = ResizeImage(unsharpedImage,640,480,LanczosFilter,1.0,exception);
2005
2006 #ifdef MAGICKCORE_CLPERFMARKER
2007   clEndPerfMarkerAMD();
2008 #endif
2009
2010       if (i > 0)
2011         stopAccelerateTimer(&timer);
2012
2013       if (bluredImage) DestroyImage(bluredImage);
2014       if (unsharpedImage) DestroyImage(unsharpedImage);
2015       if (resizedImage) DestroyImage(resizedImage);
2016     }
2017     DestroyImage(inputImage);
2018   }
2019   /* end of microbenchmark */
2020   
2021   if (device->score == NULL) {
2022     device->score = malloc(sizeof(AccelerateScoreType));
2023   }
2024   *(AccelerateScoreType*)device->score = readAccelerateTimer(&timer);
2025
2026 cleanup:
2027   if (clEnv!=NULL)
2028     RelinquishMagickOpenCLEnv(clEnv);
2029   if (oldClEnv!=NULL)
2030     defaultCLEnv = oldClEnv;
2031   return status;
2032 }
2033
2034
2035
2036 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2037   if (device
2038      && device->score) {
2039     /* generate a string from the score */
2040     char* s = (char*)malloc(sizeof(char)*256);
2041     sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2042     *serializedScore = (void*)s;
2043     *serializedScoreSize = strlen(s);
2044     return DS_SUCCESS;
2045   }
2046   else {
2047     return DS_SCORE_SERIALIZER_ERROR;
2048   }
2049 }
2050
2051 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2052   if (device) {
2053     /* convert the string back to an int */
2054     char* s = (char*)malloc(serializedScoreSize+1);
2055     memcpy(s, serializedScore, serializedScoreSize);
2056     s[serializedScoreSize] = (char)'\0';
2057     device->score = malloc(sizeof(AccelerateScoreType));
2058     *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2059     free(s);
2060     return DS_SUCCESS;
2061   }
2062   else {
2063     return DS_SCORE_DESERIALIZER_ERROR;
2064   }
2065 }
2066
2067 ds_status AccelerateScoreRelease(void* score) {
2068   if (score!=NULL) {
2069     free(score);
2070   }
2071   return DS_SUCCESS;
2072 }
2073
2074
2075 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2076 #define IMAGEMAGICK_PROFILE_FILE    "ImagemagickOpenCLDeviceProfile"
2077 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2078
2079   MagickBooleanType mStatus = MagickFalse;
2080   ds_status status;
2081   ds_profile* profile;
2082   unsigned int numDeviceProfiled = 0;
2083   unsigned int i;
2084   unsigned int bestDeviceIndex;
2085   AccelerateScoreType bestScore;
2086   char path[MaxTextExtent];
2087
2088
2089   LockDefaultOpenCLEnv();
2090
2091   status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2092   if (status!=DS_SUCCESS) {
2093     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2094     goto cleanup;
2095   }
2096
2097   (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2098          ,GetOpenCLCachedFilesDirectory()
2099          ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2100
2101   readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2102   status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2103   if (status!=DS_SUCCESS) {
2104     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2105     goto cleanup;
2106   }
2107   if (numDeviceProfiled > 0) {
2108     status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2109     if (status!=DS_SUCCESS) {
2110       (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2111     }
2112   }
2113
2114   /* pick the best device */
2115   bestDeviceIndex = 0;
2116   bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2117   for (i = 1; i < profile->numDevices; i++) {
2118     AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2119     if (score < bestScore) {
2120       bestDeviceIndex = i;
2121       bestScore = score;
2122     }
2123   }
2124
2125   /* set up clEnv with the best device */
2126   if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2127     /* CPU device */
2128     MagickBooleanType flag = MagickTrue;
2129     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2130                                   , sizeof(MagickBooleanType), &flag, exception);
2131   }
2132   else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2133     /* OpenCL device */
2134     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2135       , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2136   }
2137   else {
2138     status = DS_PERF_EVALUATOR_ERROR;
2139     goto cleanup;
2140   }
2141   mStatus=InitOpenCLEnvInternal(clEnv, exception);
2142
2143   status = releaseDSProfile(profile, AccelerateScoreRelease);
2144   if (status!=DS_SUCCESS) {
2145     (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2146   }
2147
2148 cleanup:
2149
2150   UnlockDefaultOpenCLEnv();
2151   return mStatus;
2152 }
2153
2154
2155 /*
2156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2157 %                                                                             %
2158 %                                                                             %
2159 %                                                                             %
2160 +   I n i t I m a g e M a g i c k O p e n C L                                 %
2161 %                                                                             %
2162 %                                                                             %
2163 %                                                                             %
2164 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2165 %
2166 %  InitImageMagickOpenCL() provides a simplified interface to initialize
2167 %  the OpenCL environtment in ImageMagick
2168 %  
2169 %  The format of the InitImageMagickOpenCL() method is:
2170 %
2171 %      MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode, 
2172 %                                        void* userSelectedDevice, 
2173 %                                        void* selectedDevice) 
2174 %
2175 %  A description of each parameter follows:
2176 %
2177 %    o mode: OpenCL mode in ImageMagick, could be off,auto,user
2178 %
2179 %    o userSelectedDevice:  when in user mode, a pointer to the selected
2180 %                           cl_device_id
2181 %
2182 %    o selectedDevice: a pointer to cl_device_id where the selected
2183 %                      cl_device_id by ImageMagick could be returned
2184 %
2185 %    o exception: exception
2186 %
2187 */
2188 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode, 
2189                                         void* userSelectedDevice, 
2190                                         void* selectedDevice,
2191                                         ExceptionInfo* exception) {
2192  
2193   MagickBooleanType status = MagickTrue;
2194   MagickCLEnv clEnv = NULL;
2195   MagickBooleanType flag;
2196
2197   exception = AcquireExceptionInfo();
2198   clEnv = GetDefaultOpenCLEnv();
2199   if (clEnv!=NULL) {
2200     switch(mode) {
2201
2202     case MAGICK_OPENCL_OFF:
2203       flag = MagickTrue;
2204       SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2205         , sizeof(MagickBooleanType), &flag, exception);
2206       status = InitOpenCLEnv(clEnv, exception);
2207
2208       if (selectedDevice)
2209         *(cl_device_id*)selectedDevice = NULL;
2210       break;
2211
2212     case MAGICK_OPENCL_DEVICE_SELECT_USER:
2213
2214       if (userSelectedDevice == NULL)
2215         return MagickFalse;
2216
2217       flag = MagickFalse;
2218       SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2219         , sizeof(MagickBooleanType), &flag, exception);
2220
2221       SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2222         , sizeof(cl_device_id), userSelectedDevice,exception);
2223
2224       status = InitOpenCLEnv(clEnv, exception);
2225       if (selectedDevice) {
2226         GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2227           , sizeof(cl_device_id), selectedDevice, exception);
2228       }
2229       break;
2230
2231     case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2232     default:
2233       {
2234         cl_device_id d = NULL;
2235         flag = MagickFalse;
2236         SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2237           , sizeof(MagickBooleanType), &flag, exception);
2238         SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2239           , sizeof(cl_device_id), &d,exception);
2240         status = InitOpenCLEnv(clEnv, exception);
2241         if (selectedDevice) {
2242           GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2243             , sizeof(cl_device_id),  selectedDevice, exception);
2244         }
2245       }
2246       break;
2247     };
2248   }
2249   return status;
2250 }
2251
2252
2253 #else
2254
2255 struct _MagickCLEnv {
2256   MagickBooleanType OpenCLInitialized;  /* whether OpenCL environment is initialized. */
2257 };
2258
2259 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2260 {
2261   return NULL;
2262 }
2263
2264 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2265   MagickCLEnv magick_unused(clEnv))
2266 {
2267   magick_unreferenced(clEnv);
2268
2269   return MagickFalse;
2270 }
2271
2272 /*
2273 * Return the OpenCL environment
2274 */ 
2275 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2276   ExceptionInfo *magick_unused(exception))
2277 {
2278   magick_unreferenced(exception);
2279
2280   return (MagickCLEnv) NULL;
2281 }
2282
2283 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2284   MagickCLEnv magick_unused(clEnv))
2285 {
2286   magick_unreferenced(clEnv);
2287
2288   return (MagickCLEnv) NULL;
2289
2290
2291 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2292   MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2293   size_t magick_unused(dataSize),void *magick_unused(data),
2294   ExceptionInfo *magick_unused(exception))
2295 {
2296   magick_unreferenced(clEnv);
2297   magick_unreferenced(param);
2298   magick_unreferenced(dataSize);
2299   magick_unreferenced(data);
2300   magick_unreferenced(exception);
2301
2302   return MagickFalse;
2303 }
2304
2305 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2306   MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2307   size_t magick_unused(dataSize),void *magick_unused(data),
2308   ExceptionInfo *magick_unused(exception))
2309 {
2310   magick_unreferenced(clEnv);
2311   magick_unreferenced(param);
2312   magick_unreferenced(dataSize);
2313   magick_unreferenced(data);
2314   magick_unreferenced(exception);
2315
2316   return MagickFalse;
2317 }
2318
2319 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2320   ExceptionInfo *magick_unused(exception))
2321 {
2322   magick_unreferenced(clEnv);
2323   magick_unreferenced(exception);
2324
2325   return MagickFalse;
2326 }
2327
2328 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2329   MagickCLEnv magick_unused(clEnv))
2330 {
2331   magick_unreferenced(clEnv);
2332
2333   return (cl_command_queue) NULL;
2334 }
2335
2336 MagickExport MagickBooleanType RelinquishCommandQueue(
2337   MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2338 {
2339   magick_unreferenced(clEnv);
2340   magick_unreferenced(queue);
2341
2342   return MagickFalse;
2343 }
2344
2345 MagickExport cl_kernel AcquireOpenCLKernel(
2346   MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2347   const char *magick_unused(kernelName))
2348 {
2349   magick_unreferenced(clEnv);
2350   magick_unreferenced(program);
2351   magick_unreferenced(kernelName);
2352
2353   return (cl_kernel)NULL;
2354 }
2355
2356 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2357   MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2358 {
2359   magick_unreferenced(clEnv);
2360   magick_unreferenced(kernel);
2361
2362   return MagickFalse;
2363 }
2364
2365 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2366   MagickCLEnv magick_unused(clEnv))
2367 {
2368   magick_unreferenced(clEnv);
2369
2370   return 0;
2371 }
2372
2373 MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode, 
2374                                         void* userSelectedDevice, 
2375                                         void* selectedDevice,
2376                                         ExceptionInfo* exception) 
2377 {
2378   magick_unreferenced(mode);
2379   magick_unreferenced(userSelectedDevice);
2380   magick_unreferenced(selectedDevice);
2381   magick_unreferenced(exception);
2382   return MagickFalse;
2383 }
2384
2385 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2386
2387 char* openclCachedFilesDirectory;
2388 SemaphoreInfo* openclCachedFilesDirectoryLock;
2389
2390 MagickExport
2391 const char* GetOpenCLCachedFilesDirectory() {
2392   if (openclCachedFilesDirectory == NULL) {
2393     if (openclCachedFilesDirectoryLock == NULL)
2394     {
2395       AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2396     }
2397     LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2398     if (openclCachedFilesDirectory == NULL) {
2399       char path[MaxTextExtent];
2400       char *home = NULL;
2401       char *temp = NULL;
2402       struct stat attributes;
2403       MagickBooleanType status;
2404
2405 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2406       home=GetEnvironmentValue("LOCALAPPDATA");
2407       if (home == (char *) NULL)
2408         home=GetEnvironmentValue("APPDATA");
2409       if (home == (char *) NULL)
2410         home=GetEnvironmentValue("USERPROFILE");
2411 #else
2412       home=GetEnvironmentValue("HOME");
2413 #endif
2414       if (home != (char *) NULL)
2415       {
2416         /*
2417         Search $HOME/.magick.
2418         */
2419         (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2420           DirectorySeparator);
2421         home=DestroyString(home);
2422         temp = (char*)AcquireMagickMemory(strlen(path)+1);
2423         CopyMagickString(temp,path,strlen(path)+1);
2424         status=GetPathAttributes(path,&attributes);
2425         if (status == MagickFalse) {
2426 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2427           mkdir(path);
2428 #else
2429           mkdir(path, 0777);
2430 #endif
2431         }
2432       }
2433       openclCachedFilesDirectory = temp;
2434     }
2435     UnlockSemaphoreInfo(openclCachedFilesDirectoryLock); 
2436   }
2437   return openclCachedFilesDirectory;
2438 }
2439
2440 /* create a function for OpenCL log */
2441 MagickExport
2442 void OpenCLLog(const char* message) {
2443
2444 #ifdef OPENCLLOG_ENABLED
2445 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2446
2447   FILE* log;
2448   if (getenv("MAGICK_OCL_LOG"))
2449   {
2450     if (message) {
2451       char path[MaxTextExtent];
2452
2453       /*  dump the source into a file */
2454       (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2455         ,GetOpenCLCachedFilesDirectory()
2456         ,DirectorySeparator,OPENCL_LOG_FILE);
2457
2458
2459       log = fopen(path, "ab");
2460       fwrite(message, sizeof(char), strlen(message), log);
2461       fwrite("\n", sizeof(char), 1, log);
2462       fclose(log);
2463     }
2464   }
2465 #else
2466   magick_unreferenced(message);
2467 #endif
2468 }
2469