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