blob: 246386278874e7a76af1d2bcc6b90f75e767d60b [file] [log] [blame]
cristy3f6d1482010-01-20 21:01:21 +00001/*
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 %
cristyde984cd2013-12-01 14:49:27 +000016% Cristy %
cristyf034abb2013-11-24 14:16:14 +000017% SiuChi Chan %
18% Guansong Zhang %
cristy3f6d1482010-01-20 21:01:21 +000019% January 2010 %
20% %
21% %
cristyfe676ee2013-11-18 13:03:38 +000022% Copyright 1999-2014 ImageMagick Studio LLC, a non-profit organization %
cristy3f6d1482010-01-20 21:01:21 +000023% 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%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cristy3f6d1482010-01-20 21:01:21 +000037*/
cristyf034abb2013-11-24 14:16:14 +000038
cristy3f6d1482010-01-20 21:01:21 +000039/*
cristyf034abb2013-11-24 14:16:14 +000040Include declarations.
cristy3f6d1482010-01-20 21:01:21 +000041*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/accelerate.h"
cristyf034abb2013-11-24 14:16:14 +000044#include "MagickCore/accelerate-private.h"
cristy4c08aed2011-07-01 19:47:50 +000045#include "MagickCore/artifact.h"
cristy35f33492011-07-07 16:54:49 +000046#include "MagickCore/cache.h"
cristyd1dd6e42011-09-04 01:46:08 +000047#include "MagickCore/cache-private.h"
cristy4c08aed2011-07-01 19:47:50 +000048#include "MagickCore/cache-view.h"
49#include "MagickCore/color-private.h"
cristy7f866842013-07-11 01:15:58 +000050#include "MagickCore/delegate-private.h"
cristy4c08aed2011-07-01 19:47:50 +000051#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"
cristyf034abb2013-11-24 14:16:14 +000062#include "MagickCore/opencl.h"
63#include "MagickCore/opencl-private.h"
cristy4c08aed2011-07-01 19:47:50 +000064#include "MagickCore/option.h"
cristyf034abb2013-11-24 14:16:14 +000065#include "MagickCore/pixel-private.h"
cristy4c08aed2011-07-01 19:47:50 +000066#include "MagickCore/prepress.h"
67#include "MagickCore/quantize.h"
dirk8a5cf512014-07-28 20:16:27 +000068#include "MagickCore/quantum-private.h"
cristye85d0f72013-11-27 02:25:43 +000069#include "MagickCore/random_.h"
70#include "MagickCore/random-private.h"
cristy4c08aed2011-07-01 19:47:50 +000071#include "MagickCore/registry.h"
cristyf034abb2013-11-24 14:16:14 +000072#include "MagickCore/resize.h"
73#include "MagickCore/resize-private.h"
cristy4c08aed2011-07-01 19:47:50 +000074#include "MagickCore/semaphore.h"
75#include "MagickCore/splay-tree.h"
76#include "MagickCore/statistic.h"
77#include "MagickCore/string_.h"
78#include "MagickCore/string-private.h"
79#include "MagickCore/token.h"
cristyf034abb2013-11-24 14:16:14 +000080
81#ifdef MAGICKCORE_CLPERFMARKER
82#include "CLPerfMarker.h"
83#endif
84
cristye85d0f72013-11-27 02:25:43 +000085#define MAGICK_MAX(x,y) (((x) >= (y))?(x):(y))
86#define MAGICK_MIN(x,y) (((x) <= (y))?(x):(y))
87
cristyf034abb2013-11-24 14:16:14 +000088#if defined(MAGICKCORE_OPENCL_SUPPORT)
89
90#define ALIGNED(pointer,type) ((((long)(pointer)) & (sizeof(type)-1)) == 0)
cristyf034abb2013-11-24 14:16:14 +000091
cristy0c832c62014-03-07 22:21:04 +000092/* pad the global workgroup size to the next multiple of
93 the local workgroup size */
dirk832becc2014-08-04 19:44:34 +000094inline static unsigned int padGlobalWorkgroupSizeToLocalWorkgroupSize(
95 const unsigned int orgGlobalSize,const unsigned int localGroupSize)
96{
97 return ((orgGlobalSize+(localGroupSize-1))/localGroupSize*localGroupSize);
98}
99
100static MagickBooleanType checkOpenCLEnvironment(ExceptionInfo* exception)
101{
102 MagickBooleanType
103 flag;
104
105 MagickCLEnv
106 clEnv;
107
108 clEnv=GetDefaultOpenCLEnv();
109
110 GetMagickOpenCLEnvParam(clEnv,MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,
111 sizeof(MagickBooleanType),&flag,exception);
112 if (flag != MagickFalse)
113 return(MagickFalse);
114
115 GetMagickOpenCLEnvParam(clEnv,MAGICK_OPENCL_ENV_PARAM_OPENCL_INITIALIZED,
116 sizeof(MagickBooleanType),&flag,exception);
117 if (flag == MagickFalse)
118 {
119 if (InitOpenCLEnv(clEnv,exception) == MagickFalse)
120 return(MagickFalse);
121
122 GetMagickOpenCLEnvParam(clEnv,MAGICK_OPENCL_ENV_PARAM_OPENCL_DISABLED,
123 sizeof(MagickBooleanType),&flag,exception);
124 if (flag != MagickFalse)
125 return(MagickFalse);
126 }
127
128 return(MagickTrue);
129}
130
131static MagickBooleanType checkAccelerateCondition(const Image* image,
132 const ChannelType channel)
133{
134 /* check if the image's colorspace is supported */
135 if (image->colorspace != RGBColorspace &&
136 image->colorspace != sRGBColorspace &&
137 image->colorspace != GRAYColorspace)
138 return(MagickFalse);
139
140 /* check if the channel is supported */
141 if (((channel & RedChannel) == 0) ||
142 ((channel & GreenChannel) == 0) ||
143 ((channel & BlueChannel) == 0))
144 return(MagickFalse);
145
146 /* check if the virtual pixel method is compatible with the OpenCL implementation */
147 if ((GetImageVirtualPixelMethod(image) != UndefinedVirtualPixelMethod) &&
148 (GetImageVirtualPixelMethod(image) != EdgeVirtualPixelMethod))
149 return(MagickFalse);
150
151 /* check if the image has read / write mask */
152 if (image->read_mask != MagickFalse || image->write_mask != MagickFalse)
153 return(MagickFalse);
154
155 return(MagickTrue);
156}
157
158static MagickBooleanType checkHistogramCondition(Image *image,
159 const ChannelType channel)
160{
161 /* ensure this is the only pass get in for now. */
162 if ((channel & SyncChannels) == 0)
163 return MagickFalse;
164
165 if (image->intensity == Rec601LuminancePixelIntensityMethod ||
166 image->intensity == Rec709LuminancePixelIntensityMethod)
167 return MagickFalse;
168
169 if (image->colorspace != sRGBColorspace)
170 return MagickFalse;
171
172 return MagickTrue;
173}
174
175static MagickBooleanType splitImage(const Image* image)
176{
177 MagickBooleanType
178 split;
179
180 MagickCLEnv
181 clEnv;
182
183 unsigned long
184 allocSize,
185 tempSize;
186
187 clEnv=GetDefaultOpenCLEnv();
188
189 allocSize=GetOpenCLDeviceMaxMemAllocSize(clEnv);
190 tempSize=image->columns * image->rows * 4 * 4;
191
192 split = ((tempSize > allocSize) ? MagickTrue : MagickFalse);
193 return(split);
cristy0c832c62014-03-07 22:21:04 +0000194}
195
dirk8a5cf512014-07-28 20:16:27 +0000196/*
197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198% %
199% %
200% %
201% C o n v o l v e I m a g e w i t h O p e n C L %
202% %
203% %
204% %
205%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206%
207% ConvolveImage() applies a custom convolution kernel to the image.
208%
209% The format of the ConvolveImage method is:
210%
211% Image *ConvolveImage(const Image *image,const size_t order,
212% const double *kernel,ExceptionInfo *exception)
213% Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
214% const size_t order,const double *kernel,ExceptionInfo *exception)
215%
216% A description of each parameter follows:
217%
218% o image: the image.
219%
220% o channel: the channel type.
221%
222% o kernel: kernel info.
223%
224% o exception: return any errors or warnings in this structure.
225%
226*/
cristyf034abb2013-11-24 14:16:14 +0000227
dirk832becc2014-08-04 19:44:34 +0000228static Image *ComputeConvolveImage(const Image* image,
229 const ChannelType channel,const KernelInfo *kernel,ExceptionInfo *exception)
230{
231 CacheView
232 *filteredImage_view,
233 *image_view;
234
235 cl_command_queue
236 queue;
237
238 cl_context
239 context;
240
241 cl_kernel
242 clkernel;
243
244 cl_int
245 clStatus;
246
247 cl_mem
248 convolutionKernel,
249 filteredImageBuffer,
250 imageBuffer;
251
252 cl_mem_flags
253 mem_flags;
254
255 cl_ulong
256 deviceLocalMemorySize;
257
258 const void
259 *inputPixels;
260
261 float
262 *kernelBufferPtr;
263
264 Image
265 *filteredImage;
266
267 MagickBooleanType
268 outputReady;
269
270 MagickCLEnv
271 clEnv;
272
273 MagickSizeType
274 length;
275
276 size_t
277 global_work_size[3],
278 localGroupSize[3],
279 localMemoryRequirement;
280
281 unsigned
282 kernelSize;
283
284 unsigned int
285 filterHeight,
286 filterWidth,
287 i,
288 imageHeight,
289 imageWidth,
290 matte;
291
292 void
293 *filteredPixels,
294 *hostPtr;
295
296 /* intialize all CL objects to NULL */
297 context = NULL;
298 imageBuffer = NULL;
299 filteredImageBuffer = NULL;
300 convolutionKernel = NULL;
301 clkernel = NULL;
302 queue = NULL;
303
304 filteredImage = NULL;
305 filteredImage_view = NULL;
cristyf034abb2013-11-24 14:16:14 +0000306 outputReady = MagickFalse;
307
308 clEnv = GetDefaultOpenCLEnv();
309 context = GetOpenCLContext(clEnv);
310
dirk832becc2014-08-04 19:44:34 +0000311 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +0000312 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +0000313 if (inputPixels == (const void *) NULL)
314 {
dirk8a5cf512014-07-28 20:16:27 +0000315 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +0000316 goto cleanup;
317 }
318
319 /* Create and initialize OpenCL buffers. */
320
321 /* If the host pointer is aligned to the size of CLPixelPacket,
322 then use the host buffer directly from the GPU; otherwise,
323 create a buffer on the GPU and copy the data over */
324 if (ALIGNED(inputPixels,CLPixelPacket))
325 {
326 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
327 }
328 else
329 {
330 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
331 }
332 /* create a CL buffer from image pixel buffer */
dirk832becc2014-08-04 19:44:34 +0000333 length = image->columns * image->rows;
dirk8a5cf512014-07-28 20:16:27 +0000334 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000335 if (clStatus != CL_SUCCESS)
336 {
cristy0c832c62014-03-07 22:21:04 +0000337 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000338 goto cleanup;
339 }
340
dirk8a5cf512014-07-28 20:16:27 +0000341 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +0000342 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +0000343 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +0000344 {
cristya22457d2013-12-07 14:03:06 +0000345 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000346 goto cleanup;
347 }
dirk832becc2014-08-04 19:44:34 +0000348 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +0000349 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +0000350 if (filteredPixels == (void *) NULL)
351 {
cristya22457d2013-12-07 14:03:06 +0000352 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +0000353 goto cleanup;
354 }
355
356 if (ALIGNED(filteredPixels,CLPixelPacket))
357 {
358 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
359 hostPtr = filteredPixels;
360 }
361 else
362 {
363 mem_flags = CL_MEM_WRITE_ONLY;
364 hostPtr = NULL;
365 }
366 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +0000367 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000368 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000369 if (clStatus != CL_SUCCESS)
370 {
cristy0c832c62014-03-07 22:21:04 +0000371 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000372 goto cleanup;
373 }
374
375 kernelSize = kernel->width * kernel->height;
cristy0c832c62014-03-07 22:21:04 +0000376 convolutionKernel = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernelSize * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000377 if (clStatus != CL_SUCCESS)
378 {
cristy0c832c62014-03-07 22:21:04 +0000379 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000380 goto cleanup;
381 }
382
383 queue = AcquireOpenCLCommandQueue(clEnv);
384
cristy0c832c62014-03-07 22:21:04 +0000385 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, convolutionKernel, CL_TRUE, CL_MAP_WRITE, 0, kernelSize * sizeof(float)
cristyf034abb2013-11-24 14:16:14 +0000386 , 0, NULL, NULL, &clStatus);
387 if (clStatus != CL_SUCCESS)
388 {
cristy0c832c62014-03-07 22:21:04 +0000389 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000390 goto cleanup;
391 }
392 for (i = 0; i < kernelSize; i++)
393 {
394 kernelBufferPtr[i] = (float) kernel->values[i];
395 }
cristy0c832c62014-03-07 22:21:04 +0000396 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, convolutionKernel, kernelBufferPtr, 0, NULL, NULL);
397 if (clStatus != CL_SUCCESS)
cristyf034abb2013-11-24 14:16:14 +0000398 {
cristy0c832c62014-03-07 22:21:04 +0000399 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000400 goto cleanup;
401 }
cristy0c832c62014-03-07 22:21:04 +0000402 clEnv->library->clFlush(queue);
403
404 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
cristyf034abb2013-11-24 14:16:14 +0000405
406 /* Compute the local memory requirement for a 16x16 workgroup.
407 If it's larger than 16k, reduce the workgroup size to 8x8 */
408 localGroupSize[0] = 16;
409 localGroupSize[1] = 16;
410 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
411 + kernel->width*kernel->height*sizeof(float);
cristy0c832c62014-03-07 22:21:04 +0000412
413 if (localMemoryRequirement > deviceLocalMemorySize)
cristyf034abb2013-11-24 14:16:14 +0000414 {
cristyf034abb2013-11-24 14:16:14 +0000415 localGroupSize[0] = 8;
416 localGroupSize[1] = 8;
cristyf034abb2013-11-24 14:16:14 +0000417 localMemoryRequirement = (localGroupSize[0]+kernel->width-1) * (localGroupSize[1]+kernel->height-1) * sizeof(CLPixelPacket)
418 + kernel->width*kernel->height*sizeof(float);
419 }
cristyf034abb2013-11-24 14:16:14 +0000420 if (localMemoryRequirement <= deviceLocalMemorySize)
421 {
422 /* get the OpenCL kernel */
cristya22457d2013-12-07 14:03:06 +0000423 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ConvolveOptimized");
cristyf034abb2013-11-24 14:16:14 +0000424 if (clkernel == NULL)
425 {
cristya22457d2013-12-07 14:03:06 +0000426 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000427 goto cleanup;
428 }
429
430 /* set the kernel arguments */
431 i = 0;
dirk8a5cf512014-07-28 20:16:27 +0000432 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +0000433 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +0000434 imageWidth = image->columns;
435 imageHeight = image->rows;
cristy0c832c62014-03-07 22:21:04 +0000436 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
437 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
438 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
cristyf034abb2013-11-24 14:16:14 +0000439 filterWidth = kernel->width;
440 filterHeight = kernel->height;
cristy0c832c62014-03-07 22:21:04 +0000441 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
442 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
dirk8a5cf512014-07-28 20:16:27 +0000443 matte = (image->alpha_trait==BlendPixelTrait)?1:0;
cristy0c832c62014-03-07 22:21:04 +0000444 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
445 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
446 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, (localGroupSize[0] + kernel->width-1)*(localGroupSize[1] + kernel->height-1)*sizeof(CLPixelPacket),NULL);
447 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++, kernel->width*kernel->height*sizeof(float),NULL);
cristyf034abb2013-11-24 14:16:14 +0000448 if (clStatus != CL_SUCCESS)
449 {
cristy0c832c62014-03-07 22:21:04 +0000450 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000451 goto cleanup;
452 }
453
454 /* pad the global size to a multiple of the local work size dimension */
dirk8a5cf512014-07-28 20:16:27 +0000455 global_work_size[0] = ((image->columns + localGroupSize[0] - 1)/localGroupSize[0] ) * localGroupSize[0] ;
456 global_work_size[1] = ((image->rows + localGroupSize[1] - 1)/localGroupSize[1]) * localGroupSize[1];
cristyf034abb2013-11-24 14:16:14 +0000457
458 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +0000459 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000460 if (clStatus != CL_SUCCESS)
461 {
cristy0c832c62014-03-07 22:21:04 +0000462 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000463 goto cleanup;
464 }
465 }
466 else
467 {
468 /* get the OpenCL kernel */
469 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Convolve");
470 if (clkernel == NULL)
471 {
cristya22457d2013-12-07 14:03:06 +0000472 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000473 goto cleanup;
474 }
475
476 /* set the kernel arguments */
477 i = 0;
dirk8a5cf512014-07-28 20:16:27 +0000478 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +0000479 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +0000480 imageWidth = image->columns;
481 imageHeight = image->rows;
cristy0c832c62014-03-07 22:21:04 +0000482 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageWidth);
483 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&imageHeight);
484 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&convolutionKernel);
cristyf034abb2013-11-24 14:16:14 +0000485 filterWidth = kernel->width;
486 filterHeight = kernel->height;
cristy0c832c62014-03-07 22:21:04 +0000487 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterWidth);
488 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&filterHeight);
dirk8a5cf512014-07-28 20:16:27 +0000489 matte = (image->alpha_trait==BlendPixelTrait)?1:0;
cristy0c832c62014-03-07 22:21:04 +0000490 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&matte);
491 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
cristyf034abb2013-11-24 14:16:14 +0000492 if (clStatus != CL_SUCCESS)
493 {
cristy0c832c62014-03-07 22:21:04 +0000494 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000495 goto cleanup;
496 }
497
cristy0c832c62014-03-07 22:21:04 +0000498 localGroupSize[0] = 8;
499 localGroupSize[1] = 8;
dirk8a5cf512014-07-28 20:16:27 +0000500 global_work_size[0] = (image->columns + (localGroupSize[0]-1))/localGroupSize[0] * localGroupSize[0];
501 global_work_size[1] = (image->rows + (localGroupSize[1]-1))/localGroupSize[1] * localGroupSize[1];
cristy0c832c62014-03-07 22:21:04 +0000502 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, global_work_size, localGroupSize, 0, NULL, NULL);
503
cristyf034abb2013-11-24 14:16:14 +0000504 if (clStatus != CL_SUCCESS)
505 {
cristy0c832c62014-03-07 22:21:04 +0000506 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000507 goto cleanup;
508 }
509 }
cristy0c832c62014-03-07 22:21:04 +0000510 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000511
512 if (ALIGNED(filteredPixels,CLPixelPacket))
513 {
dirk8a5cf512014-07-28 20:16:27 +0000514 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000515 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000516 }
517 else
518 {
dirk8a5cf512014-07-28 20:16:27 +0000519 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000520 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000521 }
522 if (clStatus != CL_SUCCESS)
523 {
cristya22457d2013-12-07 14:03:06 +0000524 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000525 goto cleanup;
526 }
527
dirk832becc2014-08-04 19:44:34 +0000528 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
529
530cleanup:
531 OpenCLLogException(__FUNCTION__,__LINE__,exception);
532
533 image_view=DestroyCacheView(image_view);
534 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +0000535 filteredImage_view=DestroyCacheView(filteredImage_view);
cristyf034abb2013-11-24 14:16:14 +0000536
dirk8a5cf512014-07-28 20:16:27 +0000537 if (imageBuffer != NULL)
538 clEnv->library->clReleaseMemObject(imageBuffer);
cristyf034abb2013-11-24 14:16:14 +0000539
540 if (filteredImageBuffer != NULL)
cristy0c832c62014-03-07 22:21:04 +0000541 clEnv->library->clReleaseMemObject(filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +0000542
543 if (convolutionKernel != NULL)
cristy0c832c62014-03-07 22:21:04 +0000544 clEnv->library->clReleaseMemObject(convolutionKernel);
cristyf034abb2013-11-24 14:16:14 +0000545
546 if (clkernel != NULL)
547 RelinquishOpenCLKernel(clEnv, clkernel);
548
549 if (queue != NULL)
550 RelinquishOpenCLCommandQueue(clEnv, queue);
551
552 if (outputReady == MagickFalse)
553 {
554 if (filteredImage != NULL)
555 {
556 DestroyImage(filteredImage);
557 filteredImage = NULL;
558 }
559 }
560
dirk8a5cf512014-07-28 20:16:27 +0000561 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +0000562}
563
dirk832becc2014-08-04 19:44:34 +0000564MagickExport Image *AccelerateConvolveImageChannel(const Image *image,
565 const ChannelType channel,const KernelInfo *kernel,ExceptionInfo *exception)
566{
567 Image
568 *filteredImage;
569
570 assert(image != NULL);
571 assert(kernel != (KernelInfo *) NULL);
572 assert(exception != (ExceptionInfo *) NULL);
573
574 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
575 (checkAccelerateCondition(image, channel) == MagickFalse))
576 return NULL;
577
578 filteredImage=ComputeConvolveImage(image, channel, kernel, exception);
579 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +0000580}
581
dirk832becc2014-08-04 19:44:34 +0000582static MagickBooleanType ComputeFunctionImage(Image *image,
583 const ChannelType channel,const MagickFunction function,
584 const size_t number_parameters,const double *parameters,
585 ExceptionInfo *exception)
586{
587 CacheView
588 *image_view;
589
590 cl_command_queue
591 queue;
592
593 cl_context
594 context;
595
596 cl_int
597 clStatus;
598
599 cl_kernel
600 clkernel;
601
602 cl_mem
603 imageBuffer,
604 parametersBuffer;
605
606 cl_mem_flags
607 mem_flags;
608
609 float
610 *parametersBufferPtr;
611
612 MagickBooleanType
613 status;
614
615 MagickCLEnv
616 clEnv;
617
618 MagickSizeType
619 length;
620
621 size_t
622 globalWorkSize[2];
623
624 unsigned int
625 i;
626
627 void
628 *pixels;
629
630 status = MagickFalse;
631
632 context = NULL;
633 clkernel = NULL;
634 queue = NULL;
635 imageBuffer = NULL;
636 parametersBuffer = NULL;
637
638 clEnv = GetDefaultOpenCLEnv();
639 context = GetOpenCLContext(clEnv);
640
641 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +0000642 pixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +0000643 if (pixels == (void *) NULL)
644 {
cristya22457d2013-12-07 14:03:06 +0000645 (void) OpenCLThrowMagickException(exception, GetMagickModule(), CacheWarning,
cristyf034abb2013-11-24 14:16:14 +0000646 "GetPixelCachePixels failed.",
647 "'%s'", image->filename);
648 goto cleanup;
649 }
650
651
652 if (ALIGNED(pixels,CLPixelPacket))
653 {
654 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
655 }
656 else
657 {
658 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
659 }
660 /* create a CL buffer from image pixel buffer */
661 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000662 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)pixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000663 if (clStatus != CL_SUCCESS)
664 {
cristy0c832c62014-03-07 22:21:04 +0000665 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000666 goto cleanup;
667 }
668
cristy0c832c62014-03-07 22:21:04 +0000669 parametersBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, number_parameters * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000670 if (clStatus != CL_SUCCESS)
671 {
cristy0c832c62014-03-07 22:21:04 +0000672 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000673 goto cleanup;
674 }
675
676 queue = AcquireOpenCLCommandQueue(clEnv);
677
cristy0c832c62014-03-07 22:21:04 +0000678 parametersBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, parametersBuffer, CL_TRUE, CL_MAP_WRITE, 0, number_parameters * sizeof(float)
cristyf034abb2013-11-24 14:16:14 +0000679 , 0, NULL, NULL, &clStatus);
680 if (clStatus != CL_SUCCESS)
681 {
cristy0c832c62014-03-07 22:21:04 +0000682 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000683 goto cleanup;
684 }
685 for (i = 0; i < number_parameters; i++)
686 {
687 parametersBufferPtr[i] = (float)parameters[i];
688 }
cristy0c832c62014-03-07 22:21:04 +0000689 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, parametersBuffer, parametersBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000690 if (clStatus != CL_SUCCESS)
691 {
cristy0c832c62014-03-07 22:21:04 +0000692 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000693 goto cleanup;
694 }
cristy0c832c62014-03-07 22:21:04 +0000695 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000696
697 clkernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "FunctionImage");
698 if (clkernel == NULL)
699 {
cristya22457d2013-12-07 14:03:06 +0000700 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000701 goto cleanup;
702 }
703
704 /* set the kernel arguments */
705 i = 0;
cristy0c832c62014-03-07 22:21:04 +0000706 clStatus =clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
707 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(ChannelType),(void *)&channel);
708 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(MagickFunction),(void *)&function);
709 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(unsigned int),(void *)&number_parameters);
710 clStatus|=clEnv->library->clSetKernelArg(clkernel,i++,sizeof(cl_mem),(void *)&parametersBuffer);
cristyf034abb2013-11-24 14:16:14 +0000711 if (clStatus != CL_SUCCESS)
712 {
cristy0c832c62014-03-07 22:21:04 +0000713 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000714 goto cleanup;
715 }
716
717 globalWorkSize[0] = image->columns;
718 globalWorkSize[1] = image->rows;
719 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +0000720 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, clkernel, 2, NULL, globalWorkSize, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000721 if (clStatus != CL_SUCCESS)
722 {
cristy0c832c62014-03-07 22:21:04 +0000723 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000724 goto cleanup;
725 }
cristy0c832c62014-03-07 22:21:04 +0000726 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +0000727
728
729 if (ALIGNED(pixels,CLPixelPacket))
730 {
731 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000732 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000733 }
734 else
735 {
736 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000737 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), pixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000738 }
739 if (clStatus != CL_SUCCESS)
740 {
cristya22457d2013-12-07 14:03:06 +0000741 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000742 goto cleanup;
743 }
dirk832becc2014-08-04 19:44:34 +0000744 status=SyncCacheViewAuthenticPixels(image_view,exception);
745
746cleanup:
747 OpenCLLogException(__FUNCTION__,__LINE__,exception);
748
dirk8a5cf512014-07-28 20:16:27 +0000749 image_view=DestroyCacheView(image_view);
cristyf034abb2013-11-24 14:16:14 +0000750
751 if (clkernel != NULL) RelinquishOpenCLKernel(clEnv, clkernel);
752 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
cristy0c832c62014-03-07 22:21:04 +0000753 if (imageBuffer != NULL) clEnv->library->clReleaseMemObject(imageBuffer);
754 if (parametersBuffer != NULL) clEnv->library->clReleaseMemObject(parametersBuffer);
cristyf034abb2013-11-24 14:16:14 +0000755
dirk8a5cf512014-07-28 20:16:27 +0000756 return(status);
cristyf034abb2013-11-24 14:16:14 +0000757}
758
dirk832becc2014-08-04 19:44:34 +0000759MagickExport MagickBooleanType AccelerateFunctionImage(Image *image,
760 const ChannelType channel,const MagickFunction function,
761 const size_t number_parameters,const double *parameters,
762 ExceptionInfo *exception)
763{
764 MagickBooleanType
765 status;
766
767 assert(image != NULL);
768 assert(exception != (ExceptionInfo *) NULL);
769
770 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
771 (checkAccelerateCondition(image, channel) == MagickFalse))
772 return(MagickFalse);
773
774 status=ComputeFunctionImage(image, channel, function, number_parameters, parameters, exception);
775 return(status);
cristyf034abb2013-11-24 14:16:14 +0000776}
777
dirk8a5cf512014-07-28 20:16:27 +0000778/*
779%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
780% %
781% %
782% %
783% B l u r I m a g e w i t h O p e n C L %
784% %
785% %
786% %
787%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
788%
789% BlurImage() blurs an image. We convolve the image with a Gaussian operator
790% of the given radius and standard deviation (sigma). For reasonable results,
791% the radius should be larger than sigma. Use a radius of 0 and BlurImage()
792% selects a suitable radius for you.
793%
794% The format of the BlurImage method is:
795%
796% Image *BlurImage(const Image *image,const double radius,
797% const double sigma,ExceptionInfo *exception)
798% Image *BlurImageChannel(const Image *image,const ChannelType channel,
799% const double radius,const double sigma,ExceptionInfo *exception)
800%
801% A description of each parameter follows:
802%
803% o image: the image.
804%
805% o channel: the channel type.
806%
807% o radius: the radius of the Gaussian, in pixels, not counting the center
808% pixel.
809%
810% o sigma: the standard deviation of the Gaussian, in pixels.
811%
812% o exception: return any errors or warnings in this structure.
813%
814*/
cristyf034abb2013-11-24 14:16:14 +0000815
dirk832becc2014-08-04 19:44:34 +0000816static Image *ComputeBlurImage(const Image* image,const ChannelType channel,
817 const double radius,const double sigma,ExceptionInfo *exception)
818{
819 CacheView
820 *filteredImage_view,
821 *image_view;
822
823 char
824 geometry[MaxTextExtent];
825
826 cl_command_queue
827 queue;
828
829 cl_context
830 context;
831
832 cl_int
833 clStatus;
834
835 cl_kernel
836 blurColumnKernel,
837 blurRowKernel;
838
839 cl_mem
840 filteredImageBuffer,
841 imageBuffer,
842 imageKernelBuffer,
843 tempImageBuffer;
844
845 cl_mem_flags
846 mem_flags;
847
848 const void
849 *inputPixels;
850
851 float
852 *kernelBufferPtr;
853
854 Image
855 *filteredImage;
856
857 MagickBooleanType
858 outputReady;
859
860 MagickCLEnv
861 clEnv;
862
863 MagickSizeType
864 length;
865
866 KernelInfo
867 *kernel;
868
869 unsigned int
870 i,
871 imageColumns,
872 imageRows,
873 kernelWidth;
874
875 void
876 *filteredPixels,
877 *hostPtr;
878
879 context = NULL;
880 filteredImage = NULL;
881 filteredImage_view = NULL;
882 imageBuffer = NULL;
883 tempImageBuffer = NULL;
884 filteredImageBuffer = NULL;
885 imageKernelBuffer = NULL;
886 blurRowKernel = NULL;
887 blurColumnKernel = NULL;
888 queue = NULL;
889 kernel = NULL;
890
891 outputReady = MagickFalse;
892
893 clEnv = GetDefaultOpenCLEnv();
894 context = GetOpenCLContext(clEnv);
895 queue = AcquireOpenCLCommandQueue(clEnv);
896
897 /* Create and initialize OpenCL buffers. */
898 {
899 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +0000900 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +0000901 if (inputPixels == (const void *) NULL)
902 {
dirk8a5cf512014-07-28 20:16:27 +0000903 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +0000904 goto cleanup;
905 }
906 /* If the host pointer is aligned to the size of CLPixelPacket,
907 then use the host buffer directly from the GPU; otherwise,
908 create a buffer on the GPU and copy the data over */
909 if (ALIGNED(inputPixels,CLPixelPacket))
910 {
911 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
912 }
913 else
914 {
915 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
916 }
917 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +0000918 length = image->columns * image->rows;
919 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000920 if (clStatus != CL_SUCCESS)
921 {
cristy0c832c62014-03-07 22:21:04 +0000922 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000923 goto cleanup;
924 }
925 }
926
927 /* create output */
928 {
dirk8a5cf512014-07-28 20:16:27 +0000929 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +0000930 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +0000931 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +0000932 {
cristya22457d2013-12-07 14:03:06 +0000933 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000934 goto cleanup;
935 }
dirk832becc2014-08-04 19:44:34 +0000936 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +0000937 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +0000938 if (filteredPixels == (void *) NULL)
939 {
cristya22457d2013-12-07 14:03:06 +0000940 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +0000941 goto cleanup;
942 }
943
944 if (ALIGNED(filteredPixels,CLPixelPacket))
945 {
946 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
947 hostPtr = filteredPixels;
948 }
949 else
950 {
951 mem_flags = CL_MEM_WRITE_ONLY;
952 hostPtr = NULL;
953 }
954 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +0000955 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +0000956 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000957 if (clStatus != CL_SUCCESS)
958 {
cristy0c832c62014-03-07 22:21:04 +0000959 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000960 goto cleanup;
961 }
962 }
963
964 /* create processing kernel */
965 {
966 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
967 kernel=AcquireKernelInfo(geometry);
968 if (kernel == (KernelInfo *) NULL)
969 {
cristya22457d2013-12-07 14:03:06 +0000970 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.",".");
cristyf034abb2013-11-24 14:16:14 +0000971 goto cleanup;
972 }
973
cristy0c832c62014-03-07 22:21:04 +0000974 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernel->width * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000975 if (clStatus != CL_SUCCESS)
976 {
cristy0c832c62014-03-07 22:21:04 +0000977 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000978 goto cleanup;
979 }
cristy0c832c62014-03-07 22:21:04 +0000980 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +0000981 if (clStatus != CL_SUCCESS)
982 {
cristy0c832c62014-03-07 22:21:04 +0000983 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +0000984 goto cleanup;
985 }
986
987 for (i = 0; i < kernel->width; i++)
988 {
989 kernelBufferPtr[i] = (float) kernel->values[i];
990 }
991
cristy0c832c62014-03-07 22:21:04 +0000992 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +0000993 if (clStatus != CL_SUCCESS)
994 {
cristy0c832c62014-03-07 22:21:04 +0000995 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +0000996 goto cleanup;
997 }
998 }
999
1000 {
1001
1002 /* create temp buffer */
1003 {
dirk8a5cf512014-07-28 20:16:27 +00001004 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001005 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001006 if (clStatus != CL_SUCCESS)
1007 {
cristy0c832c62014-03-07 22:21:04 +00001008 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001009 goto cleanup;
1010 }
1011 }
1012
1013 /* get the OpenCL kernels */
1014 {
1015 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow");
1016 if (blurRowKernel == NULL)
1017 {
cristya22457d2013-12-07 14:03:06 +00001018 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001019 goto cleanup;
1020 };
1021
1022 blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumn");
1023 if (blurColumnKernel == NULL)
1024 {
cristya22457d2013-12-07 14:03:06 +00001025 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001026 goto cleanup;
1027 };
1028 }
1029
1030 {
1031 /* need logic to decide this value */
1032 int chunkSize = 256;
1033
1034 {
dirk8a5cf512014-07-28 20:16:27 +00001035 imageColumns = image->columns;
1036 imageRows = image->rows;
cristyf034abb2013-11-24 14:16:14 +00001037
1038 /* set the kernel arguments */
1039 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00001040 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00001041 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1042 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
1043 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00001044 kernelWidth = kernel->width;
cristy0c832c62014-03-07 22:21:04 +00001045 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1046 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1047 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1048 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
cristyf034abb2013-11-24 14:16:14 +00001049 if (clStatus != CL_SUCCESS)
1050 {
cristy0c832c62014-03-07 22:21:04 +00001051 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001052 goto cleanup;
1053 }
1054 }
1055
1056 /* launch the kernel */
1057 {
1058 size_t gsize[2];
1059 size_t wsize[2];
1060
dirk8a5cf512014-07-28 20:16:27 +00001061 gsize[0] = chunkSize*((image->columns+chunkSize-1)/chunkSize);
1062 gsize[1] = image->rows;
cristyf034abb2013-11-24 14:16:14 +00001063 wsize[0] = chunkSize;
1064 wsize[1] = 1;
1065
cristy0c832c62014-03-07 22:21:04 +00001066 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001067 if (clStatus != CL_SUCCESS)
1068 {
cristy0c832c62014-03-07 22:21:04 +00001069 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001070 goto cleanup;
1071 }
cristy0c832c62014-03-07 22:21:04 +00001072 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001073 }
1074 }
1075
1076 {
1077 /* need logic to decide this value */
1078 int chunkSize = 256;
1079
1080 {
dirk8a5cf512014-07-28 20:16:27 +00001081 imageColumns = image->columns;
1082 imageRows = image->rows;
cristyf034abb2013-11-24 14:16:14 +00001083
1084 /* set the kernel arguments */
1085 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001086 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1087 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1088 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel);
1089 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00001090 kernelWidth = kernel->width;
cristy0c832c62014-03-07 22:21:04 +00001091 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1092 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1093 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1094 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL);
cristyf034abb2013-11-24 14:16:14 +00001095 if (clStatus != CL_SUCCESS)
1096 {
cristy0c832c62014-03-07 22:21:04 +00001097 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001098 goto cleanup;
1099 }
1100 }
1101
1102 /* launch the kernel */
1103 {
1104 size_t gsize[2];
1105 size_t wsize[2];
1106
dirk8a5cf512014-07-28 20:16:27 +00001107 gsize[0] = image->columns;
1108 gsize[1] = chunkSize*((image->rows+chunkSize-1)/chunkSize);
cristyf034abb2013-11-24 14:16:14 +00001109 wsize[0] = 1;
1110 wsize[1] = chunkSize;
1111
cristy0c832c62014-03-07 22:21:04 +00001112 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001113 if (clStatus != CL_SUCCESS)
1114 {
cristy0c832c62014-03-07 22:21:04 +00001115 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001116 goto cleanup;
1117 }
cristy0c832c62014-03-07 22:21:04 +00001118 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001119 }
1120 }
1121
1122 }
1123
1124 /* get result */
1125 if (ALIGNED(filteredPixels,CLPixelPacket))
1126 {
dirk8a5cf512014-07-28 20:16:27 +00001127 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001128 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001129 }
1130 else
1131 {
dirk8a5cf512014-07-28 20:16:27 +00001132 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001133 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001134 }
1135 if (clStatus != CL_SUCCESS)
1136 {
cristya22457d2013-12-07 14:03:06 +00001137 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001138 goto cleanup;
1139 }
1140
dirk832becc2014-08-04 19:44:34 +00001141 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
1142
1143cleanup:
1144 OpenCLLogException(__FUNCTION__,__LINE__,exception);
1145
1146 image_view=DestroyCacheView(image_view);
1147 if (filteredImage_view != NULL)
1148 filteredImage_view=DestroyCacheView(filteredImage_view);
1149
dirk8a5cf512014-07-28 20:16:27 +00001150 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00001151 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
1152 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
1153 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00001154 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
1155 if (blurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurColumnKernel);
1156 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
1157 if (kernel!=NULL) DestroyKernelInfo(kernel);
dirk8a5cf512014-07-28 20:16:27 +00001158 if (outputReady == MagickFalse && filteredImage != NULL)
dirk832becc2014-08-04 19:44:34 +00001159 filteredImage=DestroyImage(filteredImage);
dirk8a5cf512014-07-28 20:16:27 +00001160 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00001161}
1162
dirk832becc2014-08-04 19:44:34 +00001163static Image* ComputeBlurImageSection(const Image* image,
1164 const ChannelType channel,const double radius,const double sigma,
1165 ExceptionInfo *exception)
1166{
1167 CacheView
1168 *filteredImage_view,
1169 *image_view;
1170
1171 char
1172 geometry[MaxTextExtent];
1173
1174 cl_command_queue
1175 queue;
1176
1177 cl_int
1178 clStatus;
1179
1180 cl_kernel
1181 blurColumnKernel,
1182 blurRowKernel;
1183
1184 cl_mem
1185 imageBuffer,
1186 tempImageBuffer,
1187 filteredImageBuffer,
1188 imageKernelBuffer;
1189
1190 cl_mem_flags
1191 mem_flags;
1192
1193 cl_context
1194 context;
1195
1196 const void
1197 *inputPixels;
1198
1199 float
1200 *kernelBufferPtr;
1201
1202 Image
1203 *filteredImage;
1204
1205 KernelInfo
1206 *kernel;
1207
1208 MagickBooleanType
1209 outputReady;
1210
1211 MagickCLEnv
1212 clEnv;
1213
1214 MagickSizeType
1215 length;
1216
1217 unsigned int
1218 i,
1219 imageColumns,
1220 imageRows,
1221 kernelWidth;
1222
1223 void
1224 *filteredPixels,
1225 *hostPtr;
1226
1227 context = NULL;
1228 filteredImage = NULL;
1229 filteredImage_view = NULL;
1230 imageBuffer = NULL;
1231 tempImageBuffer = NULL;
1232 filteredImageBuffer = NULL;
1233 imageKernelBuffer = NULL;
1234 blurRowKernel = NULL;
1235 blurColumnKernel = NULL;
1236 queue = NULL;
1237 kernel = NULL;
1238
1239 outputReady = MagickFalse;
1240
1241 clEnv = GetDefaultOpenCLEnv();
1242 context = GetOpenCLContext(clEnv);
1243 queue = AcquireOpenCLCommandQueue(clEnv);
1244
1245 /* Create and initialize OpenCL buffers. */
1246 {
1247 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00001248 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00001249 if (inputPixels == (const void *) NULL)
1250 {
dirk8a5cf512014-07-28 20:16:27 +00001251 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00001252 goto cleanup;
1253 }
1254 /* If the host pointer is aligned to the size of CLPixelPacket,
1255 then use the host buffer directly from the GPU; otherwise,
1256 create a buffer on the GPU and copy the data over */
1257 if (ALIGNED(inputPixels,CLPixelPacket))
1258 {
1259 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1260 }
1261 else
1262 {
1263 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1264 }
1265 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00001266 length = image->columns * image->rows;
1267 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001268 if (clStatus != CL_SUCCESS)
1269 {
cristy0c832c62014-03-07 22:21:04 +00001270 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001271 goto cleanup;
1272 }
1273 }
1274
1275 /* create output */
1276 {
dirk8a5cf512014-07-28 20:16:27 +00001277 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +00001278 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00001279 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00001280 {
cristya22457d2013-12-07 14:03:06 +00001281 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001282 goto cleanup;
1283 }
dirk832becc2014-08-04 19:44:34 +00001284 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00001285 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00001286 if (filteredPixels == (void *) NULL)
1287 {
cristya22457d2013-12-07 14:03:06 +00001288 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001289 goto cleanup;
1290 }
1291
1292 if (ALIGNED(filteredPixels,CLPixelPacket))
1293 {
1294 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1295 hostPtr = filteredPixels;
1296 }
1297 else
1298 {
1299 mem_flags = CL_MEM_WRITE_ONLY;
1300 hostPtr = NULL;
1301 }
1302 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00001303 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001304 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001305 if (clStatus != CL_SUCCESS)
1306 {
cristy0c832c62014-03-07 22:21:04 +00001307 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001308 goto cleanup;
1309 }
1310 }
1311
1312 /* create processing kernel */
1313 {
1314 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
1315 kernel=AcquireKernelInfo(geometry);
1316 if (kernel == (KernelInfo *) NULL)
1317 {
cristya22457d2013-12-07 14:03:06 +00001318 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "MemoryAllocationFailed.",".");
cristyf034abb2013-11-24 14:16:14 +00001319 goto cleanup;
1320 }
1321
cristy0c832c62014-03-07 22:21:04 +00001322 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, kernel->width * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001323 if (clStatus != CL_SUCCESS)
1324 {
cristy0c832c62014-03-07 22:21:04 +00001325 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001326 goto cleanup;
1327 }
cristy0c832c62014-03-07 22:21:04 +00001328 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001329 if (clStatus != CL_SUCCESS)
1330 {
cristy0c832c62014-03-07 22:21:04 +00001331 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001332 goto cleanup;
1333 }
1334
1335 for (i = 0; i < kernel->width; i++)
1336 {
1337 kernelBufferPtr[i] = (float) kernel->values[i];
1338 }
1339
cristy0c832c62014-03-07 22:21:04 +00001340 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001341 if (clStatus != CL_SUCCESS)
1342 {
cristy0c832c62014-03-07 22:21:04 +00001343 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001344 goto cleanup;
1345 }
1346 }
1347
1348 {
1349 unsigned int offsetRows;
1350 unsigned int sec;
1351
1352 /* create temp buffer */
1353 {
dirk8a5cf512014-07-28 20:16:27 +00001354 length = image->columns * (image->rows / 2 + 1 + (kernel->width-1) / 2);
cristy0c832c62014-03-07 22:21:04 +00001355 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001356 if (clStatus != CL_SUCCESS)
1357 {
cristy0c832c62014-03-07 22:21:04 +00001358 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001359 goto cleanup;
1360 }
1361 }
1362
1363 /* get the OpenCL kernels */
1364 {
1365 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection");
1366 if (blurRowKernel == NULL)
1367 {
cristya22457d2013-12-07 14:03:06 +00001368 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001369 goto cleanup;
1370 };
1371
1372 blurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurColumnSection");
1373 if (blurColumnKernel == NULL)
1374 {
cristya22457d2013-12-07 14:03:06 +00001375 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001376 goto cleanup;
1377 };
1378 }
1379
1380 for (sec = 0; sec < 2; sec++)
1381 {
1382 {
1383 /* need logic to decide this value */
1384 int chunkSize = 256;
1385
1386 {
dirk8a5cf512014-07-28 20:16:27 +00001387 imageColumns = image->columns;
cristyf034abb2013-11-24 14:16:14 +00001388 if (sec == 0)
dirk8a5cf512014-07-28 20:16:27 +00001389 imageRows = image->rows / 2 + (kernel->width-1) / 2;
cristyf034abb2013-11-24 14:16:14 +00001390 else
dirk8a5cf512014-07-28 20:16:27 +00001391 imageRows = (image->rows - image->rows / 2) + (kernel->width-1) / 2;
cristyf034abb2013-11-24 14:16:14 +00001392
dirk8a5cf512014-07-28 20:16:27 +00001393 offsetRows = sec * image->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00001394
1395 kernelWidth = kernel->width;
1396
1397 /* set the kernel arguments */
1398 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00001399 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00001400 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1401 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
1402 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1403 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1404 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1405 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1406 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
1407 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
1408 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00001409 if (clStatus != CL_SUCCESS)
1410 {
cristy0c832c62014-03-07 22:21:04 +00001411 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001412 goto cleanup;
1413 }
1414 }
1415
1416 /* launch the kernel */
1417 {
1418 size_t gsize[2];
1419 size_t wsize[2];
1420
1421 gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize);
1422 gsize[1] = imageRows;
1423 wsize[0] = chunkSize;
1424 wsize[1] = 1;
1425
cristy0c832c62014-03-07 22:21:04 +00001426 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001427 if (clStatus != CL_SUCCESS)
1428 {
cristy0c832c62014-03-07 22:21:04 +00001429 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001430 goto cleanup;
1431 }
cristy0c832c62014-03-07 22:21:04 +00001432 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001433 }
1434 }
1435
1436 {
1437 /* need logic to decide this value */
1438 int chunkSize = 256;
1439
1440 {
dirk8a5cf512014-07-28 20:16:27 +00001441 imageColumns = image->columns;
cristyf034abb2013-11-24 14:16:14 +00001442 if (sec == 0)
dirk8a5cf512014-07-28 20:16:27 +00001443 imageRows = image->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00001444 else
dirk8a5cf512014-07-28 20:16:27 +00001445 imageRows = (image->rows - image->rows / 2);
cristyf034abb2013-11-24 14:16:14 +00001446
dirk8a5cf512014-07-28 20:16:27 +00001447 offsetRows = sec * image->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00001448
1449 kernelWidth = kernel->width;
1450
1451 /* set the kernel arguments */
1452 i = 0;
cristy0c832c62014-03-07 22:21:04 +00001453 clStatus=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
1454 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
1455 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(ChannelType),&channel);
1456 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
1457 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
1458 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
1459 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
1460 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(cl_float4)*(chunkSize+kernel->width),(void *)NULL);
1461 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
1462 clStatus|=clEnv->library->clSetKernelArg(blurColumnKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00001463 if (clStatus != CL_SUCCESS)
1464 {
cristy0c832c62014-03-07 22:21:04 +00001465 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001466 goto cleanup;
1467 }
1468 }
1469
1470 /* launch the kernel */
1471 {
1472 size_t gsize[2];
1473 size_t wsize[2];
1474
1475 gsize[0] = imageColumns;
1476 gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize);
1477 wsize[0] = 1;
1478 wsize[1] = chunkSize;
1479
cristy0c832c62014-03-07 22:21:04 +00001480 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001481 if (clStatus != CL_SUCCESS)
1482 {
cristy0c832c62014-03-07 22:21:04 +00001483 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001484 goto cleanup;
1485 }
cristy0c832c62014-03-07 22:21:04 +00001486 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001487 }
1488 }
1489 }
1490
1491 }
1492
1493 /* get result */
1494 if (ALIGNED(filteredPixels,CLPixelPacket))
1495 {
dirk8a5cf512014-07-28 20:16:27 +00001496 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001497 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001498 }
1499 else
1500 {
dirk8a5cf512014-07-28 20:16:27 +00001501 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001502 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001503 }
1504 if (clStatus != CL_SUCCESS)
1505 {
cristya22457d2013-12-07 14:03:06 +00001506 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001507 goto cleanup;
1508 }
1509
dirk832becc2014-08-04 19:44:34 +00001510 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
1511
1512cleanup:
1513 OpenCLLogException(__FUNCTION__,__LINE__,exception);
1514
1515 image_view=DestroyCacheView(image_view);
1516 if (filteredImage_view != NULL)
1517 filteredImage_view=DestroyCacheView(filteredImage_view);
1518
dirk8a5cf512014-07-28 20:16:27 +00001519 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00001520 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
1521 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
1522 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00001523 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
1524 if (blurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurColumnKernel);
1525 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
1526 if (kernel!=NULL) DestroyKernelInfo(kernel);
1527 if (outputReady == MagickFalse)
1528 {
1529 if (filteredImage != NULL)
1530 {
1531 DestroyImage(filteredImage);
1532 filteredImage = NULL;
1533 }
1534 }
1535 return filteredImage;
1536}
1537
dirk832becc2014-08-04 19:44:34 +00001538MagickExport Image* AccelerateBlurImage(const Image *image,
1539 const ChannelType channel,const double radius,const double sigma,
1540 ExceptionInfo *exception)
1541{
1542 Image
1543 *filteredImage;
1544
1545 assert(image != NULL);
1546 assert(exception != (ExceptionInfo *) NULL);
1547
1548 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
1549 (checkAccelerateCondition(image, channel) == MagickFalse))
1550 return NULL;
1551
1552 if (splitImage(image) && (image->rows / 2 > radius))
1553 filteredImage=ComputeBlurImageSection(image, channel, radius, sigma, exception);
1554 else
1555 filteredImage=ComputeBlurImage(image, channel, radius, sigma, exception);
1556
1557 return(filteredImage);
dirk8a5cf512014-07-28 20:16:27 +00001558}
1559
cristyf034abb2013-11-24 14:16:14 +00001560/*
1561%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1562% %
1563% %
1564% %
dirk8a5cf512014-07-28 20:16:27 +00001565% R o t a t i o n a l B l u r I m a g e w i t h O p e n C L %
cristyf034abb2013-11-24 14:16:14 +00001566% %
1567% %
1568% %
1569%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1570%
dirk8a5cf512014-07-28 20:16:27 +00001571% RotationalBlurImage() applies a rotational blur to the image.
cristyf034abb2013-11-24 14:16:14 +00001572%
dirk8a5cf512014-07-28 20:16:27 +00001573% Andrew Protano contributed this effect.
cristyf034abb2013-11-24 14:16:14 +00001574%
dirk8a5cf512014-07-28 20:16:27 +00001575% The format of the RotationalBlurImage method is:
1576%
1577% Image *RotationalBlurImage(const Image *image,const double angle,
1578% ExceptionInfo *exception)
1579% Image *RotationalBlurImageChannel(const Image *image,const ChannelType channel,
1580% const double angle,ExceptionInfo *exception)
cristyf034abb2013-11-24 14:16:14 +00001581%
1582% A description of each parameter follows:
1583%
1584% o image: the image.
1585%
1586% o channel: the channel type.
1587%
dirk8a5cf512014-07-28 20:16:27 +00001588% o angle: the angle of the rotational blur.
cristyf034abb2013-11-24 14:16:14 +00001589%
1590% o exception: return any errors or warnings in this structure.
1591%
1592*/
1593
dirk832becc2014-08-04 19:44:34 +00001594static Image* ComputeRotationalBlurImage(const Image *image,
1595 const ChannelType channel,const double angle,ExceptionInfo *exception)
1596{
1597 CacheView
1598 *image_view,
1599 *filteredImage_view;
1600
1601 cl_command_queue
1602 queue;
1603
1604 cl_context
1605 context;
1606
1607 cl_float2
1608 blurCenter;
1609
1610 cl_float4
1611 biasPixel;
1612
1613 cl_int
1614 clStatus;
1615
1616 cl_mem
1617 cosThetaBuffer,
1618 filteredImageBuffer,
1619 imageBuffer,
1620 sinThetaBuffer;
1621
1622 cl_mem_flags
1623 mem_flags;
1624
1625 cl_kernel
1626 rotationalBlurKernel;
1627
1628 const void
1629 *inputPixels;
1630
1631 float
1632 blurRadius,
1633 *cosThetaPtr,
1634 offset,
1635 *sinThetaPtr,
1636 theta;
1637
1638 Image
1639 *filteredImage;
1640
1641 MagickBooleanType
1642 outputReady;
1643
1644 MagickCLEnv
1645 clEnv;
1646
1647 PixelInfo
1648 bias;
1649
1650 MagickSizeType
1651 length;
1652
1653 size_t
1654 global_work_size[2];
1655
1656 unsigned int
1657 cossin_theta_size,
1658 i,
1659 matte;
1660
1661 void
1662 *filteredPixels,
1663 *hostPtr;
1664
1665 outputReady = MagickFalse;
1666 context = NULL;
1667 filteredImage = NULL;
1668 filteredImage_view = NULL;
1669 imageBuffer = NULL;
1670 filteredImageBuffer = NULL;
1671 sinThetaBuffer = NULL;
1672 cosThetaBuffer = NULL;
1673 queue = NULL;
1674 rotationalBlurKernel = NULL;
1675
1676
1677 clEnv = GetDefaultOpenCLEnv();
1678 context = GetOpenCLContext(clEnv);
1679
1680
1681 /* Create and initialize OpenCL buffers. */
1682
1683 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00001684 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00001685 if (inputPixels == (const void *) NULL)
1686 {
dirk8a5cf512014-07-28 20:16:27 +00001687 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00001688 goto cleanup;
1689 }
1690
1691 /* If the host pointer is aligned to the size of CLPixelPacket,
1692 then use the host buffer directly from the GPU; otherwise,
1693 create a buffer on the GPU and copy the data over */
1694 if (ALIGNED(inputPixels,CLPixelPacket))
1695 {
1696 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
1697 }
1698 else
1699 {
1700 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
1701 }
1702 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00001703 length = image->columns * image->rows;
1704 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001705 if (clStatus != CL_SUCCESS)
1706 {
cristy0c832c62014-03-07 22:21:04 +00001707 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001708 goto cleanup;
1709 }
1710
1711
dirk8a5cf512014-07-28 20:16:27 +00001712 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +00001713 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00001714 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00001715 {
cristya22457d2013-12-07 14:03:06 +00001716 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001717 goto cleanup;
1718 }
dirk832becc2014-08-04 19:44:34 +00001719 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00001720 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00001721 if (filteredPixels == (void *) NULL)
1722 {
cristya22457d2013-12-07 14:03:06 +00001723 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00001724 goto cleanup;
1725 }
1726
1727 if (ALIGNED(filteredPixels,CLPixelPacket))
1728 {
1729 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
1730 hostPtr = filteredPixels;
1731 }
1732 else
1733 {
1734 mem_flags = CL_MEM_WRITE_ONLY;
1735 hostPtr = NULL;
1736 }
1737 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00001738 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001739 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001740 if (clStatus != CL_SUCCESS)
1741 {
cristy0c832c62014-03-07 22:21:04 +00001742 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001743 goto cleanup;
1744 }
1745
dirk8a5cf512014-07-28 20:16:27 +00001746 blurCenter.s[0] = (float) (image->columns-1)/2.0;
1747 blurCenter.s[1] = (float) (image->rows-1)/2.0;
cristyf034abb2013-11-24 14:16:14 +00001748 blurRadius=hypot(blurCenter.s[0],blurCenter.s[1]);
1749 cossin_theta_size=(unsigned int) fabs(4.0*DegreesToRadians(angle)*sqrt((double)blurRadius)+2UL);
1750
1751 /* create a buffer for sin_theta and cos_theta */
cristy0c832c62014-03-07 22:21:04 +00001752 sinThetaBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, cossin_theta_size * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001753 if (clStatus != CL_SUCCESS)
1754 {
cristy0c832c62014-03-07 22:21:04 +00001755 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001756 goto cleanup;
1757 }
cristy0c832c62014-03-07 22:21:04 +00001758 cosThetaBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, cossin_theta_size * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001759 if (clStatus != CL_SUCCESS)
1760 {
cristy0c832c62014-03-07 22:21:04 +00001761 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001762 goto cleanup;
1763 }
1764
1765
1766 queue = AcquireOpenCLCommandQueue(clEnv);
cristy0c832c62014-03-07 22:21:04 +00001767 sinThetaPtr = (float*) clEnv->library->clEnqueueMapBuffer(queue, sinThetaBuffer, CL_TRUE, CL_MAP_WRITE, 0, cossin_theta_size*sizeof(float), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001768 if (clStatus != CL_SUCCESS)
1769 {
cristya22457d2013-12-07 14:03:06 +00001770 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001771 goto cleanup;
1772 }
1773
cristy0c832c62014-03-07 22:21:04 +00001774 cosThetaPtr = (float*) clEnv->library->clEnqueueMapBuffer(queue, cosThetaBuffer, CL_TRUE, CL_MAP_WRITE, 0, cossin_theta_size*sizeof(float), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001775 if (clStatus != CL_SUCCESS)
1776 {
cristya22457d2013-12-07 14:03:06 +00001777 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnqueuemapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00001778 goto cleanup;
1779 }
1780
1781 theta=DegreesToRadians(angle)/(MagickRealType) (cossin_theta_size-1);
1782 offset=theta*(MagickRealType) (cossin_theta_size-1)/2.0;
1783 for (i=0; i < (ssize_t) cossin_theta_size; i++)
1784 {
1785 cosThetaPtr[i]=(float)cos((double) (theta*i-offset));
1786 sinThetaPtr[i]=(float)sin((double) (theta*i-offset));
1787 }
1788
cristy0c832c62014-03-07 22:21:04 +00001789 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, sinThetaBuffer, sinThetaPtr, 0, NULL, NULL);
1790 clStatus |= clEnv->library->clEnqueueUnmapMemObject(queue, cosThetaBuffer, cosThetaPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001791 if (clStatus != CL_SUCCESS)
1792 {
cristy0c832c62014-03-07 22:21:04 +00001793 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001794 goto cleanup;
1795 }
1796
1797 /* get the OpenCL kernel */
dirk6d612cf2014-03-13 21:17:23 +00001798 rotationalBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RotationalBlur");
1799 if (rotationalBlurKernel == NULL)
cristyf034abb2013-11-24 14:16:14 +00001800 {
cristya22457d2013-12-07 14:03:06 +00001801 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001802 goto cleanup;
1803 }
1804
1805
1806 /* set the kernel arguments */
1807 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00001808 clStatus=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
dirk6d612cf2014-03-13 21:17:23 +00001809 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00001810
dirk8a5cf512014-07-28 20:16:27 +00001811 GetPixelInfo(image,&bias);
cristyf034abb2013-11-24 14:16:14 +00001812 biasPixel.s[0] = bias.red;
1813 biasPixel.s[1] = bias.green;
1814 biasPixel.s[2] = bias.blue;
dirk8a5cf512014-07-28 20:16:27 +00001815 biasPixel.s[3] = bias.alpha;
dirk6d612cf2014-03-13 21:17:23 +00001816 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_float4), &biasPixel);
1817 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(ChannelType), &channel);
cristyf034abb2013-11-24 14:16:14 +00001818
dirk8a5cf512014-07-28 20:16:27 +00001819 matte = (image->alpha_trait==BlendPixelTrait)?1:0;
dirk6d612cf2014-03-13 21:17:23 +00001820 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(unsigned int), &matte);
cristyf034abb2013-11-24 14:16:14 +00001821
dirk6d612cf2014-03-13 21:17:23 +00001822 clStatus=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_float2), &blurCenter);
cristyf034abb2013-11-24 14:16:14 +00001823
dirk6d612cf2014-03-13 21:17:23 +00001824 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&cosThetaBuffer);
1825 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(cl_mem),(void *)&sinThetaBuffer);
1826 clStatus|=clEnv->library->clSetKernelArg(rotationalBlurKernel,i++,sizeof(unsigned int), &cossin_theta_size);
cristyf034abb2013-11-24 14:16:14 +00001827 if (clStatus != CL_SUCCESS)
1828 {
cristy0c832c62014-03-07 22:21:04 +00001829 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001830 goto cleanup;
1831 }
1832
1833
dirk8a5cf512014-07-28 20:16:27 +00001834 global_work_size[0] = image->columns;
1835 global_work_size[1] = image->rows;
cristyf034abb2013-11-24 14:16:14 +00001836 /* launch the kernel */
dirk6d612cf2014-03-13 21:17:23 +00001837 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, rotationalBlurKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001838 if (clStatus != CL_SUCCESS)
1839 {
cristy0c832c62014-03-07 22:21:04 +00001840 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001841 goto cleanup;
1842 }
cristy0c832c62014-03-07 22:21:04 +00001843 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00001844
1845 if (ALIGNED(filteredPixels,CLPixelPacket))
1846 {
dirk8a5cf512014-07-28 20:16:27 +00001847 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001848 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00001849 }
1850 else
1851 {
dirk8a5cf512014-07-28 20:16:27 +00001852 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00001853 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00001854 }
1855 if (clStatus != CL_SUCCESS)
1856 {
cristya22457d2013-12-07 14:03:06 +00001857 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00001858 goto cleanup;
1859 }
dirk832becc2014-08-04 19:44:34 +00001860 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
1861
1862cleanup:
1863 OpenCLLogException(__FUNCTION__,__LINE__,exception);
1864
1865 image_view=DestroyCacheView(image_view);
1866 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00001867 filteredImage_view=DestroyCacheView(filteredImage_view);
cristya22457d2013-12-07 14:03:06 +00001868
cristy0c832c62014-03-07 22:21:04 +00001869 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +00001870 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00001871 if (sinThetaBuffer!=NULL) clEnv->library->clReleaseMemObject(sinThetaBuffer);
1872 if (cosThetaBuffer!=NULL) clEnv->library->clReleaseMemObject(cosThetaBuffer);
dirk6d612cf2014-03-13 21:17:23 +00001873 if (rotationalBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, rotationalBlurKernel);
cristyf034abb2013-11-24 14:16:14 +00001874 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
1875 if (outputReady == MagickFalse)
1876 {
1877 if (filteredImage != NULL)
1878 {
1879 DestroyImage(filteredImage);
1880 filteredImage = NULL;
1881 }
1882 }
1883 return filteredImage;
1884}
1885
dirk832becc2014-08-04 19:44:34 +00001886MagickExport Image* AccelerateRotationalBlurImage(const Image *image,
1887 const ChannelType channel,const double angle,ExceptionInfo *exception)
1888{
1889 Image
1890 *filteredImage;
1891
1892 assert(image != NULL);
1893 assert(exception != (ExceptionInfo *) NULL);
1894
1895 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
1896 (checkAccelerateCondition(image, channel) == MagickFalse))
1897 return NULL;
1898
1899 filteredImage=ComputeRotationalBlurImage(image, channel, angle, exception);
1900 return filteredImage;
dirk8a5cf512014-07-28 20:16:27 +00001901}
1902
cristyf034abb2013-11-24 14:16:14 +00001903/*
1904%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1905% %
1906% %
1907% %
dirk8a5cf512014-07-28 20:16:27 +00001908% 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 %
cristyf034abb2013-11-24 14:16:14 +00001909% %
1910% %
1911% %
1912%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1913%
dirk8a5cf512014-07-28 20:16:27 +00001914% UnsharpMaskImage() sharpens one or more image channels. We convolve the
1915% image with a Gaussian operator of the given radius and standard deviation
1916% (sigma). For reasonable results, radius should be larger than sigma. Use a
1917% radius of 0 and UnsharpMaskImage() selects a suitable radius for you.
cristyf034abb2013-11-24 14:16:14 +00001918%
dirk8a5cf512014-07-28 20:16:27 +00001919% The format of the UnsharpMaskImage method is:
cristyf034abb2013-11-24 14:16:14 +00001920%
dirk8a5cf512014-07-28 20:16:27 +00001921% Image *UnsharpMaskImage(const Image *image,const double radius,
1922% const double sigma,const double amount,const double threshold,
cristyf034abb2013-11-24 14:16:14 +00001923% ExceptionInfo *exception)
dirk8a5cf512014-07-28 20:16:27 +00001924% Image *UnsharpMaskImageChannel(const Image *image,
1925% const ChannelType channel,const double radius,const double sigma,
1926% const double gain,const double threshold,ExceptionInfo *exception)
cristyf034abb2013-11-24 14:16:14 +00001927%
1928% A description of each parameter follows:
1929%
1930% o image: the image.
1931%
1932% o channel: the channel type.
1933%
dirk8a5cf512014-07-28 20:16:27 +00001934% o radius: the radius of the Gaussian, in pixels, not counting the center
1935% pixel.
1936%
1937% o sigma: the standard deviation of the Gaussian, in pixels.
1938%
1939% o gain: the percentage of the difference between the original and the
1940% blur image that is added back into the original.
1941%
1942% o threshold: the threshold in pixels needed to apply the diffence gain.
cristyf034abb2013-11-24 14:16:14 +00001943%
1944% o exception: return any errors or warnings in this structure.
1945%
1946*/
1947
dirk832becc2014-08-04 19:44:34 +00001948static Image *ComputeUnsharpMaskImage(const Image *image,
1949 const ChannelType channel,const double radius,const double sigma,
1950 const double gain,const double threshold,ExceptionInfo *exception)
1951{
1952 CacheView
1953 *filteredImage_view,
1954 *image_view;
1955
1956 char
1957 geometry[MaxTextExtent];
1958
1959 cl_command_queue
1960 queue;
1961
1962 cl_context
1963 context;
1964
1965 cl_int
1966 clStatus;
1967
1968 cl_kernel
1969 blurRowKernel,
1970 unsharpMaskBlurColumnKernel;
1971
1972 cl_mem
1973 filteredImageBuffer,
1974 imageBuffer,
1975 imageKernelBuffer,
1976 tempImageBuffer;
1977
1978 cl_mem_flags
1979 mem_flags;
1980
1981 const void
1982 *inputPixels;
1983
1984 float
1985 fGain,
1986 fThreshold,
1987 *kernelBufferPtr;
1988
1989 Image
1990 *filteredImage;
1991
1992 int
1993 chunkSize;
1994
1995 KernelInfo
1996 *kernel;
1997
1998 MagickBooleanType
1999 outputReady;
2000
2001 MagickCLEnv
2002 clEnv;
2003
2004 MagickSizeType
2005 length;
2006
2007 void
2008 *filteredPixels,
2009 *hostPtr;
2010
2011 unsigned int
2012 i,
2013 imageColumns,
2014 imageRows,
2015 kernelWidth;
2016
2017 clEnv = NULL;
2018 filteredImage = NULL;
2019 filteredImage_view = NULL;
2020 kernel = NULL;
2021 context = NULL;
2022 imageBuffer = NULL;
2023 filteredImageBuffer = NULL;
2024 tempImageBuffer = NULL;
2025 imageKernelBuffer = NULL;
2026 blurRowKernel = NULL;
2027 unsharpMaskBlurColumnKernel = NULL;
2028 queue = NULL;
2029 outputReady = MagickFalse;
2030
2031 clEnv = GetDefaultOpenCLEnv();
2032 context = GetOpenCLContext(clEnv);
2033 queue = AcquireOpenCLCommandQueue(clEnv);
2034
2035 /* Create and initialize OpenCL buffers. */
2036 {
2037 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00002038 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00002039 if (inputPixels == (const void *) NULL)
2040 {
dirk8a5cf512014-07-28 20:16:27 +00002041 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00002042 goto cleanup;
2043 }
2044
2045 /* If the host pointer is aligned to the size of CLPixelPacket,
2046 then use the host buffer directly from the GPU; otherwise,
2047 create a buffer on the GPU and copy the data over */
2048 if (ALIGNED(inputPixels,CLPixelPacket))
2049 {
2050 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2051 }
2052 else
2053 {
2054 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2055 }
2056 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00002057 length = image->columns * image->rows;
2058 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002059 if (clStatus != CL_SUCCESS)
2060 {
cristy0c832c62014-03-07 22:21:04 +00002061 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002062 goto cleanup;
2063 }
2064 }
2065
2066 /* create output */
2067 {
dirk8a5cf512014-07-28 20:16:27 +00002068 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +00002069 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00002070 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00002071 {
cristya22457d2013-12-07 14:03:06 +00002072 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002073 goto cleanup;
2074 }
dirk832becc2014-08-04 19:44:34 +00002075 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00002076 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00002077 if (filteredPixels == (void *) NULL)
2078 {
cristya22457d2013-12-07 14:03:06 +00002079 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00002080 goto cleanup;
2081 }
2082
2083 if (ALIGNED(filteredPixels,CLPixelPacket))
2084 {
2085 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
2086 hostPtr = filteredPixels;
2087 }
2088 else
2089 {
2090 mem_flags = CL_MEM_WRITE_ONLY;
2091 hostPtr = NULL;
2092 }
2093
2094 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00002095 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002096 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002097 if (clStatus != CL_SUCCESS)
2098 {
cristy0c832c62014-03-07 22:21:04 +00002099 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002100 goto cleanup;
2101 }
2102 }
2103
2104 /* create the blur kernel */
2105 {
2106 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
2107 kernel=AcquireKernelInfo(geometry);
2108 if (kernel == (KernelInfo *) NULL)
2109 {
cristya22457d2013-12-07 14:03:06 +00002110 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002111 goto cleanup;
2112 }
2113
cristy0c832c62014-03-07 22:21:04 +00002114 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002115 if (clStatus != CL_SUCCESS)
2116 {
cristy0c832c62014-03-07 22:21:04 +00002117 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002118 goto cleanup;
2119 }
2120
2121
cristy0c832c62014-03-07 22:21:04 +00002122 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002123 if (clStatus != CL_SUCCESS)
2124 {
cristy0c832c62014-03-07 22:21:04 +00002125 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002126 goto cleanup;
2127 }
2128 for (i = 0; i < kernel->width; i++)
2129 {
2130 kernelBufferPtr[i] = (float) kernel->values[i];
2131 }
cristy0c832c62014-03-07 22:21:04 +00002132 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002133 if (clStatus != CL_SUCCESS)
2134 {
cristy0c832c62014-03-07 22:21:04 +00002135 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002136 goto cleanup;
2137 }
2138 }
2139
2140 {
2141 /* create temp buffer */
2142 {
dirk8a5cf512014-07-28 20:16:27 +00002143 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002144 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002145 if (clStatus != CL_SUCCESS)
2146 {
cristy0c832c62014-03-07 22:21:04 +00002147 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002148 goto cleanup;
2149 }
2150 }
2151
2152 /* get the opencl kernel */
2153 {
2154 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRow");
2155 if (blurRowKernel == NULL)
2156 {
cristya22457d2013-12-07 14:03:06 +00002157 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002158 goto cleanup;
2159 };
2160
2161 unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumn");
2162 if (unsharpMaskBlurColumnKernel == NULL)
2163 {
cristya22457d2013-12-07 14:03:06 +00002164 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002165 goto cleanup;
2166 };
2167 }
2168
2169 {
2170 chunkSize = 256;
2171
dirk8a5cf512014-07-28 20:16:27 +00002172 imageColumns = image->columns;
2173 imageRows = image->rows;
cristyf034abb2013-11-24 14:16:14 +00002174
2175 kernelWidth = kernel->width;
2176
2177 /* set the kernel arguments */
2178 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00002179 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00002180 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2181 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
2182 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2183 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2184 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2185 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2186 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
cristyf034abb2013-11-24 14:16:14 +00002187 if (clStatus != CL_SUCCESS)
2188 {
cristy0c832c62014-03-07 22:21:04 +00002189 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002190 goto cleanup;
2191 }
2192 }
2193
2194 /* launch the kernel */
2195 {
2196 size_t gsize[2];
2197 size_t wsize[2];
2198
dirk8a5cf512014-07-28 20:16:27 +00002199 gsize[0] = chunkSize*((image->columns+chunkSize-1)/chunkSize);
2200 gsize[1] = image->rows;
cristyf034abb2013-11-24 14:16:14 +00002201 wsize[0] = chunkSize;
2202 wsize[1] = 1;
2203
cristy0c832c62014-03-07 22:21:04 +00002204 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002205 if (clStatus != CL_SUCCESS)
2206 {
cristy0c832c62014-03-07 22:21:04 +00002207 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002208 goto cleanup;
2209 }
cristy0c832c62014-03-07 22:21:04 +00002210 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002211 }
2212
2213
2214 {
2215 chunkSize = 256;
dirk8a5cf512014-07-28 20:16:27 +00002216 imageColumns = image->columns;
2217 imageRows = image->rows;
cristyf034abb2013-11-24 14:16:14 +00002218 kernelWidth = kernel->width;
2219 fGain = (float)gain;
2220 fThreshold = (float)threshold;
2221
2222 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00002223 clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00002224 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2225 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
2226 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2227 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2228 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
2229 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL);
2230 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel);
2231 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2232 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2233 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
2234 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
cristyf034abb2013-11-24 14:16:14 +00002235
2236 if (clStatus != CL_SUCCESS)
2237 {
cristy0c832c62014-03-07 22:21:04 +00002238 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002239 goto cleanup;
2240 }
2241 }
2242
2243 /* launch the kernel */
2244 {
2245 size_t gsize[2];
2246 size_t wsize[2];
2247
dirk8a5cf512014-07-28 20:16:27 +00002248 gsize[0] = image->columns;
2249 gsize[1] = chunkSize*((image->rows+chunkSize-1)/chunkSize);
cristyf034abb2013-11-24 14:16:14 +00002250 wsize[0] = 1;
2251 wsize[1] = chunkSize;
2252
cristy0c832c62014-03-07 22:21:04 +00002253 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002254 if (clStatus != CL_SUCCESS)
2255 {
cristy0c832c62014-03-07 22:21:04 +00002256 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002257 goto cleanup;
2258 }
cristy0c832c62014-03-07 22:21:04 +00002259 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002260 }
2261
2262 }
2263
2264 /* get result */
2265 if (ALIGNED(filteredPixels,CLPixelPacket))
2266 {
dirk8a5cf512014-07-28 20:16:27 +00002267 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002268 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002269 }
2270 else
2271 {
dirk8a5cf512014-07-28 20:16:27 +00002272 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002273 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002274 }
2275 if (clStatus != CL_SUCCESS)
2276 {
cristya22457d2013-12-07 14:03:06 +00002277 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002278 goto cleanup;
2279 }
2280
dirk832becc2014-08-04 19:44:34 +00002281 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
2282
2283cleanup:
2284 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2285
2286 image_view=DestroyCacheView(image_view);
2287 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00002288 filteredImage_view=DestroyCacheView(filteredImage_view);
cristya22457d2013-12-07 14:03:06 +00002289
cristyf034abb2013-11-24 14:16:14 +00002290 if (kernel != NULL) kernel=DestroyKernelInfo(kernel);
dirk8a5cf512014-07-28 20:16:27 +00002291 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00002292 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
2293 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
2294 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00002295 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
2296 if (unsharpMaskBlurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel);
2297 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
2298 if (outputReady == MagickFalse)
2299 {
2300 if (filteredImage != NULL)
2301 {
2302 DestroyImage(filteredImage);
2303 filteredImage = NULL;
2304 }
2305 }
dirk8a5cf512014-07-28 20:16:27 +00002306 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00002307}
2308
dirk832becc2014-08-04 19:44:34 +00002309static Image *ComputeUnsharpMaskImageSection(const Image *image,
2310 const ChannelType channel,const double radius,const double sigma,
2311 const double gain,const double threshold,ExceptionInfo *exception)
2312{
2313 CacheView
2314 *filteredImage_view,
2315 *image_view;
2316
2317 char
2318 geometry[MaxTextExtent];
2319
2320 cl_command_queue
2321 queue;
2322
2323 cl_context
2324 context;
2325
2326 cl_int
2327 clStatus;
2328
2329 cl_kernel
2330 blurRowKernel,
2331 unsharpMaskBlurColumnKernel;
2332
2333 cl_mem
2334 filteredImageBuffer,
2335 imageBuffer,
2336 imageKernelBuffer,
2337 tempImageBuffer;
2338
2339 cl_mem_flags
2340 mem_flags;
2341
2342 const void
2343 *inputPixels;
2344
2345 float
2346 fGain,
2347 fThreshold,
2348 *kernelBufferPtr;
2349
2350 Image
2351 *filteredImage;
2352
2353 int
2354 chunkSize;
2355
2356 KernelInfo
2357 *kernel;
2358
2359 MagickBooleanType
2360 outputReady;
2361
2362 MagickCLEnv
2363 clEnv;
2364
2365 MagickSizeType
2366 length;
2367
2368 void
2369 *filteredPixels,
2370 *hostPtr;
2371
2372 unsigned int
2373 i,
2374 imageColumns,
2375 imageRows,
2376 kernelWidth;
2377
2378 clEnv = NULL;
2379 filteredImage = NULL;
2380 filteredImage_view = NULL;
2381 kernel = NULL;
2382 context = NULL;
2383 imageBuffer = NULL;
2384 filteredImageBuffer = NULL;
2385 tempImageBuffer = NULL;
2386 imageKernelBuffer = NULL;
2387 blurRowKernel = NULL;
2388 unsharpMaskBlurColumnKernel = NULL;
2389 queue = NULL;
2390 outputReady = MagickFalse;
2391
2392 clEnv = GetDefaultOpenCLEnv();
2393 context = GetOpenCLContext(clEnv);
2394 queue = AcquireOpenCLCommandQueue(clEnv);
2395
2396 /* Create and initialize OpenCL buffers. */
2397 {
2398 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00002399 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00002400 if (inputPixels == (const void *) NULL)
2401 {
dirk8a5cf512014-07-28 20:16:27 +00002402 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00002403 goto cleanup;
2404 }
2405
2406 /* If the host pointer is aligned to the size of CLPixelPacket,
2407 then use the host buffer directly from the GPU; otherwise,
2408 create a buffer on the GPU and copy the data over */
2409 if (ALIGNED(inputPixels,CLPixelPacket))
2410 {
2411 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
2412 }
2413 else
2414 {
2415 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
2416 }
2417 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00002418 length = image->columns * image->rows;
2419 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002420 if (clStatus != CL_SUCCESS)
2421 {
cristy0c832c62014-03-07 22:21:04 +00002422 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002423 goto cleanup;
2424 }
2425 }
2426
2427 /* create output */
2428 {
dirk8a5cf512014-07-28 20:16:27 +00002429 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +00002430 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00002431 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00002432 {
cristya22457d2013-12-07 14:03:06 +00002433 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002434 goto cleanup;
2435 }
dirk832becc2014-08-04 19:44:34 +00002436 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00002437 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00002438 if (filteredPixels == (void *) NULL)
2439 {
cristya22457d2013-12-07 14:03:06 +00002440 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00002441 goto cleanup;
2442 }
2443
2444 if (ALIGNED(filteredPixels,CLPixelPacket))
2445 {
2446 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
2447 hostPtr = filteredPixels;
2448 }
2449 else
2450 {
2451 mem_flags = CL_MEM_WRITE_ONLY;
2452 hostPtr = NULL;
2453 }
2454
2455 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00002456 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002457 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002458 if (clStatus != CL_SUCCESS)
2459 {
cristy0c832c62014-03-07 22:21:04 +00002460 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002461 goto cleanup;
2462 }
2463 }
2464
2465 /* create the blur kernel */
2466 {
2467 (void) FormatLocaleString(geometry,MaxTextExtent,"blur:%.20gx%.20g;blur:%.20gx%.20g+90",radius,sigma,radius,sigma);
2468 kernel=AcquireKernelInfo(geometry);
2469 if (kernel == (KernelInfo *) NULL)
2470 {
cristya22457d2013-12-07 14:03:06 +00002471 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireKernelInfo failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002472 goto cleanup;
2473 }
2474
cristy0c832c62014-03-07 22:21:04 +00002475 imageKernelBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, kernel->width * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002476 if (clStatus != CL_SUCCESS)
2477 {
cristy0c832c62014-03-07 22:21:04 +00002478 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002479 goto cleanup;
2480 }
2481
2482
cristy0c832c62014-03-07 22:21:04 +00002483 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer, CL_TRUE, CL_MAP_WRITE, 0, kernel->width * sizeof(float), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002484 if (clStatus != CL_SUCCESS)
2485 {
cristy0c832c62014-03-07 22:21:04 +00002486 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002487 goto cleanup;
2488 }
2489 for (i = 0; i < kernel->width; i++)
2490 {
2491 kernelBufferPtr[i] = (float) kernel->values[i];
2492 }
cristy0c832c62014-03-07 22:21:04 +00002493 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002494 if (clStatus != CL_SUCCESS)
2495 {
cristy0c832c62014-03-07 22:21:04 +00002496 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002497 goto cleanup;
2498 }
2499 }
2500
2501 {
2502 unsigned int offsetRows;
2503 unsigned int sec;
2504
2505 /* create temp buffer */
2506 {
dirk8a5cf512014-07-28 20:16:27 +00002507 length = image->columns * (image->rows / 2 + 1 + (kernel->width-1) / 2);
cristy0c832c62014-03-07 22:21:04 +00002508 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length * 4 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002509 if (clStatus != CL_SUCCESS)
2510 {
cristy0c832c62014-03-07 22:21:04 +00002511 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00002512 goto cleanup;
2513 }
2514 }
2515
2516 /* get the opencl kernel */
2517 {
2518 blurRowKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "BlurRowSection");
2519 if (blurRowKernel == NULL)
2520 {
cristya22457d2013-12-07 14:03:06 +00002521 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002522 goto cleanup;
2523 };
2524
2525 unsharpMaskBlurColumnKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "UnsharpMaskBlurColumnSection");
2526 if (unsharpMaskBlurColumnKernel == NULL)
2527 {
cristya22457d2013-12-07 14:03:06 +00002528 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002529 goto cleanup;
2530 };
2531 }
2532
2533 for (sec = 0; sec < 2; sec++)
2534 {
2535 {
2536 chunkSize = 256;
2537
dirk8a5cf512014-07-28 20:16:27 +00002538 imageColumns = image->columns;
cristyf034abb2013-11-24 14:16:14 +00002539 if (sec == 0)
dirk8a5cf512014-07-28 20:16:27 +00002540 imageRows = image->rows / 2 + (kernel->width-1) / 2;
cristyf034abb2013-11-24 14:16:14 +00002541 else
dirk8a5cf512014-07-28 20:16:27 +00002542 imageRows = (image->rows - image->rows / 2) + (kernel->width-1) / 2;
cristyf034abb2013-11-24 14:16:14 +00002543
dirk8a5cf512014-07-28 20:16:27 +00002544 offsetRows = sec * image->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00002545
2546 kernelWidth = kernel->width;
2547
2548 /* set the kernel arguments */
2549 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00002550 clStatus=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00002551 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2552 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(ChannelType),&channel);
2553 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2554 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2555 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2556 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2557 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(CLPixelPacket)*(chunkSize+kernel->width),(void *)NULL);
2558 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
2559 clStatus|=clEnv->library->clSetKernelArg(blurRowKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00002560 if (clStatus != CL_SUCCESS)
2561 {
cristy0c832c62014-03-07 22:21:04 +00002562 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002563 goto cleanup;
2564 }
2565 }
2566 /* launch the kernel */
2567 {
2568 size_t gsize[2];
2569 size_t wsize[2];
2570
2571 gsize[0] = chunkSize*((imageColumns+chunkSize-1)/chunkSize);
2572 gsize[1] = imageRows;
2573 wsize[0] = chunkSize;
2574 wsize[1] = 1;
2575
cristy0c832c62014-03-07 22:21:04 +00002576 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, blurRowKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002577 if (clStatus != CL_SUCCESS)
2578 {
cristy0c832c62014-03-07 22:21:04 +00002579 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002580 goto cleanup;
2581 }
cristy0c832c62014-03-07 22:21:04 +00002582 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002583 }
2584
2585
2586 {
2587 chunkSize = 256;
2588
dirk8a5cf512014-07-28 20:16:27 +00002589 imageColumns = image->columns;
cristyf034abb2013-11-24 14:16:14 +00002590 if (sec == 0)
dirk8a5cf512014-07-28 20:16:27 +00002591 imageRows = image->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00002592 else
dirk8a5cf512014-07-28 20:16:27 +00002593 imageRows = (image->rows - image->rows / 2);
cristyf034abb2013-11-24 14:16:14 +00002594
dirk8a5cf512014-07-28 20:16:27 +00002595 offsetRows = sec * image->rows / 2;
cristyf034abb2013-11-24 14:16:14 +00002596
2597 kernelWidth = kernel->width;
2598
2599 fGain = (float)gain;
2600 fThreshold = (float)threshold;
2601
2602 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00002603 clStatus=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00002604 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&tempImageBuffer);
2605 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&filteredImageBuffer);
2606 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageColumns);
2607 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&imageRows);
2608 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, (chunkSize+kernelWidth-1)*sizeof(cl_float4),NULL);
2609 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++, kernelWidth*sizeof(float),NULL);
2610 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(ChannelType),&channel);
2611 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(cl_mem),(void *)&imageKernelBuffer);
2612 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&kernelWidth);
2613 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fGain);
2614 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(float),(void *)&fThreshold);
2615 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&offsetRows);
2616 clStatus|=clEnv->library->clSetKernelArg(unsharpMaskBlurColumnKernel,i++,sizeof(unsigned int),(void *)&sec);
cristyf034abb2013-11-24 14:16:14 +00002617
2618 if (clStatus != CL_SUCCESS)
2619 {
cristy0c832c62014-03-07 22:21:04 +00002620 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002621 goto cleanup;
2622 }
2623 }
2624
2625 /* launch the kernel */
2626 {
2627 size_t gsize[2];
2628 size_t wsize[2];
2629
2630 gsize[0] = imageColumns;
2631 gsize[1] = chunkSize*((imageRows+chunkSize-1)/chunkSize);
2632 wsize[0] = 1;
2633 wsize[1] = chunkSize;
2634
cristy0c832c62014-03-07 22:21:04 +00002635 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, unsharpMaskBlurColumnKernel, 2, NULL, gsize, wsize, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002636 if (clStatus != CL_SUCCESS)
2637 {
cristy0c832c62014-03-07 22:21:04 +00002638 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002639 goto cleanup;
2640 }
cristy0c832c62014-03-07 22:21:04 +00002641 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002642 }
2643 }
2644 }
2645
2646 /* get result */
2647 if (ALIGNED(filteredPixels,CLPixelPacket))
2648 {
dirk8a5cf512014-07-28 20:16:27 +00002649 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002650 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00002651 }
2652 else
2653 {
dirk8a5cf512014-07-28 20:16:27 +00002654 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00002655 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002656 }
2657 if (clStatus != CL_SUCCESS)
2658 {
cristya22457d2013-12-07 14:03:06 +00002659 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002660 goto cleanup;
2661 }
2662
dirk832becc2014-08-04 19:44:34 +00002663 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
2664
2665cleanup:
2666 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2667
2668 image_view=DestroyCacheView(image_view);
2669 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00002670 filteredImage_view=DestroyCacheView(filteredImage_view);
cristya22457d2013-12-07 14:03:06 +00002671
cristyf034abb2013-11-24 14:16:14 +00002672 if (kernel != NULL) kernel=DestroyKernelInfo(kernel);
dirk8a5cf512014-07-28 20:16:27 +00002673 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00002674 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
2675 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
2676 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
cristyf034abb2013-11-24 14:16:14 +00002677 if (blurRowKernel!=NULL) RelinquishOpenCLKernel(clEnv, blurRowKernel);
2678 if (unsharpMaskBlurColumnKernel!=NULL) RelinquishOpenCLKernel(clEnv, unsharpMaskBlurColumnKernel);
2679 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
2680 if (outputReady == MagickFalse)
2681 {
2682 if (filteredImage != NULL)
2683 {
2684 DestroyImage(filteredImage);
2685 filteredImage = NULL;
2686 }
2687 }
2688 return filteredImage;
dirk832becc2014-08-04 19:44:34 +00002689}
2690
2691MagickExport Image *AccelerateUnsharpMaskImage(const Image *image,
2692 const ChannelType channel,const double radius,const double sigma,
2693 const double gain,const double threshold,ExceptionInfo *exception)
2694{
2695 Image
2696 *filteredImage;
2697
2698 assert(image != NULL);
2699 assert(exception != (ExceptionInfo *) NULL);
2700
2701 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
2702 (checkAccelerateCondition(image, channel) == MagickFalse))
2703 return NULL;
2704
2705 if (splitImage(image) && (image->rows / 2 > radius))
2706 filteredImage = ComputeUnsharpMaskImageSection(image,channel,radius,sigma,gain,threshold,exception);
2707 else
2708 filteredImage = ComputeUnsharpMaskImage(image,channel,radius,sigma,gain,threshold,exception);
2709 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00002710}
2711
cristyf034abb2013-11-24 14:16:14 +00002712/*
2713%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714% %
2715% %
2716% %
dirk8a5cf512014-07-28 20:16:27 +00002717% A c c e l e r a t e R e s i z e I m a g e %
cristyf034abb2013-11-24 14:16:14 +00002718% %
2719% %
2720% %
2721%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722%
dirk8a5cf512014-07-28 20:16:27 +00002723% AccelerateResizeImage() is an OpenCL implementation of ResizeImage()
cristyf034abb2013-11-24 14:16:14 +00002724%
dirk8a5cf512014-07-28 20:16:27 +00002725% AccelerateResizeImage() scales an image to the desired dimensions, using the given
2726% filter (see AcquireFilterInfo()).
cristyf034abb2013-11-24 14:16:14 +00002727%
dirk8a5cf512014-07-28 20:16:27 +00002728% If an undefined filter is given the filter defaults to Mitchell for a
2729% colormapped image, a image with a matte channel, or if the image is
2730% enlarged. Otherwise the filter defaults to a Lanczos.
2731%
2732% AccelerateResizeImage() was inspired by Paul Heckbert's "zoom" program.
2733%
2734% The format of the AccelerateResizeImage method is:
2735%
2736% Image *ResizeImage(Image *image,const size_t columns,
2737% const size_t rows, const ResizeFilter* filter,
2738% ExceptionInfo *exception)
cristyf034abb2013-11-24 14:16:14 +00002739%
2740% A description of each parameter follows:
2741%
2742% o image: the image.
2743%
dirk8a5cf512014-07-28 20:16:27 +00002744% o columns: the number of columns in the scaled image.
cristyf034abb2013-11-24 14:16:14 +00002745%
dirk8a5cf512014-07-28 20:16:27 +00002746% o rows: the number of rows in the scaled image.
cristyf034abb2013-11-24 14:16:14 +00002747%
dirk8a5cf512014-07-28 20:16:27 +00002748% o filter: Image filter to use.
cristyf034abb2013-11-24 14:16:14 +00002749%
2750% o exception: return any errors or warnings in this structure.
2751%
2752*/
2753
dirk832becc2014-08-04 19:44:34 +00002754static MagickBooleanType resizeHorizontalFilter(cl_mem image,
2755 const unsigned int imageColumns,const unsigned int imageRows,
2756 const unsigned int matte,cl_mem resizedImage,
2757 const unsigned int resizedColumns,const unsigned int resizedRows,
2758 const ResizeFilter *resizeFilter,cl_mem resizeFilterCubicCoefficients,
2759 const float xFactor,MagickCLEnv clEnv,cl_command_queue queue,
2760 ExceptionInfo *exception)
2761{
2762 cl_kernel
2763 horizontalKernel;
2764
2765 cl_int clStatus;
2766
2767 const unsigned int
2768 workgroupSize = 256;
2769
2770 float
2771 resizeFilterScale,
2772 resizeFilterSupport,
2773 resizeFilterWindowSupport,
2774 resizeFilterBlur,
2775 scale,
2776 support;
2777
2778 int
2779 cacheRangeStart,
2780 cacheRangeEnd,
2781 numCachedPixels,
2782 resizeFilterType,
2783 resizeWindowType;
2784
2785 MagickBooleanType
2786 status = MagickFalse;
2787
2788 size_t
2789 deviceLocalMemorySize,
2790 gammaAccumulatorLocalMemorySize,
2791 global_work_size[2],
2792 imageCacheLocalMemorySize,
2793 pixelAccumulatorLocalMemorySize,
2794 local_work_size[2],
2795 totalLocalMemorySize,
2796 weightAccumulatorLocalMemorySize;
2797
2798 unsigned int
2799 chunkSize,
2800 i,
2801 pixelPerWorkgroup;
2802
2803 horizontalKernel = NULL;
dirk8a5cf512014-07-28 20:16:27 +00002804 status = MagickFalse;
cristyf034abb2013-11-24 14:16:14 +00002805
2806 /*
2807 Apply filter to resize vertically from image to resize image.
2808 */
cristye85d0f72013-11-27 02:25:43 +00002809 scale=MAGICK_MAX(1.0/xFactor+MagickEpsilon,1.0);
cristyf034abb2013-11-24 14:16:14 +00002810 support=scale*GetResizeFilterSupport(resizeFilter);
2811 if (support < 0.5)
2812 {
2813 /*
2814 Support too small even for nearest neighbour: Reduce to point
2815 sampling.
2816 */
2817 support=(MagickRealType) 0.5;
2818 scale=1.0;
2819 }
2820 scale=PerceptibleReciprocal(scale);
2821
2822 if (resizedColumns < workgroupSize)
2823 {
2824 chunkSize = 32;
2825 pixelPerWorkgroup = 32;
2826 }
2827 else
2828 {
2829 chunkSize = workgroupSize;
2830 pixelPerWorkgroup = workgroupSize;
2831 }
2832
2833 /* get the local memory size supported by the device */
2834 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
2835
dirke3c5f892013-12-10 06:04:40 +00002836DisableMSCWarning(4127)
cristyf034abb2013-11-24 14:16:14 +00002837 while(1)
dirke3c5f892013-12-10 06:04:40 +00002838RestoreMSCWarning
cristyf034abb2013-11-24 14:16:14 +00002839 {
2840 /* calculate the local memory size needed per workgroup */
2841 cacheRangeStart = (int) (((0 + 0.5)/xFactor+MagickEpsilon)-support+0.5);
2842 cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/xFactor+MagickEpsilon)+support+0.5);
2843 numCachedPixels = cacheRangeEnd - cacheRangeStart + 1;
2844 imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket);
2845 totalLocalMemorySize = imageCacheLocalMemorySize;
2846
2847 /* local size for the pixel accumulator */
2848 pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4);
2849 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
2850
2851 /* local memory size for the weight accumulator */
2852 weightAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2853 totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
2854
2855 /* local memory size for the gamma accumulator */
2856 if (matte == 0)
2857 gammaAccumulatorLocalMemorySize = sizeof(float);
2858 else
2859 gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float);
2860 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
2861
2862 if (totalLocalMemorySize <= deviceLocalMemorySize)
2863 break;
2864 else
2865 {
2866 pixelPerWorkgroup = pixelPerWorkgroup/2;
2867 chunkSize = chunkSize/2;
2868 if (pixelPerWorkgroup == 0
2869 || chunkSize == 0)
2870 {
2871 /* quit, fallback to CPU */
2872 goto cleanup;
2873 }
2874 }
2875 }
2876
2877 resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter);
2878 resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter);
2879
2880
2881 if (resizeFilterType == SincFastWeightingFunction
2882 && resizeWindowType == SincFastWeightingFunction)
2883 {
2884 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilterSinc");
2885 }
2886 else
2887 {
2888 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeHorizontalFilter");
2889 }
2890 if (horizontalKernel == NULL)
2891 {
cristya22457d2013-12-07 14:03:06 +00002892 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002893 goto cleanup;
2894 }
2895
2896 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00002897 clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&image);
2898 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&imageColumns);
2899 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&imageRows);
cristy0c832c62014-03-07 22:21:04 +00002900 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte);
2901 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&xFactor);
2902 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage);
cristyf034abb2013-11-24 14:16:14 +00002903
cristy0c832c62014-03-07 22:21:04 +00002904 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns);
2905 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows);
cristyf034abb2013-11-24 14:16:14 +00002906
cristy0c832c62014-03-07 22:21:04 +00002907 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType);
2908 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType);
2909 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients);
cristyf034abb2013-11-24 14:16:14 +00002910
2911 resizeFilterScale = (float) GetResizeFilterScale(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002912 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale);
cristyf034abb2013-11-24 14:16:14 +00002913
2914 resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002915 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport);
cristyf034abb2013-11-24 14:16:14 +00002916
2917 resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002918 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport);
cristyf034abb2013-11-24 14:16:14 +00002919
2920 resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00002921 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur);
cristyf034abb2013-11-24 14:16:14 +00002922
2923
cristy0c832c62014-03-07 22:21:04 +00002924 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL);
2925 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels);
2926 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup);
2927 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize);
cristyf034abb2013-11-24 14:16:14 +00002928
2929
cristy0c832c62014-03-07 22:21:04 +00002930 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL);
2931 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL);
2932 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL);
cristyf034abb2013-11-24 14:16:14 +00002933
2934 if (clStatus != CL_SUCCESS)
2935 {
cristy0c832c62014-03-07 22:21:04 +00002936 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002937 goto cleanup;
2938 }
2939
2940 global_work_size[0] = (resizedColumns+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize;
2941 global_work_size[1] = resizedRows;
2942
2943 local_work_size[0] = workgroupSize;
2944 local_work_size[1] = 1;
cristy0c832c62014-03-07 22:21:04 +00002945 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00002946 if (clStatus != CL_SUCCESS)
2947 {
cristy0c832c62014-03-07 22:21:04 +00002948 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00002949 goto cleanup;
2950 }
cristy0c832c62014-03-07 22:21:04 +00002951 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00002952 status = MagickTrue;
2953
2954
2955cleanup:
cristya22457d2013-12-07 14:03:06 +00002956 OpenCLLogException(__FUNCTION__,__LINE__,exception);
2957
cristyf034abb2013-11-24 14:16:14 +00002958 if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
2959
dirk832becc2014-08-04 19:44:34 +00002960 return(status);
2961}
2962
2963static MagickBooleanType resizeVerticalFilter(cl_mem image,
2964 const unsigned int imageColumns,const unsigned int imageRows,
2965 const unsigned int matte,cl_mem resizedImage,
2966 const unsigned int resizedColumns,const unsigned int resizedRows,
2967 const ResizeFilter *resizeFilter,cl_mem resizeFilterCubicCoefficients,
2968 const float yFactor,MagickCLEnv clEnv,cl_command_queue queue,
2969 ExceptionInfo *exception)
2970{
2971 cl_kernel
2972 horizontalKernel;
2973
2974 cl_int clStatus;
2975
2976 const unsigned int
2977 workgroupSize = 256;
2978
2979 float
2980 resizeFilterScale,
2981 resizeFilterSupport,
2982 resizeFilterWindowSupport,
2983 resizeFilterBlur,
2984 scale,
2985 support;
2986
2987 int
2988 cacheRangeStart,
2989 cacheRangeEnd,
2990 numCachedPixels,
2991 resizeFilterType,
2992 resizeWindowType;
2993
2994 MagickBooleanType
2995 status = MagickFalse;
2996
2997 size_t
2998 deviceLocalMemorySize,
2999 gammaAccumulatorLocalMemorySize,
3000 global_work_size[2],
3001 imageCacheLocalMemorySize,
3002 pixelAccumulatorLocalMemorySize,
3003 local_work_size[2],
3004 totalLocalMemorySize,
3005 weightAccumulatorLocalMemorySize;
3006
3007 unsigned int
3008 chunkSize,
3009 i,
3010 pixelPerWorkgroup;
3011
3012 horizontalKernel = NULL;
dirk8a5cf512014-07-28 20:16:27 +00003013 status = MagickFalse;
cristyf034abb2013-11-24 14:16:14 +00003014
3015 /*
3016 Apply filter to resize vertically from image to resize image.
3017 */
cristye85d0f72013-11-27 02:25:43 +00003018 scale=MAGICK_MAX(1.0/yFactor+MagickEpsilon,1.0);
cristyf034abb2013-11-24 14:16:14 +00003019 support=scale*GetResizeFilterSupport(resizeFilter);
3020 if (support < 0.5)
3021 {
3022 /*
3023 Support too small even for nearest neighbour: Reduce to point
3024 sampling.
3025 */
3026 support=(MagickRealType) 0.5;
3027 scale=1.0;
3028 }
3029 scale=PerceptibleReciprocal(scale);
3030
3031 if (resizedRows < workgroupSize)
3032 {
3033 chunkSize = 32;
3034 pixelPerWorkgroup = 32;
3035 }
3036 else
3037 {
3038 chunkSize = workgroupSize;
3039 pixelPerWorkgroup = workgroupSize;
3040 }
3041
3042 /* get the local memory size supported by the device */
3043 deviceLocalMemorySize = GetOpenCLDeviceLocalMemorySize(clEnv);
3044
dirke3c5f892013-12-10 06:04:40 +00003045DisableMSCWarning(4127)
cristyf034abb2013-11-24 14:16:14 +00003046 while(1)
dirke3c5f892013-12-10 06:04:40 +00003047RestoreMSCWarning
cristyf034abb2013-11-24 14:16:14 +00003048 {
3049 /* calculate the local memory size needed per workgroup */
3050 cacheRangeStart = (int) (((0 + 0.5)/yFactor+MagickEpsilon)-support+0.5);
3051 cacheRangeEnd = (int) ((((pixelPerWorkgroup-1) + 0.5)/yFactor+MagickEpsilon)+support+0.5);
3052 numCachedPixels = cacheRangeEnd - cacheRangeStart + 1;
3053 imageCacheLocalMemorySize = numCachedPixels * sizeof(CLPixelPacket);
3054 totalLocalMemorySize = imageCacheLocalMemorySize;
3055
3056 /* local size for the pixel accumulator */
3057 pixelAccumulatorLocalMemorySize = chunkSize * sizeof(cl_float4);
3058 totalLocalMemorySize+=pixelAccumulatorLocalMemorySize;
3059
3060 /* local memory size for the weight accumulator */
3061 weightAccumulatorLocalMemorySize = chunkSize * sizeof(float);
3062 totalLocalMemorySize+=weightAccumulatorLocalMemorySize;
3063
3064 /* local memory size for the gamma accumulator */
3065 if (matte == 0)
3066 gammaAccumulatorLocalMemorySize = sizeof(float);
3067 else
3068 gammaAccumulatorLocalMemorySize = chunkSize * sizeof(float);
3069 totalLocalMemorySize+=gammaAccumulatorLocalMemorySize;
3070
3071 if (totalLocalMemorySize <= deviceLocalMemorySize)
3072 break;
3073 else
3074 {
3075 pixelPerWorkgroup = pixelPerWorkgroup/2;
3076 chunkSize = chunkSize/2;
3077 if (pixelPerWorkgroup == 0
3078 || chunkSize == 0)
3079 {
3080 /* quit, fallback to CPU */
3081 goto cleanup;
3082 }
3083 }
3084 }
3085
3086 resizeFilterType = (int)GetResizeFilterWeightingType(resizeFilter);
3087 resizeWindowType = (int)GetResizeFilterWindowWeightingType(resizeFilter);
3088
3089 if (resizeFilterType == SincFastWeightingFunction
3090 && resizeWindowType == SincFastWeightingFunction)
3091 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilterSinc");
3092 else
3093 horizontalKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "ResizeVerticalFilter");
3094
3095 if (horizontalKernel == NULL)
3096 {
cristya22457d2013-12-07 14:03:06 +00003097 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003098 goto cleanup;
3099 }
3100
3101 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00003102 clStatus = clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&image);
3103 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&imageColumns);
3104 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&imageRows);
cristy0c832c62014-03-07 22:21:04 +00003105 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&matte);
3106 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&yFactor);
3107 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizedImage);
cristyf034abb2013-11-24 14:16:14 +00003108
cristy0c832c62014-03-07 22:21:04 +00003109 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedColumns);
3110 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), (void*)&resizedRows);
cristyf034abb2013-11-24 14:16:14 +00003111
cristy0c832c62014-03-07 22:21:04 +00003112 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeFilterType);
3113 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), (void*)&resizeWindowType);
3114 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(cl_mem), (void*)&resizeFilterCubicCoefficients);
cristyf034abb2013-11-24 14:16:14 +00003115
3116 resizeFilterScale = (float) GetResizeFilterScale(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00003117 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterScale);
cristyf034abb2013-11-24 14:16:14 +00003118
3119 resizeFilterSupport = (float) GetResizeFilterSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00003120 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterSupport);
cristyf034abb2013-11-24 14:16:14 +00003121
3122 resizeFilterWindowSupport = (float) GetResizeFilterWindowSupport(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00003123 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterWindowSupport);
cristyf034abb2013-11-24 14:16:14 +00003124
3125 resizeFilterBlur = (float) GetResizeFilterBlur(resizeFilter);
cristy0c832c62014-03-07 22:21:04 +00003126 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(float), (void*)&resizeFilterBlur);
cristyf034abb2013-11-24 14:16:14 +00003127
3128
cristy0c832c62014-03-07 22:21:04 +00003129 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, imageCacheLocalMemorySize, NULL);
3130 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(int), &numCachedPixels);
3131 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &pixelPerWorkgroup);
3132 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, sizeof(unsigned int), &chunkSize);
cristyf034abb2013-11-24 14:16:14 +00003133
3134
cristy0c832c62014-03-07 22:21:04 +00003135 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, pixelAccumulatorLocalMemorySize, NULL);
3136 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, weightAccumulatorLocalMemorySize, NULL);
3137 clStatus |= clEnv->library->clSetKernelArg(horizontalKernel, i++, gammaAccumulatorLocalMemorySize, NULL);
cristyf034abb2013-11-24 14:16:14 +00003138
3139 if (clStatus != CL_SUCCESS)
3140 {
cristy0c832c62014-03-07 22:21:04 +00003141 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003142 goto cleanup;
3143 }
3144
3145 global_work_size[0] = resizedColumns;
3146 global_work_size[1] = (resizedRows+pixelPerWorkgroup-1)/pixelPerWorkgroup*workgroupSize;
3147
3148 local_work_size[0] = 1;
3149 local_work_size[1] = workgroupSize;
cristy0c832c62014-03-07 22:21:04 +00003150 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, horizontalKernel, 2, NULL, global_work_size, local_work_size, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003151 if (clStatus != CL_SUCCESS)
3152 {
cristy0c832c62014-03-07 22:21:04 +00003153 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003154 goto cleanup;
3155 }
cristy0c832c62014-03-07 22:21:04 +00003156 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00003157 status = MagickTrue;
3158
3159
3160cleanup:
cristya22457d2013-12-07 14:03:06 +00003161 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3162
cristyf034abb2013-11-24 14:16:14 +00003163 if (horizontalKernel != NULL) RelinquishOpenCLKernel(clEnv, horizontalKernel);
3164
dirk8a5cf512014-07-28 20:16:27 +00003165 return(status);
cristyf034abb2013-11-24 14:16:14 +00003166}
3167
dirk832becc2014-08-04 19:44:34 +00003168static Image *ComputeResizeImage(const Image* image,
3169 const size_t resizedColumns,const size_t resizedRows,
3170 const ResizeFilter *resizeFilter,ExceptionInfo *exception)
3171{
3172 CacheView
3173 *filteredImage_view,
3174 *image_view;
3175
3176 cl_command_queue
3177 queue;
3178
3179 cl_int
3180 clStatus;
3181
3182 cl_context
3183 context;
3184
3185 cl_mem
3186 cubicCoefficientsBuffer,
3187 filteredImageBuffer,
3188 imageBuffer,
3189 tempImageBuffer;
3190
3191 cl_mem_flags
3192 mem_flags;
3193
3194 const double
3195 *resizeFilterCoefficient;
3196
3197 const void
3198 *inputPixels;
3199
3200 float
3201 *mappedCoefficientBuffer,
3202 xFactor,
3203 yFactor;
3204
3205 MagickBooleanType
3206 outputReady,
3207 status;
3208
3209 MagickCLEnv
3210 clEnv;
3211
3212 MagickSizeType
3213 length;
3214
3215 Image
3216 *filteredImage;
3217
3218 unsigned int
3219 i;
3220
3221 void
3222 *filteredPixels,
3223 *hostPtr;
3224
3225 outputReady = MagickFalse;
3226 filteredImage = NULL;
3227 filteredImage_view = NULL;
3228 clEnv = NULL;
3229 context = NULL;
3230 imageBuffer = NULL;
3231 tempImageBuffer = NULL;
3232 filteredImageBuffer = NULL;
3233 cubicCoefficientsBuffer = NULL;
3234 queue = NULL;
3235
3236 clEnv = GetDefaultOpenCLEnv();
3237 context = GetOpenCLContext(clEnv);
3238
3239 /* Create and initialize OpenCL buffers. */
3240 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00003241 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00003242 if (inputPixels == (const void *) NULL)
3243 {
dirk8a5cf512014-07-28 20:16:27 +00003244 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00003245 goto cleanup;
3246 }
3247
3248 /* If the host pointer is aligned to the size of CLPixelPacket,
3249 then use the host buffer directly from the GPU; otherwise,
3250 create a buffer on the GPU and copy the data over */
3251 if (ALIGNED(inputPixels,CLPixelPacket))
3252 {
3253 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
3254 }
3255 else
3256 {
3257 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
3258 }
3259 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00003260 length = image->columns * image->rows;
3261 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003262 if (clStatus != CL_SUCCESS)
3263 {
cristy0c832c62014-03-07 22:21:04 +00003264 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003265 goto cleanup;
3266 }
3267
cristy0c832c62014-03-07 22:21:04 +00003268 cubicCoefficientsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY, 7 * sizeof(float), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003269 if (clStatus != CL_SUCCESS)
3270 {
cristy0c832c62014-03-07 22:21:04 +00003271 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003272 goto cleanup;
3273 }
3274 queue = AcquireOpenCLCommandQueue(clEnv);
cristy0c832c62014-03-07 22:21:04 +00003275 mappedCoefficientBuffer = (float*)clEnv->library->clEnqueueMapBuffer(queue, cubicCoefficientsBuffer, CL_TRUE, CL_MAP_WRITE, 0, 7 * sizeof(float)
cristyf034abb2013-11-24 14:16:14 +00003276 , 0, NULL, NULL, &clStatus);
3277 if (clStatus != CL_SUCCESS)
3278 {
cristy0c832c62014-03-07 22:21:04 +00003279 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003280 goto cleanup;
3281 }
3282 resizeFilterCoefficient = GetResizeFilterCoefficient(resizeFilter);
3283 for (i = 0; i < 7; i++)
3284 {
3285 mappedCoefficientBuffer[i] = (float) resizeFilterCoefficient[i];
3286 }
cristy0c832c62014-03-07 22:21:04 +00003287 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, cubicCoefficientsBuffer, mappedCoefficientBuffer, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003288 if (clStatus != CL_SUCCESS)
3289 {
cristy0c832c62014-03-07 22:21:04 +00003290 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003291 goto cleanup;
3292 }
3293
dirk8a5cf512014-07-28 20:16:27 +00003294 filteredImage = CloneImage(image,resizedColumns,resizedRows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +00003295 if (filteredImage == NULL)
3296 goto cleanup;
3297
dirk8a5cf512014-07-28 20:16:27 +00003298 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00003299 {
cristya22457d2013-12-07 14:03:06 +00003300 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003301 goto cleanup;
3302 }
dirk832becc2014-08-04 19:44:34 +00003303 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00003304 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00003305 if (filteredPixels == (void *) NULL)
3306 {
cristya22457d2013-12-07 14:03:06 +00003307 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00003308 goto cleanup;
3309 }
3310
3311 if (ALIGNED(filteredPixels,CLPixelPacket))
3312 {
3313 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
3314 hostPtr = filteredPixels;
3315 }
3316 else
3317 {
3318 mem_flags = CL_MEM_WRITE_ONLY;
3319 hostPtr = NULL;
3320 }
3321
3322 /* create a CL buffer from image pixel buffer */
3323 length = filteredImage->columns * filteredImage->rows;
cristy0c832c62014-03-07 22:21:04 +00003324 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003325 if (clStatus != CL_SUCCESS)
3326 {
cristy0c832c62014-03-07 22:21:04 +00003327 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003328 goto cleanup;
3329 }
3330
dirk8a5cf512014-07-28 20:16:27 +00003331 xFactor=(float) resizedColumns/(float) image->columns;
3332 yFactor=(float) resizedRows/(float) image->rows;
cristyf034abb2013-11-24 14:16:14 +00003333 if (xFactor > yFactor)
3334 {
3335
dirk8a5cf512014-07-28 20:16:27 +00003336 length = resizedColumns*image->rows;
cristy0c832c62014-03-07 22:21:04 +00003337 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003338 if (clStatus != CL_SUCCESS)
3339 {
cristy0c832c62014-03-07 22:21:04 +00003340 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003341 goto cleanup;
3342 }
3343
dirk8a5cf512014-07-28 20:16:27 +00003344 status = resizeHorizontalFilter(imageBuffer, image->columns, image->rows, (image->alpha_trait==BlendPixelTrait)?1:0
3345 , tempImageBuffer, resizedColumns, image->rows
cristyf034abb2013-11-24 14:16:14 +00003346 , resizeFilter, cubicCoefficientsBuffer
3347 , xFactor, clEnv, queue, exception);
3348 if (status != MagickTrue)
3349 goto cleanup;
3350
dirk8a5cf512014-07-28 20:16:27 +00003351 status = resizeVerticalFilter(tempImageBuffer, resizedColumns, image->rows, (image->alpha_trait==BlendPixelTrait)?1:0
cristyf034abb2013-11-24 14:16:14 +00003352 , filteredImageBuffer, resizedColumns, resizedRows
3353 , resizeFilter, cubicCoefficientsBuffer
3354 , yFactor, clEnv, queue, exception);
3355 if (status != MagickTrue)
3356 goto cleanup;
3357 }
3358 else
3359 {
dirk8a5cf512014-07-28 20:16:27 +00003360 length = image->columns*resizedRows;
cristy0c832c62014-03-07 22:21:04 +00003361 tempImageBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, length*sizeof(CLPixelPacket), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003362 if (clStatus != CL_SUCCESS)
3363 {
cristy0c832c62014-03-07 22:21:04 +00003364 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003365 goto cleanup;
3366 }
3367
dirk8a5cf512014-07-28 20:16:27 +00003368 status = resizeVerticalFilter(imageBuffer, image->columns, image->rows, (image->alpha_trait==BlendPixelTrait)?1:0
3369 , tempImageBuffer, image->columns, resizedRows
cristyf034abb2013-11-24 14:16:14 +00003370 , resizeFilter, cubicCoefficientsBuffer
3371 , yFactor, clEnv, queue, exception);
3372 if (status != MagickTrue)
3373 goto cleanup;
3374
dirk8a5cf512014-07-28 20:16:27 +00003375 status = resizeHorizontalFilter(tempImageBuffer, image->columns, resizedRows, (image->alpha_trait==BlendPixelTrait)?1:0
cristyf034abb2013-11-24 14:16:14 +00003376 , filteredImageBuffer, resizedColumns, resizedRows
3377 , resizeFilter, cubicCoefficientsBuffer
3378 , xFactor, clEnv, queue, exception);
3379 if (status != MagickTrue)
3380 goto cleanup;
3381 }
3382 length = resizedColumns*resizedRows;
3383 if (ALIGNED(filteredPixels,CLPixelPacket))
3384 {
cristy0c832c62014-03-07 22:21:04 +00003385 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003386 }
3387 else
3388 {
cristy0c832c62014-03-07 22:21:04 +00003389 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003390 }
3391 if (clStatus != CL_SUCCESS)
3392 {
cristya22457d2013-12-07 14:03:06 +00003393 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003394 goto cleanup;
3395 }
dirk832becc2014-08-04 19:44:34 +00003396 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
3397
3398cleanup:
3399 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3400
3401 image_view=DestroyCacheView(image_view);
3402 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00003403 filteredImage_view=DestroyCacheView(filteredImage_view);
cristyf034abb2013-11-24 14:16:14 +00003404
dirk8a5cf512014-07-28 20:16:27 +00003405 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00003406 if (tempImageBuffer!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer);
3407 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
3408 if (cubicCoefficientsBuffer!=NULL) clEnv->library->clReleaseMemObject(cubicCoefficientsBuffer);
cristyf034abb2013-11-24 14:16:14 +00003409 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
dirk8a5cf512014-07-28 20:16:27 +00003410 if (outputReady == MagickFalse && filteredImage != NULL)
3411 filteredImage=DestroyImage(filteredImage);
3412 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00003413}
3414
dirk832becc2014-08-04 19:44:34 +00003415const ResizeWeightingFunctionType supportedResizeWeighting[] =
3416{
3417 BoxWeightingFunction,
3418 TriangleWeightingFunction,
3419 HanningWeightingFunction,
3420 HammingWeightingFunction,
3421 BlackmanWeightingFunction,
3422 CubicBCWeightingFunction,
3423 SincWeightingFunction,
3424 SincFastWeightingFunction,
3425 LastWeightingFunction
cristyf034abb2013-11-24 14:16:14 +00003426};
3427
dirk832becc2014-08-04 19:44:34 +00003428static MagickBooleanType gpuSupportedResizeWeighting(
3429 ResizeWeightingFunctionType f)
3430{
3431 unsigned int
3432 i;
3433
3434 for (i = 0; ;i++)
3435 {
3436 if (supportedResizeWeighting[i] == LastWeightingFunction)
3437 break;
3438 if (supportedResizeWeighting[i] == f)
3439 return(MagickTrue);
3440 }
3441 return(MagickFalse);
3442}
3443
3444MagickExport Image *AccelerateResizeImage(const Image *image,
3445 const size_t resizedColumns,const size_t resizedRows,
3446 const ResizeFilter *resizeFilter,ExceptionInfo *exception)
3447{
3448 Image
3449 *filteredImage;
3450
3451 assert(image != NULL);
3452 assert(exception != (ExceptionInfo *) NULL);
3453
3454 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
3455 (checkAccelerateCondition(image, AllChannels) == MagickFalse))
3456 return NULL;
3457
3458 if (gpuSupportedResizeWeighting(GetResizeFilterWeightingType(resizeFilter)) == MagickFalse ||
3459 gpuSupportedResizeWeighting(GetResizeFilterWindowWeightingType(resizeFilter)) == MagickFalse)
3460 return NULL;
3461
3462 filteredImage=ComputeResizeImage(image,resizedColumns,resizedRows,resizeFilter,exception);
3463 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00003464}
3465
3466/*
3467%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3468% %
3469% %
3470% %
3471% C o n t r a s t I m a g e w i t h O p e n C L %
3472% %
3473% %
3474% %
3475%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3476%
3477% ContrastImage() enhances the intensity differences between the lighter and
3478% darker elements of the image. Set sharpen to a MagickTrue to increase the
3479% image contrast otherwise the contrast is reduced.
3480%
3481% The format of the ContrastImage method is:
3482%
3483% MagickBooleanType ContrastImage(Image *image,
3484% const MagickBooleanType sharpen)
3485%
3486% A description of each parameter follows:
3487%
3488% o image: the image.
3489%
3490% o sharpen: Increase or decrease image contrast.
3491%
3492*/
3493
dirk832becc2014-08-04 19:44:34 +00003494static MagickBooleanType ComputeContrastImage(Image *image,
3495 const MagickBooleanType sharpen,ExceptionInfo *exception)
3496{
3497 CacheView
3498 *image_view;
3499
3500 cl_command_queue
3501 queue;
3502
3503 cl_context
3504 context;
3505
3506 cl_int
3507 clStatus;
3508
3509 cl_kernel
3510 filterKernel;
3511
3512 cl_mem
3513 imageBuffer;
3514
3515 cl_mem_flags
3516 mem_flags;
3517
3518 MagickBooleanType
3519 outputReady;
3520
3521 MagickCLEnv
3522 clEnv;
3523
3524 MagickSizeType
3525 length;
3526
3527 size_t
3528 global_work_size[2];
3529
3530 unsigned int
3531 i,
3532 uSharpen;
3533
3534 void
3535 *inputPixels;
3536
3537 outputReady = MagickFalse;
3538 clEnv = NULL;
3539 inputPixels = NULL;
3540 context = NULL;
3541 imageBuffer = NULL;
3542 filterKernel = NULL;
3543 queue = NULL;
3544
3545 clEnv = GetDefaultOpenCLEnv();
3546 context = GetOpenCLContext(clEnv);
3547
3548 /* Create and initialize OpenCL buffers. */
3549 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00003550 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00003551 if (inputPixels == (void *) NULL)
cristyd43a46b2010-01-21 02:13:41 +00003552 {
dirk8a5cf512014-07-28 20:16:27 +00003553 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00003554 goto cleanup;
cristyd43a46b2010-01-21 02:13:41 +00003555 }
cristyf034abb2013-11-24 14:16:14 +00003556
3557 /* If the host pointer is aligned to the size of CLPixelPacket,
dirk8a5cf512014-07-28 20:16:27 +00003558 then use the host buffer directly from the GPU; otherwise,
3559 create a buffer on the GPU and copy the data over */
cristyf034abb2013-11-24 14:16:14 +00003560 if (ALIGNED(inputPixels,CLPixelPacket))
3561 {
3562 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3563 }
3564 else
3565 {
3566 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3567 }
3568 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00003569 length = image->columns * image->rows;
3570 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003571 if (clStatus != CL_SUCCESS)
3572 {
cristy0c832c62014-03-07 22:21:04 +00003573 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00003574 goto cleanup;
3575 }
dirk8a5cf512014-07-28 20:16:27 +00003576
3577 filterKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Contrast");
3578 if (filterKernel == NULL)
cristyf034abb2013-11-24 14:16:14 +00003579 {
cristya22457d2013-12-07 14:03:06 +00003580 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003581 goto cleanup;
3582 }
3583
cristyf034abb2013-11-24 14:16:14 +00003584 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00003585 clStatus=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
3586
3587 uSharpen = (sharpen == MagickFalse)?0:1;
3588 clStatus|=clEnv->library->clSetKernelArg(filterKernel,i++,sizeof(cl_uint),&uSharpen);
cristyf034abb2013-11-24 14:16:14 +00003589 if (clStatus != CL_SUCCESS)
3590 {
cristy0c832c62014-03-07 22:21:04 +00003591 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003592 goto cleanup;
3593 }
3594
dirk8a5cf512014-07-28 20:16:27 +00003595 global_work_size[0] = image->columns;
3596 global_work_size[1] = image->rows;
3597 /* launch the kernel */
3598 queue = AcquireOpenCLCommandQueue(clEnv);
3599 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, filterKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
3600 if (clStatus != CL_SUCCESS)
cristyf034abb2013-11-24 14:16:14 +00003601 {
dirk8a5cf512014-07-28 20:16:27 +00003602 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3603 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00003604 }
dirk8a5cf512014-07-28 20:16:27 +00003605 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00003606
3607 if (ALIGNED(inputPixels,CLPixelPacket))
3608 {
dirk8a5cf512014-07-28 20:16:27 +00003609 length = image->columns * image->rows;
3610 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00003611 }
3612 else
3613 {
dirk8a5cf512014-07-28 20:16:27 +00003614 length = image->columns * image->rows;
3615 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00003616 }
3617 if (clStatus != CL_SUCCESS)
3618 {
cristya22457d2013-12-07 14:03:06 +00003619 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00003620 goto cleanup;
3621 }
dirk832becc2014-08-04 19:44:34 +00003622 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
3623
3624cleanup:
3625 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3626
dirk8a5cf512014-07-28 20:16:27 +00003627 image_view=DestroyCacheView(image_view);
cristyf034abb2013-11-24 14:16:14 +00003628
dirk8a5cf512014-07-28 20:16:27 +00003629 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
3630 if (filterKernel!=NULL) RelinquishOpenCLKernel(clEnv, filterKernel);
3631 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
3632 return(outputReady);
dirk832becc2014-08-04 19:44:34 +00003633}
3634
3635MagickExport MagickBooleanType AccelerateContrastImage(Image *image,
3636 const MagickBooleanType sharpen,ExceptionInfo *exception)
3637{
3638 MagickBooleanType
3639 status;
3640
3641 assert(image != NULL);
3642 assert(exception != (ExceptionInfo *) NULL);
3643
3644 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
3645 (checkAccelerateCondition(image, AllChannels) == MagickFalse))
3646 return(MagickFalse);
3647
3648 status = ComputeContrastImage(image,sharpen,exception);
3649 return(status);
cristy3f6d1482010-01-20 21:01:21 +00003650}
cristyf034abb2013-11-24 14:16:14 +00003651
3652/*
3653%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3654% %
3655% %
3656% %
3657% M o d u l a t e I m a g e w i t h O p e n C L %
3658% %
3659% %
3660% %
3661%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3662%
3663% ModulateImage() lets you control the brightness, saturation, and hue
3664% of an image. Modulate represents the brightness, saturation, and hue
3665% as one parameter (e.g. 90,150,100). If the image colorspace is HSL, the
3666% modulation is lightness, saturation, and hue. For HWB, use blackness,
3667% whiteness, and hue. And for HCL, use chrome, luma, and hue.
3668%
3669% The format of the ModulateImage method is:
3670%
3671% MagickBooleanType ModulateImage(Image *image,const char *modulate)
3672%
3673% A description of each parameter follows:
3674%
3675% o image: the image.
3676%
3677% o percent_*: Define the percent change in brightness, saturation, and
3678% hue.
3679%
3680*/
3681
dirk832becc2014-08-04 19:44:34 +00003682MagickBooleanType ComputeModulateImage(Image *image,
3683 double percent_brightness,double percent_hue,double percent_saturation,
3684 ColorspaceType colorspace,ExceptionInfo *exception)
3685{
3686 CacheView
3687 *image_view;
3688
3689 cl_float
3690 bright,
3691 hue,
3692 saturation;
3693
3694 cl_context
3695 context;
3696
3697 cl_command_queue
3698 queue;
3699
3700 cl_int
3701 color,
3702 clStatus;
3703
3704 cl_kernel
3705 modulateKernel;
3706
3707 cl_mem
3708 imageBuffer;
3709
3710 cl_mem_flags
3711 mem_flags;
3712
3713 MagickBooleanType
3714 outputReady;
3715
3716 MagickCLEnv
3717 clEnv;
3718
3719 MagickSizeType
3720 length;
3721
3722 register ssize_t
3723 i;
3724
3725 void
3726 *inputPixels;
3727
3728 inputPixels = NULL;
3729 imageBuffer = NULL;
3730 modulateKernel = NULL;
3731
3732 assert(image != (Image *) NULL);
3733 assert(image->signature == MagickSignature);
3734 if (image->debug != MagickFalse)
3735 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3736
3737 /*
3738 * initialize opencl env
3739 */
3740 clEnv = GetDefaultOpenCLEnv();
3741 context = GetOpenCLContext(clEnv);
3742 queue = AcquireOpenCLCommandQueue(clEnv);
3743
3744 outputReady = MagickFalse;
3745
3746 /* Create and initialize OpenCL buffers.
3747 inputPixels = AcquirePixelCachePixels(image, &length, exception);
3748 assume this will get a writable image
3749 */
3750 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00003751 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00003752 if (inputPixels == (void *) NULL)
3753 {
dirk8a5cf512014-07-28 20:16:27 +00003754 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristy0c832c62014-03-07 22:21:04 +00003755 goto cleanup;
3756 }
3757
3758 /* If the host pointer is aligned to the size of CLPixelPacket,
3759 then use the host buffer directly from the GPU; otherwise,
3760 create a buffer on the GPU and copy the data over
3761 */
3762 if (ALIGNED(inputPixels,CLPixelPacket))
3763 {
3764 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3765 }
3766 else
3767 {
3768 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3769 }
3770 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00003771 length = image->columns * image->rows;
3772 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00003773 if (clStatus != CL_SUCCESS)
3774 {
3775 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3776 goto cleanup;
3777 }
3778
dirk8a5cf512014-07-28 20:16:27 +00003779 modulateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Modulate");
3780 if (modulateKernel == NULL)
cristy0c832c62014-03-07 22:21:04 +00003781 {
3782 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3783 goto cleanup;
3784 }
3785
dirk8a5cf512014-07-28 20:16:27 +00003786 bright=percent_brightness;
3787 hue=percent_hue;
3788 saturation=percent_saturation;
3789 color=colorspace;
3790
cristy0c832c62014-03-07 22:21:04 +00003791 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00003792 clStatus=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
3793 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&bright);
3794 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&hue);
3795 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&saturation);
3796 clStatus|=clEnv->library->clSetKernelArg(modulateKernel,i++,sizeof(cl_float),&color);
cristy0c832c62014-03-07 22:21:04 +00003797 if (clStatus != CL_SUCCESS)
3798 {
3799 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
3800 printf("no kernel\n");
3801 goto cleanup;
3802 }
3803
3804 {
3805 size_t global_work_size[2];
dirk8a5cf512014-07-28 20:16:27 +00003806 global_work_size[0] = image->columns;
3807 global_work_size[1] = image->rows;
cristy0c832c62014-03-07 22:21:04 +00003808 /* launch the kernel */
dirk8a5cf512014-07-28 20:16:27 +00003809 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, modulateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristy0c832c62014-03-07 22:21:04 +00003810 if (clStatus != CL_SUCCESS)
3811 {
3812 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
3813 goto cleanup;
3814 }
3815 clEnv->library->clFlush(queue);
3816 }
3817
3818 if (ALIGNED(inputPixels,CLPixelPacket))
3819 {
dirk8a5cf512014-07-28 20:16:27 +00003820 length = image->columns * image->rows;
3821 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00003822 }
3823 else
3824 {
dirk8a5cf512014-07-28 20:16:27 +00003825 length = image->columns * image->rows;
3826 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristy0c832c62014-03-07 22:21:04 +00003827 }
3828 if (clStatus != CL_SUCCESS)
3829 {
3830 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
3831 goto cleanup;
3832 }
3833
dirk832becc2014-08-04 19:44:34 +00003834 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
3835
3836cleanup:
3837 OpenCLLogException(__FUNCTION__,__LINE__,exception);
3838
dirk8a5cf512014-07-28 20:16:27 +00003839 image_view=DestroyCacheView(image_view);
cristy0c832c62014-03-07 22:21:04 +00003840
dirk8a5cf512014-07-28 20:16:27 +00003841 if (imageBuffer!=NULL)
3842 clEnv->library->clReleaseMemObject(imageBuffer);
3843 if (modulateKernel!=NULL)
3844 RelinquishOpenCLKernel(clEnv, modulateKernel);
cristy0c832c62014-03-07 22:21:04 +00003845 if (queue != NULL)
3846 RelinquishOpenCLCommandQueue(clEnv, queue);
3847
3848 return outputReady;
3849
3850}
3851
dirk832becc2014-08-04 19:44:34 +00003852MagickExport MagickBooleanType AccelerateModulateImage(Image *image,
3853 double percent_brightness,double percent_hue,double percent_saturation,
3854 ColorspaceType colorspace,ExceptionInfo *exception)
3855{
3856 MagickBooleanType
3857 status;
3858
3859 assert(image != NULL);
3860 assert(exception != (ExceptionInfo *) NULL);
3861
3862 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
3863 (checkAccelerateCondition(image, AllChannels) == MagickFalse))
3864 return(MagickFalse);
3865
3866 if ((colorspace != HSLColorspace && colorspace != UndefinedColorspace))
3867 return(MagickFalse);
3868
3869 status = ComputeModulateImage(image,percent_brightness, percent_hue, percent_saturation, colorspace, exception);
3870 return(status);
dirk8a5cf512014-07-28 20:16:27 +00003871}
cristy0c832c62014-03-07 22:21:04 +00003872
3873/*
3874%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3875% %
3876% %
3877% %
3878% N e g a t e I m a g e w i t h O p e n C L %
3879% %
3880% %
3881% %
3882%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3883%
3884%
3885% A description of each parameter follows:
3886%
3887% o image: the image.
3888%
3889% o channel: the channel.
3890%
3891% o grayscale: If MagickTrue, only negate grayscale pixels within the image.
3892%
3893*/
3894
dirk832becc2014-08-04 19:44:34 +00003895MagickBooleanType ComputeNegateImageChannel(Image *image,
3896 const ChannelType channel,const MagickBooleanType magick_unused(grayscale),
3897 ExceptionInfo* exception)
3898{
3899 CacheView
3900 *image_view;
3901
3902 cl_context
3903 context;
3904
3905 cl_command_queue
3906 queue;
3907
3908 cl_int
3909 clStatus;
3910
3911 cl_kernel
3912 negateKernel;
3913
3914 cl_mem
3915 imageBuffer;
3916
3917 cl_mem_flags
3918 mem_flags;
3919
3920 MagickBooleanType
3921 outputReady;
3922
3923 MagickCLEnv
3924 clEnv;
3925
3926 MagickSizeType
3927 length;
3928
3929 register ssize_t
3930 i;
3931
3932 void
3933 *inputPixels;
3934
3935 magick_unreferenced(grayscale);
3936
3937 inputPixels = NULL;
3938 imageBuffer = NULL;
3939 negateKernel = NULL;
3940
3941 assert(image != (Image *) NULL);
3942 assert(image->signature == MagickSignature);
3943 if (image->debug != MagickFalse)
3944 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3945
3946 /*
3947 * initialize opencl env
3948 */
3949 clEnv = GetDefaultOpenCLEnv();
3950 context = GetOpenCLContext(clEnv);
3951 queue = AcquireOpenCLCommandQueue(clEnv);
3952
3953 outputReady = MagickFalse;
3954
3955 /* Create and initialize OpenCL buffers.
3956 inputPixels = AcquirePixelCachePixels(image, &length, exception);
3957 assume this will get a writable image
3958 */
3959 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00003960 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00003961 if (inputPixels == (void *) NULL)
3962 {
dirk8a5cf512014-07-28 20:16:27 +00003963 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristy0c832c62014-03-07 22:21:04 +00003964 goto cleanup;
3965 }
3966
3967 /* If the host pointer is aligned to the size of CLPixelPacket,
3968 then use the host buffer directly from the GPU; otherwise,
3969 create a buffer on the GPU and copy the data over
3970 */
3971 if (ALIGNED(inputPixels,CLPixelPacket))
3972 {
3973 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
3974 }
3975 else
3976 {
3977 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
3978 }
3979 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00003980 length = image->columns * image->rows;
3981 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00003982 if (clStatus != CL_SUCCESS)
3983 {
3984 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
3985 goto cleanup;
3986 }
3987
dirk8a5cf512014-07-28 20:16:27 +00003988 negateKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Negate");
3989 if (negateKernel == NULL)
cristy0c832c62014-03-07 22:21:04 +00003990 {
3991 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
3992 goto cleanup;
3993 }
3994
3995 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00003996 clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
3997 clStatus=clEnv->library->clSetKernelArg(negateKernel,i++,sizeof(ChannelType),(void *)&channel);
cristy0c832c62014-03-07 22:21:04 +00003998 if (clStatus != CL_SUCCESS)
3999 {
4000 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
4001 printf("no kernel\n");
4002 goto cleanup;
4003 }
4004
4005 {
4006 size_t global_work_size[2];
dirk8a5cf512014-07-28 20:16:27 +00004007 global_work_size[0] = image->columns;
4008 global_work_size[1] = image->rows;
cristy0c832c62014-03-07 22:21:04 +00004009 /* launch the kernel */
dirk8a5cf512014-07-28 20:16:27 +00004010 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, negateKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristy0c832c62014-03-07 22:21:04 +00004011 if (clStatus != CL_SUCCESS)
4012 {
4013 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
4014 goto cleanup;
4015 }
4016 clEnv->library->clFlush(queue);
4017 }
4018
4019 if (ALIGNED(inputPixels,CLPixelPacket))
4020 {
dirk8a5cf512014-07-28 20:16:27 +00004021 length = image->columns * image->rows;
4022 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00004023 }
4024 else
4025 {
dirk8a5cf512014-07-28 20:16:27 +00004026 length = image->columns * image->rows;
4027 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristy0c832c62014-03-07 22:21:04 +00004028 }
4029 if (clStatus != CL_SUCCESS)
4030 {
4031 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4032 goto cleanup;
4033 }
4034
dirk832becc2014-08-04 19:44:34 +00004035 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
4036
4037cleanup:
4038 OpenCLLogException(__FUNCTION__,__LINE__,exception);
4039
dirk8a5cf512014-07-28 20:16:27 +00004040 image_view=DestroyCacheView(image_view);
cristy0c832c62014-03-07 22:21:04 +00004041
dirk8a5cf512014-07-28 20:16:27 +00004042 if (imageBuffer!=NULL)
4043 clEnv->library->clReleaseMemObject(imageBuffer);
4044 if (negateKernel!=NULL)
4045 RelinquishOpenCLKernel(clEnv, negateKernel);
cristy0c832c62014-03-07 22:21:04 +00004046 if (queue != NULL)
4047 RelinquishOpenCLCommandQueue(clEnv, queue);
4048
dirk8a5cf512014-07-28 20:16:27 +00004049 return(outputReady);
dirk832becc2014-08-04 19:44:34 +00004050}
4051
4052MagickExport MagickBooleanType AccelerateNegateImageChannel(Image *image,
4053 const ChannelType channel,const MagickBooleanType grayscale,
4054 ExceptionInfo* exception)
4055{
4056 MagickBooleanType
4057 status;
4058
4059 assert(image != NULL);
4060 assert(exception != (ExceptionInfo *) NULL);
4061
4062 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
4063 (checkAccelerateCondition(image, channel) == MagickFalse))
4064 return(MagickFalse);
4065
4066 status=ComputeNegateImageChannel(image,channel,grayscale,exception);
4067 return(status);
cristy0c832c62014-03-07 22:21:04 +00004068}
dirk8a5cf512014-07-28 20:16:27 +00004069
cristy0c832c62014-03-07 22:21:04 +00004070/*
4071%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4072% %
4073% %
4074% %
4075% G r a y s c a l e I m a g e w i t h O p e n C L %
4076% %
4077% %
4078% %
4079%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4080%
4081% GrayscaleImage() converts the colors in the reference image to gray.
4082%
4083% The format of the GrayscaleImageChannel method is:
4084%
4085% MagickBooleanType GrayscaleImage(Image *image,
4086% const PixelIntensityMethod method)
4087%
4088% A description of each parameter follows:
4089%
4090% o image: the image.
4091%
4092% o channel: the channel.
4093%
4094*/
4095
dirk832becc2014-08-04 19:44:34 +00004096MagickBooleanType ComputeGrayscaleImage(Image *image,
4097 const PixelIntensityMethod method,ExceptionInfo *exception)
4098{
4099 CacheView
4100 *image_view;
4101
4102 cl_command_queue
4103 queue;
4104
4105 cl_context
4106 context;
4107
4108 cl_int
4109 clStatus,
4110 intensityMethod;
4111
4112 cl_int
4113 colorspace;
4114
4115 cl_kernel
4116 grayscaleKernel;
4117
4118 cl_mem
4119 imageBuffer;
4120
4121 cl_mem_flags
4122 mem_flags;
4123
4124 MagickBooleanType
4125 outputReady;
4126
4127 MagickCLEnv
4128 clEnv;
4129
4130 MagickSizeType
4131 length;
4132
4133 register ssize_t
4134 i;
4135
4136 void
4137 *inputPixels;
4138
4139 inputPixels = NULL;
4140 imageBuffer = NULL;
4141 grayscaleKernel = NULL;
4142
4143 assert(image != (Image *) NULL);
4144 assert(image->signature == MagickSignature);
4145 if (image->debug != MagickFalse)
4146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4147
4148 /*
4149 * initialize opencl env
4150 */
4151 clEnv = GetDefaultOpenCLEnv();
4152 context = GetOpenCLContext(clEnv);
4153 queue = AcquireOpenCLCommandQueue(clEnv);
4154
4155 outputReady = MagickFalse;
4156
4157 /* Create and initialize OpenCL buffers.
4158 inputPixels = AcquirePixelCachePixels(image, &length, exception);
4159 assume this will get a writable image
4160 */
4161 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00004162 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
4163 if (inputPixels == (void *) NULL)
4164 {
4165 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
4166 goto cleanup;
4167 }
cristy0c832c62014-03-07 22:21:04 +00004168
dirk8a5cf512014-07-28 20:16:27 +00004169 /* If the host pointer is aligned to the size of CLPixelPacket,
4170 then use the host buffer directly from the GPU; otherwise,
4171 create a buffer on the GPU and copy the data over
4172 */
4173 if (ALIGNED(inputPixels,CLPixelPacket))
4174 {
4175 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4176 }
4177 else
4178 {
4179 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4180 }
4181 /* create a CL buffer from image pixel buffer */
4182 length = image->columns * image->rows;
4183 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
4184 if (clStatus != CL_SUCCESS)
4185 {
4186 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
4187 goto cleanup;
4188 }
cristy0c832c62014-03-07 22:21:04 +00004189
dirk8a5cf512014-07-28 20:16:27 +00004190 intensityMethod = method;
4191 colorspace = image->colorspace;
cristy0c832c62014-03-07 22:21:04 +00004192
dirk8a5cf512014-07-28 20:16:27 +00004193 grayscaleKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Grayscale");
4194 if (grayscaleKernel == NULL)
4195 {
4196 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
4197 goto cleanup;
4198 }
cristy0c832c62014-03-07 22:21:04 +00004199
dirk8a5cf512014-07-28 20:16:27 +00004200 i = 0;
4201 clStatus=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
4202 clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&intensityMethod);
4203 clStatus|=clEnv->library->clSetKernelArg(grayscaleKernel,i++,sizeof(cl_int),&colorspace);
4204 if (clStatus != CL_SUCCESS)
4205 {
4206 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
4207 printf("no kernel\n");
4208 goto cleanup;
4209 }
cristy0c832c62014-03-07 22:21:04 +00004210
dirk8a5cf512014-07-28 20:16:27 +00004211 {
4212 size_t global_work_size[2];
4213 global_work_size[0] = image->columns;
4214 global_work_size[1] = image->rows;
4215 /* launch the kernel */
4216 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, grayscaleKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
4217 if (clStatus != CL_SUCCESS)
4218 {
4219 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
4220 goto cleanup;
4221 }
4222 clEnv->library->clFlush(queue);
4223 }
cristy0c832c62014-03-07 22:21:04 +00004224
dirk8a5cf512014-07-28 20:16:27 +00004225 if (ALIGNED(inputPixels,CLPixelPacket))
4226 {
4227 length = image->columns * image->rows;
4228 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
4229 }
4230 else
4231 {
4232 length = image->columns * image->rows;
4233 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
4234 }
4235 if (clStatus != CL_SUCCESS)
4236 {
4237 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
4238 goto cleanup;
4239 }
cristy0c832c62014-03-07 22:21:04 +00004240
dirk832becc2014-08-04 19:44:34 +00004241 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
4242
4243cleanup:
4244 OpenCLLogException(__FUNCTION__,__LINE__,exception);
4245
dirk8a5cf512014-07-28 20:16:27 +00004246 image_view=DestroyCacheView(image_view);
4247
4248 if (imageBuffer!=NULL)
4249 clEnv->library->clReleaseMemObject(imageBuffer);
4250 if (grayscaleKernel!=NULL)
4251 RelinquishOpenCLKernel(clEnv, grayscaleKernel);
4252 if (queue != NULL)
4253 RelinquishOpenCLCommandQueue(clEnv, queue);
4254
4255 return( outputReady);
dirk832becc2014-08-04 19:44:34 +00004256}
4257
4258MagickExport MagickBooleanType AccelerateGrayscaleImage(Image* image,
4259 const PixelIntensityMethod method,ExceptionInfo *exception)
4260{
4261 MagickBooleanType
4262 status;
4263
4264 assert(image != NULL);
4265 assert(exception != (ExceptionInfo *) NULL);
4266
4267 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
4268 (checkAccelerateCondition(image, AllChannels) == MagickFalse))
4269 return(MagickFalse);
4270
4271 if (method == Rec601LuminancePixelIntensityMethod || method == Rec709LuminancePixelIntensityMethod)
4272 return(MagickFalse);
4273
4274 if (image->colorspace != sRGBColorspace)
4275 return(MagickFalse);
4276
4277 status=ComputeGrayscaleImage(image,method,exception);
4278 return(status);
cristy0c832c62014-03-07 22:21:04 +00004279}
4280
dirk8a5cf512014-07-28 20:16:27 +00004281/*
4282%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4283% %
4284% %
4285% %
4286% E q u a l i z e I m a g e w i t h O p e n C L %
4287% %
4288% %
4289% %
4290%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4291%
4292% EqualizeImage() applies a histogram equalization to the image.
4293%
4294% The format of the EqualizeImage method is:
4295%
4296% MagickBooleanType EqualizeImage(Image *image)
4297% MagickBooleanType EqualizeImageChannel(Image *image,
4298% const ChannelType channel)
4299%
4300% A description of each parameter follows:
4301%
4302% o image: the image.
4303%
4304% o channel: the channel.
4305%
4306*/
cristy0c832c62014-03-07 22:21:04 +00004307
dirk832becc2014-08-04 19:44:34 +00004308static MagickBooleanType LaunchHistogramKernel(MagickCLEnv clEnv,
4309 cl_command_queue queue,cl_mem imageBuffer,cl_mem histogramBuffer,
4310 Image *image,const ChannelType channel,ExceptionInfo *exception)
4311{
4312 MagickBooleanType
4313 outputReady;
4314
4315 cl_int
4316 clStatus,
4317 colorspace,
4318 method;
4319
4320 cl_kernel
4321 histogramKernel;
4322
4323 register ssize_t
4324 i;
4325
4326 size_t
4327 global_work_size[2];
4328
cristy0c832c62014-03-07 22:21:04 +00004329 histogramKernel = NULL;
4330
4331 outputReady = MagickFalse;
dirk8a5cf512014-07-28 20:16:27 +00004332 method = image->intensity;
4333 colorspace = image->colorspace;
cristy0c832c62014-03-07 22:21:04 +00004334
4335 /* get the OpenCL kernel */
4336 histogramKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Histogram");
4337 if (histogramKernel == NULL)
4338 {
4339 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
4340 goto cleanup;
4341 }
4342
4343 /* set the kernel arguments */
4344 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00004345 clStatus=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00004346 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(ChannelType),&channel);
4347 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&method);
4348 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_int),&colorspace);
4349 clStatus|=clEnv->library->clSetKernelArg(histogramKernel,i++,sizeof(cl_mem),(void *)&histogramBuffer);
4350 if (clStatus != CL_SUCCESS)
4351 {
4352 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
4353 goto cleanup;
4354 }
4355
4356 /* launch the kernel */
dirk8a5cf512014-07-28 20:16:27 +00004357 global_work_size[0] = image->columns;
4358 global_work_size[1] = image->rows;
cristy0c832c62014-03-07 22:21:04 +00004359
4360 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, histogramKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
4361
4362 if (clStatus != CL_SUCCESS)
4363 {
4364 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
4365 goto cleanup;
4366 }
4367 clEnv->library->clFlush(queue);
4368
4369 outputReady = MagickTrue;
4370
4371cleanup:
4372 OpenCLLogException(__FUNCTION__,__LINE__,exception);
4373
4374 if (histogramKernel!=NULL)
4375 RelinquishOpenCLKernel(clEnv, histogramKernel);
4376
dirk8a5cf512014-07-28 20:16:27 +00004377 return(outputReady);
cristy0c832c62014-03-07 22:21:04 +00004378}
4379
dirk832becc2014-08-04 19:44:34 +00004380MagickExport MagickBooleanType ComputeEqualizeImage(Image *image,
4381 const ChannelType channel,ExceptionInfo *exception)
4382{
4383#define EqualizeImageTag "Equalize/Image"
4384
4385 CacheView
4386 *image_view;
4387
4388 cl_command_queue
4389 queue;
4390
4391 cl_context
4392 context;
4393
4394 cl_int
4395 clStatus;
4396
4397 cl_mem_flags
4398 mem_flags;
4399
4400 cl_mem
4401 equalizeMapBuffer,
4402 histogramBuffer,
4403 imageBuffer;
4404
4405 cl_kernel
4406 equalizeKernel,
4407 histogramKernel;
4408
4409 cl_uint4
4410 *histogram;
4411
4412 FloatPixelPacket
4413 white,
4414 black,
4415 intensity,
4416 *map;
4417
4418 MagickBooleanType
4419 outputReady,
4420 status;
4421
4422 MagickCLEnv
4423 clEnv;
4424
4425 MagickSizeType
4426 length;
4427
4428 PixelPacket
4429 *equalize_map;
4430
4431 register ssize_t
4432 i;
4433
4434 size_t
4435 global_work_size[2];
4436
4437 void
4438 *hostPtr,
4439 *inputPixels;
4440
4441 map=NULL;
4442 histogram=NULL;
4443 equalize_map=NULL;
4444 inputPixels = NULL;
4445 imageBuffer = NULL;
4446 histogramBuffer = NULL;
4447 equalizeMapBuffer = NULL;
4448 histogramKernel = NULL;
4449 equalizeKernel = NULL;
4450 context = NULL;
4451 queue = NULL;
4452 outputReady = MagickFalse;
4453
4454 assert(image != (Image *) NULL);
4455 assert(image->signature == MagickSignature);
4456 if (image->debug != MagickFalse)
4457 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4458
4459 /*
4460 * initialize opencl env
4461 */
4462 clEnv = GetDefaultOpenCLEnv();
4463 context = GetOpenCLContext(clEnv);
4464 queue = AcquireOpenCLCommandQueue(clEnv);
4465
4466 /*
4467 Allocate and initialize histogram arrays.
4468 */
4469 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
4470 if (histogram == (cl_uint4 *) NULL)
4471 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
4472
4473 /* reset histogram */
4474 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
4475
4476 /* Create and initialize OpenCL buffers. */
4477 /* inputPixels = AcquirePixelCachePixels(image, &length, exception); */
4478 /* assume this will get a writable image */
4479 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00004480 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00004481
4482 if (inputPixels == (void *) NULL)
4483 {
dirk8a5cf512014-07-28 20:16:27 +00004484 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00004485 goto cleanup;
4486 }
4487 /* If the host pointer is aligned to the size of CLPixelPacket,
4488 then use the host buffer directly from the GPU; otherwise,
4489 create a buffer on the GPU and copy the data over */
4490 if (ALIGNED(inputPixels,CLPixelPacket))
4491 {
4492 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4493 }
4494 else
4495 {
4496 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
4497 }
4498 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00004499 length = image->columns * image->rows;
4500 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004501 if (clStatus != CL_SUCCESS)
4502 {
cristy0c832c62014-03-07 22:21:04 +00004503 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004504 goto cleanup;
4505 }
cristy0c832c62014-03-07 22:21:04 +00004506
cristyf034abb2013-11-24 14:16:14 +00004507 /* If the host pointer is aligned to the size of cl_uint,
4508 then use the host buffer directly from the GPU; otherwise,
4509 create a buffer on the GPU and copy the data over */
4510 if (ALIGNED(histogram,cl_uint4))
4511 {
4512 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4513 hostPtr = histogram;
4514 }
4515 else
4516 {
4517 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4518 hostPtr = histogram;
4519 }
4520 /* create a CL buffer for histogram */
4521 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004522 histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004523 if (clStatus != CL_SUCCESS)
4524 {
cristy0c832c62014-03-07 22:21:04 +00004525 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004526 goto cleanup;
4527 }
4528
dirk8a5cf512014-07-28 20:16:27 +00004529 status = LaunchHistogramKernel(clEnv, queue, imageBuffer, histogramBuffer, image, channel, exception);
cristy0c832c62014-03-07 22:21:04 +00004530 if (status == MagickFalse)
cristyf034abb2013-11-24 14:16:14 +00004531 goto cleanup;
cristyf034abb2013-11-24 14:16:14 +00004532
4533 /* read from the kenel output */
4534 if (ALIGNED(histogram,cl_uint4))
4535 {
4536 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004537 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004538 }
4539 else
4540 {
4541 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004542 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004543 }
4544 if (clStatus != CL_SUCCESS)
4545 {
cristya22457d2013-12-07 14:03:06 +00004546 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004547 goto cleanup;
4548 }
4549
4550 /* unmap, don't block gpu to use this buffer again. */
4551 if (ALIGNED(histogram,cl_uint4))
4552 {
cristy0c832c62014-03-07 22:21:04 +00004553 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004554 if (clStatus != CL_SUCCESS)
4555 {
cristy0c832c62014-03-07 22:21:04 +00004556 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004557 goto cleanup;
4558 }
4559 }
4560
cristy0c832c62014-03-07 22:21:04 +00004561 /* recreate input buffer later, in case image updated */
4562#ifdef RECREATEBUFFER
dirk8a5cf512014-07-28 20:16:27 +00004563 if (imageBuffer!=NULL)
4564 clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00004565#endif
4566
4567 /* CPU stuff */
cristyf034abb2013-11-24 14:16:14 +00004568 equalize_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*equalize_map));
4569 if (equalize_map == (PixelPacket *) NULL)
cristy0c832c62014-03-07 22:21:04 +00004570 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
cristyf034abb2013-11-24 14:16:14 +00004571
4572 map=(FloatPixelPacket *) AcquireQuantumMemory(MaxMap+1UL,sizeof(*map));
4573 if (map == (FloatPixelPacket *) NULL)
cristy0c832c62014-03-07 22:21:04 +00004574 ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", image->filename);
cristyf034abb2013-11-24 14:16:14 +00004575
4576 /*
4577 Integrate the histogram to get the equalization map.
4578 */
4579 (void) ResetMagickMemory(&intensity,0,sizeof(intensity));
4580 for (i=0; i <= (ssize_t) MaxMap; i++)
4581 {
4582 if ((channel & SyncChannels) != 0)
cristy0c832c62014-03-07 22:21:04 +00004583 {
4584 intensity.red+=histogram[i].s[2];
4585 map[i]=intensity;
4586 continue;
4587 }
cristyf034abb2013-11-24 14:16:14 +00004588 if ((channel & RedChannel) != 0)
4589 intensity.red+=histogram[i].s[2];
4590 if ((channel & GreenChannel) != 0)
4591 intensity.green+=histogram[i].s[1];
4592 if ((channel & BlueChannel) != 0)
4593 intensity.blue+=histogram[i].s[0];
4594 if ((channel & OpacityChannel) != 0)
dirk8a5cf512014-07-28 20:16:27 +00004595 intensity.alpha+=histogram[i].s[3];
cristy0c832c62014-03-07 22:21:04 +00004596 /*
cristyf034abb2013-11-24 14:16:14 +00004597 if (((channel & IndexChannel) != 0) &&
4598 (image->colorspace == CMYKColorspace))
4599 {
cristy0c832c62014-03-07 22:21:04 +00004600 intensity.index+=histogram[i].index;
cristyf034abb2013-11-24 14:16:14 +00004601 }
cristy0c832c62014-03-07 22:21:04 +00004602 */
cristyf034abb2013-11-24 14:16:14 +00004603 map[i]=intensity;
4604 }
4605 black=map[0];
4606 white=map[(int) MaxMap];
4607 (void) ResetMagickMemory(equalize_map,0,(MaxMap+1)*sizeof(*equalize_map));
4608 for (i=0; i <= (ssize_t) MaxMap; i++)
4609 {
4610 if ((channel & SyncChannels) != 0)
cristy0c832c62014-03-07 22:21:04 +00004611 {
4612 if (white.red != black.red)
4613 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4614 (map[i].red-black.red))/(white.red-black.red)));
4615 continue;
4616 }
cristyf034abb2013-11-24 14:16:14 +00004617 if (((channel & RedChannel) != 0) && (white.red != black.red))
4618 equalize_map[i].red=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004619 (map[i].red-black.red))/(white.red-black.red)));
cristyf034abb2013-11-24 14:16:14 +00004620 if (((channel & GreenChannel) != 0) && (white.green != black.green))
4621 equalize_map[i].green=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004622 (map[i].green-black.green))/(white.green-black.green)));
cristyf034abb2013-11-24 14:16:14 +00004623 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
4624 equalize_map[i].blue=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004625 (map[i].blue-black.blue))/(white.blue-black.blue)));
dirk8a5cf512014-07-28 20:16:27 +00004626 if (((channel & OpacityChannel) != 0) && (white.alpha != black.alpha))
4627 equalize_map[i].alpha=ScaleMapToQuantum((MagickRealType) ((MaxMap*
4628 (map[i].alpha-black.alpha))/(white.alpha-black.alpha)));
cristyf034abb2013-11-24 14:16:14 +00004629 /*
4630 if ((((channel & IndexChannel) != 0) &&
cristy0c832c62014-03-07 22:21:04 +00004631 (image->colorspace == CMYKColorspace)) &&
cristyf034abb2013-11-24 14:16:14 +00004632 (white.index != black.index))
4633 equalize_map[i].index=ScaleMapToQuantum((MagickRealType) ((MaxMap*
cristy0c832c62014-03-07 22:21:04 +00004634 (map[i].index-black.index))/(white.index-black.index)));
cristyf034abb2013-11-24 14:16:14 +00004635 */
4636 }
4637
cristyf034abb2013-11-24 14:16:14 +00004638 if (image->storage_class == PseudoClass)
4639 {
cristy0c832c62014-03-07 22:21:04 +00004640 /*
4641 Equalize colormap.
4642 */
4643 for (i=0; i < (ssize_t) image->colors; i++)
4644 {
4645 if ((channel & SyncChannels) != 0)
cristyf034abb2013-11-24 14:16:14 +00004646 {
cristy0c832c62014-03-07 22:21:04 +00004647 if (white.red != black.red)
4648 {
cristyf034abb2013-11-24 14:16:14 +00004649 image->colormap[i].red=equalize_map[
4650 ScaleQuantumToMap(image->colormap[i].red)].red;
cristyf034abb2013-11-24 14:16:14 +00004651 image->colormap[i].green=equalize_map[
cristy0c832c62014-03-07 22:21:04 +00004652 ScaleQuantumToMap(image->colormap[i].green)].red;
cristyf034abb2013-11-24 14:16:14 +00004653 image->colormap[i].blue=equalize_map[
cristy0c832c62014-03-07 22:21:04 +00004654 ScaleQuantumToMap(image->colormap[i].blue)].red;
dirk8a5cf512014-07-28 20:16:27 +00004655 image->colormap[i].alpha=equalize_map[
4656 ScaleQuantumToMap(image->colormap[i].alpha)].red;
cristy0c832c62014-03-07 22:21:04 +00004657 }
4658 continue;
cristyf034abb2013-11-24 14:16:14 +00004659 }
cristy0c832c62014-03-07 22:21:04 +00004660 if (((channel & RedChannel) != 0) && (white.red != black.red))
4661 image->colormap[i].red=equalize_map[
4662 ScaleQuantumToMap(image->colormap[i].red)].red;
4663 if (((channel & GreenChannel) != 0) && (white.green != black.green))
4664 image->colormap[i].green=equalize_map[
4665 ScaleQuantumToMap(image->colormap[i].green)].green;
4666 if (((channel & BlueChannel) != 0) && (white.blue != black.blue))
4667 image->colormap[i].blue=equalize_map[
4668 ScaleQuantumToMap(image->colormap[i].blue)].blue;
4669 if (((channel & OpacityChannel) != 0) &&
dirk8a5cf512014-07-28 20:16:27 +00004670 (white.alpha != black.alpha))
4671 image->colormap[i].alpha=equalize_map[
4672 ScaleQuantumToMap(image->colormap[i].alpha)].alpha;
cristy0c832c62014-03-07 22:21:04 +00004673 }
cristyf034abb2013-11-24 14:16:14 +00004674 }
4675
4676 /*
4677 Equalize image.
4678 */
4679
4680 /* GPU can work on this again, image and equalize map as input
4681 image: uchar4 (CLPixelPacket)
4682 equalize_map: uchar4 (PixelPacket)
4683 black, white: float4 (FloatPixelPacket) */
4684
cristy0c832c62014-03-07 22:21:04 +00004685#ifdef RECREATEBUFFER
cristyf034abb2013-11-24 14:16:14 +00004686 /* If the host pointer is aligned to the size of CLPixelPacket,
4687 then use the host buffer directly from the GPU; otherwise,
4688 create a buffer on the GPU and copy the data over */
4689 if (ALIGNED(inputPixels,CLPixelPacket))
4690 {
4691 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
4692 }
4693 else
4694 {
4695 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4696 }
4697 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00004698 length = image->columns * image->rows;
4699 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004700 if (clStatus != CL_SUCCESS)
4701 {
cristy0c832c62014-03-07 22:21:04 +00004702 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004703 goto cleanup;
4704 }
cristy0c832c62014-03-07 22:21:04 +00004705#endif
cristyf034abb2013-11-24 14:16:14 +00004706
4707 /* Create and initialize OpenCL buffers. */
4708 if (ALIGNED(equalize_map, PixelPacket))
4709 {
4710 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
4711 hostPtr = equalize_map;
4712 }
4713 else
4714 {
4715 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
4716 hostPtr = equalize_map;
4717 }
4718 /* create a CL buffer for eqaulize_map */
4719 length = (MaxMap+1);
cristy0c832c62014-03-07 22:21:04 +00004720 equalizeMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004721 if (clStatus != CL_SUCCESS)
4722 {
cristy0c832c62014-03-07 22:21:04 +00004723 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00004724 goto cleanup;
4725 }
4726
4727 /* get the OpenCL kernel */
4728 equalizeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Equalize");
4729 if (equalizeKernel == NULL)
4730 {
cristya22457d2013-12-07 14:03:06 +00004731 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004732 goto cleanup;
4733 }
4734
4735 /* set the kernel arguments */
4736 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00004737 clStatus=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00004738 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(ChannelType),&channel);
4739 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(cl_mem),(void *)&equalizeMapBuffer);
4740 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&white);
4741 clStatus|=clEnv->library->clSetKernelArg(equalizeKernel,i++,sizeof(FloatPixelPacket),&black);
cristyf034abb2013-11-24 14:16:14 +00004742 if (clStatus != CL_SUCCESS)
4743 {
cristy0c832c62014-03-07 22:21:04 +00004744 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004745 goto cleanup;
4746 }
4747
4748 /* launch the kernel */
dirk8a5cf512014-07-28 20:16:27 +00004749 global_work_size[0] = image->columns;
4750 global_work_size[1] = image->rows;
cristyf034abb2013-11-24 14:16:14 +00004751
cristy0c832c62014-03-07 22:21:04 +00004752 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, equalizeKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004753
4754 if (clStatus != CL_SUCCESS)
4755 {
cristy0c832c62014-03-07 22:21:04 +00004756 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004757 goto cleanup;
4758 }
cristy0c832c62014-03-07 22:21:04 +00004759 clEnv->library->clFlush(queue);
cristyf034abb2013-11-24 14:16:14 +00004760
4761 /* read the data back */
4762 if (ALIGNED(inputPixels,CLPixelPacket))
4763 {
dirk8a5cf512014-07-28 20:16:27 +00004764 length = image->columns * image->rows;
4765 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00004766 }
4767 else
4768 {
dirk8a5cf512014-07-28 20:16:27 +00004769 length = image->columns * image->rows;
4770 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00004771 }
4772 if (clStatus != CL_SUCCESS)
4773 {
cristya22457d2013-12-07 14:03:06 +00004774 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00004775 goto cleanup;
4776 }
4777
dirk832becc2014-08-04 19:44:34 +00004778 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
4779
4780cleanup:
4781 OpenCLLogException(__FUNCTION__,__LINE__,exception);
4782
dirk8a5cf512014-07-28 20:16:27 +00004783 image_view=DestroyCacheView(image_view);
cristyf034abb2013-11-24 14:16:14 +00004784
dirk8a5cf512014-07-28 20:16:27 +00004785 if (imageBuffer!=NULL)
4786 clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00004787
4788 if (map!=NULL)
4789 map=(FloatPixelPacket *) RelinquishMagickMemory(map);
4790
4791 if (equalizeMapBuffer!=NULL)
4792 clEnv->library->clReleaseMemObject(equalizeMapBuffer);
4793 if (equalize_map!=NULL)
4794 equalize_map=(PixelPacket *) RelinquishMagickMemory(equalize_map);
4795
cristyf034abb2013-11-24 14:16:14 +00004796 if (histogramBuffer!=NULL)
cristy0c832c62014-03-07 22:21:04 +00004797 clEnv->library->clReleaseMemObject(histogramBuffer);
4798 if (histogram!=NULL)
4799 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
4800
cristyf034abb2013-11-24 14:16:14 +00004801 if (histogramKernel!=NULL)
4802 RelinquishOpenCLKernel(clEnv, histogramKernel);
cristy0c832c62014-03-07 22:21:04 +00004803 if (equalizeKernel!=NULL)
4804 RelinquishOpenCLKernel(clEnv, equalizeKernel);
4805
cristyf034abb2013-11-24 14:16:14 +00004806 if (queue != NULL)
4807 RelinquishOpenCLCommandQueue(clEnv, queue);
4808
dirk8a5cf512014-07-28 20:16:27 +00004809 return(outputReady);
dirk832becc2014-08-04 19:44:34 +00004810}
4811
4812MagickExport MagickBooleanType AccelerateEqualizeImage(Image *image,
4813 const ChannelType channel,ExceptionInfo *exception)
4814{
4815 MagickBooleanType
4816 status;
4817
4818 assert(image != NULL);
4819 assert(exception != (ExceptionInfo *) NULL);
4820
4821 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
4822 (checkAccelerateCondition(image, channel) == MagickFalse) ||
4823 (checkHistogramCondition(image, channel) == MagickFalse))
4824 return(MagickFalse);
4825
4826 status=ComputeEqualizeImage(image,channel,exception);
4827 return(status);
cristyf034abb2013-11-24 14:16:14 +00004828}
4829
4830/*
4831%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4832% %
4833% %
4834% %
dirk8a5cf512014-07-28 20:16:27 +00004835% 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 %
cristyf034abb2013-11-24 14:16:14 +00004836% %
4837% %
4838% %
4839%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4840%
dirk8a5cf512014-07-28 20:16:27 +00004841% ContrastStretchImage() is a simple image enhancement technique that attempts
4842% to improve the contrast in an image by `stretching' the range of intensity
4843% values it contains to span a desired range of values. It differs from the
4844% more sophisticated histogram equalization in that it can only apply a
4845% linear scaling function to the image pixel values. As a result the
4846% `enhancement' is less harsh.
cristyf034abb2013-11-24 14:16:14 +00004847%
dirk8a5cf512014-07-28 20:16:27 +00004848% The format of the ContrastStretchImage method is:
cristyf034abb2013-11-24 14:16:14 +00004849%
dirk8a5cf512014-07-28 20:16:27 +00004850% MagickBooleanType ContrastStretchImage(Image *image,
4851% const char *levels)
4852% MagickBooleanType ContrastStretchImageChannel(Image *image,
4853% const size_t channel,const double black_point,
4854% const double white_point)
cristyf034abb2013-11-24 14:16:14 +00004855%
4856% A description of each parameter follows:
4857%
4858% o image: the image.
4859%
4860% o channel: the channel.
4861%
dirk8a5cf512014-07-28 20:16:27 +00004862% o black_point: the black point.
4863%
4864% o white_point: the white point.
4865%
4866% o levels: Specify the levels where the black and white points have the
4867% range of 0 to number-of-pixels (e.g. 1%, 10x90%, etc.).
4868%
cristyf034abb2013-11-24 14:16:14 +00004869*/
4870
dirk832becc2014-08-04 19:44:34 +00004871MagickExport MagickBooleanType ComputeContrastStretchImageChannel(Image *image,
4872 const ChannelType channel,const double black_point,const double white_point,
4873 ExceptionInfo *exception)
4874{
4875#define ContrastStretchImageTag "ContrastStretch/Image"
4876#define MaxRange(color) ((MagickRealType) ScaleQuantumToMap((Quantum) (color)))
4877
4878 CacheView
4879 *image_view;
4880
4881 cl_command_queue
4882 queue;
4883
4884 cl_context
4885 context;
4886
4887 cl_int
4888 clStatus;
4889
4890 cl_mem_flags
4891 mem_flags;
4892
4893 cl_mem
4894 histogramBuffer,
4895 imageBuffer,
4896 stretchMapBuffer;
4897
4898 cl_kernel
4899 histogramKernel,
4900 stretchKernel;
4901
4902 cl_uint4
4903 *histogram;
4904
4905 double
4906 intensity;
4907
4908 FloatPixelPacket
4909 black,
4910 white;
4911
4912 MagickBooleanType
4913 outputReady,
4914 status;
4915
4916 MagickCLEnv
4917 clEnv;
4918
4919 MagickSizeType
4920 length;
4921
4922 PixelPacket
4923 *stretch_map;
4924
4925 register ssize_t
4926 i;
4927
4928 size_t
4929 global_work_size[2];
4930
4931 void
4932 *hostPtr,
4933 *inputPixels;
4934
4935 histogram=NULL;
4936 stretch_map=NULL;
4937 inputPixels = NULL;
4938 imageBuffer = NULL;
4939 histogramBuffer = NULL;
4940 stretchMapBuffer = NULL;
4941 histogramKernel = NULL;
4942 stretchKernel = NULL;
4943 context = NULL;
4944 queue = NULL;
4945 outputReady = MagickFalse;
4946
4947
4948 assert(image != (Image *) NULL);
4949 assert(image->signature == MagickSignature);
4950 if (image->debug != MagickFalse)
4951 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4952
4953 //exception=(&image->exception);
4954
4955 /*
4956 * initialize opencl env
4957 */
4958 clEnv = GetDefaultOpenCLEnv();
4959 context = GetOpenCLContext(clEnv);
4960 queue = AcquireOpenCLCommandQueue(clEnv);
4961
4962 /*
4963 Allocate and initialize histogram arrays.
4964 */
4965 histogram=(cl_uint4 *) AcquireQuantumMemory(MaxMap+1UL, sizeof(*histogram));
4966
4967 if (histogram == (cl_uint4 *) NULL)
4968 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", image->filename);
4969
4970 /* reset histogram */
4971 (void) ResetMagickMemory(histogram,0,(MaxMap+1)*sizeof(*histogram));
4972
4973 /*
4974 if (IsGrayImage(image,exception) != MagickFalse)
4975 (void) SetImageColorspace(image,GRAYColorspace);
4976 */
4977
4978 status=MagickTrue;
4979
4980
4981 /*
4982 Form histogram.
4983 */
4984 /* Create and initialize OpenCL buffers. */
4985 /* inputPixels = AcquirePixelCachePixels(image, &length, exception); */
4986 /* assume this will get a writable image */
4987 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00004988 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00004989
4990 if (inputPixels == (void *) NULL)
4991 {
dirk8a5cf512014-07-28 20:16:27 +00004992 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristy0c832c62014-03-07 22:21:04 +00004993 goto cleanup;
4994 }
4995 /* If the host pointer is aligned to the size of CLPixelPacket,
4996 then use the host buffer directly from the GPU; otherwise,
4997 create a buffer on the GPU and copy the data over */
4998 if (ALIGNED(inputPixels,CLPixelPacket))
4999 {
5000 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5001 }
5002 else
5003 {
5004 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5005 }
5006 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00005007 length = image->columns * image->rows;
5008 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00005009 if (clStatus != CL_SUCCESS)
5010 {
5011 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5012 goto cleanup;
5013 }
5014
5015 /* If the host pointer is aligned to the size of cl_uint,
5016 then use the host buffer directly from the GPU; otherwise,
5017 create a buffer on the GPU and copy the data over */
5018 if (ALIGNED(histogram,cl_uint4))
5019 {
5020 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
5021 hostPtr = histogram;
5022 }
5023 else
5024 {
5025 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
5026 hostPtr = histogram;
5027 }
5028 /* create a CL buffer for histogram */
5029 length = (MaxMap+1);
5030 histogramBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(cl_uint4), hostPtr, &clStatus);
5031 if (clStatus != CL_SUCCESS)
5032 {
5033 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5034 goto cleanup;
5035 }
5036
dirk8a5cf512014-07-28 20:16:27 +00005037 status = LaunchHistogramKernel(clEnv, queue, imageBuffer, histogramBuffer, image, channel, exception);
cristy0c832c62014-03-07 22:21:04 +00005038 if (status == MagickFalse)
5039 goto cleanup;
5040
5041 /* read from the kenel output */
5042 if (ALIGNED(histogram,cl_uint4))
5043 {
5044 length = (MaxMap+1);
5045 clEnv->library->clEnqueueMapBuffer(queue, histogramBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(cl_uint4), 0, NULL, NULL, &clStatus);
5046 }
5047 else
5048 {
5049 length = (MaxMap+1);
5050 clStatus = clEnv->library->clEnqueueReadBuffer(queue, histogramBuffer, CL_TRUE, 0, length * sizeof(cl_uint4), histogram, 0, NULL, NULL);
5051 }
5052 if (clStatus != CL_SUCCESS)
5053 {
5054 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
5055 goto cleanup;
5056 }
5057
5058 /* unmap, don't block gpu to use this buffer again. */
5059 if (ALIGNED(histogram,cl_uint4))
5060 {
5061 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, histogramBuffer, histogram, 0, NULL, NULL);
5062 if (clStatus != CL_SUCCESS)
5063 {
5064 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
5065 goto cleanup;
5066 }
5067 }
5068
5069 /* recreate input buffer later, in case image updated */
5070#ifdef RECREATEBUFFER
dirk8a5cf512014-07-28 20:16:27 +00005071 if (imageBuffer!=NULL)
5072 clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00005073#endif
5074
5075 /* CPU stuff */
5076 /*
5077 Find the histogram boundaries by locating the black/white levels.
5078 */
5079 black.red=0.0;
5080 white.red=MaxRange(QuantumRange);
5081 if ((channel & RedChannel) != 0)
5082 {
5083 intensity=0.0;
5084 for (i=0; i <= (ssize_t) MaxMap; i++)
5085 {
5086 intensity+=histogram[i].s[2];
5087 if (intensity > black_point)
5088 break;
5089 }
5090 black.red=(MagickRealType) i;
5091 intensity=0.0;
5092 for (i=(ssize_t) MaxMap; i != 0; i--)
5093 {
5094 intensity+=histogram[i].s[2];
5095 if (intensity > ((double) image->columns*image->rows-white_point))
5096 break;
5097 }
5098 white.red=(MagickRealType) i;
5099 }
5100 black.green=0.0;
5101 white.green=MaxRange(QuantumRange);
5102 if ((channel & GreenChannel) != 0)
5103 {
5104 intensity=0.0;
5105 for (i=0; i <= (ssize_t) MaxMap; i++)
5106 {
5107 intensity+=histogram[i].s[2];
5108 if (intensity > black_point)
5109 break;
5110 }
5111 black.green=(MagickRealType) i;
5112 intensity=0.0;
5113 for (i=(ssize_t) MaxMap; i != 0; i--)
5114 {
5115 intensity+=histogram[i].s[2];
5116 if (intensity > ((double) image->columns*image->rows-white_point))
5117 break;
5118 }
5119 white.green=(MagickRealType) i;
5120 }
5121 black.blue=0.0;
5122 white.blue=MaxRange(QuantumRange);
5123 if ((channel & BlueChannel) != 0)
5124 {
5125 intensity=0.0;
5126 for (i=0; i <= (ssize_t) MaxMap; i++)
5127 {
5128 intensity+=histogram[i].s[2];
5129 if (intensity > black_point)
5130 break;
5131 }
5132 black.blue=(MagickRealType) i;
5133 intensity=0.0;
5134 for (i=(ssize_t) MaxMap; i != 0; i--)
5135 {
5136 intensity+=histogram[i].s[2];
5137 if (intensity > ((double) image->columns*image->rows-white_point))
5138 break;
5139 }
5140 white.blue=(MagickRealType) i;
5141 }
dirk8a5cf512014-07-28 20:16:27 +00005142 black.alpha=0.0;
5143 white.alpha=MaxRange(QuantumRange);
cristy0c832c62014-03-07 22:21:04 +00005144 if ((channel & OpacityChannel) != 0)
5145 {
5146 intensity=0.0;
5147 for (i=0; i <= (ssize_t) MaxMap; i++)
5148 {
5149 intensity+=histogram[i].s[2];
5150 if (intensity > black_point)
5151 break;
5152 }
dirk8a5cf512014-07-28 20:16:27 +00005153 black.alpha=(MagickRealType) i;
cristy0c832c62014-03-07 22:21:04 +00005154 intensity=0.0;
5155 for (i=(ssize_t) MaxMap; i != 0; i--)
5156 {
5157 intensity+=histogram[i].s[2];
5158 if (intensity > ((double) image->columns*image->rows-white_point))
5159 break;
5160 }
dirk8a5cf512014-07-28 20:16:27 +00005161 white.alpha=(MagickRealType) i;
cristy0c832c62014-03-07 22:21:04 +00005162 }
5163 /*
5164 black.index=0.0;
5165 white.index=MaxRange(QuantumRange);
5166 if (((channel & IndexChannel) != 0) && (image->colorspace == CMYKColorspace))
5167 {
5168 intensity=0.0;
5169 for (i=0; i <= (ssize_t) MaxMap; i++)
5170 {
5171 intensity+=histogram[i].index;
5172 if (intensity > black_point)
5173 break;
5174 }
5175 black.index=(MagickRealType) i;
5176 intensity=0.0;
5177 for (i=(ssize_t) MaxMap; i != 0; i--)
5178 {
5179 intensity+=histogram[i].index;
5180 if (intensity > ((double) image->columns*image->rows-white_point))
5181 break;
5182 }
5183 white.index=(MagickRealType) i;
5184 }
5185 */
5186
5187
5188 stretch_map=(PixelPacket *) AcquireQuantumMemory(MaxMap+1UL,
5189 sizeof(*stretch_map));
5190
cristy931c8062014-03-10 13:19:17 +00005191 if (stretch_map == (PixelPacket *) NULL)
cristy0c832c62014-03-07 22:21:04 +00005192 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
5193 image->filename);
5194
5195 /*
5196 Stretch the histogram to create the stretched image mapping.
5197 */
5198 (void) ResetMagickMemory(stretch_map,0,(MaxMap+1)*sizeof(*stretch_map));
5199 for (i=0; i <= (ssize_t) MaxMap; i++)
5200 {
5201 if ((channel & RedChannel) != 0)
5202 {
5203 if (i < (ssize_t) black.red)
5204 stretch_map[i].red=(Quantum) 0;
5205 else
5206 if (i > (ssize_t) white.red)
5207 stretch_map[i].red=QuantumRange;
5208 else
5209 if (black.red != white.red)
5210 stretch_map[i].red=ScaleMapToQuantum((MagickRealType) (MaxMap*
5211 (i-black.red)/(white.red-black.red)));
5212 }
5213 if ((channel & GreenChannel) != 0)
5214 {
5215 if (i < (ssize_t) black.green)
5216 stretch_map[i].green=0;
5217 else
5218 if (i > (ssize_t) white.green)
5219 stretch_map[i].green=QuantumRange;
5220 else
5221 if (black.green != white.green)
5222 stretch_map[i].green=ScaleMapToQuantum((MagickRealType) (MaxMap*
5223 (i-black.green)/(white.green-black.green)));
5224 }
5225 if ((channel & BlueChannel) != 0)
5226 {
5227 if (i < (ssize_t) black.blue)
5228 stretch_map[i].blue=0;
5229 else
5230 if (i > (ssize_t) white.blue)
5231 stretch_map[i].blue= QuantumRange;
5232 else
5233 if (black.blue != white.blue)
5234 stretch_map[i].blue=ScaleMapToQuantum((MagickRealType) (MaxMap*
5235 (i-black.blue)/(white.blue-black.blue)));
5236 }
5237 if ((channel & OpacityChannel) != 0)
5238 {
dirk8a5cf512014-07-28 20:16:27 +00005239 if (i < (ssize_t) black.alpha)
5240 stretch_map[i].alpha=0;
cristy0c832c62014-03-07 22:21:04 +00005241 else
dirk8a5cf512014-07-28 20:16:27 +00005242 if (i > (ssize_t) white.alpha)
5243 stretch_map[i].alpha=QuantumRange;
cristy0c832c62014-03-07 22:21:04 +00005244 else
dirk8a5cf512014-07-28 20:16:27 +00005245 if (black.alpha != white.alpha)
5246 stretch_map[i].alpha=ScaleMapToQuantum((MagickRealType) (MaxMap*
5247 (i-black.alpha)/(white.alpha-black.alpha)));
cristy0c832c62014-03-07 22:21:04 +00005248 }
5249 /*
5250 if (((channel & IndexChannel) != 0) &&
5251 (image->colorspace == CMYKColorspace))
5252 {
5253 if (i < (ssize_t) black.index)
5254 stretch_map[i].index=0;
5255 else
5256 if (i > (ssize_t) white.index)
5257 stretch_map[i].index=QuantumRange;
5258 else
5259 if (black.index != white.index)
5260 stretch_map[i].index=ScaleMapToQuantum((MagickRealType) (MaxMap*
5261 (i-black.index)/(white.index-black.index)));
5262 }
5263 */
5264 }
5265
5266 /*
5267 Stretch the image.
5268 */
5269 if (((channel & OpacityChannel) != 0) || (((channel & IndexChannel) != 0) &&
5270 (image->colorspace == CMYKColorspace)))
5271 image->storage_class=DirectClass;
5272 if (image->storage_class == PseudoClass)
5273 {
5274 /*
5275 Stretch colormap.
5276 */
5277 for (i=0; i < (ssize_t) image->colors; i++)
5278 {
5279 if ((channel & RedChannel) != 0)
5280 {
5281 if (black.red != white.red)
5282 image->colormap[i].red=stretch_map[
5283 ScaleQuantumToMap(image->colormap[i].red)].red;
5284 }
5285 if ((channel & GreenChannel) != 0)
5286 {
5287 if (black.green != white.green)
5288 image->colormap[i].green=stretch_map[
5289 ScaleQuantumToMap(image->colormap[i].green)].green;
5290 }
5291 if ((channel & BlueChannel) != 0)
5292 {
5293 if (black.blue != white.blue)
5294 image->colormap[i].blue=stretch_map[
5295 ScaleQuantumToMap(image->colormap[i].blue)].blue;
5296 }
5297 if ((channel & OpacityChannel) != 0)
5298 {
dirk8a5cf512014-07-28 20:16:27 +00005299 if (black.alpha != white.alpha)
5300 image->colormap[i].alpha=stretch_map[
5301 ScaleQuantumToMap(image->colormap[i].alpha)].alpha;
cristy0c832c62014-03-07 22:21:04 +00005302 }
5303 }
5304 }
5305
5306 /*
5307 Stretch image.
5308 */
5309
5310
5311 /* GPU can work on this again, image and equalize map as input
5312 image: uchar4 (CLPixelPacket)
5313 stretch_map: uchar4 (PixelPacket)
5314 black, white: float4 (FloatPixelPacket) */
5315
5316#ifdef RECREATEBUFFER
5317 /* If the host pointer is aligned to the size of CLPixelPacket,
5318 then use the host buffer directly from the GPU; otherwise,
5319 create a buffer on the GPU and copy the data over */
5320 if (ALIGNED(inputPixels,CLPixelPacket))
5321 {
5322 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
5323 }
5324 else
5325 {
5326 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
5327 }
5328 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00005329 length = image->columns * image->rows;
5330 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00005331 if (clStatus != CL_SUCCESS)
5332 {
5333 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5334 goto cleanup;
5335 }
5336#endif
5337
5338 /* Create and initialize OpenCL buffers. */
5339 if (ALIGNED(stretch_map, PixelPacket))
5340 {
5341 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5342 hostPtr = stretch_map;
5343 }
5344 else
5345 {
5346 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
5347 hostPtr = stretch_map;
5348 }
5349 /* create a CL buffer for stretch_map */
5350 length = (MaxMap+1);
5351 stretchMapBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(PixelPacket), hostPtr, &clStatus);
5352 if (clStatus != CL_SUCCESS)
5353 {
5354 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
5355 goto cleanup;
5356 }
5357
5358 /* get the OpenCL kernel */
5359 stretchKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "Stretch");
5360 if (stretchKernel == NULL)
5361 {
5362 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "AcquireOpenCLKernel failed.", "'%s'", ".");
5363 goto cleanup;
5364 }
5365
5366 /* set the kernel arguments */
5367 i = 0;
dirk8a5cf512014-07-28 20:16:27 +00005368 clStatus=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00005369 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(ChannelType),&channel);
5370 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(cl_mem),(void *)&stretchMapBuffer);
5371 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&white);
5372 clStatus|=clEnv->library->clSetKernelArg(stretchKernel,i++,sizeof(FloatPixelPacket),&black);
5373 if (clStatus != CL_SUCCESS)
5374 {
5375 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
5376 goto cleanup;
5377 }
5378
5379 /* launch the kernel */
dirk8a5cf512014-07-28 20:16:27 +00005380 global_work_size[0] = image->columns;
5381 global_work_size[1] = image->rows;
cristy0c832c62014-03-07 22:21:04 +00005382
5383 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, stretchKernel, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
5384
5385 if (clStatus != CL_SUCCESS)
5386 {
5387 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
5388 goto cleanup;
5389 }
5390 clEnv->library->clFlush(queue);
5391
5392 /* read the data back */
5393 if (ALIGNED(inputPixels,CLPixelPacket))
5394 {
dirk8a5cf512014-07-28 20:16:27 +00005395 length = image->columns * image->rows;
5396 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00005397 }
5398 else
5399 {
dirk8a5cf512014-07-28 20:16:27 +00005400 length = image->columns * image->rows;
5401 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristy0c832c62014-03-07 22:21:04 +00005402 }
5403 if (clStatus != CL_SUCCESS)
5404 {
5405 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
5406 goto cleanup;
5407 }
5408
dirk832becc2014-08-04 19:44:34 +00005409 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
5410
5411cleanup:
5412 OpenCLLogException(__FUNCTION__,__LINE__,exception);
5413
dirk8a5cf512014-07-28 20:16:27 +00005414 image_view=DestroyCacheView(image_view);
cristy0c832c62014-03-07 22:21:04 +00005415
dirk8a5cf512014-07-28 20:16:27 +00005416 if (imageBuffer!=NULL)
5417 clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00005418
5419 if (stretchMapBuffer!=NULL)
5420 clEnv->library->clReleaseMemObject(stretchMapBuffer);
5421 if (stretch_map!=NULL)
5422 stretch_map=(PixelPacket *) RelinquishMagickMemory(stretch_map);
5423
5424
5425 if (histogramBuffer!=NULL)
5426 clEnv->library->clReleaseMemObject(histogramBuffer);
5427 if (histogram!=NULL)
5428 histogram=(cl_uint4 *) RelinquishMagickMemory(histogram);
5429
5430
5431 if (histogramKernel!=NULL)
5432 RelinquishOpenCLKernel(clEnv, histogramKernel);
5433 if (stretchKernel!=NULL)
5434 RelinquishOpenCLKernel(clEnv, stretchKernel);
5435
5436 if (queue != NULL)
5437 RelinquishOpenCLCommandQueue(clEnv, queue);
5438
dirk832becc2014-08-04 19:44:34 +00005439 return(outputReady);
5440}
5441
5442MagickExport MagickBooleanType AccelerateContrastStretchImageChannel(
5443 Image *image,const ChannelType channel,const double black_point,
5444 const double white_point,ExceptionInfo *exception)
5445{
5446 MagickBooleanType
5447 status;
5448
5449 assert(image != NULL);
5450 assert(exception != (ExceptionInfo *) NULL);
5451
5452 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
5453 (checkAccelerateCondition(image, channel) == MagickFalse) ||
5454 (checkHistogramCondition(image, channel) == MagickFalse))
5455 return(MagickFalse);
5456
5457 status=ComputeContrastStretchImageChannel(image,channel, black_point, white_point, exception);
5458 return(status);
cristy0c832c62014-03-07 22:21:04 +00005459}
5460
cristy0c832c62014-03-07 22:21:04 +00005461/*
5462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5463% %
5464% %
5465% %
dirk8a5cf512014-07-28 20:16:27 +00005466% D e s p e c k l e I m a g e w i t h O p e n C L %
cristy0c832c62014-03-07 22:21:04 +00005467% %
5468% %
5469% %
5470%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5471%
dirk8a5cf512014-07-28 20:16:27 +00005472% DespeckleImage() reduces the speckle noise in an image while perserving the
5473% edges of the original image. A speckle removing filter uses a complementary
5474% hulling technique (raising pixels that are darker than their surrounding
5475% neighbors, then complementarily lowering pixels that are brighter than their
5476% surrounding neighbors) to reduce the speckle index of that image (reference
5477% Crimmins speckle removal).
cristy0c832c62014-03-07 22:21:04 +00005478%
dirk8a5cf512014-07-28 20:16:27 +00005479% The format of the DespeckleImage method is:
cristy0c832c62014-03-07 22:21:04 +00005480%
dirk8a5cf512014-07-28 20:16:27 +00005481% Image *DespeckleImage(const Image *image,ExceptionInfo *exception)
cristy0c832c62014-03-07 22:21:04 +00005482%
5483% A description of each parameter follows:
5484%
5485% o image: the image.
5486%
dirk8a5cf512014-07-28 20:16:27 +00005487% o exception: return any errors or warnings in this structure.
cristy0c832c62014-03-07 22:21:04 +00005488%
5489*/
5490
dirk832becc2014-08-04 19:44:34 +00005491static Image *ComputeDespeckleImage(const Image *image,
5492 ExceptionInfo*exception)
5493{
5494 static const int
5495 X[4] = {0, 1, 1,-1},
5496 Y[4] = {1, 0, 1, 1};
5497
5498 CacheView
5499 *filteredImage_view,
5500 *image_view;
5501
5502 cl_command_queue
5503 queue;
5504
5505 cl_context
5506 context;
5507
5508 cl_int
5509 clStatus;
5510
5511 cl_kernel
5512 hullPass1,
5513 hullPass2;
5514
5515 cl_mem_flags
5516 mem_flags;
5517
5518 cl_mem
5519 filteredImageBuffer,
5520 imageBuffer,
5521 tempImageBuffer[2];
5522
5523 const void
5524 *inputPixels;
5525
5526 Image
5527 *filteredImage;
5528
5529 int
5530 k,
5531 matte;
5532
5533 MagickBooleanType
5534 outputReady;
5535
5536 MagickCLEnv
5537 clEnv;
5538
5539 MagickSizeType
5540 length;
5541
5542 size_t
5543 global_work_size[2];
5544
5545 unsigned int
5546 imageHeight,
5547 imageWidth;
5548
5549 void
5550 *filteredPixels,
5551 *hostPtr;
5552
5553 outputReady = MagickFalse;
5554 clEnv = NULL;
5555 inputPixels = NULL;
5556 filteredImage = NULL;
5557 filteredImage_view = NULL;
5558 filteredPixels = NULL;
5559 context = NULL;
5560 imageBuffer = NULL;
5561 filteredImageBuffer = NULL;
5562 hullPass1 = NULL;
5563 hullPass2 = NULL;
5564 queue = NULL;
5565 tempImageBuffer[0] = tempImageBuffer[1] = NULL;
5566 clEnv = GetDefaultOpenCLEnv();
5567 context = GetOpenCLContext(clEnv);
5568 queue = AcquireOpenCLCommandQueue(clEnv);
5569
5570 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00005571 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00005572 if (inputPixels == (void *) NULL)
5573 {
dirk8a5cf512014-07-28 20:16:27 +00005574 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristyf034abb2013-11-24 14:16:14 +00005575 goto cleanup;
5576 }
5577
5578 if (ALIGNED(inputPixels,CLPixelPacket))
5579 {
5580 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5581 }
5582 else
5583 {
5584 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5585 }
5586 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00005587 length = image->columns * image->rows;
5588 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005589 if (clStatus != CL_SUCCESS)
5590 {
cristy0c832c62014-03-07 22:21:04 +00005591 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00005592 goto cleanup;
5593 }
5594
5595 mem_flags = CL_MEM_READ_WRITE;
dirk8a5cf512014-07-28 20:16:27 +00005596 length = image->columns * image->rows;
cristyf034abb2013-11-24 14:16:14 +00005597 for (k = 0; k < 2; k++)
5598 {
cristy0c832c62014-03-07 22:21:04 +00005599 tempImageBuffer[k] = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005600 if (clStatus != CL_SUCCESS)
5601 {
cristy0c832c62014-03-07 22:21:04 +00005602 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00005603 goto cleanup;
5604 }
5605 }
5606
dirk8a5cf512014-07-28 20:16:27 +00005607 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristyf034abb2013-11-24 14:16:14 +00005608 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00005609 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristyf034abb2013-11-24 14:16:14 +00005610 {
cristya22457d2013-12-07 14:03:06 +00005611 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005612 goto cleanup;
5613 }
dirk832becc2014-08-04 19:44:34 +00005614 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00005615 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristyf034abb2013-11-24 14:16:14 +00005616 if (filteredPixels == (void *) NULL)
5617 {
cristya22457d2013-12-07 14:03:06 +00005618 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristyf034abb2013-11-24 14:16:14 +00005619 goto cleanup;
5620 }
5621
5622 if (ALIGNED(filteredPixels,CLPixelPacket))
5623 {
5624 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5625 hostPtr = filteredPixels;
5626 }
5627 else
5628 {
5629 mem_flags = CL_MEM_WRITE_ONLY;
5630 hostPtr = NULL;
5631 }
5632 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00005633 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00005634 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005635 if (clStatus != CL_SUCCESS)
5636 {
cristy0c832c62014-03-07 22:21:04 +00005637 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristyf034abb2013-11-24 14:16:14 +00005638 goto cleanup;
5639 }
5640
5641 hullPass1 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass1");
5642 hullPass2 = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "HullPass2");
5643
dirk8a5cf512014-07-28 20:16:27 +00005644 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00005645 clStatus |=clEnv->library->clSetKernelArg(hullPass1,1,sizeof(cl_mem),(void *)(tempImageBuffer+1));
dirk8a5cf512014-07-28 20:16:27 +00005646 imageWidth = image->columns;
cristy0c832c62014-03-07 22:21:04 +00005647 clStatus |=clEnv->library->clSetKernelArg(hullPass1,2,sizeof(unsigned int),(void *)&imageWidth);
dirk8a5cf512014-07-28 20:16:27 +00005648 imageHeight = image->rows;
cristy0c832c62014-03-07 22:21:04 +00005649 clStatus |=clEnv->library->clSetKernelArg(hullPass1,3,sizeof(unsigned int),(void *)&imageHeight);
dirk8a5cf512014-07-28 20:16:27 +00005650 matte = (image->alpha_trait==BlendPixelTrait)?0:1;
cristy0c832c62014-03-07 22:21:04 +00005651 clStatus |=clEnv->library->clSetKernelArg(hullPass1,6,sizeof(int),(void *)&matte);
cristyf034abb2013-11-24 14:16:14 +00005652 if (clStatus != CL_SUCCESS)
5653 {
cristy0c832c62014-03-07 22:21:04 +00005654 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005655 goto cleanup;
5656 }
5657
cristy0c832c62014-03-07 22:21:04 +00005658 clStatus = clEnv->library->clSetKernelArg(hullPass2,0,sizeof(cl_mem),(void *)(tempImageBuffer+1));
5659 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)tempImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +00005660 imageWidth = image->columns;
cristy0c832c62014-03-07 22:21:04 +00005661 clStatus |=clEnv->library->clSetKernelArg(hullPass2,2,sizeof(unsigned int),(void *)&imageWidth);
dirk8a5cf512014-07-28 20:16:27 +00005662 imageHeight = image->rows;
cristy0c832c62014-03-07 22:21:04 +00005663 clStatus |=clEnv->library->clSetKernelArg(hullPass2,3,sizeof(unsigned int),(void *)&imageHeight);
dirk8a5cf512014-07-28 20:16:27 +00005664 matte = (image->alpha_trait==BlendPixelTrait)?0:1;
cristy0c832c62014-03-07 22:21:04 +00005665 clStatus |=clEnv->library->clSetKernelArg(hullPass2,6,sizeof(int),(void *)&matte);
cristyf034abb2013-11-24 14:16:14 +00005666 if (clStatus != CL_SUCCESS)
5667 {
cristy0c832c62014-03-07 22:21:04 +00005668 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005669 goto cleanup;
5670 }
5671
5672
dirk8a5cf512014-07-28 20:16:27 +00005673 global_work_size[0] = image->columns;
5674 global_work_size[1] = image->rows;
cristyf034abb2013-11-24 14:16:14 +00005675
5676
5677 for (k = 0; k < 4; k++)
5678 {
5679 cl_int2 offset;
5680 int polarity;
5681
5682
5683 offset.s[0] = X[k];
5684 offset.s[1] = Y[k];
5685 polarity = 1;
cristy0c832c62014-03-07 22:21:04 +00005686 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5687 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5688 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5689 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005690 if (clStatus != CL_SUCCESS)
5691 {
cristy0c832c62014-03-07 22:21:04 +00005692 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005693 goto cleanup;
5694 }
5695 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005696 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005697 if (clStatus != CL_SUCCESS)
5698 {
cristy0c832c62014-03-07 22:21:04 +00005699 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005700 goto cleanup;
5701 }
5702 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005703 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005704 if (clStatus != CL_SUCCESS)
5705 {
cristy0c832c62014-03-07 22:21:04 +00005706 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005707 goto cleanup;
5708 }
5709
5710
5711 if (k == 0)
cristy0c832c62014-03-07 22:21:04 +00005712 clStatus =clEnv->library->clSetKernelArg(hullPass1,0,sizeof(cl_mem),(void *)(tempImageBuffer));
cristyf034abb2013-11-24 14:16:14 +00005713 offset.s[0] = -X[k];
5714 offset.s[1] = -Y[k];
5715 polarity = 1;
cristy0c832c62014-03-07 22:21:04 +00005716 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5717 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5718 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5719 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005720 if (clStatus != CL_SUCCESS)
5721 {
cristy0c832c62014-03-07 22:21:04 +00005722 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005723 goto cleanup;
5724 }
5725 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005726 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005727 if (clStatus != CL_SUCCESS)
5728 {
cristy0c832c62014-03-07 22:21:04 +00005729 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005730 goto cleanup;
5731 }
5732 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005733 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005734 if (clStatus != CL_SUCCESS)
5735 {
cristy0c832c62014-03-07 22:21:04 +00005736 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005737 goto cleanup;
5738 }
5739
5740 offset.s[0] = -X[k];
5741 offset.s[1] = -Y[k];
5742 polarity = -1;
cristy0c832c62014-03-07 22:21:04 +00005743 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5744 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5745 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5746 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005747 if (clStatus != CL_SUCCESS)
5748 {
cristy0c832c62014-03-07 22:21:04 +00005749 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005750 goto cleanup;
5751 }
5752 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005753 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005754 if (clStatus != CL_SUCCESS)
5755 {
cristy0c832c62014-03-07 22:21:04 +00005756 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005757 goto cleanup;
5758 }
5759 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005760 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005761 if (clStatus != CL_SUCCESS)
5762 {
cristy0c832c62014-03-07 22:21:04 +00005763 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005764 goto cleanup;
5765 }
5766
5767 offset.s[0] = X[k];
5768 offset.s[1] = Y[k];
5769 polarity = -1;
cristy0c832c62014-03-07 22:21:04 +00005770 clStatus = clEnv->library->clSetKernelArg(hullPass1,4,sizeof(cl_int2),(void *)&offset);
5771 clStatus|= clEnv->library->clSetKernelArg(hullPass1,5,sizeof(int),(void *)&polarity);
5772 clStatus|=clEnv->library->clSetKernelArg(hullPass2,4,sizeof(cl_int2),(void *)&offset);
5773 clStatus|=clEnv->library->clSetKernelArg(hullPass2,5,sizeof(int),(void *)&polarity);
cristyf034abb2013-11-24 14:16:14 +00005774
5775 if (k == 3)
cristy0c832c62014-03-07 22:21:04 +00005776 clStatus |=clEnv->library->clSetKernelArg(hullPass2,1,sizeof(cl_mem),(void *)&filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005777
5778 if (clStatus != CL_SUCCESS)
5779 {
cristy0c832c62014-03-07 22:21:04 +00005780 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005781 goto cleanup;
5782 }
5783 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005784 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass1, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005785 if (clStatus != CL_SUCCESS)
5786 {
cristy0c832c62014-03-07 22:21:04 +00005787 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005788 goto cleanup;
5789 }
5790 /* launch the kernel */
cristy0c832c62014-03-07 22:21:04 +00005791 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, hullPass2, 2, NULL, global_work_size, NULL, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005792 if (clStatus != CL_SUCCESS)
5793 {
cristy0c832c62014-03-07 22:21:04 +00005794 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005795 goto cleanup;
5796 }
5797 }
5798
5799 if (ALIGNED(filteredPixels,CLPixelPacket))
5800 {
dirk8a5cf512014-07-28 20:16:27 +00005801 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00005802 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristyf034abb2013-11-24 14:16:14 +00005803 }
5804 else
5805 {
dirk8a5cf512014-07-28 20:16:27 +00005806 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00005807 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristyf034abb2013-11-24 14:16:14 +00005808 }
5809 if (clStatus != CL_SUCCESS)
5810 {
cristya22457d2013-12-07 14:03:06 +00005811 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristyf034abb2013-11-24 14:16:14 +00005812 goto cleanup;
5813 }
5814
dirk832becc2014-08-04 19:44:34 +00005815 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
5816
5817cleanup:
5818 OpenCLLogException(__FUNCTION__,__LINE__,exception);
5819
5820 image_view=DestroyCacheView(image_view);
5821 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00005822 filteredImage_view=DestroyCacheView(filteredImage_view);
cristya22457d2013-12-07 14:03:06 +00005823
cristyf034abb2013-11-24 14:16:14 +00005824 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
dirk8a5cf512014-07-28 20:16:27 +00005825 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005826 for (k = 0; k < 2; k++)
5827 {
cristy0c832c62014-03-07 22:21:04 +00005828 if (tempImageBuffer[k]!=NULL) clEnv->library->clReleaseMemObject(tempImageBuffer[k]);
cristyf034abb2013-11-24 14:16:14 +00005829 }
cristy0c832c62014-03-07 22:21:04 +00005830 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
cristyf034abb2013-11-24 14:16:14 +00005831 if (hullPass1!=NULL) RelinquishOpenCLKernel(clEnv, hullPass1);
5832 if (hullPass2!=NULL) RelinquishOpenCLKernel(clEnv, hullPass2);
dirk8a5cf512014-07-28 20:16:27 +00005833 if (outputReady == MagickFalse && filteredImage != NULL)
5834 filteredImage=DestroyImage(filteredImage);
5835 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00005836}
5837
dirk832becc2014-08-04 19:44:34 +00005838MagickExport Image *AccelerateDespeckleImage(const Image* image,
5839 ExceptionInfo* exception)
5840{
5841 Image
5842 *filteredImage;
5843
5844 assert(image != NULL);
5845 assert(exception != (ExceptionInfo *) NULL);
5846
5847 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
5848 (checkAccelerateCondition(image, AllChannels) == MagickFalse))
5849 return NULL;
5850
5851 filteredImage=ComputeDespeckleImage(image,exception);
5852 return(filteredImage);
cristyf034abb2013-11-24 14:16:14 +00005853}
5854
dirk832becc2014-08-04 19:44:34 +00005855static Image *ComputeAddNoiseImage(const Image *image,
5856 const ChannelType channel,const NoiseType noise_type,
5857 ExceptionInfo *exception)
5858{
5859 CacheView
5860 *filteredImage_view,
5861 *image_view;
5862
5863 cl_command_queue
5864 queue;
5865
5866 cl_context
5867 context;
5868
5869 cl_int
5870 clStatus;
5871
5872 cl_kernel
5873 addNoiseKernel;
5874
5875 cl_mem_flags
5876 mem_flags;
5877
5878 cl_mem
5879 filteredImageBuffer,
5880 imageBuffer,
5881 randomNumberBuffer;
5882
5883 const char
5884 *option;
5885
5886 const void
5887 *inputPixels;
5888
5889 float
5890 attenuate,
5891 *randomNumberBufferPtr;
5892
5893 MagickBooleanType
5894 outputReady;
5895
5896 MagickCLEnv
5897 clEnv;
5898
5899 MagickSizeType
5900 length;
5901
5902 Image
5903 *filteredImage;
5904
5905 int
5906 i;
5907
5908 RandomInfo
5909 **restrict random_info;
5910
5911 size_t
5912 global_work_size[2];
5913
5914 unsigned int
5915 inputColumns,
5916 inputRows,
5917 k,
5918 numRandomNumberPerBuffer,
5919 numRandomNumberPerPixel,
5920 numRowsPerKernelLaunch,
5921 r;
5922
5923#if defined(MAGICKCORE_OPENMP_SUPPORT)
5924 unsigned long
5925 key;
5926#endif
5927
5928 void
5929 *filteredPixels,
5930 *hostPtr;
5931
5932 outputReady = MagickFalse;
5933 clEnv = NULL;
5934 inputPixels = NULL;
5935 filteredImage = NULL;
5936 filteredImage_view = NULL;
5937 filteredPixels = NULL;
5938 randomNumberBufferPtr = NULL;
5939 context = NULL;
5940 imageBuffer = NULL;
5941 randomNumberBuffer = NULL;
5942 filteredImageBuffer = NULL;
5943 queue = NULL;
5944 addNoiseKernel = NULL;
5945
5946 clEnv = GetDefaultOpenCLEnv();
5947 context = GetOpenCLContext(clEnv);
5948 queue = AcquireOpenCLCommandQueue(clEnv);
5949
5950 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00005951 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristye85d0f72013-11-27 02:25:43 +00005952 if (inputPixels == (void *) NULL)
5953 {
dirk8a5cf512014-07-28 20:16:27 +00005954 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristye85d0f72013-11-27 02:25:43 +00005955 goto cleanup;
5956 }
5957
5958 if (ALIGNED(inputPixels,CLPixelPacket))
5959 {
5960 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
5961 }
5962 else
5963 {
5964 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
5965 }
5966 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00005967 length = image->columns * image->rows;
5968 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00005969 if (clStatus != CL_SUCCESS)
5970 {
cristy0c832c62014-03-07 22:21:04 +00005971 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00005972 goto cleanup;
5973 }
5974
5975
dirk8a5cf512014-07-28 20:16:27 +00005976 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristye85d0f72013-11-27 02:25:43 +00005977 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00005978 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristye85d0f72013-11-27 02:25:43 +00005979 {
cristya22457d2013-12-07 14:03:06 +00005980 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00005981 goto cleanup;
5982 }
dirk832becc2014-08-04 19:44:34 +00005983 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00005984 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristye85d0f72013-11-27 02:25:43 +00005985 if (filteredPixels == (void *) NULL)
5986 {
cristya22457d2013-12-07 14:03:06 +00005987 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristye85d0f72013-11-27 02:25:43 +00005988 goto cleanup;
5989 }
5990
5991 if (ALIGNED(filteredPixels,CLPixelPacket))
5992 {
5993 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
5994 hostPtr = filteredPixels;
5995 }
5996 else
5997 {
5998 mem_flags = CL_MEM_WRITE_ONLY;
5999 hostPtr = NULL;
6000 }
6001 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00006002 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006003 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00006004 if (clStatus != CL_SUCCESS)
6005 {
cristy0c832c62014-03-07 22:21:04 +00006006 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006007 goto cleanup;
6008 }
6009
6010 /* find out how many random numbers needed by pixel */
6011 numRandomNumberPerPixel = 0;
6012 {
6013 unsigned int numRandPerChannel = 0;
6014 switch (noise_type)
6015 {
6016 case UniformNoise:
6017 case ImpulseNoise:
6018 case LaplacianNoise:
6019 case RandomNoise:
6020 default:
6021 numRandPerChannel = 1;
6022 break;
6023 case GaussianNoise:
6024 case MultiplicativeGaussianNoise:
6025 case PoissonNoise:
6026 numRandPerChannel = 2;
6027 break;
6028 };
6029
6030 if ((channel & RedChannel) != 0)
6031 numRandomNumberPerPixel+=numRandPerChannel;
6032 if ((channel & GreenChannel) != 0)
6033 numRandomNumberPerPixel+=numRandPerChannel;
6034 if ((channel & BlueChannel) != 0)
6035 numRandomNumberPerPixel+=numRandPerChannel;
6036 if ((channel & OpacityChannel) != 0)
6037 numRandomNumberPerPixel+=numRandPerChannel;
6038 }
6039
6040 numRowsPerKernelLaunch = 512;
6041 /* create a buffer for random numbers */
dirk8a5cf512014-07-28 20:16:27 +00006042 numRandomNumberPerBuffer = (image->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel;
cristy0c832c62014-03-07 22:21:04 +00006043 randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, numRandomNumberPerBuffer*sizeof(float)
cristye85d0f72013-11-27 02:25:43 +00006044 , NULL, &clStatus);
6045
6046
6047 /* set up the random number generators */
6048 attenuate=1.0;
dirk8a5cf512014-07-28 20:16:27 +00006049 option=GetImageArtifact(image,"attenuate");
cristye85d0f72013-11-27 02:25:43 +00006050 if (option != (char *) NULL)
6051 attenuate=StringToDouble(option,(char **) NULL);
6052 random_info=AcquireRandomInfoThreadSet();
6053#if defined(MAGICKCORE_OPENMP_SUPPORT)
6054 key=GetRandomSecretKey(random_info[0]);
6055#endif
6056
6057 addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage");
6058
6059 k = 0;
dirk8a5cf512014-07-28 20:16:27 +00006060 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006061 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +00006062 inputColumns = image->columns;
cristy0c832c62014-03-07 22:21:04 +00006063 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns);
dirk8a5cf512014-07-28 20:16:27 +00006064 inputRows = image->rows;
cristy0c832c62014-03-07 22:21:04 +00006065 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows);
6066 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel);
6067 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type);
cristye85d0f72013-11-27 02:25:43 +00006068 attenuate=1.0f;
dirk8a5cf512014-07-28 20:16:27 +00006069 option=GetImageArtifact(image,"attenuate");
cristye85d0f72013-11-27 02:25:43 +00006070 if (option != (char *) NULL)
6071 attenuate=(float)StringToDouble(option,(char **) NULL);
cristy0c832c62014-03-07 22:21:04 +00006072 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate);
6073 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
6074 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel);
cristye85d0f72013-11-27 02:25:43 +00006075
6076 global_work_size[0] = inputColumns;
6077 for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch)
6078 {
6079 /* Generate random numbers in the buffer */
cristy0c832c62014-03-07 22:21:04 +00006080 randomNumberBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, randomNumberBuffer, CL_TRUE, CL_MAP_WRITE, 0
cristye85d0f72013-11-27 02:25:43 +00006081 , numRandomNumberPerBuffer*sizeof(float), 0, NULL, NULL, &clStatus);
6082 if (clStatus != CL_SUCCESS)
6083 {
cristy0c832c62014-03-07 22:21:04 +00006084 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006085 goto cleanup;
6086 }
6087
6088#if defined(MAGICKCORE_OPENMP_SUPPORT)
6089 #pragma omp parallel for schedule(static,4) \
6090 num_threads((key == ~0UL) == 0 ? 1 : (size_t) GetMagickResourceLimit(ThreadResource))
6091#endif
6092 for (i = 0; i < numRandomNumberPerBuffer; i++)
6093 {
6094 const int id = GetOpenMPThreadId();
6095 randomNumberBufferPtr[i] = (float)GetPseudoRandomValue(random_info[id]);
6096 }
6097
cristy0c832c62014-03-07 22:21:04 +00006098 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberBuffer, randomNumberBufferPtr, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00006099 if (clStatus != CL_SUCCESS)
6100 {
cristy0c832c62014-03-07 22:21:04 +00006101 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006102 goto cleanup;
6103 }
6104
6105 /* set the row offset */
cristy0c832c62014-03-07 22:21:04 +00006106 clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r);
cristye85d0f72013-11-27 02:25:43 +00006107 global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r);
cristy0c832c62014-03-07 22:21:04 +00006108 clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
cristye85d0f72013-11-27 02:25:43 +00006109 }
6110
6111 if (ALIGNED(filteredPixels,CLPixelPacket))
6112 {
dirk8a5cf512014-07-28 20:16:27 +00006113 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006114 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00006115 }
6116 else
6117 {
dirk8a5cf512014-07-28 20:16:27 +00006118 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006119 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00006120 }
6121 if (clStatus != CL_SUCCESS)
6122 {
cristya22457d2013-12-07 14:03:06 +00006123 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00006124 goto cleanup;
6125 }
6126
dirk832becc2014-08-04 19:44:34 +00006127 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
6128
6129cleanup:
6130 OpenCLLogException(__FUNCTION__,__LINE__,exception);
6131
6132 image_view=DestroyCacheView(image_view);
6133 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00006134 filteredImage_view=DestroyCacheView(filteredImage_view);
cristya22457d2013-12-07 14:03:06 +00006135
cristye85d0f72013-11-27 02:25:43 +00006136 if (queue!=NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
6137 if (addNoiseKernel!=NULL) RelinquishOpenCLKernel(clEnv, addNoiseKernel);
dirk8a5cf512014-07-28 20:16:27 +00006138 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006139 if (randomNumberBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberBuffer);
6140 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
dirk832becc2014-08-04 19:44:34 +00006141 if (outputReady == MagickFalse && filteredImage != NULL)
6142 filteredImage=DestroyImage(filteredImage);
6143
dirk8a5cf512014-07-28 20:16:27 +00006144 return(filteredImage);
cristye85d0f72013-11-27 02:25:43 +00006145}
6146
dirk832becc2014-08-04 19:44:34 +00006147static Image *ComputeAddNoiseImageOptRandomNum(const Image*image,
6148 const ChannelType channel,const NoiseType noise_type,
6149 ExceptionInfo *exception)
6150{
6151 CacheView
6152 *filteredImage_view,
6153 *image_view;
6154
6155 cl_command_queue
6156 queue;
6157
6158 cl_context
6159 context;
6160
6161 cl_int
6162 clStatus;
6163
6164 cl_kernel
6165 addNoiseKernel,
6166 randomNumberGeneratorKernel;
6167
6168 cl_mem
6169 filteredImageBuffer,
6170 imageBuffer,
6171 randomNumberBuffer,
6172 randomNumberSeedsBuffer;
6173
6174 cl_mem_flags
6175 mem_flags;
6176
6177 const char
6178 *option;
6179
6180 const void
6181 *inputPixels;
6182
6183 float
6184 attenuate,
6185 fNormalize;
6186
6187 Image
6188 *filteredImage;
6189
6190 int
6191 i;
6192
6193 MagickBooleanType
6194 outputReady;
6195
6196 MagickCLEnv
6197 clEnv;
6198
6199 MagickSizeType
6200 length;
6201
6202 size_t
6203 global_work_size[2],
6204 random_work_size;
6205
6206 unsigned int
6207 initRandom,
6208 inputColumns,
6209 inputRows,
6210 k,
6211 numRandomNumberGenerators,
6212 numRandomNumberPerBuffer,
6213 numRandomNumberPerPixel,
6214 numRowsPerKernelLaunch,
6215 r;
6216
6217 void
6218 *filteredPixels,
6219 *hostPtr;
6220
6221 outputReady = MagickFalse;
6222 clEnv = NULL;
6223 inputPixels = NULL;
6224 filteredImage = NULL;
6225 filteredImage_view = NULL;
6226 filteredPixels = NULL;
6227 context = NULL;
6228 imageBuffer = NULL;
6229 randomNumberBuffer = NULL;
6230 filteredImageBuffer = NULL;
6231 randomNumberSeedsBuffer = NULL;
6232 queue = NULL;
6233 addNoiseKernel = NULL;
6234 randomNumberGeneratorKernel = NULL;
6235
6236 clEnv = GetDefaultOpenCLEnv();
6237 context = GetOpenCLContext(clEnv);
6238 queue = AcquireOpenCLCommandQueue(clEnv);
6239
6240 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00006241 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristye85d0f72013-11-27 02:25:43 +00006242 if (inputPixels == (void *) NULL)
6243 {
dirk8a5cf512014-07-28 20:16:27 +00006244 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristye85d0f72013-11-27 02:25:43 +00006245 goto cleanup;
6246 }
6247
6248 if (ALIGNED(inputPixels,CLPixelPacket))
6249 {
6250 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
6251 }
6252 else
6253 {
6254 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
6255 }
6256 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00006257 length = image->columns * image->rows;
6258 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00006259 if (clStatus != CL_SUCCESS)
6260 {
cristy0c832c62014-03-07 22:21:04 +00006261 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006262 goto cleanup;
6263 }
6264
6265
dirk8a5cf512014-07-28 20:16:27 +00006266 filteredImage = CloneImage(image,image->columns,image->rows,MagickTrue,exception);
cristye85d0f72013-11-27 02:25:43 +00006267 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00006268 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristye85d0f72013-11-27 02:25:43 +00006269 {
cristya22457d2013-12-07 14:03:06 +00006270 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "CloneImage failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00006271 goto cleanup;
6272 }
dirk832becc2014-08-04 19:44:34 +00006273 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00006274 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristye85d0f72013-11-27 02:25:43 +00006275 if (filteredPixels == (void *) NULL)
6276 {
cristya22457d2013-12-07 14:03:06 +00006277 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning, "UnableToReadPixelCache.","`%s'",filteredImage->filename);
cristye85d0f72013-11-27 02:25:43 +00006278 goto cleanup;
6279 }
6280
6281 if (ALIGNED(filteredPixels,CLPixelPacket))
6282 {
6283 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
6284 hostPtr = filteredPixels;
6285 }
6286 else
6287 {
6288 mem_flags = CL_MEM_WRITE_ONLY;
6289 hostPtr = NULL;
6290 }
6291 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00006292 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006293 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), hostPtr, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00006294 if (clStatus != CL_SUCCESS)
6295 {
cristy0c832c62014-03-07 22:21:04 +00006296 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006297 goto cleanup;
6298 }
6299
6300 /* find out how many random numbers needed by pixel */
6301 numRandomNumberPerPixel = 0;
6302 {
6303 unsigned int numRandPerChannel = 0;
6304 switch (noise_type)
6305 {
6306 case UniformNoise:
6307 case ImpulseNoise:
6308 case LaplacianNoise:
6309 case RandomNoise:
6310 default:
6311 numRandPerChannel = 1;
6312 break;
6313 case GaussianNoise:
6314 case MultiplicativeGaussianNoise:
6315 case PoissonNoise:
6316 numRandPerChannel = 2;
6317 break;
6318 };
6319
6320 if ((channel & RedChannel) != 0)
6321 numRandomNumberPerPixel+=numRandPerChannel;
6322 if ((channel & GreenChannel) != 0)
6323 numRandomNumberPerPixel+=numRandPerChannel;
6324 if ((channel & BlueChannel) != 0)
6325 numRandomNumberPerPixel+=numRandPerChannel;
6326 if ((channel & OpacityChannel) != 0)
6327 numRandomNumberPerPixel+=numRandPerChannel;
6328 }
6329
6330 numRowsPerKernelLaunch = 512;
6331
6332 /* create a buffer for random numbers */
dirk8a5cf512014-07-28 20:16:27 +00006333 numRandomNumberPerBuffer = (image->columns*numRowsPerKernelLaunch)*numRandomNumberPerPixel;
cristy0c832c62014-03-07 22:21:04 +00006334 randomNumberBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_READ_WRITE, numRandomNumberPerBuffer*sizeof(float)
cristye85d0f72013-11-27 02:25:43 +00006335 , NULL, &clStatus);
6336
6337 {
6338 /* setup the random number generators */
6339 unsigned long* seeds;
6340 numRandomNumberGenerators = 512;
cristy0c832c62014-03-07 22:21:04 +00006341 randomNumberSeedsBuffer = clEnv->library->clCreateBuffer(context, CL_MEM_ALLOC_HOST_PTR|CL_MEM_READ_WRITE
cristye85d0f72013-11-27 02:25:43 +00006342 , numRandomNumberGenerators * 4 * sizeof(unsigned long), NULL, &clStatus);
6343 if (clStatus != CL_SUCCESS)
6344 {
cristy0c832c62014-03-07 22:21:04 +00006345 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006346 goto cleanup;
6347 }
cristy0c832c62014-03-07 22:21:04 +00006348 seeds = (unsigned long*) clEnv->library->clEnqueueMapBuffer(queue, randomNumberSeedsBuffer, CL_TRUE, CL_MAP_WRITE, 0
cristye85d0f72013-11-27 02:25:43 +00006349 , numRandomNumberGenerators*4*sizeof(unsigned long), 0, NULL, NULL, &clStatus);
6350 if (clStatus != CL_SUCCESS)
6351 {
cristy0c832c62014-03-07 22:21:04 +00006352 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueMapBuffer failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006353 goto cleanup;
6354 }
6355
6356 for (i = 0; i < numRandomNumberGenerators; i++) {
6357 RandomInfo* randomInfo = AcquireRandomInfo();
6358 const unsigned long* s = GetRandomInfoSeed(randomInfo);
6359
6360 if (i == 0)
6361 fNormalize = GetRandomInfoNormalize(randomInfo);
6362
6363 seeds[i*4] = s[0];
6364 randomInfo = DestroyRandomInfo(randomInfo);
6365 }
6366
cristy0c832c62014-03-07 22:21:04 +00006367 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, randomNumberSeedsBuffer, seeds, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00006368 if (clStatus != CL_SUCCESS)
6369 {
cristy0c832c62014-03-07 22:21:04 +00006370 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clEnqueueUnmapMemObject failed.",".");
cristye85d0f72013-11-27 02:25:43 +00006371 goto cleanup;
6372 }
6373
6374 randomNumberGeneratorKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE
6375 ,"randomNumberGeneratorKernel");
6376
6377 k = 0;
cristy0c832c62014-03-07 22:21:04 +00006378 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberSeedsBuffer);
6379 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(float),(void *)&fNormalize);
6380 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
cristye85d0f72013-11-27 02:25:43 +00006381 initRandom = 1;
cristy0c832c62014-03-07 22:21:04 +00006382 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&initRandom);
6383 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerBuffer);
cristye85d0f72013-11-27 02:25:43 +00006384
6385 random_work_size = numRandomNumberGenerators;
6386 }
6387
6388 addNoiseKernel = AcquireOpenCLKernel(clEnv,MAGICK_OPENCL_ACCELERATE,"AddNoiseImage");
6389 k = 0;
dirk8a5cf512014-07-28 20:16:27 +00006390 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006391 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +00006392 inputColumns = image->columns;
cristy0c832c62014-03-07 22:21:04 +00006393 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputColumns);
dirk8a5cf512014-07-28 20:16:27 +00006394 inputRows = image->rows;
cristy0c832c62014-03-07 22:21:04 +00006395 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&inputRows);
6396 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(ChannelType),(void *)&channel);
6397 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(NoiseType),(void *)&noise_type);
cristye85d0f72013-11-27 02:25:43 +00006398 attenuate=1.0f;
dirk8a5cf512014-07-28 20:16:27 +00006399 option=GetImageArtifact(image,"attenuate");
cristye85d0f72013-11-27 02:25:43 +00006400 if (option != (char *) NULL)
6401 attenuate=(float)StringToDouble(option,(char **) NULL);
cristy0c832c62014-03-07 22:21:04 +00006402 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(float),(void *)&attenuate);
6403 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(cl_mem),(void *)&randomNumberBuffer);
6404 clEnv->library->clSetKernelArg(addNoiseKernel,k++,sizeof(unsigned int),(void *)&numRandomNumberPerPixel);
cristye85d0f72013-11-27 02:25:43 +00006405
6406 global_work_size[0] = inputColumns;
6407 for (r = 0; r < inputRows; r+=numRowsPerKernelLaunch)
6408 {
6409 size_t generator_local_size = 64;
6410 /* Generate random numbers in the buffer */
cristy0c832c62014-03-07 22:21:04 +00006411 clEnv->library->clEnqueueNDRangeKernel(queue,randomNumberGeneratorKernel,1,NULL
cristye85d0f72013-11-27 02:25:43 +00006412 ,&random_work_size,&generator_local_size,0,NULL,NULL);
6413 if (initRandom != 0)
6414 {
6415 /* make sure we only do init once */
6416 initRandom = 0;
cristy0c832c62014-03-07 22:21:04 +00006417 clEnv->library->clSetKernelArg(randomNumberGeneratorKernel,3,sizeof(unsigned int),(void *)&initRandom);
cristye85d0f72013-11-27 02:25:43 +00006418 }
6419
6420 /* set the row offset */
cristy0c832c62014-03-07 22:21:04 +00006421 clEnv->library->clSetKernelArg(addNoiseKernel,k,sizeof(unsigned int),(void *)&r);
cristye85d0f72013-11-27 02:25:43 +00006422 global_work_size[1] = MAGICK_MIN(numRowsPerKernelLaunch, inputRows - r);
cristy0c832c62014-03-07 22:21:04 +00006423 clEnv->library->clEnqueueNDRangeKernel(queue,addNoiseKernel,2,NULL,global_work_size,NULL,0,NULL,NULL);
cristye85d0f72013-11-27 02:25:43 +00006424 }
6425
6426 if (ALIGNED(filteredPixels,CLPixelPacket))
6427 {
dirk8a5cf512014-07-28 20:16:27 +00006428 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006429 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristye85d0f72013-11-27 02:25:43 +00006430 }
6431 else
6432 {
dirk8a5cf512014-07-28 20:16:27 +00006433 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006434 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
cristye85d0f72013-11-27 02:25:43 +00006435 }
6436 if (clStatus != CL_SUCCESS)
6437 {
cristya22457d2013-12-07 14:03:06 +00006438 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
cristye85d0f72013-11-27 02:25:43 +00006439 goto cleanup;
6440 }
6441
dirk832becc2014-08-04 19:44:34 +00006442 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
6443
6444cleanup:
6445 OpenCLLogException(__FUNCTION__,__LINE__,exception);
6446
6447 image_view=DestroyCacheView(image_view);
6448 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00006449 filteredImage_view=DestroyCacheView(filteredImage_view);
cristya22457d2013-12-07 14:03:06 +00006450
cristye85d0f72013-11-27 02:25:43 +00006451 if (queue!=NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
6452 if (addNoiseKernel!=NULL) RelinquishOpenCLKernel(clEnv, addNoiseKernel);
6453 if (randomNumberGeneratorKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomNumberGeneratorKernel);
dirk8a5cf512014-07-28 20:16:27 +00006454 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006455 if (randomNumberBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberBuffer);
6456 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
6457 if (randomNumberSeedsBuffer!=NULL) clEnv->library->clReleaseMemObject(randomNumberSeedsBuffer);
dirk832becc2014-08-04 19:44:34 +00006458 if (outputReady == MagickFalse && filteredImage != NULL)
6459 filteredImage=DestroyImage(filteredImage);
6460
dirk8a5cf512014-07-28 20:16:27 +00006461 return(filteredImage);
cristye85d0f72013-11-27 02:25:43 +00006462}
6463
dirk832becc2014-08-04 19:44:34 +00006464MagickExport Image *AccelerateAddNoiseImage(const Image *image,
6465 const ChannelType channel,const NoiseType noise_type,
6466 ExceptionInfo *exception)
6467{
6468 Image
6469 *filteredImage;
6470
6471 assert(image != NULL);
6472 assert(exception != (ExceptionInfo *) NULL);
6473
6474 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
6475 (checkAccelerateCondition(image, channel) == MagickFalse))
6476 return NULL;
6477
6478DisableMSCWarning(4127)
6479 if (sizeof(unsigned long) == 4)
6480RestoreMSCWarning
6481 filteredImage = ComputeAddNoiseImageOptRandomNum(image,channel,noise_type,exception);
6482 else
6483 filteredImage = ComputeAddNoiseImage(image,channel,noise_type,exception);
6484
6485 return(filteredImage);
cristye85d0f72013-11-27 02:25:43 +00006486}
6487
dirk832becc2014-08-04 19:44:34 +00006488static MagickBooleanType LaunchRandomImageKernel(MagickCLEnv clEnv,
6489 cl_command_queue queue,cl_mem imageBuffer,const unsigned int imageColumns,
6490 const unsigned int imageRows,cl_mem seedBuffer,
6491 const unsigned int numGenerators,ExceptionInfo *exception)
6492{
6493 int
6494 k;
6495
6496 cl_int
6497 clStatus;
6498
6499 cl_kernel
6500 randomImageKernel;
6501
6502 MagickBooleanType
6503 status;
6504
6505 size_t
6506 global_work_size,
6507 local_work_size;
6508
dirk8a5cf512014-07-28 20:16:27 +00006509 status = MagickFalse;
cristy0c832c62014-03-07 22:21:04 +00006510 randomImageKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE, "RandomImage");
6511
6512 k = 0;
dirk8a5cf512014-07-28 20:16:27 +00006513 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006514 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageColumns);
6515 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_uint),(void*)&imageRows);
6516 clEnv->library->clSetKernelArg(randomImageKernel,k++,sizeof(cl_mem),(void*)&seedBuffer);
6517 {
6518 const float randNormNumerator = 1.0f;
6519 const unsigned int randNormDenominator = (unsigned int)(~0UL);
6520 clEnv->library->clSetKernelArg(randomImageKernel,k++,
6521 sizeof(float),(void*)&randNormNumerator);
6522 clEnv->library->clSetKernelArg(randomImageKernel,k++,
6523 sizeof(cl_uint),(void*)&randNormDenominator);
6524 }
6525
6526
6527 global_work_size = numGenerators;
6528 local_work_size = 64;
6529
6530 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue,randomImageKernel,1,NULL,&global_work_size,
6531 &local_work_size,0,NULL,NULL);
6532
6533 if (clStatus != CL_SUCCESS)
6534 {
6535 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning,
6536 "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
6537 goto cleanup;
6538 }
6539 status = MagickTrue;
6540
6541cleanup:
6542 if (randomImageKernel!=NULL) RelinquishOpenCLKernel(clEnv, randomImageKernel);
dirk832becc2014-08-04 19:44:34 +00006543 return(status);
6544}
6545
6546static MagickBooleanType ComputeRandomImage(Image* image,
6547 ExceptionInfo* exception)
6548{
6549 CacheView
6550 *image_view;
6551
6552 cl_command_queue
6553 queue;
6554
6555 cl_context
6556 context;
6557
6558 cl_int
6559 clStatus;
6560
6561 /* Don't release this buffer in this function !!! */
6562 cl_mem
6563 randomNumberSeedsBuffer;
6564
6565 cl_mem_flags
6566 mem_flags;
6567
6568 cl_mem
6569 imageBuffer;
6570
6571 MagickBooleanType
6572 outputReady,
6573 status;
6574
6575 MagickCLEnv
6576 clEnv;
6577
6578 MagickSizeType
6579 length;
6580
6581 void
6582 *inputPixels;
6583
6584 status = MagickFalse;
6585 outputReady = MagickFalse;
6586 inputPixels = NULL;
6587 context = NULL;
6588 imageBuffer = NULL;
6589 queue = NULL;
6590
6591 clEnv = GetDefaultOpenCLEnv();
6592 context = GetOpenCLContext(clEnv);
6593
6594 /* Create and initialize OpenCL buffers. */
6595 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00006596 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00006597 if (inputPixels == (void *) NULL)
6598 {
dirk8a5cf512014-07-28 20:16:27 +00006599 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,"UnableToReadPixelCache.","`%s'",image->filename);
cristy0c832c62014-03-07 22:21:04 +00006600 goto cleanup;
6601 }
6602
6603 /* If the host pointer is aligned to the size of CLPixelPacket,
6604 then use the host buffer directly from the GPU; otherwise,
6605 create a buffer on the GPU and copy the data over */
6606 if (ALIGNED(inputPixels,CLPixelPacket))
6607 {
6608 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
6609 }
6610 else
6611 {
6612 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
6613 }
6614 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00006615 length = image->columns * image->rows;
6616 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags, length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00006617 if (clStatus != CL_SUCCESS)
6618 {
6619 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
6620 goto cleanup;
6621 }
6622
6623 queue = AcquireOpenCLCommandQueue(clEnv);
6624
6625 randomNumberSeedsBuffer = GetAndLockRandSeedBuffer(clEnv);
6626 if (randomNumberSeedsBuffer==NULL)
6627 {
6628 (void) OpenCLThrowMagickException(exception, GetMagickModule(),
6629 ResourceLimitWarning, "Failed to get GPU random number generators.",
6630 "'%s'", ".");
6631 goto cleanup;
6632 }
6633
6634 status = LaunchRandomImageKernel(clEnv,queue,
dirk8a5cf512014-07-28 20:16:27 +00006635 imageBuffer,
6636 image->columns,
6637 image->rows,
cristy0c832c62014-03-07 22:21:04 +00006638 randomNumberSeedsBuffer,
6639 GetNumRandGenerators(clEnv),
6640 exception);
6641 if (status==MagickFalse)
6642 {
6643 goto cleanup;
6644 }
6645
6646 if (ALIGNED(inputPixels,CLPixelPacket))
6647 {
dirk8a5cf512014-07-28 20:16:27 +00006648 length = image->columns * image->rows;
6649 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE, CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL, NULL, &clStatus);
cristy0c832c62014-03-07 22:21:04 +00006650 }
6651 else
6652 {
dirk8a5cf512014-07-28 20:16:27 +00006653 length = image->columns * image->rows;
6654 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0, length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
cristy0c832c62014-03-07 22:21:04 +00006655 }
6656 if (clStatus != CL_SUCCESS)
6657 {
6658 (void) OpenCLThrowMagickException(exception, GetMagickModule(), ResourceLimitWarning, "Reading output image from CL buffer failed.", "'%s'", ".");
6659 goto cleanup;
6660 }
dirk832becc2014-08-04 19:44:34 +00006661 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
6662
6663cleanup:
6664 OpenCLLogException(__FUNCTION__,__LINE__,exception);
6665
dirk8a5cf512014-07-28 20:16:27 +00006666 image_view=DestroyCacheView(image_view);
cristy0c832c62014-03-07 22:21:04 +00006667
6668 UnlockRandSeedBuffer(clEnv);
dirk8a5cf512014-07-28 20:16:27 +00006669 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006670 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
6671 return outputReady;
6672}
6673
dirk832becc2014-08-04 19:44:34 +00006674MagickExport MagickBooleanType AccelerateRandomImage(Image *image,
6675 ExceptionInfo* exception)
6676{
6677 MagickBooleanType
6678 status;
6679
6680 assert(image != NULL);
6681 assert(exception != (ExceptionInfo *) NULL);
6682
6683 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
6684 (checkAccelerateCondition(image, AllChannels) == MagickFalse))
6685 return(MagickFalse);
6686
6687 status=ComputeRandomImage(image,exception);
6688 return(status);
cristy0c832c62014-03-07 22:21:04 +00006689}
6690
dirk832becc2014-08-04 19:44:34 +00006691static Image* ComputeMotionBlurImage(const Image *image,
6692 const ChannelType channel,const double *kernel,const size_t width,
6693 const OffsetInfo *offset,ExceptionInfo *exception)
6694{
6695 CacheView
6696 *filteredImage_view,
6697 *image_view;
6698
6699 cl_command_queue
6700 queue;
6701
6702 cl_context
6703 context;
6704
6705 cl_float4
6706 biasPixel;
6707
6708 cl_int
6709 clStatus;
6710
6711 cl_kernel
6712 motionBlurKernel;
6713
6714 cl_mem
6715 filteredImageBuffer,
6716 imageBuffer,
6717 imageKernelBuffer,
6718 offsetBuffer;
6719
6720 cl_mem_flags
6721 mem_flags;
6722
6723 const void
6724 *inputPixels;
6725
6726 float
6727 *kernelBufferPtr;
6728
6729 Image
6730 *filteredImage;
6731
6732 int
6733 *offsetBufferPtr;
6734
6735 MagickBooleanType
6736 outputReady;
6737
6738 MagickCLEnv
6739 clEnv;
6740
6741 PixelInfo
6742 bias;
6743
6744 MagickSizeType
6745 length;
6746
6747 size_t
6748 global_work_size[2],
6749 local_work_size[2];
6750
6751 unsigned int
6752 i,
6753 imageHeight,
6754 imageWidth,
6755 matte;
6756
6757 void
6758 *filteredPixels,
6759 *hostPtr;
6760
6761 outputReady = MagickFalse;
6762 context = NULL;
6763 filteredImage = NULL;
6764 filteredImage_view = NULL;
6765 imageBuffer = NULL;
6766 filteredImageBuffer = NULL;
6767 imageKernelBuffer = NULL;
6768 motionBlurKernel = NULL;
6769 queue = NULL;
6770
6771 clEnv = GetDefaultOpenCLEnv();
6772 context = GetOpenCLContext(clEnv);
6773
6774 /* Create and initialize OpenCL buffers. */
6775
6776 image_view=AcquireVirtualCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00006777 inputPixels=GetCacheViewVirtualPixels(image_view,0,0,image->columns,image->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00006778 if (inputPixels == (const void *) NULL)
6779 {
6780 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
dirk8a5cf512014-07-28 20:16:27 +00006781 "UnableToReadPixelCache.","`%s'",image->filename);
cristy0c832c62014-03-07 22:21:04 +00006782 goto cleanup;
6783 }
6784
6785 // If the host pointer is aligned to the size of CLPixelPacket,
6786 // then use the host buffer directly from the GPU; otherwise,
6787 // create a buffer on the GPU and copy the data over
6788 if (ALIGNED(inputPixels,CLPixelPacket))
6789 {
6790 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
6791 }
6792 else
6793 {
6794 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
6795 }
6796 // create a CL buffer from image pixel buffer
dirk8a5cf512014-07-28 20:16:27 +00006797 length = image->columns * image->rows;
6798 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
cristy0c832c62014-03-07 22:21:04 +00006799 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
6800 if (clStatus != CL_SUCCESS)
6801 {
6802 (void) ThrowMagickException(exception, GetMagickModule(),
6803 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6804 goto cleanup;
6805 }
6806
6807
dirk8a5cf512014-07-28 20:16:27 +00006808 filteredImage = CloneImage(image,image->columns,image->rows,
cristy0c832c62014-03-07 22:21:04 +00006809 MagickTrue,exception);
6810 assert(filteredImage != NULL);
dirk8a5cf512014-07-28 20:16:27 +00006811 if (SetImageStorageClass(filteredImage,DirectClass,exception) != MagickTrue)
cristy0c832c62014-03-07 22:21:04 +00006812 {
6813 (void) ThrowMagickException(exception, GetMagickModule(),
6814 ResourceLimitError, "CloneImage failed.", "'%s'", ".");
6815 goto cleanup;
6816 }
dirk832becc2014-08-04 19:44:34 +00006817 filteredImage_view=AcquireAuthenticCacheView(filteredImage,exception);
dirk8a5cf512014-07-28 20:16:27 +00006818 filteredPixels=GetCacheViewAuthenticPixels(filteredImage_view,0,0,filteredImage->columns,filteredImage->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00006819 if (filteredPixels == (void *) NULL)
6820 {
6821 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
6822 "UnableToReadPixelCache.","`%s'",filteredImage->filename);
6823 goto cleanup;
6824 }
6825
6826 if (ALIGNED(filteredPixels,CLPixelPacket))
6827 {
6828 mem_flags = CL_MEM_WRITE_ONLY|CL_MEM_USE_HOST_PTR;
6829 hostPtr = filteredPixels;
6830 }
6831 else
6832 {
6833 mem_flags = CL_MEM_WRITE_ONLY;
6834 hostPtr = NULL;
6835 }
6836 // create a CL buffer from image pixel buffer
dirk8a5cf512014-07-28 20:16:27 +00006837 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006838 filteredImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
6839 length * sizeof(CLPixelPacket), hostPtr, &clStatus);
6840 if (clStatus != CL_SUCCESS)
6841 {
6842 (void) ThrowMagickException(exception, GetMagickModule(),
6843 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6844 goto cleanup;
6845 }
6846
6847
6848 imageKernelBuffer = clEnv->library->clCreateBuffer(context,
6849 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(float), NULL,
6850 &clStatus);
6851 if (clStatus != CL_SUCCESS)
6852 {
6853 (void) ThrowMagickException(exception, GetMagickModule(),
6854 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6855 goto cleanup;
6856 }
6857
6858 queue = AcquireOpenCLCommandQueue(clEnv);
6859 kernelBufferPtr = (float*)clEnv->library->clEnqueueMapBuffer(queue, imageKernelBuffer,
6860 CL_TRUE, CL_MAP_WRITE, 0, width * sizeof(float), 0, NULL, NULL, &clStatus);
6861 if (clStatus != CL_SUCCESS)
6862 {
6863 (void) ThrowMagickException(exception, GetMagickModule(),
6864 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
6865 goto cleanup;
6866 }
6867 for (i = 0; i < width; i++)
6868 {
6869 kernelBufferPtr[i] = (float) kernel[i];
6870 }
6871 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, imageKernelBuffer, kernelBufferPtr,
6872 0, NULL, NULL);
6873 if (clStatus != CL_SUCCESS)
6874 {
6875 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6876 "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
6877 goto cleanup;
6878 }
6879
6880 offsetBuffer = clEnv->library->clCreateBuffer(context,
6881 CL_MEM_READ_ONLY|CL_MEM_ALLOC_HOST_PTR, width * sizeof(cl_int2), NULL,
6882 &clStatus);
6883 if (clStatus != CL_SUCCESS)
6884 {
6885 (void) ThrowMagickException(exception, GetMagickModule(),
6886 ResourceLimitError, "clEnv->library->clCreateBuffer failed.",".");
6887 goto cleanup;
6888 }
6889
6890 offsetBufferPtr = (int*)clEnv->library->clEnqueueMapBuffer(queue, offsetBuffer, CL_TRUE,
6891 CL_MAP_WRITE, 0, width * sizeof(cl_int2), 0, NULL, NULL, &clStatus);
6892 if (clStatus != CL_SUCCESS)
6893 {
6894 (void) ThrowMagickException(exception, GetMagickModule(),
6895 ResourceLimitError, "clEnv->library->clEnqueueMapBuffer failed.",".");
6896 goto cleanup;
6897 }
6898 for (i = 0; i < width; i++)
6899 {
6900 offsetBufferPtr[2*i] = (int)offset[i].x;
6901 offsetBufferPtr[2*i+1] = (int)offset[i].y;
6902 }
6903 clStatus = clEnv->library->clEnqueueUnmapMemObject(queue, offsetBuffer, offsetBufferPtr, 0,
6904 NULL, NULL);
6905 if (clStatus != CL_SUCCESS)
6906 {
6907 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6908 "clEnv->library->clEnqueueUnmapMemObject failed.", "'%s'", ".");
6909 goto cleanup;
6910 }
6911
6912
6913 // get the OpenCL kernel
6914 motionBlurKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE,
6915 "MotionBlur");
6916 if (motionBlurKernel == NULL)
6917 {
6918 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6919 "AcquireOpenCLKernel failed.", "'%s'", ".");
6920 goto cleanup;
6921 }
6922
6923 // set the kernel arguments
6924 i = 0;
6925 clStatus=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
dirk8a5cf512014-07-28 20:16:27 +00006926 (void *)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00006927 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6928 (void *)&filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +00006929 imageWidth = image->columns;
6930 imageHeight = image->rows;
cristy0c832c62014-03-07 22:21:04 +00006931 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6932 &imageWidth);
6933 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6934 &imageHeight);
6935 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6936 (void *)&imageKernelBuffer);
6937 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int),
6938 &width);
6939 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_mem),
6940 (void *)&offsetBuffer);
6941
dirk8a5cf512014-07-28 20:16:27 +00006942 GetPixelInfo(image,&bias);
cristy0c832c62014-03-07 22:21:04 +00006943 biasPixel.s[0] = bias.red;
6944 biasPixel.s[1] = bias.green;
6945 biasPixel.s[2] = bias.blue;
dirk8a5cf512014-07-28 20:16:27 +00006946 biasPixel.s[3] = bias.alpha;
cristy0c832c62014-03-07 22:21:04 +00006947 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(cl_float4), &biasPixel);
6948
6949 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(ChannelType), &channel);
dirk8a5cf512014-07-28 20:16:27 +00006950 matte = (image->alpha_trait==BlendPixelTrait)?1:0;
cristy0c832c62014-03-07 22:21:04 +00006951 clStatus|=clEnv->library->clSetKernelArg(motionBlurKernel,i++,sizeof(unsigned int), &matte);
6952 if (clStatus != CL_SUCCESS)
6953 {
6954 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6955 "clEnv->library->clSetKernelArg failed.", "'%s'", ".");
6956 goto cleanup;
6957 }
6958
6959 // launch the kernel
6960 local_work_size[0] = 16;
6961 local_work_size[1] = 16;
6962 global_work_size[0] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
dirk8a5cf512014-07-28 20:16:27 +00006963 image->columns,local_work_size[0]);
cristy0c832c62014-03-07 22:21:04 +00006964 global_work_size[1] = (size_t)padGlobalWorkgroupSizeToLocalWorkgroupSize(
dirk8a5cf512014-07-28 20:16:27 +00006965 image->rows,local_work_size[1]);
cristy0c832c62014-03-07 22:21:04 +00006966 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, motionBlurKernel, 2, NULL,
6967 global_work_size, local_work_size, 0, NULL, NULL);
6968
6969 if (clStatus != CL_SUCCESS)
6970 {
6971 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6972 "clEnv->library->clEnqueueNDRangeKernel failed.", "'%s'", ".");
6973 goto cleanup;
6974 }
6975 clEnv->library->clFlush(queue);
6976
6977 if (ALIGNED(filteredPixels,CLPixelPacket))
6978 {
dirk8a5cf512014-07-28 20:16:27 +00006979 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006980 clEnv->library->clEnqueueMapBuffer(queue, filteredImageBuffer, CL_TRUE,
6981 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
6982 NULL, &clStatus);
6983 }
6984 else
6985 {
dirk8a5cf512014-07-28 20:16:27 +00006986 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00006987 clStatus = clEnv->library->clEnqueueReadBuffer(queue, filteredImageBuffer, CL_TRUE, 0,
6988 length * sizeof(CLPixelPacket), filteredPixels, 0, NULL, NULL);
6989 }
6990 if (clStatus != CL_SUCCESS)
6991 {
6992 (void) ThrowMagickException(exception, GetMagickModule(), ModuleFatalError,
6993 "Reading output image from CL buffer failed.", "'%s'", ".");
6994 goto cleanup;
6995 }
dirk832becc2014-08-04 19:44:34 +00006996 outputReady=SyncCacheViewAuthenticPixels(filteredImage_view,exception);
6997
6998cleanup:
6999
7000 image_view=DestroyCacheView(image_view);
7001 if (filteredImage_view != NULL)
dirk8a5cf512014-07-28 20:16:27 +00007002 filteredImage_view=DestroyCacheView(filteredImage_view);
cristy0c832c62014-03-07 22:21:04 +00007003
7004 if (filteredImageBuffer!=NULL) clEnv->library->clReleaseMemObject(filteredImageBuffer);
dirk8a5cf512014-07-28 20:16:27 +00007005 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00007006 if (imageKernelBuffer!=NULL) clEnv->library->clReleaseMemObject(imageKernelBuffer);
7007 if (motionBlurKernel!=NULL) RelinquishOpenCLKernel(clEnv, motionBlurKernel);
7008 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
dirk832becc2014-08-04 19:44:34 +00007009 if (outputReady == MagickFalse && filteredImage != NULL)
7010 filteredImage=DestroyImage(filteredImage);
7011
dirk8a5cf512014-07-28 20:16:27 +00007012 return(filteredImage);
cristy0c832c62014-03-07 22:21:04 +00007013}
7014
dirk832becc2014-08-04 19:44:34 +00007015MagickExport Image *AccelerateMotionBlurImage(const Image *image,
7016 const ChannelType channel,const double* kernel,const size_t width,
7017 const OffsetInfo *offset,ExceptionInfo *exception)
7018{
7019 Image
7020 *filteredImage;
7021
7022 assert(image != NULL);
7023 assert(kernel != (double *) NULL);
7024 assert(offset != (OffsetInfo *) NULL);
7025 assert(exception != (ExceptionInfo *) NULL);
7026
7027 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
7028 (checkAccelerateCondition(image, channel) == MagickFalse))
7029 return NULL;
7030
7031 filteredImage=ComputeMotionBlurImage(image, channel, kernel, width,
7032 offset, exception);
7033 return(filteredImage);
cristy0c832c62014-03-07 22:21:04 +00007034}
7035
dirk832becc2014-08-04 19:44:34 +00007036static MagickBooleanType LaunchCompositeKernel(MagickCLEnv clEnv,
7037 cl_command_queue queue,cl_mem imageBuffer,const unsigned int inputWidth,
7038 const unsigned int inputHeight,const unsigned int matte,
7039 const ChannelType channel,const CompositeOperator compose,
7040 const cl_mem compositeImageBuffer,const unsigned int compositeWidth,
7041 const unsigned int compositeHeight,const float destination_dissolve,
7042 const float source_dissolve,ExceptionInfo *magick_unused(exception))
7043{
7044 cl_int
7045 clStatus;
7046
7047 cl_kernel
7048 compositeKernel;
7049
7050 int
7051 k;
7052
7053 size_t
7054 global_work_size[2],
7055 local_work_size[2];
7056
7057 unsigned int
7058 composeOp;
7059
cristy0c832c62014-03-07 22:21:04 +00007060 magick_unreferenced(exception);
7061
7062 compositeKernel = AcquireOpenCLKernel(clEnv, MAGICK_OPENCL_ACCELERATE,
7063 "Composite");
7064
7065 k = 0;
dirk8a5cf512014-07-28 20:16:27 +00007066 clStatus=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00007067 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputWidth);
7068 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&inputHeight);
7069 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(cl_mem),(void*)&compositeImageBuffer);
7070 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeWidth);
7071 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&compositeHeight);
7072 composeOp = (unsigned int)compose;
7073 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&composeOp);
7074 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(ChannelType),(void*)&channel);
7075 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(unsigned int),(void*)&matte);
7076 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&destination_dissolve);
7077 clStatus|=clEnv->library->clSetKernelArg(compositeKernel,k++,sizeof(float),(void*)&source_dissolve);
7078
7079 if (clStatus!=CL_SUCCESS)
7080 return MagickFalse;
7081
7082 local_work_size[0] = 64;
7083 local_work_size[1] = 1;
7084
7085 global_work_size[0] = padGlobalWorkgroupSizeToLocalWorkgroupSize(inputWidth,
7086 local_work_size[0]);
7087 global_work_size[1] = inputHeight;
7088 clStatus = clEnv->library->clEnqueueNDRangeKernel(queue, compositeKernel, 2, NULL,
7089 global_work_size, local_work_size, 0, NULL, NULL);
7090
7091
7092 RelinquishOpenCLKernel(clEnv, compositeKernel);
7093
dirk832becc2014-08-04 19:44:34 +00007094 return((clStatus==CL_SUCCESS) ? MagickTrue : MagickFalse);
7095}
7096
7097static MagickBooleanType ComputeCompositeImage(Image *image,
7098 const ChannelType channel,const CompositeOperator compose,
7099 const Image *compositeImage,const ssize_t magick_unused(x_offset),
7100 const ssize_t magick_unused(y_offset),const float destination_dissolve,
7101 const float source_dissolve,ExceptionInfo *exception)
7102{
7103 CacheView
7104 *image_view;
7105
7106 cl_command_queue
7107 queue;
7108
7109 cl_context
7110 context;
7111
7112 cl_int
7113 clStatus;
7114
7115 cl_mem_flags
7116 mem_flags;
7117
7118 cl_mem
7119 compositeImageBuffer,
7120 imageBuffer;
7121
7122 const void
7123 *composePixels;
7124
7125 MagickBooleanType
7126 outputReady,
7127 status;
7128
7129 MagickCLEnv
7130 clEnv;
7131
7132 MagickSizeType
7133 length;
7134
7135 void
7136 *inputPixels;
7137
7138 magick_unreferenced(x_offset);
7139 magick_unreferenced(y_offset);
7140
7141 status = MagickFalse;
7142 outputReady = MagickFalse;
7143 composePixels = NULL;
7144 imageBuffer = NULL;
7145 compositeImageBuffer = NULL;
7146
7147 clEnv = GetDefaultOpenCLEnv();
7148 context = GetOpenCLContext(clEnv);
7149 queue = AcquireOpenCLCommandQueue(clEnv);
7150
7151 /* Create and initialize OpenCL buffers. */
7152 image_view=AcquireAuthenticCacheView(image,exception);
dirk8a5cf512014-07-28 20:16:27 +00007153 inputPixels=GetCacheViewAuthenticPixels(image_view,0,0,image->columns,image->rows,exception);
cristy0c832c62014-03-07 22:21:04 +00007154 if (inputPixels == (void *) NULL)
7155 {
7156 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,
dirk8a5cf512014-07-28 20:16:27 +00007157 "UnableToReadPixelCache.","`%s'",image->filename);
cristy0c832c62014-03-07 22:21:04 +00007158 goto cleanup;
7159 }
7160
7161 /* If the host pointer is aligned to the size of CLPixelPacket,
7162 then use the host buffer directly from the GPU; otherwise,
7163 create a buffer on the GPU and copy the data over */
7164 if (ALIGNED(inputPixels,CLPixelPacket))
7165 {
7166 mem_flags = CL_MEM_READ_WRITE|CL_MEM_USE_HOST_PTR;
7167 }
7168 else
7169 {
7170 mem_flags = CL_MEM_READ_WRITE|CL_MEM_COPY_HOST_PTR;
7171 }
7172 /* create a CL buffer from image pixel buffer */
dirk8a5cf512014-07-28 20:16:27 +00007173 length = image->columns * image->rows;
7174 imageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
cristy0c832c62014-03-07 22:21:04 +00007175 length * sizeof(CLPixelPacket), (void*)inputPixels, &clStatus);
7176 if (clStatus != CL_SUCCESS)
7177 {
7178 (void) OpenCLThrowMagickException(exception, GetMagickModule(),
7179 ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
7180 goto cleanup;
7181 }
7182
7183
7184 /* Create and initialize OpenCL buffers. */
7185 composePixels = AcquirePixelCachePixels(compositeImage, &length, exception);
7186 if (composePixels == (void *) NULL)
7187 {
7188 (void) OpenCLThrowMagickException(exception,GetMagickModule(),CacheWarning,
7189 "UnableToReadPixelCache.","`%s'",compositeImage->filename);
7190 goto cleanup;
7191 }
7192
7193 /* If the host pointer is aligned to the size of CLPixelPacket,
7194 then use the host buffer directly from the GPU; otherwise,
7195 create a buffer on the GPU and copy the data over */
7196 if (ALIGNED(composePixels,CLPixelPacket))
7197 {
7198 mem_flags = CL_MEM_READ_ONLY|CL_MEM_USE_HOST_PTR;
7199 }
7200 else
7201 {
7202 mem_flags = CL_MEM_READ_ONLY|CL_MEM_COPY_HOST_PTR;
7203 }
7204 /* create a CL buffer from image pixel buffer */
7205 length = compositeImage->columns * compositeImage->rows;
7206 compositeImageBuffer = clEnv->library->clCreateBuffer(context, mem_flags,
7207 length * sizeof(CLPixelPacket), (void*)composePixels, &clStatus);
7208 if (clStatus != CL_SUCCESS)
7209 {
7210 (void) OpenCLThrowMagickException(exception, GetMagickModule(),
7211 ResourceLimitWarning, "clEnv->library->clCreateBuffer failed.",".");
7212 goto cleanup;
7213 }
7214
dirk8a5cf512014-07-28 20:16:27 +00007215 status = LaunchCompositeKernel(clEnv,queue,imageBuffer,
7216 (unsigned int) image->columns,
7217 (unsigned int) image->rows,
7218 (unsigned int) (image->alpha_trait==BlendPixelTrait) ? 1 : 0,
cristy0c832c62014-03-07 22:21:04 +00007219 channel, compose, compositeImageBuffer,
7220 (unsigned int) compositeImage->columns,
7221 (unsigned int) compositeImage->rows,
7222 destination_dissolve,source_dissolve,
7223 exception);
7224
7225 if (status==MagickFalse)
7226 goto cleanup;
7227
dirk8a5cf512014-07-28 20:16:27 +00007228 length = image->columns * image->rows;
cristy0c832c62014-03-07 22:21:04 +00007229 if (ALIGNED(inputPixels,CLPixelPacket))
7230 {
dirk8a5cf512014-07-28 20:16:27 +00007231 clEnv->library->clEnqueueMapBuffer(queue, imageBuffer, CL_TRUE,
cristy0c832c62014-03-07 22:21:04 +00007232 CL_MAP_READ|CL_MAP_WRITE, 0, length * sizeof(CLPixelPacket), 0, NULL,
7233 NULL, &clStatus);
7234 }
7235 else
7236 {
dirk8a5cf512014-07-28 20:16:27 +00007237 clStatus = clEnv->library->clEnqueueReadBuffer(queue, imageBuffer, CL_TRUE, 0,
cristy0c832c62014-03-07 22:21:04 +00007238 length * sizeof(CLPixelPacket), inputPixels, 0, NULL, NULL);
7239 }
7240 if (clStatus==CL_SUCCESS)
dirk832becc2014-08-04 19:44:34 +00007241 outputReady=SyncCacheViewAuthenticPixels(image_view,exception);
7242
7243cleanup:
7244
7245 image_view=DestroyCacheView(image_view);
dirk8a5cf512014-07-28 20:16:27 +00007246 if (imageBuffer!=NULL) clEnv->library->clReleaseMemObject(imageBuffer);
cristy0c832c62014-03-07 22:21:04 +00007247 if (compositeImageBuffer!=NULL) clEnv->library->clReleaseMemObject(compositeImageBuffer);
7248 if (queue != NULL) RelinquishOpenCLCommandQueue(clEnv, queue);
7249
dirk832becc2014-08-04 19:44:34 +00007250 return(outputReady);
7251}
7252
7253MagickExport MagickBooleanType AccelerateCompositeImage(Image *image,
7254 const ChannelType channel,const CompositeOperator compose,
7255 const Image *composite,const ssize_t x_offset,const ssize_t y_offset,
7256 const float destination_dissolve,const float source_dissolve,
7257 ExceptionInfo *exception)
7258{
7259 MagickBooleanType
7260 status;
7261
7262 assert(image != NULL);
7263 assert(exception != (ExceptionInfo *) NULL);
7264
7265 if ((checkOpenCLEnvironment(exception) == MagickFalse) ||
7266 (checkAccelerateCondition(image, channel) == MagickFalse))
dirk8a5cf512014-07-28 20:16:27 +00007267 return(MagickFalse);
cristy0c832c62014-03-07 22:21:04 +00007268
7269 /* only support zero offset and
7270 images with the size for now */
7271 if (x_offset!=0
7272 || y_offset!=0
7273 || image->columns!=composite->columns
7274 || image->rows!=composite->rows)
7275 return MagickFalse;
7276
7277 switch(compose) {
7278 case ColorDodgeCompositeOp:
7279 case BlendCompositeOp:
7280 break;
7281 default:
7282 // unsupported compose operator, quit
7283 return MagickFalse;
7284 };
7285
7286 status = ComputeCompositeImage(image,channel,compose,composite,
7287 x_offset,y_offset,destination_dissolve,source_dissolve,exception);
7288
dirk8a5cf512014-07-28 20:16:27 +00007289 return(status);
cristy0c832c62014-03-07 22:21:04 +00007290}
7291
cristyf034abb2013-11-24 14:16:14 +00007292#else /* MAGICKCORE_OPENCL_SUPPORT */
7293
7294MagickExport Image *AccelerateConvolveImageChannel(
7295 const Image *magick_unused(image),const ChannelType magick_unused(channel),
7296 const KernelInfo *magick_unused(kernel),
7297 ExceptionInfo *magick_unused(exception))
7298{
7299 magick_unreferenced(image);
7300 magick_unreferenced(channel);
7301 magick_unreferenced(kernel);
7302 magick_unreferenced(exception);
7303
7304 return NULL;
7305}
7306
7307MagickExport MagickBooleanType AccelerateFunctionImage(
7308 Image *magick_unused(image),const ChannelType magick_unused(channel),
7309 const MagickFunction magick_unused(function),
7310 const size_t magick_unused(number_parameters),
7311 const double *magick_unused(parameters),
7312 ExceptionInfo *magick_unused(exception))
7313{
7314 magick_unreferenced(image);
7315 magick_unreferenced(channel);
7316 magick_unreferenced(function);
7317 magick_unreferenced(number_parameters);
7318 magick_unreferenced(parameters);
7319 magick_unreferenced(exception);
7320
7321 return MagickFalse;
7322}
7323
7324MagickExport Image *AccelerateBlurImage(const Image *magick_unused(image),
7325 const ChannelType magick_unused(channel),const double magick_unused(radius),
7326 const double magick_unused(sigma),ExceptionInfo *magick_unused(exception))
7327{
7328 magick_unreferenced(image);
7329 magick_unreferenced(channel);
7330 magick_unreferenced(radius);
7331 magick_unreferenced(sigma);
7332 magick_unreferenced(exception);
7333
7334 return NULL;
7335}
7336
dirk6d612cf2014-03-13 21:17:23 +00007337MagickExport Image *AccelerateRotationalBlurImage(
cristyf034abb2013-11-24 14:16:14 +00007338 const Image *magick_unused(image),const ChannelType magick_unused(channel),
7339 const double magick_unused(angle),ExceptionInfo *magick_unused(exception))
7340{
7341 magick_unreferenced(image);
7342 magick_unreferenced(channel);
7343 magick_unreferenced(angle);
7344 magick_unreferenced(exception);
7345
7346 return NULL;
7347}
7348
7349
7350MagickExport Image *AccelerateUnsharpMaskImage(
7351 const Image *magick_unused(image),const ChannelType magick_unused(channel),
7352 const double magick_unused(radius),const double magick_unused(sigma),
7353 const double magick_unused(gain),const double magick_unused(threshold),
7354 ExceptionInfo *magick_unused(exception))
7355{
7356 magick_unreferenced(image);
7357 magick_unreferenced(channel);
7358 magick_unreferenced(radius);
7359 magick_unreferenced(sigma);
7360 magick_unreferenced(gain);
7361 magick_unreferenced(threshold);
7362 magick_unreferenced(exception);
7363
7364 return NULL;
7365}
7366
cristy0b8a2e92014-03-08 00:52:49 +00007367MagickExport
7368MagickBooleanType AccelerateCompositeImage(Image *image,
7369 const ChannelType channel,const CompositeOperator compose,
7370 const Image *composite,const ssize_t x_offset,const ssize_t y_offset,
7371 const float destination_dissolve,const float source_dissolve,
7372 ExceptionInfo *exception)
7373{
7374 magick_unreferenced(image);
cristya219e4b2014-03-08 12:36:16 +00007375 magick_unreferenced(channel);
7376 magick_unreferenced(compose);
7377 magick_unreferenced(composite);
7378 magick_unreferenced(x_offset);
7379 magick_unreferenced(y_offset);
7380 magick_unreferenced(destination_dissolve);
7381 magick_unreferenced(source_dissolve);
7382 magick_unreferenced(exception);
cristy0b8a2e92014-03-08 00:52:49 +00007383
7384 return MagickFalse;
7385}
7386
cristyf034abb2013-11-24 14:16:14 +00007387
7388MagickExport MagickBooleanType AccelerateContrastImage(
7389 Image* magick_unused(image),const MagickBooleanType magick_unused(sharpen),
7390 ExceptionInfo* magick_unused(exception))
7391{
7392 magick_unreferenced(image);
7393 magick_unreferenced(sharpen);
7394 magick_unreferenced(exception);
7395
7396 return MagickFalse;
7397}
7398
cristy0b8a2e92014-03-08 00:52:49 +00007399MagickExport MagickBooleanType AccelerateContrastStretchImageChannel(
cristy0c832c62014-03-07 22:21:04 +00007400 Image * image, const ChannelType channel, const double black_point, const double white_point,
7401 ExceptionInfo* magick_unused(exception))
7402{
7403 magick_unreferenced(image);
7404 magick_unreferenced(channel);
7405 magick_unreferenced(black_point);
7406 magick_unreferenced(white_point);
7407 magick_unreferenced(exception);
7408
7409 return MagickFalse;
7410}
7411
cristyf034abb2013-11-24 14:16:14 +00007412MagickExport MagickBooleanType AccelerateEqualizeImage(
7413 Image* magick_unused(image), const ChannelType magick_unused(channel),
7414 ExceptionInfo* magick_unused(exception))
7415{
7416 magick_unreferenced(image);
7417 magick_unreferenced(channel);
7418 magick_unreferenced(exception);
7419
7420 return MagickFalse;
7421}
7422
7423MagickExport Image *AccelerateDespeckleImage(const Image* magick_unused(image),
7424 ExceptionInfo* magick_unused(exception))
7425{
7426 magick_unreferenced(image);
7427 magick_unreferenced(exception);
7428
7429 return NULL;
7430}
7431
7432MagickExport Image *AccelerateResizeImage(const Image* magick_unused(image),
7433 const size_t magick_unused(resizedColumns),
7434 const size_t magick_unused(resizedRows),
7435 const ResizeFilter* magick_unused(resizeFilter),
7436 ExceptionInfo *magick_unused(exception))
7437{
7438 magick_unreferenced(image);
7439 magick_unreferenced(resizedColumns);
7440 magick_unreferenced(resizedRows);
7441 magick_unreferenced(resizeFilter);
7442 magick_unreferenced(exception);
7443
7444 return NULL;
7445}
7446
cristyf034abb2013-11-24 14:16:14 +00007447MagickExport
7448MagickBooleanType AccelerateModulateImage(
7449 Image* image, double percent_brightness, double percent_hue,
7450 double percent_saturation, ColorspaceType colorspace, ExceptionInfo* exception)
7451{
7452 magick_unreferenced(image);
7453 magick_unreferenced(percent_brightness);
7454 magick_unreferenced(percent_hue);
7455 magick_unreferenced(percent_saturation);
7456 magick_unreferenced(colorspace);
7457 magick_unreferenced(exception);
7458 return(MagickFalse);
7459}
7460
cristy0c832c62014-03-07 22:21:04 +00007461MagickExport
7462MagickBooleanType AccelerateNegateImageChannel(
7463 Image* image, const ChannelType channel, const MagickBooleanType grayscale, ExceptionInfo* exception)
7464{
7465 magick_unreferenced(image);
7466 magick_unreferenced(channel);
7467 magick_unreferenced(grayscale);
7468 magick_unreferenced(exception);
7469 return(MagickFalse);
7470}
7471
7472MagickExport
7473MagickBooleanType AccelerateGrayscaleImage(
7474 Image* image, const PixelIntensityMethod method, ExceptionInfo* exception)
7475{
7476 magick_unreferenced(image);
7477 magick_unreferenced(method);
7478 magick_unreferenced(exception);
7479 return(MagickFalse);
7480}
7481
cristye85d0f72013-11-27 02:25:43 +00007482MagickExport Image *AccelerateAddNoiseImage(const Image *image,
7483 const ChannelType channel, const NoiseType noise_type,ExceptionInfo *exception)
7484{
7485 magick_unreferenced(image);
7486 magick_unreferenced(channel);
7487 magick_unreferenced(noise_type);
7488 magick_unreferenced(exception);
7489 return NULL;
7490}
cristyf034abb2013-11-24 14:16:14 +00007491
cristy0c832c62014-03-07 22:21:04 +00007492
7493MagickExport MagickBooleanType AccelerateRandomImage(Image* image, ExceptionInfo* exception)
7494{
7495 magick_unreferenced(image);
7496 magick_unreferenced(exception);
7497 return MagickFalse;
7498}
7499
7500MagickExport
7501Image* AccelerateMotionBlurImage(const Image *image, const ChannelType channel,
7502 const double* kernel, const size_t width,
7503 const OffsetInfo *offset,
7504 ExceptionInfo *exception)
7505{
7506 magick_unreferenced(image);
7507 magick_unreferenced(channel);
7508 magick_unreferenced(kernel);
7509 magick_unreferenced(width);
7510 magick_unreferenced(offset);
7511 magick_unreferenced(exception);
7512 return NULL;
7513}
7514
cristyf034abb2013-11-24 14:16:14 +00007515#endif /* MAGICKCORE_OPENCL_SUPPORT */
7516
7517MagickExport MagickBooleanType AccelerateConvolveImage(
7518 const Image *magick_unused(image),const KernelInfo *magick_unused(kernel),
7519 Image *magick_unused(convolve_image),ExceptionInfo *magick_unused(exception))
7520{
7521 magick_unreferenced(image);
7522 magick_unreferenced(kernel);
7523 magick_unreferenced(convolve_image);
7524 magick_unreferenced(exception);
7525
7526 /* legacy, do not use */
7527 return(MagickFalse);
7528}
7529