Coverage Report

Created: 2026-11-12 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/opencl.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                   OOO   PPPP   EEEEE  N   N   CCCC  L                       %
7
%                  O   O  P   P  E      NN  N  C      L                       %
8
%                  O   O  PPPP   EEE    N N N  C      L                       %
9
%                  O   O  P      E      N  NN  C      L                       %
10
%                   OOO   P      EEEEE  N   N   CCCC  LLLLL                   %
11
%                                                                             %
12
%                                                                             %
13
%                         MagickCore OpenCL Methods                           %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 March 2000                                  %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/license/                                         %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
%
38
*/
39

40
/*
41
  Include declarations.
42
*/
43
#include "MagickCore/studio.h"
44
#include "MagickCore/accelerate-kernels-private.h"
45
#include "MagickCore/artifact.h"
46
#include "MagickCore/cache.h"
47
#include "MagickCore/cache-private.h"
48
#include "MagickCore/color.h"
49
#include "MagickCore/compare.h"
50
#include "MagickCore/constitute.h"
51
#include "MagickCore/configure.h"
52
#include "MagickCore/distort.h"
53
#include "MagickCore/draw.h"
54
#include "MagickCore/effect.h"
55
#include "MagickCore/exception.h"
56
#include "MagickCore/exception-private.h"
57
#include "MagickCore/fx.h"
58
#include "MagickCore/gem.h"
59
#include "MagickCore/geometry.h"
60
#include "MagickCore/image.h"
61
#include "MagickCore/image-private.h"
62
#include "MagickCore/layer.h"
63
#include "MagickCore/locale_.h"
64
#include "MagickCore/mime-private.h"
65
#include "MagickCore/memory_.h"
66
#include "MagickCore/memory-private.h"
67
#include "MagickCore/monitor.h"
68
#include "MagickCore/montage.h"
69
#include "MagickCore/morphology.h"
70
#include "MagickCore/nt-base.h"
71
#include "MagickCore/nt-base-private.h"
72
#include "MagickCore/opencl.h"
73
#include "MagickCore/opencl-private.h"
74
#include "MagickCore/option.h"
75
#include "MagickCore/policy.h"
76
#include "MagickCore/property.h"
77
#include "MagickCore/quantize.h"
78
#include "MagickCore/quantum.h"
79
#include "MagickCore/random_.h"
80
#include "MagickCore/random-private.h"
81
#include "MagickCore/resample.h"
82
#include "MagickCore/resource_.h"
83
#include "MagickCore/splay-tree.h"
84
#include "MagickCore/semaphore.h"
85
#include "MagickCore/statistic.h"
86
#include "MagickCore/string_.h"
87
#include "MagickCore/string-private.h"
88
#include "MagickCore/token.h"
89
#include "MagickCore/utility.h"
90
#include "MagickCore/utility-private.h"
91
#include "MagickCore/xml-tree-private.h"
92
93
#if defined(MAGICKCORE_OPENCL_SUPPORT)
94
#if defined(MAGICKCORE_LTDL_DELEGATE)
95
#include "ltdl.h"
96
#endif
97
98
/*
99
  Define declarations.
100
*/
101
#define IMAGEMAGICK_PROFILE_FILE "ImagemagickOpenCLDeviceProfile.xml"
102
103
/*
104
  Typedef declarations.
105
*/
106
typedef struct
107
{
108
  long long freq;
109
  long long clocks;
110
  long long start;
111
} AccelerateTimer;
112
113
typedef struct
114
{
115
  char
116
    *name,
117
    *platform_name,
118
    *vendor_name,
119
    *version;
120
121
  cl_uint
122
    max_clock_frequency,
123
    max_compute_units;
124
125
  double
126
    score;
127
} MagickCLDeviceBenchmark;
128
129
/*
130
  Forward declarations.
131
*/
132
133
static MagickBooleanType
134
  HasOpenCLDevices(MagickCLEnv,ExceptionInfo *),
135
  LoadOpenCLLibrary(void);
136
137
static MagickCLDevice
138
  RelinquishMagickCLDevice(MagickCLDevice);
139
140
static MagickCLEnv
141
  RelinquishMagickCLEnv(MagickCLEnv);
142
143
static void
144
  BenchmarkOpenCLDevices(MagickCLEnv);
145
146
/* OpenCL library */
147
MagickLibrary
148
  *openCL_library;
149
150
/* Default OpenCL environment */
151
MagickCLEnv
152
  default_CLEnv;
153
MagickThreadType
154
  test_thread_id=0;
155
SemaphoreInfo
156
  *openCL_lock;
157
158
/* Cached location of the OpenCL cache files */
159
char
160
  *cache_directory;
161
SemaphoreInfo
162
  *cache_directory_lock;
163
164
static inline MagickBooleanType IsSameOpenCLDevice(MagickCLDevice a,
165
  MagickCLDevice b)
166
{
167
  if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
168
      (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
169
      (LocaleCompare(a->name,b->name) == 0) &&
170
      (LocaleCompare(a->version,b->version) == 0) &&
171
      (a->max_clock_frequency == b->max_clock_frequency) &&
172
      (a->max_compute_units == b->max_compute_units))
173
    return(MagickTrue);
174
175
  return(MagickFalse);
176
}
177
178
static inline MagickBooleanType IsBenchmarkedOpenCLDevice(MagickCLDevice a,
179
  MagickCLDeviceBenchmark *b)
180
{
181
  if ((LocaleCompare(a->platform_name,b->platform_name) == 0) &&
182
      (LocaleCompare(a->vendor_name,b->vendor_name) == 0) &&
183
      (LocaleCompare(a->name,b->name) == 0) &&
184
      (LocaleCompare(a->version,b->version) == 0) &&
185
      (a->max_clock_frequency == b->max_clock_frequency) &&
186
      (a->max_compute_units == b->max_compute_units))
187
    return(MagickTrue);
188
189
  return(MagickFalse);
190
}
191
192
static inline void RelinquishMagickCLDevices(MagickCLEnv clEnv)
193
{
194
  size_t
195
    i;
196
197
  if (clEnv->devices != (MagickCLDevice *) NULL)
198
    {
199
      for (i = 0; i < clEnv->number_devices; i++)
200
        clEnv->devices[i]=RelinquishMagickCLDevice(clEnv->devices[i]);
201
      clEnv->devices=(MagickCLDevice *) RelinquishMagickMemory(clEnv->devices);
202
    }
203
  clEnv->number_devices=0;
204
}
205
206
static inline MagickBooleanType MagickCreateDirectory(const char *path)
207
{
208
  int
209
    status;
210
211
#ifdef MAGICKCORE_WINDOWS_SUPPORT
212
  status=_mkdir(path);
213
#else
214
  status=mkdir(path,0777);
215
#endif
216
  return(status == 0 ? MagickTrue : MagickFalse);
217
}
218
219
static inline void InitAccelerateTimer(AccelerateTimer *timer)
220
{
221
#ifdef _WIN32
222
  QueryPerformanceFrequency((LARGE_INTEGER*)&timer->freq);
223
#else
224
  timer->freq=(long long)1.0E3;
225
#endif
226
  timer->clocks=0;
227
  timer->start=0;
228
}
229
230
static inline double ReadAccelerateTimer(AccelerateTimer *timer)
231
{
232
  return (double)timer->clocks/(double)timer->freq;
233
}
234
235
static inline void StartAccelerateTimer(AccelerateTimer* timer)
236
{
237
#ifdef _WIN32
238
  QueryPerformanceCounter((LARGE_INTEGER*)&timer->start);
239
#else
240
  struct timeval
241
    s;
242
  gettimeofday(&s,0);
243
  timer->start=(long long)s.tv_sec*(long long)1.0E3+(long long)s.tv_usec/
244
    (long long)1.0E3;
245
#endif
246
}
247
248
static inline void StopAccelerateTimer(AccelerateTimer *timer)
249
{
250
  long long
251
    n;
252
253
  n=0;
254
#ifdef _WIN32
255
  QueryPerformanceCounter((LARGE_INTEGER*)&(n));
256
#else
257
  struct timeval
258
    s;
259
  gettimeofday(&s,0);
260
  n=(long long)s.tv_sec*(long long)1.0E3+(long long)s.tv_usec/
261
    (long long)1.0E3;
262
#endif
263
  n-=timer->start;
264
  timer->start=0;
265
  timer->clocks+=n;
266
}
267
268
static const char *GetOpenCLCacheDirectory()
269
{
270
  if (cache_directory == (char *) NULL)
271
    {
272
      if (cache_directory_lock == (SemaphoreInfo *) NULL)
273
        ActivateSemaphoreInfo(&cache_directory_lock);
274
      LockSemaphoreInfo(cache_directory_lock);
275
      if (cache_directory == (char *) NULL)
276
        {
277
          char
278
            *home,
279
            path[MagickPathExtent],
280
            *temp;
281
282
          MagickBooleanType
283
            status;
284
285
          struct stat
286
            attributes;
287
288
          temp=(char *) NULL;
289
          home=GetEnvironmentValue("MAGICK_OPENCL_CACHE_DIR");
290
          if (home == (char *) NULL)
291
            {
292
              home=GetEnvironmentValue("XDG_CACHE_HOME");
293
#if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
294
              if (home == (char *) NULL)
295
                home=GetEnvironmentValue("LOCALAPPDATA");
296
              if (home == (char *) NULL)
297
                home=GetEnvironmentValue("APPDATA");
298
              if (home == (char *) NULL)
299
                home=GetEnvironmentValue("USERPROFILE");
300
#endif
301
            }
302
303
          if (home != (char *) NULL)
304
            {
305
              /* first check if $HOME exists */
306
              (void) FormatLocaleString(path,MagickPathExtent,"%s",home);
307
              status=GetPathAttributes(path,&attributes);
308
              if (status == MagickFalse)
309
                status=MagickCreateDirectory(path);
310
311
              /* first check if $HOME/ImageMagick exists */
312
              if (status != MagickFalse)
313
                {
314
                  (void) FormatLocaleString(path,MagickPathExtent,
315
                    "%s%sImageMagick",home,DirectorySeparator);
316
317
                  status=GetPathAttributes(path,&attributes);
318
                  if (status == MagickFalse)
319
                    status=MagickCreateDirectory(path);
320
                }
321
322
              if (status != MagickFalse)
323
                {
324
                  temp=(char*) AcquireCriticalMemory(strlen(path)+1);
325
                  (void) CopyMagickString(temp,path,strlen(path)+1);
326
                }
327
              home=DestroyString(home);
328
            }
329
          else
330
            {
331
              home=GetEnvironmentValue("HOME");
332
              if (home != (char *) NULL)
333
                {
334
                  /* first check if $HOME/.cache exists */
335
                  (void) FormatLocaleString(path,MagickPathExtent,"%s%s.cache",
336
                    home,DirectorySeparator);
337
                  status=GetPathAttributes(path,&attributes);
338
                  if (status == MagickFalse)
339
                    status=MagickCreateDirectory(path);
340
341
                  /* first check if $HOME/.cache/ImageMagick exists */
342
                  if (status != MagickFalse)
343
                    {
344
                      (void) FormatLocaleString(path,MagickPathExtent,
345
                        "%s%s.cache%sImageMagick",home,DirectorySeparator,
346
                        DirectorySeparator);
347
                      status=GetPathAttributes(path,&attributes);
348
                      if (status == MagickFalse)
349
                        status=MagickCreateDirectory(path);
350
                    }
351
352
                  if (status != MagickFalse)
353
                    {
354
                      temp=(char*) AcquireCriticalMemory(strlen(path)+1);
355
                      (void) CopyMagickString(temp,path,strlen(path)+1);
356
                    }
357
                  home=DestroyString(home);
358
                }
359
            }
360
          if (temp == (char *) NULL)
361
            {
362
              temp=AcquireString("?");
363
              (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
364
                "Cannot use cache directory: \"%s\"",path);
365
            }
366
          else
367
            (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
368
              "Using cache directory: \"%s\"",temp);
369
          cache_directory=temp;
370
        }
371
      UnlockSemaphoreInfo(cache_directory_lock);
372
    }
373
  if (*cache_directory == '?')
374
    return((const char *) NULL);
375
  return(cache_directory);
376
}
377
378
static void SelectOpenCLDevice(MagickCLEnv clEnv,cl_device_type type)
379
{
380
  MagickCLDevice
381
    device;
382
383
  size_t
384
    i,
385
    j;
386
387
  (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
388
    "Selecting device for type: %d",(int) type);
389
  for (i = 0; i < clEnv->number_devices; i++)
390
    clEnv->devices[i]->enabled=MagickFalse;
391
392
  for (i = 0; i < clEnv->number_devices; i++)
393
  {
394
    device=clEnv->devices[i];
395
    if (device->type != type)
396
      continue;
397
398
    device->enabled=MagickTrue;
399
    (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
400
      "Selected device: %s",device->name);
401
    for (j = i+1; j < clEnv->number_devices; j++)
402
    {
403
      MagickCLDevice
404
        other_device;
405
406
      other_device=clEnv->devices[j];
407
      if (IsSameOpenCLDevice(device,other_device))
408
        other_device->enabled=MagickTrue;
409
    }
410
  }
411
}
412
413
static size_t StringSignature(const char* string)
414
{
415
  size_t
416
    n,
417
    i,
418
    j,
419
    signature,
420
    stringLength;
421
422
  union
423
  {
424
    const char* s;
425
    const size_t* u;
426
  } p;
427
428
  stringLength=(size_t) strlen(string);
429
  signature=stringLength;
430
  n=stringLength/sizeof(size_t);
431
  p.s=string;
432
  for (i = 0; i < n; i++)
433
    signature^=p.u[i];
434
  if (n * sizeof(size_t) != stringLength)
435
    {
436
      char
437
        padded[4];
438
439
      j=n*sizeof(size_t);
440
      for (i = 0; i < 4; i++, j++)
441
      {
442
        if (j < stringLength)
443
          padded[i]=p.s[j];
444
        else
445
          padded[i]=0;
446
      }
447
      p.s=padded;
448
      signature^=p.u[0];
449
    }
450
  return(signature);
451
}
452
453
static void DestroyMagickCLCacheInfo(MagickCLCacheInfo info)
454
{
455
  ssize_t
456
    i;
457
458
  for (i=0; i < (ssize_t) info->event_count; i++)
459
    openCL_library->clReleaseEvent(info->events[i]);
460
  info->events=(cl_event *) RelinquishMagickMemory(info->events);
461
  if (info->buffer != (cl_mem) NULL)
462
    openCL_library->clReleaseMemObject(info->buffer);
463
  RelinquishSemaphoreInfo(&info->events_semaphore);
464
  ReleaseOpenCLDevice(info->device);
465
  RelinquishMagickMemory(info);
466
}
467
468
/*
469
  Provide call to OpenCL library methods
470
*/
471
472
MagickPrivate cl_mem CreateOpenCLBuffer(MagickCLDevice device,
473
  cl_mem_flags flags,size_t size,void *host_ptr)
474
{
475
  return(openCL_library->clCreateBuffer(device->context,flags,size,host_ptr,
476
    (cl_int *) NULL));
477
}
478
479
MagickPrivate void ReleaseOpenCLKernel(cl_kernel kernel)
480
{
481
  (void) openCL_library->clReleaseKernel(kernel);
482
}
483
484
MagickPrivate void ReleaseOpenCLMemObject(cl_mem memobj)
485
{
486
  (void) openCL_library->clReleaseMemObject(memobj);
487
}
488
489
MagickPrivate void RetainOpenCLMemObject(cl_mem memobj)
490
{
491
  (void) openCL_library->clRetainMemObject(memobj);
492
}
493
494
MagickPrivate cl_int SetOpenCLKernelArg(cl_kernel kernel,size_t arg_index,
495
  size_t arg_size,const void *arg_value)
496
{
497
  return(openCL_library->clSetKernelArg(kernel,(cl_uint) arg_index,arg_size,
498
    arg_value));
499
}
500
501
/*
502
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
503
%                                                                             %
504
%                                                                             %
505
%                                                                             %
506
+   A c q u i r e M a g i c k C L C a c h e I n f o                           %
507
%                                                                             %
508
%                                                                             %
509
%                                                                             %
510
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511
%
512
%  AcquireMagickCLCacheInfo() acquires an OpenCL cache info structure.
513
%
514
%  The format of the AcquireMagickCLCacheInfo method is:
515
%
516
%      MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
517
%        Quantum *pixels,const MagickSizeType length)
518
%
519
%  A description of each parameter follows:
520
%
521
%    o device: the OpenCL device.
522
%
523
%    o pixels: the pixel buffer of the image.
524
%
525
%    o length: the length of the pixel buffer.
526
%
527
*/
528
529
MagickPrivate MagickCLCacheInfo AcquireMagickCLCacheInfo(MagickCLDevice device,
530
  Quantum *pixels,const MagickSizeType length)
531
{
532
  cl_int
533
    status;
534
535
  MagickCLCacheInfo
536
    info;
537
538
  info=(MagickCLCacheInfo) AcquireCriticalMemory(sizeof(*info));
539
  (void) memset(info,0,sizeof(*info));
540
  LockSemaphoreInfo(openCL_lock);
541
  device->requested++;
542
  UnlockSemaphoreInfo(openCL_lock);
543
  info->device=device;
544
  info->length=length;
545
  info->pixels=pixels;
546
  info->events_semaphore=AcquireSemaphoreInfo();
547
  info->buffer=openCL_library->clCreateBuffer(device->context,
548
    CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR,(size_t) length,(void *) pixels,
549
    &status);
550
  if (status == CL_SUCCESS)
551
    return(info);
552
  DestroyMagickCLCacheInfo(info);
553
  return((MagickCLCacheInfo) NULL);
554
}
555
556
/*
557
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
558
%                                                                             %
559
%                                                                             %
560
%                                                                             %
561
%   A c q u i r e M a g i c k C L D e v i c e                                 %
562
%                                                                             %
563
%                                                                             %
564
%                                                                             %
565
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
566
%
567
%  AcquireMagickCLDevice() acquires an OpenCL device
568
%
569
%  The format of the AcquireMagickCLDevice method is:
570
%
571
%      MagickCLDevice AcquireMagickCLDevice()
572
%
573
*/
574
575
static MagickCLDevice AcquireMagickCLDevice()
576
{
577
  MagickCLDevice
578
    device;
579
580
  device=(MagickCLDevice) AcquireMagickMemory(sizeof(*device));
581
  if (device != NULL)
582
  {
583
    (void) memset(device,0,sizeof(*device));
584
    ActivateSemaphoreInfo(&device->lock);
585
    device->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
586
    device->command_queues_index=-1;
587
    device->enabled=MagickTrue;
588
  }
589
  return(device);
590
}
591
592
/*
593
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594
%                                                                             %
595
%                                                                             %
596
%                                                                             %
597
%   A c q u i r e M a g i c k C L E n v                                       %
598
%                                                                             %
599
%                                                                             %
600
%                                                                             %
601
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602
%
603
% AcquireMagickCLEnv() allocates the MagickCLEnv structure
604
%
605
*/
606
607
static MagickCLEnv AcquireMagickCLEnv(void)
608
{
609
  char
610
    *option;
611
612
  MagickCLEnv
613
    clEnv;
614
615
  clEnv=(MagickCLEnv) AcquireMagickMemory(sizeof(*clEnv));
616
  if (clEnv != (MagickCLEnv) NULL)
617
  {
618
    (void) memset(clEnv,0,sizeof(*clEnv));
619
    ActivateSemaphoreInfo(&clEnv->lock);
620
    clEnv->cpu_score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
621
    clEnv->enabled=MagickFalse;
622
    option=GetEnvironmentValue("MAGICK_OCL_DEVICE");
623
    if (option != (const char *) NULL)
624
      {
625
        if ((IsStringTrue(option) != MagickFalse) ||
626
            (strcmp(option,"GPU") == 0) ||
627
            (strcmp(option,"CPU") == 0))
628
          clEnv->enabled=MagickTrue;
629
        option=DestroyString(option);
630
      }
631
  }
632
  return clEnv;
633
}
634
635
/*
636
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
637
%                                                                             %
638
%                                                                             %
639
%                                                                             %
640
+   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                         %
641
%                                                                             %
642
%                                                                             %
643
%                                                                             %
644
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
645
%
646
%  AcquireOpenCLCommandQueue() acquires an OpenCL command queue
647
%
648
%  The format of the AcquireOpenCLCommandQueue method is:
649
%
650
%      cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
651
%
652
%  A description of each parameter follows:
653
%
654
%    o device: the OpenCL device.
655
%
656
*/
657
658
MagickPrivate cl_command_queue AcquireOpenCLCommandQueue(MagickCLDevice device)
659
{
660
  cl_command_queue
661
    queue;
662
663
  cl_command_queue_properties
664
    properties;
665
666
  assert(device != (MagickCLDevice) NULL);
667
  LockSemaphoreInfo(device->lock);
668
  if ((device->profile_kernels == MagickFalse) &&
669
      (device->command_queues_index >= 0))
670
  {
671
    queue=device->command_queues[device->command_queues_index--];
672
    UnlockSemaphoreInfo(device->lock);
673
  }
674
  else
675
  {
676
    UnlockSemaphoreInfo(device->lock);
677
    properties=0;
678
    if (device->profile_kernels != MagickFalse)
679
      properties=CL_QUEUE_PROFILING_ENABLE;
680
    queue=openCL_library->clCreateCommandQueue(device->context,
681
      device->deviceID,properties,(cl_int *) NULL);
682
  }
683
  return(queue);
684
}
685
686
/*
687
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
688
%                                                                             %
689
%                                                                             %
690
%                                                                             %
691
+   A c q u i r e O p e n C L K e r n e l                                     %
692
%                                                                             %
693
%                                                                             %
694
%                                                                             %
695
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696
%
697
%  AcquireOpenCLKernel() acquires an OpenCL kernel
698
%
699
%  The format of the AcquireOpenCLKernel method is:
700
%
701
%      cl_kernel AcquireOpenCLKernel(MagickCLEnv clEnv,
702
%        MagickOpenCLProgram program, const char* kernelName)
703
%
704
%  A description of each parameter follows:
705
%
706
%    o clEnv: the OpenCL environment.
707
%
708
%    o program: the OpenCL program module that the kernel belongs to.
709
%
710
%    o kernelName:  the name of the kernel
711
%
712
*/
713
714
MagickPrivate cl_kernel AcquireOpenCLKernel(MagickCLDevice device,
715
  const char *kernel_name)
716
{
717
  cl_kernel
718
    kernel;
719
720
  assert(device != (MagickCLDevice) NULL);
721
  (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),"Using kernel: %s",
722
    kernel_name);
723
  kernel=openCL_library->clCreateKernel(device->program,kernel_name,
724
    (cl_int *) NULL);
725
  return(kernel);
726
}
727
728
/*
729
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730
%                                                                             %
731
%                                                                             %
732
%                                                                             %
733
%   A u t o S e l e c t O p e n C L D e v i c e s                             %
734
%                                                                             %
735
%                                                                             %
736
%                                                                             %
737
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738
%
739
%  AutoSelectOpenCLDevices() determines the best device based on the
740
%  information from the micro-benchmark.
741
%
742
%  The format of the AutoSelectOpenCLDevices method is:
743
%
744
%      void AcquireOpenCLKernel(MagickCLEnv clEnv,ExceptionInfo *exception)
745
%
746
%  A description of each parameter follows:
747
%
748
%    o clEnv: the OpenCL environment.
749
%
750
%    o exception: return any errors or warnings in this structure.
751
%
752
*/
753
754
#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
755
static MagickCLDeviceBenchmark* RelinquishDeviceBenchmark(
756
  MagickCLDeviceBenchmark *device_benchmark)
757
{
758
  if (device_benchmark == (MagickCLDeviceBenchmark*) NULL)
759
    return((MagickCLDeviceBenchmark *) NULL);
760
761
  device_benchmark->platform_name=(char *) RelinquishMagickMemory(
762
    device_benchmark->platform_name);
763
  device_benchmark->vendor_name=(char *) RelinquishMagickMemory(
764
    device_benchmark->vendor_name);
765
  device_benchmark->name=(char *) RelinquishMagickMemory(
766
    device_benchmark->name);
767
  device_benchmark->version=(char *) RelinquishMagickMemory(
768
    device_benchmark->version);
769
  return((MagickCLDeviceBenchmark *) RelinquishMagickMemory(
770
    device_benchmark));
771
}
772
773
static void LoadOpenCLDeviceBenchmark(MagickCLEnv clEnv,const char *xml)
774
{
775
  char
776
    keyword[MagickPathExtent],
777
    *token;
778
779
  const char
780
    *q;
781
782
  MagickCLDeviceBenchmark
783
    *device_benchmark;
784
785
  size_t
786
    i,
787
    extent;
788
789
  if (xml == (char *) NULL)
790
    return;
791
  device_benchmark=(MagickCLDeviceBenchmark *) NULL;
792
  token=AcquireString(xml);
793
  extent=strlen(token)+MagickPathExtent;
794
  for (q=(char *) xml; *q != '\0'; )
795
  {
796
    /*
797
      Interpret XML.
798
    */
799
    if (SkipXMLComment(&q) == MagickFalse)
800
      break;
801
    (void) GetNextToken(q,&q,extent,token);
802
    if (*token == '\0')
803
      break;
804
    (void) CopyMagickString(keyword,token,MagickPathExtent);
805
    if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
806
      {
807
        if (SkipXMLDocType(&q) == MagickFalse)
808
          break;
809
        continue;
810
      }
811
    if (LocaleCompare(keyword,"<device") == 0)
812
      {
813
        /*
814
          Device element.
815
        */
816
        device_benchmark=(MagickCLDeviceBenchmark *) AcquireQuantumMemory(1,
817
          sizeof(*device_benchmark));
818
        if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
819
          break;
820
        (void) memset(device_benchmark,0,sizeof(*device_benchmark));
821
        device_benchmark->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
822
        continue;
823
      }
824
    if (device_benchmark == (MagickCLDeviceBenchmark *) NULL)
825
      continue;
826
    if (LocaleCompare(keyword,"/>") == 0)
827
      {
828
        if (device_benchmark->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
829
          {
830
            if (LocaleCompare(device_benchmark->name,"CPU") == 0)
831
              clEnv->cpu_score=device_benchmark->score;
832
            else
833
              {
834
                MagickCLDevice
835
                  device;
836
837
                /*
838
                  Set the score for all devices that match this device.
839
                */
840
                for (i = 0; i < clEnv->number_devices; i++)
841
                {
842
                  device=clEnv->devices[i];
843
                  if (IsBenchmarkedOpenCLDevice(device,device_benchmark))
844
                    device->score=device_benchmark->score;
845
                }
846
              }
847
          }
848
        device_benchmark=RelinquishDeviceBenchmark(device_benchmark);
849
        continue;
850
      }
851
    (void) GetNextToken(q,(const char **) NULL,extent,token);
852
    if (*token != '=')
853
      continue;
854
    (void) GetNextToken(q,&q,extent,token);
855
    (void) GetNextToken(q,&q,extent,token);
856
    switch (*keyword)
857
    {
858
      case 'M':
859
      case 'm':
860
      {
861
        if (LocaleCompare((char *) keyword,"maxClockFrequency") == 0)
862
          {
863
            device_benchmark->max_clock_frequency=StringToInteger(token);
864
            break;
865
          }
866
        if (LocaleCompare((char *) keyword,"maxComputeUnits") == 0)
867
          {
868
            device_benchmark->max_compute_units=StringToInteger(token);
869
            break;
870
          }
871
        break;
872
      }
873
      case 'N':
874
      case 'n':
875
      {
876
        if (LocaleCompare((char *) keyword,"name") == 0)
877
          device_benchmark->name=ConstantString(token);
878
        break;
879
      }
880
      case 'P':
881
      case 'p':
882
      {
883
        if (LocaleCompare((char *) keyword,"platform") == 0)
884
          device_benchmark->platform_name=ConstantString(token);
885
        break;
886
      }
887
      case 'S':
888
      case 's':
889
      {
890
        if (LocaleCompare((char *) keyword,"score") == 0)
891
          device_benchmark->score=StringToDouble(token,(char **) NULL);
892
        break;
893
      }
894
      case 'V':
895
      case 'v':
896
      {
897
        if (LocaleCompare((char *) keyword,"vendor") == 0)
898
          device_benchmark->vendor_name=ConstantString(token);
899
        if (LocaleCompare((char *) keyword,"version") == 0)
900
          device_benchmark->version=ConstantString(token);
901
        break;
902
      }
903
      default:
904
        break;
905
    }
906
  }
907
  token=(char *) RelinquishMagickMemory(token);
908
  device_benchmark=RelinquishDeviceBenchmark(device_benchmark);
909
}
910
911
static MagickBooleanType CanWriteProfileToFile(const char *filename)
912
{
913
  FILE
914
    *profileFile;
915
916
  profileFile=fopen_utf8(filename,"ab");
917
918
  if (profileFile == (FILE *) NULL)
919
    {
920
      (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
921
        "Unable to save profile to: \"%s\"",filename);
922
      return(MagickFalse);
923
    }
924
925
  fclose(profileFile);
926
  return(MagickTrue);
927
}
928
#endif
929
930
static MagickBooleanType LoadOpenCLBenchmarks(MagickCLEnv clEnv)
931
{
932
#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
933
  char
934
    filename[MagickPathExtent];
935
936
  StringInfo
937
    *option;
938
939
  (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
940
    GetOpenCLCacheDirectory(),DirectorySeparator,IMAGEMAGICK_PROFILE_FILE);
941
942
  /*
943
    We don't run the benchmark when we can not write out a device profile. The
944
    first GPU device will be used.
945
  */
946
  if (CanWriteProfileToFile(filename) == MagickFalse)
947
#endif
948
    {
949
      size_t
950
        i;
951
952
      for (i = 0; i < clEnv->number_devices; i++)
953
        clEnv->devices[i]->score=1.0;
954
955
      SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
956
      return(MagickFalse);
957
    }
958
#if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
959
  option=ConfigureFileToStringInfo(filename);
960
  LoadOpenCLDeviceBenchmark(clEnv,(const char *) GetStringInfoDatum(option));
961
  option=DestroyStringInfo(option);
962
  return(MagickTrue);
963
#endif
964
}
965
966
static void AutoSelectOpenCLDevices(MagickCLEnv clEnv)
967
{
968
  char
969
    *option;
970
971
  double
972
    best_score;
973
974
  MagickBooleanType
975
    benchmark;
976
977
  size_t
978
    i;
979
980
  option=GetEnvironmentValue("MAGICK_OCL_DEVICE");
981
  if (option != (const char *) NULL)
982
    {
983
      if (strcmp(option,"GPU") == 0)
984
        SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_GPU);
985
      else if (strcmp(option,"CPU") == 0)
986
        SelectOpenCLDevice(clEnv,CL_DEVICE_TYPE_CPU);
987
      option=DestroyString(option);
988
    }
989
990
  if (LoadOpenCLBenchmarks(clEnv) == MagickFalse)
991
    return;
992
993
  benchmark=MagickFalse;
994
  if (clEnv->cpu_score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
995
    benchmark=MagickTrue;
996
  else
997
    {
998
      for (i = 0; i < clEnv->number_devices; i++)
999
      {
1000
        if (clEnv->devices[i]->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1001
        {
1002
          benchmark=MagickTrue;
1003
          break;
1004
        }
1005
      }
1006
    }
1007
1008
  if (benchmark != MagickFalse)
1009
    BenchmarkOpenCLDevices(clEnv);
1010
1011
  best_score=clEnv->cpu_score;
1012
  for (i = 0; i < clEnv->number_devices; i++)
1013
    best_score=MagickMin(clEnv->devices[i]->score,best_score);
1014
1015
  for (i = 0; i < clEnv->number_devices; i++)
1016
  {
1017
    if (clEnv->devices[i]->score != best_score)
1018
      clEnv->devices[i]->enabled=MagickFalse;
1019
  }
1020
}
1021
1022
/*
1023
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1024
%                                                                             %
1025
%                                                                             %
1026
%                                                                             %
1027
%   B e n c h m a r k O p e n C L D e v i c e s                               %
1028
%                                                                             %
1029
%                                                                             %
1030
%                                                                             %
1031
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1032
%
1033
%  BenchmarkOpenCLDevices() benchmarks the OpenCL devices and the CPU to help
1034
%  the automatic selection of the best device.
1035
%
1036
%  The format of the BenchmarkOpenCLDevices method is:
1037
%
1038
%    void BenchmarkOpenCLDevices(MagickCLEnv clEnv,ExceptionInfo *exception)
1039
%
1040
%  A description of each parameter follows:
1041
%
1042
%    o clEnv: the OpenCL environment.
1043
%
1044
%    o exception: return any errors or warnings
1045
*/
1046
1047
static double RunOpenCLBenchmark(MagickBooleanType is_cpu)
1048
{
1049
  AccelerateTimer
1050
    timer;
1051
1052
  ExceptionInfo
1053
    *exception;
1054
1055
  Image
1056
    *inputImage;
1057
1058
  ImageInfo
1059
    *imageInfo;
1060
1061
  size_t
1062
    i;
1063
1064
  exception=AcquireExceptionInfo();
1065
  imageInfo=AcquireImageInfo();
1066
  CloneString(&imageInfo->size,"2048x1536");
1067
  (void) CopyMagickString(imageInfo->filename,"xc:none",MagickPathExtent);
1068
  inputImage=ReadImage(imageInfo,exception);
1069
  if (inputImage == (Image *) NULL)
1070
    return(0.0);
1071
1072
  InitAccelerateTimer(&timer);
1073
1074
  for (i=0; i<=2; i++)
1075
  {
1076
    Image
1077
      *blurredImage,
1078
      *resizedImage,
1079
      *unsharpedImage;
1080
1081
    if (i > 0)
1082
      StartAccelerateTimer(&timer);
1083
1084
    blurredImage=BlurImage(inputImage,10.0f,3.5f,exception);
1085
    unsharpedImage=UnsharpMaskImage(blurredImage,2.0f,2.0f,50.0f,10.0f,
1086
      exception);
1087
    resizedImage=ResizeImage(unsharpedImage,640,480,LanczosFilter,
1088
      exception);
1089
1090
    /*
1091
      We need this to get a proper performance benchmark, the operations
1092
      are executed asynchronous.
1093
    */
1094
    if (is_cpu == MagickFalse)
1095
      {
1096
        CacheInfo
1097
          *cache_info;
1098
1099
        cache_info=(CacheInfo *) resizedImage->cache;
1100
        if (cache_info->opencl != (MagickCLCacheInfo) NULL)
1101
          openCL_library->clWaitForEvents(cache_info->opencl->event_count,
1102
            cache_info->opencl->events);
1103
      }
1104
1105
    if (i > 0)
1106
      StopAccelerateTimer(&timer);
1107
1108
    if (blurredImage != (Image *) NULL)
1109
      DestroyImage(blurredImage);
1110
    if (unsharpedImage != (Image *) NULL)
1111
      DestroyImage(unsharpedImage);
1112
    if (resizedImage != (Image *) NULL)
1113
      DestroyImage(resizedImage);
1114
  }
1115
  DestroyImage(inputImage);
1116
  return(ReadAccelerateTimer(&timer));
1117
}
1118
1119
static void RunDeviceBenchmark(MagickCLEnv clEnv,MagickCLEnv testEnv,
1120
  MagickCLDevice device)
1121
{
1122
  testEnv->devices[0]=device;
1123
  default_CLEnv=testEnv;
1124
  device->score=RunOpenCLBenchmark(MagickFalse);
1125
  default_CLEnv=clEnv;
1126
  testEnv->devices[0]=(MagickCLDevice) NULL;
1127
}
1128
1129
static void CacheOpenCLBenchmarks(MagickCLEnv clEnv)
1130
{
1131
  char
1132
    filename[MagickPathExtent];
1133
1134
  FILE
1135
    *cache_file;
1136
1137
  MagickCLDevice
1138
    device;
1139
1140
  size_t
1141
    i,
1142
    j;
1143
1144
  (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1145
    GetOpenCLCacheDirectory(),DirectorySeparator,
1146
    IMAGEMAGICK_PROFILE_FILE);
1147
1148
  cache_file=fopen_utf8(filename,"wb");
1149
  if (cache_file == (FILE *) NULL)
1150
    return;
1151
  fwrite("<devices>\n",sizeof(char),10,cache_file);
1152
  fprintf(cache_file,"  <device name=\"CPU\" score=\"%.4g\"/>\n",
1153
    clEnv->cpu_score);
1154
  for (i = 0; i < clEnv->number_devices; i++)
1155
  {
1156
    MagickBooleanType
1157
      duplicate;
1158
1159
    device=clEnv->devices[i];
1160
    duplicate=MagickFalse;
1161
    for (j = 0; j < i; j++)
1162
    {
1163
      if (IsSameOpenCLDevice(clEnv->devices[j],device))
1164
      {
1165
        duplicate=MagickTrue;
1166
        break;
1167
      }
1168
    }
1169
1170
    if (duplicate)
1171
      continue;
1172
1173
    if (device->score != MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1174
      fprintf(cache_file,"  <device platform=\"%s\" vendor=\"%s\" name=\"%s\"\
1175
 version=\"%s\" maxClockFrequency=\"%d\" maxComputeUnits=\"%d\"\
1176
 score=\"%.4g\"/>\n",
1177
        device->platform_name,device->vendor_name,device->name,device->version,
1178
        (int)device->max_clock_frequency,(int)device->max_compute_units,
1179
        device->score);
1180
  }
1181
  fwrite("</devices>",sizeof(char),10,cache_file);
1182
1183
  fclose(cache_file);
1184
}
1185
1186
static void BenchmarkOpenCLDevices(MagickCLEnv clEnv)
1187
{
1188
  MagickCLDevice
1189
    device;
1190
1191
  MagickCLEnv
1192
    testEnv;
1193
1194
  size_t
1195
    i,
1196
    j;
1197
1198
  (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1199
    "Starting benchmark");
1200
  testEnv=AcquireMagickCLEnv();
1201
  testEnv->library=openCL_library;
1202
  testEnv->devices=(MagickCLDevice *) AcquireCriticalMemory(
1203
    sizeof(MagickCLDevice));
1204
  testEnv->number_devices=1;
1205
  testEnv->benchmark_thread_id=GetMagickThreadId();
1206
  testEnv->initialized=MagickTrue;
1207
1208
  for (i = 0; i < clEnv->number_devices; i++)
1209
    clEnv->devices[i]->score=MAGICKCORE_OPENCL_UNDEFINED_SCORE;
1210
1211
  for (i = 0; i < clEnv->number_devices; i++)
1212
  {
1213
    device=clEnv->devices[i];
1214
    if (device->score == MAGICKCORE_OPENCL_UNDEFINED_SCORE)
1215
      RunDeviceBenchmark(clEnv,testEnv,device);
1216
1217
    /* Set the score on all the other devices that are the same */
1218
    for (j = i+1; j < clEnv->number_devices; j++)
1219
    {
1220
      MagickCLDevice
1221
        other_device;
1222
1223
      other_device=clEnv->devices[j];
1224
      if (IsSameOpenCLDevice(device,other_device))
1225
        other_device->score=device->score;
1226
    }
1227
  }
1228
1229
  testEnv->enabled=MagickFalse;
1230
  default_CLEnv=testEnv;
1231
  clEnv->cpu_score=RunOpenCLBenchmark(MagickTrue);
1232
  default_CLEnv=clEnv;
1233
1234
  testEnv=RelinquishMagickCLEnv(testEnv);
1235
  CacheOpenCLBenchmarks(clEnv);
1236
}
1237
1238
/*
1239
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1240
%                                                                             %
1241
%                                                                             %
1242
%                                                                             %
1243
%   C o m p i l e O p e n C L K e r n e l                                     %
1244
%                                                                             %
1245
%                                                                             %
1246
%                                                                             %
1247
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1248
%
1249
%  CompileOpenCLKernel() compiles the kernel for the specified device. The
1250
%  kernel will be cached on disk to reduce the compilation time.
1251
%
1252
%  The format of the CompileOpenCLKernel method is:
1253
%
1254
%      MagickBooleanType AcquireOpenCLKernel(MagickCLDevice clEnv,
1255
%        unsigned int signature,const char *kernel,const char *options,
1256
%        ExceptionInfo *exception)
1257
%
1258
%  A description of each parameter follows:
1259
%
1260
%    o device: the OpenCL device.
1261
%
1262
%    o kernel: the source code of the kernel.
1263
%
1264
%    o options: options for the compiler.
1265
%
1266
%    o signature: a number to uniquely identify the kernel
1267
%
1268
%    o exception: return any errors or warnings in this structure.
1269
%
1270
*/
1271
1272
static void CacheOpenCLKernel(MagickCLDevice device,char *filename,
1273
  ExceptionInfo *exception)
1274
{
1275
  cl_uint
1276
    status;
1277
1278
  size_t
1279
    binaryProgramSize;
1280
1281
  unsigned char
1282
    *binaryProgram;
1283
1284
  status=openCL_library->clGetProgramInfo(device->program,
1285
    CL_PROGRAM_BINARY_SIZES,sizeof(size_t),&binaryProgramSize,NULL);
1286
  if (status != CL_SUCCESS)
1287
    return;
1288
  binaryProgram=(unsigned char*) AcquireQuantumMemory(1,binaryProgramSize);
1289
  if (binaryProgram == (unsigned char *) NULL)
1290
    {
1291
      (void) ThrowMagickException(exception,GetMagickModule(),
1292
        ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1293
      return;
1294
    }
1295
  status=openCL_library->clGetProgramInfo(device->program,
1296
    CL_PROGRAM_BINARIES,sizeof(unsigned char*),&binaryProgram,NULL);
1297
  if (status == CL_SUCCESS)
1298
    {
1299
      (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1300
        "Creating cache file: \"%s\"",filename);
1301
      (void) BlobToFile(filename,binaryProgram,binaryProgramSize,exception);
1302
    }
1303
  binaryProgram=(unsigned char *) RelinquishMagickMemory(binaryProgram);
1304
}
1305
1306
static MagickBooleanType LoadCachedOpenCLKernels(MagickCLDevice device,
1307
  const char *filename)
1308
{
1309
  cl_int
1310
    binaryStatus,
1311
    status;
1312
1313
  ExceptionInfo
1314
    *sans_exception;
1315
1316
  size_t
1317
    length;
1318
1319
  unsigned char
1320
    *binaryProgram;
1321
1322
  sans_exception=AcquireExceptionInfo();
1323
  binaryProgram=(unsigned char *) FileToBlob(filename,SIZE_MAX,&length,
1324
    sans_exception);
1325
  sans_exception=DestroyExceptionInfo(sans_exception);
1326
  if (binaryProgram == (unsigned char *) NULL)
1327
    return(MagickFalse);
1328
  (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
1329
    "Loaded cached kernels: \"%s\"",filename);
1330
  device->program=openCL_library->clCreateProgramWithBinary(device->context,1,
1331
    &device->deviceID,&length,(const unsigned char**)&binaryProgram,
1332
    &binaryStatus,&status);
1333
  binaryProgram=(unsigned char *) RelinquishMagickMemory(binaryProgram);
1334
  return((status != CL_SUCCESS) || (binaryStatus != CL_SUCCESS) ? MagickFalse :
1335
    MagickTrue);
1336
}
1337
1338
static void LogOpenCLBuildFailure(MagickCLDevice device,const char *kernel,
1339
  ExceptionInfo *exception)
1340
{
1341
  char
1342
    filename[MagickPathExtent],
1343
    *log;
1344
1345
  size_t
1346
    log_size;
1347
1348
  (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1349
    GetOpenCLCacheDirectory(),DirectorySeparator,"magick_badcl.cl");
1350
1351
  (void) remove_utf8(filename);
1352
  (void) BlobToFile(filename,kernel,strlen(kernel),exception);
1353
1354
  openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1355
    CL_PROGRAM_BUILD_LOG,0,NULL,&log_size);
1356
  log=(char*)AcquireCriticalMemory(log_size);
1357
  openCL_library->clGetProgramBuildInfo(device->program,device->deviceID,
1358
    CL_PROGRAM_BUILD_LOG,log_size,log,&log_size);
1359
1360
  (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1361
    GetOpenCLCacheDirectory(),DirectorySeparator,"magick_badcl.log");
1362
1363
  (void) remove_utf8(filename);
1364
  (void) BlobToFile(filename,log,log_size,exception);
1365
  log=(char*)RelinquishMagickMemory(log);
1366
}
1367
1368
static MagickBooleanType CompileOpenCLKernel(MagickCLDevice device,
1369
  const char *kernel,const char *options,size_t signature,
1370
  ExceptionInfo *exception)
1371
{
1372
  char
1373
    deviceName[MagickPathExtent],
1374
    filename[MagickPathExtent],
1375
    *ptr;
1376
1377
  cl_int
1378
    status;
1379
1380
  MagickBooleanType
1381
    loaded;
1382
1383
  size_t
1384
    length;
1385
1386
  (void) CopyMagickString(deviceName,device->name,MagickPathExtent);
1387
  ptr=deviceName;
1388
  /* Strip out illegal characters for file names */
1389
  while (*ptr != '\0')
1390
  {
1391
    if ((*ptr == ' ') || (*ptr == '\\') || (*ptr == '/') || (*ptr == ':') ||
1392
        (*ptr == '*') || (*ptr == '?') || (*ptr == '"') || (*ptr == '<') ||
1393
        (*ptr == '>' || *ptr == '|'))
1394
      *ptr = '_';
1395
    ptr++;
1396
  }
1397
  (void) FormatLocaleString(filename,MagickPathExtent,
1398
    "%s%s%s_%s_%08x_%.17g.bin",GetOpenCLCacheDirectory(),
1399
    DirectorySeparator,"magick_opencl",deviceName,(unsigned int) signature,
1400
    (double) sizeof(char*)*8);
1401
  loaded=LoadCachedOpenCLKernels(device,filename);
1402
  if (loaded == MagickFalse)
1403
    {
1404
      /* Binary CL program unavailable, compile the program from source */
1405
      length=strlen(kernel);
1406
      device->program=openCL_library->clCreateProgramWithSource(
1407
        device->context,1,&kernel,&length,&status);
1408
      if (status != CL_SUCCESS)
1409
        return(MagickFalse);
1410
    }
1411
1412
  status=openCL_library->clBuildProgram(device->program,1,&device->deviceID,
1413
    options,NULL,NULL);
1414
  if (status != CL_SUCCESS)
1415
  {
1416
    (void) ThrowMagickException(exception,GetMagickModule(),DelegateWarning,
1417
      "clBuildProgram failed.","(%d)",(int)status);
1418
    LogOpenCLBuildFailure(device,kernel,exception);
1419
    return(MagickFalse);
1420
  }
1421
1422
  /* Save the binary to a file to avoid re-compilation of the kernels */
1423
  if (loaded == MagickFalse)
1424
    CacheOpenCLKernel(device,filename,exception);
1425
1426
  return(MagickTrue);
1427
}
1428
1429
static cl_event* CopyOpenCLEvents(MagickCLCacheInfo first,
1430
  MagickCLCacheInfo second,cl_uint *event_count)
1431
{
1432
  cl_event
1433
    *events;
1434
1435
  size_t
1436
    i;
1437
1438
  size_t
1439
    j;
1440
1441
  assert(first != (MagickCLCacheInfo) NULL);
1442
  assert(event_count != (cl_uint *) NULL);
1443
  events=(cl_event *) NULL;
1444
  LockSemaphoreInfo(first->events_semaphore);
1445
  if (second != (MagickCLCacheInfo) NULL)
1446
    LockSemaphoreInfo(second->events_semaphore);
1447
  *event_count=first->event_count;
1448
  if (second != (MagickCLCacheInfo) NULL)
1449
    *event_count+=second->event_count;
1450
  if (*event_count > 0)
1451
    {
1452
      events=(cl_event *) AcquireQuantumMemory(*event_count,sizeof(*events));
1453
      if (events == (cl_event *) NULL)
1454
        *event_count=0;
1455
      else
1456
        {
1457
          j=0;
1458
          for (i=0; i < first->event_count; i++, j++)
1459
            events[j]=first->events[i];
1460
          if (second != (MagickCLCacheInfo) NULL)
1461
            {
1462
              for (i=0; i < second->event_count; i++, j++)
1463
                events[j]=second->events[i];
1464
            }
1465
        }
1466
    }
1467
  UnlockSemaphoreInfo(first->events_semaphore);
1468
  if (second != (MagickCLCacheInfo) NULL)
1469
    UnlockSemaphoreInfo(second->events_semaphore);
1470
  return(events);
1471
}
1472
1473
/*
1474
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1475
%                                                                             %
1476
%                                                                             %
1477
%                                                                             %
1478
+   C o p y M a g i c k C L C a c h e I n f o                                 %
1479
%                                                                             %
1480
%                                                                             %
1481
%                                                                             %
1482
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483
%
1484
%  CopyMagickCLCacheInfo() copies the memory from the device into host memory.
1485
%
1486
%  The format of the CopyMagickCLCacheInfo method is:
1487
%
1488
%      void CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1489
%
1490
%  A description of each parameter follows:
1491
%
1492
%    o info: the OpenCL cache info.
1493
%
1494
*/
1495
MagickPrivate MagickCLCacheInfo CopyMagickCLCacheInfo(MagickCLCacheInfo info)
1496
{
1497
  cl_command_queue
1498
    queue;
1499
1500
  cl_event
1501
    *events;
1502
1503
  cl_uint
1504
    event_count;
1505
1506
  Quantum
1507
    *pixels;
1508
1509
  if (info == (MagickCLCacheInfo) NULL)
1510
    return((MagickCLCacheInfo) NULL);
1511
  events=CopyOpenCLEvents(info,(MagickCLCacheInfo) NULL,&event_count);
1512
  if (events != (cl_event *) NULL)
1513
    {
1514
      queue=AcquireOpenCLCommandQueue(info->device);
1515
      pixels=(Quantum *) openCL_library->clEnqueueMapBuffer(queue,info->buffer,
1516
        CL_TRUE,CL_MAP_READ | CL_MAP_WRITE,0,(size_t) info->length,event_count,
1517
        events,
1518
        (cl_event *) NULL,(cl_int *) NULL);
1519
      assert(pixels == info->pixels);
1520
      ReleaseOpenCLCommandQueue(info->device,queue);
1521
      events=(cl_event *) RelinquishMagickMemory(events);
1522
    }
1523
  return(RelinquishMagickCLCacheInfo(info,MagickFalse));
1524
}
1525
1526
/*
1527
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1528
%                                                                             %
1529
%                                                                             %
1530
%                                                                             %
1531
+   D u m p O p e n C L P r o f i l e D a t a                                 %
1532
%                                                                             %
1533
%                                                                             %
1534
%                                                                             %
1535
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536
%
1537
%  DumpOpenCLProfileData() dumps the kernel profile data.
1538
%
1539
%  The format of the DumpProfileData method is:
1540
%
1541
%      void DumpProfileData()
1542
%
1543
*/
1544
1545
MagickPrivate void DumpOpenCLProfileData()
1546
{
1547
#define OpenCLLog(message) \
1548
   fwrite(message,sizeof(char),strlen(message),log); \
1549
   fwrite("\n",sizeof(char),1,log);
1550
1551
  char
1552
    buf[4096],
1553
    filename[MagickPathExtent],
1554
    indent[160];
1555
1556
  FILE
1557
    *log;
1558
1559
  size_t
1560
    i,
1561
    j;
1562
1563
  if (default_CLEnv == (MagickCLEnv) NULL)
1564
    return;
1565
1566
  for (i = 0; i < default_CLEnv->number_devices; i++)
1567
    if (default_CLEnv->devices[i]->profile_kernels != MagickFalse)
1568
      break;
1569
  if (i == default_CLEnv->number_devices)
1570
    return;
1571
1572
  (void) FormatLocaleString(filename,MagickPathExtent,"%s%s%s",
1573
    GetOpenCLCacheDirectory(),DirectorySeparator,"ImageMagickOpenCL.log");
1574
1575
  log=fopen_utf8(filename,"wb");
1576
  if (log == (FILE *) NULL)
1577
    return;
1578
  for (i = 0; i < default_CLEnv->number_devices; i++)
1579
  {
1580
    MagickCLDevice
1581
      device;
1582
1583
    device=default_CLEnv->devices[i];
1584
    if ((device->profile_kernels == MagickFalse) ||
1585
        (device->profile_records == (KernelProfileRecord *) NULL))
1586
      continue;
1587
1588
    OpenCLLog("====================================================");
1589
    fprintf(log,"Device:  %s\n",device->name);
1590
    fprintf(log,"Version: %s\n",device->version);
1591
    OpenCLLog("====================================================");
1592
    OpenCLLog("                     average   calls     min     max");
1593
    OpenCLLog("                     -------   -----     ---     ---");
1594
    j=0;
1595
    while (device->profile_records[j] != (KernelProfileRecord) NULL)
1596
    {
1597
      KernelProfileRecord
1598
        profile;
1599
1600
      profile=device->profile_records[j];
1601
      (void) CopyMagickString(indent,"                              ",
1602
        sizeof(indent));
1603
      (void) CopyMagickString(indent,profile->kernel_name,MagickMin(strlen(
1604
        profile->kernel_name),strlen(indent)));
1605
      (void) FormatLocaleString(buf,sizeof(buf),"%s %7d %7d %7d %7d",indent,
1606
        (int) (profile->total/profile->count),(int) profile->count,
1607
        (int) profile->min,(int) profile->max);
1608
      OpenCLLog(buf);
1609
      j++;
1610
    }
1611
    OpenCLLog("====================================================");
1612
    fwrite("\n\n",sizeof(char),2,log);
1613
  }
1614
  fclose(log);
1615
}
1616
/*
1617
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1618
%                                                                             %
1619
%                                                                             %
1620
%                                                                             %
1621
+   E n q u e u e O p e n C L K e r n e l                                     %
1622
%                                                                             %
1623
%                                                                             %
1624
%                                                                             %
1625
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626
%
1627
%  EnqueueOpenCLKernel() enques the specified kernel and registers the OpenCL
1628
%  events with the images.
1629
%
1630
%  The format of the EnqueueOpenCLKernel method is:
1631
%
1632
%      MagickBooleanType EnqueueOpenCLKernel(cl_kernel kernel,cl_uint work_dim,
1633
%        const size_t *global_work_offset,const size_t *global_work_size,
1634
%        const size_t *local_work_size,const Image *input_image,
1635
%        const Image *output_image,ExceptionInfo *exception)
1636
%
1637
%  A description of each parameter follows:
1638
%
1639
%    o kernel: the OpenCL kernel.
1640
%
1641
%    o work_dim: the number of dimensions used to specify the global work-items
1642
%                and work-items in the work-group.
1643
%
1644
%    o offset: can be used to specify an array of work_dim unsigned values
1645
%              that describe the offset used to calculate the global ID of a
1646
%              work-item.
1647
%
1648
%    o gsize: points to an array of work_dim unsigned values that describe the
1649
%             number of global work-items in work_dim dimensions that will
1650
%             execute the kernel function.
1651
%
1652
%    o lsize: points to an array of work_dim unsigned values that describe the
1653
%             number of work-items that make up a work-group that will execute
1654
%             the kernel specified by kernel.
1655
%
1656
%    o input_image: the input image of the operation.
1657
%
1658
%    o output_image: the output or secondary image of the operation.
1659
%
1660
%    o exception: return any errors or warnings in this structure.
1661
%
1662
*/
1663
1664
static MagickBooleanType RegisterCacheEvent(MagickCLCacheInfo info,
1665
  cl_event event)
1666
{
1667
  assert(info != (MagickCLCacheInfo) NULL);
1668
  assert(event != (cl_event) NULL);
1669
  if (openCL_library->clRetainEvent(event) != CL_SUCCESS)
1670
    {
1671
      openCL_library->clWaitForEvents(1,&event);
1672
      return(MagickFalse);
1673
    }
1674
  LockSemaphoreInfo(info->events_semaphore);
1675
  if (info->events == (cl_event *) NULL)
1676
    {
1677
      info->events=(cl_event *) AcquireMagickMemory(sizeof(*info->events));
1678
      info->event_count=1;
1679
    }
1680
  else
1681
    info->events=(cl_event *) ResizeQuantumMemory(info->events,
1682
      ++info->event_count,sizeof(*info->events));
1683
  if (info->events == (cl_event *) NULL)
1684
    {
1685
      UnlockSemaphoreInfo(info->events_semaphore);
1686
      return(MagickFalse);
1687
    }
1688
  info->events[info->event_count-1]=event;
1689
  UnlockSemaphoreInfo(info->events_semaphore);
1690
  return(MagickTrue);
1691
}
1692
1693
MagickPrivate MagickBooleanType EnqueueOpenCLKernel(cl_command_queue queue,
1694
  cl_kernel kernel,cl_uint work_dim,const size_t *offset,const size_t *gsize,
1695
  const size_t *lsize,const Image *input_image,const Image *output_image,
1696
  MagickBooleanType flush,ExceptionInfo *exception)
1697
{
1698
  CacheInfo
1699
    *output_info,
1700
    *input_info;
1701
1702
  cl_event
1703
    event,
1704
    *events;
1705
1706
  cl_int
1707
    status;
1708
1709
  cl_uint
1710
    event_count;
1711
1712
  assert(input_image != (const Image *) NULL);
1713
  input_info=(CacheInfo *) input_image->cache;
1714
  assert(input_info != (CacheInfo *) NULL);
1715
  assert(input_info->opencl != (MagickCLCacheInfo) NULL);
1716
  output_info=(CacheInfo *) NULL;
1717
  if (output_image == (const Image *) NULL)
1718
    events=CopyOpenCLEvents(input_info->opencl,(MagickCLCacheInfo) NULL,
1719
      &event_count);
1720
  else
1721
    {
1722
      output_info=(CacheInfo *) output_image->cache;
1723
      assert(output_info != (CacheInfo *) NULL);
1724
      assert(output_info->opencl != (MagickCLCacheInfo) NULL);
1725
      events=CopyOpenCLEvents(input_info->opencl,output_info->opencl,
1726
        &event_count);
1727
    }
1728
  status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,offset,
1729
    gsize,lsize,event_count,events,&event);
1730
  /* This can fail due to memory issues and calling clFinish might help. */
1731
  if ((status != CL_SUCCESS) && (event_count > 0))
1732
    {
1733
      openCL_library->clFinish(queue);
1734
      status=openCL_library->clEnqueueNDRangeKernel(queue,kernel,work_dim,
1735
        offset,gsize,lsize,event_count,events,&event);
1736
    }
1737
  events=(cl_event *) RelinquishMagickMemory(events);
1738
  if (status != CL_SUCCESS)
1739
    {
1740
      (void) OpenCLThrowMagickException(input_info->opencl->device,exception,
1741
        GetMagickModule(),ResourceLimitWarning,
1742
        "clEnqueueNDRangeKernel failed.","'%s'",".");
1743
      return(MagickFalse);
1744
    }
1745
  if (flush != MagickFalse)
1746
    openCL_library->clFlush(queue);
1747
  if (RecordProfileData(input_info->opencl->device,kernel,event) == MagickFalse)
1748
    {
1749
      if (RegisterCacheEvent(input_info->opencl,event) != MagickFalse)
1750
        {
1751
          if (output_info != (CacheInfo *) NULL)
1752
            (void) RegisterCacheEvent(output_info->opencl,event);
1753
        }
1754
    }
1755
  openCL_library->clReleaseEvent(event);
1756
  return(MagickTrue);
1757
}
1758
1759
/*
1760
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1761
%                                                                             %
1762
%                                                                             %
1763
%                                                                             %
1764
+   G e t C u r r e n t O p e n C L E n v                                     %
1765
%                                                                             %
1766
%                                                                             %
1767
%                                                                             %
1768
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1769
%
1770
%  GetCurrentOpenCLEnv() returns the current OpenCL env
1771
%
1772
%  The format of the GetCurrentOpenCLEnv method is:
1773
%
1774
%      MagickCLEnv GetCurrentOpenCLEnv()
1775
%
1776
*/
1777
1778
MagickPrivate MagickCLEnv GetCurrentOpenCLEnv(void)
1779
{
1780
  if (default_CLEnv != (MagickCLEnv) NULL)
1781
  {
1782
    if ((default_CLEnv->benchmark_thread_id != (MagickThreadType) 0) &&
1783
        (default_CLEnv->benchmark_thread_id != GetMagickThreadId()))
1784
      return((MagickCLEnv) NULL);
1785
    else
1786
      return(default_CLEnv);
1787
  }
1788
1789
  if (GetOpenCLCacheDirectory() == (char *) NULL)
1790
    return((MagickCLEnv) NULL);
1791
1792
  if (openCL_lock == (SemaphoreInfo *) NULL)
1793
    ActivateSemaphoreInfo(&openCL_lock);
1794
1795
  LockSemaphoreInfo(openCL_lock);
1796
  if (default_CLEnv == (MagickCLEnv) NULL)
1797
    default_CLEnv=AcquireMagickCLEnv();
1798
  UnlockSemaphoreInfo(openCL_lock);
1799
1800
  return(default_CLEnv);
1801
}
1802
1803
/*
1804
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1805
%                                                                             %
1806
%                                                                             %
1807
%                                                                             %
1808
%   G e t O p e n C L D e v i c e B e n c h m a r k D u r a t i o n           %
1809
%                                                                             %
1810
%                                                                             %
1811
%                                                                             %
1812
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1813
%
1814
%  GetOpenCLDeviceBenchmarkScore() returns the score of the benchmark for the
1815
%  device. The score is determined by the duration of the micro benchmark so
1816
%  that means a lower score is better than a higher score.
1817
%
1818
%  The format of the GetOpenCLDeviceBenchmarkScore method is:
1819
%
1820
%      double GetOpenCLDeviceBenchmarkScore(const MagickCLDevice device)
1821
%
1822
%  A description of each parameter follows:
1823
%
1824
%    o device: the OpenCL device.
1825
*/
1826
1827
MagickExport double GetOpenCLDeviceBenchmarkScore(
1828
  const MagickCLDevice device)
1829
{
1830
  if (device == (MagickCLDevice) NULL)
1831
    return(MAGICKCORE_OPENCL_UNDEFINED_SCORE);
1832
  return(device->score);
1833
}
1834
1835
/*
1836
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837
%                                                                             %
1838
%                                                                             %
1839
%                                                                             %
1840
%   G e t O p e n C L D e v i c e E n a b l e d                               %
1841
%                                                                             %
1842
%                                                                             %
1843
%                                                                             %
1844
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1845
%
1846
%  GetOpenCLDeviceEnabled() returns true if the device is enabled.
1847
%
1848
%  The format of the GetOpenCLDeviceEnabled method is:
1849
%
1850
%      MagickBooleanType GetOpenCLDeviceEnabled(const MagickCLDevice device)
1851
%
1852
%  A description of each parameter follows:
1853
%
1854
%    o device: the OpenCL device.
1855
*/
1856
1857
MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
1858
  const MagickCLDevice device)
1859
{
1860
  if (device == (MagickCLDevice) NULL)
1861
    return(MagickFalse);
1862
  return(device->enabled);
1863
}
1864
1865
/*
1866
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1867
%                                                                             %
1868
%                                                                             %
1869
%                                                                             %
1870
%   G e t O p e n C L D e v i c e N a m e                                     %
1871
%                                                                             %
1872
%                                                                             %
1873
%                                                                             %
1874
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1875
%
1876
%  GetOpenCLDeviceName() returns the name of the device.
1877
%
1878
%  The format of the GetOpenCLDeviceName method is:
1879
%
1880
%      const char *GetOpenCLDeviceName(const MagickCLDevice device)
1881
%
1882
%  A description of each parameter follows:
1883
%
1884
%    o device: the OpenCL device.
1885
*/
1886
1887
MagickExport const char *GetOpenCLDeviceName(const MagickCLDevice device)
1888
{
1889
  if (device == (MagickCLDevice) NULL)
1890
    return((const char *) NULL);
1891
  return(device->name);
1892
}
1893
1894
/*
1895
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1896
%                                                                             %
1897
%                                                                             %
1898
%                                                                             %
1899
%   G e t O p e n C L D e v i c e V e n d o r N a m e                         %
1900
%                                                                             %
1901
%                                                                             %
1902
%                                                                             %
1903
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904
%
1905
%  GetOpenCLDeviceVendorName() returns the vendor name of the device.
1906
%
1907
%  The format of the GetOpenCLDeviceVendorName method is:
1908
%
1909
%      const char *GetOpenCLDeviceVendorName(const MagickCLDevice device)
1910
%
1911
%  A description of each parameter follows:
1912
%
1913
%    o device: the OpenCL device.
1914
*/
1915
1916
MagickExport const char *GetOpenCLDeviceVendorName(const MagickCLDevice device)
1917
{
1918
  if (device == (MagickCLDevice) NULL)
1919
    return((const char *) NULL);
1920
  return(device->vendor_name);
1921
}
1922
1923
/*
1924
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1925
%                                                                             %
1926
%                                                                             %
1927
%                                                                             %
1928
%   G e t O p e n C L D e v i c e s                                           %
1929
%                                                                             %
1930
%                                                                             %
1931
%                                                                             %
1932
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1933
%
1934
%  GetOpenCLDevices() returns the devices of the OpenCL environment at sets the
1935
%  value of length to the number of devices that are available.
1936
%
1937
%  The format of the GetOpenCLDevices method is:
1938
%
1939
%      const MagickCLDevice *GetOpenCLDevices(size_t *length,
1940
%        ExceptionInfo *exception)
1941
%
1942
%  A description of each parameter follows:
1943
%
1944
%    o length: the number of device.
1945
%
1946
%    o exception: return any errors or warnings in this structure.
1947
%
1948
*/
1949
1950
MagickExport MagickCLDevice *GetOpenCLDevices(size_t *length,
1951
  ExceptionInfo *exception)
1952
{
1953
  MagickCLEnv
1954
    clEnv;
1955
1956
  clEnv=GetCurrentOpenCLEnv();
1957
  if (clEnv == (MagickCLEnv) NULL)
1958
    {
1959
      if (length != (size_t *) NULL)
1960
        *length=0;
1961
      return((MagickCLDevice *) NULL);
1962
    }
1963
  InitializeOpenCL(clEnv,exception);
1964
  if (length != (size_t *) NULL)
1965
    *length=clEnv->number_devices;
1966
  return(clEnv->devices);
1967
}
1968
1969
/*
1970
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1971
%                                                                             %
1972
%                                                                             %
1973
%                                                                             %
1974
%   G e t O p e n C L D e v i c e T y p e                                     %
1975
%                                                                             %
1976
%                                                                             %
1977
%                                                                             %
1978
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1979
%
1980
%  GetOpenCLDeviceType() returns the type of the device.
1981
%
1982
%  The format of the GetOpenCLDeviceType method is:
1983
%
1984
%      MagickCLDeviceType GetOpenCLDeviceType(const MagickCLDevice device)
1985
%
1986
%  A description of each parameter follows:
1987
%
1988
%    o device: the OpenCL device.
1989
*/
1990
1991
MagickExport MagickCLDeviceType GetOpenCLDeviceType(
1992
  const MagickCLDevice device)
1993
{
1994
  if (device == (MagickCLDevice) NULL)
1995
    return(UndefinedCLDeviceType);
1996
  if (device->type == CL_DEVICE_TYPE_GPU)
1997
    return(GpuCLDeviceType);
1998
  if (device->type == CL_DEVICE_TYPE_CPU)
1999
    return(CpuCLDeviceType);
2000
  return(UndefinedCLDeviceType);
2001
}
2002
2003
/*
2004
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005
%                                                                             %
2006
%                                                                             %
2007
%                                                                             %
2008
%   G e t O p e n C L D e v i c e V e r s i o n                               %
2009
%                                                                             %
2010
%                                                                             %
2011
%                                                                             %
2012
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2013
%
2014
%  GetOpenCLDeviceVersion() returns the version of the device.
2015
%
2016
%  The format of the GetOpenCLDeviceName method is:
2017
%
2018
%      const char *GetOpenCLDeviceVersion(MagickCLDevice device)
2019
%
2020
%  A description of each parameter follows:
2021
%
2022
%    o device: the OpenCL device.
2023
*/
2024
2025
MagickExport const char *GetOpenCLDeviceVersion(const MagickCLDevice device)
2026
{
2027
  if (device == (MagickCLDevice) NULL)
2028
    return((const char *) NULL);
2029
  return(device->version);
2030
}
2031
2032
/*
2033
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2034
%                                                                             %
2035
%                                                                             %
2036
%                                                                             %
2037
%   G e t O p e n C L E n a b l e d                                           %
2038
%                                                                             %
2039
%                                                                             %
2040
%                                                                             %
2041
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2042
%
2043
%  GetOpenCLEnabled() returns true if OpenCL acceleration is enabled.
2044
%
2045
%  The format of the GetOpenCLEnabled method is:
2046
%
2047
%      MagickBooleanType GetOpenCLEnabled()
2048
%
2049
*/
2050
2051
MagickExport MagickBooleanType GetOpenCLEnabled(void)
2052
{
2053
  MagickCLEnv
2054
    clEnv;
2055
2056
  clEnv=GetCurrentOpenCLEnv();
2057
  if (clEnv == (MagickCLEnv) NULL)
2058
    return(MagickFalse);
2059
  return(clEnv->enabled);
2060
}
2061
2062
/*
2063
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2064
%                                                                             %
2065
%                                                                             %
2066
%                                                                             %
2067
%   G e t O p e n C L K e r n e l P r o f i l e R e c o r d s                 %
2068
%                                                                             %
2069
%                                                                             %
2070
%                                                                             %
2071
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2072
%
2073
%  GetOpenCLKernelProfileRecords() returns the profile records for the
2074
%  specified device and sets length to the number of profile records.
2075
%
2076
%  The format of the GetOpenCLKernelProfileRecords method is:
2077
%
2078
%      const KernelProfileRecord *GetOpenCLKernelProfileRecords(size *length)
2079
%
2080
%  A description of each parameter follows:
2081
%
2082
%    o length: the number of profiles records.
2083
*/
2084
2085
MagickExport const KernelProfileRecord *GetOpenCLKernelProfileRecords(
2086
  const MagickCLDevice device,size_t *length)
2087
{
2088
  if ((device == (const MagickCLDevice) NULL) || (device->profile_records ==
2089
      (KernelProfileRecord *) NULL))
2090
  {
2091
    if (length != (size_t *) NULL)
2092
      *length=0;
2093
    return((const KernelProfileRecord *) NULL);
2094
  }
2095
  if (length != (size_t *) NULL)
2096
    {
2097
      *length=0;
2098
      LockSemaphoreInfo(device->lock);
2099
      while (device->profile_records[*length] != (KernelProfileRecord) NULL)
2100
        *length=*length+1;
2101
      UnlockSemaphoreInfo(device->lock);
2102
    }
2103
  return(device->profile_records);
2104
}
2105
2106
/*
2107
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2108
%                                                                             %
2109
%                                                                             %
2110
%                                                                             %
2111
%   H a s O p e n C L D e v i c e s                                           %
2112
%                                                                             %
2113
%                                                                             %
2114
%                                                                             %
2115
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2116
%
2117
%  HasOpenCLDevices() checks if the OpenCL environment has devices that are
2118
%  enabled and compiles the kernel for the device when necessary. False will be
2119
%  returned if no enabled devices could be found
2120
%
2121
%  The format of the HasOpenCLDevices method is:
2122
%
2123
%    MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2124
%      ExceptionInfo exception)
2125
%
2126
%  A description of each parameter follows:
2127
%
2128
%    o clEnv: the OpenCL environment.
2129
%
2130
%    o exception: return any errors or warnings in this structure.
2131
%
2132
*/
2133
2134
static MagickBooleanType HasOpenCLDevices(MagickCLEnv clEnv,
2135
  ExceptionInfo *exception)
2136
{
2137
  char
2138
    *accelerateKernelsBuffer,
2139
    options[MagickPathExtent];
2140
2141
  MagickBooleanType
2142
    status;
2143
2144
  size_t
2145
    i;
2146
2147
  size_t
2148
    signature;
2149
2150
  /* Check if there are enabled devices */
2151
  for (i = 0; i < clEnv->number_devices; i++)
2152
  {
2153
    if ((clEnv->devices[i]->enabled != MagickFalse))
2154
      break;
2155
  }
2156
  if (i == clEnv->number_devices)
2157
    return(MagickFalse);
2158
2159
  /* Check if we need to compile a kernel for one of the devices */
2160
  status=MagickTrue;
2161
  for (i = 0; i < clEnv->number_devices; i++)
2162
  {
2163
    if ((clEnv->devices[i]->enabled != MagickFalse) &&
2164
        (clEnv->devices[i]->program == (cl_program) NULL))
2165
    {
2166
      status=MagickFalse;
2167
      break;
2168
    }
2169
  }
2170
  if (status != MagickFalse)
2171
    return(MagickTrue);
2172
2173
  /* Get additional options */
2174
  (void) FormatLocaleString(options,MagickPathExtent,CLOptions,
2175
    (float)QuantumRange,(float)CLCharQuantumScale,(float)MagickEpsilon,
2176
    (float)MagickPI,(unsigned int)MaxMap,(unsigned int)MAGICKCORE_QUANTUM_DEPTH);
2177
2178
  signature=StringSignature(options);
2179
  accelerateKernelsBuffer=(char*) AcquireQuantumMemory(1,
2180
    strlen(accelerateKernels)+strlen(accelerateKernels2)+1);
2181
  if (accelerateKernelsBuffer == (char*) NULL)
2182
    return(MagickFalse);
2183
  (void) FormatLocaleString(accelerateKernelsBuffer,strlen(accelerateKernels)+
2184
    strlen(accelerateKernels2)+1,"%s%s",accelerateKernels,accelerateKernels2);
2185
  signature^=StringSignature(accelerateKernelsBuffer);
2186
2187
  status=MagickTrue;
2188
  for (i = 0; i < clEnv->number_devices; i++)
2189
  {
2190
    MagickCLDevice
2191
      device;
2192
2193
    size_t
2194
      device_signature;
2195
2196
    device=clEnv->devices[i];
2197
    if ((device->enabled == MagickFalse) ||
2198
        (device->program != (cl_program) NULL))
2199
      continue;
2200
2201
    LockSemaphoreInfo(device->lock);
2202
    if (device->program != (cl_program) NULL)
2203
    {
2204
      UnlockSemaphoreInfo(device->lock);
2205
      continue;
2206
    }
2207
    device_signature=signature;
2208
    device_signature^=StringSignature(device->platform_name);
2209
    status=CompileOpenCLKernel(device,accelerateKernelsBuffer,options,
2210
      device_signature,exception);
2211
    UnlockSemaphoreInfo(device->lock);
2212
    if (status == MagickFalse)
2213
      break;
2214
  }
2215
  accelerateKernelsBuffer=(char *) RelinquishMagickMemory(
2216
    accelerateKernelsBuffer);
2217
  return(status);
2218
}
2219
2220
/*
2221
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2222
%                                                                             %
2223
%                                                                             %
2224
%                                                                             %
2225
+   I n i t i a l i z e O p e n C L                                           %
2226
%                                                                             %
2227
%                                                                             %
2228
%                                                                             %
2229
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2230
%
2231
%  InitializeOpenCL() is used to initialize the OpenCL environment. This method
2232
%  makes sure the devices are properly initialized and benchmarked.
2233
%
2234
%  The format of the InitializeOpenCL method is:
2235
%
2236
%    MagickBooleanType InitializeOpenCL(ExceptionInfo exception)
2237
%
2238
%  A description of each parameter follows:
2239
%
2240
%    o exception: return any errors or warnings in this structure.
2241
%
2242
*/
2243
2244
static cl_uint GetOpenCLDeviceCount(MagickCLEnv clEnv,cl_platform_id platform)
2245
{
2246
  char
2247
    version[MagickPathExtent];
2248
2249
  cl_uint
2250
    num;
2251
2252
  if (clEnv->library->clGetPlatformInfo(platform,CL_PLATFORM_VERSION,
2253
        MagickPathExtent,version,NULL) != CL_SUCCESS)
2254
    return(0);
2255
  if (strncmp(version,"OpenCL 1.0 ",11) == 0)
2256
    return(0);
2257
  if (clEnv->library->clGetDeviceIDs(platform,
2258
        CL_DEVICE_TYPE_CPU|CL_DEVICE_TYPE_GPU,0,NULL,&num) != CL_SUCCESS)
2259
    return(0);
2260
  return(num);
2261
}
2262
2263
static inline char *GetOpenCLPlatformString(cl_platform_id platform,
2264
  cl_platform_info param_name)
2265
{
2266
  char
2267
    *value;
2268
2269
  size_t
2270
    length;
2271
2272
  openCL_library->clGetPlatformInfo(platform,param_name,0,NULL,&length);
2273
  value=(char *) AcquireCriticalMemory(length*sizeof(*value));
2274
  openCL_library->clGetPlatformInfo(platform,param_name,length,value,NULL);
2275
  return(value);
2276
}
2277
2278
static inline char *GetOpenCLDeviceString(cl_device_id device,
2279
  cl_device_info param_name)
2280
{
2281
  char
2282
    *value;
2283
2284
  size_t
2285
    length;
2286
2287
  openCL_library->clGetDeviceInfo(device,param_name,0,NULL,&length);
2288
  value=(char *) AcquireCriticalMemory(length*sizeof(*value));
2289
  openCL_library->clGetDeviceInfo(device,param_name,length,value,NULL);
2290
  return(value);
2291
}
2292
2293
static void LoadOpenCLDevices(MagickCLEnv clEnv)
2294
{
2295
  cl_context_properties
2296
    properties[3];
2297
2298
  cl_device_id
2299
    *devices;
2300
2301
  cl_int
2302
    status;
2303
2304
  cl_platform_id
2305
    *platforms;
2306
2307
  cl_uint
2308
    i,
2309
    j,
2310
    next,
2311
    number_devices,
2312
    number_platforms;
2313
2314
  number_platforms=0;
2315
  if (openCL_library->clGetPlatformIDs(0,NULL,&number_platforms) != CL_SUCCESS)
2316
    return;
2317
  if (number_platforms == 0)
2318
    return;
2319
  platforms=(cl_platform_id *) AcquireQuantumMemory(1,number_platforms*
2320
    sizeof(cl_platform_id));
2321
  if (platforms == (cl_platform_id *) NULL)
2322
    return;
2323
  if (openCL_library->clGetPlatformIDs(number_platforms,platforms,NULL) != CL_SUCCESS)
2324
    {
2325
       platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2326
       return;
2327
    }
2328
  for (i = 0; i < number_platforms; i++)
2329
  {
2330
    number_devices=GetOpenCLDeviceCount(clEnv,platforms[i]);
2331
    if (number_devices == 0)
2332
      platforms[i]=(cl_platform_id) NULL;
2333
    else
2334
      clEnv->number_devices+=number_devices;
2335
  }
2336
  if (clEnv->number_devices == 0)
2337
    {
2338
      platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2339
      return;
2340
    }
2341
  clEnv->devices=(MagickCLDevice *) AcquireQuantumMemory(clEnv->number_devices,
2342
    sizeof(MagickCLDevice));
2343
  if (clEnv->devices == (MagickCLDevice *) NULL)
2344
    {
2345
      RelinquishMagickCLDevices(clEnv);
2346
      platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2347
      return;
2348
    }
2349
  (void) memset(clEnv->devices,0,clEnv->number_devices*sizeof(MagickCLDevice));
2350
  devices=(cl_device_id *) AcquireQuantumMemory(clEnv->number_devices,
2351
    sizeof(cl_device_id));
2352
  if (devices == (cl_device_id *) NULL)
2353
    {
2354
      platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2355
      RelinquishMagickCLDevices(clEnv);
2356
      return;
2357
    }
2358
  (void) memset(devices,0,clEnv->number_devices*sizeof(cl_device_id));
2359
  clEnv->number_contexts=(size_t) number_platforms;
2360
  clEnv->contexts=(cl_context *) AcquireQuantumMemory(clEnv->number_contexts,
2361
    sizeof(cl_context));
2362
  if (clEnv->contexts == (cl_context *) NULL)
2363
    {
2364
      devices=(cl_device_id *) RelinquishMagickMemory(devices);
2365
      platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2366
      RelinquishMagickCLDevices(clEnv);
2367
      return;
2368
    }
2369
  (void) memset(clEnv->contexts,0,clEnv->number_contexts*sizeof(cl_context));
2370
  next=0;
2371
  for (i = 0; i < number_platforms; i++)
2372
  {
2373
    if (platforms[i] == (cl_platform_id) NULL)
2374
      continue;
2375
2376
    status=clEnv->library->clGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_CPU |
2377
      CL_DEVICE_TYPE_GPU,(cl_uint) clEnv->number_devices,devices,&number_devices);
2378
    if (status != CL_SUCCESS)
2379
      continue;
2380
2381
    properties[0]=CL_CONTEXT_PLATFORM;
2382
    properties[1]=(cl_context_properties) platforms[i];
2383
    properties[2]=0;
2384
    clEnv->contexts[i]=openCL_library->clCreateContext(properties,number_devices,
2385
      devices,NULL,NULL,&status);
2386
    if (status != CL_SUCCESS)
2387
      continue;
2388
2389
    for (j = 0; j < number_devices; j++,next++)
2390
    {
2391
      MagickCLDevice
2392
        device;
2393
2394
      device=AcquireMagickCLDevice();
2395
      if (device == (MagickCLDevice) NULL)
2396
        break;
2397
2398
      device->context=clEnv->contexts[i];
2399
      device->deviceID=devices[j];
2400
2401
      device->platform_name=GetOpenCLPlatformString(platforms[i],
2402
        CL_PLATFORM_NAME);
2403
2404
      device->vendor_name=GetOpenCLPlatformString(platforms[i],
2405
        CL_PLATFORM_VENDOR);
2406
2407
      device->name=GetOpenCLDeviceString(devices[j],CL_DEVICE_NAME);
2408
2409
      device->version=GetOpenCLDeviceString(devices[j],CL_DRIVER_VERSION);
2410
2411
      openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_CLOCK_FREQUENCY,
2412
        sizeof(cl_uint),&device->max_clock_frequency,NULL);
2413
2414
      openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_MAX_COMPUTE_UNITS,
2415
        sizeof(cl_uint),&device->max_compute_units,NULL);
2416
2417
      openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_TYPE,
2418
        sizeof(cl_device_type),&device->type,NULL);
2419
2420
      openCL_library->clGetDeviceInfo(devices[j],CL_DEVICE_LOCAL_MEM_SIZE,
2421
        sizeof(cl_ulong),&device->local_memory_size,NULL);
2422
2423
      clEnv->devices[next]=device;
2424
      (void) LogMagickEvent(AccelerateEvent,GetMagickModule(),
2425
        "Found device: %s (%s)",device->name,device->platform_name);
2426
    }
2427
  }
2428
  if (next != clEnv->number_devices)
2429
    RelinquishMagickCLDevices(clEnv);
2430
  platforms=(cl_platform_id *) RelinquishMagickMemory(platforms);
2431
  devices=(cl_device_id *) RelinquishMagickMemory(devices);
2432
}
2433
2434
MagickPrivate MagickBooleanType InitializeOpenCL(MagickCLEnv clEnv,
2435
  ExceptionInfo *exception)
2436
{
2437
  LockSemaphoreInfo(clEnv->lock);
2438
  if (clEnv->initialized != MagickFalse)
2439
    {
2440
      UnlockSemaphoreInfo(clEnv->lock);
2441
      return(HasOpenCLDevices(clEnv,exception));
2442
    }
2443
  if (LoadOpenCLLibrary() != MagickFalse)
2444
    {
2445
      clEnv->library=openCL_library;
2446
      LoadOpenCLDevices(clEnv);
2447
      if (clEnv->number_devices > 0)
2448
        AutoSelectOpenCLDevices(clEnv);
2449
    }
2450
  clEnv->initialized=MagickTrue;
2451
  UnlockSemaphoreInfo(clEnv->lock);
2452
  return(HasOpenCLDevices(clEnv,exception));
2453
}
2454
2455
/*
2456
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2457
%                                                                             %
2458
%                                                                             %
2459
%                                                                             %
2460
%   L o a d O p e n C L L i b r a r y                                         %
2461
%                                                                             %
2462
%                                                                             %
2463
%                                                                             %
2464
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2465
%
2466
%  LoadOpenCLLibrary() load and binds the OpenCL library.
2467
%
2468
%  The format of the LoadOpenCLLibrary method is:
2469
%
2470
%    MagickBooleanType LoadOpenCLLibrary(void)
2471
%
2472
*/
2473
2474
void *OsLibraryGetFunctionAddress(void *library,const char *functionName)
2475
{
2476
  if ((library == (void *) NULL) || (functionName == (const char *) NULL))
2477
    return (void *) NULL;
2478
  return lt_dlsym(library,functionName);
2479
}
2480
2481
static MagickBooleanType BindOpenCLFunctions()
2482
{
2483
#ifdef MAGICKCORE_HAVE_OPENCL_CL_H
2484
#define BIND(X) openCL_library->X= &X;
2485
#else
2486
  (void) memset(openCL_library,0,sizeof(MagickLibrary));
2487
#ifdef MAGICKCORE_WINDOWS_SUPPORT
2488
  openCL_library->library=(void *)lt_dlopen("OpenCL.dll");
2489
#else
2490
  openCL_library->library=(void *)lt_dlopen("libOpenCL.so");
2491
#endif
2492
#define BIND(X) \
2493
  if ((openCL_library->X=(MAGICKpfn_##X)OsLibraryGetFunctionAddress(openCL_library->library,#X)) == NULL) \
2494
    return(MagickFalse);
2495
#endif
2496
2497
  if (openCL_library->library == (void*) NULL)
2498
    return(MagickFalse);
2499
2500
  BIND(clGetPlatformIDs);
2501
  BIND(clGetPlatformInfo);
2502
2503
  BIND(clGetDeviceIDs);
2504
  BIND(clGetDeviceInfo);
2505
2506
  BIND(clCreateBuffer);
2507
  BIND(clReleaseMemObject);
2508
  BIND(clRetainMemObject);
2509
2510
  BIND(clCreateContext);
2511
  BIND(clReleaseContext);
2512
2513
  BIND(clCreateCommandQueue);
2514
  BIND(clReleaseCommandQueue);
2515
  BIND(clFlush);
2516
  BIND(clFinish);
2517
2518
  BIND(clCreateProgramWithSource);
2519
  BIND(clCreateProgramWithBinary);
2520
  BIND(clReleaseProgram);
2521
  BIND(clBuildProgram);
2522
  BIND(clGetProgramBuildInfo);
2523
  BIND(clGetProgramInfo);
2524
2525
  BIND(clCreateKernel);
2526
  BIND(clReleaseKernel);
2527
  BIND(clSetKernelArg);
2528
  BIND(clGetKernelInfo);
2529
2530
  BIND(clEnqueueReadBuffer);
2531
  BIND(clEnqueueMapBuffer);
2532
  BIND(clEnqueueUnmapMemObject);
2533
  BIND(clEnqueueNDRangeKernel);
2534
2535
  BIND(clGetEventInfo);
2536
  BIND(clWaitForEvents);
2537
  BIND(clReleaseEvent);
2538
  BIND(clRetainEvent);
2539
  BIND(clSetEventCallback);
2540
2541
  BIND(clGetEventProfilingInfo);
2542
2543
  return(MagickTrue);
2544
}
2545
2546
static MagickBooleanType LoadOpenCLLibrary(void)
2547
{
2548
  openCL_library=(MagickLibrary *) AcquireMagickMemory(sizeof(MagickLibrary));
2549
  if (openCL_library == (MagickLibrary *) NULL)
2550
    return(MagickFalse);
2551
2552
  if (BindOpenCLFunctions() == MagickFalse)
2553
    {
2554
      openCL_library=(MagickLibrary *)RelinquishMagickMemory(openCL_library);
2555
      return(MagickFalse);
2556
    }
2557
2558
  return(MagickTrue);
2559
}
2560
2561
/*
2562
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2563
%                                                                             %
2564
%                                                                             %
2565
%                                                                             %
2566
+   O p e n C L T e r m i n u s                                               %
2567
%                                                                             %
2568
%                                                                             %
2569
%                                                                             %
2570
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2571
%
2572
%  OpenCLTerminus() destroys the OpenCL component.
2573
%
2574
%  The format of the OpenCLTerminus method is:
2575
%
2576
%      OpenCLTerminus(void)
2577
%
2578
*/
2579
2580
MagickPrivate void OpenCLTerminus()
2581
{
2582
  DumpOpenCLProfileData();
2583
  if (cache_directory != (char *) NULL)
2584
    cache_directory=DestroyString(cache_directory);
2585
  if (cache_directory_lock != (SemaphoreInfo *) NULL)
2586
    RelinquishSemaphoreInfo(&cache_directory_lock);
2587
  if (default_CLEnv != (MagickCLEnv) NULL)
2588
    default_CLEnv=RelinquishMagickCLEnv(default_CLEnv);
2589
  if (openCL_lock != (SemaphoreInfo *) NULL)
2590
    RelinquishSemaphoreInfo(&openCL_lock);
2591
  if (openCL_library != (MagickLibrary *) NULL)
2592
    {
2593
      if (openCL_library->library != (void *) NULL)
2594
        (void) lt_dlclose(openCL_library->library);
2595
      openCL_library=(MagickLibrary *) RelinquishMagickMemory(openCL_library);
2596
    }
2597
}
2598
2599
/*
2600
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2601
%                                                                             %
2602
%                                                                             %
2603
%                                                                             %
2604
+   O p e n C L T h r o w M a g i c k E x c e p t i o n                       %
2605
%                                                                             %
2606
%                                                                             %
2607
%                                                                             %
2608
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2609
%
2610
%  OpenCLThrowMagickException logs an OpenCL exception as determined by the log
2611
%  configuration file.  If an error occurs, MagickFalse is returned
2612
%  otherwise MagickTrue.
2613
%
2614
%  The format of the OpenCLThrowMagickException method is:
2615
%
2616
%      MagickBooleanType OpenCLThrowMagickException(ExceptionInfo *exception,
2617
%        const char *module,const char *function,const size_t line,
2618
%        const ExceptionType severity,const char *tag,const char *format,...)
2619
%
2620
%  A description of each parameter follows:
2621
%
2622
%    o exception: the exception info.
2623
%
2624
%    o filename: the source module filename.
2625
%
2626
%    o function: the function name.
2627
%
2628
%    o line: the line number of the source module.
2629
%
2630
%    o severity: Specifies the numeric error category.
2631
%
2632
%    o tag: the locale tag.
2633
%
2634
%    o format: the output format.
2635
%
2636
*/
2637
2638
MagickPrivate MagickBooleanType OpenCLThrowMagickException(
2639
  MagickCLDevice device,ExceptionInfo *exception,const char *module,
2640
  const char *function,const size_t line,const ExceptionType severity,
2641
  const char *tag,const char *format,...)
2642
{
2643
  MagickBooleanType
2644
    status;
2645
2646
  assert(device != (MagickCLDevice) NULL);
2647
  assert(exception != (ExceptionInfo *) NULL);
2648
  assert(exception->signature == MagickCoreSignature);
2649
  (void) exception;
2650
  status=MagickTrue;
2651
  if (severity != 0)
2652
  {
2653
    if (device->type == CL_DEVICE_TYPE_CPU)
2654
    {
2655
      /* Workaround for Intel OpenCL CPU runtime bug */
2656
      /* Turn off OpenCL when a problem is detected! */
2657
      if (strncmp(device->platform_name,"Intel",5) == 0)
2658
        default_CLEnv->enabled=MagickFalse;
2659
    }
2660
  }
2661
2662
#ifdef OPENCLLOG_ENABLED
2663
  {
2664
    va_list
2665
      operands;
2666
    va_start(operands,format);
2667
    status=ThrowMagickExceptionList(exception,module,function,line,severity,tag,
2668
      format,operands);
2669
    va_end(operands);
2670
  }
2671
#else
2672
  magick_unreferenced(module);
2673
  magick_unreferenced(function);
2674
  magick_unreferenced(line);
2675
  magick_unreferenced(tag);
2676
  magick_unreferenced(format);
2677
#endif
2678
2679
  return(status);
2680
}
2681
2682
/*
2683
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2684
%                                                                             %
2685
%                                                                             %
2686
%                                                                             %
2687
+   R e c o r d P r o f i l e D a t a                                         %
2688
%                                                                             %
2689
%                                                                             %
2690
%                                                                             %
2691
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2692
%
2693
%  RecordProfileData() records profile data.
2694
%
2695
%  The format of the RecordProfileData method is:
2696
%
2697
%      void RecordProfileData(MagickCLDevice device,ProfiledKernels kernel,
2698
%        cl_event event)
2699
%
2700
%  A description of each parameter follows:
2701
%
2702
%    o device: the OpenCL device that did the operation.
2703
%
2704
%    o event: the event that contains the profiling data.
2705
%
2706
*/
2707
2708
MagickPrivate MagickBooleanType RecordProfileData(MagickCLDevice device,
2709
  cl_kernel kernel,cl_event event)
2710
{
2711
  char
2712
    *name;
2713
2714
  cl_int
2715
    status;
2716
2717
  cl_ulong
2718
    elapsed,
2719
    end,
2720
    start;
2721
2722
  KernelProfileRecord
2723
    profile_record;
2724
2725
  size_t
2726
    i,
2727
    length;
2728
2729
  if (device->profile_kernels == MagickFalse)
2730
    return(MagickFalse);
2731
  status=openCL_library->clWaitForEvents(1,&event);
2732
  if (status != CL_SUCCESS)
2733
    return(MagickFalse);
2734
  status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,0,NULL,
2735
    &length);
2736
  if (status != CL_SUCCESS)
2737
    return(MagickTrue);
2738
  name=(char *) AcquireQuantumMemory(length,sizeof(*name));
2739
  if (name == (char *) NULL)
2740
    return(MagickTrue);
2741
  start=end=elapsed=0;
2742
  status=openCL_library->clGetKernelInfo(kernel,CL_KERNEL_FUNCTION_NAME,length,
2743
    name,(size_t *) NULL);
2744
  status|=openCL_library->clGetEventProfilingInfo(event,
2745
    CL_PROFILING_COMMAND_START,sizeof(cl_ulong),&start,NULL);
2746
  status|=openCL_library->clGetEventProfilingInfo(event,
2747
    CL_PROFILING_COMMAND_END,sizeof(cl_ulong),&end,NULL);
2748
  if (status != CL_SUCCESS)
2749
    {
2750
      name=DestroyString(name);
2751
      return(MagickTrue);
2752
    }
2753
  start/=1000; /* usecs */
2754
  end/=1000;   
2755
  elapsed=end-start;
2756
  LockSemaphoreInfo(device->lock);
2757
  i=0;
2758
  profile_record=(KernelProfileRecord) NULL;
2759
  if (device->profile_records != (KernelProfileRecord *) NULL)
2760
    {
2761
      while (device->profile_records[i] != (KernelProfileRecord) NULL)
2762
      {
2763
        if (LocaleCompare(device->profile_records[i]->kernel_name,name) == 0)
2764
          {
2765
            profile_record=device->profile_records[i];
2766
            break;
2767
          }
2768
        i++;
2769
      }
2770
    }
2771
  if (profile_record != (KernelProfileRecord) NULL)
2772
    name=DestroyString(name);
2773
  else
2774
    {
2775
      profile_record=(KernelProfileRecord) AcquireCriticalMemory(
2776
        sizeof(*profile_record));
2777
      (void) memset(profile_record,0,sizeof(*profile_record));
2778
      profile_record->kernel_name=name;
2779
      device->profile_records=(KernelProfileRecord *) ResizeQuantumMemory(
2780
        device->profile_records,(i+2),sizeof(*device->profile_records));
2781
      if (device->profile_records == (KernelProfileRecord *) NULL)
2782
        {
2783
          UnlockSemaphoreInfo(device->lock);
2784
          profile_record=(KernelProfileRecord) RelinquishMagickMemory(
2785
            profile_record);
2786
          name=DestroyString(name);
2787
          return(MagickFalse);
2788
        }
2789
      device->profile_records[i]=profile_record;
2790
      device->profile_records[i+1]=(KernelProfileRecord) NULL;
2791
    }
2792
  if ((elapsed < profile_record->min) || (profile_record->count == 0))
2793
    profile_record->min=(unsigned long) elapsed;
2794
  if (elapsed > profile_record->max)
2795
    profile_record->max=(unsigned long) elapsed;
2796
  profile_record->total+=(unsigned long) elapsed;
2797
  profile_record->count+=1;
2798
  UnlockSemaphoreInfo(device->lock);
2799
  return(MagickTrue);
2800
}
2801
2802
/*
2803
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804
%                                                                             %
2805
%                                                                             %
2806
%                                                                             %
2807
+  R e l e a s e O p e n C L C o m m a n d Q u e u e                          %
2808
%                                                                             %
2809
%                                                                             %
2810
%                                                                             %
2811
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2812
%
2813
%  ReleaseOpenCLCommandQueue() releases the OpenCL command queue
2814
%
2815
%  The format of the ReleaseOpenCLCommandQueue method is:
2816
%
2817
%      void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2818
%        cl_command_queue queue)
2819
%
2820
%  A description of each parameter follows:
2821
%
2822
%    o device: the OpenCL device.
2823
%
2824
%    o queue: the OpenCL queue to be released.
2825
*/
2826
2827
MagickPrivate void ReleaseOpenCLCommandQueue(MagickCLDevice device,
2828
  cl_command_queue queue)
2829
{
2830
  if (queue == (cl_command_queue) NULL)
2831
    return;
2832
2833
  assert(device != (MagickCLDevice) NULL);
2834
  LockSemaphoreInfo(device->lock);
2835
  if ((device->profile_kernels != MagickFalse) ||
2836
      (device->command_queues_index >= MAGICKCORE_OPENCL_COMMAND_QUEUES-1))
2837
    {
2838
      UnlockSemaphoreInfo(device->lock);
2839
      openCL_library->clFinish(queue);
2840
      (void) openCL_library->clReleaseCommandQueue(queue);
2841
    }
2842
  else
2843
    {
2844
      openCL_library->clFlush(queue);
2845
      device->command_queues[++device->command_queues_index]=queue;
2846
      UnlockSemaphoreInfo(device->lock);
2847
    }
2848
}
2849
2850
/*
2851
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2852
%                                                                             %
2853
%                                                                             %
2854
%                                                                             %
2855
+   R e l e a s e  M a g i c k C L D e v i c e                                %
2856
%                                                                             %
2857
%                                                                             %
2858
%                                                                             %
2859
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2860
%
2861
%  ReleaseOpenCLDevice() returns the OpenCL device to the environment
2862
%
2863
%  The format of the ReleaseOpenCLDevice method is:
2864
%
2865
%      void ReleaseOpenCLDevice(MagickCLDevice device)
2866
%
2867
%  A description of each parameter follows:
2868
%
2869
%    o device: the OpenCL device to be released.
2870
%
2871
*/
2872
2873
MagickPrivate void ReleaseOpenCLDevice(MagickCLDevice device)
2874
{
2875
  assert(device != (MagickCLDevice) NULL);
2876
  LockSemaphoreInfo(openCL_lock);
2877
  device->requested--;
2878
  UnlockSemaphoreInfo(openCL_lock);
2879
}
2880
2881
/*
2882
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2883
%                                                                             %
2884
%                                                                             %
2885
%                                                                             %
2886
+   R e l i n q u i s h M a g i c k C L C a c h e I n f o                     %
2887
%                                                                             %
2888
%                                                                             %
2889
%                                                                             %
2890
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2891
%
2892
%  RelinquishMagickCLCacheInfo() frees memory acquired with
2893
%  AcquireMagickCLCacheInfo()
2894
%
2895
%  The format of the RelinquishMagickCLCacheInfo method is:
2896
%
2897
%      MagickCLCacheInfo RelinquishMagickCLCacheInfo(MagickCLCacheInfo info,
2898
%        const MagickBooleanType relinquish_pixels)
2899
%
2900
%  A description of each parameter follows:
2901
%
2902
%    o info: the OpenCL cache info.
2903
%
2904
%    o relinquish_pixels: the pixels will be relinquish when set to true.
2905
%
2906
*/
2907
2908
static void CL_API_CALL DestroyMagickCLCacheInfoAndPixels(
2909
  cl_event magick_unused(event),
2910
  cl_int magick_unused(event_command_exec_status),void *user_data)
2911
{
2912
  MagickCLCacheInfo
2913
    info;
2914
2915
  Quantum
2916
    *pixels;
2917
2918
  ssize_t
2919
    i;
2920
2921
  magick_unreferenced(event);
2922
  magick_unreferenced(event_command_exec_status);
2923
  info=(MagickCLCacheInfo) user_data;
2924
  for (i=(ssize_t)info->event_count-1; i >= 0; i--)
2925
  {
2926
    cl_int
2927
      event_status;
2928
2929
    cl_uint
2930
      status;
2931
2932
    status=openCL_library->clGetEventInfo(info->events[i],
2933
      CL_EVENT_COMMAND_EXECUTION_STATUS,sizeof(event_status),&event_status,
2934
      NULL);
2935
    if ((status == CL_SUCCESS) && (event_status > CL_COMPLETE))
2936
      {
2937
        openCL_library->clSetEventCallback(info->events[i],CL_COMPLETE,
2938
          &DestroyMagickCLCacheInfoAndPixels,info);
2939
        return;
2940
      }
2941
  }
2942
  pixels=info->pixels;
2943
  RelinquishMagickResource(MemoryResource,info->length);
2944
  DestroyMagickCLCacheInfo(info);
2945
  (void) RelinquishAlignedMemory(pixels);
2946
}
2947
2948
MagickPrivate MagickCLCacheInfo RelinquishMagickCLCacheInfo(
2949
  MagickCLCacheInfo info,const MagickBooleanType relinquish_pixels)
2950
{
2951
  if (info == (MagickCLCacheInfo) NULL)
2952
    return((MagickCLCacheInfo) NULL);
2953
  if (relinquish_pixels != MagickFalse)
2954
    DestroyMagickCLCacheInfoAndPixels((cl_event) NULL,0,info);
2955
  else
2956
    DestroyMagickCLCacheInfo(info);
2957
  return((MagickCLCacheInfo) NULL);
2958
}
2959
2960
/*
2961
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2962
%                                                                             %
2963
%                                                                             %
2964
%                                                                             %
2965
%   R e l i n q u i s h M a g i c k C L D e v i c e                           %
2966
%                                                                             %
2967
%                                                                             %
2968
%                                                                             %
2969
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2970
%
2971
%  RelinquishMagickCLDevice() releases the OpenCL device
2972
%
2973
%  The format of the RelinquishMagickCLDevice method is:
2974
%
2975
%      MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2976
%
2977
%  A description of each parameter follows:
2978
%
2979
%    o device: the OpenCL device to be released.
2980
%
2981
*/
2982
2983
static MagickCLDevice RelinquishMagickCLDevice(MagickCLDevice device)
2984
{
2985
  if (device == (MagickCLDevice) NULL)
2986
    return((MagickCLDevice) NULL);
2987
2988
  device->platform_name=(char *) RelinquishMagickMemory(device->platform_name);
2989
  device->vendor_name=(char *) RelinquishMagickMemory(device->vendor_name);
2990
  device->name=(char *) RelinquishMagickMemory(device->name);
2991
  device->version=(char *) RelinquishMagickMemory(device->version);
2992
  if (device->program != (cl_program) NULL)
2993
    (void) openCL_library->clReleaseProgram(device->program);
2994
  while (device->command_queues_index >= 0)
2995
    (void) openCL_library->clReleaseCommandQueue(
2996
      device->command_queues[device->command_queues_index--]);
2997
  RelinquishSemaphoreInfo(&device->lock);
2998
  return((MagickCLDevice) RelinquishMagickMemory(device));
2999
}
3000
3001
/*
3002
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3003
%                                                                             %
3004
%                                                                             %
3005
%                                                                             %
3006
%   R e l i n q u i s h M a g i c k C L E n v                                 %
3007
%                                                                             %
3008
%                                                                             %
3009
%                                                                             %
3010
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3011
%
3012
%  RelinquishMagickCLEnv() releases the OpenCL environment
3013
%
3014
%  The format of the RelinquishMagickCLEnv method is:
3015
%
3016
%      MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv device)
3017
%
3018
%  A description of each parameter follows:
3019
%
3020
%    o clEnv: the OpenCL environment to be released.
3021
%
3022
*/
3023
3024
static MagickCLEnv RelinquishMagickCLEnv(MagickCLEnv clEnv)
3025
{
3026
  if (clEnv == (MagickCLEnv) NULL)
3027
    return((MagickCLEnv) NULL);
3028
3029
  RelinquishSemaphoreInfo(&clEnv->lock);
3030
  RelinquishMagickCLDevices(clEnv);
3031
  if (clEnv->contexts != (cl_context *) NULL)
3032
    {
3033
      ssize_t
3034
        i;
3035
3036
      for (i=0; i < (ssize_t) clEnv->number_contexts; i++)
3037
        if (clEnv->contexts[i] != (cl_context) NULL)
3038
          (void) openCL_library->clReleaseContext(clEnv->contexts[i]);
3039
      clEnv->contexts=(cl_context *) RelinquishMagickMemory(clEnv->contexts);
3040
    }
3041
  return((MagickCLEnv) RelinquishMagickMemory(clEnv));
3042
}
3043
3044
/*
3045
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3046
%                                                                             %
3047
%                                                                             %
3048
%                                                                             %
3049
+   R e q u e s t O p e n C L D e v i c e                                     %
3050
%                                                                             %
3051
%                                                                             %
3052
%                                                                             %
3053
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3054
%
3055
%  RequestOpenCLDevice() returns one of the enabled OpenCL devices.
3056
%
3057
%  The format of the RequestOpenCLDevice method is:
3058
%
3059
%      MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
3060
%
3061
%  A description of each parameter follows:
3062
%
3063
%    o clEnv: the OpenCL environment.
3064
*/
3065
3066
MagickPrivate MagickCLDevice RequestOpenCLDevice(MagickCLEnv clEnv)
3067
{
3068
  MagickCLDevice
3069
    device;
3070
3071
  double
3072
    score,
3073
    best_score;
3074
3075
  size_t
3076
    i;
3077
3078
  if (clEnv == (MagickCLEnv) NULL)
3079
    return((MagickCLDevice) NULL);
3080
3081
  if (clEnv->number_devices == 1)
3082
  {
3083
    if (clEnv->devices[0]->enabled)
3084
      return(clEnv->devices[0]);
3085
    else
3086
      return((MagickCLDevice) NULL);
3087
  }
3088
3089
  device=(MagickCLDevice) NULL;
3090
  best_score=0.0;
3091
  LockSemaphoreInfo(openCL_lock);
3092
  for (i = 0; i < clEnv->number_devices; i++)
3093
  {
3094
    if (clEnv->devices[i]->enabled == MagickFalse)
3095
      continue;
3096
3097
    score=clEnv->devices[i]->score+(clEnv->devices[i]->score*
3098
      clEnv->devices[i]->requested);
3099
    if ((device == (MagickCLDevice) NULL) || (score < best_score))
3100
    {
3101
      device=clEnv->devices[i];
3102
      best_score=score;
3103
    }
3104
  }
3105
  if (device != (MagickCLDevice)NULL)
3106
    device->requested++;
3107
  UnlockSemaphoreInfo(openCL_lock);
3108
3109
  return(device);
3110
}
3111
3112
/*
3113
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3114
%                                                                             %
3115
%                                                                             %
3116
%                                                                             %
3117
%   S e t O p e n C L D e v i c e E n a b l e d                               %
3118
%                                                                             %
3119
%                                                                             %
3120
%                                                                             %
3121
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3122
%
3123
%  SetOpenCLDeviceEnabled() can be used to enable or disabled the device.
3124
%
3125
%  The format of the SetOpenCLDeviceEnabled method is:
3126
%
3127
%      void SetOpenCLDeviceEnabled(MagickCLDevice device,
3128
%        MagickBooleanType value)
3129
%
3130
%  A description of each parameter follows:
3131
%
3132
%    o device: the OpenCL device.
3133
%
3134
%    o value: determines if the device should be enabled or disabled.
3135
*/
3136
3137
MagickExport void SetOpenCLDeviceEnabled(MagickCLDevice device,
3138
  const MagickBooleanType value)
3139
{
3140
  if (device == (MagickCLDevice) NULL)
3141
    return;
3142
  device->enabled=value;
3143
}
3144
3145
/*
3146
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3147
%                                                                             %
3148
%                                                                             %
3149
%                                                                             %
3150
%   S e t O p e n C L K e r n e l P r o f i l e E n a b l e d                 %
3151
%                                                                             %
3152
%                                                                             %
3153
%                                                                             %
3154
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3155
%
3156
%  SetOpenCLKernelProfileEnabled() can be used to enable or disabled the
3157
%  kernel profiling of a device.
3158
%
3159
%  The format of the SetOpenCLKernelProfileEnabled method is:
3160
%
3161
%      void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3162
%        MagickBooleanType value)
3163
%
3164
%  A description of each parameter follows:
3165
%
3166
%    o device: the OpenCL device.
3167
%
3168
%    o value: determines if kernel profiling for the device should be enabled
3169
%             or disabled.
3170
*/
3171
3172
MagickExport void SetOpenCLKernelProfileEnabled(MagickCLDevice device,
3173
  const MagickBooleanType value)
3174
{
3175
  if (device == (MagickCLDevice) NULL)
3176
    return;
3177
  device->profile_kernels=value;
3178
}
3179
3180
/*
3181
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3182
%                                                                             %
3183
%                                                                             %
3184
%                                                                             %
3185
%   S e t O p e n C L E n a b l e d                                           %
3186
%                                                                             %
3187
%                                                                             %
3188
%                                                                             %
3189
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3190
%
3191
%  SetOpenCLEnabled() can be used to enable or disable OpenCL acceleration.
3192
%
3193
%  The format of the SetOpenCLEnabled method is:
3194
%
3195
%      void SetOpenCLEnabled(MagickBooleanType)
3196
%
3197
%  A description of each parameter follows:
3198
%
3199
%    o value: specify true to enable OpenCL acceleration
3200
*/
3201
3202
MagickExport MagickBooleanType SetOpenCLEnabled(const MagickBooleanType value)
3203
{
3204
  MagickCLEnv
3205
    clEnv;
3206
3207
  clEnv=GetCurrentOpenCLEnv();
3208
  if (clEnv == (MagickCLEnv) NULL)
3209
    return(MagickFalse);
3210
  clEnv->enabled=value;
3211
  return(clEnv->enabled);
3212
}
3213
3214
#else
3215
3216
MagickExport double GetOpenCLDeviceBenchmarkScore(
3217
  const MagickCLDevice magick_unused(device))
3218
0
{
3219
0
  magick_unreferenced(device);
3220
0
  return(0.0);
3221
0
}
3222
3223
MagickExport MagickBooleanType GetOpenCLDeviceEnabled(
3224
  const MagickCLDevice magick_unused(device))
3225
0
{
3226
0
  magick_unreferenced(device);
3227
0
  return(MagickFalse);
3228
0
}
3229
3230
MagickExport const char *GetOpenCLDeviceName(
3231
  const MagickCLDevice magick_unused(device))
3232
0
{
3233
0
  magick_unreferenced(device);
3234
0
  return((const char *) NULL);
3235
0
}
3236
3237
MagickExport MagickCLDevice *GetOpenCLDevices(size_t *length,
3238
  ExceptionInfo *magick_unused(exception))
3239
0
{
3240
0
  magick_unreferenced(exception);
3241
0
  if (length != (size_t *) NULL)
3242
0
    *length=0;
3243
0
  return((MagickCLDevice *) NULL);
3244
0
}
3245
3246
MagickExport MagickCLDeviceType GetOpenCLDeviceType(
3247
  const MagickCLDevice magick_unused(device))
3248
0
{
3249
0
  magick_unreferenced(device);
3250
0
  return(UndefinedCLDeviceType);
3251
0
}
3252
3253
MagickExport const KernelProfileRecord *GetOpenCLKernelProfileRecords(
3254
  const MagickCLDevice magick_unused(device),size_t *length)
3255
0
{
3256
0
  magick_unreferenced(device);
3257
0
  if (length != (size_t *) NULL)
3258
0
    *length=0;
3259
0
  return((const KernelProfileRecord *) NULL);
3260
0
}
3261
3262
MagickExport const char *GetOpenCLDeviceVersion(
3263
  const MagickCLDevice magick_unused(device))
3264
0
{
3265
0
  magick_unreferenced(device);
3266
0
  return((const char *) NULL);
3267
0
}
3268
3269
MagickExport MagickBooleanType GetOpenCLEnabled(void)
3270
0
{
3271
0
  return(MagickFalse);
3272
0
}
3273
3274
MagickExport void SetOpenCLDeviceEnabled(
3275
  MagickCLDevice magick_unused(device),
3276
  const MagickBooleanType magick_unused(value))
3277
0
{
3278
0
  magick_unreferenced(device);
3279
0
  magick_unreferenced(value);
3280
0
}
3281
3282
MagickExport MagickBooleanType SetOpenCLEnabled(
3283
  const MagickBooleanType magick_unused(value))
3284
0
{
3285
0
  magick_unreferenced(value);
3286
0
  return(MagickFalse);
3287
0
}
3288
3289
MagickExport void SetOpenCLKernelProfileEnabled(
3290
  MagickCLDevice magick_unused(device),
3291
  const MagickBooleanType magick_unused(value))
3292
0
{
3293
0
  magick_unreferenced(device);
3294
0
  magick_unreferenced(value);
3295
0
}
3296
#endif