]> granicus.if.org Git - imagemagick/blobdiff - MagickCore/opencl.c
Update web pages
[imagemagick] / MagickCore / opencl.c
index b4d9c859e4252e6ace308e3308f69798a24cfb45..a703f27e3df389f0df1ab0ba46fb4c793bf5f584 100644 (file)
@@ -17,7 +17,7 @@
 %                                 March 2000                                  %
 %                                                                             %
 %                                                                             %
-%  Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization      %
+%  Copyright 1999-2015 ImageMagick Studio LLC, a non-profit organization      %
 %  dedicated to making software imaging solutions freely available.           %
 %                                                                             %
 %  You may not use this file except in compliance with the License.  You may  %
@@ -63,6 +63,7 @@ Include declarations.
 #include "MagickCore/montage.h"
 #include "MagickCore/morphology.h"
 #include "MagickCore/nt-base.h"
+#include "MagickCore/nt-base-private.h"
 #include "MagickCore/opencl.h"
 #include "MagickCore/opencl-private.h"
 #include "MagickCore/option.h"
@@ -70,6 +71,8 @@ Include declarations.
 #include "MagickCore/property.h"
 #include "MagickCore/quantize.h"
 #include "MagickCore/quantum.h"
+#include "MagickCore/random_.h"
+#include "MagickCore/random-private.h"
 #include "MagickCore/resample.h"
 #include "MagickCore/resource_.h"
 #include "MagickCore/splay-tree.h"
@@ -86,20 +89,60 @@ Include declarations.
 
 #if defined(MAGICKCORE_OPENCL_SUPPORT)
 
-struct _MagickCLEnv {
-  MagickBooleanType OpenCLInitialized;  /* whether OpenCL environment is initialized. */
-  MagickBooleanType OpenCLDisabled;    /* whether if OpenCL has been explicitely disabled. */
+#ifdef MAGICKCORE_HAVE_OPENCL_CL_H
+#define MAGICKCORE_OPENCL_MACOSX  1
+#endif
 
-  /*OpenCL objects */
-  cl_platform_id platform;
-  cl_device_type deviceType;
-  cl_device_id device;
-  cl_context context;
 
-  cl_program programs[MAGICK_OPENCL_NUM_PROGRAMS]; /* one program object maps one kernel source file */
+#define NUM_CL_RAND_GENERATORS 1024  /* number of random number generators running in parallel */ 
 
-  SemaphoreInfo* lock;
-};
+/*
+ * 
+ * Dynamic library loading functions
+ *
+ */
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+#else
+#include <dlfcn.h>
+#endif
+
+// dynamically load a library.  returns NULL on failure
+void *OsLibraryLoad(const char *libraryName)
+{
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+    return (void *)LoadLibraryA(libraryName);
+#else 
+    return (void *)dlopen(libraryName, RTLD_NOW);
+#endif
+}
+
+// get a function pointer from a loaded library.  returns NULL on failure.
+void *OsLibraryGetFunctionAddress(void *library, const char *functionName)
+{
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+    if (!library || !functionName)
+    {
+        return NULL;
+    }
+    return (void *) GetProcAddress( (HMODULE)library, functionName);
+#else
+    if (!library || !functionName)
+    {
+        return NULL;
+    }
+    return (void *)dlsym(library, functionName);
+#endif
+}
+
+// unload a library.
+void OsLibraryUnload(void *library)
+{
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+    FreeLibrary( (HMODULE)library);
+#else
+    dlclose(library);
+#endif
+}
 
 
 /*
@@ -124,7 +167,7 @@ MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
   if (clEnv != NULL)
   {
     memset(clEnv, 0, sizeof(struct _MagickCLEnv));
-    AcquireSemaphoreInfo(&clEnv->lock);
+    ActivateSemaphoreInfo(&clEnv->lock);
   }
   return clEnv;
 }
@@ -155,9 +198,9 @@ MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
 
 MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
 {
-  if (clEnv != (MagickCLEnv)NULL)
+  if (clEnv != (MagickCLEnv) NULL)
   {
-    RelinquishSemaphoreInfo(clEnv->lock);
+    RelinquishSemaphoreInfo(&clEnv->lock);
     RelinquishMagickMemory(clEnv);
     return MagickTrue;
   }
@@ -171,6 +214,103 @@ MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
 MagickCLEnv defaultCLEnv;
 SemaphoreInfo* defaultCLEnvLock;
 
+/*
+* OpenCL library
+*/
+MagickLibrary * OpenCLLib;
+SemaphoreInfo* OpenCLLibLock;
+
+
+static MagickBooleanType bindOpenCLFunctions(void* library)
+{
+#ifdef MAGICKCORE_OPENCL_MACOSX
+#define BIND(X) OpenCLLib->X= &X;
+#else
+#define BIND(X)\
+  if ((OpenCLLib->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(library,#X)) == NULL)\
+  return MagickFalse;
+#endif
+
+  BIND(clGetPlatformIDs);
+  BIND(clGetPlatformInfo);
+
+  BIND(clGetDeviceIDs);
+  BIND(clGetDeviceInfo);
+
+  BIND(clCreateContext);
+
+  BIND(clCreateBuffer);
+  BIND(clReleaseMemObject);
+
+  BIND(clCreateProgramWithSource);
+  BIND(clCreateProgramWithBinary);
+  BIND(clBuildProgram);
+  BIND(clGetProgramInfo);
+  BIND(clGetProgramBuildInfo);
+
+  BIND(clCreateKernel);
+  BIND(clReleaseKernel);
+  BIND(clSetKernelArg);
+
+  BIND(clFlush);
+  BIND(clFinish);
+
+  BIND(clEnqueueNDRangeKernel);
+  BIND(clEnqueueReadBuffer);
+  BIND(clEnqueueMapBuffer);
+  BIND(clEnqueueUnmapMemObject);
+
+  BIND(clCreateCommandQueue);
+  BIND(clReleaseCommandQueue);
+
+  return MagickTrue;
+}
+
+MagickLibrary * GetOpenCLLib()
+{ 
+  if (OpenCLLib == NULL)
+  {
+    if (OpenCLLibLock == NULL)
+    {
+      ActivateSemaphoreInfo(&OpenCLLibLock);
+    }
+
+    LockSemaphoreInfo(OpenCLLibLock);
+
+    OpenCLLib = (MagickLibrary *) AcquireMagickMemory (sizeof (MagickLibrary));
+
+    if (OpenCLLib != NULL)
+    {
+      MagickBooleanType status = MagickFalse;
+      void * library = NULL;
+
+#ifdef MAGICKCORE_OPENCL_MACOSX
+      status = bindOpenCLFunctions(library);
+#else
+      
+      memset(OpenCLLib, 0, sizeof(MagickLibrary));
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+      library = OsLibraryLoad("OpenCL.dll");
+#else
+      library = OsLibraryLoad("libOpenCL.so");
+#endif
+      if (library)
+        status = bindOpenCLFunctions(library);
+
+      if (status==MagickTrue)
+        OpenCLLib->base=library;
+      else
+        OpenCLLib=(MagickLibrary *)RelinquishMagickMemory(OpenCLLib);
+#endif
+    }
+
+    UnlockSemaphoreInfo(OpenCLLibLock); 
+  }
+  
+
+  return OpenCLLib; 
+}
+
 
 /*
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -201,7 +341,7 @@ MagickExport MagickCLEnv GetDefaultOpenCLEnv()
   {
     if (defaultCLEnvLock == NULL)
     {
-      AcquireSemaphoreInfo(&defaultCLEnvLock);
+      ActivateSemaphoreInfo(&defaultCLEnvLock);
     }
     LockSemaphoreInfo(defaultCLEnvLock);
     defaultCLEnv = AcquireMagickOpenCLEnv();
@@ -213,7 +353,7 @@ MagickExport MagickCLEnv GetDefaultOpenCLEnv()
 static void LockDefaultOpenCLEnv() {
   if (defaultCLEnvLock == NULL)
   {
-    AcquireSemaphoreInfo(&defaultCLEnvLock);
+    ActivateSemaphoreInfo(&defaultCLEnvLock);
   }
   LockSemaphoreInfo(defaultCLEnvLock);
 }
@@ -221,7 +361,7 @@ static void LockDefaultOpenCLEnv() {
 static void UnlockDefaultOpenCLEnv() {
   if (defaultCLEnvLock == NULL)
   {
-    AcquireSemaphoreInfo(&defaultCLEnvLock);
+    ActivateSemaphoreInfo(&defaultCLEnvLock);
   }
   else
     UnlockSemaphoreInfo(defaultCLEnvLock);
@@ -327,6 +467,22 @@ static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, Magi
     (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
     break;
 
+  case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
+    if (dataSize != sizeof(clEnv->disableProgramCache))
+      goto cleanup;
+    clEnv->disableProgramCache =  *((MagickBooleanType*)data);
+    clEnv->OpenCLInitialized = MagickFalse;
+    status = MagickTrue;
+    break;
+
+  case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
+    if (dataSize != sizeof(clEnv->regenerateProfile))
+      goto cleanup;
+    clEnv->regenerateProfile =  *((MagickBooleanType*)data);
+    clEnv->OpenCLInitialized = MagickFalse;
+    status = MagickTrue;
+    break;
+
   default:
     goto cleanup;
   };
@@ -418,6 +574,20 @@ MagickExport
     status = MagickTrue;
     break;
 
+  case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
+    if (dataSize != sizeof(clEnv->disableProgramCache))
+      goto cleanup;
+    *((MagickBooleanType*)data) = clEnv->disableProgramCache;
+    status = MagickTrue;
+    break;
+
+  case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
+    if (dataSize != sizeof(clEnv->regenerateProfile))
+      goto cleanup;
+    *((MagickBooleanType*)data) = clEnv->regenerateProfile;
+    status = MagickTrue;
+    break;
+
   default:
     goto cleanup;
   };
@@ -450,7 +620,7 @@ cleanup:
 %
 */
 
-MagickExport
+MagickPrivate
 cl_context GetOpenCLContext(MagickCLEnv clEnv) {
   if (clEnv == NULL)
     return NULL;
@@ -462,10 +632,10 @@ static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog,
 {
   char* name;
   char* ptr;
-  char path[MaxTextExtent];
-  char deviceName[MaxTextExtent];
+  char path[MagickPathExtent];
+  char deviceName[MagickPathExtent];
   const char* prefix = "magick_opencl";
-  clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
+  clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MagickPathExtent, deviceName, NULL);
   ptr=deviceName;
   /* strip out illegal characters for file names */
   while (*ptr != '\0')
@@ -477,9 +647,9 @@ static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog,
     }
     ptr++;
   }
-  (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s_%s_%02d_%08x.bin"
-         ,GetOpenCLCachedFilesDirectory()
-         ,DirectorySeparator,prefix,deviceName, (unsigned int)prog, signature);
+  (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s_%s_%02d_%08x_%.20g.bin",
+         GetOpenCLCachedFilesDirectory(),DirectorySeparator,prefix,deviceName,
+         (unsigned int) prog,signature,(double) sizeof(char*)*8);
   name = (char*)AcquireMagickMemory(strlen(path)+1);
   CopyMagickString(name,path,strlen(path)+1);
   return name;
@@ -503,7 +673,7 @@ static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProg
   fileHandle = NULL;
   saveSuccessful = MagickFalse;
 
-  clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
+  clStatus = clEnv->library->clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
   if (clStatus != CL_SUCCESS)
   {
     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
@@ -511,7 +681,7 @@ static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProg
   }
 
   binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
-  clStatus = clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
+  clStatus = clEnv->library->clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
   if (clStatus != CL_SUCCESS)
   {
     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
@@ -586,7 +756,7 @@ static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProg
     memset(binaryProgram, 0, length);
     b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
 
-    clEnv->programs[prog] = clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
+    clEnv->programs[prog] = clEnv->library->clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
     if (clStatus != CL_SUCCESS
         || clBinaryStatus != CL_SUCCESS)
       goto cleanup;
@@ -624,7 +794,7 @@ static unsigned int stringSignature(const char* string)
   clBeginPerfMarkerAMD(__FUNCTION__,"");
 #endif
 
-  stringLength = strlen(string);
+  stringLength = (unsigned int) strlen(string);
   signature = stringLength;
   n = stringLength/sizeof(unsigned int);
   p.s = string;
@@ -667,7 +837,7 @@ static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo*
   /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
   const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS]; 
 
-  char options[MaxTextExtent];
+  char options[MagickPathExtent];
   unsigned int optionsSignature;
 
 #ifdef MAGICKCORE_CLPERFMARKER
@@ -675,7 +845,7 @@ static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo*
 #endif
 
   /* Get additional options */
-  (void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
+  (void) FormatLocaleString(options, MagickPathExtent, CLOptions, (float)QuantumRange,
     (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
 
   /*
@@ -704,14 +874,15 @@ static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo*
     unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
 
     /* try to load the binary first */
-    if (!getenv("MAGICK_OCL_REC"))
+    if (clEnv->disableProgramCache != MagickTrue
+        && !getenv("MAGICK_OCL_REC"))
       loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature);
 
     if (loadSuccessful == MagickFalse)
     {
       /* Binary CL program unavailable, compile the program from source */
       size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
-      clEnv->programs[i] = clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
+      clEnv->programs[i] = clEnv->library->clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
       if (clStatus!=CL_SUCCESS)
       {
         (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
@@ -721,7 +892,7 @@ static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo*
       }
     }
 
-    clStatus = clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
+    clStatus = clEnv->library->clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
     if (clStatus!=CL_SUCCESS)
     {
       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
@@ -729,11 +900,11 @@ static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo*
 
       if (loadSuccessful == MagickFalse)
       {
-        char path[MaxTextExtent];
+        char path[MagickPathExtent];
         FILE* fileHandle;
 
         /*  dump the source into a file */
-        (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
+        (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
          ,GetOpenCLCachedFilesDirectory()
          ,DirectorySeparator,"magick_badcl.cl");
         fileHandle = fopen(path, "wb");        
@@ -747,11 +918,11 @@ static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo*
         {
           char* log;
           size_t logSize;
-          clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
+          clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
           log = (char*)AcquireMagickMemory(logSize);
-          clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
+          clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
 
-          (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
+          (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
            ,GetOpenCLCachedFilesDirectory()
            ,DirectorySeparator,"magick_badcl_build.log");
           fileHandle = fopen(path, "wb");      
@@ -826,7 +997,7 @@ static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionIn
 
   if (clEnv->device != NULL)
   {
-    status = clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
+    status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
     if (status != CL_SUCCESS) {
       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
           "Failed to get OpenCL platform from the selected device.", "(%d)", status);
@@ -850,7 +1021,7 @@ static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionIn
     clEnv->device = NULL;
 
     /* Get the number of OpenCL platforms available */
-    status = clGetPlatformIDs(0, NULL, &numPlatforms);
+    status = clEnv->library->clGetPlatformIDs(0, NULL, &numPlatforms);
     if (status != CL_SUCCESS)
     {
       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning, 
@@ -871,7 +1042,7 @@ static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionIn
       goto cleanup;
     }
 
-    status = clGetPlatformIDs(numPlatforms, platforms, NULL);
+    status = clEnv->library->clGetPlatformIDs(numPlatforms, platforms, NULL);
     if (status != CL_SUCCESS)
     {
       (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
@@ -902,12 +1073,22 @@ static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionIn
 
     for (i = 0; i < numPlatforms; i++)
     {
+      char version[MagickPathExtent];
       cl_uint numDevices;
-      status = clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
+      status = clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_VERSION, MagickPathExtent, version, NULL);
+      if (status != CL_SUCCESS)
+      {
+        (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
+          "clGetPlatformInfo failed.", "(%d)", status);
+        goto cleanup;
+      }
+      if (strncmp(version,"OpenCL 1.0 ",11) == 0)
+        continue;
+      status = clEnv->library->clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
       if (status != CL_SUCCESS)
       {
         (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
-          "clGetPlatformIDs failed.", "(%d)", status);
+          "clGetDeviceIDs failed.", "(%d)", status);
         goto cleanup;
       }
       if (clEnv->device != NULL)
@@ -933,7 +1114,7 @@ cleanup:
 }
 
 static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
-  if (clEnv->OpenCLInitialized == MagickTrue
+  if (clEnv->OpenCLInitialized != MagickFalse
     && clEnv->platform != NULL
     && clEnv->device != NULL) {
       clEnv->OpenCLDisabled = MagickFalse;
@@ -976,9 +1157,32 @@ MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* except
   cl_int clStatus;
   cl_context_properties cps[3];
 
-
+#ifdef MAGICKCORE_CLPERFMARKER
+  {
+    int status = clInitializePerfMarkerAMD();
+    if (status == AP_SUCCESS) {
+      //printf("PerfMarker successfully initialized\n");
+    }
+  }
+#endif
   clEnv->OpenCLInitialized = MagickTrue;
-  if (clEnv->OpenCLDisabled == MagickTrue)
+
+  /* check and init the global lib */
+  OpenCLLib=GetOpenCLLib();
+  if (OpenCLLib)
+  {
+    clEnv->library=OpenCLLib;
+  }
+  else
+  {
+    /* turn off opencl */
+    MagickBooleanType flag;
+    flag = MagickTrue;
+    SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
+        , sizeof(MagickBooleanType), &flag, exception);
+  }
+  
+  if (clEnv->OpenCLDisabled != MagickFalse)
     goto cleanup;
 
   clEnv->OpenCLDisabled = MagickTrue;
@@ -993,7 +1197,7 @@ MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* except
   cps[0] = CL_CONTEXT_PLATFORM;
   cps[1] = (cl_context_properties)clEnv->platform;
   cps[2] = 0;
-  clEnv->context = clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
+  clEnv->context = clEnv->library->clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
   if (clStatus != CL_SUCCESS)
   {
     (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
@@ -1012,6 +1216,7 @@ MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* except
   }
 
   status = EnableOpenCLInternal(clEnv);
+
 cleanup:
   return status;
 }
@@ -1068,11 +1273,11 @@ MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
 %
 */
 
-MagickExport
+MagickPrivate
 cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
 {
   if (clEnv != NULL)
-    return clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
+    return clEnv->library->clCreateCommandQueue(clEnv->context, clEnv->device, 0, NULL);
   else
     return NULL;
 }
@@ -1104,12 +1309,12 @@ cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
 %
 %
 */
-MagickExport
+MagickPrivate
 MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_queue queue)
 {
   if (clEnv != NULL)
   {
-    return ((clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
+    return ((clEnv->library->clReleaseCommandQueue(queue) == CL_SUCCESS) ? MagickTrue:MagickFalse);
   }
   else
     return MagickFalse;
@@ -1145,14 +1350,14 @@ MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv, cl_command_que
 %
 */
 
-MagickExport
+MagickPrivate
   cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
 {
   cl_int clStatus;
   cl_kernel kernel = NULL;
   if (clEnv != NULL && kernelName!=NULL)
   {
-    kernel = clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
+    kernel = clEnv->library->clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
   }
   return kernel;
 }
@@ -1185,13 +1390,13 @@ MagickExport
 %
 */
 
-MagickExport
+MagickPrivate
   MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
 {
   MagickBooleanType status = MagickFalse;
   if (clEnv != NULL && kernel != NULL)
   {
-    status = ((clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
+    status = ((clEnv->library->clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
   }
   return status;
 }
@@ -1220,19 +1425,19 @@ MagickExport
 %
 */
 
-MagickExport
+MagickPrivate
  unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
 {
   cl_ulong localMemorySize;
-  clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
+  clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
   return (unsigned long)localMemorySize;
 }
 
-MagickExport
+MagickPrivate
   unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
 {
   cl_ulong maxMemAllocSize;
-  clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
+  clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
   return (unsigned long)maxMemAllocSize;
 }
 
@@ -1265,6 +1470,7 @@ typedef enum {
 
 typedef struct {
   ds_device_type  type;
+  cl_device_type  oclDeviceType;
   cl_device_id    oclDeviceID;
   char*           oclDeviceName;
   char*           oclDriverVersion;
@@ -1329,18 +1535,18 @@ static ds_status initDSProfile(ds_profile** p, const char* version) {
   
   memset(profile, 0, sizeof(ds_profile));
 
-  clGetPlatformIDs(0, NULL, &numPlatforms);
+  OpenCLLib->clGetPlatformIDs(0, NULL, &numPlatforms);
   if (numPlatforms > 0) {
     platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
     if (platforms == NULL) {
       status = DS_MEMORY_ERROR;
       goto cleanup;
     }
-    clGetPlatformIDs(numPlatforms, platforms, NULL);
+    OpenCLLib->clGetPlatformIDs(numPlatforms, platforms, NULL);
     for (i = 0; i < (unsigned int)numPlatforms; i++) {
       cl_uint num;
-      clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num);
-      numDevices+=num;
+      if (OpenCLLib->clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num) == CL_SUCCESS)
+        numDevices+=num;
     }
   }
 
@@ -1378,7 +1584,7 @@ static ds_status initDSProfile(ds_profile** p, const char* version) {
           continue;
           break;
         }
-        if (clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
+        if (OpenCLLib->clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
           continue;
         for (j = 0; j < num; j++, next++) {
           size_t length;
@@ -1386,23 +1592,26 @@ static ds_status initDSProfile(ds_profile** p, const char* version) {
           profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
           profile->devices[next].oclDeviceID = devices[j];
 
-          clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
             , 0, NULL, &length);
           profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
-          clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
             , length, profile->devices[next].oclDeviceName, NULL);
 
-          clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
             , 0, NULL, &length);
           profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
-          clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
             , length, profile->devices[next].oclDriverVersion, NULL);
 
-          clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
             , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
 
-          clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
             , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
+
+          OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_TYPE
+            , sizeof(cl_device_type), &profile->devices[next].oclDeviceType, NULL);
         }
       }
     }
@@ -1791,7 +2000,7 @@ RestoreMSCWarning
         }
         memcpy(tmp,tmpStart,tmpEnd-tmpStart);
         tmp[tmpEnd-tmpStart] = '\0';
-        maxComputeUnits = atoi(tmp);
+        maxComputeUnits = strtol(tmp,(char **) NULL,10);
 
 
         tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
@@ -1807,7 +2016,7 @@ RestoreMSCWarning
         }
         memcpy(tmp,tmpStart,tmpEnd-tmpStart);
         tmp[tmpEnd-tmpStart] = '\0';
-        maxClockFrequency = atoi(tmp);
+        maxClockFrequency = strtol(tmp,(char **) NULL,10);
 
 
         /* check if this device is on the system */
@@ -1889,57 +2098,6 @@ static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* n
 */
 
 
-
-typedef struct _AccelerateTimer {
-  long long _freq;     
-  long long _clocks;
-  long long _start;
-} AccelerateTimer;
-
-static void startAccelerateTimer(AccelerateTimer* timer) {
-#ifdef _WIN32
-      QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start); 
-
-
-#else
-      struct timeval s;
-      gettimeofday(&s, 0);
-      timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
-#endif  
-}
-
-static void stopAccelerateTimer(AccelerateTimer* timer) {
-      long long n=0;
-#ifdef _WIN32
-      QueryPerformanceCounter((LARGE_INTEGER*)&(n));   
-#else
-      struct timeval s;
-      gettimeofday(&s, 0);
-      n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
-#endif
-      n -= timer->_start;
-      timer->_start = 0;
-      timer->_clocks += n;
-}
-
-static void resetAccelerateTimer(AccelerateTimer* timer) {
-   timer->_clocks = 0; 
-   timer->_start = 0;
-}
-
-
-static void initAccelerateTimer(AccelerateTimer* timer) {
-#ifdef _WIN32
-    QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
-#else
-    timer->_freq = (long long)1.0E3;
-#endif
-   resetAccelerateTimer(timer);
-}
-
-double readAccelerateTimer(AccelerateTimer* timer) { return (double)timer->_clocks/(double)timer->_freq; };
-
-
 typedef double AccelerateScoreType;
 
 static ds_status AcceleratePerfEvaluator(ds_device *device,
@@ -1991,6 +2149,9 @@ static ds_status AcceleratePerfEvaluator(ds_device *device,
   else
     ReturnStatus(DS_PERF_EVALUATOR_ERROR);
 
+  /* recompile the OpenCL kernels if it needs to */
+  clEnv->disableProgramCache = defaultCLEnv->disableProgramCache;
+
   InitOpenCLEnvInternal(clEnv,exception);
   oldClEnv=defaultCLEnv;
   defaultCLEnv=clEnv;
@@ -2008,7 +2169,7 @@ static ds_status AcceleratePerfEvaluator(ds_device *device,
 
     imageInfo=AcquireImageInfo();
     CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
-    CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
+    CopyMagickString(imageInfo->filename,"xc:none",MagickPathExtent);
     inputImage=ReadImage(imageInfo,exception);
 
     initAccelerateTimer(&timer);
@@ -2065,7 +2226,7 @@ ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, u
     char* s = (char*)malloc(sizeof(char)*256);
     sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
     *serializedScore = (void*)s;
-    *serializedScoreSize = strlen(s);
+    *serializedScoreSize = (unsigned int) strlen(s);
     return DS_SUCCESS;
   }
   else {
@@ -2080,7 +2241,8 @@ ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* se
     memcpy(s, serializedScore, serializedScoreSize);
     s[serializedScoreSize] = (char)'\0';
     device->score = malloc(sizeof(AccelerateScoreType));
-    *((AccelerateScoreType*)device->score) = (AccelerateScoreType)atof(s);
+    *((AccelerateScoreType*)device->score) = (AccelerateScoreType)
+       strtod(s,(char **) NULL);
     free(s);
     return DS_SUCCESS;
   }
@@ -2096,6 +2258,16 @@ ds_status AccelerateScoreRelease(void* score) {
   return DS_SUCCESS;
 }
 
+ds_status canWriteProfileToFile(const char *path)
+{
+  FILE* profileFile = fopen(path, "ab");
+  if (profileFile==NULL)
+    return DS_FILE_ERROR;
+
+  fclose(profileFile);
+  return DS_SUCCESS;
+}
 
 #define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
 #define IMAGEMAGICK_PROFILE_FILE    "ImagemagickOpenCLDeviceProfile"
@@ -2108,8 +2280,9 @@ static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exce
   unsigned int i;
   unsigned int bestDeviceIndex;
   AccelerateScoreType bestScore;
-  char path[MaxTextExtent];
+  char path[MagickPathExtent];
   MagickBooleanType flag;
+  ds_evaluation_type profileType;
 
   LockDefaultOpenCLEnv();
 
@@ -2118,37 +2291,66 @@ static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exce
   SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
     , sizeof(MagickBooleanType), &flag, exception);
 
+  /* check and init the global lib */
+  OpenCLLib=GetOpenCLLib();
+  if (OpenCLLib==NULL)
+  {
+    mStatus=InitOpenCLEnvInternal(clEnv, exception);
+    goto cleanup;
+  }
+
   status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
   if (status!=DS_SUCCESS) {
     (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
     goto cleanup;
   }
 
-  (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
+  (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
          ,GetOpenCLCachedFilesDirectory()
          ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
 
-  readProfileFromFile(profile, AccelerateScoreDeserializer, path);
-  status = profileDevices(profile, DS_EVALUATE_NEW_ONLY, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
-  if (status!=DS_SUCCESS) {
-    (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
-    goto cleanup;
+  if (canWriteProfileToFile(path) != DS_SUCCESS) {
+    /* We can not write out a device profile, so don't run the benchmark */
+    /* select the first GPU device */
+
+    bestDeviceIndex = 0;
+    for (i = 1; i < profile->numDevices; i++) {
+      if ((profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) && (profile->devices[i].oclDeviceType == CL_DEVICE_TYPE_GPU)) {
+        bestDeviceIndex = i;
+        break;
+      }
+    }
   }
-  if (numDeviceProfiled > 0) {
-    status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
+  else {
+    if (clEnv->regenerateProfile != MagickFalse) {
+      profileType = DS_EVALUATE_ALL;
+    }
+    else {
+      readProfileFromFile(profile, AccelerateScoreDeserializer, path);
+      profileType = DS_EVALUATE_NEW_ONLY;
+    }
+    status = profileDevices(profile, profileType, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
+
     if (status!=DS_SUCCESS) {
-      (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
+      (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
+      goto cleanup;
+    }
+    if (numDeviceProfiled > 0) {
+      status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
+      if (status!=DS_SUCCESS) {
+        (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
+      }
     }
-  }
 
-  /* pick the best device */
-  bestDeviceIndex = 0;
-  bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
-  for (i = 1; i < profile->numDevices; i++) {
-    AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
-    if (score < bestScore) {
-      bestDeviceIndex = i;
-      bestScore = score;
+    /* pick the best device */
+    bestDeviceIndex = 0;
+    bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
+    for (i = 1; i < profile->numDevices; i++) {
+      AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
+      if (score < bestScore) {
+        bestDeviceIndex = i;
+        bestScore = score;
+      }
     }
   }
 
@@ -2222,7 +2424,7 @@ MagickExport MagickBooleanType InitImageMagickOpenCL(
   ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
   ExceptionInfo *exception)
 {
-  MagickBooleanType status = MagickTrue;
+  MagickBooleanType status = MagickFalse;
   MagickCLEnv clEnv = NULL;
   MagickBooleanType flag;
 
@@ -2259,6 +2461,15 @@ MagickExport MagickBooleanType InitImageMagickOpenCL(
       }
       break;
 
+    case MAGICK_OPENCL_DEVICE_SELECT_AUTO_CLEAR_CACHE:
+        flag = MagickTrue;
+        SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED
+          , sizeof(MagickBooleanType), &flag, exception);
+        flag = MagickTrue;
+        SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE
+          , sizeof(MagickBooleanType), &flag, exception);
+
+    /* fall through here!! */
     case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
     default:
       {
@@ -2281,7 +2492,7 @@ MagickExport MagickBooleanType InitImageMagickOpenCL(
 }
 
 
-MagickExport
+MagickPrivate
 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
   const char *module,const char *function,const size_t line,
   const ExceptionType severity,const char *tag,const char *format,...) {
@@ -2295,14 +2506,14 @@ MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
   clEnv = GetDefaultOpenCLEnv();
 
   assert(exception != (ExceptionInfo *) NULL);
-  assert(exception->signature == MagickSignature);
+  assert(exception->signature == MagickCoreSignature);
 
   if (severity!=0) {
     cl_device_type dType;
-    clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
+    clEnv->library->clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
     if (dType == CL_DEVICE_TYPE_CPU) {
-      char buffer[MaxTextExtent];
-      clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
+      char buffer[MagickPathExtent];
+      clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MagickPathExtent, buffer, NULL);
 
       /* Workaround for Intel OpenCL CPU runtime bug */
       /* Turn off OpenCL when a problem is detected! */
@@ -2332,6 +2543,88 @@ MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
   return(status);
 }
 
+MagickPrivate cl_mem GetAndLockRandSeedBuffer(MagickCLEnv clEnv)
+{ 
+  LockSemaphoreInfo(clEnv->lock);
+  if (clEnv->seedsLock == NULL)
+  {
+    ActivateSemaphoreInfo(&clEnv->seedsLock);
+  }
+  LockSemaphoreInfo(clEnv->seedsLock);
+
+  if (clEnv->seeds == NULL)
+  {
+    cl_int clStatus;
+    clEnv->numGenerators = NUM_CL_RAND_GENERATORS;
+    clEnv->seeds = clEnv->library->clCreateBuffer(clEnv->context, CL_MEM_READ_WRITE,
+                                  clEnv->numGenerators*4*sizeof(unsigned int),
+                                  NULL, &clStatus);
+    if (clStatus != CL_SUCCESS)
+    {
+      clEnv->seeds = NULL;
+    }
+    else
+    {
+      unsigned int i;
+      cl_command_queue queue = NULL;
+      unsigned int *seeds;
+
+      queue = AcquireOpenCLCommandQueue(clEnv);
+      seeds = (unsigned int*) clEnv->library->clEnqueueMapBuffer(queue, clEnv->seeds, CL_TRUE, 
+                                                  CL_MAP_WRITE, 0,
+                                                  clEnv->numGenerators*4
+                                                  *sizeof(unsigned int),
+                                                  0, NULL, NULL, &clStatus);
+      if (clStatus!=CL_SUCCESS)
+      {
+        clEnv->library->clReleaseMemObject(clEnv->seeds);
+        goto cleanup;
+      }
+
+      for (i = 0; i < clEnv->numGenerators; i++) {
+        RandomInfo* randomInfo = AcquireRandomInfo();
+        const unsigned long* s = GetRandomInfoSeed(randomInfo);
+        if (i == 0)
+          clEnv->randNormalize = GetRandomInfoNormalize(randomInfo);
+
+        seeds[i*4]   = (unsigned int) s[0];
+        seeds[i*4+1] = (unsigned int) 0x50a7f451;
+        seeds[i*4+2] = (unsigned int) 0x5365417e;
+        seeds[i*4+3] = (unsigned int) 0xc3a4171a;
+
+        randomInfo = DestroyRandomInfo(randomInfo);
+      }
+      clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, clEnv->seeds, seeds, 0, 
+                                          NULL, NULL);
+      clEnv->library->clFinish(queue);
+cleanup:
+      if (queue != NULL) 
+        RelinquishOpenCLCommandQueue(clEnv, queue);
+    }
+  }
+  UnlockSemaphoreInfo(clEnv->lock);
+  return clEnv->seeds; 
+}
+
+MagickPrivate void UnlockRandSeedBuffer(MagickCLEnv clEnv) {
+  if (clEnv->seedsLock == NULL)
+  {
+    ActivateSemaphoreInfo(&clEnv->seedsLock);
+  }
+  else
+    UnlockSemaphoreInfo(clEnv->seedsLock);
+}
+
+MagickPrivate unsigned int GetNumRandGenerators(MagickCLEnv clEnv)
+{
+  return clEnv->numGenerators;
+}
+
+
+MagickPrivate float GetRandNormalize(MagickCLEnv clEnv)
+{
+  return clEnv->randNormalize;
+}
 
 #else
 
@@ -2339,12 +2632,12 @@ struct _MagickCLEnv {
   MagickBooleanType OpenCLInitialized;  /* whether OpenCL environment is initialized. */
 };
 
-extern MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
+MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
 {
   return NULL;
 }
 
-extern MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
+MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
   MagickCLEnv magick_unused(clEnv))
 {
   magick_unreferenced(clEnv);
@@ -2408,7 +2701,7 @@ MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
   return MagickFalse;
 }
 
-MagickExport cl_command_queue AcquireOpenCLCommandQueue(
+MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(
   MagickCLEnv magick_unused(clEnv))
 {
   magick_unreferenced(clEnv);
@@ -2416,7 +2709,7 @@ MagickExport cl_command_queue AcquireOpenCLCommandQueue(
   return (cl_command_queue) NULL;
 }
 
-MagickExport MagickBooleanType RelinquishCommandQueue(
+MagickPrivate MagickBooleanType RelinquishCommandQueue(
   MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
 {
   magick_unreferenced(clEnv);
@@ -2425,7 +2718,7 @@ MagickExport MagickBooleanType RelinquishCommandQueue(
   return MagickFalse;
 }
 
-MagickExport cl_kernel AcquireOpenCLKernel(
+MagickPrivate cl_kernel AcquireOpenCLKernel(
   MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
   const char *magick_unused(kernelName))
 {
@@ -2433,10 +2726,10 @@ MagickExport cl_kernel AcquireOpenCLKernel(
   magick_unreferenced(program);
   magick_unreferenced(kernelName);
 
-  return (cl_kernel)NULL;
+  return (cl_kernel) NULL;
 }
 
-MagickExport MagickBooleanType RelinquishOpenCLKernel(
+MagickPrivate MagickBooleanType RelinquishOpenCLKernel(
   MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
 {
   magick_unreferenced(clEnv);
@@ -2445,7 +2738,7 @@ MagickExport MagickBooleanType RelinquishOpenCLKernel(
   return MagickFalse;
 }
 
-MagickExport unsigned long GetOpenCLDeviceLocalMemorySize(
+MagickPrivate unsigned long GetOpenCLDeviceLocalMemorySize(
   MagickCLEnv magick_unused(clEnv))
 {
   magick_unreferenced(clEnv);
@@ -2466,7 +2759,7 @@ MagickExport MagickBooleanType InitImageMagickOpenCL(
 }
 
 
-MagickExport
+MagickPrivate
 MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
   const char *module,const char *function,const size_t line,
   const ExceptionType severity,const char *tag,const char *format,...) 
@@ -2480,53 +2773,111 @@ MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
   magick_unreferenced(format);
   return(MagickFalse);
 }
+
+
+MagickPrivate cl_mem GetAndLockRandSeedBuffer(MagickCLEnv clEnv)
+{
+  magick_unreferenced(clEnv);
+  return NULL;
+}
+
+
+MagickPrivate void UnlockRandSeedBuffer(MagickCLEnv clEnv)
+{
+  magick_unreferenced(clEnv);
+}
+
+MagickPrivate unsigned int GetNumRandGenerators(MagickCLEnv clEnv)
+{
+  magick_unreferenced(clEnv);
+  return 0;
+}
+
+MagickPrivate float GetRandNormalize(MagickCLEnv clEnv)
+{
+  magick_unreferenced(clEnv);
+  return 0.0f;
+}
+
 #endif /* MAGICKCORE_OPENCL_SUPPORT */
 
 char* openclCachedFilesDirectory;
 SemaphoreInfo* openclCachedFilesDirectoryLock;
 
-MagickExport
+MagickPrivate
 const char* GetOpenCLCachedFilesDirectory() {
   if (openclCachedFilesDirectory == NULL) {
     if (openclCachedFilesDirectoryLock == NULL)
     {
-      AcquireSemaphoreInfo(&openclCachedFilesDirectoryLock);
+      ActivateSemaphoreInfo(&openclCachedFilesDirectoryLock);
     }
     LockSemaphoreInfo(openclCachedFilesDirectoryLock);
     if (openclCachedFilesDirectory == NULL) {
-      char path[MaxTextExtent];
+      char path[MagickPathExtent];
       char *home = NULL;
       char *temp = NULL;
       struct stat attributes;
       MagickBooleanType status;
 
-#ifdef MAGICKCORE_WINDOWS_SUPPORT
-      home=GetEnvironmentValue("LOCALAPPDATA");
-      if (home == (char *) NULL)
-        home=GetEnvironmentValue("APPDATA");
+
+
+      home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
       if (home == (char *) NULL)
-        home=GetEnvironmentValue("USERPROFILE");
+      {
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+        home=GetEnvironmentValue("LOCALAPPDATA");
+        if (home == (char *) NULL)
+          home=GetEnvironmentValue("APPDATA");
+        if (home == (char *) NULL)
+          home=GetEnvironmentValue("USERPROFILE");
 #else
-      home=GetEnvironmentValue("HOME");
+        home=GetEnvironmentValue("HOME");
 #endif
+      }
+      
       if (home != (char *) NULL)
       {
+        int mkdirStatus = 0;
         /*
-        Search $HOME/.magick.
         */
-        (void) FormatLocaleString(path,MaxTextExtent,"%s%s.magick",home,
-          DirectorySeparator);
-        home=DestroyString(home);
-        temp = (char*)AcquireMagickMemory(strlen(path)+1);
-        CopyMagickString(temp,path,strlen(path)+1);
+
+        /* first check if $HOME/.config exists */
+        (void) FormatLocaleString(path,MagickPathExtent,"%s%s.config",
+          home,DirectorySeparator);
         status=GetPathAttributes(path,&attributes);
-        if (status == MagickFalse) {
+        if (status == MagickFalse) 
+        {
+          
+#ifdef MAGICKCORE_WINDOWS_SUPPORT
+          mkdirStatus = mkdir(path);
+#else
+          mkdirStatus = mkdir(path, 0777);
+#endif
+        }
+        
+        /* first check if $HOME/.config/ImageMagick exists */
+        if (mkdirStatus==0) 
+        {
+            (void) FormatLocaleString(path,MagickPathExtent,"%s%s.config%sImageMagick",
+              home,DirectorySeparator,DirectorySeparator);
+                    
+            status=GetPathAttributes(path,&attributes);
+            if (status == MagickFalse) 
+            {
 #ifdef MAGICKCORE_WINDOWS_SUPPORT
-          mkdir(path);
+              mkdirStatus = mkdir(path);
 #else
-          mkdir(path, 0777);
+              mkdirStatus = mkdir(path, 0777);
 #endif
+            }
+        }
+
+        if (mkdirStatus==0)
+        {
+          temp = (char*)AcquireMagickMemory(strlen(path)+1);
+          CopyMagickString(temp,path,strlen(path)+1);
         }
+        home=DestroyString(home);
       }
       openclCachedFilesDirectory = temp;
     }
@@ -2535,8 +2886,54 @@ const char* GetOpenCLCachedFilesDirectory() {
   return openclCachedFilesDirectory;
 }
 
+void startAccelerateTimer(AccelerateTimer* timer) {
+#ifdef _WIN32
+      QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start); 
+
+
+#else
+      struct timeval s;
+      gettimeofday(&s, 0);
+      timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
+#endif  
+}
+
+void stopAccelerateTimer(AccelerateTimer* timer) {
+      long long n=0;
+#ifdef _WIN32
+      QueryPerformanceCounter((LARGE_INTEGER*)&(n));   
+#else
+      struct timeval s;
+      gettimeofday(&s, 0);
+      n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
+#endif
+      n -= timer->_start;
+      timer->_start = 0;
+      timer->_clocks += n;
+}
+
+void resetAccelerateTimer(AccelerateTimer* timer) {
+   timer->_clocks = 0; 
+   timer->_start = 0;
+}
+
+
+void initAccelerateTimer(AccelerateTimer* timer) {
+#ifdef _WIN32
+    QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
+#else
+    timer->_freq = (long long)1.0E3;
+#endif
+   resetAccelerateTimer(timer);
+}
+
+double readAccelerateTimer(AccelerateTimer* timer) { 
+  return (double)timer->_clocks/(double)timer->_freq; 
+};
+
+
 /* create a function for OpenCL log */
-MagickExport
+MagickPrivate
 void OpenCLLog(const char* message) {
 
 #ifdef OPENCLLOG_ENABLED
@@ -2546,7 +2943,7 @@ void OpenCLLog(const char* message) {
   if (getenv("MAGICK_OCL_LOG"))
   {
     if (message) {
-      char path[MaxTextExtent];
+      char path[MagickPathExtent];
       unsigned long allocSize;
 
       MagickCLEnv clEnv;
@@ -2554,7 +2951,7 @@ void OpenCLLog(const char* message) {
       clEnv = GetDefaultOpenCLEnv();
 
       /*  dump the source into a file */
-      (void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
+      (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
         ,GetOpenCLCachedFilesDirectory()
         ,DirectorySeparator,OPENCL_LOG_FILE);
 
@@ -2576,3 +2973,5 @@ void OpenCLLog(const char* message) {
   magick_unreferenced(message);
 #endif
 }
+
+