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