accelerate.c revision 0c832c68ae950d35e8166671cdcb29ec46ef7b3f
1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% AAA CCCC CCCC EEEEE L EEEEE RRRR AAA TTTTT EEEEE % 7% A A C C E L E R R A A T E % 8% AAAAA C C EEE L EEE RRRR AAAAA T EEE % 9% A A C C E L E R R A A T E % 10% A A CCCC CCCC EEEEE LLLLL EEEEE R R A A T EEEEE % 11% % 12% % 13% MagickCore Acceleration Methods % 14% % 15% Software Design % 16% Cristy % 17% SiuChi Chan % 18% Guansong Zhang % 19% January 2010 % 20% % 21% % 22% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization % 23% dedicated to making software imaging solutions freely available. % 24% % 25% You may not use this file except in compliance with the License. You may % 26% obtain a copy of the License at % 27% % 28% http://www.imagemagick.org/script/license.php % 29% % 30% Unless required by applicable law or agreed to in writing, software % 31% distributed under the License is distributed on an "AS IS" BASIS, % 32% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 33% See the License for the specific language governing permissions and % 34% limitations under the License. % 35% % 36%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37*/ 38 39/* 40Include declarations. 41*/ 42#include "MagickCore/studio.h" 43#include "MagickCore/accelerate.h" 44#include "MagickCore/accelerate-private.h" 45#include "MagickCore/artifact.h" 46#include "MagickCore/cache.h" 47#include "MagickCore/cache-private.h" 48#include "MagickCore/cache-view.h" 49#include "MagickCore/color-private.h" 50#include "MagickCore/delegate-private.h" 51#include "MagickCore/enhance.h" 52#include "MagickCore/exception.h" 53#include "MagickCore/exception-private.h" 54#include "MagickCore/gem.h" 55#include "MagickCore/hashmap.h" 56#include "MagickCore/image.h" 57#include "MagickCore/image-private.h" 58#include "MagickCore/list.h" 59#include "MagickCore/memory_.h" 60#include "MagickCore/monitor-private.h" 61#include "MagickCore/accelerate.h" 62#include "MagickCore/opencl.h" 63#include "MagickCore/opencl-private.h" 64#include "MagickCore/option.h" 65#include "MagickCore/pixel-private.h" 66#include "MagickCore/prepress.h" 67#include "MagickCore/quantize.h" 68#include "MagickCore/random_.h" 69#include "MagickCore/random-private.h" 70#include "MagickCore/registry.h" 71#include "MagickCore/resize.h" 72#include "MagickCore/resize-private.h" 73#include "MagickCore/semaphore.h" 74#include "MagickCore/splay-tree.h" 75#include "MagickCore/statistic.h" 76#include "MagickCore/string_.h" 77#include "MagickCore/string-private.h" 78#include "MagickCore/token.h" 79 80#ifdef MAGICKCORE_CLPERFMARKER 81#include "CLPerfMarker.h" 82#endif 83 84#define MAGICK_MAX(x,y) (((x) >= (y))?(x):(y)) 85#define MAGICK_MIN(x,y) (((x) <= (y))?(x):(y)) 86 87#if defined(MAGICKCORE_OPENCL_SUPPORT) 88 89#define ALIGNED(pointer,type) ((((long)(pointer)) & (sizeof(type)-1)) == 0) 90/*#define ALIGNED(pointer,type) (0) */ 91 92/* pad the global workgroup size to the next multiple of 93 the local workgroup size */ 94inline static unsigned int 95 padGlobalWorkgroupSizeToLocalWorkgroupSize(const unsigned int orgGlobalSize, 96 const unsigned int localGroupSize) 97{ 98 return ((orgGlobalSize+(localGroupSize-1))/localGroupSize*localGroupSize); 99} 100 101static MagickBooleanType checkOpenCLEnvironment(ExceptionInfo* exception) 102{ 103 MagickBooleanType flag; 104 105 MagickCLEnv clEnv; 106 clEnv = GetDefaultOpenCLEnv(); 107 108 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED 109 , sizeof(MagickBooleanType), &flag, exception); 110 if (flag != MagickFalse) 111 return MagickFalse; 112 113 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED 114 , sizeof(MagickBooleanType), &flag, exception); 115 if (flag == MagickFalse) 116 { 117 if(InitOpenCLEnv(clEnv, exception) == MagickFalse) 118 return MagickFalse; 119 120 GetMagickOpenCLEnvParam(clEnv, MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED 121 , sizeof(MagickBooleanType), &flag, exception); 122 if (flag != MagickFalse) 123 return MagickFalse; 124 } 125 126 return MagickTrue; 127} 128 129 130static MagickBooleanType checkAccelerateCondition(const Image* image, const ChannelType channel) 131{ 132 /* check if the image's colorspace is supported */ 133 if (image->colorspace != RGBColorspace 134 && image->colorspace != sRGBColorspace 135 && image->colorspace != GRAYColorspace) 136 return MagickFalse; 137 138 /* check if the channel is supported */ 139 if (((channel&RedChannel) == 0) 140 || ((channel&GreenChannel) == 0) 141 || ((channel&BlueChannel) == 0)) 142 { 143 return MagickFalse; 144 } 145 146 147 /* check if if the virtual pixel method is compatible with the OpenCL implementation */ 148 if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod)&& 149 (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod)) 150 return MagickFalse; 151 152 return MagickTrue; 153} 154 155static MagickBooleanType checkHistogramCondition(Image *image, const ChannelType channel) 156{ 157 158 /* ensure this is the only pass get in for now. */ 159 if ((channel & SyncChannels) == 0) 160 return MagickFalse; 161 162 if (image->intensity == Rec601LuminancePixelIntensityMethod || 163 image->intensity == Rec709LuminancePixelIntensityMethod) 164 return MagickFalse; 165 166 if (image->colorspace != sRGBColorspace) 167 return MagickFalse; 168 169 return MagickTrue; 170} 171 172 173static Image* ComputeConvolveImage(const Image* inputImage, const ChannelType channel, const KernelInfo *kernel, ExceptionInfo *exception) 174{ 175 MagickBooleanType outputReady; 176 MagickCLEnv clEnv; 177 178 cl_int clStatus; 179 size_t global_work_size[3]; 180 size_t localGroupSize[3]; 181 size_t localMemoryRequirement; 182 Image* filteredImage; 183 MagickSizeType length; 184 const void *inputPixels; 185 void *filteredPixels; 186 cl_mem_flags mem_flags; 187 float* kernelBufferPtr; 188 unsigned kernelSize; 189 unsigned int i; 190 void *hostPtr; 191 unsigned int matte, 192 filterWidth, filterHeight, 193 imageWidth, imageHeight; 194 195 cl_context context; 196 cl_kernel clkernel; 197 cl_mem inputImageBuffer, filteredImageBuffer, convolutionKernel; 198 cl_ulong deviceLocalMemorySize; 199 200 cl_command_queue queue; 201 202 /* intialize all CL objects to NULL */ 203 context = NULL; 204 inputImageBuffer = NULL; 205 filteredImageBuffer = NULL; 206 convolutionKernel = NULL; 207 clkernel = NULL; 208 queue = NULL; 209 210 filteredImage = NULL; 211 outputReady = MagickFalse; 212 213 clEnv = GetDefaultOpenCLEnv(); 214 context = GetOpenCLContext(clEnv); 215 216 inputPixels = NULL; 217 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 218 if (inputPixels == (const void *) NULL) 219 { 220 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 221 goto cleanup; 222 } 223 224 /* Create and initialize OpenCL buffers. */ 225 226 /* If the host pointer is aligned to the size of CLPixelPacket, 227 then use the host buffer directly from the GPU; otherwise, 228 create a buffer on the GPU and copy the data over */ 229 if (ALIGNED(inputPixels,CLPixelPacket)) 230 { 231 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 232 } 233 else 234 { 235 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 236 } 237 /* create a CL buffer from image pixel buffer */ 238 length = inputImage->columns * inputImage->rows; 239 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 240 if (clStatus != CL_SUCCESS) 241 { 242 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 243 goto cleanup; 244 } 245 246 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 247 assert(filteredImage != NULL); 248 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 249 { 250 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 251 goto cleanup; 252 } 253 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 254 if (filteredPixels == (void *) NULL) 255 { 256 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 257 goto cleanup; 258 } 259 260 if (ALIGNED(filteredPixels,CLPixelPacket)) 261 { 262 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 263 hostPtr = filteredPixels; 264 } 265 else 266 { 267 mem_flags = CL_MEM_WRITE_ONLY; 268 hostPtr = NULL; 269 } 270 /* create a CL buffer from image pixel buffer */ 271 length = inputImage->columns * inputImage->rows; 272 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 273 if (clStatus != CL_SUCCESS) 274 { 275 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 276 goto cleanup; 277 } 278 279 kernelSize = kernel->width * kernel->height; 280 convolutionKernel = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernelSize * sizeof(float), NULL, &clStatus); 281 if (clStatus != CL_SUCCESS) 282 { 283 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 284 goto cleanup; 285 } 286 287 queue = AcquireOpenCLCommandQueue(clEnv); 288 289 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, convolutionKernel, CL_TRUE, CL_MAP_WRITE, 0, kernelSize * sizeof(float) 290 , 0, NULL, NULL, &clStatus); 291 if (clStatus != CL_SUCCESS) 292 { 293 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 294 goto cleanup; 295 } 296 for (i = 0; i < kernelSize; i++) 297 { 298 kernelBufferPtr[i] = (float) kernel->values[i]; 299 } 300 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, convolutionKernel, kernelBufferPtr, 0, NULL, NULL); 301 if (clStatus != CL_SUCCESS) 302 { 303 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 304 goto cleanup; 305 } 306 clEnv->library->clFlush(queue); 307 308 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv); 309 310 /* Compute the local memory requirement for a 16x16 workgroup. 311 If it's larger than 16k, reduce the workgroup size to 8x8 */ 312 localGroupSize[0] = 16; 313 localGroupSize[1] = 16; 314 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket) 315 + kernel->width*kernel->height*sizeof(float); 316 317 if (localMemoryRequirement > deviceLocalMemorySize) 318 { 319 localGroupSize[0] = 8; 320 localGroupSize[1] = 8; 321 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket) 322 + kernel->width*kernel->height*sizeof(float); 323 } 324 if (localMemoryRequirement <= deviceLocalMemorySize) 325 { 326 /* get the OpenCL kernel */ 327 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ConvolveOptimized"); 328 if (clkernel == NULL) 329 { 330 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 331 goto cleanup; 332 } 333 334 /* set the kernel arguments */ 335 i = 0; 336 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 337 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 338 imageWidth = inputImage->columns; 339 imageHeight = inputImage->rows; 340 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth); 341 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight); 342 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel); 343 filterWidth = kernel->width; 344 filterHeight = kernel->height; 345 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth); 346 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight); 347 matte = (inputImage->matte==MagickTrue)?1:0; 348 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte); 349 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel); 350 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, (localGroupSize[0] + kernel->width-1)*(localGroupSize[1] + kernel->height-1)*sizeof(CLPixelPacket),NULL); 351 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, kernel->width*kernel->height*sizeof(float),NULL); 352 if (clStatus != CL_SUCCESS) 353 { 354 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 355 goto cleanup; 356 } 357 358 /* pad the global size to a multiple of the local work size dimension */ 359 global_work_size[0] = ((inputImage->columns + localGroupSize[0] - 1)/localGroupSize[0] ) * localGroupSize[0] ; 360 global_work_size[1] = ((inputImage->rows + localGroupSize[1] - 1)/localGroupSize[1]) * localGroupSize[1]; 361 362 /* launch the kernel */ 363 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL); 364 if (clStatus != CL_SUCCESS) 365 { 366 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 367 goto cleanup; 368 } 369 } 370 else 371 { 372 /* get the OpenCL kernel */ 373 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Convolve"); 374 if (clkernel == NULL) 375 { 376 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 377 goto cleanup; 378 } 379 380 /* set the kernel arguments */ 381 i = 0; 382 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 383 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 384 imageWidth = inputImage->columns; 385 imageHeight = inputImage->rows; 386 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth); 387 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight); 388 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel); 389 filterWidth = kernel->width; 390 filterHeight = kernel->height; 391 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth); 392 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight); 393 matte = (inputImage->matte==MagickTrue)?1:0; 394 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte); 395 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel); 396 if (clStatus != CL_SUCCESS) 397 { 398 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 399 goto cleanup; 400 } 401 402 localGroupSize[0] = 8; 403 localGroupSize[1] = 8; 404 global_work_size[0] = (inputImage->columns + (localGroupSize[0]-1))/localGroupSize[0] * localGroupSize[0]; 405 global_work_size[1] = (inputImage->rows + (localGroupSize[1]-1))/localGroupSize[1] * localGroupSize[1]; 406 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL); 407 408 if (clStatus != CL_SUCCESS) 409 { 410 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 411 goto cleanup; 412 } 413 } 414 clEnv->library->clFlush(queue); 415 416 if (ALIGNED(filteredPixels,CLPixelPacket)) 417 { 418 length = inputImage->columns * inputImage->rows; 419 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 420 } 421 else 422 { 423 length = inputImage->columns * inputImage->rows; 424 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 425 } 426 if (clStatus != CL_SUCCESS) 427 { 428 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 429 goto cleanup; 430 } 431 432 /* everything is fine! :) */ 433 outputReady = MagickTrue; 434 435cleanup: 436 OpenCLLogException(__FUNCTION__,__LINE__,exception); 437 438 if (inputImageBuffer != NULL) 439 clEnv->library->clReleaseMemObject(inputImageBuffer); 440 441 if (filteredImageBuffer != NULL) 442 clEnv->library->clReleaseMemObject(filteredImageBuffer); 443 444 if (convolutionKernel != NULL) 445 clEnv->library->clReleaseMemObject(convolutionKernel); 446 447 if (clkernel != NULL) 448 RelinquishOpenCLKernel(clEnv, clkernel); 449 450 if (queue != NULL) 451 RelinquishOpenCLCommandQueue(clEnv, queue); 452 453 if (outputReady == MagickFalse) 454 { 455 if (filteredImage != NULL) 456 { 457 DestroyImage(filteredImage); 458 filteredImage = NULL; 459 } 460 } 461 462 return filteredImage; 463} 464 465/* 466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 467% % 468% % 469% % 470% C o n v o l v e I m a g e w i t h O p e n C L % 471% % 472% % 473% % 474%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 475% 476% ConvolveImage() applies a custom convolution kernel to the image. 477% 478% The format of the ConvolveImage method is: 479% 480% Image *ConvolveImage(const Image *image,const size_t order, 481% const double *kernel,ExceptionInfo *exception) 482% Image *ConvolveImageChannel(const Image *image,const ChannelType channel, 483% const size_t order,const double *kernel,ExceptionInfo *exception) 484% 485% A description of each parameter follows: 486% 487% o image: the image. 488% 489% o channel: the channel type. 490% 491% o kernel: kernel info. 492% 493% o exception: return any errors or warnings in this structure. 494% 495*/ 496 497MagickExport Image* AccelerateConvolveImageChannel(const Image *image, const ChannelType channel, const KernelInfo *kernel, ExceptionInfo *exception) 498{ 499 MagickBooleanType status; 500 Image* filteredImage = NULL; 501 502 assert(image != NULL); 503 assert(kernel != (KernelInfo *) NULL); 504 assert(exception != (ExceptionInfo *) NULL); 505 506 status = checkOpenCLEnvironment(exception); 507 if (status == MagickFalse) 508 return NULL; 509 510 status = checkAccelerateCondition(image, channel); 511 if (status == MagickFalse) 512 return NULL; 513 514 filteredImage = ComputeConvolveImage(image, channel, kernel, exception); 515 return filteredImage; 516} 517 518static MagickBooleanType ComputeFunctionImage(Image *image, const ChannelType channel,const MagickFunction function, 519 const size_t number_parameters,const double *parameters, ExceptionInfo *exception) 520{ 521 MagickBooleanType status; 522 523 MagickCLEnv clEnv; 524 525 MagickSizeType length; 526 void* pixels; 527 float* parametersBufferPtr; 528 529 cl_int clStatus; 530 cl_context context; 531 cl_kernel clkernel; 532 cl_command_queue queue; 533 cl_mem_flags mem_flags; 534 cl_mem imageBuffer; 535 cl_mem parametersBuffer; 536 size_t globalWorkSize[2]; 537 538 unsigned int i; 539 540 status = MagickFalse; 541 542 context = NULL; 543 clkernel = NULL; 544 queue = NULL; 545 imageBuffer = NULL; 546 parametersBuffer = NULL; 547 548 clEnv = GetDefaultOpenCLEnv(); 549 context = GetOpenCLContext(clEnv); 550 551 pixels = GetPixelCachePixels(image, &length, exception); 552 if (pixels == (void *) NULL) 553 { 554 (void) OpenCLThrowMagickException(exception, GetMagickModule(), CacheWarning, 555 "GetPixelCachePixels failed.", 556 "'%s'", image->filename); 557 goto cleanup; 558 } 559 560 561 if (ALIGNED(pixels,CLPixelPacket)) 562 { 563 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 564 } 565 else 566 { 567 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 568 } 569 /* create a CL buffer from image pixel buffer */ 570 length = image->columns * image->rows; 571 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)pixels, &clStatus); 572 if (clStatus != CL_SUCCESS) 573 { 574 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 575 goto cleanup; 576 } 577 578 parametersBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, number_parameters * sizeof(float), NULL, &clStatus); 579 if (clStatus != CL_SUCCESS) 580 { 581 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 582 goto cleanup; 583 } 584 585 queue = AcquireOpenCLCommandQueue(clEnv); 586 587 parametersBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, parametersBuffer, CL_TRUE, CL_MAP_WRITE, 0, number_parameters * sizeof(float) 588 , 0, NULL, NULL, &clStatus); 589 if (clStatus != CL_SUCCESS) 590 { 591 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 592 goto cleanup; 593 } 594 for (i = 0; i < number_parameters; i++) 595 { 596 parametersBufferPtr[i] = (float)parameters[i]; 597 } 598 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, parametersBuffer, parametersBufferPtr, 0, NULL, NULL); 599 if (clStatus != CL_SUCCESS) 600 { 601 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 602 goto cleanup; 603 } 604 clEnv->library->clFlush(queue); 605 606 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "FunctionImage"); 607 if (clkernel == NULL) 608 { 609 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 610 goto cleanup; 611 } 612 613 /* set the kernel arguments */ 614 i = 0; 615 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer); 616 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel); 617 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(MagickFunction),(void *)&function); 618 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&number_parameters); 619 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)¶metersBuffer); 620 if (clStatus != CL_SUCCESS) 621 { 622 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 623 goto cleanup; 624 } 625 626 globalWorkSize[0] = image->columns; 627 globalWorkSize[1] = image->rows; 628 /* launch the kernel */ 629 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, globalWorkSize, NULL, 0, NULL, NULL); 630 if (clStatus != CL_SUCCESS) 631 { 632 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 633 goto cleanup; 634 } 635 clEnv->library->clFlush(queue); 636 637 638 if (ALIGNED(pixels,CLPixelPacket)) 639 { 640 length = image->columns * image->rows; 641 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 642 } 643 else 644 { 645 length = image->columns * image->rows; 646 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), pixels, 0, NULL, NULL); 647 } 648 if (clStatus != CL_SUCCESS) 649 { 650 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 651 goto cleanup; 652 } 653 status = MagickTrue; 654 655cleanup: 656 OpenCLLogException(__FUNCTION__,__LINE__,exception); 657 658 if (clkernel != NULL) RelinquishOpenCLKernel(clEnv, clkernel); 659 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 660 if (imageBuffer != NULL) clEnv->library->clReleaseMemObject(imageBuffer); 661 if (parametersBuffer != NULL) clEnv->library->clReleaseMemObject(parametersBuffer); 662 663 return status; 664} 665 666 667 668MagickExport MagickBooleanType 669 AccelerateFunctionImage(Image *image, const ChannelType channel,const MagickFunction function, 670 const size_t number_parameters,const double *parameters, ExceptionInfo *exception) 671{ 672 MagickBooleanType status; 673 674 status = MagickFalse; 675 676 assert(image != NULL); 677 assert(exception != (ExceptionInfo *) NULL); 678 679 status = checkOpenCLEnvironment(exception); 680 if (status != MagickFalse) 681 { 682 status = checkAccelerateCondition(image, channel); 683 if (status != MagickFalse) 684 { 685 status = ComputeFunctionImage(image, channel, function, number_parameters, parameters, exception); 686 } 687 } 688 return status; 689} 690 691 692static MagickBooleanType splitImage(const Image* inputImage) 693{ 694 MagickBooleanType split; 695 696 MagickCLEnv clEnv; 697 unsigned long allocSize; 698 unsigned long tempSize; 699 700 clEnv = GetDefaultOpenCLEnv(); 701 702 allocSize = GetOpenCLDeviceMaxMemAllocSize(clEnv); 703 tempSize = inputImage->columns * inputImage->rows * 4 * 4; 704 705 /* 706 printf("alloc size: %lu\n", allocSize); 707 printf("temp size: %lu\n", tempSize); 708 */ 709 710 split = ((tempSize > allocSize) ? MagickTrue:MagickFalse); 711 712 return split; 713} 714 715static Image* ComputeBlurImage(const Image* inputImage, const ChannelType channel, const double radius, const double sigma, ExceptionInfo *exception) 716{ 717 MagickBooleanType outputReady; 718 Image* filteredImage; 719 MagickCLEnv clEnv; 720 721 cl_int clStatus; 722 723 const void *inputPixels; 724 void *filteredPixels; 725 cl_mem_flags mem_flags; 726 727 cl_context context; 728 cl_mem inputImageBuffer, tempImageBuffer, filteredImageBuffer, imageKernelBuffer; 729 cl_kernel blurRowKernel, blurColumnKernel; 730 cl_command_queue queue; 731 732 void* hostPtr; 733 float* kernelBufferPtr; 734 MagickSizeType length; 735 736 char geometry[MaxTextExtent]; 737 KernelInfo* kernel = NULL; 738 unsigned int kernelWidth; 739 unsigned int imageColumns, imageRows; 740 741 unsigned int i; 742 743 context = NULL; 744 filteredImage = NULL; 745 inputImageBuffer = NULL; 746 tempImageBuffer = NULL; 747 filteredImageBuffer = NULL; 748 imageKernelBuffer = NULL; 749 blurRowKernel = NULL; 750 blurColumnKernel = NULL; 751 queue = NULL; 752 753 outputReady = MagickFalse; 754 755 clEnv = GetDefaultOpenCLEnv(); 756 context = GetOpenCLContext(clEnv); 757 queue = AcquireOpenCLCommandQueue(clEnv); 758 759 /* Create and initialize OpenCL buffers. */ 760 { 761 inputPixels = NULL; 762 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 763 if (inputPixels == (const void *) NULL) 764 { 765 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 766 goto cleanup; 767 } 768 /* If the host pointer is aligned to the size of CLPixelPacket, 769 then use the host buffer directly from the GPU; otherwise, 770 create a buffer on the GPU and copy the data over */ 771 if (ALIGNED(inputPixels,CLPixelPacket)) 772 { 773 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 774 } 775 else 776 { 777 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 778 } 779 /* create a CL buffer from image pixel buffer */ 780 length = inputImage->columns * inputImage->rows; 781 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 782 if (clStatus != CL_SUCCESS) 783 { 784 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 785 goto cleanup; 786 } 787 } 788 789 /* create output */ 790 { 791 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 792 assert(filteredImage != NULL); 793 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 794 { 795 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 796 goto cleanup; 797 } 798 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 799 if (filteredPixels == (void *) NULL) 800 { 801 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 802 goto cleanup; 803 } 804 805 if (ALIGNED(filteredPixels,CLPixelPacket)) 806 { 807 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 808 hostPtr = filteredPixels; 809 } 810 else 811 { 812 mem_flags = CL_MEM_WRITE_ONLY; 813 hostPtr = NULL; 814 } 815 /* create a CL buffer from image pixel buffer */ 816 length = inputImage->columns * inputImage->rows; 817 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 818 if (clStatus != CL_SUCCESS) 819 { 820 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 821 goto cleanup; 822 } 823 } 824 825 /* create processing kernel */ 826 { 827 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma); 828 kernel=AcquireKernelInfo(geometry); 829 if (kernel == (KernelInfo *) NULL) 830 { 831 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.","."); 832 goto cleanup; 833 } 834 835 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernel->width * sizeof(float), NULL, &clStatus); 836 if (clStatus != CL_SUCCESS) 837 { 838 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 839 goto cleanup; 840 } 841 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus); 842 if (clStatus != CL_SUCCESS) 843 { 844 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 845 goto cleanup; 846 } 847 848 for (i = 0; i < kernel->width; i++) 849 { 850 kernelBufferPtr[i] = (float) kernel->values[i]; 851 } 852 853 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL); 854 if (clStatus != CL_SUCCESS) 855 { 856 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 857 goto cleanup; 858 } 859 } 860 861 { 862 863 /* create temp buffer */ 864 { 865 length = inputImage->columns * inputImage->rows; 866 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus); 867 if (clStatus != CL_SUCCESS) 868 { 869 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 870 goto cleanup; 871 } 872 } 873 874 /* get the OpenCL kernels */ 875 { 876 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow"); 877 if (blurRowKernel == NULL) 878 { 879 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 880 goto cleanup; 881 }; 882 883 blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumn"); 884 if (blurColumnKernel == NULL) 885 { 886 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 887 goto cleanup; 888 }; 889 } 890 891 { 892 /* need logic to decide this value */ 893 int chunkSize = 256; 894 895 { 896 imageColumns = inputImage->columns; 897 imageRows = inputImage->rows; 898 899 /* set the kernel arguments */ 900 i = 0; 901 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 902 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 903 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel); 904 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 905 kernelWidth = kernel->width; 906 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 907 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 908 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows); 909 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL); 910 if (clStatus != CL_SUCCESS) 911 { 912 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 913 goto cleanup; 914 } 915 } 916 917 /* launch the kernel */ 918 { 919 size_t gsize[2]; 920 size_t wsize[2]; 921 922 gsize[0] = chunkSize*((inputImage->columns+chunkSize-1)/chunkSize); 923 gsize[1] = inputImage->rows; 924 wsize[0] = chunkSize; 925 wsize[1] = 1; 926 927 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 928 if (clStatus != CL_SUCCESS) 929 { 930 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 931 goto cleanup; 932 } 933 clEnv->library->clFlush(queue); 934 } 935 } 936 937 { 938 /* need logic to decide this value */ 939 int chunkSize = 256; 940 941 { 942 imageColumns = inputImage->columns; 943 imageRows = inputImage->rows; 944 945 /* set the kernel arguments */ 946 i = 0; 947 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 948 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 949 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel); 950 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 951 kernelWidth = kernel->width; 952 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 953 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 954 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows); 955 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL); 956 if (clStatus != CL_SUCCESS) 957 { 958 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 959 goto cleanup; 960 } 961 } 962 963 /* launch the kernel */ 964 { 965 size_t gsize[2]; 966 size_t wsize[2]; 967 968 gsize[0] = inputImage->columns; 969 gsize[1] = chunkSize*((inputImage->rows+chunkSize-1)/chunkSize); 970 wsize[0] = 1; 971 wsize[1] = chunkSize; 972 973 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 974 if (clStatus != CL_SUCCESS) 975 { 976 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 977 goto cleanup; 978 } 979 clEnv->library->clFlush(queue); 980 } 981 } 982 983 } 984 985 /* get result */ 986 if (ALIGNED(filteredPixels,CLPixelPacket)) 987 { 988 length = inputImage->columns * inputImage->rows; 989 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 990 } 991 else 992 { 993 length = inputImage->columns * inputImage->rows; 994 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 995 } 996 if (clStatus != CL_SUCCESS) 997 { 998 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 999 goto cleanup; 1000 } 1001 1002 outputReady = MagickTrue; 1003 1004cleanup: 1005 OpenCLLogException(__FUNCTION__,__LINE__,exception); 1006 1007 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 1008 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer); 1009 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 1010 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer); 1011 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel); 1012 if (blurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurColumnKernel); 1013 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 1014 if (kernel!=NULL) DestroyKernelInfo(kernel); 1015 if (outputReady == MagickFalse) 1016 { 1017 if (filteredImage != NULL) 1018 { 1019 DestroyImage(filteredImage); 1020 filteredImage = NULL; 1021 } 1022 } 1023 return filteredImage; 1024} 1025 1026static Image* ComputeBlurImageSection(const Image* inputImage, const ChannelType channel, const double radius, const double sigma, ExceptionInfo *exception) 1027{ 1028 MagickBooleanType outputReady; 1029 Image* filteredImage; 1030 MagickCLEnv clEnv; 1031 1032 cl_int clStatus; 1033 1034 const void *inputPixels; 1035 void *filteredPixels; 1036 cl_mem_flags mem_flags; 1037 1038 cl_context context; 1039 cl_mem inputImageBuffer, tempImageBuffer, filteredImageBuffer, imageKernelBuffer; 1040 cl_kernel blurRowKernel, blurColumnKernel; 1041 cl_command_queue queue; 1042 1043 void* hostPtr; 1044 float* kernelBufferPtr; 1045 MagickSizeType length; 1046 1047 char geometry[MaxTextExtent]; 1048 KernelInfo* kernel = NULL; 1049 unsigned int kernelWidth; 1050 unsigned int imageColumns, imageRows; 1051 1052 unsigned int i; 1053 1054 context = NULL; 1055 filteredImage = NULL; 1056 inputImageBuffer = NULL; 1057 tempImageBuffer = NULL; 1058 filteredImageBuffer = NULL; 1059 imageKernelBuffer = NULL; 1060 blurRowKernel = NULL; 1061 blurColumnKernel = NULL; 1062 queue = NULL; 1063 1064 outputReady = MagickFalse; 1065 1066 clEnv = GetDefaultOpenCLEnv(); 1067 context = GetOpenCLContext(clEnv); 1068 queue = AcquireOpenCLCommandQueue(clEnv); 1069 1070 /* Create and initialize OpenCL buffers. */ 1071 { 1072 inputPixels = NULL; 1073 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 1074 if (inputPixels == (const void *) NULL) 1075 { 1076 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 1077 goto cleanup; 1078 } 1079 /* If the host pointer is aligned to the size of CLPixelPacket, 1080 then use the host buffer directly from the GPU; otherwise, 1081 create a buffer on the GPU and copy the data over */ 1082 if (ALIGNED(inputPixels,CLPixelPacket)) 1083 { 1084 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 1085 } 1086 else 1087 { 1088 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 1089 } 1090 /* create a CL buffer from image pixel buffer */ 1091 length = inputImage->columns * inputImage->rows; 1092 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 1093 if (clStatus != CL_SUCCESS) 1094 { 1095 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1096 goto cleanup; 1097 } 1098 } 1099 1100 /* create output */ 1101 { 1102 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 1103 assert(filteredImage != NULL); 1104 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 1105 { 1106 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 1107 goto cleanup; 1108 } 1109 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 1110 if (filteredPixels == (void *) NULL) 1111 { 1112 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 1113 goto cleanup; 1114 } 1115 1116 if (ALIGNED(filteredPixels,CLPixelPacket)) 1117 { 1118 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 1119 hostPtr = filteredPixels; 1120 } 1121 else 1122 { 1123 mem_flags = CL_MEM_WRITE_ONLY; 1124 hostPtr = NULL; 1125 } 1126 /* create a CL buffer from image pixel buffer */ 1127 length = inputImage->columns * inputImage->rows; 1128 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 1129 if (clStatus != CL_SUCCESS) 1130 { 1131 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1132 goto cleanup; 1133 } 1134 } 1135 1136 /* create processing kernel */ 1137 { 1138 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma); 1139 kernel=AcquireKernelInfo(geometry); 1140 if (kernel == (KernelInfo *) NULL) 1141 { 1142 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.","."); 1143 goto cleanup; 1144 } 1145 1146 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernel->width * sizeof(float), NULL, &clStatus); 1147 if (clStatus != CL_SUCCESS) 1148 { 1149 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1150 goto cleanup; 1151 } 1152 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus); 1153 if (clStatus != CL_SUCCESS) 1154 { 1155 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 1156 goto cleanup; 1157 } 1158 1159 for (i = 0; i < kernel->width; i++) 1160 { 1161 kernelBufferPtr[i] = (float) kernel->values[i]; 1162 } 1163 1164 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL); 1165 if (clStatus != CL_SUCCESS) 1166 { 1167 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 1168 goto cleanup; 1169 } 1170 } 1171 1172 { 1173 unsigned int offsetRows; 1174 unsigned int sec; 1175 1176 /* create temp buffer */ 1177 { 1178 length = inputImage->columns * (inputImage->rows / 2 + 1 + (kernel->width-1) / 2); 1179 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus); 1180 if (clStatus != CL_SUCCESS) 1181 { 1182 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1183 goto cleanup; 1184 } 1185 } 1186 1187 /* get the OpenCL kernels */ 1188 { 1189 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection"); 1190 if (blurRowKernel == NULL) 1191 { 1192 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 1193 goto cleanup; 1194 }; 1195 1196 blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumnSection"); 1197 if (blurColumnKernel == NULL) 1198 { 1199 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 1200 goto cleanup; 1201 }; 1202 } 1203 1204 for (sec = 0; sec < 2; sec++) 1205 { 1206 { 1207 /* need logic to decide this value */ 1208 int chunkSize = 256; 1209 1210 { 1211 imageColumns = inputImage->columns; 1212 if (sec == 0) 1213 imageRows = inputImage->rows / 2 + (kernel->width-1) / 2; 1214 else 1215 imageRows = (inputImage->rows - inputImage->rows / 2) + (kernel->width-1) / 2; 1216 1217 offsetRows = sec * inputImage->rows / 2; 1218 1219 kernelWidth = kernel->width; 1220 1221 /* set the kernel arguments */ 1222 i = 0; 1223 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 1224 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 1225 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel); 1226 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 1227 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 1228 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 1229 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows); 1230 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL); 1231 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows); 1232 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec); 1233 if (clStatus != CL_SUCCESS) 1234 { 1235 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 1236 goto cleanup; 1237 } 1238 } 1239 1240 /* launch the kernel */ 1241 { 1242 size_t gsize[2]; 1243 size_t wsize[2]; 1244 1245 gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize); 1246 gsize[1] = imageRows; 1247 wsize[0] = chunkSize; 1248 wsize[1] = 1; 1249 1250 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 1251 if (clStatus != CL_SUCCESS) 1252 { 1253 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 1254 goto cleanup; 1255 } 1256 clEnv->library->clFlush(queue); 1257 } 1258 } 1259 1260 { 1261 /* need logic to decide this value */ 1262 int chunkSize = 256; 1263 1264 { 1265 imageColumns = inputImage->columns; 1266 if (sec == 0) 1267 imageRows = inputImage->rows / 2; 1268 else 1269 imageRows = (inputImage->rows - inputImage->rows / 2); 1270 1271 offsetRows = sec * inputImage->rows / 2; 1272 1273 kernelWidth = kernel->width; 1274 1275 /* set the kernel arguments */ 1276 i = 0; 1277 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 1278 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 1279 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel); 1280 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 1281 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 1282 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 1283 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows); 1284 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL); 1285 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows); 1286 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&sec); 1287 if (clStatus != CL_SUCCESS) 1288 { 1289 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 1290 goto cleanup; 1291 } 1292 } 1293 1294 /* launch the kernel */ 1295 { 1296 size_t gsize[2]; 1297 size_t wsize[2]; 1298 1299 gsize[0] = imageColumns; 1300 gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize); 1301 wsize[0] = 1; 1302 wsize[1] = chunkSize; 1303 1304 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 1305 if (clStatus != CL_SUCCESS) 1306 { 1307 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 1308 goto cleanup; 1309 } 1310 clEnv->library->clFlush(queue); 1311 } 1312 } 1313 } 1314 1315 } 1316 1317 /* get result */ 1318 if (ALIGNED(filteredPixels,CLPixelPacket)) 1319 { 1320 length = inputImage->columns * inputImage->rows; 1321 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 1322 } 1323 else 1324 { 1325 length = inputImage->columns * inputImage->rows; 1326 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 1327 } 1328 if (clStatus != CL_SUCCESS) 1329 { 1330 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 1331 goto cleanup; 1332 } 1333 1334 outputReady = MagickTrue; 1335 1336cleanup: 1337 OpenCLLogException(__FUNCTION__,__LINE__,exception); 1338 1339 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 1340 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer); 1341 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 1342 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer); 1343 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel); 1344 if (blurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurColumnKernel); 1345 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 1346 if (kernel!=NULL) DestroyKernelInfo(kernel); 1347 if (outputReady == MagickFalse) 1348 { 1349 if (filteredImage != NULL) 1350 { 1351 DestroyImage(filteredImage); 1352 filteredImage = NULL; 1353 } 1354 } 1355 return filteredImage; 1356} 1357 1358/* 1359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1360% % 1361% % 1362% % 1363% B l u r I m a g e w i t h O p e n C L % 1364% % 1365% % 1366% % 1367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1368% 1369% BlurImage() blurs an image. We convolve the image with a Gaussian operator 1370% of the given radius and standard deviation (sigma). For reasonable results, 1371% the radius should be larger than sigma. Use a radius of 0 and BlurImage() 1372% selects a suitable radius for you. 1373% 1374% The format of the BlurImage method is: 1375% 1376% Image *BlurImage(const Image *image,const double radius, 1377% const double sigma,ExceptionInfo *exception) 1378% Image *BlurImageChannel(const Image *image,const ChannelType channel, 1379% const double radius,const double sigma,ExceptionInfo *exception) 1380% 1381% A description of each parameter follows: 1382% 1383% o image: the image. 1384% 1385% o channel: the channel type. 1386% 1387% o radius: the radius of the Gaussian, in pixels, not counting the center 1388% pixel. 1389% 1390% o sigma: the standard deviation of the Gaussian, in pixels. 1391% 1392% o exception: return any errors or warnings in this structure. 1393% 1394*/ 1395 1396MagickExport 1397Image* AccelerateBlurImage(const Image *image, const ChannelType channel, const double radius, const double sigma,ExceptionInfo *exception) 1398{ 1399 MagickBooleanType status; 1400 Image* filteredImage = NULL; 1401 1402 assert(image != NULL); 1403 assert(exception != (ExceptionInfo *) NULL); 1404 1405 status = checkOpenCLEnvironment(exception); 1406 if (status == MagickFalse) 1407 return NULL; 1408 1409 status = checkAccelerateCondition(image, channel); 1410 if (status == MagickFalse) 1411 return NULL; 1412 1413 if (splitImage(image) && (image->rows / 2 > radius)) 1414 filteredImage = ComputeBlurImageSection(image, channel, radius, sigma, exception); 1415 else 1416 filteredImage = ComputeBlurImage(image, channel, radius, sigma, exception); 1417 1418 return filteredImage; 1419} 1420 1421 1422static Image* ComputeRadialBlurImage(const Image *inputImage, const ChannelType channel, const double angle, ExceptionInfo *exception) 1423{ 1424 1425 MagickBooleanType outputReady; 1426 Image* filteredImage; 1427 MagickCLEnv clEnv; 1428 1429 cl_int clStatus; 1430 size_t global_work_size[2]; 1431 1432 cl_context context; 1433 cl_mem_flags mem_flags; 1434 cl_mem inputImageBuffer, filteredImageBuffer, sinThetaBuffer, cosThetaBuffer; 1435 cl_kernel radialBlurKernel; 1436 cl_command_queue queue; 1437 1438 const void *inputPixels; 1439 void *filteredPixels; 1440 void* hostPtr; 1441 float* sinThetaPtr; 1442 float* cosThetaPtr; 1443 MagickSizeType length; 1444 unsigned int matte; 1445 MagickPixelPacket bias; 1446 cl_float4 biasPixel; 1447 cl_float2 blurCenter; 1448 float blurRadius; 1449 unsigned int cossin_theta_size; 1450 float offset, theta; 1451 1452 unsigned int i; 1453 1454 outputReady = MagickFalse; 1455 context = NULL; 1456 filteredImage = NULL; 1457 inputImageBuffer = NULL; 1458 filteredImageBuffer = NULL; 1459 sinThetaBuffer = NULL; 1460 cosThetaBuffer = NULL; 1461 queue = NULL; 1462 radialBlurKernel = NULL; 1463 1464 1465 clEnv = GetDefaultOpenCLEnv(); 1466 context = GetOpenCLContext(clEnv); 1467 1468 1469 /* Create and initialize OpenCL buffers. */ 1470 1471 inputPixels = NULL; 1472 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 1473 if (inputPixels == (const void *) NULL) 1474 { 1475 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 1476 goto cleanup; 1477 } 1478 1479 /* If the host pointer is aligned to the size of CLPixelPacket, 1480 then use the host buffer directly from the GPU; otherwise, 1481 create a buffer on the GPU and copy the data over */ 1482 if (ALIGNED(inputPixels,CLPixelPacket)) 1483 { 1484 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 1485 } 1486 else 1487 { 1488 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 1489 } 1490 /* create a CL buffer from image pixel buffer */ 1491 length = inputImage->columns * inputImage->rows; 1492 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 1493 if (clStatus != CL_SUCCESS) 1494 { 1495 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1496 goto cleanup; 1497 } 1498 1499 1500 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 1501 assert(filteredImage != NULL); 1502 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 1503 { 1504 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 1505 goto cleanup; 1506 } 1507 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 1508 if (filteredPixels == (void *) NULL) 1509 { 1510 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 1511 goto cleanup; 1512 } 1513 1514 if (ALIGNED(filteredPixels,CLPixelPacket)) 1515 { 1516 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 1517 hostPtr = filteredPixels; 1518 } 1519 else 1520 { 1521 mem_flags = CL_MEM_WRITE_ONLY; 1522 hostPtr = NULL; 1523 } 1524 /* create a CL buffer from image pixel buffer */ 1525 length = inputImage->columns * inputImage->rows; 1526 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 1527 if (clStatus != CL_SUCCESS) 1528 { 1529 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1530 goto cleanup; 1531 } 1532 1533 blurCenter.s[0] = (float) (inputImage->columns-1)/2.0; 1534 blurCenter.s[1] = (float) (inputImage->rows-1)/2.0; 1535 blurRadius=hypot(blurCenter.s[0],blurCenter.s[1]); 1536 cossin_theta_size=(unsigned int) fabs(4.0*DegreesToRadians(angle)*sqrt((double)blurRadius)+2UL); 1537 1538 /* create a buffer for sin_theta and cos_theta */ 1539 sinThetaBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, cossin_theta_size * sizeof(float), NULL, &clStatus); 1540 if (clStatus != CL_SUCCESS) 1541 { 1542 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1543 goto cleanup; 1544 } 1545 cosThetaBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, cossin_theta_size * sizeof(float), NULL, &clStatus); 1546 if (clStatus != CL_SUCCESS) 1547 { 1548 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1549 goto cleanup; 1550 } 1551 1552 1553 queue = AcquireOpenCLCommandQueue(clEnv); 1554 sinThetaPtr = (float*) clEnv->library->clEnqueueMapBuffer(queue, sinThetaBuffer, CL_TRUE, CL_MAP_WRITE, 0, cossin_theta_size*sizeof(float), 0, NULL, NULL, &clStatus); 1555 if (clStatus != CL_SUCCESS) 1556 { 1557 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.","."); 1558 goto cleanup; 1559 } 1560 1561 cosThetaPtr = (float*) clEnv->library->clEnqueueMapBuffer(queue, cosThetaBuffer, CL_TRUE, CL_MAP_WRITE, 0, cossin_theta_size*sizeof(float), 0, NULL, NULL, &clStatus); 1562 if (clStatus != CL_SUCCESS) 1563 { 1564 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.","."); 1565 goto cleanup; 1566 } 1567 1568 theta=DegreesToRadians(angle)/(MagickRealType) (cossin_theta_size-1); 1569 offset=theta*(MagickRealType) (cossin_theta_size-1)/2.0; 1570 for (i=0; i < (ssize_t) cossin_theta_size; i++) 1571 { 1572 cosThetaPtr[i]=(float)cos((double) (theta*i-offset)); 1573 sinThetaPtr[i]=(float)sin((double) (theta*i-offset)); 1574 } 1575 1576 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, sinThetaBuffer, sinThetaPtr, 0, NULL, NULL); 1577 clStatus |= clEnv->library->clEnqueueUnmapMemObject(queue, cosThetaBuffer, cosThetaPtr, 0, NULL, NULL); 1578 if (clStatus != CL_SUCCESS) 1579 { 1580 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 1581 goto cleanup; 1582 } 1583 1584 /* get the OpenCL kernel */ 1585 radialBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RadialBlur"); 1586 if (radialBlurKernel == NULL) 1587 { 1588 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 1589 goto cleanup; 1590 } 1591 1592 1593 /* set the kernel arguments */ 1594 i = 0; 1595 clStatus=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 1596 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 1597 1598 GetMagickPixelPacket(inputImage,&bias); 1599 biasPixel.s[0] = bias.red; 1600 biasPixel.s[1] = bias.green; 1601 biasPixel.s[2] = bias.blue; 1602 biasPixel.s[3] = bias.opacity; 1603 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_float4), &biasPixel); 1604 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(ChannelType), &channel); 1605 1606 matte = (inputImage->matte != MagickFalse)?1:0; 1607 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(unsigned int), &matte); 1608 1609 clStatus=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_float2), &blurCenter); 1610 1611 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&cosThetaBuffer); 1612 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(cl_mem),(void *)&sinThetaBuffer); 1613 clStatus|=clEnv->library->clSetKernelArg(radialBlurKernel,i++,sizeof(unsigned int), &cossin_theta_size); 1614 if (clStatus != CL_SUCCESS) 1615 { 1616 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 1617 goto cleanup; 1618 } 1619 1620 1621 global_work_size[0] = inputImage->columns; 1622 global_work_size[1] = inputImage->rows; 1623 /* launch the kernel */ 1624 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, radialBlurKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 1625 if (clStatus != CL_SUCCESS) 1626 { 1627 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 1628 goto cleanup; 1629 } 1630 clEnv->library->clFlush(queue); 1631 1632 if (ALIGNED(filteredPixels,CLPixelPacket)) 1633 { 1634 length = inputImage->columns * inputImage->rows; 1635 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 1636 } 1637 else 1638 { 1639 length = inputImage->columns * inputImage->rows; 1640 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 1641 } 1642 if (clStatus != CL_SUCCESS) 1643 { 1644 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 1645 goto cleanup; 1646 } 1647 outputReady = MagickTrue; 1648 1649cleanup: 1650 OpenCLLogException(__FUNCTION__,__LINE__,exception); 1651 1652 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 1653 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 1654 if (sinThetaBuffer!=NULL) clEnv->library->clReleaseMemObject(sinThetaBuffer); 1655 if (cosThetaBuffer!=NULL) clEnv->library->clReleaseMemObject(cosThetaBuffer); 1656 if (radialBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, radialBlurKernel); 1657 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 1658 if (outputReady == MagickFalse) 1659 { 1660 if (filteredImage != NULL) 1661 { 1662 DestroyImage(filteredImage); 1663 filteredImage = NULL; 1664 } 1665 } 1666 return filteredImage; 1667} 1668 1669/* 1670%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1671% % 1672% % 1673% % 1674% R a d i a l B l u r I m a g e w i t h O p e n C L % 1675% % 1676% % 1677% % 1678%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1679% 1680% RadialBlurImage() applies a radial blur to the image. 1681% 1682% Andrew Protano contributed this effect. 1683% 1684% The format of the RadialBlurImage method is: 1685% 1686% Image *RadialBlurImage(const Image *image,const double angle, 1687% ExceptionInfo *exception) 1688% Image *RadialBlurImageChannel(const Image *image,const ChannelType channel, 1689% const double angle,ExceptionInfo *exception) 1690% 1691% A description of each parameter follows: 1692% 1693% o image: the image. 1694% 1695% o channel: the channel type. 1696% 1697% o angle: the angle of the radial blur. 1698% 1699% o exception: return any errors or warnings in this structure. 1700% 1701*/ 1702 1703MagickExport 1704Image* AccelerateRadialBlurImage(const Image *image, const ChannelType channel, const double angle, ExceptionInfo *exception) 1705{ 1706 MagickBooleanType status; 1707 Image* filteredImage; 1708 1709 1710 assert(image != NULL); 1711 assert(exception != NULL); 1712 1713 status = checkOpenCLEnvironment(exception); 1714 if (status == MagickFalse) 1715 return NULL; 1716 1717 status = checkAccelerateCondition(image, channel); 1718 if (status == MagickFalse) 1719 return NULL; 1720 1721 filteredImage = ComputeRadialBlurImage(image, channel, angle, exception); 1722 return filteredImage; 1723} 1724 1725 1726 1727static Image* ComputeUnsharpMaskImage(const Image *inputImage, const ChannelType channel,const double radius,const double sigma, 1728 const double gain,const double threshold,ExceptionInfo *exception) 1729{ 1730 MagickBooleanType outputReady = MagickFalse; 1731 Image* filteredImage = NULL; 1732 MagickCLEnv clEnv = NULL; 1733 1734 cl_int clStatus; 1735 1736 const void *inputPixels; 1737 void *filteredPixels; 1738 cl_mem_flags mem_flags; 1739 1740 KernelInfo *kernel = NULL; 1741 char geometry[MaxTextExtent]; 1742 1743 cl_context context = NULL; 1744 cl_mem inputImageBuffer = NULL; 1745 cl_mem filteredImageBuffer = NULL; 1746 cl_mem tempImageBuffer = NULL; 1747 cl_mem imageKernelBuffer = NULL; 1748 cl_kernel blurRowKernel = NULL; 1749 cl_kernel unsharpMaskBlurColumnKernel = NULL; 1750 cl_command_queue queue = NULL; 1751 1752 void* hostPtr; 1753 float* kernelBufferPtr; 1754 MagickSizeType length; 1755 unsigned int kernelWidth; 1756 float fGain; 1757 float fThreshold; 1758 unsigned int imageColumns, imageRows; 1759 int chunkSize; 1760 unsigned int i; 1761 1762 clEnv = GetDefaultOpenCLEnv(); 1763 context = GetOpenCLContext(clEnv); 1764 queue = AcquireOpenCLCommandQueue(clEnv); 1765 1766 /* Create and initialize OpenCL buffers. */ 1767 { 1768 inputPixels = NULL; 1769 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 1770 if (inputPixels == (const void *) NULL) 1771 { 1772 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 1773 goto cleanup; 1774 } 1775 1776 /* If the host pointer is aligned to the size of CLPixelPacket, 1777 then use the host buffer directly from the GPU; otherwise, 1778 create a buffer on the GPU and copy the data over */ 1779 if (ALIGNED(inputPixels,CLPixelPacket)) 1780 { 1781 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 1782 } 1783 else 1784 { 1785 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 1786 } 1787 /* create a CL buffer from image pixel buffer */ 1788 length = inputImage->columns * inputImage->rows; 1789 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 1790 if (clStatus != CL_SUCCESS) 1791 { 1792 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1793 goto cleanup; 1794 } 1795 } 1796 1797 /* create output */ 1798 { 1799 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 1800 assert(filteredImage != NULL); 1801 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 1802 { 1803 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 1804 goto cleanup; 1805 } 1806 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 1807 if (filteredPixels == (void *) NULL) 1808 { 1809 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 1810 goto cleanup; 1811 } 1812 1813 if (ALIGNED(filteredPixels,CLPixelPacket)) 1814 { 1815 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 1816 hostPtr = filteredPixels; 1817 } 1818 else 1819 { 1820 mem_flags = CL_MEM_WRITE_ONLY; 1821 hostPtr = NULL; 1822 } 1823 1824 /* create a CL buffer from image pixel buffer */ 1825 length = inputImage->columns * inputImage->rows; 1826 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 1827 if (clStatus != CL_SUCCESS) 1828 { 1829 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1830 goto cleanup; 1831 } 1832 } 1833 1834 /* create the blur kernel */ 1835 { 1836 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma); 1837 kernel=AcquireKernelInfo(geometry); 1838 if (kernel == (KernelInfo *) NULL) 1839 { 1840 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.","."); 1841 goto cleanup; 1842 } 1843 1844 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus); 1845 if (clStatus != CL_SUCCESS) 1846 { 1847 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1848 goto cleanup; 1849 } 1850 1851 1852 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus); 1853 if (clStatus != CL_SUCCESS) 1854 { 1855 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 1856 goto cleanup; 1857 } 1858 for (i = 0; i < kernel->width; i++) 1859 { 1860 kernelBufferPtr[i] = (float) kernel->values[i]; 1861 } 1862 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL); 1863 if (clStatus != CL_SUCCESS) 1864 { 1865 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 1866 goto cleanup; 1867 } 1868 } 1869 1870 { 1871 /* create temp buffer */ 1872 { 1873 length = inputImage->columns * inputImage->rows; 1874 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus); 1875 if (clStatus != CL_SUCCESS) 1876 { 1877 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 1878 goto cleanup; 1879 } 1880 } 1881 1882 /* get the opencl kernel */ 1883 { 1884 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow"); 1885 if (blurRowKernel == NULL) 1886 { 1887 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 1888 goto cleanup; 1889 }; 1890 1891 unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumn"); 1892 if (unsharpMaskBlurColumnKernel == NULL) 1893 { 1894 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 1895 goto cleanup; 1896 }; 1897 } 1898 1899 { 1900 chunkSize = 256; 1901 1902 imageColumns = inputImage->columns; 1903 imageRows = inputImage->rows; 1904 1905 kernelWidth = kernel->width; 1906 1907 /* set the kernel arguments */ 1908 i = 0; 1909 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 1910 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 1911 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel); 1912 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 1913 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 1914 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 1915 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows); 1916 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL); 1917 if (clStatus != CL_SUCCESS) 1918 { 1919 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 1920 goto cleanup; 1921 } 1922 } 1923 1924 /* launch the kernel */ 1925 { 1926 size_t gsize[2]; 1927 size_t wsize[2]; 1928 1929 gsize[0] = chunkSize*((inputImage->columns+chunkSize-1)/chunkSize); 1930 gsize[1] = inputImage->rows; 1931 wsize[0] = chunkSize; 1932 wsize[1] = 1; 1933 1934 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 1935 if (clStatus != CL_SUCCESS) 1936 { 1937 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 1938 goto cleanup; 1939 } 1940 clEnv->library->clFlush(queue); 1941 } 1942 1943 1944 { 1945 chunkSize = 256; 1946 imageColumns = inputImage->columns; 1947 imageRows = inputImage->rows; 1948 kernelWidth = kernel->width; 1949 fGain = (float)gain; 1950 fThreshold = (float)threshold; 1951 1952 i = 0; 1953 clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 1954 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 1955 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 1956 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 1957 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows); 1958 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL); 1959 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL); 1960 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel); 1961 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 1962 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 1963 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain); 1964 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold); 1965 1966 if (clStatus != CL_SUCCESS) 1967 { 1968 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 1969 goto cleanup; 1970 } 1971 } 1972 1973 /* launch the kernel */ 1974 { 1975 size_t gsize[2]; 1976 size_t wsize[2]; 1977 1978 gsize[0] = inputImage->columns; 1979 gsize[1] = chunkSize*((inputImage->rows+chunkSize-1)/chunkSize); 1980 wsize[0] = 1; 1981 wsize[1] = chunkSize; 1982 1983 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 1984 if (clStatus != CL_SUCCESS) 1985 { 1986 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 1987 goto cleanup; 1988 } 1989 clEnv->library->clFlush(queue); 1990 } 1991 1992 } 1993 1994 /* get result */ 1995 if (ALIGNED(filteredPixels,CLPixelPacket)) 1996 { 1997 length = inputImage->columns * inputImage->rows; 1998 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 1999 } 2000 else 2001 { 2002 length = inputImage->columns * inputImage->rows; 2003 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 2004 } 2005 if (clStatus != CL_SUCCESS) 2006 { 2007 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 2008 goto cleanup; 2009 } 2010 2011 outputReady = MagickTrue; 2012 2013cleanup: 2014 OpenCLLogException(__FUNCTION__,__LINE__,exception); 2015 2016 if (kernel != NULL) kernel=DestroyKernelInfo(kernel); 2017 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 2018 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 2019 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer); 2020 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer); 2021 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel); 2022 if (unsharpMaskBlurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel); 2023 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 2024 if (outputReady == MagickFalse) 2025 { 2026 if (filteredImage != NULL) 2027 { 2028 DestroyImage(filteredImage); 2029 filteredImage = NULL; 2030 } 2031 } 2032 return filteredImage; 2033} 2034 2035 2036static Image* ComputeUnsharpMaskImageSection(const Image *inputImage, const ChannelType channel,const double radius,const double sigma, 2037 const double gain,const double threshold,ExceptionInfo *exception) 2038{ 2039 MagickBooleanType outputReady = MagickFalse; 2040 Image* filteredImage = NULL; 2041 MagickCLEnv clEnv = NULL; 2042 2043 cl_int clStatus; 2044 2045 const void *inputPixels; 2046 void *filteredPixels; 2047 cl_mem_flags mem_flags; 2048 2049 KernelInfo *kernel = NULL; 2050 char geometry[MaxTextExtent]; 2051 2052 cl_context context = NULL; 2053 cl_mem inputImageBuffer = NULL; 2054 cl_mem filteredImageBuffer = NULL; 2055 cl_mem tempImageBuffer = NULL; 2056 cl_mem imageKernelBuffer = NULL; 2057 cl_kernel blurRowKernel = NULL; 2058 cl_kernel unsharpMaskBlurColumnKernel = NULL; 2059 cl_command_queue queue = NULL; 2060 2061 void* hostPtr; 2062 float* kernelBufferPtr; 2063 MagickSizeType length; 2064 unsigned int kernelWidth; 2065 float fGain; 2066 float fThreshold; 2067 unsigned int imageColumns, imageRows; 2068 int chunkSize; 2069 unsigned int i; 2070 2071 clEnv = GetDefaultOpenCLEnv(); 2072 context = GetOpenCLContext(clEnv); 2073 queue = AcquireOpenCLCommandQueue(clEnv); 2074 2075 /* Create and initialize OpenCL buffers. */ 2076 { 2077 inputPixels = NULL; 2078 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 2079 if (inputPixels == (const void *) NULL) 2080 { 2081 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 2082 goto cleanup; 2083 } 2084 2085 /* If the host pointer is aligned to the size of CLPixelPacket, 2086 then use the host buffer directly from the GPU; otherwise, 2087 create a buffer on the GPU and copy the data over */ 2088 if (ALIGNED(inputPixels,CLPixelPacket)) 2089 { 2090 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 2091 } 2092 else 2093 { 2094 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 2095 } 2096 /* create a CL buffer from image pixel buffer */ 2097 length = inputImage->columns * inputImage->rows; 2098 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 2099 if (clStatus != CL_SUCCESS) 2100 { 2101 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2102 goto cleanup; 2103 } 2104 } 2105 2106 /* create output */ 2107 { 2108 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 2109 assert(filteredImage != NULL); 2110 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 2111 { 2112 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 2113 goto cleanup; 2114 } 2115 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 2116 if (filteredPixels == (void *) NULL) 2117 { 2118 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 2119 goto cleanup; 2120 } 2121 2122 if (ALIGNED(filteredPixels,CLPixelPacket)) 2123 { 2124 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 2125 hostPtr = filteredPixels; 2126 } 2127 else 2128 { 2129 mem_flags = CL_MEM_WRITE_ONLY; 2130 hostPtr = NULL; 2131 } 2132 2133 /* create a CL buffer from image pixel buffer */ 2134 length = inputImage->columns * inputImage->rows; 2135 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 2136 if (clStatus != CL_SUCCESS) 2137 { 2138 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2139 goto cleanup; 2140 } 2141 } 2142 2143 /* create the blur kernel */ 2144 { 2145 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma); 2146 kernel=AcquireKernelInfo(geometry); 2147 if (kernel == (KernelInfo *) NULL) 2148 { 2149 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.","."); 2150 goto cleanup; 2151 } 2152 2153 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus); 2154 if (clStatus != CL_SUCCESS) 2155 { 2156 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2157 goto cleanup; 2158 } 2159 2160 2161 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus); 2162 if (clStatus != CL_SUCCESS) 2163 { 2164 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 2165 goto cleanup; 2166 } 2167 for (i = 0; i < kernel->width; i++) 2168 { 2169 kernelBufferPtr[i] = (float) kernel->values[i]; 2170 } 2171 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL); 2172 if (clStatus != CL_SUCCESS) 2173 { 2174 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 2175 goto cleanup; 2176 } 2177 } 2178 2179 { 2180 unsigned int offsetRows; 2181 unsigned int sec; 2182 2183 /* create temp buffer */ 2184 { 2185 length = inputImage->columns * (inputImage->rows / 2 + 1 + (kernel->width-1) / 2); 2186 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus); 2187 if (clStatus != CL_SUCCESS) 2188 { 2189 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2190 goto cleanup; 2191 } 2192 } 2193 2194 /* get the opencl kernel */ 2195 { 2196 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection"); 2197 if (blurRowKernel == NULL) 2198 { 2199 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 2200 goto cleanup; 2201 }; 2202 2203 unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumnSection"); 2204 if (unsharpMaskBlurColumnKernel == NULL) 2205 { 2206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 2207 goto cleanup; 2208 }; 2209 } 2210 2211 for (sec = 0; sec < 2; sec++) 2212 { 2213 { 2214 chunkSize = 256; 2215 2216 imageColumns = inputImage->columns; 2217 if (sec == 0) 2218 imageRows = inputImage->rows / 2 + (kernel->width-1) / 2; 2219 else 2220 imageRows = (inputImage->rows - inputImage->rows / 2) + (kernel->width-1) / 2; 2221 2222 offsetRows = sec * inputImage->rows / 2; 2223 2224 kernelWidth = kernel->width; 2225 2226 /* set the kernel arguments */ 2227 i = 0; 2228 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 2229 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 2230 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel); 2231 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 2232 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 2233 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 2234 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows); 2235 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL); 2236 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows); 2237 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec); 2238 if (clStatus != CL_SUCCESS) 2239 { 2240 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 2241 goto cleanup; 2242 } 2243 } 2244 /* launch the kernel */ 2245 { 2246 size_t gsize[2]; 2247 size_t wsize[2]; 2248 2249 gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize); 2250 gsize[1] = imageRows; 2251 wsize[0] = chunkSize; 2252 wsize[1] = 1; 2253 2254 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 2255 if (clStatus != CL_SUCCESS) 2256 { 2257 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 2258 goto cleanup; 2259 } 2260 clEnv->library->clFlush(queue); 2261 } 2262 2263 2264 { 2265 chunkSize = 256; 2266 2267 imageColumns = inputImage->columns; 2268 if (sec == 0) 2269 imageRows = inputImage->rows / 2; 2270 else 2271 imageRows = (inputImage->rows - inputImage->rows / 2); 2272 2273 offsetRows = sec * inputImage->rows / 2; 2274 2275 kernelWidth = kernel->width; 2276 2277 fGain = (float)gain; 2278 fThreshold = (float)threshold; 2279 2280 i = 0; 2281 clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 2282 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer); 2283 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer); 2284 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns); 2285 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows); 2286 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL); 2287 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL); 2288 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel); 2289 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer); 2290 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth); 2291 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain); 2292 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold); 2293 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows); 2294 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&sec); 2295 2296 if (clStatus != CL_SUCCESS) 2297 { 2298 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 2299 goto cleanup; 2300 } 2301 } 2302 2303 /* launch the kernel */ 2304 { 2305 size_t gsize[2]; 2306 size_t wsize[2]; 2307 2308 gsize[0] = imageColumns; 2309 gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize); 2310 wsize[0] = 1; 2311 wsize[1] = chunkSize; 2312 2313 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL); 2314 if (clStatus != CL_SUCCESS) 2315 { 2316 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 2317 goto cleanup; 2318 } 2319 clEnv->library->clFlush(queue); 2320 } 2321 } 2322 } 2323 2324 /* get result */ 2325 if (ALIGNED(filteredPixels,CLPixelPacket)) 2326 { 2327 length = inputImage->columns * inputImage->rows; 2328 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 2329 } 2330 else 2331 { 2332 length = inputImage->columns * inputImage->rows; 2333 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 2334 } 2335 if (clStatus != CL_SUCCESS) 2336 { 2337 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 2338 goto cleanup; 2339 } 2340 2341 outputReady = MagickTrue; 2342 2343cleanup: 2344 OpenCLLogException(__FUNCTION__,__LINE__,exception); 2345 2346 if (kernel != NULL) kernel=DestroyKernelInfo(kernel); 2347 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 2348 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 2349 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer); 2350 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer); 2351 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel); 2352 if (unsharpMaskBlurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel); 2353 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 2354 if (outputReady == MagickFalse) 2355 { 2356 if (filteredImage != NULL) 2357 { 2358 DestroyImage(filteredImage); 2359 filteredImage = NULL; 2360 } 2361 } 2362 return filteredImage; 2363} 2364 2365 2366/* 2367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2368% % 2369% % 2370% % 2371% U n s h a r p M a s k I m a g e w i t h O p e n C L % 2372% % 2373% % 2374% % 2375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2376% 2377% UnsharpMaskImage() sharpens one or more image channels. We convolve the 2378% image with a Gaussian operator of the given radius and standard deviation 2379% (sigma). For reasonable results, radius should be larger than sigma. Use a 2380% radius of 0 and UnsharpMaskImage() selects a suitable radius for you. 2381% 2382% The format of the UnsharpMaskImage method is: 2383% 2384% Image *UnsharpMaskImage(const Image *image,const double radius, 2385% const double sigma,const double amount,const double threshold, 2386% ExceptionInfo *exception) 2387% Image *UnsharpMaskImageChannel(const Image *image, 2388% const ChannelType channel,const double radius,const double sigma, 2389% const double gain,const double threshold,ExceptionInfo *exception) 2390% 2391% A description of each parameter follows: 2392% 2393% o image: the image. 2394% 2395% o channel: the channel type. 2396% 2397% o radius: the radius of the Gaussian, in pixels, not counting the center 2398% pixel. 2399% 2400% o sigma: the standard deviation of the Gaussian, in pixels. 2401% 2402% o gain: the percentage of the difference between the original and the 2403% blur image that is added back into the original. 2404% 2405% o threshold: the threshold in pixels needed to apply the diffence gain. 2406% 2407% o exception: return any errors or warnings in this structure. 2408% 2409*/ 2410 2411 2412MagickExport 2413Image* AccelerateUnsharpMaskImage(const Image *image, const ChannelType channel,const double radius,const double sigma, 2414 const double gain,const double threshold,ExceptionInfo *exception) 2415{ 2416 MagickBooleanType status; 2417 Image* filteredImage; 2418 2419 2420 assert(image != NULL); 2421 assert(exception != NULL); 2422 2423 status = checkOpenCLEnvironment(exception); 2424 if (status == MagickFalse) 2425 return NULL; 2426 2427 status = checkAccelerateCondition(image, channel); 2428 if (status == MagickFalse) 2429 return NULL; 2430 2431 if (splitImage(image) && (image->rows / 2 > radius)) 2432 filteredImage = ComputeUnsharpMaskImageSection(image,channel,radius,sigma,gain,threshold,exception); 2433 else 2434 filteredImage = ComputeUnsharpMaskImage(image,channel,radius,sigma,gain,threshold,exception); 2435 return filteredImage; 2436 2437} 2438 2439static MagickBooleanType resizeHorizontalFilter(cl_mem inputImage 2440 , const unsigned int inputImageColumns, const unsigned int inputImageRows, const unsigned int matte 2441 , cl_mem resizedImage, const unsigned int resizedColumns, const unsigned int resizedRows 2442 , const ResizeFilter* resizeFilter, cl_mem resizeFilterCubicCoefficients, const float xFactor 2443 , MagickCLEnv clEnv, cl_command_queue queue, ExceptionInfo *exception) 2444{ 2445 MagickBooleanType status = MagickFalse; 2446 2447 float scale, support; 2448 unsigned int i; 2449 cl_kernel horizontalKernel = NULL; 2450 cl_int clStatus; 2451 size_t global_work_size[2]; 2452 size_t local_work_size[2]; 2453 int resizeFilterType, resizeWindowType; 2454 float resizeFilterScale, resizeFilterSupport, resizeFilterWindowSupport, resizeFilterBlur; 2455 size_t totalLocalMemorySize; 2456 size_t imageCacheLocalMemorySize, pixelAccumulatorLocalMemorySize 2457 , weightAccumulatorLocalMemorySize, gammaAccumulatorLocalMemorySize; 2458 size_t deviceLocalMemorySize; 2459 int cacheRangeStart, cacheRangeEnd, numCachedPixels; 2460 2461 const unsigned int workgroupSize = 256; 2462 unsigned int pixelPerWorkgroup; 2463 unsigned int chunkSize; 2464 2465 /* 2466 Apply filter to resize vertically from image to resize image. 2467 */ 2468 scale=MAGICK_MAX(1.0/xFactor+MagickEpsilon,1.0); 2469 support=scale*GetResizeFilterSupport(resizeFilter); 2470 if (support < 0.5) 2471 { 2472 /* 2473 Support too small even for nearest neighbour: Reduce to point 2474 sampling. 2475 */ 2476 support=(MagickRealType) 0.5; 2477 scale=1.0; 2478 } 2479 scale=PerceptibleReciprocal(scale); 2480 2481 if (resizedColumns < workgroupSize) 2482 { 2483 chunkSize = 32; 2484 pixelPerWorkgroup = 32; 2485 } 2486 else 2487 { 2488 chunkSize = workgroupSize; 2489 pixelPerWorkgroup = workgroupSize; 2490 } 2491 2492 /* get the local memory size supported by the device */ 2493 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv); 2494 2495DisableMSCWarning(4127) 2496 while(1) 2497RestoreMSCWarning 2498 { 2499 /* calculate the local memory size needed per workgroup */ 2500 cacheRangeStart = (int) (((0 + 0.5)/xFactor+MagickEpsilon)-support+0.5); 2501 cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/xFactor+MagickEpsilon)+support+0.5); 2502 numCachedPixels = cacheRangeEnd - cacheRangeStart + 1; 2503 imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket); 2504 totalLocalMemorySize = imageCacheLocalMemorySize; 2505 2506 /* local size for the pixel accumulator */ 2507 pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4); 2508 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize; 2509 2510 /* local memory size for the weight accumulator */ 2511 weightAccumulatorLocalMemorySize = chunkSize * sizeof(float); 2512 totalLocalMemorySize+=weightAccumulatorLocalMemorySize; 2513 2514 /* local memory size for the gamma accumulator */ 2515 if (matte == 0) 2516 gammaAccumulatorLocalMemorySize = sizeof(float); 2517 else 2518 gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float); 2519 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize; 2520 2521 if (totalLocalMemorySize <= deviceLocalMemorySize) 2522 break; 2523 else 2524 { 2525 pixelPerWorkgroup = pixelPerWorkgroup/2; 2526 chunkSize = chunkSize/2; 2527 if (pixelPerWorkgroup == 0 2528 || chunkSize == 0) 2529 { 2530 /* quit, fallback to CPU */ 2531 goto cleanup; 2532 } 2533 } 2534 } 2535 2536 resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter); 2537 resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter); 2538 2539 2540 if (resizeFilterType == SincFastWeightingFunction 2541 && resizeWindowType == SincFastWeightingFunction) 2542 { 2543 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilterSinc"); 2544 } 2545 else 2546 { 2547 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilter"); 2548 } 2549 if (horizontalKernel == NULL) 2550 { 2551 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 2552 goto cleanup; 2553 } 2554 2555 i = 0; 2556 clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&inputImage); 2557 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageColumns); 2558 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageRows); 2559 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte); 2560 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&xFactor); 2561 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage); 2562 2563 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns); 2564 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows); 2565 2566 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType); 2567 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType); 2568 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients); 2569 2570 resizeFilterScale = (float) GetResizeFilterScale(resizeFilter); 2571 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale); 2572 2573 resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter); 2574 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport); 2575 2576 resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter); 2577 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport); 2578 2579 resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter); 2580 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur); 2581 2582 2583 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL); 2584 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels); 2585 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup); 2586 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize); 2587 2588 2589 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL); 2590 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL); 2591 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL); 2592 2593 if (clStatus != CL_SUCCESS) 2594 { 2595 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 2596 goto cleanup; 2597 } 2598 2599 global_work_size[0] = (resizedColumns+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize; 2600 global_work_size[1] = resizedRows; 2601 2602 local_work_size[0] = workgroupSize; 2603 local_work_size[1] = 1; 2604 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL); 2605 if (clStatus != CL_SUCCESS) 2606 { 2607 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 2608 goto cleanup; 2609 } 2610 clEnv->library->clFlush(queue); 2611 status = MagickTrue; 2612 2613 2614cleanup: 2615 OpenCLLogException(__FUNCTION__,__LINE__,exception); 2616 2617 if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel); 2618 2619 return status; 2620} 2621 2622 2623static MagickBooleanType resizeVerticalFilter(cl_mem inputImage 2624 , const unsigned int inputImageColumns, const unsigned int inputImageRows, const unsigned int matte 2625 , cl_mem resizedImage, const unsigned int resizedColumns, const unsigned int resizedRows 2626 , const ResizeFilter* resizeFilter, cl_mem resizeFilterCubicCoefficients, const float yFactor 2627 , MagickCLEnv clEnv, cl_command_queue queue, ExceptionInfo *exception) 2628{ 2629 MagickBooleanType status = MagickFalse; 2630 2631 float scale, support; 2632 unsigned int i; 2633 cl_kernel horizontalKernel = NULL; 2634 cl_int clStatus; 2635 size_t global_work_size[2]; 2636 size_t local_work_size[2]; 2637 int resizeFilterType, resizeWindowType; 2638 float resizeFilterScale, resizeFilterSupport, resizeFilterWindowSupport, resizeFilterBlur; 2639 size_t totalLocalMemorySize; 2640 size_t imageCacheLocalMemorySize, pixelAccumulatorLocalMemorySize 2641 , weightAccumulatorLocalMemorySize, gammaAccumulatorLocalMemorySize; 2642 size_t deviceLocalMemorySize; 2643 int cacheRangeStart, cacheRangeEnd, numCachedPixels; 2644 2645 const unsigned int workgroupSize = 256; 2646 unsigned int pixelPerWorkgroup; 2647 unsigned int chunkSize; 2648 2649 /* 2650 Apply filter to resize vertically from image to resize image. 2651 */ 2652 scale=MAGICK_MAX(1.0/yFactor+MagickEpsilon,1.0); 2653 support=scale*GetResizeFilterSupport(resizeFilter); 2654 if (support < 0.5) 2655 { 2656 /* 2657 Support too small even for nearest neighbour: Reduce to point 2658 sampling. 2659 */ 2660 support=(MagickRealType) 0.5; 2661 scale=1.0; 2662 } 2663 scale=PerceptibleReciprocal(scale); 2664 2665 if (resizedRows < workgroupSize) 2666 { 2667 chunkSize = 32; 2668 pixelPerWorkgroup = 32; 2669 } 2670 else 2671 { 2672 chunkSize = workgroupSize; 2673 pixelPerWorkgroup = workgroupSize; 2674 } 2675 2676 /* get the local memory size supported by the device */ 2677 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv); 2678 2679DisableMSCWarning(4127) 2680 while(1) 2681RestoreMSCWarning 2682 { 2683 /* calculate the local memory size needed per workgroup */ 2684 cacheRangeStart = (int) (((0 + 0.5)/yFactor+MagickEpsilon)-support+0.5); 2685 cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/yFactor+MagickEpsilon)+support+0.5); 2686 numCachedPixels = cacheRangeEnd - cacheRangeStart + 1; 2687 imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket); 2688 totalLocalMemorySize = imageCacheLocalMemorySize; 2689 2690 /* local size for the pixel accumulator */ 2691 pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4); 2692 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize; 2693 2694 /* local memory size for the weight accumulator */ 2695 weightAccumulatorLocalMemorySize = chunkSize * sizeof(float); 2696 totalLocalMemorySize+=weightAccumulatorLocalMemorySize; 2697 2698 /* local memory size for the gamma accumulator */ 2699 if (matte == 0) 2700 gammaAccumulatorLocalMemorySize = sizeof(float); 2701 else 2702 gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float); 2703 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize; 2704 2705 if (totalLocalMemorySize <= deviceLocalMemorySize) 2706 break; 2707 else 2708 { 2709 pixelPerWorkgroup = pixelPerWorkgroup/2; 2710 chunkSize = chunkSize/2; 2711 if (pixelPerWorkgroup == 0 2712 || chunkSize == 0) 2713 { 2714 /* quit, fallback to CPU */ 2715 goto cleanup; 2716 } 2717 } 2718 } 2719 2720 resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter); 2721 resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter); 2722 2723 if (resizeFilterType == SincFastWeightingFunction 2724 && resizeWindowType == SincFastWeightingFunction) 2725 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilterSinc"); 2726 else 2727 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilter"); 2728 2729 if (horizontalKernel == NULL) 2730 { 2731 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 2732 goto cleanup; 2733 } 2734 2735 i = 0; 2736 clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&inputImage); 2737 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageColumns); 2738 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&inputImageRows); 2739 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte); 2740 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&yFactor); 2741 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage); 2742 2743 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns); 2744 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows); 2745 2746 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType); 2747 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType); 2748 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients); 2749 2750 resizeFilterScale = (float) GetResizeFilterScale(resizeFilter); 2751 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale); 2752 2753 resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter); 2754 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport); 2755 2756 resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter); 2757 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport); 2758 2759 resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter); 2760 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur); 2761 2762 2763 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL); 2764 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels); 2765 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup); 2766 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize); 2767 2768 2769 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL); 2770 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL); 2771 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL); 2772 2773 if (clStatus != CL_SUCCESS) 2774 { 2775 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 2776 goto cleanup; 2777 } 2778 2779 global_work_size[0] = resizedColumns; 2780 global_work_size[1] = (resizedRows+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize; 2781 2782 local_work_size[0] = 1; 2783 local_work_size[1] = workgroupSize; 2784 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL); 2785 if (clStatus != CL_SUCCESS) 2786 { 2787 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 2788 goto cleanup; 2789 } 2790 clEnv->library->clFlush(queue); 2791 status = MagickTrue; 2792 2793 2794cleanup: 2795 OpenCLLogException(__FUNCTION__,__LINE__,exception); 2796 2797 if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel); 2798 2799 return status; 2800} 2801 2802 2803 2804static Image* ComputeResizeImage(const Image* inputImage, const size_t resizedColumns, const size_t resizedRows 2805 , const ResizeFilter* resizeFilter, ExceptionInfo *exception) 2806{ 2807 2808 MagickBooleanType outputReady = MagickFalse; 2809 Image* filteredImage = NULL; 2810 MagickCLEnv clEnv = NULL; 2811 2812 cl_int clStatus; 2813 MagickBooleanType status; 2814 const void *inputPixels; 2815 void* filteredPixels; 2816 void* hostPtr; 2817 const MagickRealType* resizeFilterCoefficient; 2818 float* mappedCoefficientBuffer; 2819 float xFactor, yFactor; 2820 MagickSizeType length; 2821 2822 cl_mem_flags mem_flags; 2823 cl_context context = NULL; 2824 cl_mem inputImageBuffer = NULL; 2825 cl_mem tempImageBuffer = NULL; 2826 cl_mem filteredImageBuffer = NULL; 2827 cl_mem cubicCoefficientsBuffer = NULL; 2828 cl_command_queue queue = NULL; 2829 2830 unsigned int i; 2831 2832 clEnv = GetDefaultOpenCLEnv(); 2833 context = GetOpenCLContext(clEnv); 2834 2835 /* Create and initialize OpenCL buffers. */ 2836 inputPixels = NULL; 2837 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 2838 if (inputPixels == (const void *) NULL) 2839 { 2840 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 2841 goto cleanup; 2842 } 2843 2844 /* If the host pointer is aligned to the size of CLPixelPacket, 2845 then use the host buffer directly from the GPU; otherwise, 2846 create a buffer on the GPU and copy the data over */ 2847 if (ALIGNED(inputPixels,CLPixelPacket)) 2848 { 2849 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 2850 } 2851 else 2852 { 2853 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 2854 } 2855 /* create a CL buffer from image pixel buffer */ 2856 length = inputImage->columns * inputImage->rows; 2857 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 2858 if (clStatus != CL_SUCCESS) 2859 { 2860 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2861 goto cleanup; 2862 } 2863 2864 cubicCoefficientsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, 7 * sizeof(float), NULL, &clStatus); 2865 if (clStatus != CL_SUCCESS) 2866 { 2867 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2868 goto cleanup; 2869 } 2870 queue = AcquireOpenCLCommandQueue(clEnv); 2871 mappedCoefficientBuffer = (float*)clEnv->library->clEnqueueMapBuffer(queue, cubicCoefficientsBuffer, CL_TRUE, CL_MAP_WRITE, 0, 7 * sizeof(float) 2872 , 0, NULL, NULL, &clStatus); 2873 if (clStatus != CL_SUCCESS) 2874 { 2875 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 2876 goto cleanup; 2877 } 2878 resizeFilterCoefficient = GetResizeFilterCoefficient(resizeFilter); 2879 for (i = 0; i < 7; i++) 2880 { 2881 mappedCoefficientBuffer[i] = (float) resizeFilterCoefficient[i]; 2882 } 2883 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, cubicCoefficientsBuffer, mappedCoefficientBuffer, 0, NULL, NULL); 2884 if (clStatus != CL_SUCCESS) 2885 { 2886 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 2887 goto cleanup; 2888 } 2889 2890 filteredImage = CloneImage(inputImage,resizedColumns,resizedRows,MagickTrue,exception); 2891 if (filteredImage == NULL) 2892 goto cleanup; 2893 2894 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 2895 { 2896 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 2897 goto cleanup; 2898 } 2899 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 2900 if (filteredPixels == (void *) NULL) 2901 { 2902 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 2903 goto cleanup; 2904 } 2905 2906 if (ALIGNED(filteredPixels,CLPixelPacket)) 2907 { 2908 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 2909 hostPtr = filteredPixels; 2910 } 2911 else 2912 { 2913 mem_flags = CL_MEM_WRITE_ONLY; 2914 hostPtr = NULL; 2915 } 2916 2917 /* create a CL buffer from image pixel buffer */ 2918 length = filteredImage->columns * filteredImage->rows; 2919 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 2920 if (clStatus != CL_SUCCESS) 2921 { 2922 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2923 goto cleanup; 2924 } 2925 2926 xFactor=(float) resizedColumns/(float) inputImage->columns; 2927 yFactor=(float) resizedRows/(float) inputImage->rows; 2928 if (xFactor > yFactor) 2929 { 2930 2931 length = resizedColumns*inputImage->rows; 2932 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus); 2933 if (clStatus != CL_SUCCESS) 2934 { 2935 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2936 goto cleanup; 2937 } 2938 2939 status = resizeHorizontalFilter(inputImageBuffer, inputImage->columns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0 2940 , tempImageBuffer, resizedColumns, inputImage->rows 2941 , resizeFilter, cubicCoefficientsBuffer 2942 , xFactor, clEnv, queue, exception); 2943 if (status != MagickTrue) 2944 goto cleanup; 2945 2946 status = resizeVerticalFilter(tempImageBuffer, resizedColumns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0 2947 , filteredImageBuffer, resizedColumns, resizedRows 2948 , resizeFilter, cubicCoefficientsBuffer 2949 , yFactor, clEnv, queue, exception); 2950 if (status != MagickTrue) 2951 goto cleanup; 2952 } 2953 else 2954 { 2955 length = inputImage->columns*resizedRows; 2956 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus); 2957 if (clStatus != CL_SUCCESS) 2958 { 2959 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 2960 goto cleanup; 2961 } 2962 2963 status = resizeVerticalFilter(inputImageBuffer, inputImage->columns, inputImage->rows, (inputImage->matte != MagickFalse)?1:0 2964 , tempImageBuffer, inputImage->columns, resizedRows 2965 , resizeFilter, cubicCoefficientsBuffer 2966 , yFactor, clEnv, queue, exception); 2967 if (status != MagickTrue) 2968 goto cleanup; 2969 2970 status = resizeHorizontalFilter(tempImageBuffer, inputImage->columns, resizedRows, (inputImage->matte != MagickFalse)?1:0 2971 , filteredImageBuffer, resizedColumns, resizedRows 2972 , resizeFilter, cubicCoefficientsBuffer 2973 , xFactor, clEnv, queue, exception); 2974 if (status != MagickTrue) 2975 goto cleanup; 2976 } 2977 length = resizedColumns*resizedRows; 2978 if (ALIGNED(filteredPixels,CLPixelPacket)) 2979 { 2980 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 2981 } 2982 else 2983 { 2984 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 2985 } 2986 if (clStatus != CL_SUCCESS) 2987 { 2988 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 2989 goto cleanup; 2990 } 2991 outputReady = MagickTrue; 2992 2993cleanup: 2994 OpenCLLogException(__FUNCTION__,__LINE__,exception); 2995 2996 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 2997 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer); 2998 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 2999 if (cubicCoefficientsBuffer!=NULL) clEnv->library->clReleaseMemObject(cubicCoefficientsBuffer); 3000 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 3001 if (outputReady == MagickFalse) 3002 { 3003 if (filteredImage != NULL) 3004 { 3005 DestroyImage(filteredImage); 3006 filteredImage = NULL; 3007 } 3008 } 3009 3010 return filteredImage; 3011} 3012 3013const ResizeWeightingFunctionType supportedResizeWeighting[] = 3014{ 3015 BoxWeightingFunction 3016 ,TriangleWeightingFunction 3017 ,HanningWeightingFunction 3018 ,HammingWeightingFunction 3019 ,BlackmanWeightingFunction 3020 ,CubicBCWeightingFunction 3021 ,SincWeightingFunction 3022 ,SincFastWeightingFunction 3023 ,LastWeightingFunction 3024}; 3025 3026static MagickBooleanType gpuSupportedResizeWeighting(ResizeWeightingFunctionType f) 3027{ 3028 MagickBooleanType supported = MagickFalse; 3029 unsigned int i; 3030 for (i = 0; ;i++) 3031 { 3032 if (supportedResizeWeighting[i] == LastWeightingFunction) 3033 break; 3034 if (supportedResizeWeighting[i] == f) 3035 { 3036 supported = MagickTrue; 3037 break; 3038 } 3039 } 3040 return supported; 3041} 3042 3043 3044/* 3045%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3046% % 3047% % 3048% % 3049% A c c e l e r a t e R e s i z e I m a g e % 3050% % 3051% % 3052% % 3053%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3054% 3055% AccelerateResizeImage() is an OpenCL implementation of ResizeImage() 3056% 3057% AccelerateResizeImage() scales an image to the desired dimensions, using the given 3058% filter (see AcquireFilterInfo()). 3059% 3060% If an undefined filter is given the filter defaults to Mitchell for a 3061% colormapped image, a image with a matte channel, or if the image is 3062% enlarged. Otherwise the filter defaults to a Lanczos. 3063% 3064% AccelerateResizeImage() was inspired by Paul Heckbert's "zoom" program. 3065% 3066% The format of the AccelerateResizeImage method is: 3067% 3068% Image *ResizeImage(Image *image,const size_t columns, 3069% const size_t rows, const ResizeFilter* filter, 3070% ExceptionInfo *exception) 3071% 3072% A description of each parameter follows: 3073% 3074% o image: the image. 3075% 3076% o columns: the number of columns in the scaled image. 3077% 3078% o rows: the number of rows in the scaled image. 3079% 3080% o filter: Image filter to use. 3081% 3082% o exception: return any errors or warnings in this structure. 3083% 3084*/ 3085 3086MagickExport 3087Image* AccelerateResizeImage(const Image* image, const size_t resizedColumns, const size_t resizedRows 3088 , const ResizeFilter* resizeFilter, ExceptionInfo *exception) 3089{ 3090 MagickBooleanType status; 3091 Image* filteredImage; 3092 3093 assert(image != NULL); 3094 assert(resizeFilter != NULL); 3095 3096 status = checkOpenCLEnvironment(exception); 3097 if (status == MagickFalse) 3098 return NULL; 3099 3100 status = checkAccelerateCondition(image, AllChannels); 3101 if (status == MagickFalse) 3102 return NULL; 3103 3104 if (gpuSupportedResizeWeighting(GetResizeFilterWeightingType(resizeFilter)) == MagickFalse 3105 || gpuSupportedResizeWeighting(GetResizeFilterWindowWeightingType(resizeFilter)) == MagickFalse) 3106 return NULL; 3107 3108 filteredImage = ComputeResizeImage(image,resizedColumns,resizedRows,resizeFilter,exception); 3109 return filteredImage; 3110 3111} 3112 3113 3114static MagickBooleanType ComputeContrastImage(Image *inputImage, const MagickBooleanType sharpen, ExceptionInfo *exception) 3115{ 3116 MagickBooleanType outputReady = MagickFalse; 3117 MagickCLEnv clEnv = NULL; 3118 3119 cl_int clStatus; 3120 size_t global_work_size[2]; 3121 3122 void *inputPixels = NULL; 3123 MagickSizeType length; 3124 unsigned int uSharpen; 3125 unsigned int i; 3126 3127 cl_mem_flags mem_flags; 3128 cl_context context = NULL; 3129 cl_mem inputImageBuffer = NULL; 3130 cl_kernel filterKernel = NULL; 3131 cl_command_queue queue = NULL; 3132 3133 clEnv = GetDefaultOpenCLEnv(); 3134 context = GetOpenCLContext(clEnv); 3135 3136 /* Create and initialize OpenCL buffers. */ 3137 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 3138 if (inputPixels == (void *) NULL) 3139 { 3140 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 3141 goto cleanup; 3142 } 3143 3144 /* If the host pointer is aligned to the size of CLPixelPacket, 3145 then use the host buffer directly from the GPU; otherwise, 3146 create a buffer on the GPU and copy the data over */ 3147 if (ALIGNED(inputPixels,CLPixelPacket)) 3148 { 3149 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 3150 } 3151 else 3152 { 3153 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 3154 } 3155 /* create a CL buffer from image pixel buffer */ 3156 length = inputImage->columns * inputImage->rows; 3157 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 3158 if (clStatus != CL_SUCCESS) 3159 { 3160 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 3161 goto cleanup; 3162 } 3163 3164 filterKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Contrast"); 3165 if (filterKernel == NULL) 3166 { 3167 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 3168 goto cleanup; 3169 } 3170 3171 i = 0; 3172 clStatus=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 3173 3174 uSharpen = (sharpen == MagickFalse)?0:1; 3175 clStatus|=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_uint),&uSharpen); 3176 if (clStatus != CL_SUCCESS) 3177 { 3178 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 3179 goto cleanup; 3180 } 3181 3182 global_work_size[0] = inputImage->columns; 3183 global_work_size[1] = inputImage->rows; 3184 /* launch the kernel */ 3185 queue = AcquireOpenCLCommandQueue(clEnv); 3186 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, filterKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 3187 if (clStatus != CL_SUCCESS) 3188 { 3189 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 3190 goto cleanup; 3191 } 3192 clEnv->library->clFlush(queue); 3193 3194 if (ALIGNED(inputPixels,CLPixelPacket)) 3195 { 3196 length = inputImage->columns * inputImage->rows; 3197 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 3198 } 3199 else 3200 { 3201 length = inputImage->columns * inputImage->rows; 3202 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 3203 } 3204 if (clStatus != CL_SUCCESS) 3205 { 3206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 3207 goto cleanup; 3208 } 3209 outputReady = MagickTrue; 3210 3211cleanup: 3212 OpenCLLogException(__FUNCTION__,__LINE__,exception); 3213 3214 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 3215 if (filterKernel!=NULL) RelinquishOpenCLKernel(clEnv, filterKernel); 3216 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 3217 return outputReady; 3218} 3219 3220/* 3221%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3222% % 3223% % 3224% % 3225% C o n t r a s t I m a g e w i t h O p e n C L % 3226% % 3227% % 3228% % 3229%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3230% 3231% ContrastImage() enhances the intensity differences between the lighter and 3232% darker elements of the image. Set sharpen to a MagickTrue to increase the 3233% image contrast otherwise the contrast is reduced. 3234% 3235% The format of the ContrastImage method is: 3236% 3237% MagickBooleanType ContrastImage(Image *image, 3238% const MagickBooleanType sharpen) 3239% 3240% A description of each parameter follows: 3241% 3242% o image: the image. 3243% 3244% o sharpen: Increase or decrease image contrast. 3245% 3246*/ 3247 3248MagickExport 3249MagickBooleanType AccelerateContrastImage(Image* image, const MagickBooleanType sharpen, ExceptionInfo* exception) 3250{ 3251 MagickBooleanType status; 3252 3253 assert(image != NULL); 3254 assert(exception != NULL); 3255 3256 status = checkOpenCLEnvironment(exception); 3257 if (status == MagickFalse) 3258 return MagickFalse; 3259 3260 status = checkAccelerateCondition(image, AllChannels); 3261 if (status == MagickFalse) 3262 return MagickFalse; 3263 3264 status = ComputeContrastImage(image,sharpen,exception); 3265 return status; 3266} 3267 3268 3269 3270MagickBooleanType ComputeModulateImage(Image* image, double percent_brightness, double percent_hue, double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception) 3271{ 3272 register ssize_t 3273 i; 3274 3275 cl_float 3276 bright, 3277 hue, 3278 saturation; 3279 3280 cl_int color; 3281 3282 MagickBooleanType outputReady; 3283 3284 MagickCLEnv clEnv; 3285 3286 void *inputPixels; 3287 3288 MagickSizeType length; 3289 3290 cl_context context; 3291 cl_command_queue queue; 3292 cl_kernel modulateKernel; 3293 3294 cl_mem inputImageBuffer; 3295 cl_mem_flags mem_flags; 3296 3297 cl_int clStatus; 3298 3299 Image * inputImage = image; 3300 3301 inputPixels = NULL; 3302 inputImageBuffer = NULL; 3303 modulateKernel = NULL; 3304 3305 assert(inputImage != (Image *) NULL); 3306 assert(inputImage->signature == MagickSignature); 3307 if (inputImage->debug != MagickFalse) 3308 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename); 3309 3310 /* 3311 * initialize opencl env 3312 */ 3313 clEnv = GetDefaultOpenCLEnv(); 3314 context = GetOpenCLContext(clEnv); 3315 queue = AcquireOpenCLCommandQueue(clEnv); 3316 3317 outputReady = MagickFalse; 3318 3319 /* Create and initialize OpenCL buffers. 3320 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 3321 assume this will get a writable image 3322 */ 3323 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 3324 if (inputPixels == (void *) NULL) 3325 { 3326 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 3327 goto cleanup; 3328 } 3329 3330 /* If the host pointer is aligned to the size of CLPixelPacket, 3331 then use the host buffer directly from the GPU; otherwise, 3332 create a buffer on the GPU and copy the data over 3333 */ 3334 if (ALIGNED(inputPixels,CLPixelPacket)) 3335 { 3336 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 3337 } 3338 else 3339 { 3340 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 3341 } 3342 /* create a CL buffer from image pixel buffer */ 3343 length = inputImage->columns * inputImage->rows; 3344 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 3345 if (clStatus != CL_SUCCESS) 3346 { 3347 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 3348 goto cleanup; 3349 } 3350 3351 modulateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Modulate"); 3352 if (modulateKernel == NULL) 3353 { 3354 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 3355 goto cleanup; 3356 } 3357 3358 bright=percent_brightness; 3359 hue=percent_hue; 3360 saturation=percent_saturation; 3361 color=colorspace; 3362 3363 i = 0; 3364 clStatus=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 3365 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&bright); 3366 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&hue); 3367 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&saturation); 3368 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&color); 3369 if (clStatus != CL_SUCCESS) 3370 { 3371 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 3372 printf("no kernel\n"); 3373 goto cleanup; 3374 } 3375 3376 { 3377 size_t global_work_size[2]; 3378 global_work_size[0] = inputImage->columns; 3379 global_work_size[1] = inputImage->rows; 3380 /* launch the kernel */ 3381 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, modulateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 3382 if (clStatus != CL_SUCCESS) 3383 { 3384 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 3385 goto cleanup; 3386 } 3387 clEnv->library->clFlush(queue); 3388 } 3389 3390 if (ALIGNED(inputPixels,CLPixelPacket)) 3391 { 3392 length = inputImage->columns * inputImage->rows; 3393 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 3394 } 3395 else 3396 { 3397 length = inputImage->columns * inputImage->rows; 3398 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 3399 } 3400 if (clStatus != CL_SUCCESS) 3401 { 3402 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 3403 goto cleanup; 3404 } 3405 3406 outputReady = MagickTrue; 3407 3408cleanup: 3409 OpenCLLogException(__FUNCTION__,__LINE__,exception); 3410 3411 if (inputPixels) { 3412 //ReleasePixelCachePixels(); 3413 inputPixels = NULL; 3414 } 3415 3416 if (inputImageBuffer!=NULL) 3417 clEnv->library->clReleaseMemObject(inputImageBuffer); 3418 if (modulateKernel!=NULL) 3419 RelinquishOpenCLKernel(clEnv, modulateKernel); 3420 if (queue != NULL) 3421 RelinquishOpenCLCommandQueue(clEnv, queue); 3422 3423 return outputReady; 3424 3425} 3426 3427/* 3428%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3429% % 3430% % 3431% % 3432% M o d u l a t e I m a g e w i t h O p e n C L % 3433% % 3434% % 3435% % 3436%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3437% 3438% ModulateImage() lets you control the brightness, saturation, and hue 3439% of an image. Modulate represents the brightness, saturation, and hue 3440% as one parameter (e.g. 90,150,100). If the image colorspace is HSL, the 3441% modulation is lightness, saturation, and hue. For HWB, use blackness, 3442% whiteness, and hue. And for HCL, use chrome, luma, and hue. 3443% 3444% The format of the ModulateImage method is: 3445% 3446% MagickBooleanType ModulateImage(Image *image,const char *modulate) 3447% 3448% A description of each parameter follows: 3449% 3450% o image: the image. 3451% 3452% o percent_*: Define the percent change in brightness, saturation, and 3453% hue. 3454% 3455*/ 3456 3457MagickExport 3458MagickBooleanType AccelerateModulateImage(Image* image, double percent_brightness, double percent_hue, double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception) 3459{ 3460 MagickBooleanType status; 3461 3462 assert(image != NULL); 3463 assert(exception != NULL); 3464 3465 status = checkOpenCLEnvironment(exception); 3466 if (status == MagickFalse) 3467 return MagickFalse; 3468 3469 status = checkAccelerateCondition(image, AllChannels); 3470 if (status == MagickFalse) 3471 return MagickFalse; 3472 3473 if ((colorspace != HSLColorspace && colorspace != UndefinedColorspace)) 3474 return MagickFalse; 3475 3476 3477 status = ComputeModulateImage(image,percent_brightness, percent_hue, percent_saturation, colorspace, exception); 3478 return status; 3479} 3480 3481MagickBooleanType ComputeNegateImageChannel(Image* image, const ChannelType channel, const MagickBooleanType magick_unused(grayscale), ExceptionInfo* exception) 3482{ 3483 register ssize_t 3484 i; 3485 3486 MagickBooleanType outputReady; 3487 3488 MagickCLEnv clEnv; 3489 3490 void *inputPixels; 3491 3492 MagickSizeType length; 3493 3494 cl_context context; 3495 cl_command_queue queue; 3496 cl_kernel negateKernel; 3497 3498 cl_mem inputImageBuffer; 3499 cl_mem_flags mem_flags; 3500 3501 cl_int clStatus; 3502 3503 Image * inputImage = image; 3504 3505 magick_unreferenced(grayscale); 3506 3507 inputPixels = NULL; 3508 inputImageBuffer = NULL; 3509 negateKernel = NULL; 3510 3511 assert(inputImage != (Image *) NULL); 3512 assert(inputImage->signature == MagickSignature); 3513 if (inputImage->debug != MagickFalse) 3514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename); 3515 3516 /* 3517 * initialize opencl env 3518 */ 3519 clEnv = GetDefaultOpenCLEnv(); 3520 context = GetOpenCLContext(clEnv); 3521 queue = AcquireOpenCLCommandQueue(clEnv); 3522 3523 outputReady = MagickFalse; 3524 3525 /* Create and initialize OpenCL buffers. 3526 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 3527 assume this will get a writable image 3528 */ 3529 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 3530 if (inputPixels == (void *) NULL) 3531 { 3532 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 3533 goto cleanup; 3534 } 3535 3536 /* If the host pointer is aligned to the size of CLPixelPacket, 3537 then use the host buffer directly from the GPU; otherwise, 3538 create a buffer on the GPU and copy the data over 3539 */ 3540 if (ALIGNED(inputPixels,CLPixelPacket)) 3541 { 3542 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 3543 } 3544 else 3545 { 3546 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 3547 } 3548 /* create a CL buffer from image pixel buffer */ 3549 length = inputImage->columns * inputImage->rows; 3550 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 3551 if (clStatus != CL_SUCCESS) 3552 { 3553 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 3554 goto cleanup; 3555 } 3556 3557 negateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Negate"); 3558 if (negateKernel == NULL) 3559 { 3560 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 3561 goto cleanup; 3562 } 3563 3564 i = 0; 3565 clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 3566 clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(ChannelType),(void *)&channel); 3567 if (clStatus != CL_SUCCESS) 3568 { 3569 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 3570 printf("no kernel\n"); 3571 goto cleanup; 3572 } 3573 3574 { 3575 size_t global_work_size[2]; 3576 global_work_size[0] = inputImage->columns; 3577 global_work_size[1] = inputImage->rows; 3578 /* launch the kernel */ 3579 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, negateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 3580 if (clStatus != CL_SUCCESS) 3581 { 3582 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 3583 goto cleanup; 3584 } 3585 clEnv->library->clFlush(queue); 3586 } 3587 3588 if (ALIGNED(inputPixels,CLPixelPacket)) 3589 { 3590 length = inputImage->columns * inputImage->rows; 3591 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 3592 } 3593 else 3594 { 3595 length = inputImage->columns * inputImage->rows; 3596 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 3597 } 3598 if (clStatus != CL_SUCCESS) 3599 { 3600 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 3601 goto cleanup; 3602 } 3603 3604 outputReady = MagickTrue; 3605 3606cleanup: 3607 OpenCLLogException(__FUNCTION__,__LINE__,exception); 3608 3609 if (inputPixels) { 3610 //ReleasePixelCachePixels(); 3611 inputPixels = NULL; 3612 } 3613 3614 if (inputImageBuffer!=NULL) 3615 clEnv->library->clReleaseMemObject(inputImageBuffer); 3616 if (negateKernel!=NULL) 3617 RelinquishOpenCLKernel(clEnv, negateKernel); 3618 if (queue != NULL) 3619 RelinquishOpenCLCommandQueue(clEnv, queue); 3620 3621 return outputReady; 3622 3623} 3624 3625 3626/* 3627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3628% % 3629% % 3630% % 3631% N e g a t e I m a g e w i t h O p e n C L % 3632% % 3633% % 3634% % 3635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3636% 3637% 3638% A description of each parameter follows: 3639% 3640% o image: the image. 3641% 3642% o channel: the channel. 3643% 3644% o grayscale: If MagickTrue, only negate grayscale pixels within the image. 3645% 3646*/ 3647 3648MagickExport 3649MagickBooleanType AccelerateNegateImageChannel(Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception) 3650{ 3651 MagickBooleanType status; 3652 3653 assert(image != NULL); 3654 assert(exception != NULL); 3655 3656 status = checkOpenCLEnvironment(exception); 3657 if (status == MagickFalse) 3658 return MagickFalse; 3659 3660 status = checkAccelerateCondition(image, AllChannels); 3661 if (status == MagickFalse) 3662 return MagickFalse; 3663 3664 status = ComputeNegateImageChannel(image,channel,grayscale,exception); 3665 3666 return status; 3667} 3668 3669 3670MagickBooleanType ComputeGrayscaleImage(Image* image, const PixelIntensityMethod method, ExceptionInfo* exception) 3671{ 3672 register ssize_t 3673 i; 3674 3675 cl_int intensityMethod; 3676 cl_int colorspace; 3677 3678 MagickBooleanType outputReady; 3679 3680 MagickCLEnv clEnv; 3681 3682 void *inputPixels; 3683 3684 MagickSizeType length; 3685 3686 cl_context context; 3687 cl_command_queue queue; 3688 cl_kernel grayscaleKernel; 3689 3690 cl_mem inputImageBuffer; 3691 cl_mem_flags mem_flags; 3692 3693 cl_int clStatus; 3694 3695 Image * inputImage = image; 3696 3697 inputPixels = NULL; 3698 inputImageBuffer = NULL; 3699 grayscaleKernel = NULL; 3700 3701 assert(inputImage != (Image *) NULL); 3702 assert(inputImage->signature == MagickSignature); 3703 if (inputImage->debug != MagickFalse) 3704 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename); 3705 3706 /* 3707 * initialize opencl env 3708 */ 3709 clEnv = GetDefaultOpenCLEnv(); 3710 context = GetOpenCLContext(clEnv); 3711 queue = AcquireOpenCLCommandQueue(clEnv); 3712 3713 outputReady = MagickFalse; 3714 3715 /* Create and initialize OpenCL buffers. 3716 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 3717 assume this will get a writable image 3718 */ 3719 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 3720 if (inputPixels == (void *) NULL) 3721 { 3722 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 3723 goto cleanup; 3724 } 3725 3726 /* If the host pointer is aligned to the size of CLPixelPacket, 3727 then use the host buffer directly from the GPU; otherwise, 3728 create a buffer on the GPU and copy the data over 3729 */ 3730 if (ALIGNED(inputPixels,CLPixelPacket)) 3731 { 3732 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 3733 } 3734 else 3735 { 3736 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 3737 } 3738 /* create a CL buffer from image pixel buffer */ 3739 length = inputImage->columns * inputImage->rows; 3740 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 3741 if (clStatus != CL_SUCCESS) 3742 { 3743 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 3744 goto cleanup; 3745 } 3746 3747 intensityMethod = method; 3748 colorspace = image->colorspace; 3749 3750 grayscaleKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Grayscale"); 3751 if (grayscaleKernel == NULL) 3752 { 3753 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 3754 goto cleanup; 3755 } 3756 3757 i = 0; 3758 clStatus=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 3759 clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&intensityMethod); 3760 clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&colorspace); 3761 if (clStatus != CL_SUCCESS) 3762 { 3763 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 3764 printf("no kernel\n"); 3765 goto cleanup; 3766 } 3767 3768 { 3769 size_t global_work_size[2]; 3770 global_work_size[0] = inputImage->columns; 3771 global_work_size[1] = inputImage->rows; 3772 /* launch the kernel */ 3773 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, grayscaleKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 3774 if (clStatus != CL_SUCCESS) 3775 { 3776 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 3777 goto cleanup; 3778 } 3779 clEnv->library->clFlush(queue); 3780 } 3781 3782 if (ALIGNED(inputPixels,CLPixelPacket)) 3783 { 3784 length = inputImage->columns * inputImage->rows; 3785 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 3786 } 3787 else 3788 { 3789 length = inputImage->columns * inputImage->rows; 3790 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 3791 } 3792 if (clStatus != CL_SUCCESS) 3793 { 3794 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 3795 goto cleanup; 3796 } 3797 3798 outputReady = MagickTrue; 3799 3800cleanup: 3801 OpenCLLogException(__FUNCTION__,__LINE__,exception); 3802 3803 if (inputPixels) { 3804 //ReleasePixelCachePixels(); 3805 inputPixels = NULL; 3806 } 3807 3808 if (inputImageBuffer!=NULL) 3809 clEnv->library->clReleaseMemObject(inputImageBuffer); 3810 if (grayscaleKernel!=NULL) 3811 RelinquishOpenCLKernel(clEnv, grayscaleKernel); 3812 if (queue != NULL) 3813 RelinquishOpenCLCommandQueue(clEnv, queue); 3814 3815 return outputReady; 3816 3817} 3818/* 3819%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3820% % 3821% % 3822% % 3823% G r a y s c a l e I m a g e w i t h O p e n C L % 3824% % 3825% % 3826% % 3827%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3828% 3829% GrayscaleImage() converts the colors in the reference image to gray. 3830% 3831% The format of the GrayscaleImageChannel method is: 3832% 3833% MagickBooleanType GrayscaleImage(Image *image, 3834% const PixelIntensityMethod method) 3835% 3836% A description of each parameter follows: 3837% 3838% o image: the image. 3839% 3840% o channel: the channel. 3841% 3842*/ 3843 3844MagickExport 3845MagickBooleanType AccelerateGrayscaleImage(Image* image, const PixelIntensityMethod method, ExceptionInfo* exception) 3846{ 3847 MagickBooleanType status; 3848 3849 assert(image != NULL); 3850 assert(exception != NULL); 3851 3852 status = checkOpenCLEnvironment(exception); 3853 if (status == MagickFalse) 3854 return MagickFalse; 3855 3856 status = checkAccelerateCondition(image, AllChannels); 3857 if (status == MagickFalse) 3858 return MagickFalse; 3859 3860 if (method == Rec601LuminancePixelIntensityMethod || method == Rec709LuminancePixelIntensityMethod) 3861 return MagickFalse; 3862 3863 if (image->colorspace != sRGBColorspace) 3864 return MagickFalse; 3865 3866 status = ComputeGrayscaleImage(image,method,exception); 3867 3868 return status; 3869} 3870 3871static MagickBooleanType LaunchHistogramKernel(MagickCLEnv clEnv, 3872 cl_command_queue queue, 3873 cl_mem inputImageBuffer, 3874 cl_mem histogramBuffer, 3875 Image *inputImage, 3876 const ChannelType channel, 3877 ExceptionInfo * _exception) 3878{ 3879 ExceptionInfo 3880 *exception=_exception; 3881 3882 register ssize_t 3883 i; 3884 3885 MagickBooleanType outputReady; 3886 3887 cl_int clStatus; 3888 3889 size_t global_work_size[2]; 3890 3891 cl_kernel histogramKernel; 3892 3893 cl_int method; 3894 cl_int colorspace; 3895 3896 histogramKernel = NULL; 3897 3898 outputReady = MagickFalse; 3899 method = inputImage->intensity; 3900 colorspace = inputImage->colorspace; 3901 3902 /* get the OpenCL kernel */ 3903 histogramKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Histogram"); 3904 if (histogramKernel == NULL) 3905 { 3906 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 3907 goto cleanup; 3908 } 3909 3910 /* set the kernel arguments */ 3911 i = 0; 3912 clStatus=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 3913 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(ChannelType),&channel); 3914 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&method); 3915 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&colorspace); 3916 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&histogramBuffer); 3917 if (clStatus != CL_SUCCESS) 3918 { 3919 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 3920 goto cleanup; 3921 } 3922 3923 /* launch the kernel */ 3924 global_work_size[0] = inputImage->columns; 3925 global_work_size[1] = inputImage->rows; 3926 3927 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, histogramKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 3928 3929 if (clStatus != CL_SUCCESS) 3930 { 3931 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 3932 goto cleanup; 3933 } 3934 clEnv->library->clFlush(queue); 3935 3936 outputReady = MagickTrue; 3937 3938cleanup: 3939 OpenCLLogException(__FUNCTION__,__LINE__,exception); 3940 3941 if (histogramKernel!=NULL) 3942 RelinquishOpenCLKernel(clEnv, histogramKernel); 3943 3944 return outputReady; 3945} 3946 3947 3948MagickExport MagickBooleanType ComputeEqualizeImage(Image *inputImage, const ChannelType channel, ExceptionInfo * _exception) 3949{ 3950#define EqualizeImageTag "Equalize/Image" 3951 3952 ExceptionInfo 3953 *exception=_exception; 3954 3955 FloatPixelPacket 3956 white, 3957 black, 3958 intensity, 3959 *map=NULL; 3960 3961 cl_uint4 3962 *histogram=NULL; 3963 3964 PixelPacket 3965 *equalize_map=NULL; 3966 3967 register ssize_t 3968 i; 3969 3970 Image * image = inputImage; 3971 3972 MagickBooleanType outputReady; 3973 3974 MagickCLEnv clEnv; 3975 3976 cl_int clStatus; 3977 MagickBooleanType status; 3978 3979 size_t global_work_size[2]; 3980 3981 void *inputPixels; 3982 cl_mem_flags mem_flags; 3983 3984 cl_context context; 3985 cl_mem inputImageBuffer; 3986 cl_mem histogramBuffer; 3987 cl_mem equalizeMapBuffer; 3988 cl_kernel histogramKernel; 3989 cl_kernel equalizeKernel; 3990 cl_command_queue queue; 3991 3992 void* hostPtr; 3993 3994 MagickSizeType length; 3995 3996 inputPixels = NULL; 3997 inputImageBuffer = NULL; 3998 histogramBuffer = NULL; 3999 equalizeMapBuffer = NULL; 4000 histogramKernel = NULL; 4001 equalizeKernel = NULL; 4002 context = NULL; 4003 queue = NULL; 4004 outputReady = MagickFalse; 4005 4006 assert(inputImage != (Image *) NULL); 4007 assert(inputImage->signature == MagickSignature); 4008 if (inputImage->debug != MagickFalse) 4009 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",inputImage->filename); 4010 4011 /* 4012 * initialize opencl env 4013 */ 4014 clEnv = GetDefaultOpenCLEnv(); 4015 context = GetOpenCLContext(clEnv); 4016 queue = AcquireOpenCLCommandQueue(clEnv); 4017 4018 /* 4019 Allocate and initialize histogram arrays. 4020 */ 4021 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram)); 4022 if (histogram == (cl_uint4 *) NULL) 4023 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename); 4024 4025 /* reset histogram */ 4026 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram)); 4027 4028 /* Create and initialize OpenCL buffers. */ 4029 /* inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); */ 4030 /* assume this will get a writable image */ 4031 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 4032 4033 if (inputPixels == (void *) NULL) 4034 { 4035 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 4036 goto cleanup; 4037 } 4038 /* If the host pointer is aligned to the size of CLPixelPacket, 4039 then use the host buffer directly from the GPU; otherwise, 4040 create a buffer on the GPU and copy the data over */ 4041 if (ALIGNED(inputPixels,CLPixelPacket)) 4042 { 4043 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 4044 } 4045 else 4046 { 4047 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 4048 } 4049 /* create a CL buffer from image pixel buffer */ 4050 length = inputImage->columns * inputImage->rows; 4051 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 4052 if (clStatus != CL_SUCCESS) 4053 { 4054 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4055 goto cleanup; 4056 } 4057 4058 /* If the host pointer is aligned to the size of cl_uint, 4059 then use the host buffer directly from the GPU; otherwise, 4060 create a buffer on the GPU and copy the data over */ 4061 if (ALIGNED(histogram,cl_uint4)) 4062 { 4063 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 4064 hostPtr = histogram; 4065 } 4066 else 4067 { 4068 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 4069 hostPtr = histogram; 4070 } 4071 /* create a CL buffer for histogram */ 4072 length = (MaxMap+1); 4073 histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus); 4074 if (clStatus != CL_SUCCESS) 4075 { 4076 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4077 goto cleanup; 4078 } 4079 4080 status = LaunchHistogramKernel(clEnv, queue, inputImageBuffer, histogramBuffer, image, channel, exception); 4081 if (status == MagickFalse) 4082 goto cleanup; 4083 4084 /* read from the kenel output */ 4085 if (ALIGNED(histogram,cl_uint4)) 4086 { 4087 length = (MaxMap+1); 4088 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus); 4089 } 4090 else 4091 { 4092 length = (MaxMap+1); 4093 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL); 4094 } 4095 if (clStatus != CL_SUCCESS) 4096 { 4097 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 4098 goto cleanup; 4099 } 4100 4101 /* unmap, don't block gpu to use this buffer again. */ 4102 if (ALIGNED(histogram,cl_uint4)) 4103 { 4104 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL); 4105 if (clStatus != CL_SUCCESS) 4106 { 4107 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 4108 goto cleanup; 4109 } 4110 } 4111 4112 /* recreate input buffer later, in case image updated */ 4113#ifdef RECREATEBUFFER 4114 if (inputImageBuffer!=NULL) 4115 clEnv->library->clReleaseMemObject(inputImageBuffer); 4116#endif 4117 4118 /* CPU stuff */ 4119 equalize_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*equalize_map)); 4120 if (equalize_map == (PixelPacket *) NULL) 4121 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename); 4122 4123 map=(FloatPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map)); 4124 if (map == (FloatPixelPacket *) NULL) 4125 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename); 4126 4127 /* 4128 Integrate the histogram to get the equalization map. 4129 */ 4130 (void) ResetMagickMemory(&intensity,0,sizeof(intensity)); 4131 for (i=0; i <= (ssize_t) MaxMap; i++) 4132 { 4133 if ((channel & SyncChannels) != 0) 4134 { 4135 intensity.red+=histogram[i].s[2]; 4136 map[i]=intensity; 4137 continue; 4138 } 4139 if ((channel & RedChannel) != 0) 4140 intensity.red+=histogram[i].s[2]; 4141 if ((channel & GreenChannel) != 0) 4142 intensity.green+=histogram[i].s[1]; 4143 if ((channel & BlueChannel) != 0) 4144 intensity.blue+=histogram[i].s[0]; 4145 if ((channel & OpacityChannel) != 0) 4146 intensity.opacity+=histogram[i].s[3]; 4147 /* 4148 if (((channel & IndexChannel) != 0) && 4149 (image->colorspace == CMYKColorspace)) 4150 { 4151 intensity.index+=histogram[i].index; 4152 } 4153 */ 4154 map[i]=intensity; 4155 } 4156 black=map[0]; 4157 white=map[(int) MaxMap]; 4158 (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map)); 4159 for (i=0; i <= (ssize_t) MaxMap; i++) 4160 { 4161 if ((channel & SyncChannels) != 0) 4162 { 4163 if (white.red != black.red) 4164 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap* 4165 (map[i].red-black.red))/(white.red-black.red))); 4166 continue; 4167 } 4168 if (((channel & RedChannel) != 0) && (white.red != black.red)) 4169 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap* 4170 (map[i].red-black.red))/(white.red-black.red))); 4171 if (((channel & GreenChannel) != 0) && (white.green != black.green)) 4172 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap* 4173 (map[i].green-black.green))/(white.green-black.green))); 4174 if (((channel & BlueChannel) != 0) && (white.blue != black.blue)) 4175 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap* 4176 (map[i].blue-black.blue))/(white.blue-black.blue))); 4177 if (((channel & OpacityChannel) != 0) && (white.opacity != black.opacity)) 4178 equalize_map[i].opacity=ScaleMapToQuantum((MagickRealType) ((MaxMap* 4179 (map[i].opacity-black.opacity))/(white.opacity-black.opacity))); 4180 /* 4181 if ((((channel & IndexChannel) != 0) && 4182 (image->colorspace == CMYKColorspace)) && 4183 (white.index != black.index)) 4184 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap* 4185 (map[i].index-black.index))/(white.index-black.index))); 4186 */ 4187 } 4188 4189 if (image->storage_class == PseudoClass) 4190 { 4191 /* 4192 Equalize colormap. 4193 */ 4194 for (i=0; i < (ssize_t) image->colors; i++) 4195 { 4196 if ((channel & SyncChannels) != 0) 4197 { 4198 if (white.red != black.red) 4199 { 4200 image->colormap[i].red=equalize_map[ 4201 ScaleQuantumToMap(image->colormap[i].red)].red; 4202 image->colormap[i].green=equalize_map[ 4203 ScaleQuantumToMap(image->colormap[i].green)].red; 4204 image->colormap[i].blue=equalize_map[ 4205 ScaleQuantumToMap(image->colormap[i].blue)].red; 4206 image->colormap[i].opacity=equalize_map[ 4207 ScaleQuantumToMap(image->colormap[i].opacity)].red; 4208 } 4209 continue; 4210 } 4211 if (((channel & RedChannel) != 0) && (white.red != black.red)) 4212 image->colormap[i].red=equalize_map[ 4213 ScaleQuantumToMap(image->colormap[i].red)].red; 4214 if (((channel & GreenChannel) != 0) && (white.green != black.green)) 4215 image->colormap[i].green=equalize_map[ 4216 ScaleQuantumToMap(image->colormap[i].green)].green; 4217 if (((channel & BlueChannel) != 0) && (white.blue != black.blue)) 4218 image->colormap[i].blue=equalize_map[ 4219 ScaleQuantumToMap(image->colormap[i].blue)].blue; 4220 if (((channel & OpacityChannel) != 0) && 4221 (white.opacity != black.opacity)) 4222 image->colormap[i].opacity=equalize_map[ 4223 ScaleQuantumToMap(image->colormap[i].opacity)].opacity; 4224 } 4225 } 4226 4227 /* 4228 Equalize image. 4229 */ 4230 4231 /* GPU can work on this again, image and equalize map as input 4232 image: uchar4 (CLPixelPacket) 4233 equalize_map: uchar4 (PixelPacket) 4234 black, white: float4 (FloatPixelPacket) */ 4235 4236#ifdef RECREATEBUFFER 4237 /* If the host pointer is aligned to the size of CLPixelPacket, 4238 then use the host buffer directly from the GPU; otherwise, 4239 create a buffer on the GPU and copy the data over */ 4240 if (ALIGNED(inputPixels,CLPixelPacket)) 4241 { 4242 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 4243 } 4244 else 4245 { 4246 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 4247 } 4248 /* create a CL buffer from image pixel buffer */ 4249 length = inputImage->columns * inputImage->rows; 4250 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 4251 if (clStatus != CL_SUCCESS) 4252 { 4253 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4254 goto cleanup; 4255 } 4256#endif 4257 4258 /* Create and initialize OpenCL buffers. */ 4259 if (ALIGNED(equalize_map, PixelPacket)) 4260 { 4261 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 4262 hostPtr = equalize_map; 4263 } 4264 else 4265 { 4266 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 4267 hostPtr = equalize_map; 4268 } 4269 /* create a CL buffer for eqaulize_map */ 4270 length = (MaxMap+1); 4271 equalizeMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus); 4272 if (clStatus != CL_SUCCESS) 4273 { 4274 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4275 goto cleanup; 4276 } 4277 4278 /* get the OpenCL kernel */ 4279 equalizeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Equalize"); 4280 if (equalizeKernel == NULL) 4281 { 4282 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 4283 goto cleanup; 4284 } 4285 4286 /* set the kernel arguments */ 4287 i = 0; 4288 clStatus=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 4289 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(ChannelType),&channel); 4290 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&equalizeMapBuffer); 4291 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&white); 4292 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&black); 4293 if (clStatus != CL_SUCCESS) 4294 { 4295 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 4296 goto cleanup; 4297 } 4298 4299 /* launch the kernel */ 4300 global_work_size[0] = inputImage->columns; 4301 global_work_size[1] = inputImage->rows; 4302 4303 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, equalizeKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 4304 4305 if (clStatus != CL_SUCCESS) 4306 { 4307 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 4308 goto cleanup; 4309 } 4310 clEnv->library->clFlush(queue); 4311 4312 /* read the data back */ 4313 if (ALIGNED(inputPixels,CLPixelPacket)) 4314 { 4315 length = inputImage->columns * inputImage->rows; 4316 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 4317 } 4318 else 4319 { 4320 length = inputImage->columns * inputImage->rows; 4321 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 4322 } 4323 if (clStatus != CL_SUCCESS) 4324 { 4325 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 4326 goto cleanup; 4327 } 4328 4329 outputReady = MagickTrue; 4330 4331cleanup: 4332 OpenCLLogException(__FUNCTION__,__LINE__,exception); 4333 4334 if (inputPixels) { 4335 /*ReleasePixelCachePixels();*/ 4336 inputPixels = NULL; 4337 } 4338 4339 if (inputImageBuffer!=NULL) 4340 clEnv->library->clReleaseMemObject(inputImageBuffer); 4341 4342 if (map!=NULL) 4343 map=(FloatPixelPacket *) RelinquishMagickMemory(map); 4344 4345 if (equalizeMapBuffer!=NULL) 4346 clEnv->library->clReleaseMemObject(equalizeMapBuffer); 4347 if (equalize_map!=NULL) 4348 equalize_map=(PixelPacket *) RelinquishMagickMemory(equalize_map); 4349 4350 if (histogramBuffer!=NULL) 4351 clEnv->library->clReleaseMemObject(histogramBuffer); 4352 if (histogram!=NULL) 4353 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram); 4354 4355 if (histogramKernel!=NULL) 4356 RelinquishOpenCLKernel(clEnv, histogramKernel); 4357 if (equalizeKernel!=NULL) 4358 RelinquishOpenCLKernel(clEnv, equalizeKernel); 4359 4360 if (queue != NULL) 4361 RelinquishOpenCLCommandQueue(clEnv, queue); 4362 4363 return outputReady; 4364} 4365 4366/* 4367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4368% % 4369% % 4370% % 4371% E q u a l i z e I m a g e w i t h O p e n C L % 4372% % 4373% % 4374% % 4375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4376% 4377% EqualizeImage() applies a histogram equalization to the image. 4378% 4379% The format of the EqualizeImage method is: 4380% 4381% MagickBooleanType EqualizeImage(Image *image) 4382% MagickBooleanType EqualizeImageChannel(Image *image, 4383% const ChannelType channel) 4384% 4385% A description of each parameter follows: 4386% 4387% o image: the image. 4388% 4389% o channel: the channel. 4390% 4391*/ 4392 4393 4394MagickExport 4395MagickBooleanType AccelerateEqualizeImage(Image* image, const ChannelType channel, ExceptionInfo* exception) 4396{ 4397 MagickBooleanType status; 4398 4399 assert(image != NULL); 4400 assert(exception != NULL); 4401 4402 status = checkOpenCLEnvironment(exception); 4403 if (status == MagickFalse) 4404 return MagickFalse; 4405 4406 status = checkAccelerateCondition(image, channel); 4407 if (status == MagickFalse) 4408 return MagickFalse; 4409 4410 status = checkHistogramCondition(image, channel); 4411 if (status == MagickFalse) 4412 return MagickFalse; 4413 4414 status = ComputeEqualizeImage(image,channel,exception); 4415 return status; 4416} 4417 4418 4419 4420MagickExport MagickBooleanType ComputeContrastStretchImageChannel(Image *image, 4421 const ChannelType channel,const double black_point,const double white_point, 4422 ExceptionInfo * _exception) 4423{ 4424#define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color))) 4425#define ContrastStretchImageTag "ContrastStretch/Image" 4426 4427 ExceptionInfo 4428 *exception=_exception; 4429 4430 double 4431 intensity; 4432 4433 FloatPixelPacket 4434 black, 4435 white; 4436 4437 cl_uint4 4438 *histogram=NULL; 4439 4440 PixelPacket 4441 *stretch_map=NULL; 4442 4443 register ssize_t 4444 i; 4445 4446 Image * inputImage; 4447 4448 MagickBooleanType outputReady; 4449 4450 MagickCLEnv clEnv; 4451 4452 cl_int clStatus; 4453 MagickBooleanType status; 4454 4455 size_t global_work_size[2]; 4456 4457 void *inputPixels; 4458 cl_mem_flags mem_flags; 4459 4460 cl_context context; 4461 cl_mem inputImageBuffer; 4462 cl_mem histogramBuffer; 4463 cl_mem stretchMapBuffer; 4464 cl_kernel histogramKernel; 4465 cl_kernel stretchKernel; 4466 cl_command_queue queue; 4467 4468 void* hostPtr; 4469 4470 MagickSizeType length; 4471 4472 inputImage = image; 4473 inputPixels = NULL; 4474 inputImageBuffer = NULL; 4475 histogramBuffer = NULL; 4476 stretchMapBuffer = NULL; 4477 histogramKernel = NULL; 4478 stretchKernel = NULL; 4479 context = NULL; 4480 queue = NULL; 4481 outputReady = MagickFalse; 4482 4483 4484 assert(image != (Image *) NULL); 4485 assert(image->signature == MagickSignature); 4486 if (image->debug != MagickFalse) 4487 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 4488 4489 //exception=(&image->exception); 4490 4491 /* 4492 * initialize opencl env 4493 */ 4494 clEnv = GetDefaultOpenCLEnv(); 4495 context = GetOpenCLContext(clEnv); 4496 queue = AcquireOpenCLCommandQueue(clEnv); 4497 4498 /* 4499 Allocate and initialize histogram arrays. 4500 */ 4501 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram)); 4502 4503 if ((histogram == (cl_uint4 *) NULL)) 4504 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename); 4505 4506 /* reset histogram */ 4507 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram)); 4508 4509 /* 4510 if (IsGrayImage(image,exception) != MagickFalse) 4511 (void) SetImageColorspace(image,GRAYColorspace); 4512 */ 4513 4514 status=MagickTrue; 4515 4516 4517 /* 4518 Form histogram. 4519 */ 4520 /* Create and initialize OpenCL buffers. */ 4521 /* inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); */ 4522 /* assume this will get a writable image */ 4523 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 4524 4525 if (inputPixels == (void *) NULL) 4526 { 4527 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 4528 goto cleanup; 4529 } 4530 /* If the host pointer is aligned to the size of CLPixelPacket, 4531 then use the host buffer directly from the GPU; otherwise, 4532 create a buffer on the GPU and copy the data over */ 4533 if (ALIGNED(inputPixels,CLPixelPacket)) 4534 { 4535 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 4536 } 4537 else 4538 { 4539 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 4540 } 4541 /* create a CL buffer from image pixel buffer */ 4542 length = inputImage->columns * inputImage->rows; 4543 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 4544 if (clStatus != CL_SUCCESS) 4545 { 4546 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4547 goto cleanup; 4548 } 4549 4550 /* If the host pointer is aligned to the size of cl_uint, 4551 then use the host buffer directly from the GPU; otherwise, 4552 create a buffer on the GPU and copy the data over */ 4553 if (ALIGNED(histogram,cl_uint4)) 4554 { 4555 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 4556 hostPtr = histogram; 4557 } 4558 else 4559 { 4560 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 4561 hostPtr = histogram; 4562 } 4563 /* create a CL buffer for histogram */ 4564 length = (MaxMap+1); 4565 histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus); 4566 if (clStatus != CL_SUCCESS) 4567 { 4568 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4569 goto cleanup; 4570 } 4571 4572 status = LaunchHistogramKernel(clEnv, queue, inputImageBuffer, histogramBuffer, image, channel, exception); 4573 if (status == MagickFalse) 4574 goto cleanup; 4575 4576 /* read from the kenel output */ 4577 if (ALIGNED(histogram,cl_uint4)) 4578 { 4579 length = (MaxMap+1); 4580 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus); 4581 } 4582 else 4583 { 4584 length = (MaxMap+1); 4585 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL); 4586 } 4587 if (clStatus != CL_SUCCESS) 4588 { 4589 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 4590 goto cleanup; 4591 } 4592 4593 /* unmap, don't block gpu to use this buffer again. */ 4594 if (ALIGNED(histogram,cl_uint4)) 4595 { 4596 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL); 4597 if (clStatus != CL_SUCCESS) 4598 { 4599 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 4600 goto cleanup; 4601 } 4602 } 4603 4604 /* recreate input buffer later, in case image updated */ 4605#ifdef RECREATEBUFFER 4606 if (inputImageBuffer!=NULL) 4607 clEnv->library->clReleaseMemObject(inputImageBuffer); 4608#endif 4609 4610 /* CPU stuff */ 4611 /* 4612 Find the histogram boundaries by locating the black/white levels. 4613 */ 4614 black.red=0.0; 4615 white.red=MaxRange(QuantumRange); 4616 if ((channel & RedChannel) != 0) 4617 { 4618 intensity=0.0; 4619 for (i=0; i <= (ssize_t) MaxMap; i++) 4620 { 4621 intensity+=histogram[i].s[2]; 4622 if (intensity > black_point) 4623 break; 4624 } 4625 black.red=(MagickRealType) i; 4626 intensity=0.0; 4627 for (i=(ssize_t) MaxMap; i != 0; i--) 4628 { 4629 intensity+=histogram[i].s[2]; 4630 if (intensity > ((double) image->columns*image->rows-white_point)) 4631 break; 4632 } 4633 white.red=(MagickRealType) i; 4634 } 4635 black.green=0.0; 4636 white.green=MaxRange(QuantumRange); 4637 if ((channel & GreenChannel) != 0) 4638 { 4639 intensity=0.0; 4640 for (i=0; i <= (ssize_t) MaxMap; i++) 4641 { 4642 intensity+=histogram[i].s[2]; 4643 if (intensity > black_point) 4644 break; 4645 } 4646 black.green=(MagickRealType) i; 4647 intensity=0.0; 4648 for (i=(ssize_t) MaxMap; i != 0; i--) 4649 { 4650 intensity+=histogram[i].s[2]; 4651 if (intensity > ((double) image->columns*image->rows-white_point)) 4652 break; 4653 } 4654 white.green=(MagickRealType) i; 4655 } 4656 black.blue=0.0; 4657 white.blue=MaxRange(QuantumRange); 4658 if ((channel & BlueChannel) != 0) 4659 { 4660 intensity=0.0; 4661 for (i=0; i <= (ssize_t) MaxMap; i++) 4662 { 4663 intensity+=histogram[i].s[2]; 4664 if (intensity > black_point) 4665 break; 4666 } 4667 black.blue=(MagickRealType) i; 4668 intensity=0.0; 4669 for (i=(ssize_t) MaxMap; i != 0; i--) 4670 { 4671 intensity+=histogram[i].s[2]; 4672 if (intensity > ((double) image->columns*image->rows-white_point)) 4673 break; 4674 } 4675 white.blue=(MagickRealType) i; 4676 } 4677 black.opacity=0.0; 4678 white.opacity=MaxRange(QuantumRange); 4679 if ((channel & OpacityChannel) != 0) 4680 { 4681 intensity=0.0; 4682 for (i=0; i <= (ssize_t) MaxMap; i++) 4683 { 4684 intensity+=histogram[i].s[2]; 4685 if (intensity > black_point) 4686 break; 4687 } 4688 black.opacity=(MagickRealType) i; 4689 intensity=0.0; 4690 for (i=(ssize_t) MaxMap; i != 0; i--) 4691 { 4692 intensity+=histogram[i].s[2]; 4693 if (intensity > ((double) image->columns*image->rows-white_point)) 4694 break; 4695 } 4696 white.opacity=(MagickRealType) i; 4697 } 4698 /* 4699 black.index=0.0; 4700 white.index=MaxRange(QuantumRange); 4701 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace)) 4702 { 4703 intensity=0.0; 4704 for (i=0; i <= (ssize_t) MaxMap; i++) 4705 { 4706 intensity+=histogram[i].index; 4707 if (intensity > black_point) 4708 break; 4709 } 4710 black.index=(MagickRealType) i; 4711 intensity=0.0; 4712 for (i=(ssize_t) MaxMap; i != 0; i--) 4713 { 4714 intensity+=histogram[i].index; 4715 if (intensity > ((double) image->columns*image->rows-white_point)) 4716 break; 4717 } 4718 white.index=(MagickRealType) i; 4719 } 4720 */ 4721 4722 4723 stretch_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL, 4724 sizeof(*stretch_map)); 4725 4726 if ((stretch_map == (PixelPacket *) NULL)) 4727 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 4728 image->filename); 4729 4730 /* 4731 Stretch the histogram to create the stretched image mapping. 4732 */ 4733 (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map)); 4734 for (i=0; i <= (ssize_t) MaxMap; i++) 4735 { 4736 if ((channel & RedChannel) != 0) 4737 { 4738 if (i < (ssize_t) black.red) 4739 stretch_map[i].red=(Quantum) 0; 4740 else 4741 if (i > (ssize_t) white.red) 4742 stretch_map[i].red=QuantumRange; 4743 else 4744 if (black.red != white.red) 4745 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap* 4746 (i-black.red)/(white.red-black.red))); 4747 } 4748 if ((channel & GreenChannel) != 0) 4749 { 4750 if (i < (ssize_t) black.green) 4751 stretch_map[i].green=0; 4752 else 4753 if (i > (ssize_t) white.green) 4754 stretch_map[i].green=QuantumRange; 4755 else 4756 if (black.green != white.green) 4757 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap* 4758 (i-black.green)/(white.green-black.green))); 4759 } 4760 if ((channel & BlueChannel) != 0) 4761 { 4762 if (i < (ssize_t) black.blue) 4763 stretch_map[i].blue=0; 4764 else 4765 if (i > (ssize_t) white.blue) 4766 stretch_map[i].blue= QuantumRange; 4767 else 4768 if (black.blue != white.blue) 4769 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap* 4770 (i-black.blue)/(white.blue-black.blue))); 4771 } 4772 if ((channel & OpacityChannel) != 0) 4773 { 4774 if (i < (ssize_t) black.opacity) 4775 stretch_map[i].opacity=0; 4776 else 4777 if (i > (ssize_t) white.opacity) 4778 stretch_map[i].opacity=QuantumRange; 4779 else 4780 if (black.opacity != white.opacity) 4781 stretch_map[i].opacity=ScaleMapToQuantum((MagickRealType) (MaxMap* 4782 (i-black.opacity)/(white.opacity-black.opacity))); 4783 } 4784 /* 4785 if (((channel & IndexChannel) != 0) && 4786 (image->colorspace == CMYKColorspace)) 4787 { 4788 if (i < (ssize_t) black.index) 4789 stretch_map[i].index=0; 4790 else 4791 if (i > (ssize_t) white.index) 4792 stretch_map[i].index=QuantumRange; 4793 else 4794 if (black.index != white.index) 4795 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap* 4796 (i-black.index)/(white.index-black.index))); 4797 } 4798 */ 4799 } 4800 4801 /* 4802 Stretch the image. 4803 */ 4804 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) && 4805 (image->colorspace == CMYKColorspace))) 4806 image->storage_class=DirectClass; 4807 if (image->storage_class == PseudoClass) 4808 { 4809 /* 4810 Stretch colormap. 4811 */ 4812 for (i=0; i < (ssize_t) image->colors; i++) 4813 { 4814 if ((channel & RedChannel) != 0) 4815 { 4816 if (black.red != white.red) 4817 image->colormap[i].red=stretch_map[ 4818 ScaleQuantumToMap(image->colormap[i].red)].red; 4819 } 4820 if ((channel & GreenChannel) != 0) 4821 { 4822 if (black.green != white.green) 4823 image->colormap[i].green=stretch_map[ 4824 ScaleQuantumToMap(image->colormap[i].green)].green; 4825 } 4826 if ((channel & BlueChannel) != 0) 4827 { 4828 if (black.blue != white.blue) 4829 image->colormap[i].blue=stretch_map[ 4830 ScaleQuantumToMap(image->colormap[i].blue)].blue; 4831 } 4832 if ((channel & OpacityChannel) != 0) 4833 { 4834 if (black.opacity != white.opacity) 4835 image->colormap[i].opacity=stretch_map[ 4836 ScaleQuantumToMap(image->colormap[i].opacity)].opacity; 4837 } 4838 } 4839 } 4840 4841 /* 4842 Stretch image. 4843 */ 4844 4845 4846 /* GPU can work on this again, image and equalize map as input 4847 image: uchar4 (CLPixelPacket) 4848 stretch_map: uchar4 (PixelPacket) 4849 black, white: float4 (FloatPixelPacket) */ 4850 4851#ifdef RECREATEBUFFER 4852 /* If the host pointer is aligned to the size of CLPixelPacket, 4853 then use the host buffer directly from the GPU; otherwise, 4854 create a buffer on the GPU and copy the data over */ 4855 if (ALIGNED(inputPixels,CLPixelPacket)) 4856 { 4857 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 4858 } 4859 else 4860 { 4861 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 4862 } 4863 /* create a CL buffer from image pixel buffer */ 4864 length = inputImage->columns * inputImage->rows; 4865 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 4866 if (clStatus != CL_SUCCESS) 4867 { 4868 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4869 goto cleanup; 4870 } 4871#endif 4872 4873 /* Create and initialize OpenCL buffers. */ 4874 if (ALIGNED(stretch_map, PixelPacket)) 4875 { 4876 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 4877 hostPtr = stretch_map; 4878 } 4879 else 4880 { 4881 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 4882 hostPtr = stretch_map; 4883 } 4884 /* create a CL buffer for stretch_map */ 4885 length = (MaxMap+1); 4886 stretchMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus); 4887 if (clStatus != CL_SUCCESS) 4888 { 4889 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 4890 goto cleanup; 4891 } 4892 4893 /* get the OpenCL kernel */ 4894 stretchKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Stretch"); 4895 if (stretchKernel == NULL) 4896 { 4897 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", "."); 4898 goto cleanup; 4899 } 4900 4901 /* set the kernel arguments */ 4902 i = 0; 4903 clStatus=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&inputImageBuffer); 4904 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(ChannelType),&channel); 4905 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&stretchMapBuffer); 4906 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&white); 4907 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&black); 4908 if (clStatus != CL_SUCCESS) 4909 { 4910 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 4911 goto cleanup; 4912 } 4913 4914 /* launch the kernel */ 4915 global_work_size[0] = inputImage->columns; 4916 global_work_size[1] = inputImage->rows; 4917 4918 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, stretchKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 4919 4920 if (clStatus != CL_SUCCESS) 4921 { 4922 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 4923 goto cleanup; 4924 } 4925 clEnv->library->clFlush(queue); 4926 4927 /* read the data back */ 4928 if (ALIGNED(inputPixels,CLPixelPacket)) 4929 { 4930 length = inputImage->columns * inputImage->rows; 4931 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 4932 } 4933 else 4934 { 4935 length = inputImage->columns * inputImage->rows; 4936 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 4937 } 4938 if (clStatus != CL_SUCCESS) 4939 { 4940 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 4941 goto cleanup; 4942 } 4943 4944 outputReady = MagickTrue; 4945 4946cleanup: 4947 OpenCLLogException(__FUNCTION__,__LINE__,exception); 4948 4949 if (inputPixels) { 4950 /*ReleasePixelCachePixels();*/ 4951 inputPixels = NULL; 4952 } 4953 4954 if (inputImageBuffer!=NULL) 4955 clEnv->library->clReleaseMemObject(inputImageBuffer); 4956 4957 if (stretchMapBuffer!=NULL) 4958 clEnv->library->clReleaseMemObject(stretchMapBuffer); 4959 if (stretch_map!=NULL) 4960 stretch_map=(PixelPacket *) RelinquishMagickMemory(stretch_map); 4961 4962 4963 if (histogramBuffer!=NULL) 4964 clEnv->library->clReleaseMemObject(histogramBuffer); 4965 if (histogram!=NULL) 4966 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram); 4967 4968 4969 if (histogramKernel!=NULL) 4970 RelinquishOpenCLKernel(clEnv, histogramKernel); 4971 if (stretchKernel!=NULL) 4972 RelinquishOpenCLKernel(clEnv, stretchKernel); 4973 4974 if (queue != NULL) 4975 RelinquishOpenCLCommandQueue(clEnv, queue); 4976 4977 return outputReady; 4978} 4979 4980 4981/* 4982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4983% % 4984% % 4985% % 4986% C o n t r a s t S t r e t c h I m a g e w i t h O p e n C L % 4987% % 4988% % 4989% % 4990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4991% 4992% ContrastStretchImage() is a simple image enhancement technique that attempts 4993% to improve the contrast in an image by `stretching' the range of intensity 4994% values it contains to span a desired range of values. It differs from the 4995% more sophisticated histogram equalization in that it can only apply a 4996% linear scaling function to the image pixel values. As a result the 4997% `enhancement' is less harsh. 4998% 4999% The format of the ContrastStretchImage method is: 5000% 5001% MagickBooleanType ContrastStretchImage(Image *image, 5002% const char *levels) 5003% MagickBooleanType ContrastStretchImageChannel(Image *image, 5004% const size_t channel,const double black_point, 5005% const double white_point) 5006% 5007% A description of each parameter follows: 5008% 5009% o image: the image. 5010% 5011% o channel: the channel. 5012% 5013% o black_point: the black point. 5014% 5015% o white_point: the white point. 5016% 5017% o levels: Specify the levels where the black and white points have the 5018% range of 0 to number-of-pixels (e.g. 1%, 10x90%, etc.). 5019% 5020*/ 5021 5022MagickExport MagickBooleanType AccelerateContrastStretchImageChannel( 5023 Image * image, const ChannelType channel, const double black_point, const double white_point, 5024 ExceptionInfo* exception) 5025{ 5026 MagickBooleanType status; 5027 5028 assert(image != NULL); 5029 assert(exception != NULL); 5030 5031 status = checkOpenCLEnvironment(exception); 5032 if (status == MagickFalse) 5033 return MagickFalse; 5034 5035 status = checkAccelerateCondition(image, channel); 5036 if (status == MagickFalse) 5037 return MagickFalse; 5038 5039 status = checkHistogramCondition(image, channel); 5040 if (status == MagickFalse) 5041 return MagickFalse; 5042 5043 status = ComputeContrastStretchImageChannel(image,channel, black_point, white_point, exception); 5044 5045 return status; 5046} 5047 5048 5049static Image* ComputeDespeckleImage(const Image* inputImage, ExceptionInfo* exception) 5050{ 5051 5052 MagickBooleanType outputReady = MagickFalse; 5053 MagickCLEnv clEnv = NULL; 5054 5055 cl_int clStatus; 5056 size_t global_work_size[2]; 5057 5058 const void *inputPixels = NULL; 5059 Image* filteredImage = NULL; 5060 void *filteredPixels = NULL; 5061 void *hostPtr; 5062 MagickSizeType length; 5063 5064 cl_mem_flags mem_flags; 5065 cl_context context = NULL; 5066 cl_mem inputImageBuffer = NULL; 5067 cl_mem tempImageBuffer[2]; 5068 cl_mem filteredImageBuffer = NULL; 5069 cl_command_queue queue = NULL; 5070 cl_kernel hullPass1 = NULL; 5071 cl_kernel hullPass2 = NULL; 5072 5073 unsigned int imageWidth, imageHeight; 5074 int matte; 5075 int k; 5076 5077 static const int 5078 X[4] = {0, 1, 1,-1}, 5079 Y[4] = {1, 0, 1, 1}; 5080 5081 tempImageBuffer[0] = tempImageBuffer[1] = NULL; 5082 clEnv = GetDefaultOpenCLEnv(); 5083 context = GetOpenCLContext(clEnv); 5084 queue = AcquireOpenCLCommandQueue(clEnv); 5085 5086 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 5087 if (inputPixels == (void *) NULL) 5088 { 5089 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 5090 goto cleanup; 5091 } 5092 5093 if (ALIGNED(inputPixels,CLPixelPacket)) 5094 { 5095 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 5096 } 5097 else 5098 { 5099 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 5100 } 5101 /* create a CL buffer from image pixel buffer */ 5102 length = inputImage->columns * inputImage->rows; 5103 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 5104 if (clStatus != CL_SUCCESS) 5105 { 5106 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5107 goto cleanup; 5108 } 5109 5110 mem_flags = CL_MEM_READ_WRITE; 5111 length = inputImage->columns * inputImage->rows; 5112 for (k = 0; k < 2; k++) 5113 { 5114 tempImageBuffer[k] = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), NULL, &clStatus); 5115 if (clStatus != CL_SUCCESS) 5116 { 5117 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5118 goto cleanup; 5119 } 5120 } 5121 5122 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 5123 assert(filteredImage != NULL); 5124 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 5125 { 5126 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 5127 goto cleanup; 5128 } 5129 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 5130 if (filteredPixels == (void *) NULL) 5131 { 5132 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 5133 goto cleanup; 5134 } 5135 5136 if (ALIGNED(filteredPixels,CLPixelPacket)) 5137 { 5138 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 5139 hostPtr = filteredPixels; 5140 } 5141 else 5142 { 5143 mem_flags = CL_MEM_WRITE_ONLY; 5144 hostPtr = NULL; 5145 } 5146 /* create a CL buffer from image pixel buffer */ 5147 length = inputImage->columns * inputImage->rows; 5148 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 5149 if (clStatus != CL_SUCCESS) 5150 { 5151 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5152 goto cleanup; 5153 } 5154 5155 hullPass1 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass1"); 5156 hullPass2 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass2"); 5157 5158 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)&inputImageBuffer); 5159 clStatus |=clEnv->library->clSetKernelArg(hullPass1,1,sizeof(cl_mem),(void *)(tempImageBuffer+1)); 5160 imageWidth = inputImage->columns; 5161 clStatus |=clEnv->library->clSetKernelArg(hullPass1,2,sizeof(unsigned int),(void *)&imageWidth); 5162 imageHeight = inputImage->rows; 5163 clStatus |=clEnv->library->clSetKernelArg(hullPass1,3,sizeof(unsigned int),(void *)&imageHeight); 5164 matte = (inputImage->matte==MagickFalse)?0:1; 5165 clStatus |=clEnv->library->clSetKernelArg(hullPass1,6,sizeof(int),(void *)&matte); 5166 if (clStatus != CL_SUCCESS) 5167 { 5168 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5169 goto cleanup; 5170 } 5171 5172 clStatus = clEnv->library->clSetKernelArg(hullPass2,0,sizeof(cl_mem),(void *)(tempImageBuffer+1)); 5173 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)tempImageBuffer); 5174 imageWidth = inputImage->columns; 5175 clStatus |=clEnv->library->clSetKernelArg(hullPass2,2,sizeof(unsigned int),(void *)&imageWidth); 5176 imageHeight = inputImage->rows; 5177 clStatus |=clEnv->library->clSetKernelArg(hullPass2,3,sizeof(unsigned int),(void *)&imageHeight); 5178 matte = (inputImage->matte==MagickFalse)?0:1; 5179 clStatus |=clEnv->library->clSetKernelArg(hullPass2,6,sizeof(int),(void *)&matte); 5180 if (clStatus != CL_SUCCESS) 5181 { 5182 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5183 goto cleanup; 5184 } 5185 5186 5187 global_work_size[0] = inputImage->columns; 5188 global_work_size[1] = inputImage->rows; 5189 5190 5191 for (k = 0; k < 4; k++) 5192 { 5193 cl_int2 offset; 5194 int polarity; 5195 5196 5197 offset.s[0] = X[k]; 5198 offset.s[1] = Y[k]; 5199 polarity = 1; 5200 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset); 5201 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity); 5202 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset); 5203 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity); 5204 if (clStatus != CL_SUCCESS) 5205 { 5206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5207 goto cleanup; 5208 } 5209 /* launch the kernel */ 5210 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5211 if (clStatus != CL_SUCCESS) 5212 { 5213 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5214 goto cleanup; 5215 } 5216 /* launch the kernel */ 5217 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5218 if (clStatus != CL_SUCCESS) 5219 { 5220 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5221 goto cleanup; 5222 } 5223 5224 5225 if (k == 0) 5226 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)(tempImageBuffer)); 5227 offset.s[0] = -X[k]; 5228 offset.s[1] = -Y[k]; 5229 polarity = 1; 5230 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset); 5231 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity); 5232 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset); 5233 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity); 5234 if (clStatus != CL_SUCCESS) 5235 { 5236 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5237 goto cleanup; 5238 } 5239 /* launch the kernel */ 5240 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5241 if (clStatus != CL_SUCCESS) 5242 { 5243 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5244 goto cleanup; 5245 } 5246 /* launch the kernel */ 5247 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5248 if (clStatus != CL_SUCCESS) 5249 { 5250 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5251 goto cleanup; 5252 } 5253 5254 offset.s[0] = -X[k]; 5255 offset.s[1] = -Y[k]; 5256 polarity = -1; 5257 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset); 5258 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity); 5259 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset); 5260 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity); 5261 if (clStatus != CL_SUCCESS) 5262 { 5263 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5264 goto cleanup; 5265 } 5266 /* launch the kernel */ 5267 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5268 if (clStatus != CL_SUCCESS) 5269 { 5270 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5271 goto cleanup; 5272 } 5273 /* launch the kernel */ 5274 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5275 if (clStatus != CL_SUCCESS) 5276 { 5277 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5278 goto cleanup; 5279 } 5280 5281 offset.s[0] = X[k]; 5282 offset.s[1] = Y[k]; 5283 polarity = -1; 5284 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset); 5285 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity); 5286 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset); 5287 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity); 5288 5289 if (k == 3) 5290 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)&filteredImageBuffer); 5291 5292 if (clStatus != CL_SUCCESS) 5293 { 5294 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5295 goto cleanup; 5296 } 5297 /* launch the kernel */ 5298 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5299 if (clStatus != CL_SUCCESS) 5300 { 5301 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5302 goto cleanup; 5303 } 5304 /* launch the kernel */ 5305 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL); 5306 if (clStatus != CL_SUCCESS) 5307 { 5308 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 5309 goto cleanup; 5310 } 5311 } 5312 5313 if (ALIGNED(filteredPixels,CLPixelPacket)) 5314 { 5315 length = inputImage->columns * inputImage->rows; 5316 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 5317 } 5318 else 5319 { 5320 length = inputImage->columns * inputImage->rows; 5321 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 5322 } 5323 if (clStatus != CL_SUCCESS) 5324 { 5325 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 5326 goto cleanup; 5327 } 5328 5329 outputReady = MagickTrue; 5330 5331cleanup: 5332 OpenCLLogException(__FUNCTION__,__LINE__,exception); 5333 5334 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 5335 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 5336 for (k = 0; k < 2; k++) 5337 { 5338 if (tempImageBuffer[k]!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer[k]); 5339 } 5340 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 5341 if (hullPass1!=NULL) RelinquishOpenCLKernel(clEnv, hullPass1); 5342 if (hullPass2!=NULL) RelinquishOpenCLKernel(clEnv, hullPass2); 5343 if (outputReady == MagickFalse) 5344 { 5345 if (filteredImage != NULL) 5346 { 5347 DestroyImage(filteredImage); 5348 filteredImage = NULL; 5349 } 5350 } 5351 return filteredImage; 5352} 5353 5354/* 5355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5356% % 5357% % 5358% % 5359% D e s p e c k l e I m a g e w i t h O p e n C L % 5360% % 5361% % 5362% % 5363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 5364% 5365% DespeckleImage() reduces the speckle noise in an image while perserving the 5366% edges of the original image. A speckle removing filter uses a complementary 5367% hulling technique (raising pixels that are darker than their surrounding 5368% neighbors, then complementarily lowering pixels that are brighter than their 5369% surrounding neighbors) to reduce the speckle index of that image (reference 5370% Crimmins speckle removal). 5371% 5372% The format of the DespeckleImage method is: 5373% 5374% Image *DespeckleImage(const Image *image,ExceptionInfo *exception) 5375% 5376% A description of each parameter follows: 5377% 5378% o image: the image. 5379% 5380% o exception: return any errors or warnings in this structure. 5381% 5382*/ 5383 5384MagickExport 5385Image* AccelerateDespeckleImage(const Image* image, ExceptionInfo* exception) 5386{ 5387 MagickBooleanType status; 5388 Image* newImage = NULL; 5389 5390 assert(image != NULL); 5391 assert(exception != NULL); 5392 5393 status = checkOpenCLEnvironment(exception); 5394 if (status == MagickFalse) 5395 return NULL; 5396 5397 status = checkAccelerateCondition(image, AllChannels); 5398 if (status == MagickFalse) 5399 return NULL; 5400 5401 newImage = ComputeDespeckleImage(image,exception); 5402 return newImage; 5403} 5404 5405static Image* ComputeAddNoiseImage(const Image* inputImage, 5406 const ChannelType channel, const NoiseType noise_type, 5407 ExceptionInfo *exception) 5408{ 5409 MagickBooleanType outputReady = MagickFalse; 5410 MagickCLEnv clEnv = NULL; 5411 5412 cl_int clStatus; 5413 size_t global_work_size[2]; 5414 5415 const void *inputPixels = NULL; 5416 Image* filteredImage = NULL; 5417 void *filteredPixels = NULL; 5418 void *hostPtr; 5419 unsigned int inputColumns, inputRows; 5420 float attenuate; 5421 float *randomNumberBufferPtr = NULL; 5422 MagickSizeType length; 5423 unsigned int numRandomNumberPerPixel; 5424 unsigned int numRowsPerKernelLaunch; 5425 unsigned int numRandomNumberPerBuffer; 5426 unsigned int r; 5427 unsigned int k; 5428 int i; 5429 5430 RandomInfo **restrict random_info; 5431 const char *option; 5432#if defined(MAGICKCORE_OPENMP_SUPPORT) 5433 unsigned long key; 5434#endif 5435 5436 cl_mem_flags mem_flags; 5437 cl_context context = NULL; 5438 cl_mem inputImageBuffer = NULL; 5439 cl_mem randomNumberBuffer = NULL; 5440 cl_mem filteredImageBuffer = NULL; 5441 cl_command_queue queue = NULL; 5442 cl_kernel addNoiseKernel = NULL; 5443 5444 5445 clEnv = GetDefaultOpenCLEnv(); 5446 context = GetOpenCLContext(clEnv); 5447 queue = AcquireOpenCLCommandQueue(clEnv); 5448 5449 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 5450 if (inputPixels == (void *) NULL) 5451 { 5452 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 5453 goto cleanup; 5454 } 5455 5456 if (ALIGNED(inputPixels,CLPixelPacket)) 5457 { 5458 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 5459 } 5460 else 5461 { 5462 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 5463 } 5464 /* create a CL buffer from image pixel buffer */ 5465 length = inputImage->columns * inputImage->rows; 5466 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 5467 if (clStatus != CL_SUCCESS) 5468 { 5469 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5470 goto cleanup; 5471 } 5472 5473 5474 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 5475 assert(filteredImage != NULL); 5476 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 5477 { 5478 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 5479 goto cleanup; 5480 } 5481 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 5482 if (filteredPixels == (void *) NULL) 5483 { 5484 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 5485 goto cleanup; 5486 } 5487 5488 if (ALIGNED(filteredPixels,CLPixelPacket)) 5489 { 5490 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 5491 hostPtr = filteredPixels; 5492 } 5493 else 5494 { 5495 mem_flags = CL_MEM_WRITE_ONLY; 5496 hostPtr = NULL; 5497 } 5498 /* create a CL buffer from image pixel buffer */ 5499 length = inputImage->columns * inputImage->rows; 5500 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 5501 if (clStatus != CL_SUCCESS) 5502 { 5503 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5504 goto cleanup; 5505 } 5506 5507 /* find out how many random numbers needed by pixel */ 5508 numRandomNumberPerPixel = 0; 5509 { 5510 unsigned int numRandPerChannel = 0; 5511 switch (noise_type) 5512 { 5513 case UniformNoise: 5514 case ImpulseNoise: 5515 case LaplacianNoise: 5516 case RandomNoise: 5517 default: 5518 numRandPerChannel = 1; 5519 break; 5520 case GaussianNoise: 5521 case MultiplicativeGaussianNoise: 5522 case PoissonNoise: 5523 numRandPerChannel = 2; 5524 break; 5525 }; 5526 5527 if ((channel & RedChannel) != 0) 5528 numRandomNumberPerPixel+=numRandPerChannel; 5529 if ((channel & GreenChannel) != 0) 5530 numRandomNumberPerPixel+=numRandPerChannel; 5531 if ((channel & BlueChannel) != 0) 5532 numRandomNumberPerPixel+=numRandPerChannel; 5533 if ((channel & OpacityChannel) != 0) 5534 numRandomNumberPerPixel+=numRandPerChannel; 5535 } 5536 5537 numRowsPerKernelLaunch = 512; 5538 /* create a buffer for random numbers */ 5539 numRandomNumberPerBuffer = (inputImage->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel; 5540 randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, numRandomNumberPerBuffer*sizeof(float) 5541 , NULL, &clStatus); 5542 5543 5544 /* set up the random number generators */ 5545 attenuate=1.0; 5546 option=GetImageArtifact(inputImage,"attenuate"); 5547 if (option != (char *) NULL) 5548 attenuate=StringToDouble(option,(char **) NULL); 5549 random_info=AcquireRandomInfoThreadSet(); 5550#if defined(MAGICKCORE_OPENMP_SUPPORT) 5551 key=GetRandomSecretKey(random_info[0]); 5552#endif 5553 5554 addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage"); 5555 5556 k = 0; 5557 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&inputImageBuffer); 5558 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer); 5559 inputColumns = inputImage->columns; 5560 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns); 5561 inputRows = inputImage->rows; 5562 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows); 5563 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel); 5564 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type); 5565 attenuate=1.0f; 5566 option=GetImageArtifact(inputImage,"attenuate"); 5567 if (option != (char *) NULL) 5568 attenuate=(float)StringToDouble(option,(char **) NULL); 5569 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate); 5570 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer); 5571 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel); 5572 5573 global_work_size[0] = inputColumns; 5574 for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch) 5575 { 5576 /* Generate random numbers in the buffer */ 5577 randomNumberBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, randomNumberBuffer, CL_TRUE, CL_MAP_WRITE, 0 5578 , numRandomNumberPerBuffer*sizeof(float), 0, NULL, NULL, &clStatus); 5579 if (clStatus != CL_SUCCESS) 5580 { 5581 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 5582 goto cleanup; 5583 } 5584 5585#if defined(MAGICKCORE_OPENMP_SUPPORT) 5586 #pragma omp parallel for schedule(static,4) \ 5587 num_threads((key == ~0UL) == 0 ? 1 : (size_t) GetMagickResourceLimit(ThreadResource)) 5588#endif 5589 for (i = 0; i < numRandomNumberPerBuffer; i++) 5590 { 5591 const int id = GetOpenMPThreadId(); 5592 randomNumberBufferPtr[i] = (float)GetPseudoRandomValue(random_info[id]); 5593 } 5594 5595 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberBuffer, randomNumberBufferPtr, 0, NULL, NULL); 5596 if (clStatus != CL_SUCCESS) 5597 { 5598 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.","."); 5599 goto cleanup; 5600 } 5601 5602 /* set the row offset */ 5603 clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r); 5604 global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r); 5605 clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL); 5606 } 5607 5608 if (ALIGNED(filteredPixels,CLPixelPacket)) 5609 { 5610 length = inputImage->columns * inputImage->rows; 5611 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 5612 } 5613 else 5614 { 5615 length = inputImage->columns * inputImage->rows; 5616 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 5617 } 5618 if (clStatus != CL_SUCCESS) 5619 { 5620 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 5621 goto cleanup; 5622 } 5623 5624 outputReady = MagickTrue; 5625 5626cleanup: 5627 OpenCLLogException(__FUNCTION__,__LINE__,exception); 5628 5629 if (queue!=NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 5630 if (addNoiseKernel!=NULL) RelinquishOpenCLKernel(clEnv, addNoiseKernel); 5631 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 5632 if (randomNumberBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberBuffer); 5633 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 5634 if (outputReady == MagickFalse 5635 && filteredImage != NULL) 5636 { 5637 DestroyImage(filteredImage); 5638 filteredImage = NULL; 5639 } 5640 return filteredImage; 5641} 5642 5643 5644static Image* ComputeAddNoiseImageOptRandomNum(const Image* inputImage, 5645 const ChannelType channel, const NoiseType noise_type, 5646 ExceptionInfo *exception) 5647{ 5648 MagickBooleanType outputReady = MagickFalse; 5649 MagickCLEnv clEnv = NULL; 5650 5651 cl_int clStatus; 5652 size_t global_work_size[2]; 5653 size_t random_work_size; 5654 5655 const void *inputPixels = NULL; 5656 Image* filteredImage = NULL; 5657 void *filteredPixels = NULL; 5658 void *hostPtr; 5659 unsigned int inputColumns, inputRows; 5660 float attenuate; 5661 MagickSizeType length; 5662 unsigned int numRandomNumberPerPixel; 5663 unsigned int numRowsPerKernelLaunch; 5664 unsigned int numRandomNumberPerBuffer; 5665 unsigned int numRandomNumberGenerators; 5666 unsigned int initRandom; 5667 float fNormalize; 5668 unsigned int r; 5669 unsigned int k; 5670 int i; 5671 const char *option; 5672 5673 cl_mem_flags mem_flags; 5674 cl_context context = NULL; 5675 cl_mem inputImageBuffer = NULL; 5676 cl_mem randomNumberBuffer = NULL; 5677 cl_mem filteredImageBuffer = NULL; 5678 cl_mem randomNumberSeedsBuffer = NULL; 5679 cl_command_queue queue = NULL; 5680 cl_kernel addNoiseKernel = NULL; 5681 cl_kernel randomNumberGeneratorKernel = NULL; 5682 5683 5684 clEnv = GetDefaultOpenCLEnv(); 5685 context = GetOpenCLContext(clEnv); 5686 queue = AcquireOpenCLCommandQueue(clEnv); 5687 5688 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 5689 if (inputPixels == (void *) NULL) 5690 { 5691 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 5692 goto cleanup; 5693 } 5694 5695 if (ALIGNED(inputPixels,CLPixelPacket)) 5696 { 5697 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 5698 } 5699 else 5700 { 5701 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 5702 } 5703 /* create a CL buffer from image pixel buffer */ 5704 length = inputImage->columns * inputImage->rows; 5705 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 5706 if (clStatus != CL_SUCCESS) 5707 { 5708 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5709 goto cleanup; 5710 } 5711 5712 5713 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows,MagickTrue,exception); 5714 assert(filteredImage != NULL); 5715 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 5716 { 5717 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", "."); 5718 goto cleanup; 5719 } 5720 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 5721 if (filteredPixels == (void *) NULL) 5722 { 5723 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename); 5724 goto cleanup; 5725 } 5726 5727 if (ALIGNED(filteredPixels,CLPixelPacket)) 5728 { 5729 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 5730 hostPtr = filteredPixels; 5731 } 5732 else 5733 { 5734 mem_flags = CL_MEM_WRITE_ONLY; 5735 hostPtr = NULL; 5736 } 5737 /* create a CL buffer from image pixel buffer */ 5738 length = inputImage->columns * inputImage->rows; 5739 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus); 5740 if (clStatus != CL_SUCCESS) 5741 { 5742 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5743 goto cleanup; 5744 } 5745 5746 /* find out how many random numbers needed by pixel */ 5747 numRandomNumberPerPixel = 0; 5748 { 5749 unsigned int numRandPerChannel = 0; 5750 switch (noise_type) 5751 { 5752 case UniformNoise: 5753 case ImpulseNoise: 5754 case LaplacianNoise: 5755 case RandomNoise: 5756 default: 5757 numRandPerChannel = 1; 5758 break; 5759 case GaussianNoise: 5760 case MultiplicativeGaussianNoise: 5761 case PoissonNoise: 5762 numRandPerChannel = 2; 5763 break; 5764 }; 5765 5766 if ((channel & RedChannel) != 0) 5767 numRandomNumberPerPixel+=numRandPerChannel; 5768 if ((channel & GreenChannel) != 0) 5769 numRandomNumberPerPixel+=numRandPerChannel; 5770 if ((channel & BlueChannel) != 0) 5771 numRandomNumberPerPixel+=numRandPerChannel; 5772 if ((channel & OpacityChannel) != 0) 5773 numRandomNumberPerPixel+=numRandPerChannel; 5774 } 5775 5776 numRowsPerKernelLaunch = 512; 5777 5778 /* create a buffer for random numbers */ 5779 numRandomNumberPerBuffer = (inputImage->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel; 5780 randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, numRandomNumberPerBuffer*sizeof(float) 5781 , NULL, &clStatus); 5782 5783 { 5784 /* setup the random number generators */ 5785 unsigned long* seeds; 5786 numRandomNumberGenerators = 512; 5787 randomNumberSeedsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR|CL_MEM_READ_WRITE 5788 , numRandomNumberGenerators * 4 * sizeof(unsigned long), NULL, &clStatus); 5789 if (clStatus != CL_SUCCESS) 5790 { 5791 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 5792 goto cleanup; 5793 } 5794 seeds = (unsigned long*) clEnv->library->clEnqueueMapBuffer(queue, randomNumberSeedsBuffer, CL_TRUE, CL_MAP_WRITE, 0 5795 , numRandomNumberGenerators*4*sizeof(unsigned long), 0, NULL, NULL, &clStatus); 5796 if (clStatus != CL_SUCCESS) 5797 { 5798 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.","."); 5799 goto cleanup; 5800 } 5801 5802 for (i = 0; i < numRandomNumberGenerators; i++) { 5803 RandomInfo* randomInfo = AcquireRandomInfo(); 5804 const unsigned long* s = GetRandomInfoSeed(randomInfo); 5805 5806 if (i == 0) 5807 fNormalize = GetRandomInfoNormalize(randomInfo); 5808 5809 seeds[i*4] = s[0]; 5810 randomInfo = DestroyRandomInfo(randomInfo); 5811 } 5812 5813 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberSeedsBuffer, seeds, 0, NULL, NULL); 5814 if (clStatus != CL_SUCCESS) 5815 { 5816 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.","."); 5817 goto cleanup; 5818 } 5819 5820 randomNumberGeneratorKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE 5821 ,"randomNumberGeneratorKernel"); 5822 5823 k = 0; 5824 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberSeedsBuffer); 5825 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(float),(void *)&fNormalize); 5826 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer); 5827 initRandom = 1; 5828 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&initRandom); 5829 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerBuffer); 5830 5831 random_work_size = numRandomNumberGenerators; 5832 } 5833 5834 addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage"); 5835 k = 0; 5836 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&inputImageBuffer); 5837 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer); 5838 inputColumns = inputImage->columns; 5839 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns); 5840 inputRows = inputImage->rows; 5841 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows); 5842 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel); 5843 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type); 5844 attenuate=1.0f; 5845 option=GetImageArtifact(inputImage,"attenuate"); 5846 if (option != (char *) NULL) 5847 attenuate=(float)StringToDouble(option,(char **) NULL); 5848 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate); 5849 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer); 5850 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel); 5851 5852 global_work_size[0] = inputColumns; 5853 for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch) 5854 { 5855 size_t generator_local_size = 64; 5856 /* Generate random numbers in the buffer */ 5857 clEnv->library->clEnqueueNDRangeKernel(queue,randomNumberGeneratorKernel,1,NULL 5858 ,&random_work_size,&generator_local_size,0,NULL,NULL); 5859 if (initRandom != 0) 5860 { 5861 /* make sure we only do init once */ 5862 initRandom = 0; 5863 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,3,sizeof(unsigned int),(void *)&initRandom); 5864 } 5865 5866 /* set the row offset */ 5867 clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r); 5868 global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r); 5869 clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL); 5870 } 5871 5872 if (ALIGNED(filteredPixels,CLPixelPacket)) 5873 { 5874 length = inputImage->columns * inputImage->rows; 5875 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 5876 } 5877 else 5878 { 5879 length = inputImage->columns * inputImage->rows; 5880 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 5881 } 5882 if (clStatus != CL_SUCCESS) 5883 { 5884 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 5885 goto cleanup; 5886 } 5887 5888 outputReady = MagickTrue; 5889 5890cleanup: 5891 OpenCLLogException(__FUNCTION__,__LINE__,exception); 5892 5893 if (queue!=NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 5894 if (addNoiseKernel!=NULL) RelinquishOpenCLKernel(clEnv, addNoiseKernel); 5895 if (randomNumberGeneratorKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomNumberGeneratorKernel); 5896 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 5897 if (randomNumberBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberBuffer); 5898 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 5899 if (randomNumberSeedsBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberSeedsBuffer); 5900 if (outputReady == MagickFalse 5901 && filteredImage != NULL) 5902 { 5903 DestroyImage(filteredImage); 5904 filteredImage = NULL; 5905 } 5906 return filteredImage; 5907} 5908 5909 5910 5911MagickExport 5912Image* AccelerateAddNoiseImage(const Image *image, const ChannelType channel, 5913 const NoiseType noise_type,ExceptionInfo *exception) 5914{ 5915 MagickBooleanType status; 5916 Image* filteredImage = NULL; 5917 5918 assert(image != NULL); 5919 assert(exception != NULL); 5920 5921 status = checkOpenCLEnvironment(exception); 5922 if (status == MagickFalse) 5923 return NULL; 5924 5925 status = checkAccelerateCondition(image, channel); 5926 if (status == MagickFalse) 5927 return NULL; 5928 5929DisableMSCWarning(4127) 5930 if (sizeof(unsigned long) == 4) 5931RestoreMSCWarning 5932 filteredImage = ComputeAddNoiseImageOptRandomNum(image,channel,noise_type,exception); 5933 else 5934 filteredImage = ComputeAddNoiseImage(image,channel,noise_type,exception); 5935 5936 return filteredImage; 5937} 5938 5939static MagickBooleanType LaunchRandomImageKernel(MagickCLEnv clEnv, 5940 cl_command_queue queue, 5941 cl_mem inputImageBuffer, 5942 const unsigned int imageColumns, 5943 const unsigned int imageRows, 5944 cl_mem seedBuffer, 5945 const unsigned int numGenerators, 5946 ExceptionInfo *exception) 5947{ 5948 MagickBooleanType status = MagickFalse; 5949 size_t global_work_size; 5950 size_t local_work_size; 5951 int k; 5952 5953 cl_int clStatus; 5954 cl_kernel randomImageKernel = NULL; 5955 5956 randomImageKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RandomImage"); 5957 5958 k = 0; 5959 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&inputImageBuffer); 5960 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageColumns); 5961 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageRows); 5962 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&seedBuffer); 5963 { 5964 const float randNormNumerator = 1.0f; 5965 const unsigned int randNormDenominator = (unsigned int)(~0UL); 5966 clEnv->library->clSetKernelArg(randomImageKernel,k++, 5967 sizeof(float),(void*)&randNormNumerator); 5968 clEnv->library->clSetKernelArg(randomImageKernel,k++, 5969 sizeof(cl_uint),(void*)&randNormDenominator); 5970 } 5971 5972 5973 global_work_size = numGenerators; 5974 local_work_size = 64; 5975 5976 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue,randomImageKernel,1,NULL,&global_work_size, 5977 &local_work_size,0,NULL,NULL); 5978 5979 if (clStatus != CL_SUCCESS) 5980 { 5981 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, 5982 "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 5983 goto cleanup; 5984 } 5985 status = MagickTrue; 5986 5987cleanup: 5988 if (randomImageKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomImageKernel); 5989 return status; 5990} 5991 5992static MagickBooleanType ComputeRandomImage(Image* inputImage, 5993 ExceptionInfo* exception) 5994{ 5995 MagickBooleanType status = MagickFalse; 5996 5997 MagickBooleanType outputReady = MagickFalse; 5998 MagickCLEnv clEnv = NULL; 5999 6000 cl_int clStatus; 6001 6002 void *inputPixels = NULL; 6003 MagickSizeType length; 6004 6005 cl_mem_flags mem_flags; 6006 cl_context context = NULL; 6007 cl_mem inputImageBuffer = NULL; 6008 cl_command_queue queue = NULL; 6009 6010 /* Don't release this buffer in this function !!! */ 6011 cl_mem randomNumberSeedsBuffer; 6012 6013 clEnv = GetDefaultOpenCLEnv(); 6014 context = GetOpenCLContext(clEnv); 6015 6016 /* Create and initialize OpenCL buffers. */ 6017 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 6018 if (inputPixels == (void *) NULL) 6019 { 6020 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",inputImage->filename); 6021 goto cleanup; 6022 } 6023 6024 /* If the host pointer is aligned to the size of CLPixelPacket, 6025 then use the host buffer directly from the GPU; otherwise, 6026 create a buffer on the GPU and copy the data over */ 6027 if (ALIGNED(inputPixels,CLPixelPacket)) 6028 { 6029 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 6030 } 6031 else 6032 { 6033 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 6034 } 6035 /* create a CL buffer from image pixel buffer */ 6036 length = inputImage->columns * inputImage->rows; 6037 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 6038 if (clStatus != CL_SUCCESS) 6039 { 6040 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 6041 goto cleanup; 6042 } 6043 6044 queue = AcquireOpenCLCommandQueue(clEnv); 6045 6046 randomNumberSeedsBuffer = GetAndLockRandSeedBuffer(clEnv); 6047 if (randomNumberSeedsBuffer==NULL) 6048 { 6049 (void) OpenCLThrowMagickException(exception, GetMagickModule(), 6050 ResourceLimitWarning, "Failed to get GPU random number generators.", 6051 "'%s'", "."); 6052 goto cleanup; 6053 } 6054 6055 status = LaunchRandomImageKernel(clEnv,queue, 6056 inputImageBuffer, 6057 inputImage->columns, 6058 inputImage->rows, 6059 randomNumberSeedsBuffer, 6060 GetNumRandGenerators(clEnv), 6061 exception); 6062 if (status==MagickFalse) 6063 { 6064 goto cleanup; 6065 } 6066 6067 if (ALIGNED(inputPixels,CLPixelPacket)) 6068 { 6069 length = inputImage->columns * inputImage->rows; 6070 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus); 6071 } 6072 else 6073 { 6074 length = inputImage->columns * inputImage->rows; 6075 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 6076 } 6077 if (clStatus != CL_SUCCESS) 6078 { 6079 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", "."); 6080 goto cleanup; 6081 } 6082 outputReady = MagickTrue; 6083 6084cleanup: 6085 OpenCLLogException(__FUNCTION__,__LINE__,exception); 6086 6087 UnlockRandSeedBuffer(clEnv); 6088 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 6089 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 6090 return outputReady; 6091} 6092 6093MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception) 6094{ 6095 MagickBooleanType status = MagickFalse; 6096 6097 status = checkOpenCLEnvironment(exception); 6098 if (status==MagickFalse) 6099 return status; 6100 6101 status = checkAccelerateCondition(image, AllChannels); 6102 if (status==MagickFalse) 6103 return status; 6104 6105 status = ComputeRandomImage(image,exception); 6106 return status; 6107} 6108 6109static Image* ComputeMotionBlurImage(const Image *inputImage, 6110 const ChannelType channel, const double *kernel, const size_t width, 6111 const OffsetInfo *offset, ExceptionInfo *exception) 6112{ 6113 MagickBooleanType outputReady; 6114 Image* filteredImage; 6115 MagickCLEnv clEnv; 6116 6117 cl_int clStatus; 6118 size_t global_work_size[2]; 6119 size_t local_work_size[2]; 6120 6121 cl_context context; 6122 cl_mem_flags mem_flags; 6123 cl_mem inputImageBuffer, filteredImageBuffer, imageKernelBuffer, 6124 offsetBuffer; 6125 cl_kernel motionBlurKernel; 6126 cl_command_queue queue; 6127 6128 const void *inputPixels; 6129 void *filteredPixels; 6130 void* hostPtr; 6131 float* kernelBufferPtr; 6132 int* offsetBufferPtr; 6133 MagickSizeType length; 6134 unsigned int matte; 6135 MagickPixelPacket bias; 6136 cl_float4 biasPixel; 6137 unsigned int imageWidth, imageHeight; 6138 6139 unsigned int i; 6140 6141 outputReady = MagickFalse; 6142 context = NULL; 6143 filteredImage = NULL; 6144 inputImageBuffer = NULL; 6145 filteredImageBuffer = NULL; 6146 imageKernelBuffer = NULL; 6147 motionBlurKernel = NULL; 6148 queue = NULL; 6149 6150 6151 clEnv = GetDefaultOpenCLEnv(); 6152 context = GetOpenCLContext(clEnv); 6153 6154 /* Create and initialize OpenCL buffers. */ 6155 6156 inputPixels = NULL; 6157 inputPixels = AcquirePixelCachePixels(inputImage, &length, exception); 6158 if (inputPixels == (const void *) NULL) 6159 { 6160 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 6161 "UnableToReadPixelCache.","`%s'",inputImage->filename); 6162 goto cleanup; 6163 } 6164 6165 // If the host pointer is aligned to the size of CLPixelPacket, 6166 // then use the host buffer directly from the GPU; otherwise, 6167 // create a buffer on the GPU and copy the data over 6168 if (ALIGNED(inputPixels,CLPixelPacket)) 6169 { 6170 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 6171 } 6172 else 6173 { 6174 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 6175 } 6176 // create a CL buffer from image pixel buffer 6177 length = inputImage->columns * inputImage->rows; 6178 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, 6179 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 6180 if (clStatus != CL_SUCCESS) 6181 { 6182 (void) ThrowMagickException(exception, GetMagickModule(), 6183 ResourceLimitError, "clEnv->library->clCreateBuffer failed.","."); 6184 goto cleanup; 6185 } 6186 6187 6188 filteredImage = CloneImage(inputImage,inputImage->columns,inputImage->rows, 6189 MagickTrue,exception); 6190 assert(filteredImage != NULL); 6191 if (SetImageStorageClass(filteredImage,DirectClass) != MagickTrue) 6192 { 6193 (void) ThrowMagickException(exception, GetMagickModule(), 6194 ResourceLimitError, "CloneImage failed.", "'%s'", "."); 6195 goto cleanup; 6196 } 6197 filteredPixels = GetPixelCachePixels(filteredImage, &length, exception); 6198 if (filteredPixels == (void *) NULL) 6199 { 6200 (void) ThrowMagickException(exception,GetMagickModule(),CacheError, 6201 "UnableToReadPixelCache.","`%s'",filteredImage->filename); 6202 goto cleanup; 6203 } 6204 6205 if (ALIGNED(filteredPixels,CLPixelPacket)) 6206 { 6207 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR; 6208 hostPtr = filteredPixels; 6209 } 6210 else 6211 { 6212 mem_flags = CL_MEM_WRITE_ONLY; 6213 hostPtr = NULL; 6214 } 6215 // create a CL buffer from image pixel buffer 6216 length = inputImage->columns * inputImage->rows; 6217 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, 6218 length * sizeof(CLPixelPacket), hostPtr, &clStatus); 6219 if (clStatus != CL_SUCCESS) 6220 { 6221 (void) ThrowMagickException(exception, GetMagickModule(), 6222 ResourceLimitError, "clEnv->library->clCreateBuffer failed.","."); 6223 goto cleanup; 6224 } 6225 6226 6227 imageKernelBuffer = clEnv->library->clCreateBuffer(context, 6228 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(float), NULL, 6229 &clStatus); 6230 if (clStatus != CL_SUCCESS) 6231 { 6232 (void) ThrowMagickException(exception, GetMagickModule(), 6233 ResourceLimitError, "clEnv->library->clCreateBuffer failed.","."); 6234 goto cleanup; 6235 } 6236 6237 queue = AcquireOpenCLCommandQueue(clEnv); 6238 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, 6239 CL_TRUE, CL_MAP_WRITE, 0, width * sizeof(float), 0, NULL, NULL, &clStatus); 6240 if (clStatus != CL_SUCCESS) 6241 { 6242 (void) ThrowMagickException(exception, GetMagickModule(), 6243 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.","."); 6244 goto cleanup; 6245 } 6246 for (i = 0; i < width; i++) 6247 { 6248 kernelBufferPtr[i] = (float) kernel[i]; 6249 } 6250 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 6251 0, NULL, NULL); 6252 if (clStatus != CL_SUCCESS) 6253 { 6254 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, 6255 "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 6256 goto cleanup; 6257 } 6258 6259 offsetBuffer = clEnv->library->clCreateBuffer(context, 6260 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(cl_int2), NULL, 6261 &clStatus); 6262 if (clStatus != CL_SUCCESS) 6263 { 6264 (void) ThrowMagickException(exception, GetMagickModule(), 6265 ResourceLimitError, "clEnv->library->clCreateBuffer failed.","."); 6266 goto cleanup; 6267 } 6268 6269 offsetBufferPtr = (int*)clEnv->library->clEnqueueMapBuffer(queue, offsetBuffer, CL_TRUE, 6270 CL_MAP_WRITE, 0, width * sizeof(cl_int2), 0, NULL, NULL, &clStatus); 6271 if (clStatus != CL_SUCCESS) 6272 { 6273 (void) ThrowMagickException(exception, GetMagickModule(), 6274 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.","."); 6275 goto cleanup; 6276 } 6277 for (i = 0; i < width; i++) 6278 { 6279 offsetBufferPtr[2*i] = (int)offset[i].x; 6280 offsetBufferPtr[2*i+1] = (int)offset[i].y; 6281 } 6282 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, offsetBuffer, offsetBufferPtr, 0, 6283 NULL, NULL); 6284 if (clStatus != CL_SUCCESS) 6285 { 6286 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, 6287 "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", "."); 6288 goto cleanup; 6289 } 6290 6291 6292 // get the OpenCL kernel 6293 motionBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, 6294 "MotionBlur"); 6295 if (motionBlurKernel == NULL) 6296 { 6297 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, 6298 "AcquireOpenCLKernel failed.", "'%s'", "."); 6299 goto cleanup; 6300 } 6301 6302 // set the kernel arguments 6303 i = 0; 6304 clStatus=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem), 6305 (void *)&inputImageBuffer); 6306 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem), 6307 (void *)&filteredImageBuffer); 6308 imageWidth = inputImage->columns; 6309 imageHeight = inputImage->rows; 6310 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), 6311 &imageWidth); 6312 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), 6313 &imageHeight); 6314 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem), 6315 (void *)&imageKernelBuffer); 6316 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), 6317 &width); 6318 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem), 6319 (void *)&offsetBuffer); 6320 6321 GetMagickPixelPacket(inputImage,&bias); 6322 biasPixel.s[0] = bias.red; 6323 biasPixel.s[1] = bias.green; 6324 biasPixel.s[2] = bias.blue; 6325 biasPixel.s[3] = bias.opacity; 6326 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_float4), &biasPixel); 6327 6328 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(ChannelType), &channel); 6329 matte = (inputImage->matte == MagickTrue)?1:0; 6330 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), &matte); 6331 if (clStatus != CL_SUCCESS) 6332 { 6333 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, 6334 "clEnv->library->clSetKernelArg failed.", "'%s'", "."); 6335 goto cleanup; 6336 } 6337 6338 // launch the kernel 6339 local_work_size[0] = 16; 6340 local_work_size[1] = 16; 6341 global_work_size[0] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize( 6342 inputImage->columns,local_work_size[0]); 6343 global_work_size[1] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize( 6344 inputImage->rows,local_work_size[1]); 6345 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, motionBlurKernel, 2, NULL, 6346 global_work_size, local_work_size, 0, NULL, NULL); 6347 6348 if (clStatus != CL_SUCCESS) 6349 { 6350 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, 6351 "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", "."); 6352 goto cleanup; 6353 } 6354 clEnv->library->clFlush(queue); 6355 6356 if (ALIGNED(filteredPixels,CLPixelPacket)) 6357 { 6358 length = inputImage->columns * inputImage->rows; 6359 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, 6360 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, 6361 NULL, &clStatus); 6362 } 6363 else 6364 { 6365 length = inputImage->columns * inputImage->rows; 6366 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, 6367 length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL); 6368 } 6369 if (clStatus != CL_SUCCESS) 6370 { 6371 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError, 6372 "Reading output image from CL buffer failed.", "'%s'", "."); 6373 goto cleanup; 6374 } 6375 outputReady = MagickTrue; 6376 6377cleanup: 6378 6379 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer); 6380 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 6381 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer); 6382 if (motionBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, motionBlurKernel); 6383 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 6384 if (outputReady == MagickFalse) 6385 { 6386 if (filteredImage != NULL) 6387 { 6388 DestroyImage(filteredImage); 6389 filteredImage = NULL; 6390 } 6391 } 6392 6393 return filteredImage; 6394} 6395 6396 6397MagickExport 6398Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel, 6399 const double* kernel, const size_t width, const OffsetInfo *offset, 6400 ExceptionInfo *exception) 6401{ 6402 MagickBooleanType status; 6403 Image* filteredImage = NULL; 6404 6405 assert(image != NULL); 6406 assert(kernel != (double *) NULL); 6407 assert(offset != (OffsetInfo *) NULL); 6408 assert(exception != (ExceptionInfo *) NULL); 6409 6410 status = checkOpenCLEnvironment(exception); 6411 if (status == MagickFalse) 6412 return NULL; 6413 6414 status = checkAccelerateCondition(image, channel); 6415 if (status == MagickFalse) 6416 return NULL; 6417 6418 filteredImage = ComputeMotionBlurImage(image, channel, kernel, width, 6419 offset, exception); 6420 return filteredImage; 6421 6422} 6423 6424 6425static MagickBooleanType LaunchCompositeKernel(MagickCLEnv clEnv, 6426 cl_command_queue queue, 6427 cl_mem inputImageBuffer, 6428 const unsigned int inputWidth, const unsigned int inputHeight, 6429 const unsigned int matte, 6430 const ChannelType channel,const CompositeOperator compose, 6431 const cl_mem compositeImageBuffer, 6432 const unsigned int compositeWidth, 6433 const unsigned int compositeHeight, 6434 const float destination_dissolve,const float source_dissolve, 6435 ExceptionInfo *magick_unused(exception)) 6436{ 6437 size_t global_work_size[2]; 6438 size_t local_work_size[2]; 6439 unsigned int composeOp; 6440 int k; 6441 6442 cl_int clStatus; 6443 cl_kernel compositeKernel = NULL; 6444 6445 magick_unreferenced(exception); 6446 6447 compositeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, 6448 "Composite"); 6449 6450 k = 0; 6451 clStatus=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&inputImageBuffer); 6452 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputWidth); 6453 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputHeight); 6454 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&compositeImageBuffer); 6455 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeWidth); 6456 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeHeight); 6457 composeOp = (unsigned int)compose; 6458 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&composeOp); 6459 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(ChannelType),(void*)&channel); 6460 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&matte); 6461 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&destination_dissolve); 6462 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&source_dissolve); 6463 6464 if (clStatus!=CL_SUCCESS) 6465 return MagickFalse; 6466 6467 local_work_size[0] = 64; 6468 local_work_size[1] = 1; 6469 6470 global_work_size[0] = padGlobalWorkgroupSizeToLocalWorkgroupSize(inputWidth, 6471 local_work_size[0]); 6472 global_work_size[1] = inputHeight; 6473 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, compositeKernel, 2, NULL, 6474 global_work_size, local_work_size, 0, NULL, NULL); 6475 6476 6477 RelinquishOpenCLKernel(clEnv, compositeKernel); 6478 6479 return (clStatus==CL_SUCCESS)?MagickTrue:MagickFalse; 6480} 6481 6482 6483static MagickBooleanType ComputeCompositeImage(Image *inputImage, 6484 const ChannelType channel,const CompositeOperator compose, 6485 const Image *compositeImage,const ssize_t magick_unused(x_offset),const ssize_t magick_unused(y_offset), 6486 const float destination_dissolve,const float source_dissolve, 6487 ExceptionInfo *exception) 6488{ 6489 MagickBooleanType status = MagickFalse; 6490 6491 MagickBooleanType outputReady = MagickFalse; 6492 MagickCLEnv clEnv = NULL; 6493 6494 cl_int clStatus; 6495 6496 void *inputPixels = NULL; 6497 const void *composePixels = NULL; 6498 MagickSizeType length; 6499 6500 cl_mem_flags mem_flags; 6501 cl_context context = NULL; 6502 cl_mem inputImageBuffer = NULL; 6503 cl_mem compositeImageBuffer = NULL; 6504 cl_command_queue queue = NULL; 6505 6506 magick_unreferenced(x_offset); 6507 magick_unreferenced(y_offset); 6508 6509 clEnv = GetDefaultOpenCLEnv(); 6510 context = GetOpenCLContext(clEnv); 6511 queue = AcquireOpenCLCommandQueue(clEnv); 6512 6513 /* Create and initialize OpenCL buffers. */ 6514 inputPixels = GetPixelCachePixels(inputImage, &length, exception); 6515 if (inputPixels == (void *) NULL) 6516 { 6517 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, 6518 "UnableToReadPixelCache.","`%s'",inputImage->filename); 6519 goto cleanup; 6520 } 6521 6522 /* If the host pointer is aligned to the size of CLPixelPacket, 6523 then use the host buffer directly from the GPU; otherwise, 6524 create a buffer on the GPU and copy the data over */ 6525 if (ALIGNED(inputPixels,CLPixelPacket)) 6526 { 6527 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR; 6528 } 6529 else 6530 { 6531 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR; 6532 } 6533 /* create a CL buffer from image pixel buffer */ 6534 length = inputImage->columns * inputImage->rows; 6535 inputImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, 6536 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus); 6537 if (clStatus != CL_SUCCESS) 6538 { 6539 (void) OpenCLThrowMagickException(exception, GetMagickModule(), 6540 ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 6541 goto cleanup; 6542 } 6543 6544 6545 /* Create and initialize OpenCL buffers. */ 6546 composePixels = AcquirePixelCachePixels(compositeImage, &length, exception); 6547 if (composePixels == (void *) NULL) 6548 { 6549 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, 6550 "UnableToReadPixelCache.","`%s'",compositeImage->filename); 6551 goto cleanup; 6552 } 6553 6554 /* If the host pointer is aligned to the size of CLPixelPacket, 6555 then use the host buffer directly from the GPU; otherwise, 6556 create a buffer on the GPU and copy the data over */ 6557 if (ALIGNED(composePixels,CLPixelPacket)) 6558 { 6559 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR; 6560 } 6561 else 6562 { 6563 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR; 6564 } 6565 /* create a CL buffer from image pixel buffer */ 6566 length = compositeImage->columns * compositeImage->rows; 6567 compositeImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, 6568 length * sizeof(CLPixelPacket), (void*)composePixels, &clStatus); 6569 if (clStatus != CL_SUCCESS) 6570 { 6571 (void) OpenCLThrowMagickException(exception, GetMagickModule(), 6572 ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.","."); 6573 goto cleanup; 6574 } 6575 6576 status = LaunchCompositeKernel(clEnv,queue,inputImageBuffer, 6577 (unsigned int) inputImage->columns, 6578 (unsigned int) inputImage->rows, 6579 (unsigned int) inputImage->matte, 6580 channel, compose, compositeImageBuffer, 6581 (unsigned int) compositeImage->columns, 6582 (unsigned int) compositeImage->rows, 6583 destination_dissolve,source_dissolve, 6584 exception); 6585 6586 if (status==MagickFalse) 6587 goto cleanup; 6588 6589 length = inputImage->columns * inputImage->rows; 6590 if (ALIGNED(inputPixels,CLPixelPacket)) 6591 { 6592 clEnv->library->clEnqueueMapBuffer(queue, inputImageBuffer, CL_TRUE, 6593 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, 6594 NULL, &clStatus); 6595 } 6596 else 6597 { 6598 clStatus = clEnv->library->clEnqueueReadBuffer(queue, inputImageBuffer, CL_TRUE, 0, 6599 length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL); 6600 } 6601 if (clStatus==CL_SUCCESS) 6602 outputReady = MagickTrue; 6603 6604cleanup: 6605 if (inputImageBuffer!=NULL) clEnv->library->clReleaseMemObject(inputImageBuffer); 6606 if (compositeImageBuffer!=NULL) clEnv->library->clReleaseMemObject(compositeImageBuffer); 6607 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue); 6608 6609 return outputReady; 6610} 6611 6612 6613MagickExport 6614MagickBooleanType AccelerateCompositeImage(Image *image, 6615 const ChannelType channel,const CompositeOperator compose, 6616 const Image *composite,const ssize_t x_offset,const ssize_t y_offset, 6617 const float destination_dissolve,const float source_dissolve, 6618 ExceptionInfo *exception) 6619{ 6620 MagickBooleanType status; 6621 6622 assert(image != NULL); 6623 assert(composite != NULL); 6624 assert(exception != (ExceptionInfo *) NULL); 6625 6626 status = checkOpenCLEnvironment(exception); 6627 if (status == MagickFalse) 6628 return MagickFalse; 6629 6630 status = checkAccelerateCondition(image, channel); 6631 if (status == MagickFalse) 6632 return MagickFalse; 6633 6634 /* only support zero offset and 6635 images with the size for now */ 6636 if (x_offset!=0 6637 || y_offset!=0 6638 || image->columns!=composite->columns 6639 || image->rows!=composite->rows) 6640 return MagickFalse; 6641 6642 switch(compose) { 6643 case ColorDodgeCompositeOp: 6644 case BlendCompositeOp: 6645 break; 6646 default: 6647 // unsupported compose operator, quit 6648 return MagickFalse; 6649 }; 6650 6651 status = ComputeCompositeImage(image,channel,compose,composite, 6652 x_offset,y_offset,destination_dissolve,source_dissolve,exception); 6653 6654 return status; 6655} 6656 6657 6658 6659#else /* MAGICKCORE_OPENCL_SUPPORT */ 6660 6661MagickExport Image *AccelerateConvolveImageChannel( 6662 const Image *magick_unused(image),const ChannelType magick_unused(channel), 6663 const KernelInfo *magick_unused(kernel), 6664 ExceptionInfo *magick_unused(exception)) 6665{ 6666 magick_unreferenced(image); 6667 magick_unreferenced(channel); 6668 magick_unreferenced(kernel); 6669 magick_unreferenced(exception); 6670 6671 return NULL; 6672} 6673 6674MagickExport MagickBooleanType AccelerateFunctionImage( 6675 Image *magick_unused(image),const ChannelType magick_unused(channel), 6676 const MagickFunction magick_unused(function), 6677 const size_t magick_unused(number_parameters), 6678 const double *magick_unused(parameters), 6679 ExceptionInfo *magick_unused(exception)) 6680{ 6681 magick_unreferenced(image); 6682 magick_unreferenced(channel); 6683 magick_unreferenced(function); 6684 magick_unreferenced(number_parameters); 6685 magick_unreferenced(parameters); 6686 magick_unreferenced(exception); 6687 6688 return MagickFalse; 6689} 6690 6691MagickExport Image *AccelerateBlurImage(const Image *magick_unused(image), 6692 const ChannelType magick_unused(channel),const double magick_unused(radius), 6693 const double magick_unused(sigma),ExceptionInfo *magick_unused(exception)) 6694{ 6695 magick_unreferenced(image); 6696 magick_unreferenced(channel); 6697 magick_unreferenced(radius); 6698 magick_unreferenced(sigma); 6699 magick_unreferenced(exception); 6700 6701 return NULL; 6702} 6703 6704MagickExport Image *AccelerateRadialBlurImage( 6705 const Image *magick_unused(image),const ChannelType magick_unused(channel), 6706 const double magick_unused(angle),ExceptionInfo *magick_unused(exception)) 6707{ 6708 magick_unreferenced(image); 6709 magick_unreferenced(channel); 6710 magick_unreferenced(angle); 6711 magick_unreferenced(exception); 6712 6713 return NULL; 6714} 6715 6716 6717MagickExport Image *AccelerateUnsharpMaskImage( 6718 const Image *magick_unused(image),const ChannelType magick_unused(channel), 6719 const double magick_unused(radius),const double magick_unused(sigma), 6720 const double magick_unused(gain),const double magick_unused(threshold), 6721 ExceptionInfo *magick_unused(exception)) 6722{ 6723 magick_unreferenced(image); 6724 magick_unreferenced(channel); 6725 magick_unreferenced(radius); 6726 magick_unreferenced(sigma); 6727 magick_unreferenced(gain); 6728 magick_unreferenced(threshold); 6729 magick_unreferenced(exception); 6730 6731 return NULL; 6732} 6733 6734 6735MagickExport MagickBooleanType AccelerateContrastImage( 6736 Image* magick_unused(image),const MagickBooleanType magick_unused(sharpen), 6737 ExceptionInfo* magick_unused(exception)) 6738{ 6739 magick_unreferenced(image); 6740 magick_unreferenced(sharpen); 6741 magick_unreferenced(exception); 6742 6743 return MagickFalse; 6744} 6745 6746MagickExport MagickBooleanType AcceleratContrastStretchImageChannel( 6747 Image * image, const ChannelType channel, const double black_point, const double white_point, 6748 ExceptionInfo* magick_unused(exception)) 6749{ 6750 magick_unreferenced(image); 6751 magick_unreferenced(channel); 6752 magick_unreferenced(black_point); 6753 magick_unreferenced(white_point); 6754 magick_unreferenced(exception); 6755 6756 return MagickFalse; 6757} 6758 6759MagickExport MagickBooleanType AccelerateEqualizeImage( 6760 Image* magick_unused(image), const ChannelType magick_unused(channel), 6761 ExceptionInfo* magick_unused(exception)) 6762{ 6763 magick_unreferenced(image); 6764 magick_unreferenced(channel); 6765 magick_unreferenced(exception); 6766 6767 return MagickFalse; 6768} 6769 6770MagickExport Image *AccelerateDespeckleImage(const Image* magick_unused(image), 6771 ExceptionInfo* magick_unused(exception)) 6772{ 6773 magick_unreferenced(image); 6774 magick_unreferenced(exception); 6775 6776 return NULL; 6777} 6778 6779MagickExport Image *AccelerateResizeImage(const Image* magick_unused(image), 6780 const size_t magick_unused(resizedColumns), 6781 const size_t magick_unused(resizedRows), 6782 const ResizeFilter* magick_unused(resizeFilter), 6783 ExceptionInfo *magick_unused(exception)) 6784{ 6785 magick_unreferenced(image); 6786 magick_unreferenced(resizedColumns); 6787 magick_unreferenced(resizedRows); 6788 magick_unreferenced(resizeFilter); 6789 magick_unreferenced(exception); 6790 6791 return NULL; 6792} 6793 6794MagickExport 6795MagickBooleanType AccelerateModulateImage( 6796 Image* image, double percent_brightness, double percent_hue, 6797 double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception) 6798{ 6799 magick_unreferenced(image); 6800 magick_unreferenced(percent_brightness); 6801 magick_unreferenced(percent_hue); 6802 magick_unreferenced(percent_saturation); 6803 magick_unreferenced(colorspace); 6804 magick_unreferenced(exception); 6805 return(MagickFalse); 6806} 6807 6808MagickExport 6809MagickBooleanType AccelerateNegateImageChannel( 6810 Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception) 6811{ 6812 magick_unreferenced(image); 6813 magick_unreferenced(channel); 6814 magick_unreferenced(grayscale); 6815 magick_unreferenced(exception); 6816 return(MagickFalse); 6817} 6818 6819MagickExport 6820MagickBooleanType AccelerateGrayscaleImage( 6821 Image* image, const PixelIntensityMethod method, ExceptionInfo* exception) 6822{ 6823 magick_unreferenced(image); 6824 magick_unreferenced(method); 6825 magick_unreferenced(exception); 6826 return(MagickFalse); 6827} 6828 6829MagickExport Image *AccelerateAddNoiseImage(const Image *image, 6830 const ChannelType channel, const NoiseType noise_type,ExceptionInfo *exception) 6831{ 6832 magick_unreferenced(image); 6833 magick_unreferenced(channel); 6834 magick_unreferenced(noise_type); 6835 magick_unreferenced(exception); 6836 return NULL; 6837} 6838 6839 6840MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception) 6841{ 6842 magick_unreferenced(image); 6843 magick_unreferenced(exception); 6844 return MagickFalse; 6845} 6846 6847MagickExport 6848Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel, 6849 const double* kernel, const size_t width, 6850 const OffsetInfo *offset, 6851 ExceptionInfo *exception) 6852{ 6853 magick_unreferenced(image); 6854 magick_unreferenced(channel); 6855 magick_unreferenced(kernel); 6856 magick_unreferenced(width); 6857 magick_unreferenced(offset); 6858 magick_unreferenced(exception); 6859 return NULL; 6860} 6861 6862#endif /* MAGICKCORE_OPENCL_SUPPORT */ 6863 6864MagickExport MagickBooleanType AccelerateConvolveImage( 6865 const Image *magick_unused(image),const KernelInfo *magick_unused(kernel), 6866 Image *magick_unused(convolve_image),ExceptionInfo *magick_unused(exception)) 6867{ 6868 magick_unreferenced(image); 6869 magick_unreferenced(kernel); 6870 magick_unreferenced(convolve_image); 6871 magick_unreferenced(exception); 6872 6873 /* legacy, do not use */ 6874 return(MagickFalse); 6875} 6876 6877