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