imagemagick/magick/opencl.c

3106 lines
95 KiB
C
Raw Normal View History

2023-02-03 21:16:55 +08:00
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% OOO PPPP EEEEE N N CCCC L %
% O O P P E NN N C L %
% O O PPPP EEE N N N C L %
% O O P E N NN C L %
% OOO P EEEEE N N CCCC LLLLL %
% %
% %
% MagickCore OpenCL Methods %
% %
% Software Design %
% Cristy %
% March 2000 %
% %
% %
% Copyright 1999-2021 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 %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
%
*/
/*
Include declarations.
*/
#include "magick/studio.h"
#include "magick/artifact.h"
#include "magick/cache.h"
#include "magick/cache-private.h"
#include "magick/color.h"
#include "magick/compare.h"
#include "magick/constitute.h"
#include "magick/distort.h"
#include "magick/draw.h"
#include "magick/effect.h"
#include "magick/exception.h"
#include "magick/exception-private.h"
#include "magick/fx.h"
#include "magick/gem.h"
#include "magick/geometry.h"
#include "magick/image.h"
#include "magick/image-private.h"
#include "magick/layer.h"
#include "magick/mime-private.h"
#include "magick/memory_.h"
#include "magick/memory-private.h"
#include "magick/monitor.h"
#include "magick/montage.h"
#include "magick/morphology.h"
#include "magick/nt-base.h"
#include "magick/nt-base-private.h"
#include "magick/opencl.h"
#include "magick/opencl-private.h"
#include "magick/option.h"
#include "magick/policy.h"
#include "magick/property.h"
#include "magick/quantize.h"
#include "magick/quantum.h"
#include "magick/random_.h"
#include "magick/random-private.h"
#include "magick/resample.h"
#include "magick/resource_.h"
#include "magick/splay-tree.h"
#include "magick/semaphore.h"
#include "magick/statistic.h"
#include "magick/string_.h"
#include "magick/token.h"
#include "magick/utility.h"
#include "magick/utility-private.h"
#ifdef MAGICKCORE_CLPERFMARKER
#include "CLPerfMarker.h"
#endif
#if defined(MAGICKCORE_OPENCL_SUPPORT)
#ifdef MAGICKCORE_HAVE_OPENCL_CL_H
#define MAGICKCORE_OPENCL_MACOSX 1
#endif
#define NUM_CL_RAND_GENERATORS 1024 /* number of random number generators running in parallel */
#define PROFILE_OCL_KERNELS 0
typedef struct
{
cl_ulong min;
cl_ulong max;
cl_ulong total;
cl_ulong count;
} KernelProfileRecord;
static const char *kernelNames[] = {
"AddNoise",
"BlurRow",
"BlurColumn",
"Composite",
"ComputeFunction",
"Contrast",
"ContrastStretch",
"Convolve",
"Equalize",
"GrayScale",
"Histogram",
"HullPass1",
"HullPass2",
"LocalContrastBlurRow",
"LocalContrastBlurApplyColumn",
"Modulate",
"MotionBlur",
"RadialBlur",
"RandomNumberGenerator",
"ResizeHorizontal",
"ResizeVertical",
"UnsharpMaskBlurColumn",
"UnsharpMask",
"WaveletDenoise",
"NONE" };
KernelProfileRecord
profileRecords[KERNEL_COUNT];
typedef struct _AccelerateTimer {
long long _freq;
long long _clocks;
long long _start;
} AccelerateTimer;
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;
};
MagickPrivate MagickBooleanType RecordProfileData(MagickCLEnv clEnv, ProfiledKernels kernel, cl_event event)
{
#if PROFILE_OCL_KERNELS
cl_int status;
cl_ulong start = 0;
cl_ulong end = 0;
cl_ulong elapsed = 0;
clEnv->library->clWaitForEvents(1, &event);
status = clEnv->library->clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL);
status &= clEnv->library->clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL);
if (status == CL_SUCCESS) {
start /= 1000; // usecs
end /= 1000; // usecs
elapsed = end - start;
/* we can use the commandQueuesLock to make the code below thread safe */
LockSemaphoreInfo(clEnv->commandQueuesLock);
if ((elapsed < profileRecords[kernel].min) || (profileRecords[kernel].count == 0))
profileRecords[kernel].min = elapsed;
if (elapsed > profileRecords[kernel].max)
profileRecords[kernel].max = elapsed;
profileRecords[kernel].total += elapsed;
profileRecords[kernel].count += 1;
UnlockSemaphoreInfo(clEnv->commandQueuesLock);
}
return(MagickTrue);
#else
magick_unreferenced(clEnv);
magick_unreferenced(kernel);
magick_unreferenced(event);
return(MagickFalse);
#endif
}
void DumpProfileData()
{
#if PROFILE_OCL_KERNELS
int i;
OpenCLLog("====================================================");
/*
Write out the device info to the profile.
*/
if (0 == 1)
{
MagickCLEnv clEnv;
char buff[2048];
cl_int status;
clEnv = GetDefaultOpenCLEnv();
status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_VENDOR, 2048, buff, NULL);
OpenCLLog(buff);
status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, 2048, buff, NULL);
OpenCLLog(buff);
status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DRIVER_VERSION, 2048, buff, NULL);
OpenCLLog(buff);
}
OpenCLLog("====================================================");
OpenCLLog(" ave\tcalls \tmin -> max");
OpenCLLog(" ---\t----- \t----------");
for (i = 0; i < KERNEL_COUNT; ++i) {
char buf[4096];
char indent[160];
strcpy(indent, " ");
strncpy(indent, kernelNames[i], min(strlen(kernelNames[i]), strlen(indent) - 1));
sprintf(buf, "%s%d\t(%d calls) \t%d -> %d", indent, profileRecords[i].count > 0 ? (profileRecords[i].total / profileRecords[i].count) : 0, profileRecords[i].count, profileRecords[i].min, profileRecords[i].max);
/*
printf("%s%d\t(%d calls) \t%d -> %d\n", indent, profileRecords[i].count > 0 ? (profileRecords[i].total / profileRecords[i].count) : 0, profileRecords[i].count, profileRecords[i].min, profileRecords[i].max);
*/
OpenCLLog(buf);
}
OpenCLLog("====================================================");
#endif
}
/*
*
* 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
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A c q u i r e M a g i c k O p e n C L E n v %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure.
%
*/
MagickPrivate MagickCLEnv AcquireMagickOpenCLEnv()
{
MagickCLEnv clEnv;
clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
if (clEnv != NULL)
{
memset(clEnv, 0, sizeof(struct _MagickCLEnv));
clEnv->commandQueuesPos=-1;
ActivateSemaphoreInfo(&clEnv->lock);
ActivateSemaphoreInfo(&clEnv->commandQueuesLock);
}
return clEnv;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ 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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
%
% The format of the RelinquishMagickOpenCLEnv method is:
%
% MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
%
% A description of each parameter follows:
%
% o clEnv: MagickCLEnv structure to destroy
%
*/
MagickPrivate MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
{
if (clEnv != (MagickCLEnv) NULL)
{
while (clEnv->commandQueuesPos >= 0)
{
clEnv->library->clReleaseCommandQueue(
clEnv->commandQueues[clEnv->commandQueuesPos--]);
}
if (clEnv->programs[0] != (cl_program) NULL)
(void) clEnv->library->clReleaseProgram(clEnv->programs[0]);
if (clEnv->context != (cl_context) NULL)
clEnv->library->clReleaseContext(clEnv->context);
DestroySemaphoreInfo(&clEnv->lock);
DestroySemaphoreInfo(&clEnv->commandQueuesLock);
RelinquishMagickMemory(clEnv);
return MagickTrue;
}
return MagickFalse;
}
/*
* Default OpenCL environment
*/
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(clReleaseContext);
BIND(clCreateBuffer);
BIND(clRetainMemObject);
BIND(clReleaseMemObject);
BIND(clCreateProgramWithSource);
BIND(clCreateProgramWithBinary);
BIND(clBuildProgram);
BIND(clReleaseProgram);
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);
BIND(clGetEventProfilingInfo);
BIND(clGetEventInfo);
BIND(clWaitForEvents);
BIND(clReleaseEvent);
BIND(clRetainEvent);
BIND(clSetEventCallback);
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;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t D e f a u l t O p e n C L E n v %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetDefaultOpenCLEnv() returns the default OpenCL env
%
% The format of the GetDefaultOpenCLEnv method is:
%
% MagickCLEnv GetDefaultOpenCLEnv()
%
% A description of each parameter follows:
%
% o exception: return any errors or warnings.
%
*/
MagickExport MagickCLEnv GetDefaultOpenCLEnv()
{
if (defaultCLEnv == NULL)
{
if (defaultCLEnvLock == NULL)
{
ActivateSemaphoreInfo(&defaultCLEnvLock);
}
LockSemaphoreInfo(defaultCLEnvLock);
if (defaultCLEnv == NULL)
defaultCLEnv = AcquireMagickOpenCLEnv();
UnlockSemaphoreInfo(defaultCLEnvLock);
}
return defaultCLEnv;
}
static void LockDefaultOpenCLEnv() {
if (defaultCLEnvLock == NULL)
{
ActivateSemaphoreInfo(&defaultCLEnvLock);
}
LockSemaphoreInfo(defaultCLEnvLock);
}
static void UnlockDefaultOpenCLEnv() {
if (defaultCLEnvLock == NULL)
{
ActivateSemaphoreInfo(&defaultCLEnvLock);
}
else
UnlockSemaphoreInfo(defaultCLEnvLock);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ S e t D e f a u l t O p e n C L E n v %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SetDefaultOpenCLEnv() sets the new OpenCL environment as default
% and returns the old OpenCL environment
%
% The format of the SetDefaultOpenCLEnv() method is:
%
% MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
%
% A description of each parameter follows:
%
% o clEnv: the new default OpenCL environment.
%
*/
MagickPrivate MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
{
MagickCLEnv oldEnv;
LockDefaultOpenCLEnv();
oldEnv = defaultCLEnv;
defaultCLEnv = clEnv;
UnlockDefaultOpenCLEnv();
return oldEnv;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ S e t M a g i c k O p e n C L E n v P a r a m %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
%
% The format of the SetMagickOpenCLEnvParam() method is:
%
% MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
% MagickOpenCLEnvParam param, size_t dataSize, void* data,
% ExceptionInfo* exception)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
% o param: the parameter to be set.
%
% o dataSize: the data size of the parameter value.
%
% o data: the pointer to the new parameter value
%
% o exception: return any errors or warnings
%
*/
static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
, size_t dataSize, void* data, ExceptionInfo* exception)
{
MagickBooleanType status = MagickFalse;
if (clEnv == NULL
|| data == NULL)
goto cleanup;
switch(param)
{
case MAGICK_OPENCL_ENV_PARAM_DEVICE:
if (dataSize != sizeof(clEnv->device))
goto cleanup;
clEnv->device = *((cl_device_id*)data);
clEnv->OpenCLInitialized = MagickFalse;
status = MagickTrue;
break;
case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
if (dataSize != sizeof(clEnv->OpenCLDisabled))
goto cleanup;
clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
clEnv->OpenCLInitialized = MagickFalse;
status = MagickTrue;
break;
case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
(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;
};
cleanup:
return status;
}
MagickExport
MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
, size_t dataSize, void* data, ExceptionInfo* exception) {
MagickBooleanType status = MagickFalse;
if (clEnv!=NULL) {
LockSemaphoreInfo(clEnv->lock);
status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
UnlockSemaphoreInfo(clEnv->lock);
}
return status;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t M a g i c k O p e n C L E n v P a r a m %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
%
% The format of the GetMagickOpenCLEnvParam() method is:
%
% MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
% MagickOpenCLEnvParam param, size_t dataSize, void* data,
% ExceptionInfo* exception)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
% o param: the parameter to be returned.
%
% o dataSize: the data size of the parameter value.
%
% o data: the location where the returned parameter value will be stored
%
% o exception: return any errors or warnings
%
*/
MagickExport
MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
, size_t dataSize, void* data, ExceptionInfo* exception)
{
MagickBooleanType
status;
size_t
length;
magick_unreferenced(exception);
status = MagickFalse;
if (clEnv == NULL
|| data == NULL)
goto cleanup;
switch(param)
{
case MAGICK_OPENCL_ENV_PARAM_DEVICE:
if (dataSize != sizeof(cl_device_id))
goto cleanup;
*((cl_device_id*)data) = clEnv->device;
status = MagickTrue;
break;
case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
if (dataSize != sizeof(clEnv->OpenCLDisabled))
goto cleanup;
*((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
status = MagickTrue;
break;
case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
if (dataSize != sizeof(clEnv->OpenCLDisabled))
goto cleanup;
*((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
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;
case MAGICK_OPENCL_ENV_PARAM_PLATFORM_VENDOR:
if (dataSize != sizeof(char *))
goto cleanup;
clEnv->library->clGetPlatformInfo(clEnv->platform,CL_PLATFORM_VENDOR,0,
NULL,&length);
*((char **) data)=(char *) AcquireQuantumMemory(length,sizeof(char));
clEnv->library->clGetPlatformInfo(clEnv->platform,CL_PLATFORM_VENDOR,
length,*((char **) data),NULL);
status = MagickTrue;
break;
case MAGICK_OPENCL_ENV_PARAM_DEVICE_NAME:
if (dataSize != sizeof(char *))
goto cleanup;
clEnv->library->clGetDeviceInfo(clEnv->device,CL_DEVICE_NAME,0,NULL,
&length);
*((char **) data)=(char *) AcquireQuantumMemory(length,sizeof(char));
clEnv->library->clGetDeviceInfo(clEnv->device,CL_DEVICE_NAME,length,
*((char **) data),NULL);
status = MagickTrue;
break;
default:
goto cleanup;
};
cleanup:
return status;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ G e t O p e n C L C o n t e x t %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetOpenCLContext() returns the OpenCL context
%
% The format of the GetOpenCLContext() method is:
%
% cl_context GetOpenCLContext(MagickCLEnv clEnv)
%
% A description of each parameter follows:
%
% o clEnv: OpenCL environment
%
*/
MagickPrivate
cl_context GetOpenCLContext(MagickCLEnv clEnv) {
if (clEnv == NULL)
return NULL;
else
return clEnv->context;
}
static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
{
char* name;
char* ptr;
char path[MaxTextExtent];
char deviceName[MaxTextExtent];
const char* prefix = "magick_opencl";
clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MaxTextExtent, deviceName, NULL);
ptr=deviceName;
/* strip out illegal characters for file names */
while (*ptr != '\0')
{
if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
|| *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
{
*ptr = '_';
}
ptr++;
}
(void) FormatLocaleString(path,MaxTextExtent,"%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;
}
static void saveBinaryCLProgram(MagickCLEnv clEnv,MagickOpenCLProgram prog,
unsigned int signature,ExceptionInfo* exception)
{
char
*filename;
cl_int
status;
cl_uint
num_devices;
size_t
i,
size,
*program_sizes;
filename=getBinaryCLProgramName(clEnv,prog,signature);
status=clEnv->library->clGetProgramInfo(clEnv->programs[prog],
CL_PROGRAM_NUM_DEVICES,sizeof(cl_uint),&num_devices,NULL);
if (status != CL_SUCCESS)
return;
size=num_devices*sizeof(*program_sizes);
program_sizes=(size_t*) AcquireQuantumMemory(1,size);
if (program_sizes == (size_t*) NULL)
return;
status=clEnv->library->clGetProgramInfo(clEnv->programs[prog],
CL_PROGRAM_BINARY_SIZES,size,program_sizes,NULL);
if (status == CL_SUCCESS)
{
size_t
binary_program_size;
unsigned char
**binary_program;
binary_program_size=num_devices*sizeof(*binary_program);
binary_program=(unsigned char **) AcquireQuantumMemory(1,
binary_program_size);
if (binary_program == (unsigned char **) NULL)
{
program_sizes=(size_t *) RelinquishMagickMemory(program_sizes);
return;
}
for (i = 0; i < num_devices; i++)
{
binary_program[i]=AcquireQuantumMemory(MagickMax(*(program_sizes+i),1),
sizeof(**binary_program));
if (binary_program[i] == (unsigned char *) NULL)
{
status=CL_OUT_OF_HOST_MEMORY;
break;
}
}
if (status == CL_SUCCESS)
status=clEnv->library->clGetProgramInfo(clEnv->programs[prog],
CL_PROGRAM_BINARIES,binary_program_size,binary_program,NULL);
if (status == CL_SUCCESS)
{
for (i = 0; i < num_devices; i++)
{
int
file;
size_t
program_size;
program_size=*(program_sizes+i);
if (program_size < 1)
continue;
file=open_utf8(filename,O_WRONLY | O_CREAT | O_BINARY,S_MODE);
if (file != -1)
{
write(file,binary_program[i],program_size);
file=close(file);
}
else
(void) ThrowMagickException(exception,GetMagickModule(),
DelegateWarning,"Saving kernel failed.","`%s'",filename);
break;
}
}
for (i = 0; i < num_devices; i++)
binary_program[i]=(unsigned char *) RelinquishMagickMemory(
binary_program[i]);
binary_program=(unsigned char **) RelinquishMagickMemory(binary_program);
}
program_sizes=(size_t *) RelinquishMagickMemory(program_sizes);
}
static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
{
MagickBooleanType loadSuccessful;
unsigned char* binaryProgram;
char* binaryFileName;
FILE* fileHandle;
#ifdef MAGICKCORE_CLPERFMARKER
clBeginPerfMarkerAMD(__FUNCTION__,"");
#endif
binaryProgram = NULL;
binaryFileName = NULL;
fileHandle = NULL;
loadSuccessful = MagickFalse;
binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
fileHandle = fopen(binaryFileName, "rb");
if (fileHandle != NULL)
{
int b_error;
size_t length;
cl_int clStatus;
cl_int clBinaryStatus;
b_error = 0 ;
length = 0;
b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
b_error |= ( length = ftell( fileHandle ) ) <= 0;
b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
if( b_error )
goto cleanup;
binaryProgram = (unsigned char*)AcquireMagickMemory(length);
if (binaryProgram == NULL)
goto cleanup;
memset(binaryProgram, 0, length);
b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
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;
loadSuccessful = MagickTrue;
}
cleanup:
if (fileHandle != NULL)
fclose(fileHandle);
if (binaryFileName != NULL)
RelinquishMagickMemory(binaryFileName);
if (binaryProgram != NULL)
RelinquishMagickMemory(binaryProgram);
#ifdef MAGICKCORE_CLPERFMARKER
clEndPerfMarkerAMD();
#endif
return loadSuccessful;
}
static unsigned int stringSignature(const char* string)
{
unsigned int stringLength;
unsigned int n,i,j;
unsigned int signature;
union
{
const char* s;
const unsigned int* u;
}p;
#ifdef MAGICKCORE_CLPERFMARKER
clBeginPerfMarkerAMD(__FUNCTION__,"");
#endif
stringLength = (unsigned int) strlen(string);
signature = stringLength;
n = stringLength/sizeof(unsigned int);
p.s = string;
for (i = 0; i < n; i++)
{
signature^=p.u[i];
}
if (n * sizeof(unsigned int) != stringLength)
{
char padded[4];
j = n * sizeof(unsigned int);
for (i = 0; i < 4; i++,j++)
{
if (j < stringLength)
padded[i] = p.s[j];
else
padded[i] = 0;
}
p.s = padded;
signature^=p.u[0];
}
#ifdef MAGICKCORE_CLPERFMARKER
clEndPerfMarkerAMD();
#endif
return signature;
}
/* OpenCL kernels for accelerate.c */
extern const char *accelerateKernels, *accelerateKernels2;
static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
{
MagickBooleanType status = MagickFalse;
cl_int clStatus;
unsigned int i;
char* accelerateKernelsBuffer = NULL;
/* 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];
unsigned int optionsSignature;
#ifdef MAGICKCORE_CLPERFMARKER
clBeginPerfMarkerAMD(__FUNCTION__,"");
#endif
/* Get additional options */
(void) FormatLocaleString(options, MaxTextExtent, CLOptions, (float)QuantumRange,
(float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
/*
if (getenv("MAGICK_OCL_DEF"))
{
strcat(options," ");
strcat(options,getenv("MAGICK_OCL_DEF"));
}
*/
/*
if (getenv("MAGICK_OCL_BUILD"))
printf("options: %s\n", options);
*/
optionsSignature = stringSignature(options);
/* get all the OpenCL program strings here */
accelerateKernelsBuffer = (char*) AcquireQuantumMemory(1,strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
{
MagickBooleanType loadSuccessful = MagickFalse;
unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
/* try to load the binary first */
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] = clEnv->library->clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
if (clStatus!=CL_SUCCESS)
{
(void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
"clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
goto cleanup;
}
}
clStatus = clEnv->library->clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
if (clStatus!=CL_SUCCESS)
{
(void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
"clBuildProgram failed.", "(%d)", (int)clStatus);
if (loadSuccessful == MagickFalse)
{
char path[MaxTextExtent];
FILE* fileHandle;
/* dump the source into a file */
(void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
,GetOpenCLCachedFilesDirectory()
,DirectorySeparator,"magick_badcl.cl");
fileHandle = fopen(path, "wb");
if (fileHandle != NULL)
{
fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
fclose(fileHandle);
}
/* dump the build log */
{
char* log;
size_t logSize;
clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
log = (char*)AcquireCriticalMemory(logSize);
clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
(void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
,GetOpenCLCachedFilesDirectory()
,DirectorySeparator,"magick_badcl_build.log");
fileHandle = fopen(path, "wb");
if (fileHandle != NULL)
{
const char* buildOptionsTitle = "build options: ";
fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
fwrite(options, sizeof(char), strlen(options), fileHandle);
fwrite("\n",sizeof(char), 1, fileHandle);
fwrite(log, sizeof(char), logSize, fileHandle);
fclose(fileHandle);
}
RelinquishMagickMemory(log);
}
}
goto cleanup;
}
if (loadSuccessful == MagickFalse)
{
/* Save the binary to a file to avoid re-compilation of the kernels in the future */
saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
}
}
status = MagickTrue;
cleanup:
if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
#ifdef MAGICKCORE_CLPERFMARKER
clEndPerfMarkerAMD();
#endif
return status;
}
static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
int i,j;
cl_int status;
cl_uint numPlatforms = 0;
cl_platform_id *platforms = NULL;
char* MAGICK_OCL_DEVICE = NULL;
MagickBooleanType OpenCLAvailable = MagickFalse;
#ifdef MAGICKCORE_CLPERFMARKER
clBeginPerfMarkerAMD(__FUNCTION__,"");
#endif
/* check if there's an environment variable overriding the device selection */
MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
if (MAGICK_OCL_DEVICE != NULL)
{
if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
clEnv->deviceType = CL_DEVICE_TYPE_CPU;
else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
clEnv->deviceType = CL_DEVICE_TYPE_GPU;
else if (IsStringNotFalse(MAGICK_OCL_DEVICE) == MagickFalse)
goto cleanup;
}
else if (clEnv->deviceType == 0) {
clEnv->deviceType = CL_DEVICE_TYPE_ALL;
}
if (clEnv->device != 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);
}
goto cleanup;
}
else if (clEnv->platform != NULL)
{
numPlatforms = 1;
platforms = (cl_platform_id *) AcquireQuantumMemory(1,numPlatforms * sizeof(cl_platform_id));
if (platforms == (cl_platform_id *) NULL)
{
(void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
"AcquireMagickMemory failed.",".");
goto cleanup;
}
platforms[0] = clEnv->platform;
}
else
{
clEnv->device = NULL;
/* Get the number of OpenCL platforms available */
status = clEnv->library->clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS)
{
(void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
"clGetplatformIDs failed.", "(%d)", status);
goto cleanup;
}
/* No OpenCL available, just leave */
if (numPlatforms == 0) {
goto cleanup;
}
platforms = (cl_platform_id *) AcquireQuantumMemory(1,numPlatforms * sizeof(cl_platform_id));
if (platforms == (cl_platform_id *) NULL)
{
(void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
"AcquireMagickMemory failed.",".");
goto cleanup;
}
status = clEnv->library->clGetPlatformIDs(numPlatforms, platforms, NULL);
if (status != CL_SUCCESS)
{
(void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
"clGetPlatformIDs failed.", "(%d)", status);
goto cleanup;
}
}
/* Device selection */
clEnv->device = NULL;
for (j = 0; j < 2; j++)
{
cl_device_type deviceType;
if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
{
if (j == 0)
deviceType = CL_DEVICE_TYPE_GPU;
else
deviceType = CL_DEVICE_TYPE_CPU;
}
else if (j == 1)
{
break;
}
else
deviceType = clEnv->deviceType;
for (i = 0; i < numPlatforms; i++)
{
char version[MaxTextExtent];
cl_uint numDevices;
status = clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_VERSION, MaxTextExtent, 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,
"clGetDeviceIDs failed.", "(%d)", status);
goto cleanup;
}
if (clEnv->device != NULL)
{
clEnv->platform = platforms[i];
goto cleanup;
}
}
}
cleanup:
if (platforms!=NULL)
RelinquishMagickMemory(platforms);
OpenCLAvailable = (clEnv->platform!=NULL
&& clEnv->device!=NULL)?MagickTrue:MagickFalse;
#ifdef MAGICKCORE_CLPERFMARKER
clEndPerfMarkerAMD();
#endif
return OpenCLAvailable;
}
static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
if (clEnv->OpenCLInitialized != MagickFalse
&& clEnv->platform != NULL
&& clEnv->device != NULL) {
clEnv->OpenCLDisabled = MagickFalse;
return MagickTrue;
}
clEnv->OpenCLDisabled = MagickTrue;
return MagickFalse;
}
static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ I n i t O p e n C L E n v %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% InitOpenCLEnv() initialize the OpenCL environment
%
% The format of the RelinquishMagickOpenCLEnv method is:
%
% MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
%
% A description of each parameter follows:
%
% o clEnv: OpenCL environment structure
%
% o exception: return any errors or warnings.
%
*/
static void RelinquishCommandQueues(MagickCLEnv clEnv)
{
if (clEnv == (MagickCLEnv) NULL)
return;
LockSemaphoreInfo(clEnv->commandQueuesLock);
while (clEnv->commandQueuesPos >= 0)
clEnv->library->clReleaseCommandQueue(
clEnv->commandQueues[clEnv->commandQueuesPos--]);
UnlockSemaphoreInfo(clEnv->commandQueuesLock);
}
MagickExport
MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
MagickBooleanType status = MagickTrue;
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;
/* 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;
/* setup the OpenCL platform and device */
status = InitOpenCLPlatformDevice(clEnv, exception);
if (status == MagickFalse) {
/* No OpenCL device available */
goto cleanup;
}
/* create an OpenCL context */
cps[0] = CL_CONTEXT_PLATFORM;
cps[1] = (cl_context_properties)clEnv->platform;
cps[2] = 0;
clEnv->context = clEnv->library->clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
if (clStatus != CL_SUCCESS)
{
(void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
"clCreateContext failed.", "(%d)", clStatus);
status = MagickFalse;
goto cleanup;
}
RelinquishCommandQueues(clEnv);
status = CompileOpenCLKernels(clEnv, exception);
if (status == MagickFalse) {
(void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
"clCreateCommandQueue failed.", "(%d)", status);
goto cleanup;
}
status = EnableOpenCLInternal(clEnv);
cleanup:
return status;
}
MagickExport
MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
MagickBooleanType status = MagickFalse;
if (clEnv == NULL)
return MagickFalse;
#ifdef MAGICKCORE_CLPERFMARKER
clBeginPerfMarkerAMD(__FUNCTION__,"");
#endif
LockSemaphoreInfo(clEnv->lock);
if (clEnv->OpenCLInitialized == MagickFalse) {
if (clEnv->device==NULL
&& clEnv->OpenCLDisabled == MagickFalse)
status = autoSelectDevice(clEnv, exception);
else
status = InitOpenCLEnvInternal(clEnv, exception);
}
UnlockSemaphoreInfo(clEnv->lock);
#ifdef MAGICKCORE_CLPERFMARKER
clEndPerfMarkerAMD();
#endif
return status;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ 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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireOpenCLCommandQueue() acquires an OpenCL command queue
%
% The format of the AcquireOpenCLCommandQueue method is:
%
% cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
*/
MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
{
cl_command_queue
queue;
cl_command_queue_properties
properties;
if (clEnv == (MagickCLEnv) NULL)
return (cl_command_queue) NULL;
LockSemaphoreInfo(clEnv->commandQueuesLock);
if (clEnv->commandQueuesPos >= 0) {
queue=clEnv->commandQueues[clEnv->commandQueuesPos--];
UnlockSemaphoreInfo(clEnv->commandQueuesLock);
}
else {
UnlockSemaphoreInfo(clEnv->commandQueuesLock);
properties=0;
#if PROFILE_OCL_KERNELS
properties=CL_QUEUE_PROFILING_ENABLE;
#endif
queue=clEnv->library->clCreateCommandQueue(clEnv->context,clEnv->device,
properties,NULL);
}
return(queue);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ 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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RelinquishOpenCLCommandQueue() releases the OpenCL command queue
%
% The format of the RelinquishOpenCLCommandQueue method is:
%
% MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
% cl_command_queue queue)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
% o queue: the OpenCL queue to be released.
%
%
*/
MagickPrivate MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
cl_command_queue queue)
{
MagickBooleanType
status;
if (clEnv == NULL)
return(MagickFalse);
LockSemaphoreInfo(clEnv->commandQueuesLock);
if (clEnv->commandQueuesPos >= MAX_COMMAND_QUEUES-1)
{
clEnv->library->clFinish(queue);
status=(clEnv->library->clReleaseCommandQueue(queue) == CL_SUCCESS) ?
MagickTrue : MagickFalse;
}
else
{
clEnv->library->clFlush(queue);
clEnv->commandQueues[++clEnv->commandQueuesPos]=queue;
status=MagickTrue;
}
UnlockSemaphoreInfo(clEnv->commandQueuesLock);
return(status);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ A c q u i r e O p e n C L K e r n e l %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% AcquireOpenCLKernel() acquires an OpenCL kernel
%
% The format of the AcquireOpenCLKernel method is:
%
% cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
% MagickOpenCLProgram program, const char* kernelName)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
% o program: the OpenCL program module that the kernel belongs to.
%
% o kernelName: the name of the kernel
%
*/
MagickPrivate
cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
{
cl_int clStatus;
cl_kernel kernel = NULL;
if (clEnv != NULL && kernelName!=NULL)
{
kernel = clEnv->library->clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
}
return kernel;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ R e l i n q u i s h O p e n C L K e r n e l %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RelinquishOpenCLKernel() releases an OpenCL kernel
%
% The format of the RelinquishOpenCLKernel method is:
%
% MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
% cl_kernel kernel)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
% o kernel: the OpenCL kernel object to be released.
%
%
*/
MagickPrivate
MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
{
MagickBooleanType status = MagickFalse;
if (clEnv != NULL && kernel != NULL)
{
status = ((clEnv->library->clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
}
return status;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ 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 %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
%
% The format of the GetOpenCLDeviceLocalMemorySize method is:
%
% unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
%
% A description of each parameter follows:
%
% o clEnv: the OpenCL environment.
%
%
*/
MagickPrivate
unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
{
cl_ulong localMemorySize;
clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
return (unsigned long)localMemorySize;
}
MagickPrivate
unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
{
cl_ulong maxMemAllocSize;
clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
return (unsigned long)maxMemAllocSize;
}
/*
Beginning of the OpenCL device selection infrastructure
*/
typedef enum {
DS_SUCCESS = 0
,DS_INVALID_PROFILE = 1000
,DS_MEMORY_ERROR
,DS_INVALID_PERF_EVALUATOR_TYPE
,DS_INVALID_PERF_EVALUATOR
,DS_PERF_EVALUATOR_ERROR
,DS_FILE_ERROR
,DS_UNKNOWN_DEVICE_TYPE
,DS_PROFILE_FILE_ERROR
,DS_SCORE_SERIALIZER_ERROR
,DS_SCORE_DESERIALIZER_ERROR
} ds_status;
/* device type */
typedef enum {
DS_DEVICE_NATIVE_CPU = 0
,DS_DEVICE_OPENCL_DEVICE
} ds_device_type;
typedef struct {
ds_device_type type;
cl_device_type oclDeviceType;
cl_device_id oclDeviceID;
char* oclDeviceName;
char* oclDriverVersion;
cl_uint oclMaxClockFrequency;
cl_uint oclMaxComputeUnits;
void* score; /* a pointer to the score data, the content/format is application defined */
} ds_device;
typedef struct {
unsigned int numDevices;
ds_device* devices;
const char* version;
} ds_profile;
/* deallocate memory used by score */
typedef ds_status (*ds_score_release)(void* score);
static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
ds_status status = DS_SUCCESS;
if (device) {
if (device->oclDeviceName) RelinquishMagickMemory(device->oclDeviceName);
if (device->oclDriverVersion) RelinquishMagickMemory(device->oclDriverVersion);
if (device->score) status = sr(device->score);
}
return status;
}
static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
ds_status status = DS_SUCCESS;
if (profile!=NULL) {
if (profile->devices!=NULL && sr!=NULL) {
unsigned int i;
for (i = 0; i < profile->numDevices; i++) {
status = releaseDeviceResource(profile->devices+i,sr);
if (status != DS_SUCCESS)
break;
}
RelinquishMagickMemory(profile->devices);
}
RelinquishMagickMemory(profile);
}
return status;
}
static ds_status initDSProfile(ds_profile** p, const char* version) {
int numDevices = 0;
cl_uint numPlatforms = 0;
cl_platform_id* platforms = NULL;
cl_device_id* devices = NULL;
ds_status status = DS_SUCCESS;
ds_profile* profile = NULL;
unsigned int next = 0;
unsigned int i;
if (p == NULL)
return DS_INVALID_PROFILE;
profile = (ds_profile*) AcquireMagickMemory(sizeof(ds_profile));
if (profile == NULL)
return DS_MEMORY_ERROR;
memset(profile, 0, sizeof(ds_profile));
OpenCLLib->clGetPlatformIDs(0, NULL, &numPlatforms);
if (numPlatforms > 0) {
platforms = (cl_platform_id*) AcquireQuantumMemory(numPlatforms,sizeof(cl_platform_id));
if (platforms == NULL) {
status = DS_MEMORY_ERROR;
goto cleanup;
}
OpenCLLib->clGetPlatformIDs(numPlatforms, platforms, NULL);
for (i = 0; i < (unsigned int)numPlatforms; i++) {
cl_uint num;
if (OpenCLLib->clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num) == CL_SUCCESS)
numDevices+=num;
}
}
profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
profile->devices = (ds_device*) AcquireQuantumMemory(profile->numDevices,sizeof(ds_device));
if (profile->devices == NULL) {
profile->numDevices = 0;
status = DS_MEMORY_ERROR;
goto cleanup;
}
memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
if (numDevices > 0) {
devices = (cl_device_id*) AcquireQuantumMemory(numDevices,sizeof(cl_device_id));
if (devices == NULL) {
status = DS_MEMORY_ERROR;
goto cleanup;
}
for (i = 0; i < (unsigned int)numPlatforms; i++) {
cl_uint num;
int d;
for (d = 0; d < 2; d++) {
unsigned int j;
cl_device_type deviceType;
switch(d) {
case 0:
deviceType = CL_DEVICE_TYPE_GPU;
break;
case 1:
deviceType = CL_DEVICE_TYPE_CPU;
break;
default:
continue;
break;
}
if (OpenCLLib->clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
continue;
for (j = 0; j < num; j++, next++) {
size_t length;
profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
profile->devices[next].oclDeviceID = devices[j];
OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
, 0, NULL, &length);
profile->devices[next].oclDeviceName = (char*) AcquireQuantumMemory(length,sizeof(char));
OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
, length, profile->devices[next].oclDeviceName, NULL);
OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
, 0, NULL, &length);
profile->devices[next].oclDriverVersion = (char*) AcquireQuantumMemory(length,sizeof(char));
OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
, length, profile->devices[next].oclDriverVersion, NULL);
OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
, sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
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);
}
}
}
}
profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
profile->version = version;
cleanup:
if (platforms) RelinquishMagickMemory(platforms);
if (devices) RelinquishMagickMemory(devices);
if (status == DS_SUCCESS) {
*p = profile;
}
else {
if (profile) {
if (profile->devices)
RelinquishMagickMemory(profile->devices);
RelinquishMagickMemory(profile);
}
}
return status;
}
/* Pointer to a function that calculates the score of a device (ex: device->score)
update the data size of score. The encoding and the format of the score data
is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
*/
typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
typedef enum {
DS_EVALUATE_ALL
,DS_EVALUATE_NEW_ONLY
} ds_evaluation_type;
static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
ds_status status = DS_SUCCESS;
unsigned int i;
unsigned int updates = 0;
if (profile == NULL) {
return DS_INVALID_PROFILE;
}
if (evaluator == NULL) {
return DS_INVALID_PERF_EVALUATOR;
}
for (i = 0; i < profile->numDevices; i++) {
ds_status evaluatorStatus;
switch (type) {
case DS_EVALUATE_NEW_ONLY:
if (profile->devices[i].score != NULL)
break;
/* else fall through */
case DS_EVALUATE_ALL:
evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
if (evaluatorStatus != DS_SUCCESS) {
status = evaluatorStatus;
return status;
}
updates++;
break;
default:
return DS_INVALID_PERF_EVALUATOR_TYPE;
break;
};
}
if (numUpdates)
*numUpdates = updates;
return status;
}
#define DS_TAG_VERSION "<version>"
#define DS_TAG_VERSION_END "</version>"
#define DS_TAG_DEVICE "<device>"
#define DS_TAG_DEVICE_END "</device>"
#define DS_TAG_SCORE "<score>"
#define DS_TAG_SCORE_END "</score>"
#define DS_TAG_DEVICE_TYPE "<type>"
#define DS_TAG_DEVICE_TYPE_END "</type>"
#define DS_TAG_DEVICE_NAME "<name>"
#define DS_TAG_DEVICE_NAME_END "</name>"
#define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
#define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
#define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
#define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
#define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
#define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
#define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
ds_status status = DS_SUCCESS;
FILE* profileFile = NULL;
if (profile == NULL)
return DS_INVALID_PROFILE;
profileFile = fopen(file, "wb");
if (profileFile==NULL) {
status = DS_FILE_ERROR;
}
else {
unsigned int i;
/* write version string */
fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
fwrite("\n", sizeof(char), 1, profileFile);
for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
void* serializedScore;
unsigned int serializedScoreSize;
fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
switch(profile->devices[i].type) {
case DS_DEVICE_NATIVE_CPU:
{
/* There's no need to emit a device name for the native CPU device. */
/*
fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
*/
}
break;
case DS_DEVICE_OPENCL_DEVICE:
{
char tmp[16];
fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
}
break;
default:
status = DS_UNKNOWN_DEVICE_TYPE;
break;
};
fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
RelinquishMagickMemory(serializedScore);
}
fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
fwrite("\n",sizeof(char),1,profileFile);
}
fclose(profileFile);
}
return status;
}
static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
ds_status status = DS_SUCCESS;
FILE * input = NULL;
size_t size = 0;
size_t rsize = 0;
char* binary = NULL;
*contentSize = 0;
*content = NULL;
input = fopen(fileName, "rb");
if(input == NULL) {
return DS_FILE_ERROR;
}
fseek(input, 0L, SEEK_END);
size = ftell(input);
rewind(input);
binary = (char*) AcquireQuantumMemory(1,size);
if(binary == NULL) {
status = DS_FILE_ERROR;
goto cleanup;
}
rsize = fread(binary, sizeof(char), size, input);
if (rsize!=size
|| ferror(input)) {
status = DS_FILE_ERROR;
goto cleanup;
}
*contentSize = size;
*content = binary;
cleanup:
if (input != NULL) fclose(input);
if (status != DS_SUCCESS
&& binary != NULL) {
RelinquishMagickMemory(binary);
*content = NULL;
*contentSize = 0;
}
return status;
}
static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
size_t stringLength;
const char* currentPosition;
const char* found;
found = NULL;
stringLength = strlen(string);
currentPosition = contentStart;
for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
if (*currentPosition == string[0]) {
if (currentPosition+stringLength < contentEnd) {
if (strncmp(currentPosition, string, stringLength) == 0) {
found = currentPosition;
break;
}
}
}
}
return found;
}
typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
ds_status status = DS_SUCCESS;
char* contentStart = NULL;
const char* contentEnd = NULL;
size_t contentSize;
if (profile==NULL)
return DS_INVALID_PROFILE;
status = readProFile(file, &contentStart, &contentSize);
if (status == DS_SUCCESS) {
const char* currentPosition;
const char* dataStart;
const char* dataEnd;
size_t versionStringLength;
contentEnd = contentStart + contentSize;
currentPosition = contentStart;
/* parse the version string */
dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
if (dataStart == NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
dataStart += strlen(DS_TAG_VERSION);
dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
if (dataEnd==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
versionStringLength = strlen(profile->version);
if (versionStringLength!=(size_t)(dataEnd-dataStart)
|| strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
/* version mismatch */
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
/* parse the device information */
DisableMSCWarning(4127)
while (1) {
RestoreMSCWarning
unsigned int i;
const char* deviceTypeStart;
const char* deviceTypeEnd;
ds_device_type deviceType;
const char* deviceNameStart;
const char* deviceNameEnd;
const char* deviceScoreStart;
const char* deviceScoreEnd;
const char* deviceDriverStart;
const char* deviceDriverEnd;
const char* tmpStart;
const char* tmpEnd;
char tmp[16];
cl_uint maxClockFrequency;
cl_uint maxComputeUnits;
dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
if (dataStart==NULL) {
/* nothing useful remain, quit...*/
break;
}
dataStart+=strlen(DS_TAG_DEVICE);
dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
if (dataEnd==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
/* parse the device type */
deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
if (deviceTypeStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
if (deviceTypeEnd==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
/* parse the device name */
if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
if (deviceNameStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
if (deviceNameEnd==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
if (deviceDriverStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
if (deviceDriverEnd ==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
if (tmpStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
if (tmpEnd ==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
memcpy(tmp,tmpStart,tmpEnd-tmpStart);
tmp[tmpEnd-tmpStart] = '\0';
maxComputeUnits = strtol(tmp,(char **) NULL,10);
tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
if (tmpStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
if (tmpEnd ==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
memcpy(tmp,tmpStart,tmpEnd-tmpStart);
tmp[tmpEnd-tmpStart] = '\0';
maxClockFrequency = strtol(tmp,(char **) NULL,10);
/* check if this device is on the system */
for (i = 0; i < profile->numDevices; i++) {
if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
size_t actualDeviceNameLength;
size_t driverVersionLength;
actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
&& driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
&& maxComputeUnits == profile->devices[i].oclMaxComputeUnits
&& maxClockFrequency == profile->devices[i].oclMaxClockFrequency
&& strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
&& strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
if (deviceNameStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
deviceScoreStart+=strlen(DS_TAG_SCORE);
deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
if (status != DS_SUCCESS) {
goto cleanup;
}
}
}
}
}
else if (deviceType == DS_DEVICE_NATIVE_CPU) {
for (i = 0; i < profile->numDevices; i++) {
if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
if (deviceScoreStart==NULL) {
status = DS_PROFILE_FILE_ERROR;
goto cleanup;
}
deviceScoreStart+=strlen(DS_TAG_SCORE);
deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
if (status != DS_SUCCESS) {
goto cleanup;
}
}
}
}
/* skip over the current one to find the next device */
currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
}
}
cleanup:
if (contentStart!=NULL) RelinquishMagickMemory(contentStart);
return status;
}
#if 0
static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
unsigned int i;
if (profile == NULL || num==NULL)
return DS_MEMORY_ERROR;
*num=0;
for (i = 0; i < profile->numDevices; i++) {
if (profile->devices[i].score == NULL) {
(*num)++;
}
}
return DS_SUCCESS;
}
#endif
/*
End of the OpenCL device selection infrastructure
*/
typedef double AccelerateScoreType;
static ds_status AcceleratePerfEvaluator(ds_device *device,
void *magick_unused(data))
{
#define ACCELERATE_PERF_DIMEN "2048x1536"
#define NUM_ITER 2
#define ReturnStatus(status) \
{ \
if (oldClEnv != (MagickCLEnv) NULL) \
defaultCLEnv=oldClEnv; \
if (clEnv != (MagickCLEnv) NULL) \
(void) RelinquishMagickOpenCLEnv(clEnv); \
return status; \
}
AccelerateTimer
timer;
ExceptionInfo
*exception=NULL;
MagickBooleanType
status;
MagickCLEnv
clEnv=NULL,
oldClEnv=NULL;
magick_unreferenced(data);
if (device == NULL)
ReturnStatus(DS_PERF_EVALUATOR_ERROR);
clEnv=AcquireMagickOpenCLEnv();
exception=AcquireExceptionInfo();
if (device->type == DS_DEVICE_NATIVE_CPU)
{
/* CPU device */
MagickBooleanType flag=MagickTrue;
SetMagickOpenCLEnvParamInternal(clEnv,
MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
&flag,exception);
}
else if (device->type == DS_DEVICE_OPENCL_DEVICE)
{
/* OpenCL device */
SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
sizeof(cl_device_id),&device->oclDeviceID,exception);
}
else
ReturnStatus(DS_PERF_EVALUATOR_ERROR);
/* recompile the OpenCL kernels if it needs to */
clEnv->disableProgramCache = defaultCLEnv->disableProgramCache;
status=InitOpenCLEnvInternal(clEnv,exception);
oldClEnv=defaultCLEnv;
defaultCLEnv=clEnv;
/* microbenchmark */
if (status != MagickFalse)
{
Image
*inputImage;
ImageInfo
*imageInfo;
int
i;
imageInfo=AcquireImageInfo();
CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
CopyMagickString(imageInfo->filename,"xc:none",MaxTextExtent);
inputImage=ReadImage(imageInfo,exception);
initAccelerateTimer(&timer);
for (i=0; i<=NUM_ITER; i++)
{
cl_uint
event_count;
cl_event
*events;
Image
*bluredImage,
*resizedImage,
*unsharpedImage;
if (i > 0)
startAccelerateTimer(&timer);
#ifdef MAGICKCORE_CLPERFMARKER
clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
#endif
bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
exception);
resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,1.0,
exception);
/*
We need this to get a proper performance benchmark, the operations
are executed asynchronous.
*/
if (device->type != DS_DEVICE_NATIVE_CPU)
{
events=GetOpenCLEvents(resizedImage,&event_count);
if (event_count > 0)
clEnv->library->clWaitForEvents(event_count,events);
events=(cl_event *) RelinquishMagickMemory(events);
}
#ifdef MAGICKCORE_CLPERFMARKER
clEndPerfMarkerAMD();
#endif
if (i > 0)
stopAccelerateTimer(&timer);
if (bluredImage)
DestroyImage(bluredImage);
if (unsharpedImage)
DestroyImage(unsharpedImage);
if (resizedImage)
DestroyImage(resizedImage);
}
DestroyImage(inputImage);
}
/* end of microbenchmark */
if (device->score == NULL)
device->score= AcquireMagickMemory(sizeof(AccelerateScoreType));
if (status != MagickFalse)
*(AccelerateScoreType*) device->score=readAccelerateTimer(&timer);
else
*(AccelerateScoreType*) device->score=42;
ReturnStatus(DS_SUCCESS);
}
ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
if (device
&& device->score) {
/* generate a string from the score */
char* s = (char*) AcquireQuantumMemory(256,sizeof(char));
sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
*serializedScore = (void*)s;
*serializedScoreSize = (unsigned int) strlen(s);
return DS_SUCCESS;
}
else {
return DS_SCORE_SERIALIZER_ERROR;
}
}
ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
if (device) {
/* convert the string back to an int */
char* s = (char*) AcquireQuantumMemory(1,serializedScoreSize+1);
memcpy(s, serializedScore, serializedScoreSize);
s[serializedScoreSize] = (char)'\0';
device->score = AcquireMagickMemory(sizeof(AccelerateScoreType));
*((AccelerateScoreType*)device->score) = (AccelerateScoreType)
strtod(s, (char **) NULL);
RelinquishMagickMemory(s);
return DS_SUCCESS;
}
else {
return DS_SCORE_DESERIALIZER_ERROR;
}
}
ds_status AccelerateScoreRelease(void* score) {
if (score!=NULL) {
RelinquishMagickMemory(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"
static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
MagickBooleanType mStatus = MagickFalse;
ds_status status;
ds_profile* profile;
unsigned int numDeviceProfiled = 0;
unsigned int i;
unsigned int bestDeviceIndex;
AccelerateScoreType bestScore;
char path[MaxTextExtent];
MagickBooleanType flag;
ds_evaluation_type profileType;
LockDefaultOpenCLEnv();
/* Initially, just set OpenCL to off */
flag = MagickTrue;
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;
}
clEnv->library=OpenCLLib;
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"
,GetOpenCLCachedFilesDirectory()
,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
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;
}
}
}
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(), 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;
}
}
}
/* set up clEnv with the best device */
if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
/* CPU device */
flag = MagickTrue;
SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
, sizeof(MagickBooleanType), &flag, exception);
}
else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
/* OpenCL device */
flag = MagickFalse;
SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
, sizeof(MagickBooleanType), &flag, exception);
SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
, sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
}
else {
status = DS_PERF_EVALUATOR_ERROR;
goto cleanup;
}
mStatus=InitOpenCLEnvInternal(clEnv, exception);
status = releaseDSProfile(profile, AccelerateScoreRelease);
if (status!=DS_SUCCESS) {
(void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
}
cleanup:
UnlockDefaultOpenCLEnv();
return mStatus;
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
+ I n i t I m a g e M a g i c k O p e n C L %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% InitImageMagickOpenCL() provides a simplified interface to initialize
% the OpenCL environtment in ImageMagick
%
% The format of the InitImageMagickOpenCL() method is:
%
% MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
% void* userSelectedDevice,
% void* selectedDevice)
%
% A description of each parameter follows:
%
% o mode: OpenCL mode in ImageMagick, could be off,auto,user
%
% o userSelectedDevice: when in user mode, a pointer to the selected
% cl_device_id
%
% o selectedDevice: a pointer to cl_device_id where the selected
% cl_device_id by ImageMagick could be returned
%
% o exception: exception
%
*/
MagickExport MagickBooleanType InitImageMagickOpenCL(
ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
ExceptionInfo *exception)
{
MagickBooleanType status = MagickFalse;
MagickCLEnv clEnv = NULL;
MagickBooleanType flag;
clEnv = GetDefaultOpenCLEnv();
if (clEnv!=NULL) {
switch(mode) {
case MAGICK_OPENCL_OFF:
flag = MagickTrue;
SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
, sizeof(MagickBooleanType), &flag, exception);
status = InitOpenCLEnv(clEnv, exception);
if (selectedDevice)
*(cl_device_id*)selectedDevice = NULL;
break;
case MAGICK_OPENCL_DEVICE_SELECT_USER:
if (userSelectedDevice == NULL)
return MagickFalse;
flag = MagickFalse;
SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
, sizeof(MagickBooleanType), &flag, exception);
SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
, sizeof(cl_device_id), userSelectedDevice,exception);
status = InitOpenCLEnv(clEnv, exception);
if (selectedDevice) {
GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
, sizeof(cl_device_id), selectedDevice, exception);
}
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:
{
cl_device_id d = NULL;
flag = MagickFalse;
SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
, sizeof(MagickBooleanType), &flag, exception);
SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
, sizeof(cl_device_id), &d,exception);
status = InitOpenCLEnv(clEnv, exception);
if (selectedDevice) {
GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
, sizeof(cl_device_id), selectedDevice, exception);
}
}
break;
};
}
return status;
}
MagickPrivate
MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
const char *module,const char *function,const size_t line,
const ExceptionType severity,const char *tag,const char *format,...) {
MagickBooleanType
status;
MagickCLEnv clEnv;
status = MagickTrue;
clEnv = GetDefaultOpenCLEnv();
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);
if (severity!=0) {
cl_device_type dType;
clEnv->library->clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
if (dType == CL_DEVICE_TYPE_CPU) {
char buffer[MaxTextExtent];
clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MaxTextExtent, buffer, NULL);
/* Workaround for Intel OpenCL CPU runtime bug */
/* Turn off OpenCL when a problem is detected! */
if (strncmp(buffer, "Intel",5) == 0) {
InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
}
}
}
#ifdef OPENCLLOG_ENABLED
{
va_list
operands;
va_start(operands,format);
status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
va_end(operands);
}
#else
magick_unreferenced(module);
magick_unreferenced(function);
magick_unreferenced(line);
magick_unreferenced(tag);
magick_unreferenced(format);
#endif
return(status);
}
char* openclCachedFilesDirectory;
SemaphoreInfo* openclCachedFilesDirectoryLock;
MagickPrivate
const char* GetOpenCLCachedFilesDirectory() {
if (openclCachedFilesDirectory == NULL) {
if (openclCachedFilesDirectoryLock == NULL)
{
ActivateSemaphoreInfo(&openclCachedFilesDirectoryLock);
}
LockSemaphoreInfo(openclCachedFilesDirectoryLock);
if (openclCachedFilesDirectory == NULL) {
char path[MaxTextExtent];
char *home = NULL;
char *temp = NULL;
struct stat attributes;
MagickBooleanType status;
int mkdirStatus = 0;
home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
if (home == (char *) NULL)
{
home=GetEnvironmentValue("XDG_CACHE_HOME");
#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
if (home == (char *) NULL)
home=GetEnvironmentValue("LOCALAPPDATA");
if (home == (char *) NULL)
home=GetEnvironmentValue("APPDATA");
if (home == (char *) NULL)
home=GetEnvironmentValue("USERPROFILE");
#endif
}
if (home != (char *) NULL)
{
/* first check if $HOME exists */
(void) FormatLocaleString(path,MaxTextExtent,"%s",home);
status=GetPathAttributes(path,&attributes);
if (status == MagickFalse)
{
#ifdef MAGICKCORE_WINDOWS_SUPPORT
mkdirStatus = mkdir(path);
#else
mkdirStatus = mkdir(path, 0777);
#endif
}
/* first check if $HOME/ImageMagick exists */
if (mkdirStatus==0)
{
(void) FormatLocaleString(path,MaxTextExtent,
"%s%sImageMagick",home,DirectorySeparator);
status=GetPathAttributes(path,&attributes);
if (status == MagickFalse)
{
#ifdef MAGICKCORE_WINDOWS_SUPPORT
mkdirStatus = mkdir(path);
#else
mkdirStatus = mkdir(path, 0777);
#endif
}
}
if (mkdirStatus==0)
{
temp = (char*)AcquireCriticalMemory(strlen(path)+1);
CopyMagickString(temp,path,strlen(path)+1);
}
home=DestroyString(home);
} else {
home=GetEnvironmentValue("HOME");
if (home != (char *) NULL)
{
/*
*/
/* first check if $HOME/.cache exists */
(void) FormatLocaleString(path,MaxTextExtent,"%s%s.cache",
home,DirectorySeparator);
status=GetPathAttributes(path,&attributes);
if (status == MagickFalse)
{
#ifdef MAGICKCORE_WINDOWS_SUPPORT
mkdirStatus = mkdir(path);
#else
mkdirStatus = mkdir(path, 0777);
#endif
}
/* first check if $HOME/.cache/ImageMagick exists */
if (mkdirStatus==0)
{
(void) FormatLocaleString(path,MaxTextExtent,
"%s%s.cache%sImageMagick",home,DirectorySeparator,
DirectorySeparator);
status=GetPathAttributes(path,&attributes);
if (status == MagickFalse)
{
#ifdef MAGICKCORE_WINDOWS_SUPPORT
mkdirStatus = mkdir(path);
#else
mkdirStatus = mkdir(path, 0777);
#endif
}
}
if (mkdirStatus==0)
{
temp = (char*)AcquireCriticalMemory(strlen(path)+1);
CopyMagickString(temp,path,strlen(path)+1);
}
home=DestroyString(home);
}
}
openclCachedFilesDirectory = temp;
}
UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
}
return openclCachedFilesDirectory;
}
/* create a function for OpenCL log */
MagickPrivate
void OpenCLLog(const char* message) {
#ifdef OPENCLLOG_ENABLED
#define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
FILE* log;
if (getenv("MAGICK_OCL_LOG"))
{
if (message) {
char path[MaxTextExtent];
unsigned long allocSize;
MagickCLEnv clEnv;
clEnv = GetDefaultOpenCLEnv();
/* dump the source into a file */
(void) FormatLocaleString(path,MaxTextExtent,"%s%s%s"
,GetOpenCLCachedFilesDirectory()
,DirectorySeparator,OPENCL_LOG_FILE);
log = fopen(path, "ab");
if (log == (FILE *) NULL)
return;
fwrite(message, sizeof(char), strlen(message), log);
fwrite("\n", sizeof(char), 1, log);
if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
{
allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
fprintf(log, "Devic Max Memory Alloc Size: %lu\n", allocSize);
}
fclose(log);
}
}
#else
magick_unreferenced(message);
#endif
}
MagickPrivate void OpenCLTerminus()
{
DumpProfileData();
if (openclCachedFilesDirectory != (char *) NULL)
openclCachedFilesDirectory=DestroyString(openclCachedFilesDirectory);
if (openclCachedFilesDirectoryLock != (SemaphoreInfo*)NULL)
DestroySemaphoreInfo(&openclCachedFilesDirectoryLock);
if (defaultCLEnv != (MagickCLEnv) NULL)
{
(void) RelinquishMagickOpenCLEnv(defaultCLEnv);
defaultCLEnv=(MagickCLEnv)NULL;
}
if (defaultCLEnvLock != (SemaphoreInfo*) NULL)
DestroySemaphoreInfo(&defaultCLEnvLock);
if (OpenCLLib != (MagickLibrary *)NULL)
{
if (OpenCLLib->base != (void *) NULL)
(void) lt_dlclose(OpenCLLib->base);
OpenCLLib=(MagickLibrary *)RelinquishMagickMemory(OpenCLLib);
}
if (OpenCLLibLock != (SemaphoreInfo*)NULL)
DestroySemaphoreInfo(&OpenCLLibLock);
}
#else
struct _MagickCLEnv {
MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
};
/*
* Return the OpenCL environment
*/
MagickExport MagickCLEnv GetDefaultOpenCLEnv()
{
return (MagickCLEnv) NULL;
}
MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
size_t magick_unused(dataSize),void *magick_unused(data),
ExceptionInfo *magick_unused(exception))
{
magick_unreferenced(clEnv);
magick_unreferenced(param);
magick_unreferenced(dataSize);
magick_unreferenced(data);
magick_unreferenced(exception);
return(MagickFalse);
}
MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
size_t magick_unused(dataSize),void *magick_unused(data),
ExceptionInfo *magick_unused(exception))
{
magick_unreferenced(clEnv);
magick_unreferenced(param);
magick_unreferenced(dataSize);
magick_unreferenced(data);
magick_unreferenced(exception);
return(MagickFalse);
}
MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
ExceptionInfo *magick_unused(exception))
{
magick_unreferenced(clEnv);
magick_unreferenced(exception);
return(MagickFalse);
}
MagickExport MagickBooleanType InitImageMagickOpenCL(
ImageMagickOpenCLMode magick_unused(mode),
void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
ExceptionInfo *magick_unused(exception))
{
magick_unreferenced(mode);
magick_unreferenced(userSelectedDevice);
magick_unreferenced(selectedDevice);
magick_unreferenced(exception);
return(MagickFalse);
}
#endif /* MAGICKCORE_OPENCL_SUPPORT */