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