blob: 7497abae70ea7825f5088c5865f914d537bf850d [file] [log] [blame]
cristydbba8212013-07-19 14:53:50 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% OOO PPPP EEEEE N N CCCC L %
7% O O P P E NN N C L %
8% O O PPPP EEE N N N C L %
9% O O P E N NN C L %
10% OOO P EEEEE N N CCCC LLLLL %
11% %
12% %
13% MagickCore OpenCL Methods %
14% %
15% Software Design %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristydbba8212013-07-19 14:53:50 +000017% March 2000 %
18% %
19% %
Cristy7ce65e72015-12-12 18:03:16 -050020% Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization %
cristydbba8212013-07-19 14:53:50 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
Cristy1dd96da2015-10-06 07:52:01 -040039
cristydbba8212013-07-19 14:53:50 +000040/*
Cristy1dd96da2015-10-06 07:52:01 -040041 Include declarations.
cristydbba8212013-07-19 14:53:50 +000042*/
43#include "MagickCore/studio.h"
44#include "MagickCore/artifact.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/color.h"
47#include "MagickCore/compare.h"
48#include "MagickCore/constitute.h"
49#include "MagickCore/distort.h"
50#include "MagickCore/draw.h"
51#include "MagickCore/effect.h"
52#include "MagickCore/exception.h"
53#include "MagickCore/exception-private.h"
54#include "MagickCore/fx.h"
55#include "MagickCore/gem.h"
56#include "MagickCore/geometry.h"
57#include "MagickCore/image.h"
58#include "MagickCore/image-private.h"
59#include "MagickCore/layer.h"
60#include "MagickCore/mime-private.h"
61#include "MagickCore/memory_.h"
62#include "MagickCore/monitor.h"
63#include "MagickCore/montage.h"
64#include "MagickCore/morphology.h"
cristyd1165552013-11-24 20:10:57 +000065#include "MagickCore/nt-base.h"
cristy1e37e8f2014-02-21 17:05:37 +000066#include "MagickCore/nt-base-private.h"
cristyf034abb2013-11-24 14:16:14 +000067#include "MagickCore/opencl.h"
68#include "MagickCore/opencl-private.h"
cristydbba8212013-07-19 14:53:50 +000069#include "MagickCore/option.h"
70#include "MagickCore/policy.h"
71#include "MagickCore/property.h"
72#include "MagickCore/quantize.h"
73#include "MagickCore/quantum.h"
cristy0c832c62014-03-07 22:21:04 +000074#include "MagickCore/random_.h"
75#include "MagickCore/random-private.h"
cristydbba8212013-07-19 14:53:50 +000076#include "MagickCore/resample.h"
77#include "MagickCore/resource_.h"
78#include "MagickCore/splay-tree.h"
cristyf034abb2013-11-24 14:16:14 +000079#include "MagickCore/semaphore.h"
cristydbba8212013-07-19 14:53:50 +000080#include "MagickCore/statistic.h"
81#include "MagickCore/string_.h"
82#include "MagickCore/token.h"
83#include "MagickCore/utility.h"
cristyf034abb2013-11-24 14:16:14 +000084
cristyf034abb2013-11-24 14:16:14 +000085#ifdef MAGICKCORE_CLPERFMARKER
86#include "CLPerfMarker.h"
87#endif
88
89
90#if defined(MAGICKCORE_OPENCL_SUPPORT)
91
cristy0c832c62014-03-07 22:21:04 +000092#ifdef MAGICKCORE_HAVE_OPENCL_CL_H
93#define MAGICKCORE_OPENCL_MACOSX 1
94#endif
cristyf034abb2013-11-24 14:16:14 +000095
Cristy1dd96da2015-10-06 07:52:01 -040096#define NUM_CL_RAND_GENERATORS 1024 /* number of random number generators running in parallel */
dirk99731742015-11-14 22:54:38 +010097#define PROFILE_OCL_KERNELS 0
98
99typedef struct
100{
101 cl_ulong min;
102 cl_ulong max;
103 cl_ulong total;
104 cl_ulong count;
105} KernelProfileRecord;
106
107static const char *kernelNames[] = {
108 "AddNoise",
109 "BlurRow",
110 "BlurColumn",
111 "Composite",
112 "ComputeFunction",
113 "Contrast",
114 "ContrastStretch",
115 "Convolve",
116 "Equalize",
117 "GrayScale",
118 "Histogram",
119 "HullPass1",
120 "HullPass2",
121 "LocalContrastBlurRow",
122 "LocalContrastBlurApplyColumn",
123 "Modulate",
124 "MotionBlur",
125 "RandomNumberGenerator",
126 "ResizeHorizontal",
127 "ResizeVertical",
128 "RotationalBlur",
129 "UnsharpMaskBlurColumn",
130 "UnsharpMask",
131 "NONE" };
132
133KernelProfileRecord
134 profileRecords[KERNEL_COUNT];
135
136typedef struct _AccelerateTimer {
137 long long _freq;
138 long long _clocks;
139 long long _start;
140} AccelerateTimer;
141
142void startAccelerateTimer(AccelerateTimer* timer) {
143#ifdef _WIN32
144 QueryPerformanceCounter((LARGE_INTEGER*)&timer->_start);
145
146
147#else
148 struct timeval s;
149 gettimeofday(&s, 0);
150 timer->_start = (long long)s.tv_sec * (long long)1.0E3 + (long long)s.tv_usec / (long long)1.0E3;
151#endif
152}
153
154void stopAccelerateTimer(AccelerateTimer* timer) {
155 long long n=0;
156#ifdef _WIN32
157 QueryPerformanceCounter((LARGE_INTEGER*)&(n));
158#else
159 struct timeval s;
160 gettimeofday(&s, 0);
161 n = (long long)s.tv_sec * (long long)1.0E3+ (long long)s.tv_usec / (long long)1.0E3;
162#endif
163 n -= timer->_start;
164 timer->_start = 0;
165 timer->_clocks += n;
166}
167
168void resetAccelerateTimer(AccelerateTimer* timer) {
169 timer->_clocks = 0;
170 timer->_start = 0;
171}
172
173void initAccelerateTimer(AccelerateTimer* timer) {
174#ifdef _WIN32
175 QueryPerformanceFrequency((LARGE_INTEGER*)&timer->_freq);
176#else
177 timer->_freq = (long long)1.0E3;
178#endif
179 resetAccelerateTimer(timer);
180}
181
182double readAccelerateTimer(AccelerateTimer* timer) {
183 return (double)timer->_clocks/(double)timer->_freq;
184};
185
dirk0fe53dc2015-11-14 23:52:55 +0100186MagickPrivate void RecordProfileData(MagickCLEnv clEnv, ProfiledKernels kernel, cl_event event)
dirk99731742015-11-14 22:54:38 +0100187{
188#if PROFILE_OCL_KERNELS
189 cl_int status;
190 cl_ulong start = 0;
191 cl_ulong end = 0;
192 cl_ulong elapsed = 0;
dirk99731742015-11-14 22:54:38 +0100193 clEnv->library->clWaitForEvents(1, &event);
194 status = clEnv->library->clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &start, NULL);
195 status &= clEnv->library->clGetEventProfilingInfo(event, CL_PROFILING_COMMAND_END, sizeof(cl_ulong), &end, NULL);
196 if (status == CL_SUCCESS) {
197 start /= 1000; // usecs
198 end /= 1000; // usecs
199 elapsed = end - start;
dirk0fe53dc2015-11-14 23:52:55 +0100200 /* we can use the commandQueuesLock to make the code below thread safe */
201 LockSemaphoreInfo(clEnv->commandQueuesLock);
dirk99731742015-11-14 22:54:38 +0100202 if ((elapsed < profileRecords[kernel].min) || (profileRecords[kernel].count == 0))
203 profileRecords[kernel].min = elapsed;
204 if (elapsed > profileRecords[kernel].max)
205 profileRecords[kernel].max = elapsed;
206 profileRecords[kernel].total += elapsed;
207 profileRecords[kernel].count += 1;
dirk0fe53dc2015-11-14 23:52:55 +0100208 UnlockSemaphoreInfo(clEnv->commandQueuesLock);
dirk99731742015-11-14 22:54:38 +0100209 }
210#endif
211}
212
213void DumpProfileData()
214{
215#if PROFILE_OCL_KERNELS
216 int i;
217
218 OpenCLLog("====================================================");
219
220 // Write out the device info to the profile
221 if (0 == 1)
222 {
223 MagickCLEnv clEnv;
224 char buff[2048];
225 cl_int status;
226
227 clEnv = GetDefaultOpenCLEnv();
228
229 status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_VENDOR, 2048, buff, NULL);
230 OpenCLLog(buff);
231
232 status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, 2048, buff, NULL);
233 OpenCLLog(buff);
234
235 status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DRIVER_VERSION, 2048, buff, NULL);
236 OpenCLLog(buff);
237 }
238
239 OpenCLLog("====================================================");
240 OpenCLLog(" ave\tcalls \tmin -> max");
241 OpenCLLog(" ---\t----- \t----------");
242 for (i = 0; i < KERNEL_COUNT; ++i) {
243 char buf[4096];
244 char indent[160];
245 strcpy(indent, " ");
246 strncpy(indent, kernelNames[i], min(strlen(kernelNames[i]), strlen(indent) - 1));
247 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);
248 //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);
249 OpenCLLog(buf);
250 }
251 OpenCLLog("====================================================");
252#endif
253}
cristyf034abb2013-11-24 14:16:14 +0000254
cristy0c832c62014-03-07 22:21:04 +0000255/*
Cristy1dd96da2015-10-06 07:52:01 -0400256 *
cristy0c832c62014-03-07 22:21:04 +0000257 * Dynamic library loading functions
258 *
259 */
260#ifdef MAGICKCORE_WINDOWS_SUPPORT
261#else
262#include <dlfcn.h>
263#endif
264
265// dynamically load a library. returns NULL on failure
266void *OsLibraryLoad(const char *libraryName)
267{
268#ifdef MAGICKCORE_WINDOWS_SUPPORT
269 return (void *)LoadLibraryA(libraryName);
Cristy1dd96da2015-10-06 07:52:01 -0400270#else
cristy0c832c62014-03-07 22:21:04 +0000271 return (void *)dlopen(libraryName, RTLD_NOW);
272#endif
273}
274
275// get a function pointer from a loaded library. returns NULL on failure.
276void *OsLibraryGetFunctionAddress(void *library, const char *functionName)
277{
278#ifdef MAGICKCORE_WINDOWS_SUPPORT
279 if (!library || !functionName)
280 {
281 return NULL;
282 }
283 return (void *) GetProcAddress( (HMODULE)library, functionName);
284#else
285 if (!library || !functionName)
286 {
287 return NULL;
288 }
289 return (void *)dlsym(library, functionName);
290#endif
291}
292
293// unload a library.
294void OsLibraryUnload(void *library)
295{
296#ifdef MAGICKCORE_WINDOWS_SUPPORT
297 FreeLibrary( (HMODULE)library);
298#else
299 dlclose(library);
300#endif
301}
cristyf034abb2013-11-24 14:16:14 +0000302
303
304/*
305%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306% %
307% %
308% %
309+ A c q u i r e M a g i c k O p e n C L E n v %
310% %
311% %
312% %
313%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314%
Cristy1dd96da2015-10-06 07:52:01 -0400315% AcquireMagickOpenCLEnv() allocates the MagickCLEnv structure
cristyf034abb2013-11-24 14:16:14 +0000316%
317*/
318
dirk69838ee2016-01-10 18:22:20 +0100319MagickExport MagickCLEnv AcquireMagickOpenCLEnv(void)
cristyf034abb2013-11-24 14:16:14 +0000320{
321 MagickCLEnv clEnv;
322 clEnv = (MagickCLEnv) AcquireMagickMemory(sizeof(struct _MagickCLEnv));
323 if (clEnv != NULL)
324 {
325 memset(clEnv, 0, sizeof(struct _MagickCLEnv));
dirk99731742015-11-14 22:54:38 +0100326 clEnv->commandQueuesPos=-1;
cristy04b11db2014-02-16 15:10:39 +0000327 ActivateSemaphoreInfo(&clEnv->lock);
dirk99731742015-11-14 22:54:38 +0100328 ActivateSemaphoreInfo(&clEnv->commandQueuesLock);
cristyf034abb2013-11-24 14:16:14 +0000329 }
330 return clEnv;
331}
332
333
334/*
335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336% %
337% %
338% %
339+ 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 %
340% %
341% %
342% %
343%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344%
345% RelinquishMagickOpenCLEnv() destroy the MagickCLEnv structure
346%
347% The format of the RelinquishMagickOpenCLEnv method is:
348%
349% MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
350%
351% A description of each parameter follows:
352%
353% o clEnv: MagickCLEnv structure to destroy
354%
355*/
356
357MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(MagickCLEnv clEnv)
358{
cristyf432c632014-12-07 15:11:28 +0000359 if (clEnv != (MagickCLEnv) NULL)
cristyf034abb2013-11-24 14:16:14 +0000360 {
dirk99731742015-11-14 22:54:38 +0100361 while (clEnv->commandQueuesPos >= 0)
362 {
363 clEnv->library->clReleaseCommandQueue(
364 clEnv->commandQueues[clEnv->commandQueuesPos--]);
365 }
dirk832becc2014-08-04 19:44:34 +0000366 RelinquishSemaphoreInfo(&clEnv->lock);
dirk99731742015-11-14 22:54:38 +0100367 RelinquishSemaphoreInfo(&clEnv->commandQueuesLock);
cristyf034abb2013-11-24 14:16:14 +0000368 RelinquishMagickMemory(clEnv);
369 return MagickTrue;
370 }
371 return MagickFalse;
372}
373
374
375/*
376* Default OpenCL environment
377*/
378MagickCLEnv defaultCLEnv;
379SemaphoreInfo* defaultCLEnvLock;
380
cristy0c832c62014-03-07 22:21:04 +0000381/*
382* OpenCL library
383*/
384MagickLibrary * OpenCLLib;
385SemaphoreInfo* OpenCLLibLock;
386
387
388static MagickBooleanType bindOpenCLFunctions(void* library)
389{
390#ifdef MAGICKCORE_OPENCL_MACOSX
391#define BIND(X) OpenCLLib->X= &X;
392#else
393#define BIND(X)\
394 if ((OpenCLLib->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(library,#X)) == NULL)\
395 return MagickFalse;
396#endif
397
398 BIND(clGetPlatformIDs);
399 BIND(clGetPlatformInfo);
400
401 BIND(clGetDeviceIDs);
402 BIND(clGetDeviceInfo);
403
404 BIND(clCreateContext);
405
406 BIND(clCreateBuffer);
407 BIND(clReleaseMemObject);
408
409 BIND(clCreateProgramWithSource);
410 BIND(clCreateProgramWithBinary);
411 BIND(clBuildProgram);
412 BIND(clGetProgramInfo);
413 BIND(clGetProgramBuildInfo);
414
415 BIND(clCreateKernel);
416 BIND(clReleaseKernel);
417 BIND(clSetKernelArg);
418
419 BIND(clFlush);
420 BIND(clFinish);
421
422 BIND(clEnqueueNDRangeKernel);
423 BIND(clEnqueueReadBuffer);
424 BIND(clEnqueueMapBuffer);
425 BIND(clEnqueueUnmapMemObject);
426
427 BIND(clCreateCommandQueue);
428 BIND(clReleaseCommandQueue);
429
dirk99731742015-11-14 22:54:38 +0100430 BIND(clGetEventProfilingInfo);
431 BIND(clWaitForEvents);
432 BIND(clReleaseEvent);
433
cristy0c832c62014-03-07 22:21:04 +0000434 return MagickTrue;
435}
436
437MagickLibrary * GetOpenCLLib()
Cristy1dd96da2015-10-06 07:52:01 -0400438{
cristy0c832c62014-03-07 22:21:04 +0000439 if (OpenCLLib == NULL)
440 {
441 if (OpenCLLibLock == NULL)
442 {
443 ActivateSemaphoreInfo(&OpenCLLibLock);
444 }
445
446 LockSemaphoreInfo(OpenCLLibLock);
447
448 OpenCLLib = (MagickLibrary *) AcquireMagickMemory (sizeof (MagickLibrary));
449
450 if (OpenCLLib != NULL)
451 {
452 MagickBooleanType status = MagickFalse;
453 void * library = NULL;
454
455#ifdef MAGICKCORE_OPENCL_MACOSX
456 status = bindOpenCLFunctions(library);
457#else
Cristy1dd96da2015-10-06 07:52:01 -0400458
cristy0c832c62014-03-07 22:21:04 +0000459 memset(OpenCLLib, 0, sizeof(MagickLibrary));
460#ifdef MAGICKCORE_WINDOWS_SUPPORT
461 library = OsLibraryLoad("OpenCL.dll");
462#else
463 library = OsLibraryLoad("libOpenCL.so");
464#endif
465 if (library)
466 status = bindOpenCLFunctions(library);
467
468 if (status==MagickTrue)
469 OpenCLLib->base=library;
470 else
471 OpenCLLib=(MagickLibrary *)RelinquishMagickMemory(OpenCLLib);
472#endif
473 }
474
Cristy1dd96da2015-10-06 07:52:01 -0400475 UnlockSemaphoreInfo(OpenCLLibLock);
cristy0c832c62014-03-07 22:21:04 +0000476 }
cristy0c832c62014-03-07 22:21:04 +0000477
Cristy1dd96da2015-10-06 07:52:01 -0400478
479 return OpenCLLib;
cristy0c832c62014-03-07 22:21:04 +0000480}
481
cristyf034abb2013-11-24 14:16:14 +0000482
483/*
484%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485% %
486% %
487% %
488+ G e t D e f a u l t O p e n C L E n v %
489% %
490% %
491% %
492%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493%
494% GetDefaultOpenCLEnv() returns the default OpenCL env
495%
496% The format of the GetDefaultOpenCLEnv method is:
497%
498% MagickCLEnv GetDefaultOpenCLEnv()
499%
500% A description of each parameter follows:
501%
502% o exception: return any errors or warnings.
503%
504*/
505
dirk69838ee2016-01-10 18:22:20 +0100506MagickExport MagickCLEnv GetDefaultOpenCLEnv(void)
Cristy1dd96da2015-10-06 07:52:01 -0400507{
cristyf034abb2013-11-24 14:16:14 +0000508 if (defaultCLEnv == NULL)
509 {
510 if (defaultCLEnvLock == NULL)
511 {
cristy04b11db2014-02-16 15:10:39 +0000512 ActivateSemaphoreInfo(&defaultCLEnvLock);
cristyf034abb2013-11-24 14:16:14 +0000513 }
514 LockSemaphoreInfo(defaultCLEnvLock);
dirk99731742015-11-14 22:54:38 +0100515 if (defaultCLEnv == NULL)
516 defaultCLEnv = AcquireMagickOpenCLEnv();
Cristy1dd96da2015-10-06 07:52:01 -0400517 UnlockSemaphoreInfo(defaultCLEnvLock);
cristyf034abb2013-11-24 14:16:14 +0000518 }
Cristy1dd96da2015-10-06 07:52:01 -0400519 return defaultCLEnv;
cristyf034abb2013-11-24 14:16:14 +0000520}
521
522static void LockDefaultOpenCLEnv() {
523 if (defaultCLEnvLock == NULL)
524 {
cristy04b11db2014-02-16 15:10:39 +0000525 ActivateSemaphoreInfo(&defaultCLEnvLock);
cristyf034abb2013-11-24 14:16:14 +0000526 }
527 LockSemaphoreInfo(defaultCLEnvLock);
528}
529
530static void UnlockDefaultOpenCLEnv() {
531 if (defaultCLEnvLock == NULL)
532 {
cristy04b11db2014-02-16 15:10:39 +0000533 ActivateSemaphoreInfo(&defaultCLEnvLock);
cristyf034abb2013-11-24 14:16:14 +0000534 }
535 else
536 UnlockSemaphoreInfo(defaultCLEnvLock);
537}
538
539
540/*
541%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
542% %
543% %
544% %
545+ S e t D e f a u l t O p e n C L E n v %
546% %
547% %
548% %
549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
550%
Cristy1dd96da2015-10-06 07:52:01 -0400551% SetDefaultOpenCLEnv() sets the new OpenCL environment as default
cristyf034abb2013-11-24 14:16:14 +0000552% and returns the old OpenCL environment
Cristy1dd96da2015-10-06 07:52:01 -0400553%
cristyf034abb2013-11-24 14:16:14 +0000554% The format of the SetDefaultOpenCLEnv() method is:
555%
556% MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
557%
558% A description of each parameter follows:
559%
560% o clEnv: the new default OpenCL environment.
561%
562*/
Cristy1dd96da2015-10-06 07:52:01 -0400563MagickExport MagickCLEnv SetDefaultOpenCLEnv(MagickCLEnv clEnv)
cristyf034abb2013-11-24 14:16:14 +0000564{
565 MagickCLEnv oldEnv;
566 LockDefaultOpenCLEnv();
567 oldEnv = defaultCLEnv;
568 defaultCLEnv = clEnv;
569 UnlockDefaultOpenCLEnv();
570 return oldEnv;
Cristy1dd96da2015-10-06 07:52:01 -0400571}
cristyf034abb2013-11-24 14:16:14 +0000572
573
574
575/*
576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577% %
578% %
579% %
580+ S e t M a g i c k O p e n C L E n v P a r a m %
581% %
582% %
583% %
584%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
585%
Cristy1dd96da2015-10-06 07:52:01 -0400586% SetMagickOpenCLEnvParam() sets the parameters in the OpenCL environment
587%
cristyf034abb2013-11-24 14:16:14 +0000588% The format of the SetMagickOpenCLEnvParam() method is:
589%
Cristy1dd96da2015-10-06 07:52:01 -0400590% MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv,
591% MagickOpenCLEnvParam param, size_t dataSize, void* data,
cristyf034abb2013-11-24 14:16:14 +0000592% ExceptionInfo* exception)
593%
594% A description of each parameter follows:
595%
596% o clEnv: the OpenCL environment.
Cristy1dd96da2015-10-06 07:52:01 -0400597%
cristyf034abb2013-11-24 14:16:14 +0000598% o param: the parameter to be set.
599%
600% o dataSize: the data size of the parameter value.
601%
602% o data: the pointer to the new parameter value
603%
604% o exception: return any errors or warnings
605%
606*/
607
608static MagickBooleanType SetMagickOpenCLEnvParamInternal(MagickCLEnv clEnv, MagickOpenCLEnvParam param
609 , size_t dataSize, void* data, ExceptionInfo* exception)
610{
611 MagickBooleanType status = MagickFalse;
612
613 if (clEnv == NULL
614 || data == NULL)
615 goto cleanup;
616
617 switch(param)
618 {
619 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
620 if (dataSize != sizeof(clEnv->device))
621 goto cleanup;
622 clEnv->device = *((cl_device_id*)data);
623 clEnv->OpenCLInitialized = MagickFalse;
624 status = MagickTrue;
625 break;
626
627 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
628 if (dataSize != sizeof(clEnv->OpenCLDisabled))
629 goto cleanup;
630 clEnv->OpenCLDisabled = *((MagickBooleanType*)data);
631 clEnv->OpenCLInitialized = MagickFalse;
632 status = MagickTrue;
633 break;
634
635 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
636 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "SetMagickOpenCLEnvParm cannot modify the OpenCL initialization state.", "'%s'", ".");
637 break;
638
dirk20932d32013-12-12 06:16:19 +0000639 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
640 if (dataSize != sizeof(clEnv->disableProgramCache))
641 goto cleanup;
642 clEnv->disableProgramCache = *((MagickBooleanType*)data);
643 clEnv->OpenCLInitialized = MagickFalse;
644 status = MagickTrue;
645 break;
646
647 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
648 if (dataSize != sizeof(clEnv->regenerateProfile))
649 goto cleanup;
650 clEnv->regenerateProfile = *((MagickBooleanType*)data);
651 clEnv->OpenCLInitialized = MagickFalse;
652 status = MagickTrue;
653 break;
654
cristyf034abb2013-11-24 14:16:14 +0000655 default:
656 goto cleanup;
657 };
658
659cleanup:
660 return status;
661}
662
663MagickExport
664 MagickBooleanType SetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
665 , size_t dataSize, void* data, ExceptionInfo* exception) {
666 MagickBooleanType status = MagickFalse;
667 if (clEnv!=NULL) {
668 LockSemaphoreInfo(clEnv->lock);
669 status = SetMagickOpenCLEnvParamInternal(clEnv,param,dataSize,data,exception);
670 UnlockSemaphoreInfo(clEnv->lock);
671 }
672 return status;
673}
674
675/*
676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
677% %
678% %
679% %
680+ G e t M a g i c k O p e n C L E n v P a r a m %
681% %
682% %
683% %
684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685%
Cristy1dd96da2015-10-06 07:52:01 -0400686% GetMagickOpenCLEnvParam() gets the parameters in the OpenCL environment
687%
cristyf034abb2013-11-24 14:16:14 +0000688% The format of the GetMagickOpenCLEnvParam() method is:
689%
Cristy1dd96da2015-10-06 07:52:01 -0400690% MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv,
691% MagickOpenCLEnvParam param, size_t dataSize, void* data,
cristyf034abb2013-11-24 14:16:14 +0000692% ExceptionInfo* exception)
693%
694% A description of each parameter follows:
695%
696% o clEnv: the OpenCL environment.
Cristy1dd96da2015-10-06 07:52:01 -0400697%
cristyf034abb2013-11-24 14:16:14 +0000698% o param: the parameter to be returned.
699%
700% o dataSize: the data size of the parameter value.
701%
Cristy1dd96da2015-10-06 07:52:01 -0400702% o data: the location where the returned parameter value will be stored
cristyf034abb2013-11-24 14:16:14 +0000703%
704% o exception: return any errors or warnings
705%
706*/
707
708MagickExport
709 MagickBooleanType GetMagickOpenCLEnvParam(MagickCLEnv clEnv, MagickOpenCLEnvParam param
710 , size_t dataSize, void* data, ExceptionInfo* exception)
711{
Cristy1dd96da2015-10-06 07:52:01 -0400712 MagickBooleanType
dirk5dcb7622013-12-01 10:43:43 +0000713 status;
714
715 magick_unreferenced(exception);
716
cristyf034abb2013-11-24 14:16:14 +0000717 status = MagickFalse;
718
719 if (clEnv == NULL
720 || data == NULL)
721 goto cleanup;
722
723 switch(param)
724 {
725 case MAGICK_OPENCL_ENV_PARAM_DEVICE:
726 if (dataSize != sizeof(cl_device_id))
727 goto cleanup;
728 *((cl_device_id*)data) = clEnv->device;
729 status = MagickTrue;
730 break;
731
732 case MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED:
733 if (dataSize != sizeof(clEnv->OpenCLDisabled))
734 goto cleanup;
735 *((MagickBooleanType*)data) = clEnv->OpenCLDisabled;
736 status = MagickTrue;
737 break;
738
739 case MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED:
740 if (dataSize != sizeof(clEnv->OpenCLDisabled))
741 goto cleanup;
742 *((MagickBooleanType*)data) = clEnv->OpenCLInitialized;
743 status = MagickTrue;
744 break;
745
dirk20932d32013-12-12 06:16:19 +0000746 case MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED:
747 if (dataSize != sizeof(clEnv->disableProgramCache))
748 goto cleanup;
749 *((MagickBooleanType*)data) = clEnv->disableProgramCache;
750 status = MagickTrue;
751 break;
752
753 case MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE:
754 if (dataSize != sizeof(clEnv->regenerateProfile))
755 goto cleanup;
756 *((MagickBooleanType*)data) = clEnv->regenerateProfile;
757 status = MagickTrue;
758 break;
759
cristyf034abb2013-11-24 14:16:14 +0000760 default:
761 goto cleanup;
762 };
763
764cleanup:
765 return status;
766}
767
768
769/*
770%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771% %
772% %
773% %
774+ G e t O p e n C L C o n t e x t %
775% %
776% %
777% %
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779%
Cristy1dd96da2015-10-06 07:52:01 -0400780% GetOpenCLContext() returns the OpenCL context
781%
cristyf034abb2013-11-24 14:16:14 +0000782% The format of the GetOpenCLContext() method is:
783%
Cristy1dd96da2015-10-06 07:52:01 -0400784% cl_context GetOpenCLContext(MagickCLEnv clEnv)
cristyf034abb2013-11-24 14:16:14 +0000785%
786% A description of each parameter follows:
787%
788% o clEnv: OpenCL environment
789%
790*/
791
cristy7b6514c2013-12-10 23:13:13 +0000792MagickPrivate
cristyf034abb2013-11-24 14:16:14 +0000793cl_context GetOpenCLContext(MagickCLEnv clEnv) {
794 if (clEnv == NULL)
795 return NULL;
796 else
797 return clEnv->context;
798}
799
800static char* getBinaryCLProgramName(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
801{
802 char* name;
cristye85d0f72013-11-27 02:25:43 +0000803 char* ptr;
cristy151b66d2015-04-15 10:50:31 +0000804 char path[MagickPathExtent];
805 char deviceName[MagickPathExtent];
cristyf034abb2013-11-24 14:16:14 +0000806 const char* prefix = "magick_opencl";
cristy151b66d2015-04-15 10:50:31 +0000807 clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_NAME, MagickPathExtent, deviceName, NULL);
cristye85d0f72013-11-27 02:25:43 +0000808 ptr=deviceName;
809 /* strip out illegal characters for file names */
810 while (*ptr != '\0')
811 {
Cristy1dd96da2015-10-06 07:52:01 -0400812 if ( *ptr == ' ' || *ptr == '\\' || *ptr == '/' || *ptr == ':' || *ptr == '*'
cristye85d0f72013-11-27 02:25:43 +0000813 || *ptr == '?' || *ptr == '"' || *ptr == '<' || *ptr == '>' || *ptr == '|')
814 {
815 *ptr = '_';
816 }
817 ptr++;
818 }
cristy151b66d2015-04-15 10:50:31 +0000819 (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s_%s_%02d_%08x_%.20g.bin",
dirkd091dc32013-12-11 12:26:40 +0000820 GetOpenCLCachedFilesDirectory(),DirectorySeparator,prefix,deviceName,
dirk584cf812013-12-12 07:59:15 +0000821 (unsigned int) prog,signature,(double) sizeof(char*)*8);
cristyf034abb2013-11-24 14:16:14 +0000822 name = (char*)AcquireMagickMemory(strlen(path)+1);
823 CopyMagickString(name,path,strlen(path)+1);
824 return name;
825}
826
827static MagickBooleanType saveBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature, ExceptionInfo* exception)
828{
829 MagickBooleanType saveSuccessful;
830 cl_int clStatus;
831 size_t binaryProgramSize;
832 unsigned char* binaryProgram;
833 char* binaryFileName;
834 FILE* fileHandle;
835
836#ifdef MAGICKCORE_CLPERFMARKER
837 clBeginPerfMarkerAMD(__FUNCTION__,"");
838#endif
839
840 binaryProgram = NULL;
841 binaryFileName = NULL;
842 fileHandle = NULL;
843 saveSuccessful = MagickFalse;
844
cristy0c832c62014-03-07 22:21:04 +0000845 clStatus = clEnv->library->clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binaryProgramSize, NULL);
cristyf034abb2013-11-24 14:16:14 +0000846 if (clStatus != CL_SUCCESS)
847 {
848 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
849 goto cleanup;
850 }
851
852 binaryProgram = (unsigned char*) AcquireMagickMemory(binaryProgramSize);
cristy0c832c62014-03-07 22:21:04 +0000853 clStatus = clEnv->library->clGetProgramInfo(clEnv->programs[prog], CL_PROGRAM_BINARIES, sizeof(char*), &binaryProgram, NULL);
cristyf034abb2013-11-24 14:16:14 +0000854 if (clStatus != CL_SUCCESS)
855 {
856 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "clGetProgramInfo failed.", "'%s'", ".");
857 goto cleanup;
858 }
859
860 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
861 fileHandle = fopen(binaryFileName, "wb");
862 if (fileHandle != NULL)
863 {
864 fwrite(binaryProgram, sizeof(char), binaryProgramSize, fileHandle);
865 saveSuccessful = MagickTrue;
866 }
867 else
868 {
869 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
870 "Saving binary kernel failed.", "'%s'", ".");
871 }
872
873cleanup:
874 if (fileHandle != NULL)
875 fclose(fileHandle);
876 if (binaryProgram != NULL)
877 RelinquishMagickMemory(binaryProgram);
878 if (binaryFileName != NULL)
879 free(binaryFileName);
880
881#ifdef MAGICKCORE_CLPERFMARKER
882 clEndPerfMarkerAMD();
883#endif
884
885 return saveSuccessful;
886}
887
dirk5dcb7622013-12-01 10:43:43 +0000888static MagickBooleanType loadBinaryCLProgram(MagickCLEnv clEnv, MagickOpenCLProgram prog, unsigned int signature)
cristyf034abb2013-11-24 14:16:14 +0000889{
890 MagickBooleanType loadSuccessful;
891 unsigned char* binaryProgram;
892 char* binaryFileName;
893 FILE* fileHandle;
894
895#ifdef MAGICKCORE_CLPERFMARKER
896 clBeginPerfMarkerAMD(__FUNCTION__,"");
897#endif
898
899 binaryProgram = NULL;
900 binaryFileName = NULL;
901 fileHandle = NULL;
902 loadSuccessful = MagickFalse;
903
904 binaryFileName = getBinaryCLProgramName(clEnv, prog, signature);
905 fileHandle = fopen(binaryFileName, "rb");
906 if (fileHandle != NULL)
907 {
908 int b_error;
909 size_t length;
910 cl_int clStatus;
911 cl_int clBinaryStatus;
912
913 b_error = 0 ;
914 length = 0;
915 b_error |= fseek( fileHandle, 0, SEEK_END ) < 0;
916 b_error |= ( length = ftell( fileHandle ) ) <= 0;
917 b_error |= fseek( fileHandle, 0, SEEK_SET ) < 0;
918 if( b_error )
919 goto cleanup;
920
921 binaryProgram = (unsigned char*)AcquireMagickMemory(length);
922 if (binaryProgram == NULL)
923 goto cleanup;
924
925 memset(binaryProgram, 0, length);
926 b_error |= fread(binaryProgram, 1, length, fileHandle) != length;
927
cristy0c832c62014-03-07 22:21:04 +0000928 clEnv->programs[prog] = clEnv->library->clCreateProgramWithBinary(clEnv->context, 1, &clEnv->device, &length, (const unsigned char**)&binaryProgram, &clBinaryStatus, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000929 if (clStatus != CL_SUCCESS
930 || clBinaryStatus != CL_SUCCESS)
931 goto cleanup;
932
933 loadSuccessful = MagickTrue;
934 }
935
936cleanup:
937 if (fileHandle != NULL)
938 fclose(fileHandle);
939 if (binaryFileName != NULL)
940 free(binaryFileName);
941 if (binaryProgram != NULL)
942 RelinquishMagickMemory(binaryProgram);
943
944#ifdef MAGICKCORE_CLPERFMARKER
945 clEndPerfMarkerAMD();
946#endif
947
948 return loadSuccessful;
949}
950
951static unsigned int stringSignature(const char* string)
952{
953 unsigned int stringLength;
954 unsigned int n,i,j;
955 unsigned int signature;
956 union
957 {
958 const char* s;
959 const unsigned int* u;
960 }p;
961
962#ifdef MAGICKCORE_CLPERFMARKER
963 clBeginPerfMarkerAMD(__FUNCTION__,"");
964#endif
965
dirkb0d783f2014-08-31 10:48:05 +0000966 stringLength = (unsigned int) strlen(string);
cristyf034abb2013-11-24 14:16:14 +0000967 signature = stringLength;
968 n = stringLength/sizeof(unsigned int);
969 p.s = string;
970 for (i = 0; i < n; i++)
971 {
972 signature^=p.u[i];
973 }
974 if (n * sizeof(unsigned int) != stringLength)
975 {
976 char padded[4];
977 j = n * sizeof(unsigned int);
978 for (i = 0; i < 4; i++,j++)
979 {
980 if (j < stringLength)
981 padded[i] = p.s[j];
982 else
983 padded[i] = 0;
984 }
985 p.s = padded;
986 signature^=p.u[0];
987 }
988
989#ifdef MAGICKCORE_CLPERFMARKER
990 clEndPerfMarkerAMD();
991#endif
992
993 return signature;
994}
995
996/* OpenCL kernels for accelerate.c */
997extern const char *accelerateKernels, *accelerateKernels2;
998
Cristy1dd96da2015-10-06 07:52:01 -0400999static MagickBooleanType CompileOpenCLKernels(MagickCLEnv clEnv, ExceptionInfo* exception)
cristyf034abb2013-11-24 14:16:14 +00001000{
1001 MagickBooleanType status = MagickFalse;
1002 cl_int clStatus;
1003 unsigned int i;
1004 char* accelerateKernelsBuffer = NULL;
1005
1006 /* The index of the program strings in this array has to match the value of the enum MagickOpenCLProgram */
Cristy1dd96da2015-10-06 07:52:01 -04001007 const char* MagickOpenCLProgramStrings[MAGICK_OPENCL_NUM_PROGRAMS];
cristyf034abb2013-11-24 14:16:14 +00001008
cristy151b66d2015-04-15 10:50:31 +00001009 char options[MagickPathExtent];
cristyf034abb2013-11-24 14:16:14 +00001010 unsigned int optionsSignature;
1011
1012#ifdef MAGICKCORE_CLPERFMARKER
1013 clBeginPerfMarkerAMD(__FUNCTION__,"");
1014#endif
1015
1016 /* Get additional options */
cristy151b66d2015-04-15 10:50:31 +00001017 (void) FormatLocaleString(options, MagickPathExtent, CLOptions, (float)QuantumRange,
cristyf034abb2013-11-24 14:16:14 +00001018 (float)QuantumScale, (float)CLCharQuantumScale, (float)MagickEpsilon, (float)MagickPI, (unsigned int)MaxMap, (unsigned int)MAGICKCORE_QUANTUM_DEPTH);
1019
1020 /*
1021 if (getenv("MAGICK_OCL_DEF"))
1022 {
1023 strcat(options," ");
1024 strcat(options,getenv("MAGICK_OCL_DEF"));
1025 }
1026 */
1027
1028 /*
1029 if (getenv("MAGICK_OCL_BUILD"))
1030 printf("options: %s\n", options);
1031 */
1032
1033 optionsSignature = stringSignature(options);
1034
1035 /* get all the OpenCL program strings here */
1036 accelerateKernelsBuffer = (char*) AcquireMagickMemory(strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
1037 sprintf(accelerateKernelsBuffer,"%s%s",accelerateKernels,accelerateKernels2);
1038 MagickOpenCLProgramStrings[MAGICK_OPENCL_ACCELERATE] = accelerateKernelsBuffer;
1039
Cristy1dd96da2015-10-06 07:52:01 -04001040 for (i = 0; i < MAGICK_OPENCL_NUM_PROGRAMS; i++)
cristyf034abb2013-11-24 14:16:14 +00001041 {
1042 MagickBooleanType loadSuccessful = MagickFalse;
1043 unsigned int programSignature = stringSignature(MagickOpenCLProgramStrings[i]) ^ optionsSignature;
1044
1045 /* try to load the binary first */
dirk20932d32013-12-12 06:16:19 +00001046 if (clEnv->disableProgramCache != MagickTrue
1047 && !getenv("MAGICK_OCL_REC"))
dirk5dcb7622013-12-01 10:43:43 +00001048 loadSuccessful = loadBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature);
cristyf034abb2013-11-24 14:16:14 +00001049
1050 if (loadSuccessful == MagickFalse)
1051 {
1052 /* Binary CL program unavailable, compile the program from source */
1053 size_t programLength = strlen(MagickOpenCLProgramStrings[i]);
cristy0c832c62014-03-07 22:21:04 +00001054 clEnv->programs[i] = clEnv->library->clCreateProgramWithSource(clEnv->context, 1, &(MagickOpenCLProgramStrings[i]), &programLength, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001055 if (clStatus!=CL_SUCCESS)
1056 {
1057 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1058 "clCreateProgramWithSource failed.", "(%d)", (int)clStatus);
1059
1060 goto cleanup;
1061 }
1062 }
1063
cristy0c832c62014-03-07 22:21:04 +00001064 clStatus = clEnv->library->clBuildProgram(clEnv->programs[i], 1, &clEnv->device, options, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001065 if (clStatus!=CL_SUCCESS)
1066 {
1067 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1068 "clBuildProgram failed.", "(%d)", (int)clStatus);
1069
1070 if (loadSuccessful == MagickFalse)
1071 {
cristy151b66d2015-04-15 10:50:31 +00001072 char path[MagickPathExtent];
cristyf034abb2013-11-24 14:16:14 +00001073 FILE* fileHandle;
1074
1075 /* dump the source into a file */
cristy151b66d2015-04-15 10:50:31 +00001076 (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
cristyf034abb2013-11-24 14:16:14 +00001077 ,GetOpenCLCachedFilesDirectory()
1078 ,DirectorySeparator,"magick_badcl.cl");
1079 fileHandle = fopen(path, "wb");
1080 if (fileHandle != NULL)
1081 {
1082 fwrite(MagickOpenCLProgramStrings[i], sizeof(char), strlen(MagickOpenCLProgramStrings[i]), fileHandle);
1083 fclose(fileHandle);
1084 }
1085
1086 /* dump the build log */
1087 {
1088 char* log;
1089 size_t logSize;
cristy0c832c62014-03-07 22:21:04 +00001090 clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
cristyf034abb2013-11-24 14:16:14 +00001091 log = (char*)AcquireMagickMemory(logSize);
cristy0c832c62014-03-07 22:21:04 +00001092 clEnv->library->clGetProgramBuildInfo(clEnv->programs[i], clEnv->device, CL_PROGRAM_BUILD_LOG, logSize, log, &logSize);
cristyf034abb2013-11-24 14:16:14 +00001093
cristy151b66d2015-04-15 10:50:31 +00001094 (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
cristyf034abb2013-11-24 14:16:14 +00001095 ,GetOpenCLCachedFilesDirectory()
1096 ,DirectorySeparator,"magick_badcl_build.log");
1097 fileHandle = fopen(path, "wb");
1098 if (fileHandle != NULL)
1099 {
1100 const char* buildOptionsTitle = "build options: ";
1101 fwrite(buildOptionsTitle, sizeof(char), strlen(buildOptionsTitle), fileHandle);
1102 fwrite(options, sizeof(char), strlen(options), fileHandle);
1103 fwrite("\n",sizeof(char), 1, fileHandle);
1104 fwrite(log, sizeof(char), logSize, fileHandle);
1105 fclose(fileHandle);
1106 }
1107 RelinquishMagickMemory(log);
1108 }
1109 }
1110 goto cleanup;
1111 }
1112
1113 if (loadSuccessful == MagickFalse)
1114 {
1115 /* Save the binary to a file to avoid re-compilation of the kernels in the future */
1116 saveBinaryCLProgram(clEnv, (MagickOpenCLProgram)i, programSignature, exception);
1117 }
1118
1119 }
1120 status = MagickTrue;
1121
1122cleanup:
1123
1124 if (accelerateKernelsBuffer!=NULL) RelinquishMagickMemory(accelerateKernelsBuffer);
1125
1126#ifdef MAGICKCORE_CLPERFMARKER
1127 clEndPerfMarkerAMD();
1128#endif
1129
1130 return status;
1131}
1132
1133static MagickBooleanType InitOpenCLPlatformDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
1134 int i,j;
1135 cl_int status;
1136 cl_uint numPlatforms = 0;
1137 cl_platform_id *platforms = NULL;
1138 char* MAGICK_OCL_DEVICE = NULL;
1139 MagickBooleanType OpenCLAvailable = MagickFalse;
1140
1141#ifdef MAGICKCORE_CLPERFMARKER
1142 clBeginPerfMarkerAMD(__FUNCTION__,"");
1143#endif
1144
1145 /* check if there's an environment variable overriding the device selection */
1146 MAGICK_OCL_DEVICE = getenv("MAGICK_OCL_DEVICE");
1147 if (MAGICK_OCL_DEVICE != NULL)
1148 {
1149 if (strcmp(MAGICK_OCL_DEVICE, "CPU") == 0)
1150 {
1151 clEnv->deviceType = CL_DEVICE_TYPE_CPU;
1152 }
1153 else if (strcmp(MAGICK_OCL_DEVICE, "GPU") == 0)
1154 {
1155 clEnv->deviceType = CL_DEVICE_TYPE_GPU;
1156 }
1157 else if (strcmp(MAGICK_OCL_DEVICE, "OFF") == 0)
1158 {
1159 /* OpenCL disabled */
1160 goto cleanup;
1161 }
1162 }
1163 else if (clEnv->deviceType == 0) {
1164 clEnv->deviceType = CL_DEVICE_TYPE_ALL;
1165 }
1166
1167 if (clEnv->device != NULL)
1168 {
cristy0c832c62014-03-07 22:21:04 +00001169 status = clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_PLATFORM, sizeof(cl_platform_id), &clEnv->platform, NULL);
cristyf034abb2013-11-24 14:16:14 +00001170 if (status != CL_SUCCESS) {
1171 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1172 "Failed to get OpenCL platform from the selected device.", "(%d)", status);
1173 }
1174 goto cleanup;
1175 }
1176 else if (clEnv->platform != NULL)
1177 {
1178 numPlatforms = 1;
1179 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
1180 if (platforms == (cl_platform_id *) NULL)
1181 {
1182 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
1183 "AcquireMagickMemory failed.",".");
1184 goto cleanup;
1185 }
1186 platforms[0] = clEnv->platform;
1187 }
1188 else
1189 {
1190 clEnv->device = NULL;
1191
1192 /* Get the number of OpenCL platforms available */
cristy0c832c62014-03-07 22:21:04 +00001193 status = clEnv->library->clGetPlatformIDs(0, NULL, &numPlatforms);
cristyf034abb2013-11-24 14:16:14 +00001194 if (status != CL_SUCCESS)
1195 {
Cristy1dd96da2015-10-06 07:52:01 -04001196 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
cristyf034abb2013-11-24 14:16:14 +00001197 "clGetplatformIDs failed.", "(%d)", status);
1198 goto cleanup;
1199 }
1200
1201 /* No OpenCL available, just leave */
1202 if (numPlatforms == 0) {
1203 goto cleanup;
1204 }
1205
1206 platforms = (cl_platform_id *) AcquireMagickMemory(numPlatforms * sizeof(cl_platform_id));
1207 if (platforms == (cl_platform_id *) NULL)
1208 {
1209 (void) ThrowMagickException(exception, GetMagickModule(), ResourceLimitError,
1210 "AcquireMagickMemory failed.",".");
1211 goto cleanup;
1212 }
1213
cristy0c832c62014-03-07 22:21:04 +00001214 status = clEnv->library->clGetPlatformIDs(numPlatforms, platforms, NULL);
cristyf034abb2013-11-24 14:16:14 +00001215 if (status != CL_SUCCESS)
1216 {
1217 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1218 "clGetPlatformIDs failed.", "(%d)", status);
1219 goto cleanup;
1220 }
1221 }
1222
1223 /* Device selection */
1224 clEnv->device = NULL;
Cristy1dd96da2015-10-06 07:52:01 -04001225 for (j = 0; j < 2; j++)
cristyf034abb2013-11-24 14:16:14 +00001226 {
1227
1228 cl_device_type deviceType;
1229 if (clEnv->deviceType == CL_DEVICE_TYPE_ALL)
1230 {
1231 if (j == 0)
1232 deviceType = CL_DEVICE_TYPE_GPU;
1233 else
1234 deviceType = CL_DEVICE_TYPE_CPU;
1235 }
1236 else if (j == 1)
1237 {
1238 break;
1239 }
1240 else
1241 deviceType = clEnv->deviceType;
1242
1243 for (i = 0; i < numPlatforms; i++)
1244 {
cristy151b66d2015-04-15 10:50:31 +00001245 char version[MagickPathExtent];
cristyf034abb2013-11-24 14:16:14 +00001246 cl_uint numDevices;
cristy151b66d2015-04-15 10:50:31 +00001247 status = clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_VERSION, MagickPathExtent, version, NULL);
dirkafb5e942014-07-11 18:20:52 +00001248 if (status != CL_SUCCESS)
1249 {
1250 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1251 "clGetPlatformInfo failed.", "(%d)", status);
1252 goto cleanup;
1253 }
1254 if (strncmp(version,"OpenCL 1.0 ",11) == 0)
1255 continue;
cristy0c832c62014-03-07 22:21:04 +00001256 status = clEnv->library->clGetDeviceIDs(platforms[i], deviceType, 1, &(clEnv->device), &numDevices);
cristyf034abb2013-11-24 14:16:14 +00001257 if (status != CL_SUCCESS)
1258 {
1259 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
cristy0c832c62014-03-07 22:21:04 +00001260 "clGetDeviceIDs failed.", "(%d)", status);
cristyf034abb2013-11-24 14:16:14 +00001261 goto cleanup;
1262 }
1263 if (clEnv->device != NULL)
1264 {
1265 clEnv->platform = platforms[i];
1266 goto cleanup;
1267 }
1268 }
1269 }
1270
1271cleanup:
1272 if (platforms!=NULL)
1273 RelinquishMagickMemory(platforms);
1274
1275 OpenCLAvailable = (clEnv->platform!=NULL
1276 && clEnv->device!=NULL)?MagickTrue:MagickFalse;
1277
1278#ifdef MAGICKCORE_CLPERFMARKER
1279 clEndPerfMarkerAMD();
1280#endif
1281
1282 return OpenCLAvailable;
1283}
1284
1285static MagickBooleanType EnableOpenCLInternal(MagickCLEnv clEnv) {
cristycd8b3312013-12-22 01:51:11 +00001286 if (clEnv->OpenCLInitialized != MagickFalse
cristyf034abb2013-11-24 14:16:14 +00001287 && clEnv->platform != NULL
1288 && clEnv->device != NULL) {
1289 clEnv->OpenCLDisabled = MagickFalse;
1290 return MagickTrue;
1291 }
1292 clEnv->OpenCLDisabled = MagickTrue;
1293 return MagickFalse;
1294}
1295
1296
1297static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception);
1298/*
1299%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300% %
1301% %
1302% %
1303+ I n i t O p e n C L E n v %
1304% %
1305% %
1306% %
1307%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1308%
1309% InitOpenCLEnv() initialize the OpenCL environment
1310%
1311% The format of the RelinquishMagickOpenCLEnv method is:
1312%
1313% MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception)
1314%
1315% A description of each parameter follows:
1316%
1317% o clEnv: OpenCL environment structure
1318%
1319% o exception: return any errors or warnings.
1320%
1321*/
1322
1323MagickExport
1324MagickBooleanType InitOpenCLEnvInternal(MagickCLEnv clEnv, ExceptionInfo* exception) {
1325 MagickBooleanType status = MagickTrue;
1326 cl_int clStatus;
1327 cl_context_properties cps[3];
1328
cristy0c832c62014-03-07 22:21:04 +00001329#ifdef MAGICKCORE_CLPERFMARKER
1330 {
1331 int status = clInitializePerfMarkerAMD();
1332 if (status == AP_SUCCESS) {
1333 //printf("PerfMarker successfully initialized\n");
1334 }
1335 }
1336#endif
cristyf034abb2013-11-24 14:16:14 +00001337 clEnv->OpenCLInitialized = MagickTrue;
cristy0c832c62014-03-07 22:21:04 +00001338
1339 /* check and init the global lib */
1340 OpenCLLib=GetOpenCLLib();
1341 if (OpenCLLib)
1342 {
1343 clEnv->library=OpenCLLib;
1344 }
1345 else
1346 {
1347 /* turn off opencl */
1348 MagickBooleanType flag;
1349 flag = MagickTrue;
1350 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
1351 , sizeof(MagickBooleanType), &flag, exception);
1352 }
Cristy1dd96da2015-10-06 07:52:01 -04001353
cristycd8b3312013-12-22 01:51:11 +00001354 if (clEnv->OpenCLDisabled != MagickFalse)
cristyf034abb2013-11-24 14:16:14 +00001355 goto cleanup;
1356
1357 clEnv->OpenCLDisabled = MagickTrue;
1358 /* setup the OpenCL platform and device */
1359 status = InitOpenCLPlatformDevice(clEnv, exception);
1360 if (status == MagickFalse) {
1361 /* No OpenCL device available */
1362 goto cleanup;
1363 }
1364
1365 /* create an OpenCL context */
1366 cps[0] = CL_CONTEXT_PLATFORM;
1367 cps[1] = (cl_context_properties)clEnv->platform;
1368 cps[2] = 0;
cristy0c832c62014-03-07 22:21:04 +00001369 clEnv->context = clEnv->library->clCreateContext(cps, 1, &(clEnv->device), NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001370 if (clStatus != CL_SUCCESS)
1371 {
1372 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1373 "clCreateContext failed.", "(%d)", clStatus);
1374 status = MagickFalse;
1375 goto cleanup;
1376 }
1377
1378 status = CompileOpenCLKernels(clEnv, exception);
1379 if (status == MagickFalse) {
1380 (void) ThrowMagickException(exception, GetMagickModule(), DelegateWarning,
1381 "clCreateCommandQueue failed.", "(%d)", status);
1382
1383 status = MagickFalse;
1384 goto cleanup;
1385 }
1386
1387 status = EnableOpenCLInternal(clEnv);
cristy0c832c62014-03-07 22:21:04 +00001388
cristyf034abb2013-11-24 14:16:14 +00001389cleanup:
1390 return status;
1391}
1392
1393
1394MagickExport
1395MagickBooleanType InitOpenCLEnv(MagickCLEnv clEnv, ExceptionInfo* exception) {
1396 MagickBooleanType status = MagickFalse;
1397
1398 if (clEnv == NULL)
1399 return MagickFalse;
1400
1401#ifdef MAGICKCORE_CLPERFMARKER
1402 clBeginPerfMarkerAMD(__FUNCTION__,"");
1403#endif
1404
1405 LockSemaphoreInfo(clEnv->lock);
1406 if (clEnv->OpenCLInitialized == MagickFalse) {
1407 if (clEnv->device==NULL
1408 && clEnv->OpenCLDisabled == MagickFalse)
1409 status = autoSelectDevice(clEnv, exception);
1410 else
1411 status = InitOpenCLEnvInternal(clEnv, exception);
1412 }
1413 UnlockSemaphoreInfo(clEnv->lock);
1414
1415#ifdef MAGICKCORE_CLPERFMARKER
1416 clEndPerfMarkerAMD();
1417#endif
1418 return status;
1419}
1420
1421
1422/*
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424% %
1425% %
1426% %
1427+ 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 %
1428% %
1429% %
1430% %
1431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1432%
1433% AcquireOpenCLCommandQueue() acquires an OpenCL command queue
1434%
1435% The format of the AcquireOpenCLCommandQueue method is:
1436%
1437% cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
1438%
1439% A description of each parameter follows:
1440%
1441% o clEnv: the OpenCL environment.
1442%
1443*/
1444
dirk99731742015-11-14 22:54:38 +01001445MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(MagickCLEnv clEnv)
cristyf034abb2013-11-24 14:16:14 +00001446{
dirk99731742015-11-14 22:54:38 +01001447 cl_command_queue
1448 queue;
cristyf034abb2013-11-24 14:16:14 +00001449
dirk99731742015-11-14 22:54:38 +01001450 cl_command_queue_properties
1451 properties;
1452
1453 if (clEnv == (MagickCLEnv) NULL)
1454 return (cl_command_queue) NULL;
1455 LockSemaphoreInfo(clEnv->commandQueuesLock);
1456 if (clEnv->commandQueuesPos >= 0) {
1457 queue=clEnv->commandQueues[clEnv->commandQueuesPos--];
1458 UnlockSemaphoreInfo(clEnv->commandQueuesLock);
1459 }
1460 else {
1461 UnlockSemaphoreInfo(clEnv->commandQueuesLock);
1462 properties=0;
1463#if PROFILE_OCL_KERNELS
1464 properties=CL_QUEUE_PROFILING_ENABLE;
1465#endif
1466 queue=clEnv->library->clCreateCommandQueue(clEnv->context,clEnv->device,
1467 properties,NULL);
1468 }
1469 return(queue);
1470}
cristyf034abb2013-11-24 14:16:14 +00001471
1472/*
1473%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1474% %
1475% %
1476% %
1477+ 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 %
1478% %
1479% %
1480% %
1481%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1482%
1483% RelinquishOpenCLCommandQueue() releases the OpenCL command queue
1484%
1485% The format of the RelinquishOpenCLCommandQueue method is:
1486%
1487% MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1488% cl_command_queue queue)
1489%
1490% A description of each parameter follows:
1491%
1492% o clEnv: the OpenCL environment.
1493%
1494% o queue: the OpenCL queue to be released.
1495%
1496%
1497*/
dirk99731742015-11-14 22:54:38 +01001498
1499MagickPrivate MagickBooleanType RelinquishOpenCLCommandQueue(MagickCLEnv clEnv,
1500 cl_command_queue queue)
cristyf034abb2013-11-24 14:16:14 +00001501{
dirk99731742015-11-14 22:54:38 +01001502 MagickBooleanType
1503 status;
1504
1505 if (clEnv == NULL)
1506 return(MagickFalse);
1507
1508 LockSemaphoreInfo(clEnv->commandQueuesLock);
1509
1510 if (clEnv->commandQueuesPos >= MAX_COMMAND_QUEUES)
1511 status=(clEnv->library->clReleaseCommandQueue(queue) == CL_SUCCESS) ?
1512 MagickTrue : MagickFalse;
cristyf034abb2013-11-24 14:16:14 +00001513 else
dirk99731742015-11-14 22:54:38 +01001514 {
1515 clEnv->commandQueues[++clEnv->commandQueuesPos]=queue;
1516 status=MagickTrue;
1517 }
1518
1519 UnlockSemaphoreInfo(clEnv->commandQueuesLock);
1520
1521 return(status);
cristyf034abb2013-11-24 14:16:14 +00001522}
1523
cristyf034abb2013-11-24 14:16:14 +00001524/*
1525%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1526% %
1527% %
1528% %
1529+ A c q u i r e O p e n C L K e r n e l %
1530% %
1531% %
1532% %
1533%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534%
1535% AcquireOpenCLKernel() acquires an OpenCL kernel
1536%
1537% The format of the AcquireOpenCLKernel method is:
1538%
Cristy1dd96da2015-10-06 07:52:01 -04001539% cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
cristyf034abb2013-11-24 14:16:14 +00001540% MagickOpenCLProgram program, const char* kernelName)
1541%
1542% A description of each parameter follows:
1543%
1544% o clEnv: the OpenCL environment.
1545%
1546% o program: the OpenCL program module that the kernel belongs to.
1547%
1548% o kernelName: the name of the kernel
1549%
1550*/
1551
cristy7b6514c2013-12-10 23:13:13 +00001552MagickPrivate
cristyf034abb2013-11-24 14:16:14 +00001553 cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv, MagickOpenCLProgram program, const char* kernelName)
1554{
1555 cl_int clStatus;
1556 cl_kernel kernel = NULL;
1557 if (clEnv != NULL && kernelName!=NULL)
1558 {
cristy0c832c62014-03-07 22:21:04 +00001559 kernel = clEnv->library->clCreateKernel(clEnv->programs[program], kernelName, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001560 }
1561 return kernel;
1562}
1563
1564
1565/*
1566%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1567% %
1568% %
1569% %
1570+ R e l i n q u i s h O p e n C L K e r n e l %
1571% %
1572% %
1573% %
1574%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1575%
1576% RelinquishOpenCLKernel() releases an OpenCL kernel
1577%
1578% The format of the RelinquishOpenCLKernel method is:
1579%
1580% MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv,
1581% cl_kernel kernel)
1582%
1583% A description of each parameter follows:
1584%
1585% o clEnv: the OpenCL environment.
1586%
1587% o kernel: the OpenCL kernel object to be released.
1588%
1589%
1590*/
1591
cristy7b6514c2013-12-10 23:13:13 +00001592MagickPrivate
cristyf034abb2013-11-24 14:16:14 +00001593 MagickBooleanType RelinquishOpenCLKernel(MagickCLEnv clEnv, cl_kernel kernel)
1594{
1595 MagickBooleanType status = MagickFalse;
1596 if (clEnv != NULL && kernel != NULL)
1597 {
cristy0c832c62014-03-07 22:21:04 +00001598 status = ((clEnv->library->clReleaseKernel(kernel) == CL_SUCCESS)?MagickTrue:MagickFalse);
cristyf034abb2013-11-24 14:16:14 +00001599 }
1600 return status;
1601}
1602
1603/*
1604%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1605% %
1606% %
1607% %
1608+ 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 %
1609% %
1610% %
1611% %
1612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613%
1614% GetOpenCLDeviceLocalMemorySize() returns local memory size of the device
1615%
1616% The format of the GetOpenCLDeviceLocalMemorySize method is:
1617%
1618% unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1619%
1620% A description of each parameter follows:
1621%
1622% o clEnv: the OpenCL environment.
1623%
1624%
1625*/
1626
cristy7b6514c2013-12-10 23:13:13 +00001627MagickPrivate
cristyf034abb2013-11-24 14:16:14 +00001628 unsigned long GetOpenCLDeviceLocalMemorySize(MagickCLEnv clEnv)
1629{
1630 cl_ulong localMemorySize;
cristy0c832c62014-03-07 22:21:04 +00001631 clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &localMemorySize, NULL);
cristyf034abb2013-11-24 14:16:14 +00001632 return (unsigned long)localMemorySize;
1633}
1634
cristy7b6514c2013-12-10 23:13:13 +00001635MagickPrivate
cristyf034abb2013-11-24 14:16:14 +00001636 unsigned long GetOpenCLDeviceMaxMemAllocSize(MagickCLEnv clEnv)
1637{
1638 cl_ulong maxMemAllocSize;
cristy0c832c62014-03-07 22:21:04 +00001639 clEnv->library->clGetDeviceInfo(clEnv->device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &maxMemAllocSize, NULL);
cristyf034abb2013-11-24 14:16:14 +00001640 return (unsigned long)maxMemAllocSize;
1641}
1642
1643
1644/*
1645 Beginning of the OpenCL device selection infrastructure
1646*/
1647
1648
cristyf034abb2013-11-24 14:16:14 +00001649typedef enum {
1650 DS_SUCCESS = 0
1651 ,DS_INVALID_PROFILE = 1000
1652 ,DS_MEMORY_ERROR
1653 ,DS_INVALID_PERF_EVALUATOR_TYPE
1654 ,DS_INVALID_PERF_EVALUATOR
1655 ,DS_PERF_EVALUATOR_ERROR
1656 ,DS_FILE_ERROR
1657 ,DS_UNKNOWN_DEVICE_TYPE
1658 ,DS_PROFILE_FILE_ERROR
1659 ,DS_SCORE_SERIALIZER_ERROR
1660 ,DS_SCORE_DESERIALIZER_ERROR
1661} ds_status;
1662
1663/* device type */
1664typedef enum {
1665 DS_DEVICE_NATIVE_CPU = 0
Cristy1dd96da2015-10-06 07:52:01 -04001666 ,DS_DEVICE_OPENCL_DEVICE
cristyf034abb2013-11-24 14:16:14 +00001667} ds_device_type;
1668
1669
1670typedef struct {
1671 ds_device_type type;
dirkb05dcc92014-08-27 15:30:53 +00001672 cl_device_type oclDeviceType;
cristyf034abb2013-11-24 14:16:14 +00001673 cl_device_id oclDeviceID;
1674 char* oclDeviceName;
1675 char* oclDriverVersion;
1676 cl_uint oclMaxClockFrequency;
1677 cl_uint oclMaxComputeUnits;
1678 void* score; /* a pointer to the score data, the content/format is application defined */
1679} ds_device;
1680
1681typedef struct {
1682 unsigned int numDevices;
1683 ds_device* devices;
1684 const char* version;
1685} ds_profile;
1686
1687/* deallocate memory used by score */
1688typedef ds_status (*ds_score_release)(void* score);
1689
1690static ds_status releaseDeviceResource(ds_device* device, ds_score_release sr) {
1691 ds_status status = DS_SUCCESS;
1692 if (device) {
1693 if (device->oclDeviceName) free(device->oclDeviceName);
1694 if (device->oclDriverVersion) free(device->oclDriverVersion);
1695 if (device->score) status = sr(device->score);
1696 }
1697 return status;
1698}
1699
1700static ds_status releaseDSProfile(ds_profile* profile, ds_score_release sr) {
1701 ds_status status = DS_SUCCESS;
1702 if (profile!=NULL) {
1703 if (profile->devices!=NULL && sr!=NULL) {
1704 unsigned int i;
1705 for (i = 0; i < profile->numDevices; i++) {
1706 status = releaseDeviceResource(profile->devices+i,sr);
1707 if (status != DS_SUCCESS)
1708 break;
1709 }
1710 free(profile->devices);
1711 }
1712 free(profile);
1713 }
1714 return status;
1715}
1716
1717
1718static ds_status initDSProfile(ds_profile** p, const char* version) {
1719 int numDevices = 0;
1720 cl_uint numPlatforms = 0;
1721 cl_platform_id* platforms = NULL;
1722 cl_device_id* devices = NULL;
1723 ds_status status = DS_SUCCESS;
1724 ds_profile* profile = NULL;
1725 unsigned int next = 0;
1726 unsigned int i;
1727
1728 if (p == NULL)
1729 return DS_INVALID_PROFILE;
1730
1731 profile = (ds_profile*)malloc(sizeof(ds_profile));
1732 if (profile == NULL)
1733 return DS_MEMORY_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04001734
cristyf034abb2013-11-24 14:16:14 +00001735 memset(profile, 0, sizeof(ds_profile));
1736
cristy0c832c62014-03-07 22:21:04 +00001737 OpenCLLib->clGetPlatformIDs(0, NULL, &numPlatforms);
cristyf034abb2013-11-24 14:16:14 +00001738 if (numPlatforms > 0) {
1739 platforms = (cl_platform_id*)malloc(numPlatforms*sizeof(cl_platform_id));
1740 if (platforms == NULL) {
1741 status = DS_MEMORY_ERROR;
1742 goto cleanup;
1743 }
cristy0c832c62014-03-07 22:21:04 +00001744 OpenCLLib->clGetPlatformIDs(numPlatforms, platforms, NULL);
cristyf034abb2013-11-24 14:16:14 +00001745 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1746 cl_uint num;
cristy0c832c62014-03-07 22:21:04 +00001747 if (OpenCLLib->clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_CPU | CL_DEVICE_TYPE_GPU, 0, NULL, &num) == CL_SUCCESS)
dirk20932d32013-12-12 06:16:19 +00001748 numDevices+=num;
cristyf034abb2013-11-24 14:16:14 +00001749 }
1750 }
1751
1752 profile->numDevices = numDevices+1; /* +1 to numDevices to include the native CPU */
1753
Cristy1dd96da2015-10-06 07:52:01 -04001754 profile->devices = (ds_device*)malloc(profile->numDevices*sizeof(ds_device));
cristyf034abb2013-11-24 14:16:14 +00001755 if (profile->devices == NULL) {
1756 profile->numDevices = 0;
1757 status = DS_MEMORY_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04001758 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00001759 }
1760 memset(profile->devices, 0, profile->numDevices*sizeof(ds_device));
1761
1762 if (numDevices > 0) {
1763 devices = (cl_device_id*)malloc(numDevices*sizeof(cl_device_id));
1764 if (devices == NULL) {
1765 status = DS_MEMORY_ERROR;
1766 goto cleanup;
1767 }
1768 for (i = 0; i < (unsigned int)numPlatforms; i++) {
1769 cl_uint num;
1770
1771 int d;
Cristy1dd96da2015-10-06 07:52:01 -04001772 for (d = 0; d < 2; d++) {
cristyf034abb2013-11-24 14:16:14 +00001773 unsigned int j;
1774 cl_device_type deviceType;
1775 switch(d) {
1776 case 0:
1777 deviceType = CL_DEVICE_TYPE_GPU;
1778 break;
1779 case 1:
1780 deviceType = CL_DEVICE_TYPE_CPU;
1781 break;
1782 default:
1783 continue;
1784 break;
1785 }
cristy0c832c62014-03-07 22:21:04 +00001786 if (OpenCLLib->clGetDeviceIDs(platforms[i], deviceType, numDevices, devices, &num) != CL_SUCCESS)
dirk7b1bb392013-12-10 22:36:32 +00001787 continue;
cristyf034abb2013-11-24 14:16:14 +00001788 for (j = 0; j < num; j++, next++) {
cristyf034abb2013-11-24 14:16:14 +00001789 size_t length;
1790
1791 profile->devices[next].type = DS_DEVICE_OPENCL_DEVICE;
1792 profile->devices[next].oclDeviceID = devices[j];
1793
cristy0c832c62014-03-07 22:21:04 +00001794 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
dirk7b1bb392013-12-10 22:36:32 +00001795 , 0, NULL, &length);
1796 profile->devices[next].oclDeviceName = (char*)malloc(sizeof(char)*length);
cristy0c832c62014-03-07 22:21:04 +00001797 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_NAME
dirk7b1bb392013-12-10 22:36:32 +00001798 , length, profile->devices[next].oclDeviceName, NULL);
1799
cristy0c832c62014-03-07 22:21:04 +00001800 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
dirk7b1bb392013-12-10 22:36:32 +00001801 , 0, NULL, &length);
1802 profile->devices[next].oclDriverVersion = (char*)malloc(sizeof(char)*length);
cristy0c832c62014-03-07 22:21:04 +00001803 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DRIVER_VERSION
dirke3c5f892013-12-10 06:04:40 +00001804 , length, profile->devices[next].oclDriverVersion, NULL);
cristyf034abb2013-11-24 14:16:14 +00001805
cristy0c832c62014-03-07 22:21:04 +00001806 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_CLOCK_FREQUENCY
cristyf034abb2013-11-24 14:16:14 +00001807 , sizeof(cl_uint), &profile->devices[next].oclMaxClockFrequency, NULL);
1808
cristy0c832c62014-03-07 22:21:04 +00001809 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_MAX_COMPUTE_UNITS
cristyf034abb2013-11-24 14:16:14 +00001810 , sizeof(cl_uint), &profile->devices[next].oclMaxComputeUnits, NULL);
dirkb05dcc92014-08-27 15:30:53 +00001811
1812 OpenCLLib->clGetDeviceInfo(profile->devices[next].oclDeviceID, CL_DEVICE_TYPE
1813 , sizeof(cl_device_type), &profile->devices[next].oclDeviceType, NULL);
cristyf034abb2013-11-24 14:16:14 +00001814 }
1815 }
1816 }
1817 }
1818
1819 profile->devices[next].type = DS_DEVICE_NATIVE_CPU;
1820 profile->version = version;
1821
1822cleanup:
1823 if (platforms) free(platforms);
1824 if (devices) free(devices);
1825 if (status == DS_SUCCESS) {
1826 *p = profile;
1827 }
1828 else {
1829 if (profile) {
1830 if (profile->devices)
1831 free(profile->devices);
1832 free(profile);
1833 }
1834 }
1835 return status;
1836}
1837
Cristy1dd96da2015-10-06 07:52:01 -04001838/* Pointer to a function that calculates the score of a device (ex: device->score)
1839 update the data size of score. The encoding and the format of the score data
dirk22624f12013-12-01 17:16:37 +00001840 is implementation defined. The function should return DS_SUCCESS if there's no error to be reported.
cristyf034abb2013-11-24 14:16:14 +00001841 */
dirk22624f12013-12-01 17:16:37 +00001842typedef ds_status (*ds_perf_evaluator)(ds_device* device, void* data);
cristyf034abb2013-11-24 14:16:14 +00001843
1844typedef enum {
1845 DS_EVALUATE_ALL
1846 ,DS_EVALUATE_NEW_ONLY
1847} ds_evaluation_type;
1848
1849static ds_status profileDevices(ds_profile* profile, const ds_evaluation_type type
dirk22624f12013-12-01 17:16:37 +00001850 ,ds_perf_evaluator evaluator, void* evaluatorData, unsigned int* numUpdates) {
cristyf034abb2013-11-24 14:16:14 +00001851 ds_status status = DS_SUCCESS;
1852 unsigned int i;
1853 unsigned int updates = 0;
1854
1855 if (profile == NULL) {
1856 return DS_INVALID_PROFILE;
1857 }
1858 if (evaluator == NULL) {
1859 return DS_INVALID_PERF_EVALUATOR;
1860 }
1861
1862 for (i = 0; i < profile->numDevices; i++) {
1863 ds_status evaluatorStatus;
Cristy1dd96da2015-10-06 07:52:01 -04001864
cristyf034abb2013-11-24 14:16:14 +00001865 switch (type) {
1866 case DS_EVALUATE_NEW_ONLY:
1867 if (profile->devices[i].score != NULL)
1868 break;
1869 /* else fall through */
1870 case DS_EVALUATE_ALL:
dirk22624f12013-12-01 17:16:37 +00001871 evaluatorStatus = evaluator(profile->devices+i,evaluatorData);
cristyf034abb2013-11-24 14:16:14 +00001872 if (evaluatorStatus != DS_SUCCESS) {
1873 status = evaluatorStatus;
1874 return status;
1875 }
1876 updates++;
1877 break;
1878 default:
1879 return DS_INVALID_PERF_EVALUATOR_TYPE;
1880 break;
1881 };
1882 }
1883 if (numUpdates)
1884 *numUpdates = updates;
1885 return status;
1886}
1887
1888
1889#define DS_TAG_VERSION "<version>"
1890#define DS_TAG_VERSION_END "</version>"
1891#define DS_TAG_DEVICE "<device>"
1892#define DS_TAG_DEVICE_END "</device>"
1893#define DS_TAG_SCORE "<score>"
1894#define DS_TAG_SCORE_END "</score>"
1895#define DS_TAG_DEVICE_TYPE "<type>"
1896#define DS_TAG_DEVICE_TYPE_END "</type>"
1897#define DS_TAG_DEVICE_NAME "<name>"
1898#define DS_TAG_DEVICE_NAME_END "</name>"
1899#define DS_TAG_DEVICE_DRIVER_VERSION "<driver>"
1900#define DS_TAG_DEVICE_DRIVER_VERSION_END "</driver>"
1901#define DS_TAG_DEVICE_MAX_COMPUTE_UNITS "<max cu>"
1902#define DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END "</max cu>"
1903#define DS_TAG_DEVICE_MAX_CLOCK_FREQ "<max clock>"
1904#define DS_TAG_DEVICE_MAX_CLOCK_FREQ_END "</max clock>"
1905
1906#define DS_DEVICE_NATIVE_CPU_STRING "native_cpu"
1907
1908
1909
1910typedef ds_status (*ds_score_serializer)(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize);
1911static ds_status writeProfileToFile(ds_profile* profile, ds_score_serializer serializer, const char* file) {
1912 ds_status status = DS_SUCCESS;
1913 FILE* profileFile = NULL;
1914
1915
1916 if (profile == NULL)
1917 return DS_INVALID_PROFILE;
1918
1919 profileFile = fopen(file, "wb");
1920 if (profileFile==NULL) {
1921 status = DS_FILE_ERROR;
1922 }
1923 else {
1924 unsigned int i;
1925
1926 /* write version string */
1927 fwrite(DS_TAG_VERSION, sizeof(char), strlen(DS_TAG_VERSION), profileFile);
1928 fwrite(profile->version, sizeof(char), strlen(profile->version), profileFile);
1929 fwrite(DS_TAG_VERSION_END, sizeof(char), strlen(DS_TAG_VERSION_END), profileFile);
1930 fwrite("\n", sizeof(char), 1, profileFile);
1931
1932 for (i = 0; i < profile->numDevices && status == DS_SUCCESS; i++) {
1933 void* serializedScore;
1934 unsigned int serializedScoreSize;
1935
1936 fwrite(DS_TAG_DEVICE, sizeof(char), strlen(DS_TAG_DEVICE), profileFile);
1937
1938 fwrite(DS_TAG_DEVICE_TYPE, sizeof(char), strlen(DS_TAG_DEVICE_TYPE), profileFile);
1939 fwrite(&profile->devices[i].type,sizeof(ds_device_type),1, profileFile);
1940 fwrite(DS_TAG_DEVICE_TYPE_END, sizeof(char), strlen(DS_TAG_DEVICE_TYPE_END), profileFile);
1941
1942 switch(profile->devices[i].type) {
1943 case DS_DEVICE_NATIVE_CPU:
Cristy1dd96da2015-10-06 07:52:01 -04001944 {
cristyf034abb2013-11-24 14:16:14 +00001945 /* There's no need to emit a device name for the native CPU device. */
1946 /*
1947 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1948 fwrite(DS_DEVICE_NATIVE_CPU_STRING,sizeof(char),strlen(DS_DEVICE_NATIVE_CPU_STRING), profileFile);
1949 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1950 */
1951 }
1952 break;
Cristy1dd96da2015-10-06 07:52:01 -04001953 case DS_DEVICE_OPENCL_DEVICE:
cristyf034abb2013-11-24 14:16:14 +00001954 {
1955 char tmp[16];
1956
1957 fwrite(DS_TAG_DEVICE_NAME, sizeof(char), strlen(DS_TAG_DEVICE_NAME), profileFile);
1958 fwrite(profile->devices[i].oclDeviceName,sizeof(char),strlen(profile->devices[i].oclDeviceName), profileFile);
1959 fwrite(DS_TAG_DEVICE_NAME_END, sizeof(char), strlen(DS_TAG_DEVICE_NAME_END), profileFile);
1960
1961 fwrite(DS_TAG_DEVICE_DRIVER_VERSION, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION), profileFile);
1962 fwrite(profile->devices[i].oclDriverVersion,sizeof(char),strlen(profile->devices[i].oclDriverVersion), profileFile);
1963 fwrite(DS_TAG_DEVICE_DRIVER_VERSION_END, sizeof(char), strlen(DS_TAG_DEVICE_DRIVER_VERSION_END), profileFile);
1964
1965 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS), profileFile);
1966 sprintf(tmp,"%d",profile->devices[i].oclMaxComputeUnits);
1967 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1968 fwrite(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END), profileFile);
1969
1970 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ), profileFile);
1971 sprintf(tmp,"%d",profile->devices[i].oclMaxClockFrequency);
1972 fwrite(tmp,sizeof(char),strlen(tmp), profileFile);
1973 fwrite(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END, sizeof(char), strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ_END), profileFile);
1974 }
1975 break;
1976 default:
1977 status = DS_UNKNOWN_DEVICE_TYPE;
1978 break;
1979 };
1980
1981 fwrite(DS_TAG_SCORE, sizeof(char), strlen(DS_TAG_SCORE), profileFile);
1982 status = serializer(profile->devices+i, &serializedScore, &serializedScoreSize);
1983 if (status == DS_SUCCESS && serializedScore!=NULL && serializedScoreSize > 0) {
1984 fwrite(serializedScore, sizeof(char), serializedScoreSize, profileFile);
1985 free(serializedScore);
1986 }
1987 fwrite(DS_TAG_SCORE_END, sizeof(char), strlen(DS_TAG_SCORE_END), profileFile);
1988 fwrite(DS_TAG_DEVICE_END, sizeof(char), strlen(DS_TAG_DEVICE_END), profileFile);
1989 fwrite("\n",sizeof(char),1,profileFile);
1990 }
1991 fclose(profileFile);
1992 }
1993 return status;
1994}
1995
1996
1997static ds_status readProFile(const char* fileName, char** content, size_t* contentSize) {
1998 ds_status status = DS_SUCCESS;
1999 FILE * input = NULL;
2000 size_t size = 0;
2001 size_t rsize = 0;
2002 char* binary = NULL;
2003
2004 *contentSize = 0;
2005 *content = NULL;
2006
2007 input = fopen(fileName, "rb");
2008 if(input == NULL) {
2009 return DS_FILE_ERROR;
2010 }
2011
Cristy1dd96da2015-10-06 07:52:01 -04002012 fseek(input, 0L, SEEK_END);
cristyf034abb2013-11-24 14:16:14 +00002013 size = ftell(input);
2014 rewind(input);
2015 binary = (char*)malloc(size);
2016 if(binary == NULL) {
2017 status = DS_FILE_ERROR;
2018 goto cleanup;
2019 }
2020 rsize = fread(binary, sizeof(char), size, input);
2021 if (rsize!=size
2022 || ferror(input)) {
2023 status = DS_FILE_ERROR;
2024 goto cleanup;
2025 }
2026 *contentSize = size;
2027 *content = binary;
2028
2029cleanup:
2030 if (input != NULL) fclose(input);
2031 if (status != DS_SUCCESS
2032 && binary != NULL) {
2033 free(binary);
2034 *content = NULL;
2035 *contentSize = 0;
2036 }
2037 return status;
2038}
2039
2040
2041static const char* findString(const char* contentStart, const char* contentEnd, const char* string) {
2042 size_t stringLength;
2043 const char* currentPosition;
2044 const char* found;
2045 found = NULL;
2046 stringLength = strlen(string);
2047 currentPosition = contentStart;
2048 for(currentPosition = contentStart; currentPosition < contentEnd; currentPosition++) {
2049 if (*currentPosition == string[0]) {
2050 if (currentPosition+stringLength < contentEnd) {
2051 if (strncmp(currentPosition, string, stringLength) == 0) {
2052 found = currentPosition;
2053 break;
2054 }
2055 }
2056 }
2057 }
2058 return found;
2059}
2060
2061
Cristy1dd96da2015-10-06 07:52:01 -04002062typedef ds_status (*ds_score_deserializer)(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize);
cristyf034abb2013-11-24 14:16:14 +00002063static ds_status readProfileFromFile(ds_profile* profile, ds_score_deserializer deserializer, const char* file) {
2064
2065 ds_status status = DS_SUCCESS;
2066 char* contentStart = NULL;
2067 const char* contentEnd = NULL;
2068 size_t contentSize;
2069
2070 if (profile==NULL)
2071 return DS_INVALID_PROFILE;
2072
2073 status = readProFile(file, &contentStart, &contentSize);
2074 if (status == DS_SUCCESS) {
2075 const char* currentPosition;
2076 const char* dataStart;
2077 const char* dataEnd;
2078 size_t versionStringLength;
2079
2080 contentEnd = contentStart + contentSize;
2081 currentPosition = contentStart;
2082
2083
2084 /* parse the version string */
2085 dataStart = findString(currentPosition, contentEnd, DS_TAG_VERSION);
2086 if (dataStart == NULL) {
2087 status = DS_PROFILE_FILE_ERROR;
2088 goto cleanup;
2089 }
2090 dataStart += strlen(DS_TAG_VERSION);
2091
2092 dataEnd = findString(dataStart, contentEnd, DS_TAG_VERSION_END);
2093 if (dataEnd==NULL) {
2094 status = DS_PROFILE_FILE_ERROR;
2095 goto cleanup;
2096 }
2097
2098 versionStringLength = strlen(profile->version);
Cristy1dd96da2015-10-06 07:52:01 -04002099 if (versionStringLength!=(size_t)(dataEnd-dataStart)
cristyf034abb2013-11-24 14:16:14 +00002100 || strncmp(profile->version, dataStart, versionStringLength)!=(int)0) {
2101 /* version mismatch */
2102 status = DS_PROFILE_FILE_ERROR;
2103 goto cleanup;
2104 }
2105 currentPosition = dataEnd+strlen(DS_TAG_VERSION_END);
2106
2107 /* parse the device information */
dirk5dcb7622013-12-01 10:43:43 +00002108DisableMSCWarning(4127)
cristyf034abb2013-11-24 14:16:14 +00002109 while (1) {
dirk5dcb7622013-12-01 10:43:43 +00002110RestoreMSCWarning
cristyf034abb2013-11-24 14:16:14 +00002111 unsigned int i;
2112
2113 const char* deviceTypeStart;
2114 const char* deviceTypeEnd;
2115 ds_device_type deviceType;
2116
2117 const char* deviceNameStart;
2118 const char* deviceNameEnd;
2119
2120 const char* deviceScoreStart;
2121 const char* deviceScoreEnd;
2122
2123 const char* deviceDriverStart;
2124 const char* deviceDriverEnd;
2125
2126 const char* tmpStart;
2127 const char* tmpEnd;
2128 char tmp[16];
2129
2130 cl_uint maxClockFrequency;
2131 cl_uint maxComputeUnits;
2132
2133 dataStart = findString(currentPosition, contentEnd, DS_TAG_DEVICE);
2134 if (dataStart==NULL) {
2135 /* nothing useful remain, quit...*/
2136 break;
2137 }
2138 dataStart+=strlen(DS_TAG_DEVICE);
2139 dataEnd = findString(dataStart, contentEnd, DS_TAG_DEVICE_END);
2140 if (dataEnd==NULL) {
2141 status = DS_PROFILE_FILE_ERROR;
2142 goto cleanup;
2143 }
2144
2145 /* parse the device type */
2146 deviceTypeStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_TYPE);
2147 if (deviceTypeStart==NULL) {
2148 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002149 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002150 }
2151 deviceTypeStart+=strlen(DS_TAG_DEVICE_TYPE);
2152 deviceTypeEnd = findString(deviceTypeStart, contentEnd, DS_TAG_DEVICE_TYPE_END);
2153 if (deviceTypeEnd==NULL) {
2154 status = DS_PROFILE_FILE_ERROR;
2155 goto cleanup;
2156 }
2157 memcpy(&deviceType, deviceTypeStart, sizeof(ds_device_type));
2158
2159
2160 /* parse the device name */
2161 if (deviceType == DS_DEVICE_OPENCL_DEVICE) {
2162
2163 deviceNameStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_NAME);
2164 if (deviceNameStart==NULL) {
2165 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002166 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002167 }
2168 deviceNameStart+=strlen(DS_TAG_DEVICE_NAME);
2169 deviceNameEnd = findString(deviceNameStart, contentEnd, DS_TAG_DEVICE_NAME_END);
2170 if (deviceNameEnd==NULL) {
2171 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002172 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002173 }
2174
2175
2176 deviceDriverStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION);
2177 if (deviceDriverStart==NULL) {
2178 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002179 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002180 }
2181 deviceDriverStart+=strlen(DS_TAG_DEVICE_DRIVER_VERSION);
2182 deviceDriverEnd = findString(deviceDriverStart, contentEnd, DS_TAG_DEVICE_DRIVER_VERSION_END);
2183 if (deviceDriverEnd ==NULL) {
2184 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002185 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002186 }
2187
2188
2189 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
2190 if (tmpStart==NULL) {
2191 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002192 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002193 }
2194 tmpStart+=strlen(DS_TAG_DEVICE_MAX_COMPUTE_UNITS);
2195 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_COMPUTE_UNITS_END);
2196 if (tmpEnd ==NULL) {
2197 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002198 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002199 }
2200 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
2201 tmp[tmpEnd-tmpStart] = '\0';
cristy79d05312014-12-25 18:13:29 +00002202 maxComputeUnits = strtol(tmp,(char **) NULL,10);
cristyf034abb2013-11-24 14:16:14 +00002203
2204
2205 tmpStart = findString(dataStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ);
2206 if (tmpStart==NULL) {
2207 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002208 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002209 }
2210 tmpStart+=strlen(DS_TAG_DEVICE_MAX_CLOCK_FREQ);
2211 tmpEnd = findString(tmpStart, contentEnd, DS_TAG_DEVICE_MAX_CLOCK_FREQ_END);
2212 if (tmpEnd ==NULL) {
2213 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002214 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002215 }
2216 memcpy(tmp,tmpStart,tmpEnd-tmpStart);
2217 tmp[tmpEnd-tmpStart] = '\0';
cristy79d05312014-12-25 18:13:29 +00002218 maxClockFrequency = strtol(tmp,(char **) NULL,10);
cristyf034abb2013-11-24 14:16:14 +00002219
2220
2221 /* check if this device is on the system */
2222 for (i = 0; i < profile->numDevices; i++) {
2223 if (profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) {
2224 size_t actualDeviceNameLength;
2225 size_t driverVersionLength;
Cristy1dd96da2015-10-06 07:52:01 -04002226
cristyf034abb2013-11-24 14:16:14 +00002227 actualDeviceNameLength = strlen(profile->devices[i].oclDeviceName);
2228 driverVersionLength = strlen(profile->devices[i].oclDriverVersion);
dirk5dcb7622013-12-01 10:43:43 +00002229 if (actualDeviceNameLength == (size_t)(deviceNameEnd - deviceNameStart)
2230 && driverVersionLength == (size_t)(deviceDriverEnd - deviceDriverStart)
cristyf034abb2013-11-24 14:16:14 +00002231 && maxComputeUnits == profile->devices[i].oclMaxComputeUnits
2232 && maxClockFrequency == profile->devices[i].oclMaxClockFrequency
2233 && strncmp(profile->devices[i].oclDeviceName, deviceNameStart, actualDeviceNameLength)==(int)0
2234 && strncmp(profile->devices[i].oclDriverVersion, deviceDriverStart, driverVersionLength)==(int)0) {
2235
2236 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
2237 if (deviceNameStart==NULL) {
2238 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002239 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002240 }
2241 deviceScoreStart+=strlen(DS_TAG_SCORE);
2242 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
2243 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
2244 if (status != DS_SUCCESS) {
2245 goto cleanup;
2246 }
2247 }
2248 }
2249 }
2250
2251 }
2252 else if (deviceType == DS_DEVICE_NATIVE_CPU) {
2253 for (i = 0; i < profile->numDevices; i++) {
2254 if (profile->devices[i].type == DS_DEVICE_NATIVE_CPU) {
2255 deviceScoreStart = findString(dataStart, contentEnd, DS_TAG_SCORE);
2256 if (deviceScoreStart==NULL) {
2257 status = DS_PROFILE_FILE_ERROR;
Cristy1dd96da2015-10-06 07:52:01 -04002258 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00002259 }
2260 deviceScoreStart+=strlen(DS_TAG_SCORE);
2261 deviceScoreEnd = findString(deviceScoreStart, contentEnd, DS_TAG_SCORE_END);
2262 status = deserializer(profile->devices+i, (const unsigned char*)deviceScoreStart, deviceScoreEnd-deviceScoreStart);
2263 if (status != DS_SUCCESS) {
2264 goto cleanup;
2265 }
2266 }
2267 }
2268 }
2269
2270 /* skip over the current one to find the next device */
2271 currentPosition = dataEnd+strlen(DS_TAG_DEVICE_END);
2272 }
2273 }
2274cleanup:
2275 if (contentStart!=NULL) free(contentStart);
2276 return status;
2277}
2278
cristya22457d2013-12-07 14:03:06 +00002279
2280#if 0
cristyf034abb2013-11-24 14:16:14 +00002281static ds_status getNumDeviceWithEmptyScore(ds_profile* profile, unsigned int* num) {
2282 unsigned int i;
2283 if (profile == NULL || num==NULL)
2284 return DS_MEMORY_ERROR;
2285 *num=0;
2286 for (i = 0; i < profile->numDevices; i++) {
2287 if (profile->devices[i].score == NULL) {
cristya22457d2013-12-07 14:03:06 +00002288 (*num)++;
cristyf034abb2013-11-24 14:16:14 +00002289 }
2290 }
2291 return DS_SUCCESS;
2292}
cristya22457d2013-12-07 14:03:06 +00002293#endif
cristyf034abb2013-11-24 14:16:14 +00002294
2295/*
2296 End of the OpenCL device selection infrastructure
2297*/
2298
2299
cristyf034abb2013-11-24 14:16:14 +00002300typedef double AccelerateScoreType;
2301
dirk22624f12013-12-01 17:16:37 +00002302static ds_status AcceleratePerfEvaluator(ds_device *device,
2303 void *magick_unused(data))
2304{
2305#define ACCELERATE_PERF_DIMEN "2048x1536"
2306#define NUM_ITER 2
2307#define ReturnStatus(status) \
2308{ \
2309 if (clEnv!=NULL) \
2310 RelinquishMagickOpenCLEnv(clEnv); \
2311 if (oldClEnv!=NULL) \
2312 defaultCLEnv = oldClEnv; \
2313 return status; \
2314}
cristyf034abb2013-11-24 14:16:14 +00002315
dirk22624f12013-12-01 17:16:37 +00002316 AccelerateTimer
2317 timer;
cristyf034abb2013-11-24 14:16:14 +00002318
dirk22624f12013-12-01 17:16:37 +00002319 ExceptionInfo
2320 *exception=NULL;
cristyf034abb2013-11-24 14:16:14 +00002321
dirk22624f12013-12-01 17:16:37 +00002322 MagickCLEnv
2323 clEnv=NULL,
2324 oldClEnv=NULL;
cristyf034abb2013-11-24 14:16:14 +00002325
dirk22624f12013-12-01 17:16:37 +00002326 magick_unreferenced(data);
2327
2328 if (device == NULL)
2329 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2330
2331 clEnv=AcquireMagickOpenCLEnv();
2332 exception=AcquireExceptionInfo();
2333
2334 if (device->type == DS_DEVICE_NATIVE_CPU)
2335 {
2336 /* CPU device */
2337 MagickBooleanType flag=MagickTrue;
2338 SetMagickOpenCLEnvParamInternal(clEnv,
2339 MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,sizeof(MagickBooleanType),
2340 &flag,exception);
2341 }
2342 else if (device->type == DS_DEVICE_OPENCL_DEVICE)
2343 {
2344 /* OpenCL device */
2345 SetMagickOpenCLEnvParamInternal(clEnv,MAGICK_OPENCL_ENV_PARAM_DEVICE,
2346 sizeof(cl_device_id),&device->oclDeviceID,exception);
2347 }
2348 else
2349 ReturnStatus(DS_PERF_EVALUATOR_ERROR);
2350
dirk20932d32013-12-12 06:16:19 +00002351 /* recompile the OpenCL kernels if it needs to */
2352 clEnv->disableProgramCache = defaultCLEnv->disableProgramCache;
2353
dirk22624f12013-12-01 17:16:37 +00002354 InitOpenCLEnvInternal(clEnv,exception);
2355 oldClEnv=defaultCLEnv;
2356 defaultCLEnv=clEnv;
cristyf034abb2013-11-24 14:16:14 +00002357
2358 /* microbenchmark */
2359 {
dirk22624f12013-12-01 17:16:37 +00002360 Image
2361 *inputImage;
cristyf034abb2013-11-24 14:16:14 +00002362
dirk22624f12013-12-01 17:16:37 +00002363 ImageInfo
2364 *imageInfo;
cristyf034abb2013-11-24 14:16:14 +00002365
dirk22624f12013-12-01 17:16:37 +00002366 int
2367 i;
2368
2369 imageInfo=AcquireImageInfo();
cristyf034abb2013-11-24 14:16:14 +00002370 CloneString(&imageInfo->size,ACCELERATE_PERF_DIMEN);
cristy151b66d2015-04-15 10:50:31 +00002371 CopyMagickString(imageInfo->filename,"xc:none",MagickPathExtent);
dirk22624f12013-12-01 17:16:37 +00002372 inputImage=ReadImage(imageInfo,exception);
cristyf034abb2013-11-24 14:16:14 +00002373
2374 initAccelerateTimer(&timer);
2375
dirk22624f12013-12-01 17:16:37 +00002376 for (i=0; i<=NUM_ITER; i++)
2377 {
2378 Image
2379 *bluredImage,
2380 *resizedImage,
2381 *unsharpedImage;
cristyf034abb2013-11-24 14:16:14 +00002382
2383 if (i > 0)
2384 startAccelerateTimer(&timer);
2385
2386#ifdef MAGICKCORE_CLPERFMARKER
dirk22624f12013-12-01 17:16:37 +00002387 clBeginPerfMarkerAMD("PerfEvaluatorRegion","");
cristyf034abb2013-11-24 14:16:14 +00002388#endif
2389
dirk22624f12013-12-01 17:16:37 +00002390 bluredImage=BlurImage(inputImage,10.0f,3.5f,exception);
2391 unsharpedImage=UnsharpMaskImage(bluredImage,2.0f,2.0f,50.0f,10.0f,
2392 exception);
dirk8a5cf512014-07-28 20:16:27 +00002393 resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
dirk22624f12013-12-01 17:16:37 +00002394 exception);
cristyf034abb2013-11-24 14:16:14 +00002395
2396#ifdef MAGICKCORE_CLPERFMARKER
dirk22624f12013-12-01 17:16:37 +00002397 clEndPerfMarkerAMD();
cristyf034abb2013-11-24 14:16:14 +00002398#endif
2399
2400 if (i > 0)
2401 stopAccelerateTimer(&timer);
2402
dirk22624f12013-12-01 17:16:37 +00002403 if (bluredImage)
2404 DestroyImage(bluredImage);
2405 if (unsharpedImage)
2406 DestroyImage(unsharpedImage);
2407 if (resizedImage)
2408 DestroyImage(resizedImage);
cristyf034abb2013-11-24 14:16:14 +00002409 }
2410 DestroyImage(inputImage);
2411 }
2412 /* end of microbenchmark */
Cristy1dd96da2015-10-06 07:52:01 -04002413
dirk22624f12013-12-01 17:16:37 +00002414 if (device->score == NULL)
2415 device->score=malloc(sizeof(AccelerateScoreType));
2416 *(AccelerateScoreType*)device->score=readAccelerateTimer(&timer);
cristyf034abb2013-11-24 14:16:14 +00002417
dirk22624f12013-12-01 17:16:37 +00002418 ReturnStatus(DS_SUCCESS);
cristyf034abb2013-11-24 14:16:14 +00002419}
2420
cristyf034abb2013-11-24 14:16:14 +00002421ds_status AccelerateScoreSerializer(ds_device* device, void** serializedScore, unsigned int* serializedScoreSize) {
2422 if (device
2423 && device->score) {
2424 /* generate a string from the score */
2425 char* s = (char*)malloc(sizeof(char)*256);
2426 sprintf(s,"%.4f",*((AccelerateScoreType*)device->score));
2427 *serializedScore = (void*)s;
dirkb0d783f2014-08-31 10:48:05 +00002428 *serializedScoreSize = (unsigned int) strlen(s);
cristyf034abb2013-11-24 14:16:14 +00002429 return DS_SUCCESS;
2430 }
2431 else {
2432 return DS_SCORE_SERIALIZER_ERROR;
2433 }
2434}
2435
2436ds_status AccelerateScoreDeserializer(ds_device* device, const unsigned char* serializedScore, unsigned int serializedScoreSize) {
2437 if (device) {
2438 /* convert the string back to an int */
2439 char* s = (char*)malloc(serializedScoreSize+1);
2440 memcpy(s, serializedScore, serializedScoreSize);
2441 s[serializedScoreSize] = (char)'\0';
2442 device->score = malloc(sizeof(AccelerateScoreType));
cristy79d05312014-12-25 18:13:29 +00002443 *((AccelerateScoreType*)device->score) = (AccelerateScoreType)
dirk53dd0e42014-12-26 03:01:48 +00002444 strtod(s,(char **) NULL);
cristyf034abb2013-11-24 14:16:14 +00002445 free(s);
2446 return DS_SUCCESS;
2447 }
2448 else {
2449 return DS_SCORE_DESERIALIZER_ERROR;
2450 }
2451}
2452
2453ds_status AccelerateScoreRelease(void* score) {
2454 if (score!=NULL) {
2455 free(score);
2456 }
2457 return DS_SUCCESS;
2458}
2459
dirk1e3b22a2014-08-28 05:36:18 +00002460ds_status canWriteProfileToFile(const char *path)
dirkb05dcc92014-08-27 15:30:53 +00002461{
cristyb515e682014-10-18 00:26:13 +00002462 FILE* profileFile = fopen(path, "ab");
Cristy1dd96da2015-10-06 07:52:01 -04002463
dirkb05dcc92014-08-27 15:30:53 +00002464 if (profileFile==NULL)
2465 return DS_FILE_ERROR;
2466
2467 fclose(profileFile);
2468 return DS_SUCCESS;
2469}
cristyf034abb2013-11-24 14:16:14 +00002470
2471#define IMAGEMAGICK_PROFILE_VERSION "ImageMagick Device Selection v0.9"
2472#define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile"
2473static MagickBooleanType autoSelectDevice(MagickCLEnv clEnv, ExceptionInfo* exception) {
2474
2475 MagickBooleanType mStatus = MagickFalse;
2476 ds_status status;
2477 ds_profile* profile;
2478 unsigned int numDeviceProfiled = 0;
2479 unsigned int i;
2480 unsigned int bestDeviceIndex;
2481 AccelerateScoreType bestScore;
cristy151b66d2015-04-15 10:50:31 +00002482 char path[MagickPathExtent];
cristya22457d2013-12-07 14:03:06 +00002483 MagickBooleanType flag;
dirk20932d32013-12-12 06:16:19 +00002484 ds_evaluation_type profileType;
cristyf034abb2013-11-24 14:16:14 +00002485
2486 LockDefaultOpenCLEnv();
2487
cristya22457d2013-12-07 14:03:06 +00002488 /* Initially, just set OpenCL to off */
2489 flag = MagickTrue;
2490 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2491 , sizeof(MagickBooleanType), &flag, exception);
2492
cristy0c832c62014-03-07 22:21:04 +00002493 /* check and init the global lib */
2494 OpenCLLib=GetOpenCLLib();
2495 if (OpenCLLib==NULL)
2496 {
2497 mStatus=InitOpenCLEnvInternal(clEnv, exception);
2498 goto cleanup;
2499 }
2500
cristyf034abb2013-11-24 14:16:14 +00002501 status = initDSProfile(&profile, IMAGEMAGICK_PROFILE_VERSION);
2502 if (status!=DS_SUCCESS) {
2503 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2504 goto cleanup;
2505 }
2506
cristy151b66d2015-04-15 10:50:31 +00002507 (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
cristyf034abb2013-11-24 14:16:14 +00002508 ,GetOpenCLCachedFilesDirectory()
2509 ,DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
2510
dirkb05dcc92014-08-27 15:30:53 +00002511 if (canWriteProfileToFile(path) != DS_SUCCESS) {
2512 /* We can not write out a device profile, so don't run the benchmark */
2513 /* select the first GPU device */
dirk20932d32013-12-12 06:16:19 +00002514
dirkb05dcc92014-08-27 15:30:53 +00002515 bestDeviceIndex = 0;
2516 for (i = 1; i < profile->numDevices; i++) {
2517 if ((profile->devices[i].type == DS_DEVICE_OPENCL_DEVICE) && (profile->devices[i].oclDeviceType == CL_DEVICE_TYPE_GPU)) {
2518 bestDeviceIndex = i;
2519 break;
2520 }
cristyf034abb2013-11-24 14:16:14 +00002521 }
2522 }
dirkb05dcc92014-08-27 15:30:53 +00002523 else {
2524 if (clEnv->regenerateProfile != MagickFalse) {
2525 profileType = DS_EVALUATE_ALL;
2526 }
2527 else {
2528 readProfileFromFile(profile, AccelerateScoreDeserializer, path);
2529 profileType = DS_EVALUATE_NEW_ONLY;
2530 }
2531 status = profileDevices(profile, profileType, AcceleratePerfEvaluator, NULL, &numDeviceProfiled);
cristyf034abb2013-11-24 14:16:14 +00002532
dirkb05dcc92014-08-27 15:30:53 +00002533 if (status!=DS_SUCCESS) {
2534 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, "Error when initializing the profile", "'%s'", ".");
2535 goto cleanup;
2536 }
2537 if (numDeviceProfiled > 0) {
2538 status = writeProfileToFile(profile, AccelerateScoreSerializer, path);
2539 if (status!=DS_SUCCESS) {
2540 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when saving the profile into a file", "'%s'", ".");
2541 }
2542 }
2543
2544 /* pick the best device */
2545 bestDeviceIndex = 0;
2546 bestScore = *(AccelerateScoreType*)profile->devices[bestDeviceIndex].score;
2547 for (i = 1; i < profile->numDevices; i++) {
2548 AccelerateScoreType score = *(AccelerateScoreType*)profile->devices[i].score;
2549 if (score < bestScore) {
2550 bestDeviceIndex = i;
2551 bestScore = score;
2552 }
cristyf034abb2013-11-24 14:16:14 +00002553 }
2554 }
2555
2556 /* set up clEnv with the best device */
2557 if (profile->devices[bestDeviceIndex].type == DS_DEVICE_NATIVE_CPU) {
2558 /* CPU device */
cristya22457d2013-12-07 14:03:06 +00002559 flag = MagickTrue;
cristyf034abb2013-11-24 14:16:14 +00002560 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2561 , sizeof(MagickBooleanType), &flag, exception);
2562 }
2563 else if (profile->devices[bestDeviceIndex].type == DS_DEVICE_OPENCL_DEVICE) {
2564 /* OpenCL device */
cristya22457d2013-12-07 14:03:06 +00002565 flag = MagickFalse;
2566 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2567 , sizeof(MagickBooleanType), &flag, exception);
cristyf034abb2013-11-24 14:16:14 +00002568 SetMagickOpenCLEnvParamInternal(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2569 , sizeof(cl_device_id), &profile->devices[bestDeviceIndex].oclDeviceID,exception);
2570 }
2571 else {
2572 status = DS_PERF_EVALUATOR_ERROR;
2573 goto cleanup;
2574 }
dirk6b57c962013-11-30 19:14:02 +00002575 mStatus=InitOpenCLEnvInternal(clEnv, exception);
cristyf034abb2013-11-24 14:16:14 +00002576
2577 status = releaseDSProfile(profile, AccelerateScoreRelease);
2578 if (status!=DS_SUCCESS) {
2579 (void) ThrowMagickException(exception, GetMagickModule(), ModuleWarning, "Error when releasing the profile", "'%s'", ".");
2580 }
cristyf034abb2013-11-24 14:16:14 +00002581
2582cleanup:
2583
2584 UnlockDefaultOpenCLEnv();
2585 return mStatus;
2586}
2587
2588
2589/*
2590%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2591% %
2592% %
2593% %
2594+ I n i t I m a g e M a g i c k O p e n C L %
2595% %
2596% %
2597% %
2598%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2599%
2600% InitImageMagickOpenCL() provides a simplified interface to initialize
2601% the OpenCL environtment in ImageMagick
Cristy1dd96da2015-10-06 07:52:01 -04002602%
cristyf034abb2013-11-24 14:16:14 +00002603% The format of the InitImageMagickOpenCL() method is:
2604%
Cristy1dd96da2015-10-06 07:52:01 -04002605% MagickBooleanType InitImageMagickOpenCL(ImageMagickOpenCLMode mode,
2606% void* userSelectedDevice,
2607% void* selectedDevice)
cristyf034abb2013-11-24 14:16:14 +00002608%
2609% A description of each parameter follows:
2610%
2611% o mode: OpenCL mode in ImageMagick, could be off,auto,user
2612%
2613% o userSelectedDevice: when in user mode, a pointer to the selected
2614% cl_device_id
2615%
2616% o selectedDevice: a pointer to cl_device_id where the selected
2617% cl_device_id by ImageMagick could be returned
2618%
2619% o exception: exception
2620%
2621*/
dirked7eb1e2013-12-04 05:53:08 +00002622MagickExport MagickBooleanType InitImageMagickOpenCL(
2623 ImageMagickOpenCLMode mode,void *userSelectedDevice,void *selectedDevice,
2624 ExceptionInfo *exception)
2625{
dirkcec9dd62014-04-08 22:59:41 +00002626 MagickBooleanType status = MagickFalse;
cristyf034abb2013-11-24 14:16:14 +00002627 MagickCLEnv clEnv = NULL;
2628 MagickBooleanType flag;
2629
cristyf034abb2013-11-24 14:16:14 +00002630 clEnv = GetDefaultOpenCLEnv();
2631 if (clEnv!=NULL) {
2632 switch(mode) {
2633
2634 case MAGICK_OPENCL_OFF:
2635 flag = MagickTrue;
2636 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2637 , sizeof(MagickBooleanType), &flag, exception);
2638 status = InitOpenCLEnv(clEnv, exception);
2639
2640 if (selectedDevice)
2641 *(cl_device_id*)selectedDevice = NULL;
2642 break;
2643
2644 case MAGICK_OPENCL_DEVICE_SELECT_USER:
2645
2646 if (userSelectedDevice == NULL)
2647 return MagickFalse;
2648
2649 flag = MagickFalse;
2650 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2651 , sizeof(MagickBooleanType), &flag, exception);
2652
2653 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2654 , sizeof(cl_device_id), userSelectedDevice,exception);
2655
2656 status = InitOpenCLEnv(clEnv, exception);
2657 if (selectedDevice) {
2658 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2659 , sizeof(cl_device_id), selectedDevice, exception);
2660 }
2661 break;
2662
dirk20932d32013-12-12 06:16:19 +00002663 case MAGICK_OPENCL_DEVICE_SELECT_AUTO_CLEAR_CACHE:
2664 flag = MagickTrue;
2665 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_PROGRAM_CACHE_DISABLED
2666 , sizeof(MagickBooleanType), &flag, exception);
2667 flag = MagickTrue;
2668 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_REGENERATE_PROFILE
2669 , sizeof(MagickBooleanType), &flag, exception);
2670
2671 /* fall through here!! */
cristyf034abb2013-11-24 14:16:14 +00002672 case MAGICK_OPENCL_DEVICE_SELECT_AUTO:
2673 default:
2674 {
2675 cl_device_id d = NULL;
2676 flag = MagickFalse;
2677 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED
2678 , sizeof(MagickBooleanType), &flag, exception);
2679 SetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2680 , sizeof(cl_device_id), &d,exception);
2681 status = InitOpenCLEnv(clEnv, exception);
2682 if (selectedDevice) {
2683 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_DEVICE
2684 , sizeof(cl_device_id), selectedDevice, exception);
2685 }
2686 }
2687 break;
2688 };
2689 }
2690 return status;
2691}
2692
2693
dirk20932d32013-12-12 06:16:19 +00002694MagickPrivate
cristya22457d2013-12-07 14:03:06 +00002695MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2696 const char *module,const char *function,const size_t line,
2697 const ExceptionType severity,const char *tag,const char *format,...) {
2698 MagickBooleanType
2699 status;
2700
2701 MagickCLEnv clEnv;
2702
2703 status = MagickTrue;
2704
2705 clEnv = GetDefaultOpenCLEnv();
2706
2707 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +00002708 assert(exception->signature == MagickCoreSignature);
cristya22457d2013-12-07 14:03:06 +00002709
2710 if (severity!=0) {
2711 cl_device_type dType;
cristy0c832c62014-03-07 22:21:04 +00002712 clEnv->library->clGetDeviceInfo(clEnv->device,CL_DEVICE_TYPE ,sizeof(cl_device_type),&dType,NULL);
cristya22457d2013-12-07 14:03:06 +00002713 if (dType == CL_DEVICE_TYPE_CPU) {
cristy151b66d2015-04-15 10:50:31 +00002714 char buffer[MagickPathExtent];
2715 clEnv->library->clGetPlatformInfo(clEnv->platform, CL_PLATFORM_NAME, MagickPathExtent, buffer, NULL);
cristya22457d2013-12-07 14:03:06 +00002716
2717 /* Workaround for Intel OpenCL CPU runtime bug */
2718 /* Turn off OpenCL when a problem is detected! */
2719 if (strncmp(buffer, "Intel",5) == 0) {
2720
2721 InitImageMagickOpenCL(MAGICK_OPENCL_OFF, NULL, NULL, exception);
2722 }
2723 }
2724 }
2725
2726#ifdef OPENCLLOG_ENABLED
2727 {
2728 va_list
2729 operands;
2730 va_start(operands,format);
2731 status=ThrowMagickExceptionList(exception,module,function,line,severity,tag, format,operands);
2732 va_end(operands);
2733 }
2734#else
2735 magick_unreferenced(module);
2736 magick_unreferenced(function);
2737 magick_unreferenced(line);
2738 magick_unreferenced(tag);
2739 magick_unreferenced(format);
2740#endif
2741
2742 return(status);
2743}
2744
cristy0c832c62014-03-07 22:21:04 +00002745MagickPrivate cl_mem GetAndLockRandSeedBuffer(MagickCLEnv clEnv)
Cristy1dd96da2015-10-06 07:52:01 -04002746{
cristy0c832c62014-03-07 22:21:04 +00002747 LockSemaphoreInfo(clEnv->lock);
2748 if (clEnv->seedsLock == NULL)
2749 {
2750 ActivateSemaphoreInfo(&clEnv->seedsLock);
2751 }
2752 LockSemaphoreInfo(clEnv->seedsLock);
2753
2754 if (clEnv->seeds == NULL)
2755 {
2756 cl_int clStatus;
2757 clEnv->numGenerators = NUM_CL_RAND_GENERATORS;
2758 clEnv->seeds = clEnv->library->clCreateBuffer(clEnv->context, CL_MEM_READ_WRITE,
2759 clEnv->numGenerators*4*sizeof(unsigned int),
2760 NULL, &clStatus);
2761 if (clStatus != CL_SUCCESS)
2762 {
2763 clEnv->seeds = NULL;
2764 }
2765 else
2766 {
2767 unsigned int i;
2768 cl_command_queue queue = NULL;
2769 unsigned int *seeds;
2770
2771 queue = AcquireOpenCLCommandQueue(clEnv);
Cristy1dd96da2015-10-06 07:52:01 -04002772 seeds = (unsigned int*) clEnv->library->clEnqueueMapBuffer(queue, clEnv->seeds, CL_TRUE,
cristy0c832c62014-03-07 22:21:04 +00002773 CL_MAP_WRITE, 0,
2774 clEnv->numGenerators*4
2775 *sizeof(unsigned int),
2776 0, NULL, NULL, &clStatus);
2777 if (clStatus!=CL_SUCCESS)
2778 {
2779 clEnv->library->clReleaseMemObject(clEnv->seeds);
2780 goto cleanup;
2781 }
2782
2783 for (i = 0; i < clEnv->numGenerators; i++) {
2784 RandomInfo* randomInfo = AcquireRandomInfo();
2785 const unsigned long* s = GetRandomInfoSeed(randomInfo);
2786 if (i == 0)
2787 clEnv->randNormalize = GetRandomInfoNormalize(randomInfo);
2788
2789 seeds[i*4] = (unsigned int) s[0];
2790 seeds[i*4+1] = (unsigned int) 0x50a7f451;
2791 seeds[i*4+2] = (unsigned int) 0x5365417e;
2792 seeds[i*4+3] = (unsigned int) 0xc3a4171a;
2793
2794 randomInfo = DestroyRandomInfo(randomInfo);
2795 }
Cristy1dd96da2015-10-06 07:52:01 -04002796 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, clEnv->seeds, seeds, 0,
cristy0c832c62014-03-07 22:21:04 +00002797 NULL, NULL);
2798 clEnv->library->clFinish(queue);
2799cleanup:
Cristy1dd96da2015-10-06 07:52:01 -04002800 if (queue != NULL)
cristy0c832c62014-03-07 22:21:04 +00002801 RelinquishOpenCLCommandQueue(clEnv, queue);
2802 }
2803 }
2804 UnlockSemaphoreInfo(clEnv->lock);
Cristy1dd96da2015-10-06 07:52:01 -04002805 return clEnv->seeds;
cristy0c832c62014-03-07 22:21:04 +00002806}
2807
2808MagickPrivate void UnlockRandSeedBuffer(MagickCLEnv clEnv) {
2809 if (clEnv->seedsLock == NULL)
2810 {
2811 ActivateSemaphoreInfo(&clEnv->seedsLock);
2812 }
2813 else
2814 UnlockSemaphoreInfo(clEnv->seedsLock);
2815}
2816
2817MagickPrivate unsigned int GetNumRandGenerators(MagickCLEnv clEnv)
2818{
2819 return clEnv->numGenerators;
2820}
2821
2822
2823MagickPrivate float GetRandNormalize(MagickCLEnv clEnv)
2824{
2825 return clEnv->randNormalize;
2826}
cristya22457d2013-12-07 14:03:06 +00002827
cristyf034abb2013-11-24 14:16:14 +00002828#else
2829
2830struct _MagickCLEnv {
2831 MagickBooleanType OpenCLInitialized; /* whether OpenCL environment is initialized. */
2832};
2833
cristy0c832c62014-03-07 22:21:04 +00002834MagickExport MagickCLEnv AcquireMagickOpenCLEnv()
cristyf034abb2013-11-24 14:16:14 +00002835{
2836 return NULL;
2837}
2838
cristy0c832c62014-03-07 22:21:04 +00002839MagickExport MagickBooleanType RelinquishMagickOpenCLEnv(
cristyf034abb2013-11-24 14:16:14 +00002840 MagickCLEnv magick_unused(clEnv))
2841{
2842 magick_unreferenced(clEnv);
2843
2844 return MagickFalse;
2845}
2846
2847/*
2848* Return the OpenCL environment
Cristy1dd96da2015-10-06 07:52:01 -04002849*/
dirk99731742015-11-14 22:54:38 +01002850MagickExport MagickCLEnv GetDefaultOpenCLEnv()
cristyf034abb2013-11-24 14:16:14 +00002851{
cristyf034abb2013-11-24 14:16:14 +00002852 return (MagickCLEnv) NULL;
2853}
2854
2855MagickExport MagickCLEnv SetDefaultOpenCLEnv(
2856 MagickCLEnv magick_unused(clEnv))
2857{
2858 magick_unreferenced(clEnv);
2859
2860 return (MagickCLEnv) NULL;
Cristy1dd96da2015-10-06 07:52:01 -04002861}
cristyf034abb2013-11-24 14:16:14 +00002862
2863MagickExport MagickBooleanType SetMagickOpenCLEnvParam(
2864 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2865 size_t magick_unused(dataSize),void *magick_unused(data),
2866 ExceptionInfo *magick_unused(exception))
2867{
2868 magick_unreferenced(clEnv);
2869 magick_unreferenced(param);
2870 magick_unreferenced(dataSize);
2871 magick_unreferenced(data);
2872 magick_unreferenced(exception);
2873
2874 return MagickFalse;
2875}
2876
2877MagickExport MagickBooleanType GetMagickOpenCLEnvParam(
2878 MagickCLEnv magick_unused(clEnv),MagickOpenCLEnvParam magick_unused(param),
2879 size_t magick_unused(dataSize),void *magick_unused(data),
2880 ExceptionInfo *magick_unused(exception))
2881{
2882 magick_unreferenced(clEnv);
2883 magick_unreferenced(param);
2884 magick_unreferenced(dataSize);
2885 magick_unreferenced(data);
2886 magick_unreferenced(exception);
2887
2888 return MagickFalse;
2889}
2890
2891MagickExport MagickBooleanType InitOpenCLEnv(MagickCLEnv magick_unused(clEnv),
2892 ExceptionInfo *magick_unused(exception))
2893{
2894 magick_unreferenced(clEnv);
2895 magick_unreferenced(exception);
2896
2897 return MagickFalse;
2898}
2899
cristy7b6514c2013-12-10 23:13:13 +00002900MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(
cristyf034abb2013-11-24 14:16:14 +00002901 MagickCLEnv magick_unused(clEnv))
2902{
2903 magick_unreferenced(clEnv);
2904
2905 return (cl_command_queue) NULL;
2906}
2907
cristy0c832c62014-03-07 22:21:04 +00002908MagickPrivate MagickBooleanType RelinquishCommandQueue(
cristyf034abb2013-11-24 14:16:14 +00002909 MagickCLEnv magick_unused(clEnv),cl_command_queue magick_unused(queue))
2910{
2911 magick_unreferenced(clEnv);
2912 magick_unreferenced(queue);
2913
2914 return MagickFalse;
2915}
2916
cristy7b6514c2013-12-10 23:13:13 +00002917MagickPrivate cl_kernel AcquireOpenCLKernel(
cristyf034abb2013-11-24 14:16:14 +00002918 MagickCLEnv magick_unused(clEnv),MagickOpenCLProgram magick_unused(program),
2919 const char *magick_unused(kernelName))
2920{
2921 magick_unreferenced(clEnv);
2922 magick_unreferenced(program);
2923 magick_unreferenced(kernelName);
2924
cristyf432c632014-12-07 15:11:28 +00002925 return (cl_kernel) NULL;
cristyf034abb2013-11-24 14:16:14 +00002926}
2927
cristy7b6514c2013-12-10 23:13:13 +00002928MagickPrivate MagickBooleanType RelinquishOpenCLKernel(
cristyf034abb2013-11-24 14:16:14 +00002929 MagickCLEnv magick_unused(clEnv),cl_kernel magick_unused(kernel))
2930{
2931 magick_unreferenced(clEnv);
2932 magick_unreferenced(kernel);
2933
2934 return MagickFalse;
2935}
2936
cristy7b6514c2013-12-10 23:13:13 +00002937MagickPrivate unsigned long GetOpenCLDeviceLocalMemorySize(
cristyf034abb2013-11-24 14:16:14 +00002938 MagickCLEnv magick_unused(clEnv))
2939{
2940 magick_unreferenced(clEnv);
2941
2942 return 0;
2943}
2944
dirked7eb1e2013-12-04 05:53:08 +00002945MagickExport MagickBooleanType InitImageMagickOpenCL(
2946 ImageMagickOpenCLMode magick_unused(mode),
2947 void *magick_unused(userSelectedDevice),void *magick_unused(selectedDevice),
2948 ExceptionInfo *magick_unused(exception))
cristyf034abb2013-11-24 14:16:14 +00002949{
2950 magick_unreferenced(mode);
2951 magick_unreferenced(userSelectedDevice);
2952 magick_unreferenced(selectedDevice);
2953 magick_unreferenced(exception);
2954 return MagickFalse;
2955}
2956
cristya22457d2013-12-07 14:03:06 +00002957
dirk20932d32013-12-12 06:16:19 +00002958MagickPrivate
cristya22457d2013-12-07 14:03:06 +00002959MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2960 const char *module,const char *function,const size_t line,
Cristy1dd96da2015-10-06 07:52:01 -04002961 const ExceptionType severity,const char *tag,const char *format,...)
cristya22457d2013-12-07 14:03:06 +00002962{
2963 magick_unreferenced(exception);
2964 magick_unreferenced(module);
2965 magick_unreferenced(function);
2966 magick_unreferenced(line);
2967 magick_unreferenced(severity);
2968 magick_unreferenced(tag);
2969 magick_unreferenced(format);
2970 return(MagickFalse);
2971}
cristy0c832c62014-03-07 22:21:04 +00002972
2973
2974MagickPrivate cl_mem GetAndLockRandSeedBuffer(MagickCLEnv clEnv)
2975{
2976 magick_unreferenced(clEnv);
2977 return NULL;
2978}
2979
2980
2981MagickPrivate void UnlockRandSeedBuffer(MagickCLEnv clEnv)
2982{
2983 magick_unreferenced(clEnv);
2984}
2985
2986MagickPrivate unsigned int GetNumRandGenerators(MagickCLEnv clEnv)
2987{
2988 magick_unreferenced(clEnv);
2989 return 0;
2990}
2991
2992MagickPrivate float GetRandNormalize(MagickCLEnv clEnv)
2993{
2994 magick_unreferenced(clEnv);
2995 return 0.0f;
2996}
2997
cristyf034abb2013-11-24 14:16:14 +00002998#endif /* MAGICKCORE_OPENCL_SUPPORT */
2999
3000char* openclCachedFilesDirectory;
3001SemaphoreInfo* openclCachedFilesDirectoryLock;
3002
cristy7b6514c2013-12-10 23:13:13 +00003003MagickPrivate
cristyf034abb2013-11-24 14:16:14 +00003004const char* GetOpenCLCachedFilesDirectory() {
3005 if (openclCachedFilesDirectory == NULL) {
3006 if (openclCachedFilesDirectoryLock == NULL)
3007 {
cristy04b11db2014-02-16 15:10:39 +00003008 ActivateSemaphoreInfo(&openclCachedFilesDirectoryLock);
cristyf034abb2013-11-24 14:16:14 +00003009 }
3010 LockSemaphoreInfo(openclCachedFilesDirectoryLock);
3011 if (openclCachedFilesDirectory == NULL) {
cristy151b66d2015-04-15 10:50:31 +00003012 char path[MagickPathExtent];
cristyf034abb2013-11-24 14:16:14 +00003013 char *home = NULL;
3014 char *temp = NULL;
3015 struct stat attributes;
3016 MagickBooleanType status;
Cristy1dd96da2015-10-06 07:52:01 -04003017 int mkdirStatus = 0;
cristyf034abb2013-11-24 14:16:14 +00003018
cristy0c832c62014-03-07 22:21:04 +00003019
3020
cristya45be692014-07-24 10:12:11 +00003021 home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
cristy0c832c62014-03-07 22:21:04 +00003022 if (home == (char *) NULL)
3023 {
Cristy1dd96da2015-10-06 07:52:01 -04003024 home=GetEnvironmentValue("XDG_CACHE_HOME");
3025 if (home == (char *) NULL)
3026 home=GetEnvironmentValue("LOCALAPPDATA");
cristy0c832c62014-03-07 22:21:04 +00003027 if (home == (char *) NULL)
3028 home=GetEnvironmentValue("APPDATA");
3029 if (home == (char *) NULL)
3030 home=GetEnvironmentValue("USERPROFILE");
cristy0c832c62014-03-07 22:21:04 +00003031 }
Cristy1dd96da2015-10-06 07:52:01 -04003032
cristyf034abb2013-11-24 14:16:14 +00003033 if (home != (char *) NULL)
3034 {
Cristy1dd96da2015-10-06 07:52:01 -04003035 /* first check if $HOME exists */
3036 (void) FormatLocaleString(path,MagickPathExtent,"%s",home);
cristycba97932014-03-05 22:52:17 +00003037 status=GetPathAttributes(path,&attributes);
Cristy1dd96da2015-10-06 07:52:01 -04003038 if (status == MagickFalse)
cristy0c832c62014-03-07 22:21:04 +00003039 {
Cristy1dd96da2015-10-06 07:52:01 -04003040
cristycba97932014-03-05 22:52:17 +00003041#ifdef MAGICKCORE_WINDOWS_SUPPORT
cristy0c832c62014-03-07 22:21:04 +00003042 mkdirStatus = mkdir(path);
cristycba97932014-03-05 22:52:17 +00003043#else
cristy0c832c62014-03-07 22:21:04 +00003044 mkdirStatus = mkdir(path, 0777);
cristycba97932014-03-05 22:52:17 +00003045#endif
3046 }
Cristy1dd96da2015-10-06 07:52:01 -04003047
3048 /* first check if $HOME/ImageMagick exists */
3049 if (mkdirStatus==0)
cristy0c832c62014-03-07 22:21:04 +00003050 {
Cristy9799a842015-10-04 19:44:36 -04003051 (void) FormatLocaleString(path,MagickPathExtent,
Cristy1dd96da2015-10-06 07:52:01 -04003052 "%s%sImageMagick",home,DirectorySeparator);
3053
cristy0c832c62014-03-07 22:21:04 +00003054 status=GetPathAttributes(path,&attributes);
Cristy1dd96da2015-10-06 07:52:01 -04003055 if (status == MagickFalse)
cristy0c832c62014-03-07 22:21:04 +00003056 {
3057#ifdef MAGICKCORE_WINDOWS_SUPPORT
3058 mkdirStatus = mkdir(path);
3059#else
3060 mkdirStatus = mkdir(path, 0777);
3061#endif
3062 }
3063 }
3064
3065 if (mkdirStatus==0)
3066 {
3067 temp = (char*)AcquireMagickMemory(strlen(path)+1);
3068 CopyMagickString(temp,path,strlen(path)+1);
3069 }
cristyf034abb2013-11-24 14:16:14 +00003070 home=DestroyString(home);
Cristy1dd96da2015-10-06 07:52:01 -04003071 } else {
3072 home=GetEnvironmentValue("HOME");
3073 if (home != (char *) NULL)
3074 {
3075 /* first check if $HOME/.cache exists */
3076 (void) FormatLocaleString(path,MagickPathExtent,"%s%s.cache",
3077 home,DirectorySeparator);
3078 status=GetPathAttributes(path,&attributes);
3079 if (status == MagickFalse)
3080 {
3081
3082#ifdef MAGICKCORE_WINDOWS_SUPPORT
3083 mkdirStatus = mkdir(path);
3084#else
3085 mkdirStatus = mkdir(path, 0777);
3086#endif
3087 }
3088
3089 /* first check if $HOME/.cache/ImageMagick exists */
3090 if (mkdirStatus==0)
3091 {
3092 (void) FormatLocaleString(path,MagickPathExtent,
3093 "%s%s.cache%sImageMagick",home,DirectorySeparator,
3094 DirectorySeparator);
3095
3096 status=GetPathAttributes(path,&attributes);
3097 if (status == MagickFalse)
3098 {
3099#ifdef MAGICKCORE_WINDOWS_SUPPORT
3100 mkdirStatus = mkdir(path);
3101#else
3102 mkdirStatus = mkdir(path, 0777);
3103#endif
3104 }
3105 }
3106
3107 if (mkdirStatus==0)
3108 {
3109 temp = (char*)AcquireMagickMemory(strlen(path)+1);
3110 CopyMagickString(temp,path,strlen(path)+1);
3111 }
3112 home=DestroyString(home);
3113 }
cristyf034abb2013-11-24 14:16:14 +00003114 }
3115 openclCachedFilesDirectory = temp;
3116 }
Cristy1dd96da2015-10-06 07:52:01 -04003117 UnlockSemaphoreInfo(openclCachedFilesDirectoryLock);
cristyf034abb2013-11-24 14:16:14 +00003118 }
3119 return openclCachedFilesDirectory;
3120}
3121
cristye85d0f72013-11-27 02:25:43 +00003122/* create a function for OpenCL log */
cristy7b6514c2013-12-10 23:13:13 +00003123MagickPrivate
cristyf034abb2013-11-24 14:16:14 +00003124void OpenCLLog(const char* message) {
3125
cristye85d0f72013-11-27 02:25:43 +00003126#ifdef OPENCLLOG_ENABLED
cristyf034abb2013-11-24 14:16:14 +00003127#define OPENCL_LOG_FILE "ImageMagickOpenCL.log"
3128
3129 FILE* log;
cristye85d0f72013-11-27 02:25:43 +00003130 if (getenv("MAGICK_OCL_LOG"))
3131 {
3132 if (message) {
cristy151b66d2015-04-15 10:50:31 +00003133 char path[MagickPathExtent];
cristya22457d2013-12-07 14:03:06 +00003134 unsigned long allocSize;
3135
3136 MagickCLEnv clEnv;
3137
3138 clEnv = GetDefaultOpenCLEnv();
cristyf034abb2013-11-24 14:16:14 +00003139
cristye85d0f72013-11-27 02:25:43 +00003140 /* dump the source into a file */
cristy151b66d2015-04-15 10:50:31 +00003141 (void) FormatLocaleString(path,MagickPathExtent,"%s%s%s"
cristye85d0f72013-11-27 02:25:43 +00003142 ,GetOpenCLCachedFilesDirectory()
3143 ,DirectorySeparator,OPENCL_LOG_FILE);
cristyf034abb2013-11-24 14:16:14 +00003144
3145
cristye85d0f72013-11-27 02:25:43 +00003146 log = fopen(path, "ab");
3147 fwrite(message, sizeof(char), strlen(message), log);
3148 fwrite("\n", sizeof(char), 1, log);
cristya22457d2013-12-07 14:03:06 +00003149
3150 if (clEnv->OpenCLInitialized && !clEnv->OpenCLDisabled)
3151 {
3152 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv);
Cristy4cf12fd2015-09-05 21:20:57 -04003153 fprintf(log, "Devic Max Memory Alloc Size: %lu\n", allocSize);
cristya22457d2013-12-07 14:03:06 +00003154 }
3155
cristye85d0f72013-11-27 02:25:43 +00003156 fclose(log);
3157 }
cristyf034abb2013-11-24 14:16:14 +00003158 }
cristye85d0f72013-11-27 02:25:43 +00003159#else
3160 magick_unreferenced(message);
3161#endif
cristyf034abb2013-11-24 14:16:14 +00003162}
dirk99731742015-11-14 22:54:38 +01003163
3164MagickPrivate void OpenCLTerminus()
3165{
dirkf6c70c32015-11-14 22:58:17 +01003166#if MAGICKCORE_OPENCL_SUPPORT
dirk251cf8e2015-11-14 23:17:52 +01003167 DumpProfileData();
dirk99731742015-11-14 22:54:38 +01003168 if (openclCachedFilesDirectory != (char *) NULL)
3169 openclCachedFilesDirectory=DestroyString(openclCachedFilesDirectory);
3170 if (openclCachedFilesDirectoryLock != (SemaphoreInfo*)NULL)
3171 RelinquishSemaphoreInfo(&openclCachedFilesDirectoryLock);
3172 if (defaultCLEnv != (MagickCLEnv) NULL)
3173 {
3174 (void) RelinquishMagickOpenCLEnv(defaultCLEnv);
3175 defaultCLEnv=(MagickCLEnv)NULL;
3176 }
3177 if (defaultCLEnvLock != (SemaphoreInfo*) NULL)
3178 RelinquishSemaphoreInfo(&defaultCLEnvLock);
3179 if (OpenCLLib != (MagickLibrary *)NULL)
3180 OpenCLLib=(MagickLibrary *)RelinquishMagickMemory(OpenCLLib);
3181 if (OpenCLLibLock != (SemaphoreInfo*)NULL)
3182 RelinquishSemaphoreInfo(&OpenCLLibLock);
dirkf6c70c32015-11-14 22:58:17 +01003183#endif
dirk99731742015-11-14 22:54:38 +01003184}