forked from openkylin/imagemagick
3106 lines
95 KiB
C
3106 lines
95 KiB
C
|
/*
|
|||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|||
|
% %
|
|||
|
% %
|
|||
|
% %
|
|||
|
% 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 */
|