]> granicus.if.org Git - imagemagick/blob - MagickCore/opencl.c
Fix for reading OpenCL device name/version.
[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 %                                   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 typedef enum {
1246   DS_SUCCESS = 0
1247  ,DS_INVALID_PROFILE = 1000
1248  ,DS_MEMORY_ERROR
1249  ,DS_INVALID_PERF_EVALUATOR_TYPE
1250  ,DS_INVALID_PERF_EVALUATOR
1251  ,DS_PERF_EVALUATOR_ERROR
1252  ,DS_FILE_ERROR
1253  ,DS_UNKNOWN_DEVICE_TYPE
1254  ,DS_PROFILE_FILE_ERROR
1255  ,DS_SCORE_SERIALIZER_ERROR
1256  ,DS_SCORE_DESERIALIZER_ERROR
1257 } ds_status;
1258
1259 /* device type */
1260 typedef enum {
1261   DS_DEVICE_NATIVE_CPU = 0
1262  ,DS_DEVICE_OPENCL_DEVICE 
1263 } ds_device_type;
1264
1265
1266 typedef struct {
1267   ds_device_type  type;
1268   cl_device_id    oclDeviceID;
1269   char*           oclDeviceName;
1270   char*           oclDriverVersion;
1271   cl_uint         oclMaxClockFrequency;
1272   cl_uint         oclMaxComputeUnits;
1273   void*           score;            /* a pointer to the score data, the content/format is application defined */
1274 } ds_device;
1275
1276 typedef struct {
1277   unsigned int  numDevices;
1278   ds_device*    devices;
1279   const char*   version;
1280 } ds_profile;
1281
1282 /* deallocate memory used by score */
1283 typedef ds_status (*ds_score_release)(void* score);
1284
1285 static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1286   ds_status status = DS_SUCCESS;
1287   if (device) {
1288     if (device->oclDeviceName)      free(device->oclDeviceName);
1289     if (device->oclDriverVersion)   free(device->oclDriverVersion);
1290     if (device->score)              status = sr(device->score);
1291   }
1292   return status;
1293 }
1294
1295 static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1296   ds_status status = DS_SUCCESS;
1297   if (profile!=NULL) {
1298     if (profile->devices!=NULL && sr!=NULL) {
1299       unsigned int i;
1300       for (i = 0; i < profile->numDevices; i++) {
1301         status = releaseDeviceResource(profile->devices+i,sr);
1302         if (status != DS_SUCCESS)
1303           break;
1304       }
1305       free(profile->devices);
1306     }
1307     free(profile);
1308   }
1309   return status;
1310 }
1311
1312
1313 static ds_status initDSProfile(ds_profile** p, const char* version) {
1314   int numDevices = 0;
1315   cl_uint numPlatforms = 0;
1316   cl_platform_id* platforms = NULL;
1317   cl_device_id*   devices = NULL;
1318   ds_status status = DS_SUCCESS;
1319   ds_profile* profile = NULL;
1320   unsigned int next = 0;
1321   unsigned int i;
1322
1323   if (p == NULL)
1324     return DS_INVALID_PROFILE;
1325
1326   profile = (ds_profile*)malloc(sizeof(ds_profile));
1327   if (profile == NULL)
1328     return DS_MEMORY_ERROR;
1329   
1330   memset(profile, 0, sizeof(ds_profile));
1331
1332   clGetPlatformIDs(0, NULL, &numPlatforms);
1333   if (numPlatforms > 0) {
1334     platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1335     if (platforms == NULL) {
1336       status = DS_MEMORY_ERROR;
1337       goto cleanup;
1338     }
1339     clGetPlatformIDs(numPlatforms, platforms, NULL);
1340     for (i = 0; i < (unsigned int)numPlatforms; i++) {
1341       cl_uint num;
1342       clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_ALL, 0, NULL, &num);
1343       numDevices+=num;
1344     }
1345   }
1346
1347   profile->numDevices = numDevices+1;     /* +1 to numDevices to include the native CPU */
1348
1349   profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));    
1350   if (profile->devices == NULL) {
1351     profile->numDevices = 0;
1352     status = DS_MEMORY_ERROR;
1353     goto cleanup;    
1354   }
1355   memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1356
1357   if (numDevices > 0) {
1358     devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1359     if (devices == NULL) {
1360       status = DS_MEMORY_ERROR;
1361       goto cleanup;
1362     }
1363     for (i = 0; i < (unsigned int)numPlatforms; i++) {
1364       cl_uint num;
1365
1366       int d;
1367       for (d = 0; d < 2; d++) { 
1368         unsigned int j;
1369         cl_device_type deviceType;
1370         switch(d) {
1371         case 0:
1372           deviceType = CL_DEVICE_TYPE_GPU;
1373           break;
1374         case 1:
1375           deviceType = CL_DEVICE_TYPE_CPU;
1376           break;
1377         default:
1378           continue;
1379           break;
1380         }
1381         clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num);
1382         for (j = 0; j < num; j++, next++) {
1383           size_t length;
1384
1385           profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1386           profile->devices[next].oclDeviceID = devices[j];
1387
1388           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME\r
1389             , 0, NULL, &length);\r
1390           profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);\r
1391           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME\r
1392             , length, profile->devices[next].oclDeviceName, NULL);\r
1393 \r
1394           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION\r
1395             , 0, NULL, &length);\r
1396           profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);\r
1397           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION\r
1398             , length, profile->devices[next].oclDriverVersion, NULL);
1399
1400           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
1401             , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1402
1403           clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
1404             , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
1405         }
1406       }
1407     }
1408   }
1409
1410   profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1411   profile->version = version;
1412
1413 cleanup:
1414   if (platforms)  free(platforms);
1415   if (devices)    free(devices);
1416   if (status == DS_SUCCESS) {
1417     *p = profile;
1418   }
1419   else {
1420     if (profile) {
1421       if (profile->devices)
1422         free(profile->devices);
1423       free(profile);
1424     }
1425   }
1426   return status;
1427 }
1428
1429 /* Pointer to a function that calculates the score of a device (ex: device->score) 
1430  update the data size of score. The encoding and the format of the score data 
1431  is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
1432  */
1433 typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
1434
1435 typedef enum {
1436   DS_EVALUATE_ALL
1437   ,DS_EVALUATE_NEW_ONLY
1438 } ds_evaluation_type;
1439
1440 static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
1441                          ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
1442   ds_status status = DS_SUCCESS;
1443   unsigned int i;
1444   unsigned int updates = 0;
1445
1446   if (profile == NULL) {
1447     return DS_INVALID_PROFILE;
1448   }
1449   if (evaluator == NULL) {
1450     return DS_INVALID_PERF_EVALUATOR;
1451   }
1452
1453   for (i = 0; i < profile->numDevices; i++) {
1454     ds_status evaluatorStatus;
1455     
1456     switch (type) {
1457     case DS_EVALUATE_NEW_ONLY:
1458       if (profile->devices[i].score != NULL)
1459         break;
1460       /*  else fall through */
1461     case DS_EVALUATE_ALL:
1462       evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
1463       if (evaluatorStatus != DS_SUCCESS) {
1464         status = evaluatorStatus;
1465         return status;
1466       }
1467       updates++;
1468       break;
1469     default:
1470       return DS_INVALID_PERF_EVALUATOR_TYPE;
1471       break;
1472     };
1473   }
1474   if (numUpdates)
1475     *numUpdates = updates;
1476   return status;
1477 }
1478
1479
1480 #define DS_TAG_VERSION                      "<version>"
1481 #define DS_TAG_VERSION_END                  "</version>"
1482 #define DS_TAG_DEVICE                       "<device>"
1483 #define DS_TAG_DEVICE_END                   "</device>"
1484 #define DS_TAG_SCORE                        "<score>"
1485 #define DS_TAG_SCORE_END                    "</score>"
1486 #define DS_TAG_DEVICE_TYPE                  "<type>"
1487 #define DS_TAG_DEVICE_TYPE_END              "</type>"
1488 #define DS_TAG_DEVICE_NAME                  "<name>"
1489 #define DS_TAG_DEVICE_NAME_END              "</name>"
1490 #define DS_TAG_DEVICE_DRIVER_VERSION        "<driver>"
1491 #define DS_TAG_DEVICE_DRIVER_VERSION_END    "</driver>"
1492 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS     "<max cu>"
1493 #define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1494 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ        "<max clock>"
1495 #define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END    "</max clock>"
1496
1497 #define DS_DEVICE_NATIVE_CPU_STRING  "native_cpu"
1498
1499
1500
1501 typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1502 static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1503   ds_status status = DS_SUCCESS;
1504   FILE* profileFile = NULL;
1505
1506
1507   if (profile == NULL)
1508     return DS_INVALID_PROFILE;
1509
1510   profileFile = fopen(file, "wb");
1511   if (profileFile==NULL) {
1512     status = DS_FILE_ERROR;
1513   }
1514   else {
1515     unsigned int i;
1516
1517     /* write version string */
1518     fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1519     fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1520     fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1521     fwrite("\n", sizeof(char), 1, profileFile);
1522
1523     for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1524       void* serializedScore;
1525       unsigned int serializedScoreSize;
1526
1527       fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1528
1529       fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1530       fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1531       fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1532
1533       switch(profile->devices[i].type) {
1534       case DS_DEVICE_NATIVE_CPU:
1535         { 
1536           /* There's no need to emit a device name for the native CPU device. */
1537           /*
1538           fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1539           fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1540           fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1541           */
1542         }
1543         break;
1544       case DS_DEVICE_OPENCL_DEVICE: 
1545         {
1546           char tmp[16];
1547
1548           fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1549           fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1550           fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1551
1552           fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1553           fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1554           fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1555
1556           fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1557           sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1558           fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1559           fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1560
1561           fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1562           sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1563           fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1564           fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1565         }
1566         break;
1567       default:
1568         status = DS_UNKNOWN_DEVICE_TYPE;
1569         break;
1570       };
1571
1572       fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1573       status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1574       if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1575         fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1576         free(serializedScore);
1577       }
1578       fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1579       fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1580       fwrite("\n",sizeof(char),1,profileFile);
1581     }
1582     fclose(profileFile);
1583   }
1584   return status;
1585 }
1586
1587
1588 static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1589   ds_status status = DS_SUCCESS;
1590   FILE * input = NULL;
1591   size_t size = 0;
1592   size_t rsize = 0;
1593   char* binary = NULL;
1594
1595   *contentSize = 0;
1596   *content = NULL;
1597
1598   input = fopen(fileName, "rb");
1599   if(input == NULL) {
1600     return DS_FILE_ERROR;
1601   }
1602
1603   fseek(input, 0L, SEEK_END); 
1604   size = ftell(input);
1605   rewind(input);
1606   binary = (char*)malloc(size);
1607   if(binary == NULL) {
1608     status = DS_FILE_ERROR;
1609     goto cleanup;
1610   }
1611   rsize = fread(binary, sizeof(char), size, input);
1612   if (rsize!=size
1613       || ferror(input)) {
1614     status = DS_FILE_ERROR;
1615     goto cleanup;
1616   }
1617   *contentSize = size;
1618   *content = binary;
1619
1620 cleanup:
1621   if (input != NULL) fclose(input);
1622   if (status != DS_SUCCESS
1623       && binary != NULL) {
1624       free(binary);
1625       *content = NULL;
1626       *contentSize = 0;
1627   }
1628   return status;
1629 }
1630
1631
1632 static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
1633   size_t stringLength;
1634   const char* currentPosition;
1635   const char* found;
1636   found = NULL;
1637   stringLength = strlen(string);
1638   currentPosition = contentStart;
1639   for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
1640     if (*currentPosition == string[0]) {
1641       if (currentPosition+stringLength < contentEnd) {
1642         if (strncmp(currentPosition, string, stringLength) == 0) {
1643           found = currentPosition;
1644           break;
1645         }
1646       }
1647     }
1648   }
1649   return found;
1650 }
1651
1652
1653 typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize); 
1654 static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
1655
1656   ds_status status = DS_SUCCESS;
1657   char* contentStart = NULL;
1658   const char* contentEnd = NULL;
1659   size_t contentSize;
1660
1661   if (profile==NULL)
1662     return DS_INVALID_PROFILE;
1663
1664   status = readProFile(file, &contentStart, &contentSize);
1665   if (status == DS_SUCCESS) {
1666     const char* currentPosition;
1667     const char* dataStart;
1668     const char* dataEnd;
1669     size_t versionStringLength;
1670
1671     contentEnd = contentStart + contentSize;
1672     currentPosition = contentStart;
1673
1674
1675     /* parse the version string */
1676     dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
1677     if (dataStart == NULL) {
1678       status = DS_PROFILE_FILE_ERROR;
1679       goto cleanup;
1680     }
1681     dataStart += strlen(DS_TAG_VERSION);
1682
1683     dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
1684     if (dataEnd==NULL) {
1685       status = DS_PROFILE_FILE_ERROR;
1686       goto cleanup;
1687     }
1688
1689     versionStringLength = strlen(profile->version);
1690     if (versionStringLength!=(size_t)(dataEnd-dataStart)   
1691         || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
1692       /* version mismatch */
1693       status = DS_PROFILE_FILE_ERROR;
1694       goto cleanup;
1695     }
1696     currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
1697
1698     /* parse the device information */
1699 DisableMSCWarning(4127)
1700     while (1) {
1701 RestoreMSCWarning
1702       unsigned int i;
1703
1704       const char* deviceTypeStart;
1705       const char* deviceTypeEnd;
1706       ds_device_type deviceType;
1707
1708       const char* deviceNameStart;
1709       const char* deviceNameEnd;
1710
1711       const char* deviceScoreStart;
1712       const char* deviceScoreEnd;
1713
1714       const char* deviceDriverStart;
1715       const char* deviceDriverEnd;
1716
1717       const char* tmpStart;
1718       const char* tmpEnd;
1719       char tmp[16];
1720
1721       cl_uint maxClockFrequency;
1722       cl_uint maxComputeUnits;
1723
1724       dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
1725       if (dataStart==NULL) {
1726         /* nothing useful remain, quit...*/
1727         break;
1728       }
1729       dataStart+=strlen(DS_TAG_DEVICE);
1730       dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
1731       if (dataEnd==NULL) {
1732         status = DS_PROFILE_FILE_ERROR;
1733         goto cleanup;
1734       }
1735
1736       /* parse the device type */
1737       deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
1738       if (deviceTypeStart==NULL) {
1739         status = DS_PROFILE_FILE_ERROR;
1740         goto cleanup;       
1741       }
1742       deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
1743       deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
1744       if (deviceTypeEnd==NULL) {
1745         status = DS_PROFILE_FILE_ERROR;
1746         goto cleanup;
1747       }
1748       memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
1749
1750
1751       /* parse the device name */
1752       if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
1753
1754         deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
1755         if (deviceNameStart==NULL) {
1756           status = DS_PROFILE_FILE_ERROR;
1757           goto cleanup;       
1758         }
1759         deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
1760         deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
1761         if (deviceNameEnd==NULL) {
1762           status = DS_PROFILE_FILE_ERROR;
1763           goto cleanup;       
1764         }
1765
1766
1767         deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
1768         if (deviceDriverStart==NULL) {
1769           status = DS_PROFILE_FILE_ERROR;
1770           goto cleanup;       
1771         }
1772         deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
1773         deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
1774         if (deviceDriverEnd ==NULL) {
1775           status = DS_PROFILE_FILE_ERROR;
1776           goto cleanup;       
1777         }
1778
1779
1780         tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1781         if (tmpStart==NULL) {
1782           status = DS_PROFILE_FILE_ERROR;
1783           goto cleanup;       
1784         }
1785         tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
1786         tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
1787         if (tmpEnd ==NULL) {
1788           status = DS_PROFILE_FILE_ERROR;
1789           goto cleanup;       
1790         }
1791         memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1792         tmp[tmpEnd-tmpStart] = '\0';
1793         maxComputeUnits = atoi(tmp);
1794
1795
1796         tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1797         if (tmpStart==NULL) {
1798           status = DS_PROFILE_FILE_ERROR;
1799           goto cleanup;       
1800         }
1801         tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
1802         tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
1803         if (tmpEnd ==NULL) {
1804           status = DS_PROFILE_FILE_ERROR;
1805           goto cleanup;       
1806         }
1807         memcpy(tmp,tmpStart,tmpEnd-tmpStart);
1808         tmp[tmpEnd-tmpStart] = '\0';
1809         maxClockFrequency = atoi(tmp);
1810
1811
1812         /* check if this device is on the system */
1813         for (i = 0; i < profile->numDevices; i++) {
1814           if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
1815             size_t actualDeviceNameLength;
1816             size_t driverVersionLength;
1817             
1818             actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
1819             driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
1820             if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
1821                && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
1822                && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
1823                && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
1824                && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
1825                && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
1826
1827               deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1828               if (deviceNameStart==NULL) {
1829                 status = DS_PROFILE_FILE_ERROR;
1830                 goto cleanup;       
1831               }
1832               deviceScoreStart+=strlen(DS_TAG_SCORE);
1833               deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1834               status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1835               if (status != DS_SUCCESS) {
1836                 goto cleanup;
1837               }
1838             }
1839           }
1840         }
1841
1842       }
1843       else if (deviceType == DS_DEVICE_NATIVE_CPU) {
1844         for (i = 0; i < profile->numDevices; i++) {
1845           if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
1846             deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
1847             if (deviceScoreStart==NULL) {
1848               status = DS_PROFILE_FILE_ERROR;
1849               goto cleanup;       
1850             }
1851             deviceScoreStart+=strlen(DS_TAG_SCORE);
1852             deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
1853             status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
1854             if (status != DS_SUCCESS) {
1855               goto cleanup;
1856             }
1857           }
1858         }
1859       }
1860
1861       /* skip over the current one to find the next device */
1862       currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
1863     }
1864   }
1865 cleanup:
1866   if (contentStart!=NULL) free(contentStart);
1867   return status;
1868 }
1869
1870
1871 #if 0
1872 static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
1873   unsigned int i;
1874   if (profile == NULL || num==NULL)
1875     return DS_MEMORY_ERROR;
1876   *num=0;
1877   for (i = 0; i < profile->numDevices; i++) {
1878     if (profile->devices[i].score == NULL) {
1879       (*num)++;
1880     }
1881   }
1882   return DS_SUCCESS;
1883 }
1884 #endif
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   void *magick_unused(data))
1946 {
1947 #define ACCELERATE_PERF_DIMEN "2048x1536"
1948 #define NUM_ITER  2
1949 #define ReturnStatus(status) \
1950 { \
1951   if (clEnv!=NULL) \
1952     RelinquishMagickOpenCLEnv(clEnv); \
1953   if (oldClEnv!=NULL) \
1954     defaultCLEnv = oldClEnv; \
1955   return status; \
1956 }
1957
1958   AccelerateTimer
1959     timer;
1960
1961   ExceptionInfo
1962     *exception=NULL;
1963
1964   MagickCLEnv
1965     clEnv=NULL,
1966     oldClEnv=NULL;
1967
1968   magick_unreferenced(data);
1969
1970   if (device == NULL)
1971     ReturnStatus(DS_PERF_EVALUATOR_ERROR);
1972
1973   clEnv=AcquireMagickOpenCLEnv();
1974   exception=AcquireExceptionInfo();
1975
1976   if (device->type == DS_DEVICE_NATIVE_CPU)
1977     {
1978       /* CPU device */
1979       MagickBooleanType flag=MagickTrue;
1980       SetMagickOpenCLEnvParamInternal(clEnv,
1981         MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
1982         &flag,exception);
1983     }
1984   else if (device->type == DS_DEVICE_OPENCL_DEVICE)
1985     {
1986       /* OpenCL device */
1987       SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
1988         sizeof(cl_device_id),&device->oclDeviceID,exception);
1989     }
1990   else
1991     ReturnStatus(DS_PERF_EVALUATOR_ERROR);
1992
1993   InitOpenCLEnvInternal(clEnv,exception);
1994   oldClEnv=defaultCLEnv;
1995   defaultCLEnv=clEnv;
1996
1997   /* microbenchmark */
1998   {
1999     Image
2000       *inputImage;
2001
2002     ImageInfo
2003       *imageInfo;
2004
2005     int
2006       i;
2007
2008     imageInfo=AcquireImageInfo();
2009     CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
2010     CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
2011     inputImage=ReadImage(imageInfo,exception);
2012
2013     initAccelerateTimer(&timer);
2014
2015     for (i=0; i<=NUM_ITER; i++)
2016     {
2017       Image
2018         *bluredImage,
2019         *resizedImage,
2020         *unsharpedImage;
2021
2022       if (i > 0)
2023         startAccelerateTimer(&timer);
2024
2025 #ifdef MAGICKCORE_CLPERFMARKER
2026       clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
2027 #endif
2028
2029       bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2030       unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2031         exception);
2032       resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
2033         exception);
2034
2035 #ifdef MAGICKCORE_CLPERFMARKER
2036       clEndPerfMarkerAMD();
2037 #endif
2038
2039       if (i > 0)
2040         stopAccelerateTimer(&timer);
2041
2042       if (bluredImage)
2043         DestroyImage(bluredImage);
2044       if (unsharpedImage)
2045         DestroyImage(unsharpedImage);
2046       if (resizedImage)
2047         DestroyImage(resizedImage);
2048     }
2049     DestroyImage(inputImage);
2050   }
2051   /* end of microbenchmark */
2052   
2053   if (device->score == NULL)
2054     device->score=malloc(sizeof(AccelerateScoreType));
2055   *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
2056
2057   ReturnStatus(DS_SUCCESS);
2058 }
2059
2060 ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2061   if (device
2062      && device->score) {
2063     /* generate a string from the score */
2064     char* s = (char*)malloc(sizeof(char)*256);
2065     sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2066     *serializedScore = (void*)s;
2067     *serializedScoreSize = strlen(s);
2068     return DS_SUCCESS;
2069   }
2070   else {
2071     return DS_SCORE_SERIALIZER_ERROR;
2072   }
2073 }
2074
2075 ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2076   if (device) {
2077     /* convert the string back to an int */
2078     char* s = (char*)malloc(serializedScoreSize+1);
2079     memcpy(s, serializedScore, serializedScoreSize);
2080     s[serializedScoreSize] = (char)'\0';
2081     device->score = malloc(sizeof(AccelerateScoreType));
2082     *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
2083     free(s);
2084     return DS_SUCCESS;
2085   }
2086   else {
2087     return DS_SCORE_DESERIALIZER_ERROR;
2088   }
2089 }
2090
2091 ds_status AccelerateScoreRelease(void* score) {
2092   if (score!=NULL) {
2093     free(score);
2094   }
2095   return DS_SUCCESS;
2096 }
2097
2098
2099 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2100 #define IMAGEMAGICK_PROFILE_FILE    "ImagemagickOpenCLDeviceProfile"
2101 static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2102
2103   MagickBooleanType mStatus = MagickFalse;
2104   ds_status status;
2105   ds_profile* profile;
2106   unsigned int numDeviceProfiled = 0;
2107   unsigned int i;
2108   unsigned int bestDeviceIndex;
2109   AccelerateScoreType bestScore;
2110   char path[MaxTextExtent];
2111   MagickBooleanType flag;
2112
2113   LockDefaultOpenCLEnv();
2114
2115   /* Initially, just set OpenCL to off */
2116   flag = MagickTrue;
2117   SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2118     , sizeof(MagickBooleanType), &flag, exception);
2119
2120   status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2121   if (status!=DS_SUCCESS) {
2122     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2123     goto cleanup;
2124   }
2125
2126   (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2127          ,GetOpenCLCachedFilesDirectory()
2128          ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2129
2130   readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2131   status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
2132   if (status!=DS_SUCCESS) {
2133     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2134     goto cleanup;
2135   }
2136   if (numDeviceProfiled > 0) {
2137     status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2138     if (status!=DS_SUCCESS) {
2139       (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2140     }
2141   }
2142
2143   /* pick the best device */
2144   bestDeviceIndex = 0;
2145   bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2146   for (i = 1; i < profile->numDevices; i++) {
2147     AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2148     if (score < bestScore) {
2149       bestDeviceIndex = i;
2150       bestScore = score;
2151     }
2152   }
2153
2154   /* set up clEnv with the best device */
2155   if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2156     /* CPU device */
2157     flag = MagickTrue;
2158     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2159                                   , sizeof(MagickBooleanType), &flag, exception);
2160   }
2161   else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2162     /* OpenCL device */
2163     flag = MagickFalse;
2164     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2165       , sizeof(MagickBooleanType), &flag, exception);
2166     SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2167       , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2168   }
2169   else {
2170     status = DS_PERF_EVALUATOR_ERROR;
2171     goto cleanup;
2172   }
2173   mStatus=InitOpenCLEnvInternal(clEnv, exception);
2174
2175   status = releaseDSProfile(profile, AccelerateScoreRelease);
2176   if (status!=DS_SUCCESS) {
2177     (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2178   }
2179
2180 cleanup:
2181
2182   UnlockDefaultOpenCLEnv();
2183   return mStatus;
2184 }
2185
2186
2187 /*
2188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2189 %                                                                             %
2190 %                                                                             %
2191 %                                                                             %
2192 +   I n i t I m a g e M a g i c k O p e n C L                                 %
2193 %                                                                             %
2194 %                                                                             %
2195 %                                                                             %
2196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2197 %
2198 %  InitImageMagickOpenCL() provides a simplified interface to initialize
2199 %  the OpenCL environtment in ImageMagick
2200 %  
2201 %  The format of the InitImageMagickOpenCL() method is:
2202 %
2203 %      MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode, 
2204 %                                        void* userSelectedDevice, 
2205 %                                        void* selectedDevice) 
2206 %
2207 %  A description of each parameter follows:
2208 %
2209 %    o mode: OpenCL mode in ImageMagick, could be off,auto,user
2210 %
2211 %    o userSelectedDevice:  when in user mode, a pointer to the selected
2212 %                           cl_device_id
2213 %
2214 %    o selectedDevice: a pointer to cl_device_id where the selected
2215 %                      cl_device_id by ImageMagick could be returned
2216 %
2217 %    o exception: exception
2218 %
2219 */
2220 MagickExport MagickBooleanType InitImageMagickOpenCL(
2221   ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2222   ExceptionInfo *exception)
2223 {
2224   MagickBooleanType status = MagickTrue;
2225   MagickCLEnv clEnv = NULL;
2226   MagickBooleanType flag;
2227
2228   clEnv = GetDefaultOpenCLEnv();
2229   if (clEnv!=NULL) {
2230     switch(mode) {
2231
2232     case MAGICK_OPENCL_OFF:
2233       flag = MagickTrue;
2234       SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2235         , sizeof(MagickBooleanType), &flag, exception);
2236       status = InitOpenCLEnv(clEnv, exception);
2237
2238       if (selectedDevice)
2239         *(cl_device_id*)selectedDevice = NULL;
2240       break;
2241
2242     case MAGICK_OPENCL_DEVICE_SELECT_USER:
2243
2244       if (userSelectedDevice == NULL)
2245         return MagickFalse;
2246
2247       flag = MagickFalse;
2248       SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2249         , sizeof(MagickBooleanType), &flag, exception);
2250
2251       SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2252         , sizeof(cl_device_id), userSelectedDevice,exception);
2253
2254       status = InitOpenCLEnv(clEnv, exception);
2255       if (selectedDevice) {
2256         GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2257           , sizeof(cl_device_id), selectedDevice, exception);
2258       }
2259       break;
2260
2261     case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2262     default:
2263       {
2264         cl_device_id d = NULL;
2265         flag = MagickFalse;
2266         SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2267           , sizeof(MagickBooleanType), &flag, exception);
2268         SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2269           , sizeof(cl_device_id), &d,exception);
2270         status = InitOpenCLEnv(clEnv, exception);
2271         if (selectedDevice) {
2272           GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2273             , sizeof(cl_device_id),  selectedDevice, exception);
2274         }
2275       }
2276       break;
2277     };
2278   }
2279   return status;
2280 }
2281
2282
2283 MagickExport
2284 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2285   const char *module,const char *function,const size_t line,
2286   const ExceptionType severity,const char *tag,const char *format,...) {
2287   MagickBooleanType
2288     status;
2289
2290   MagickCLEnv clEnv;
2291
2292   status = MagickTrue;
2293
2294   clEnv = GetDefaultOpenCLEnv();
2295
2296   assert(exception != (ExceptionInfo *) NULL);
2297   assert(exception->signature == MagickSignature);
2298
2299   if (severity!=0) {
2300     cl_device_type dType;
2301     clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
2302     if (dType == CL_DEVICE_TYPE_CPU) {
2303       char buffer[MaxTextExtent];
2304       clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
2305
2306       /* Workaround for Intel OpenCL CPU runtime bug */
2307       /* Turn off OpenCL when a problem is detected! */
2308       if (strncmp(buffer, "Intel",5) == 0) {
2309
2310         InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2311       }
2312     }
2313   }
2314
2315 #ifdef OPENCLLOG_ENABLED
2316   {
2317     va_list
2318       operands;
2319     va_start(operands,format);
2320     status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2321     va_end(operands);
2322   }
2323 #else
2324   magick_unreferenced(module);
2325   magick_unreferenced(function);
2326   magick_unreferenced(line);
2327   magick_unreferenced(tag);
2328   magick_unreferenced(format);
2329 #endif
2330
2331   return(status);
2332 }
2333
2334
2335 #else
2336
2337 struct _MagickCLEnv {
2338   MagickBooleanType OpenCLInitialized;  /* whether OpenCL environment is initialized. */
2339 };
2340
2341 extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
2342 {
2343   return NULL;
2344 }
2345
2346 extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
2347   MagickCLEnv magick_unused(clEnv))
2348 {
2349   magick_unreferenced(clEnv);
2350
2351   return MagickFalse;
2352 }
2353
2354 /*
2355 * Return the OpenCL environment
2356 */ 
2357 MagickExport MagickCLEnv GetDefaultOpenCLEnv(
2358   ExceptionInfo *magick_unused(exception))
2359 {
2360   magick_unreferenced(exception);
2361
2362   return (MagickCLEnv) NULL;
2363 }
2364
2365 MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2366   MagickCLEnv magick_unused(clEnv))
2367 {
2368   magick_unreferenced(clEnv);
2369
2370   return (MagickCLEnv) NULL;
2371
2372
2373 MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2374   MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2375   size_t magick_unused(dataSize),void *magick_unused(data),
2376   ExceptionInfo *magick_unused(exception))
2377 {
2378   magick_unreferenced(clEnv);
2379   magick_unreferenced(param);
2380   magick_unreferenced(dataSize);
2381   magick_unreferenced(data);
2382   magick_unreferenced(exception);
2383
2384   return MagickFalse;
2385 }
2386
2387 MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2388   MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2389   size_t magick_unused(dataSize),void *magick_unused(data),
2390   ExceptionInfo *magick_unused(exception))
2391 {
2392   magick_unreferenced(clEnv);
2393   magick_unreferenced(param);
2394   magick_unreferenced(dataSize);
2395   magick_unreferenced(data);
2396   magick_unreferenced(exception);
2397
2398   return MagickFalse;
2399 }
2400
2401 MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2402   ExceptionInfo *magick_unused(exception))
2403 {
2404   magick_unreferenced(clEnv);
2405   magick_unreferenced(exception);
2406
2407   return MagickFalse;
2408 }
2409
2410 MagickExport cl_command_queue AcquireOpenCLCommandQueue(
2411   MagickCLEnv magick_unused(clEnv))
2412 {
2413   magick_unreferenced(clEnv);
2414
2415   return (cl_command_queue) NULL;
2416 }
2417
2418 MagickExport MagickBooleanType RelinquishCommandQueue(
2419   MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2420 {
2421   magick_unreferenced(clEnv);
2422   magick_unreferenced(queue);
2423
2424   return MagickFalse;
2425 }
2426
2427 MagickExport cl_kernel AcquireOpenCLKernel(
2428   MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2429   const char *magick_unused(kernelName))
2430 {
2431   magick_unreferenced(clEnv);
2432   magick_unreferenced(program);
2433   magick_unreferenced(kernelName);
2434
2435   return (cl_kernel)NULL;
2436 }
2437
2438 MagickExport MagickBooleanType RelinquishOpenCLKernel(
2439   MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2440 {
2441   magick_unreferenced(clEnv);
2442   magick_unreferenced(kernel);
2443
2444   return MagickFalse;
2445 }
2446
2447 MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
2448   MagickCLEnv magick_unused(clEnv))
2449 {
2450   magick_unreferenced(clEnv);
2451
2452   return 0;
2453 }
2454
2455 MagickExport MagickBooleanType InitImageMagickOpenCL(
2456   ImageMagickOpenCLMode magick_unused(mode),
2457   void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2458   ExceptionInfo *magick_unused(exception))
2459 {
2460   magick_unreferenced(mode);
2461   magick_unreferenced(userSelectedDevice);
2462   magick_unreferenced(selectedDevice);
2463   magick_unreferenced(exception);
2464   return MagickFalse;
2465 }
2466
2467
2468 MagickExport
2469 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2470   const char *module,const char *function,const size_t line,
2471   const ExceptionType severity,const char *tag,const char *format,...) 
2472 {
2473   magick_unreferenced(exception);
2474   magick_unreferenced(module);
2475   magick_unreferenced(function);
2476   magick_unreferenced(line);
2477   magick_unreferenced(severity);
2478   magick_unreferenced(tag);
2479   magick_unreferenced(format);
2480   return(MagickFalse);
2481 }
2482 #endif /* MAGICKCORE_OPENCL_SUPPORT */
2483
2484 char* openclCachedFilesDirectory;
2485 SemaphoreInfo* openclCachedFilesDirectoryLock;
2486
2487 MagickExport
2488 const char* GetOpenCLCachedFilesDirectory() {
2489   if (openclCachedFilesDirectory == NULL) {
2490     if (openclCachedFilesDirectoryLock == NULL)
2491     {
2492       AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
2493     }
2494     LockSemaphoreInfo(openclCachedFilesDirectoryLock);
2495     if (openclCachedFilesDirectory == NULL) {
2496       char path[MaxTextExtent];
2497       char *home = NULL;
2498       char *temp = NULL;
2499       struct stat attributes;
2500       MagickBooleanType status;
2501
2502 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2503       home=GetEnvironmentValue("LOCALAPPDATA");
2504       if (home == (char *) NULL)
2505         home=GetEnvironmentValue("APPDATA");
2506       if (home == (char *) NULL)
2507         home=GetEnvironmentValue("USERPROFILE");
2508 #else
2509       home=GetEnvironmentValue("HOME");
2510 #endif
2511       if (home != (char *) NULL)
2512       {
2513         /*
2514         Search $HOME/.magick.
2515         */
2516         (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
2517           DirectorySeparator);
2518         home=DestroyString(home);
2519         temp = (char*)AcquireMagickMemory(strlen(path)+1);
2520         CopyMagickString(temp,path,strlen(path)+1);
2521         status=GetPathAttributes(path,&attributes);
2522         if (status == MagickFalse) {
2523 #ifdef MAGICKCORE_WINDOWS_SUPPORT
2524           mkdir(path);
2525 #else
2526           mkdir(path, 0777);
2527 #endif
2528         }
2529       }
2530       openclCachedFilesDirectory = temp;
2531     }
2532     UnlockSemaphoreInfo(openclCachedFilesDirectoryLock); 
2533   }
2534   return openclCachedFilesDirectory;
2535 }
2536
2537 /* create a function for OpenCL log */
2538 MagickExport
2539 void OpenCLLog(const char* message) {
2540
2541 #ifdef OPENCLLOG_ENABLED
2542 #define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
2543
2544   FILE* log;
2545   if (getenv("MAGICK_OCL_LOG"))
2546   {
2547     if (message) {
2548       char path[MaxTextExtent];
2549       unsigned long allocSize;
2550
2551       MagickCLEnv clEnv;
2552
2553       clEnv = GetDefaultOpenCLEnv();
2554
2555       /*  dump the source into a file */
2556       (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
2557         ,GetOpenCLCachedFilesDirectory()
2558         ,DirectorySeparator,OPENCL_LOG_FILE);
2559
2560
2561       log = fopen(path, "ab");
2562       fwrite(message, sizeof(char), strlen(message), log);
2563       fwrite("\n", sizeof(char), 1, log);
2564
2565       if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
2566       {
2567         allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
2568         fprintf(log, "Devic Max Memory Alloc Size: %ld\n", allocSize);
2569       }
2570
2571       fclose(log);
2572     }
2573   }
2574 #else
2575   magick_unreferenced(message);
2576 #endif
2577 }