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