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